Skip to content

Commit c6b616d

Browse files
committed
v0.0.5: default profile helper, formatting
1 parent 3ffbcda commit c6b616d

10 files changed

Lines changed: 48 additions & 13 deletions

File tree

README.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ client.profile(<profile_id>).loop(<loop_id>).participant(<participant_id>).patch
6161
```
6262

6363
## Design Philosophy
64-
All items accessible in the dotloop API follow a hierarchical structure as represented like this:
64+
All items accessible in the dotloop API follow a hierarchical structure (i.e. profiles have loops which have folders which have documents) as represented like this:
6565

6666
- Account
6767
- Contact
@@ -83,10 +83,22 @@ Accessing
8383

8484
PATCH /profile/1/loop/1/folder/1
8585

86+
with data
87+
88+
{
89+
"name": "Disclosures (renamed)"
90+
}
91+
8692
translates seamlessly to
8793

8894
```python
89-
client.profile(1).loop(1).folder(1).patch(...)
95+
client.profile(1).loop(1).folder(1).patch(name='Disclosures (renamed)')
96+
```
97+
98+
Note: if data keys ever have spaces then those keys can be included by unpacking a dictionary
99+
e.g.
100+
```python
101+
client.profile(1).loop(1).detail.patch(**{'Property Information': {...}})
90102
```
91103

92104
Inspiration was taken from [dotloop-ruby](https://github.com/sampatbadhe/dotloop-ruby) and [sendgrid-python](https://github.com/sendgrid/sendgrid-python).

dotloop/account.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33

44
class Account(DotloopObject):
55
def get(self):
6-
return self.fetch('get')
6+
return self.fetch('get')

dotloop/activity.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33

44
class Activity(DotloopObject, id_field='activity_id'):
55
def get(self, **kwargs):
6-
return self.fetch('get', params=kwargs)
6+
return self.fetch('get', params=kwargs)

dotloop/authenticate.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from base64 import b64encode
2-
from urllib.parse import urljoin, urlencode
2+
from urllib.parse import urlencode, urljoin
33

44
import requests
55

dotloop/bases.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from json import JSONDecodeError
12
from typing import Dict
23
from urllib.parse import urljoin
34

@@ -62,7 +63,10 @@ def fetch(self, method, **kwargs) -> Dict:
6263
urljoin(self.base_url, endpoint),
6364
**kwargs
6465
)
65-
return response.json()
66+
try:
67+
return response.json()
68+
except JSONDecodeError as e:
69+
return {'error': 'JSONDecodeError', 'message': f'{str(e)}: {response.content.decode()}', 'status': response.status_code}
6670

6771

6872
class NotNoneClass:
@@ -88,7 +92,7 @@ def first(iterable):
8892
raise KeyError(str(iterable))
8993

9094
items = [
91-
# [(object, method, id_value), (endpoint, params, body)]
95+
# [(object, method, id_value), endpointToFormat]
9296
[('LoopIt', 'post', None), 'loop-it'],
9397
[('Account', 'get', None), 'account'],
9498
[('Profile', 'get', None), 'profile'],
@@ -131,4 +135,4 @@ def __getitem__(self, key):
131135
return self.first(endpoint for loc, endpoint in self.items if loc == key)
132136

133137

134-
EndpointDirectory = EndpointDirectoryClass()
138+
EndpointDirectory = EndpointDirectoryClass()

dotloop/client.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from functools import cached_property
2+
13
import requests
24

35
from .account import Account
@@ -8,11 +10,14 @@
810

911
class Client:
1012
endpoint_directory = EndpointDirectory
11-
13+
1214
def __init__(self, access_token):
1315
self.session = requests.Session()
1416
self.access_token = access_token
1517

18+
def __str__(self):
19+
return '<Client>'
20+
1621
@property
1722
def access_token(self):
1823
return self._access_token
@@ -39,3 +44,17 @@ def profile(self):
3944
@property
4045
def contact(self):
4146
return Contact(parent=self)
47+
48+
@cached_property
49+
def DEFAULT_PROFILE(self):
50+
profiles = self.profile.get()
51+
try:
52+
return next(p['id'] for p in profiles['data'] if p.get('default'))
53+
except (StopIteration, KeyError):
54+
if 'error' in profiles:
55+
raise ValueError(profiles.get('message', profiles.get('error')))
56+
elif 'errors' in profiles:
57+
raise ValueError(str(profiles['errors']))
58+
else:
59+
raise ValueError('Unable to fetch default profile id.')
60+

dotloop/detail.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ def get(self):
66
return self.fetch('get')
77

88
def patch(self, **kwargs):
9-
return self.fetch('patch', json=kwargs)
9+
return self.fetch('patch', json=kwargs)

dotloop/loop_it.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ class LoopIt(DotloopObject):
55
def post(self, **kwargs):
66
return self.fetch('post', json=kwargs, params={
77
'profile_id': self.profile_id
8-
})
8+
})

dotloop/loop_template.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33

44
class LoopTemplate(DotloopObject, id_field='loop_template_id'):
55
def get(self):
6-
return self.fetch('get')
6+
return self.fetch('get')

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
setuptools.setup(
99
name='dotloop-python',
10-
version='0.0.4',
10+
version='0.0.5',
1111
packages=setuptools.find_packages(),
1212
install_requires=['requests'],
1313
author='Ben Russell',

0 commit comments

Comments
 (0)