Skip to content

Commit fb90689

Browse files
authored
Merge pull request #7 from cloudblue/new_design
New design
2 parents 2be99fd + e56218e commit fb90689

29 files changed

+943
-1290
lines changed

cnct/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# This file is part of the Ingram Micro Cloud Blue Connect connect-fluent-client.
44
# Copyright (c) 2019-2020 Ingram Micro. All Rights Reserved.
55

6-
from cnct.client.exceptions import ClientError, NotFoundError # noqa
6+
from cnct.client.exceptions import ClientError # noqa
77
from cnct.client.fluent import ConnectClient # noqa
88
from cnct.client.version import get_version # noqa
99
from cnct.rql import R # noqa

cnct/client/exceptions.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
from http import HTTPStatus
22

33

4-
class NotFoundError(AttributeError):
5-
pass
6-
7-
84
class ClientError(Exception):
95
def __init__(self, message=None, status_code=None, error_code=None, errors=None):
106
self.message = message

cnct/client/fluent.py

Lines changed: 45 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
from json.decoder import JSONDecodeError
2-
from keyword import iskeyword
32

43
import requests
54
from requests.exceptions import RequestException
65

76
from cnct.client.constants import CONNECT_ENDPOINT_URL, CONNECT_SPECS_URL
8-
from cnct.client.exceptions import ClientError, NotFoundError
7+
from cnct.client.exceptions import ClientError
98
from cnct.client.models import Collection, NS
109
from cnct.client.utils import get_headers
11-
from cnct.help import DefaultFormatter
12-
from cnct.specs.parser import parse
10+
from cnct.client.help_formatter import DefaultFormatter
11+
from cnct.client.openapi import OpenAPISpecs
1312

1413

1514
class ConnectClient:
@@ -19,11 +18,12 @@ class ConnectClient:
1918
def __init__(
2019
self,
2120
api_key,
22-
endpoint=CONNECT_ENDPOINT_URL,
23-
specs_location=CONNECT_SPECS_URL,
24-
default_headers={},
21+
endpoint=None,
22+
use_specs=True,
23+
specs_location=None,
24+
validate_using_specs=True,
25+
default_headers=None,
2526
default_limit=100,
26-
help_formatter=DefaultFormatter(),
2727
):
2828
"""
2929
Create a new instance of the ConnectClient.
@@ -40,65 +40,40 @@ def __init__(
4040
if default_headers and 'Authorization' in default_headers:
4141
raise ValueError('`default_headers` cannot contains `Authorization`')
4242

43-
self.endpoint = endpoint
43+
self.endpoint = endpoint or CONNECT_ENDPOINT_URL
4444
self.api_key = api_key
45-
self.default_headers = default_headers
46-
self.specs_location = specs_location
47-
self.specs = parse(self.specs_location) if self.specs_location else None
45+
self.default_headers = default_headers or {}
46+
self._use_specs = use_specs
47+
self._validate_using_specs = validate_using_specs
48+
self.specs_location = specs_location or CONNECT_SPECS_URL
49+
self.specs = None
50+
if self._use_specs:
51+
self.specs = OpenAPISpecs(self.specs_location)
4852
self.response = None
49-
self._help_formatter = help_formatter
53+
self._help_formatter = DefaultFormatter(self.specs)
5054

5155
def __getattr__(self, name):
5256
"""
53-
Returns a NS or a Collection object called ``name``.
57+
Returns a collection object called ``name``.
5458
55-
:param name: The name of the NS or Collection to retrieve.
59+
:param name: The name of the collection to retrieve.
5660
:type name: str
57-
:raises AttributeError: If OpenAPI specs are not avaliable.
58-
:raises AttributeError: If the name does not exist.
59-
:return: a Collection or a NS called ``name``.
60-
:rtype: Collection, NS
61+
:return: a collection called ``name``.
62+
:rtype: Collection
6163
"""
62-
if not self.specs:
63-
raise AttributeError(
64-
'No specs available. Use `ns` '
65-
'or `collection` methods instead.'
66-
)
6764
if '_' in name:
6865
name = name.replace('_', '-')
69-
if name in self.specs.namespaces:
70-
return self.ns(name)
71-
if name in self.specs.collections:
72-
return self.collection(name)
73-
raise AttributeError('Unable to resolve {}.'.format(name))
74-
75-
def __dir__(self):
76-
"""
77-
Return a list of attributes defined for this ConnectClient instance.
78-
The returned list includes the names of the root namespaces and collections.
66+
return self.collection(name)
7967

