cli2 3.3.23__tar.gz → 3.3.25__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cli2-3.3.23/cli2.egg-info → cli2-3.3.25}/PKG-INFO +1 -1
- {cli2-3.3.23 → cli2-3.3.25}/cli2/__init__.py +0 -1
- {cli2-3.3.23 → cli2-3.3.25}/cli2/client.py +16 -98
- {cli2-3.3.23 → cli2-3.3.25}/cli2/group.py +2 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/test_client.py +24 -57
- {cli2-3.3.23 → cli2-3.3.25}/cli2/test_group.py +6 -1
- {cli2-3.3.23 → cli2-3.3.25/cli2.egg-info}/PKG-INFO +1 -1
- {cli2-3.3.23 → cli2-3.3.25}/setup.py +1 -1
- {cli2-3.3.23 → cli2-3.3.25}/MANIFEST.in +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/README.rst +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/classifiers.txt +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/argument.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/asyncio.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/cli.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/colors.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/command.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/configuration.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/decorators.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/display.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/entry_point.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/example_client.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/example_client_complex.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/example_nesting.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/example_obj.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/logging.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/node.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/overrides.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/sphinx.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/table.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/test.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/test_cli.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/test_command.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/test_configuration.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/test_decorators.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/test_display.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/test_entry_point.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/test_inject.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/test_node.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2/test_table.py +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2.egg-info/SOURCES.txt +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2.egg-info/dependency_links.txt +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2.egg-info/entry_points.txt +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2.egg-info/requires.txt +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/cli2.egg-info/top_level.txt +0 -0
- {cli2-3.3.23 → cli2-3.3.25}/setup.cfg +0 -0
|
@@ -675,21 +675,19 @@ class ModelGroup(Group):
|
|
|
675
675
|
)
|
|
676
676
|
)
|
|
677
677
|
|
|
678
|
+
url_list_methods = ['find', 'get', 'delete', 'create']
|
|
678
679
|
if cls.url_list:
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
self.cmd(cls.delete)
|
|
682
|
-
self.cmd(cls.create)
|
|
680
|
+
for name in url_list_methods:
|
|
681
|
+
self.cmd(getattr(cls, name))
|
|
683
682
|
|
|
684
|
-
self.load_cls(cls, exclude=
|
|
683
|
+
self.load_cls(cls, exclude=url_list_methods)
|
|
685
684
|
|
|
686
685
|
|
|
687
686
|
class ModelMetaclass(type):
|
|
688
|
-
def __new__(cls, name, bases, attributes
|
|
689
|
-
attributes['_client_key'] = client
|
|
687
|
+
def __new__(cls, name, bases, attributes):
|
|
690
688
|
cls = super().__new__(cls, name, bases, attributes)
|
|
691
|
-
|
|
692
|
-
if
|
|
689
|
+
client = getattr(cls, 'client', None)
|
|
690
|
+
if client:
|
|
693
691
|
return cls
|
|
694
692
|
|
|
695
693
|
client_class = getattr(cls, '_client_class', None)
|
|
@@ -740,6 +738,7 @@ class Model(metaclass=ModelMetaclass):
|
|
|
740
738
|
|
|
741
739
|
The URL to get the list of objects, you're supposed to configure it as
|
|
742
740
|
a model attribute in your model subclass.
|
|
741
|
+
This may be a format string using a client ``client`` variable.
|
|
743
742
|
|
|
744
743
|
.. py:attribute:: url_detail
|
|
745
744
|
|
|
@@ -1198,11 +1197,9 @@ class Client(metaclass=ClientMetaclass):
|
|
|
1198
1197
|
self.token = None
|
|
1199
1198
|
|
|
1200
1199
|
for model in self.models:
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
client = self
|
|
1205
|
-
model = type(model.__name__, (model,), dict(client=client))
|
|
1200
|
+
model = type(model.__name__, (model,), dict(client=self))
|
|
1201
|
+
if model.url_list:
|
|
1202
|
+
model.url_list = model.url_list.format(client=self)
|
|
1206
1203
|
setattr(self, model.__name__, model)
|
|
1207
1204
|
|
|
1208
1205
|
@property
|
|
@@ -1479,6 +1476,11 @@ class Client(metaclass=ClientMetaclass):
|
|
|
1479
1476
|
|
|
1480
1477
|
return data
|
|
1481
1478
|
|
|
1479
|
+
@cmd
|
|
1480
|
+
async def get(self, url, *args, **kwargs):
|
|
1481
|
+
""" GET Request """
|
|
1482
|
+
return await self.request('GET', url, *args, **kwargs)
|
|
1483
|
+
|
|
1482
1484
|
@cmd(name='request')
|
|
1483
1485
|
async def request_cmd(self, method, url, *args, **kwargs):
|
|
1484
1486
|
"""
|
|
@@ -1505,11 +1507,6 @@ class Client(metaclass=ClientMetaclass):
|
|
|
1505
1507
|
kwargs[key] = yaml.safe_load(fh.read())
|
|
1506
1508
|
return await self.request(method, url, *args, **kwargs)
|
|
1507
1509
|
|
|
1508
|
-
@cmd
|
|
1509
|
-
async def get(self, url, *args, **kwargs):
|
|
1510
|
-
""" GET Request """
|
|
1511
|
-
return await self.request('GET', url, *args, **kwargs)
|
|
1512
|
-
|
|
1513
1510
|
async def post(self, url, *args, **kwargs):
|
|
1514
1511
|
""" POST Request """
|
|
1515
1512
|
return await self.request('POST', url, *args, **kwargs)
|
|
@@ -1552,85 +1549,6 @@ class Client(metaclass=ClientMetaclass):
|
|
|
1552
1549
|
details.
|
|
1553
1550
|
"""
|
|
1554
1551
|
|
|
1555
|
-
@property
|
|
1556
|
-
def base_url(self):
|
|
1557
|
-
return self.client.base_url
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
class ClientProxy:
|
|
1561
|
-
"""
|
|
1562
|
-
Proxy a :py:cls:`Client` with another :py:attr:`base_url`.
|
|
1563
|
-
|
|
1564
|
-
Allows to declare sub-clients:
|
|
1565
|
-
|
|
1566
|
-
.. code-block:: python
|
|
1567
|
-
|
|
1568
|
-
class YourClient(cli2.Client):
|
|
1569
|
-
def __init__(self, *args, **kwargs):
|
|
1570
|
-
super().__init__(*args, **kwargs)
|
|
1571
|
-
self.widget_client = cli2.ClientProxy(self, '/widgets')
|
|
1572
|
-
self.thing_client = cli2.ClientProxy(self, '/things')
|
|
1573
|
-
|
|
1574
|
-
You generally don't need this class.
|
|
1575
|
-
|
|
1576
|
-
.. py:attribute:: client
|
|
1577
|
-
|
|
1578
|
-
Actual :py:cls:`Client` instance
|
|
1579
|
-
|
|
1580
|
-
.. py.attribute:: base_url
|
|
1581
|
-
|
|
1582
|
-
Extra base_url
|
|
1583
|
-
"""
|
|
1584
|
-
def __init__(self, client, base_url):
|
|
1585
|
-
self.base_url = base_url
|
|
1586
|
-
self.client = client
|
|
1587
|
-
|
|
1588
|
-
def url_rewrite(self, url):
|
|
1589
|
-
return '/'.join([
|
|
1590
|
-
str(self.client.base_url),
|
|
1591
|
-
str(self.base_url.lstrip('/')),
|
|
1592
|
-
url.lstrip('/')
|
|
1593
|
-
])
|
|
1594
|
-
|
|
1595
|
-
async def request(self, method, url, *args, **kwargs):
|
|
1596
|
-
"""
|
|
1597
|
-
Join the actual client's base_url, our base_url and the url.
|
|
1598
|
-
"""
|
|
1599
|
-
return await self.client.request(
|
|
1600
|
-
method, self.url_rewrite(url), *args, **kwargs
|
|
1601
|
-
)
|
|
1602
|
-
|
|
1603
|
-
@cmd
|
|
1604
|
-
async def get(self, url, *args, **kwargs):
|
|
1605
|
-
""" GET Request """
|
|
1606
|
-
return await self.request('GET', url, *args, **kwargs)
|
|
1607
|
-
|
|
1608
|
-
async def post(self, url, *args, **kwargs):
|
|
1609
|
-
""" POST Request """
|
|
1610
|
-
return await self.request('POST', url, *args, **kwargs)
|
|
1611
|
-
|
|
1612
|
-
async def put(self, url, *args, **kwargs):
|
|
1613
|
-
""" PUT Request """
|
|
1614
|
-
return await self.request('PUT', url, *args, **kwargs)
|
|
1615
|
-
|
|
1616
|
-
async def head(self, url, *args, **kwargs):
|
|
1617
|
-
""" HEAD Request """
|
|
1618
|
-
return await self.request('HEAD', url, *args, **kwargs)
|
|
1619
|
-
|
|
1620
|
-
async def delete(self, url, *args, **kwargs):
|
|
1621
|
-
""" DELETE Request """
|
|
1622
|
-
return await self.request('DELETE', url, *args, **kwargs)
|
|
1623
|
-
|
|
1624
|
-
def paginate(self, url, *args, **kwargs):
|
|
1625
|
-
""" Paginate proxy """
|
|
1626
|
-
return self.client.paginate(self.url_rewrite(url), *args, **kwargs)
|
|
1627
|
-
|
|
1628
|
-
def pagination_initialize(self, paginator, data):
|
|
1629
|
-
return self.client.pagination_initialize(paginator, data)
|
|
1630
|
-
|
|
1631
|
-
def pagination_parameters(self, paginator, page_number):
|
|
1632
|
-
return self.client.pagination_parameters(paginator, page_number)
|
|
1633
|
-
|
|
1634
1552
|
|
|
1635
1553
|
class Expression:
|
|
1636
1554
|
def __init__(self, field, value):
|
|
@@ -183,6 +183,8 @@ class Group(EntryPoint, dict):
|
|
|
183
183
|
"""
|
|
184
184
|
exclude = exclude or []
|
|
185
185
|
for name, method in cls.__dict__.items():
|
|
186
|
+
if name in exclude:
|
|
187
|
+
continue
|
|
186
188
|
wrapped_method = getattr(method, '__func__', None)
|
|
187
189
|
if hasattr(wrapped_method, 'cli2'):
|
|
188
190
|
self.cmd(wrapped_method)
|
|
@@ -4,7 +4,6 @@ import httpx
|
|
|
4
4
|
import inspect
|
|
5
5
|
import mock
|
|
6
6
|
import pytest
|
|
7
|
-
import uuid
|
|
8
7
|
|
|
9
8
|
|
|
10
9
|
async def _response(**kwargs):
|
|
@@ -53,6 +52,23 @@ async def test_client_cli(client_class, httpx_mock):
|
|
|
53
52
|
await client_class.cli['testmodel']['find'].async_call()
|
|
54
53
|
|
|
55
54
|
|
|
55
|
+
@pytest.mark.asyncio
|
|
56
|
+
async def test_client_cli_override(client_class, httpx_mock):
|
|
57
|
+
class Client(client_class):
|
|
58
|
+
def __init__(self, *args, **kwargs):
|
|
59
|
+
self.test = 'bar'
|
|
60
|
+
super().__init__(*args, **kwargs)
|
|
61
|
+
|
|
62
|
+
class TestModel(Client.Model):
|
|
63
|
+
url_list = '{client.test}/foo'
|
|
64
|
+
|
|
65
|
+
@classmethod
|
|
66
|
+
@cli2.cmd
|
|
67
|
+
async def find(cls, foo):
|
|
68
|
+
return cls.url_list
|
|
69
|
+
assert await Client.cli['testmodel']['find'].async_call('bar') == 'bar/foo'
|
|
70
|
+
|
|
71
|
+
|
|
56
72
|
def test_client_model(client_class):
|
|
57
73
|
assert issubclass(client_class.Model, cli2.Model)
|
|
58
74
|
assert client_class.Model._client_class == client_class
|
|
@@ -942,66 +958,17 @@ async def test_debug():
|
|
|
942
958
|
|
|
943
959
|
|
|
944
960
|
@pytest.mark.asyncio
|
|
945
|
-
async def
|
|
946
|
-
class
|
|
961
|
+
async def test_url_list(client_class):
|
|
962
|
+
class Client(client_class):
|
|
947
963
|
def __init__(self, *args, **kwargs):
|
|
948
|
-
self.
|
|
964
|
+
self.foo = '/foo'
|
|
949
965
|
super().__init__(*args, **kwargs)
|
|
950
|
-
self.tokens = []
|
|
951
|
-
|
|
952
|
-
async def token_get(self):
|
|
953
|
-
token = str(uuid.uuid4())
|
|
954
|
-
self.tokens.append(token)
|
|
955
|
-
return token
|
|
956
|
-
|
|
957
|
-
class TestModel(ProxyTestClient.Model, client='sub'):
|
|
958
|
-
url_list = '/foo'
|
|
959
|
-
id = cli2.Field()
|
|
960
|
-
|
|
961
|
-
client = ProxyTestClient(base_url='http://ex')
|
|
962
|
-
assert not client.token
|
|
963
966
|
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
httpx_mock.add_response(url='http://ex/test1')
|
|
968
|
-
await client.get('/test1')
|
|
969
|
-
|
|
970
|
-
httpx_mock.add_response(url='http://ex/bar/sub')
|
|
971
|
-
await client.sub.get('/sub')
|
|
972
|
-
# don't get a new token, use the parent's
|
|
973
|
-
assert len(client.tokens) == 1
|
|
974
|
-
|
|
975
|
-
client = ProxyTestClient(base_url='http://ex2')
|
|
976
|
-
assert not client.token
|
|
977
|
-
httpx_mock.add_response(url='http://ex2/bar/sub2')
|
|
978
|
-
await client.sub.get('/sub2')
|
|
979
|
-
|
|
980
|
-
httpx_mock.add_response(url='http://ex2/root')
|
|
981
|
-
await client.get('/root')
|
|
982
|
-
# don't get a new token, use the parent's
|
|
983
|
-
assert len(client.tokens) == 1
|
|
984
|
-
|
|
985
|
-
httpx_mock.add_response(
|
|
986
|
-
url='http://ex2/bar/foo',
|
|
987
|
-
json=[dict(id=1), dict(id=2)],
|
|
988
|
-
)
|
|
989
|
-
result = await client.TestModel.find().list()
|
|
990
|
-
assert result[0].id == 1
|
|
991
|
-
assert result[1].id == 2
|
|
992
|
-
|
|
993
|
-
httpx_mock.add_response(
|
|
994
|
-
url='http://ex2/bar/foo/1',
|
|
995
|
-
json=dict(id=1),
|
|
996
|
-
)
|
|
997
|
-
result = await client.TestModel.get(id=1)
|
|
998
|
-
assert result.id == 1
|
|
967
|
+
class TestModel(Client.Model):
|
|
968
|
+
url_list = '{client.foo}/bar'
|
|
999
969
|
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
method='DELETE',
|
|
1003
|
-
)
|
|
1004
|
-
await result.delete()
|
|
970
|
+
client = Client()
|
|
971
|
+
assert client.TestModel.url_list == '/foo/bar'
|
|
1005
972
|
|
|
1006
973
|
|
|
1007
974
|
@pytest.mark.asyncio
|
|
@@ -224,8 +224,13 @@ def test_load_cls():
|
|
|
224
224
|
@cli2.cmd
|
|
225
225
|
def test2(self):
|
|
226
226
|
pass
|
|
227
|
+
|
|
228
|
+
@cli2.cmd
|
|
229
|
+
def exclude(self):
|
|
230
|
+
pass
|
|
227
231
|
group = Group()
|
|
228
|
-
group.load_cls(Foo)
|
|
232
|
+
group.load_cls(Foo, exclude=['exclude'])
|
|
229
233
|
assert 'bar' not in group
|
|
230
234
|
assert 'test' in group
|
|
231
235
|
assert 'test2' in group
|
|
236
|
+
assert 'exclude' not in group
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|