80-
:return: List of attributes.
81-
:rtype: list
82-
"""
83-
if not self.specs:
84-
return super().__dir__()
85-
ns = list(self.specs.namespaces.keys())
86-
cl = list(self.specs.collections.keys())
87-
additional_names = []
88-
for name in cl + ns:
89-
if '-' in name:
90-
name = name.replace('-', '_')
91-
if name.isidentifier() and not iskeyword(name):
92-
additional_names.append(name)
93-
return sorted(super().__dir__() + additional_names)
68+
def __call__(self, name):
69+
return self.ns(name)
9470

9571
def ns(self, name):
9672
"""
9773
Returns the namespace called ``name``.
9874
9975
:param name: The name of the namespace to access.
10076
:type name: str
101-
:raises NotFoundError: If a namespace with name ``name`` does not exist.
10277
:return: The namespace called ``name``.
10378
:rtype: NS
10479
"""
@@ -108,19 +83,14 @@ def ns(self, name):
10883
if not name:
10984
raise ValueError('`name` must not be blank.')
11085

111-
if not self.specs:
112-
return NS(self, f'{self.endpoint}/{name}',)
113-
if name in self.specs.namespaces:
114-
return NS(self, f'{self.endpoint}/{name}', self.specs.namespaces[name])
115-
raise NotFoundError(f'The namespace {name} does not exist.')
86+
return NS(self, name)
11687

11788
def collection(self, name):
11889
"""
11990
Returns the collection called ``name``.
12091
12192
:param name: The name of the collection to access.
12293
:type name: str
123-
:raises NotFoundError: If a collection with name ``name`` does not exist.
12494
:return: The collection called ``name``.
12595
:rtype: Collection
12696
"""
@@ -130,18 +100,10 @@ def collection(self, name):
130100
if not name:
131101
raise ValueError('`name` must not be blank.')
132102

133-
if not self.specs:
134-
return Collection(
135-
self,
136-
f'{self.endpoint}/{name}',
137-
)
138-
if name in self.specs.collections:
139-
return Collection(
140-
self,
141-
f'{self.endpoint}/{name}',
142-
self.specs.collections[name],
143-
)
144-
raise NotFoundError(f'The collection {name} does not exist.')
103+
return Collection(
104+
self,
105+
name,
106+
)
145107

146108
def get(self, url, **kwargs):
147109
return self.execute('get', url, **kwargs)
@@ -165,7 +127,17 @@ def update(self, url, payload=None, **kwargs):
165127
def delete(self, url, **kwargs):
166128
return self.execute('delete', url, **kwargs)
167129

168-
def execute(self, method, url, **kwargs):
130+
def execute(self, method, path, **kwargs):
131+
if (
132+
self._use_specs
133+
and self._validate_using_specs
134+
and not self.specs.exists(method, path)
135+
):
136+
# TODO more info, specs version, method etc
137+
raise ClientError(f'The path `{path}` does not exist.')
138+
139+
url = f'{self.endpoint}/{path}'
140+
169141
kwargs = kwargs or {}
170142
if 'headers' in kwargs:
171143
kwargs['headers'].update(get_headers(self.api_key))
@@ -191,8 +163,12 @@ def execute(self, method, url, **kwargs):
191163
status_code = self.response.status_code if self.response is not None else None
192164
raise ClientError(status_code=status_code, **api_error) from re
193165

166+
def print_help(self, obj):
167+
print()
168+
print(self._help_formatter.format(obj))
169+
194170
def help(self):
195-
self._help_formatter.print_help(self.specs)
171+
self.print_help(None)
196172
return self
197173

198174
def _execute_http_call(self, method, url, kwargs):

0 commit comments

Comments
 (0)