cli2 4.3.3__tar.gz → 5.0.0rc2__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-4.3.3/cli2.egg-info → cli2-5.0.0rc2}/PKG-INFO +1 -1
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2/__init__.py +0 -25
- {cli2-4.3.3 → cli2-5.0.0rc2/cli2.egg-info}/PKG-INFO +1 -1
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2.egg-info/SOURCES.txt +0 -6
- {cli2-4.3.3 → cli2-5.0.0rc2}/setup.py +1 -1
- {cli2-4.3.3 → cli2-5.0.0rc2}/tests/test_ansible.py +12 -11
- {cli2-4.3.3 → cli2-5.0.0rc2}/tests/test_ansible_variables.py +5 -5
- {cli2-4.3.3 → cli2-5.0.0rc2}/tests/test_cli.py +1 -1
- {cli2-4.3.3 → cli2-5.0.0rc2}/tests/test_client.py +64 -56
- cli2-4.3.3/cli2/ansible/__init__.py +0 -16
- cli2-4.3.3/cli2/ansible/action.py +0 -400
- cli2-4.3.3/cli2/ansible/playbook.py +0 -215
- cli2-4.3.3/cli2/ansible/variables.py +0 -115
- cli2-4.3.3/cli2/client.py +0 -1868
- cli2-4.3.3/cli2/examples/client.py +0 -61
- {cli2-4.3.3 → cli2-5.0.0rc2}/MANIFEST.in +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/README.rst +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/classifiers.txt +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2/asyncio.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2/cli.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2/cli2.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2/colors.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2/configuration.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2/decorators.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2/display.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2/examples/__init__.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2/examples/conf.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2/examples/example.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2/examples/example_obj.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2/examples/nesting.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2/examples/obj.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2/examples/obj2.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2/examples/test.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2/lock.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2/log.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2/mask.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2/node.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2/sphinx.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2/table.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2/test.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2.egg-info/dependency_links.txt +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2.egg-info/entry_points.txt +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2.egg-info/requires.txt +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/cli2.egg-info/top_level.txt +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/setup.cfg +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/tests/test_asyncio.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/tests/test_command.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/tests/test_configuration.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/tests/test_decorators.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/tests/test_display.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/tests/test_entry_point.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/tests/test_group.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/tests/test_inject.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/tests/test_lock.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/tests/test_mask.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/tests/test_node.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/tests/test_restful.py +0 -0
- {cli2-4.3.3 → cli2-5.0.0rc2}/tests/test_table.py +0 -0
|
@@ -13,31 +13,6 @@ from .asyncio import async_resolve, async_run
|
|
|
13
13
|
from .colors import colors as c
|
|
14
14
|
|
|
15
15
|
from .configuration import Configuration, cfg
|
|
16
|
-
try:
|
|
17
|
-
from .client import (
|
|
18
|
-
ClientError,
|
|
19
|
-
ResponseError,
|
|
20
|
-
TokenGetError,
|
|
21
|
-
RefusedResponseError,
|
|
22
|
-
RetriesExceededError,
|
|
23
|
-
FieldError,
|
|
24
|
-
FieldValueError,
|
|
25
|
-
FieldExternalizeError,
|
|
26
|
-
Client,
|
|
27
|
-
ClientCommand,
|
|
28
|
-
DateTimeField,
|
|
29
|
-
Field,
|
|
30
|
-
Handler,
|
|
31
|
-
JSONStringField,
|
|
32
|
-
Model,
|
|
33
|
-
ModelCommand,
|
|
34
|
-
Paginator,
|
|
35
|
-
Related,
|
|
36
|
-
)
|
|
37
|
-
except ImportError:
|
|
38
|
-
raise
|
|
39
|
-
# httpx not installed
|
|
40
|
-
pass
|
|
41
16
|
from .display import diff, diff_data, render, print, highlight, yaml_highlight
|
|
42
17
|
from .lock import Lock
|
|
43
18
|
from .log import configure, log
|
|
@@ -6,7 +6,6 @@ cli2/__init__.py
|
|
|
6
6
|
cli2/asyncio.py
|
|
7
7
|
cli2/cli.py
|
|
8
8
|
cli2/cli2.py
|
|
9
|
-
cli2/client.py
|
|
10
9
|
cli2/colors.py
|
|
11
10
|
cli2/configuration.py
|
|
12
11
|
cli2/decorators.py
|
|
@@ -24,12 +23,7 @@ cli2.egg-info/dependency_links.txt
|
|
|
24
23
|
cli2.egg-info/entry_points.txt
|
|
25
24
|
cli2.egg-info/requires.txt
|
|
26
25
|
cli2.egg-info/top_level.txt
|
|
27
|
-
cli2/ansible/__init__.py
|
|
28
|
-
cli2/ansible/action.py
|
|
29
|
-
cli2/ansible/playbook.py
|
|
30
|
-
cli2/ansible/variables.py
|
|
31
26
|
cli2/examples/__init__.py
|
|
32
|
-
cli2/examples/client.py
|
|
33
27
|
cli2/examples/conf.py
|
|
34
28
|
cli2/examples/example.py
|
|
35
29
|
cli2/examples/example_obj.py
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import cli2
|
|
2
|
+
import cclient
|
|
2
3
|
import httpx
|
|
3
4
|
import mock
|
|
4
5
|
import pytest
|
|
5
6
|
import textwrap
|
|
6
7
|
import yaml
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
import cansible
|
|
9
10
|
|
|
10
11
|
|
|
11
|
-
class ActionModule(
|
|
12
|
+
class ActionModule(cansible.ActionBase):
|
|
12
13
|
mask_keys = ['a']
|
|
13
14
|
|
|
14
15
|
async def run_async(self):
|
|
@@ -31,10 +32,10 @@ async def test_mask(monkeypatch):
|
|
|
31
32
|
|
|
32
33
|
@pytest.mark.asyncio
|
|
33
34
|
async def test_response_error(httpx_mock):
|
|
34
|
-
class Client(
|
|
35
|
+
class Client(cclient.Client):
|
|
35
36
|
mask_keys = ['secret']
|
|
36
37
|
|
|
37
|
-
class Action(
|
|
38
|
+
class Action(cansible.ActionBase):
|
|
38
39
|
async def client_factory(self):
|
|
39
40
|
return Client(base_url='http://foo')
|
|
40
41
|
|
|
@@ -59,9 +60,9 @@ async def test_response_error(httpx_mock):
|
|
|
59
60
|
|
|
60
61
|
@pytest.mark.asyncio
|
|
61
62
|
async def test_option():
|
|
62
|
-
class Action(
|
|
63
|
-
fact =
|
|
64
|
-
arg =
|
|
63
|
+
class Action(cansible.ActionBase):
|
|
64
|
+
fact = cansible.Option(fact='fact', default='default fact')
|
|
65
|
+
arg = cansible.Option(arg='arg', fact='arg_fact')
|
|
65
66
|
|
|
66
67
|
async def run_async(self):
|
|
67
68
|
self.result['arg'] = self.arg
|
|
@@ -90,8 +91,8 @@ async def test_option():
|
|
|
90
91
|
error="Missing arg `arg` or fact `arg_fact`",
|
|
91
92
|
)
|
|
92
93
|
|
|
93
|
-
class Action(
|
|
94
|
-
name =
|
|
94
|
+
class Action(cansible.ActionBase):
|
|
95
|
+
name = cansible.Option('name')
|
|
95
96
|
|
|
96
97
|
async def run_async(self):
|
|
97
98
|
self.result['name'] = self.name
|
|
@@ -108,8 +109,8 @@ async def test_diff(monkeypatch):
|
|
|
108
109
|
_print = mock.Mock()
|
|
109
110
|
monkeypatch.setattr(cli2.display, '_print', _print)
|
|
110
111
|
|
|
111
|
-
class Action(
|
|
112
|
-
name =
|
|
112
|
+
class Action(cansible.ActionBase):
|
|
113
|
+
name = cansible.Option('name', 'object_name', 'Test object')
|
|
113
114
|
|
|
114
115
|
async def run_async(self):
|
|
115
116
|
self.before_set(dict(foo=1))
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import cansible
|
|
2
2
|
import pytest
|
|
3
3
|
import os
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
def test_story():
|
|
7
|
-
variables =
|
|
7
|
+
variables = cansible.Variables(
|
|
8
8
|
root_path=os.path.dirname(__file__),
|
|
9
9
|
pass_path=os.path.dirname(__file__) + '/vault_pass',
|
|
10
10
|
)
|
|
@@ -14,7 +14,7 @@ def test_story():
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
def test_exceptions():
|
|
17
|
-
variables =
|
|
17
|
+
variables = cansible.Variables()
|
|
18
18
|
with pytest.raises(Exception) as exc:
|
|
19
19
|
variables['variables.yml']
|
|
20
20
|
assert exc.value.args == (
|
|
@@ -25,12 +25,12 @@ def test_exceptions():
|
|
|
25
25
|
variables['/variables_vault.yml']
|
|
26
26
|
assert exc.value.args == ('/variables_vault.yml does not exist',)
|
|
27
27
|
|
|
28
|
-
variables =
|
|
28
|
+
variables = cansible.Variables(root_path=os.path.dirname(__file__))
|
|
29
29
|
with pytest.raises(Exception) as exc:
|
|
30
30
|
variables['variables_vault.yml']
|
|
31
31
|
assert exc.value.args == ('Vault password required in pass_path',)
|
|
32
32
|
|
|
33
|
-
variables =
|
|
33
|
+
variables = cansible.Variables(
|
|
34
34
|
root_path=os.path.dirname(__file__),
|
|
35
35
|
pass_path='/does/not/exist',
|
|
36
36
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
2
|
import cli2
|
|
3
|
-
import
|
|
3
|
+
import cclient
|
|
4
4
|
import httpx
|
|
5
5
|
import inspect
|
|
6
6
|
import mock
|
|
@@ -11,7 +11,7 @@ async def _response(**kwargs):
|
|
|
11
11
|
return httpx.Response(**kwargs)
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
class HandlerSentinel(
|
|
14
|
+
class HandlerSentinel(cclient.Handler):
|
|
15
15
|
def __init__(self, *args, **kwargs):
|
|
16
16
|
super().__init__(*args, **kwargs)
|
|
17
17
|
self.calls = []
|
|
@@ -23,9 +23,9 @@ class HandlerSentinel(cli2.Handler):
|
|
|
23
23
|
|
|
24
24
|
@pytest.fixture
|
|
25
25
|
def client_class():
|
|
26
|
-
class TestClient(
|
|
26
|
+
class TestClient(cclient.Client):
|
|
27
27
|
""" doc """
|
|
28
|
-
class Paginator(
|
|
28
|
+
class Paginator(cclient.Paginator):
|
|
29
29
|
def pagination_parameters(self, params, page_number):
|
|
30
30
|
if page_number > 1:
|
|
31
31
|
params['page'] = page_number
|
|
@@ -76,6 +76,14 @@ async def test_client_cli(client_class, httpx_mock):
|
|
|
76
76
|
assert list(client_class.cli['testmodel3'].keys()) == ['help', 'find']
|
|
77
77
|
|
|
78
78
|
|
|
79
|
+
def test_client_cli_func(client_class):
|
|
80
|
+
# test adding a normal function
|
|
81
|
+
@client_class.cli.cmd
|
|
82
|
+
def foo(test):
|
|
83
|
+
pass
|
|
84
|
+
client_class.cli['foo']('bar')
|
|
85
|
+
|
|
86
|
+
|
|
79
87
|
@pytest.mark.asyncio
|
|
80
88
|
async def test_client_cli_override(client_class, httpx_mock):
|
|
81
89
|
class Client(client_class):
|
|
@@ -110,7 +118,7 @@ async def test_client_cli_override(client_class, httpx_mock):
|
|
|
110
118
|
|
|
111
119
|
|
|
112
120
|
def test_client_model(client_class):
|
|
113
|
-
assert issubclass(client_class.Model,
|
|
121
|
+
assert issubclass(client_class.Model, cclient.Model)
|
|
114
122
|
assert client_class.Model._client_class == client_class
|
|
115
123
|
|
|
116
124
|
class TestModel(client_class.Model):
|
|
@@ -144,27 +152,27 @@ async def test_async_factory(httpx_mock, client_class):
|
|
|
144
152
|
|
|
145
153
|
@pytest.mark.asyncio
|
|
146
154
|
async def test_client_cli_side_effect(client_class, httpx_mock):
|
|
147
|
-
from
|
|
155
|
+
from cclient import example
|
|
148
156
|
|
|
149
157
|
# test that this didn't spill over client_class
|
|
150
158
|
test_client_cli(client_class, httpx_mock)
|
|
151
159
|
|
|
152
160
|
# Test that Client's __init_subclass__ did setup a factory for self
|
|
153
161
|
assert isinstance(
|
|
154
|
-
await
|
|
155
|
-
|
|
162
|
+
await example.APIClient.cli['get']['self'].factory_value(),
|
|
163
|
+
example.APIClient,
|
|
156
164
|
)
|
|
157
165
|
|
|
158
166
|
# Test that Model's __init_subclass__ did setup a factory for cls
|
|
159
167
|
httpx_mock.add_response(url='http://localhost:8000/1', json=[1])
|
|
160
|
-
result = await
|
|
168
|
+
result = await example.cli['get'].async_call('/1')
|
|
161
169
|
assert result.json() == [1]
|
|
162
170
|
|
|
163
171
|
httpx_mock.add_response(
|
|
164
172
|
url='http://localhost:8000/objects/1/',
|
|
165
173
|
json=dict(id=1, a=2),
|
|
166
174
|
)
|
|
167
|
-
result = await
|
|
175
|
+
result = await example.cli['object']['get'].async_call('id=1')
|
|
168
176
|
assert result.id == 1
|
|
169
177
|
assert result.data['a'] == 2
|
|
170
178
|
|
|
@@ -253,7 +261,7 @@ async def test_handler(client_class):
|
|
|
253
261
|
client = client_class()
|
|
254
262
|
client.client_reset = mock.AsyncMock()
|
|
255
263
|
client.token_reset = mock.AsyncMock()
|
|
256
|
-
handler =
|
|
264
|
+
handler = cclient.Handler(accepts=[201], refuses=[218], retokens=[418])
|
|
257
265
|
|
|
258
266
|
response = httpx.Response(status_code=201)
|
|
259
267
|
result = await handler(client, response, 0, log)
|
|
@@ -268,7 +276,7 @@ async def test_handler(client_class):
|
|
|
268
276
|
|
|
269
277
|
response = httpx.Response(status_code=200, content='[2]')
|
|
270
278
|
response.request = httpx.Request('POST', '/', json=[1])
|
|
271
|
-
with pytest.raises(
|
|
279
|
+
with pytest.raises(cclient.RetriesExceededError) as exc:
|
|
272
280
|
await handler(client, response, handler.tries + 1, log)
|
|
273
281
|
log.info.assert_called_once_with(
|
|
274
282
|
'retry', status_code=200, tries=0, sleep=.0
|
|
@@ -279,7 +287,7 @@ async def test_handler(client_class):
|
|
|
279
287
|
|
|
280
288
|
response = httpx.Response(status_code=200)
|
|
281
289
|
response.request = httpx.Request('GET', '/')
|
|
282
|
-
with pytest.raises(
|
|
290
|
+
with pytest.raises(cclient.RetriesExceededError) as exc:
|
|
283
291
|
await handler(client, response, handler.tries + 1, log)
|
|
284
292
|
|
|
285
293
|
msg = 'Unacceptable response <Response [200 OK]> after 31 tries\n\x1b[0m\x1b[1mGET /\x1b[0m\n\x1b[1mHTTP 200\x1b[0m' # noqa
|
|
@@ -287,7 +295,7 @@ async def test_handler(client_class):
|
|
|
287
295
|
|
|
288
296
|
response = httpx.Response(status_code=218)
|
|
289
297
|
response.request = httpx.Request('POST', '/')
|
|
290
|
-
with pytest.raises(
|
|
298
|
+
with pytest.raises(cclient.RefusedResponseError) as exc:
|
|
291
299
|
await handler(client, response, 1, log)
|
|
292
300
|
|
|
293
301
|
assert exc.value.response
|
|
@@ -298,7 +306,7 @@ async def test_handler(client_class):
|
|
|
298
306
|
|
|
299
307
|
response = httpx.Response(status_code=418)
|
|
300
308
|
response.request = httpx.Request('POST', '/')
|
|
301
|
-
with pytest.raises(
|
|
309
|
+
with pytest.raises(cclient.TokenGetError):
|
|
302
310
|
await handler(client, response, 1, log)
|
|
303
311
|
|
|
304
312
|
assert not client.client_reset.await_count
|
|
@@ -329,7 +337,7 @@ async def test_handler(client_class):
|
|
|
329
337
|
assert not result
|
|
330
338
|
assert client.token_reset.await_count == 1
|
|
331
339
|
|
|
332
|
-
handler =
|
|
340
|
+
handler = cclient.Handler(accepts=[], refuses=[222])
|
|
333
341
|
|
|
334
342
|
response = httpx.Response(status_code=123)
|
|
335
343
|
result = await handler(client, response, 0, log)
|
|
@@ -468,7 +476,7 @@ async def test_pagination_model(httpx_mock, client_class):
|
|
|
468
476
|
|
|
469
477
|
|
|
470
478
|
def test_paginator_fields(client_class):
|
|
471
|
-
paginator =
|
|
479
|
+
paginator = cclient.Paginator(client_class(), '/')
|
|
472
480
|
paginator.total_items = 95
|
|
473
481
|
paginator.per_page = 10
|
|
474
482
|
assert paginator.total_pages == 10
|
|
@@ -509,7 +517,7 @@ async def test_pagination_patterns(httpx_mock, client_class):
|
|
|
509
517
|
class Offset(client_class.Model):
|
|
510
518
|
url_list = '/off'
|
|
511
519
|
|
|
512
|
-
class Paginator(
|
|
520
|
+
class Paginator(cclient.Paginator):
|
|
513
521
|
def pagination_initialize(self, data):
|
|
514
522
|
self.total_items = data['total']
|
|
515
523
|
|
|
@@ -576,9 +584,9 @@ async def test_pagination_reverse(httpx_mock, client_class):
|
|
|
576
584
|
|
|
577
585
|
def test_descriptor(client_class):
|
|
578
586
|
class Model(client_class.Model):
|
|
579
|
-
id =
|
|
580
|
-
bar =
|
|
581
|
-
foo =
|
|
587
|
+
id = cclient.Field()
|
|
588
|
+
bar = cclient.Field('nested/bar')
|
|
589
|
+
foo = cclient.Field('undeclared/foo')
|
|
582
590
|
|
|
583
591
|
model = Model(data=dict(id=1, nested=dict(bar=2)))
|
|
584
592
|
assert model.data['id'] == 1
|
|
@@ -613,7 +621,7 @@ def test_descriptor(client_class):
|
|
|
613
621
|
|
|
614
622
|
def test_jsonstring(client_class):
|
|
615
623
|
class Model(client_class.Model):
|
|
616
|
-
json =
|
|
624
|
+
json = cclient.JSONStringField()
|
|
617
625
|
|
|
618
626
|
client = client_class()
|
|
619
627
|
model = client.Model(data=dict(json='{"foo": 1}'))
|
|
@@ -633,7 +641,7 @@ def test_jsonstring(client_class):
|
|
|
633
641
|
|
|
634
642
|
def test_datetime(client_class):
|
|
635
643
|
class Model(client_class.Model):
|
|
636
|
-
dt =
|
|
644
|
+
dt = cclient.DateTimeField()
|
|
637
645
|
|
|
638
646
|
model = Model(dict(dt='2020-11-12T01:02:03'))
|
|
639
647
|
assert model.dt == datetime(2020, 11, 12, 1, 2, 3)
|
|
@@ -643,10 +651,10 @@ def test_datetime(client_class):
|
|
|
643
651
|
|
|
644
652
|
def test_model_inheritance(client_class):
|
|
645
653
|
class Model(client_class.Model):
|
|
646
|
-
foo =
|
|
654
|
+
foo = cclient.Field()
|
|
647
655
|
|
|
648
656
|
class Model2(Model):
|
|
649
|
-
bar =
|
|
657
|
+
bar = cclient.Field()
|
|
650
658
|
|
|
651
659
|
client = client_class()
|
|
652
660
|
assert [*client.Model._fields.keys()] == ['foo']
|
|
@@ -655,10 +663,10 @@ def test_model_inheritance(client_class):
|
|
|
655
663
|
|
|
656
664
|
def test_relation_simple(client_class):
|
|
657
665
|
class Child(client_class.Model):
|
|
658
|
-
foo =
|
|
666
|
+
foo = cclient.Field()
|
|
659
667
|
|
|
660
668
|
class Father(client_class.Model):
|
|
661
|
-
child =
|
|
669
|
+
child = cclient.Related('Child')
|
|
662
670
|
|
|
663
671
|
client = client_class()
|
|
664
672
|
model = client.Father(dict(child=dict(foo=1)))
|
|
@@ -677,10 +685,10 @@ def test_relation_simple(client_class):
|
|
|
677
685
|
|
|
678
686
|
def test_relation_many(client_class):
|
|
679
687
|
class Child(client_class.Model):
|
|
680
|
-
foo =
|
|
688
|
+
foo = cclient.Field()
|
|
681
689
|
|
|
682
690
|
class Father(client_class.Model):
|
|
683
|
-
children =
|
|
691
|
+
children = cclient.Related('Child', many=True)
|
|
684
692
|
|
|
685
693
|
client = client_class()
|
|
686
694
|
model = client.Father(dict(children=[dict(foo=1)]))
|
|
@@ -706,8 +714,8 @@ async def test_python_expression(httpx_mock, client_class):
|
|
|
706
714
|
|
|
707
715
|
class Model(client_class.Model):
|
|
708
716
|
url_list = '/foo'
|
|
709
|
-
a =
|
|
710
|
-
b =
|
|
717
|
+
a = cclient.Field()
|
|
718
|
+
b = cclient.Field()
|
|
711
719
|
paginator = Paginator
|
|
712
720
|
|
|
713
721
|
def mock():
|
|
@@ -758,8 +766,8 @@ async def test_python_expression(httpx_mock, client_class):
|
|
|
758
766
|
async def test_expression_parameter(httpx_mock, client_class):
|
|
759
767
|
class Model(client_class.Model):
|
|
760
768
|
url_list = '/foo'
|
|
761
|
-
a =
|
|
762
|
-
b =
|
|
769
|
+
a = cclient.Field()
|
|
770
|
+
b = cclient.Field(parameter='b')
|
|
763
771
|
|
|
764
772
|
httpx_mock.add_response(url='http://lol/foo?b=1', json=dict(
|
|
765
773
|
items=[dict(a=1, b=1), dict(a=3, b=1)],
|
|
@@ -788,7 +796,7 @@ async def test_model_crud(httpx_mock, client_class):
|
|
|
788
796
|
@pytest.mark.asyncio
|
|
789
797
|
async def test_client_cli2(httpx_mock, client_class):
|
|
790
798
|
class Foo(client_class.Model):
|
|
791
|
-
id =
|
|
799
|
+
id = cclient.Field()
|
|
792
800
|
url_list = '/foo'
|
|
793
801
|
|
|
794
802
|
assert client_class.cli.name == 'test'
|
|
@@ -829,14 +837,14 @@ async def test_object_command(httpx_mock, client_class):
|
|
|
829
837
|
))
|
|
830
838
|
def test_datetime_fmts(intern, extern, client_class):
|
|
831
839
|
class DtModel(client_class.Model):
|
|
832
|
-
dt =
|
|
840
|
+
dt = cclient.DateTimeField()
|
|
833
841
|
model = client_class().DtModel(dict(dt=intern))
|
|
834
842
|
assert model.dt == extern
|
|
835
843
|
|
|
836
844
|
|
|
837
845
|
def test_datetime_fmt(client_class):
|
|
838
846
|
class DtModel(client_class.Model):
|
|
839
|
-
dt =
|
|
847
|
+
dt = cclient.DateTimeField(fmt='%d/%m/%Y %H:%M:%S')
|
|
840
848
|
model = client_class().DtModel(dict(dt='13/02/2025 12:34:56'))
|
|
841
849
|
assert model.dt == datetime(2025, 2, 13, 12, 34, 56)
|
|
842
850
|
|
|
@@ -846,15 +854,15 @@ def test_datetime_fmt(client_class):
|
|
|
846
854
|
|
|
847
855
|
def test_datetime_error(client_class):
|
|
848
856
|
class DtModel(client_class.Model):
|
|
849
|
-
dt =
|
|
857
|
+
dt = cclient.DateTimeField()
|
|
850
858
|
model = client_class().DtModel(dict(dt='13/024:56'))
|
|
851
|
-
with pytest.raises(
|
|
859
|
+
with pytest.raises(cclient.FieldExternalizeError):
|
|
852
860
|
model.dt
|
|
853
861
|
|
|
854
862
|
|
|
855
863
|
def test_datetime_default_fmt(client_class):
|
|
856
864
|
class DtModel(client_class.Model):
|
|
857
|
-
dt =
|
|
865
|
+
dt = cclient.DateTimeField()
|
|
858
866
|
model = client_class().DtModel()
|
|
859
867
|
model.dt = datetime(2025, 2, 13, 16, 9, 30)
|
|
860
868
|
assert model.data['dt'] == '2025-02-13T16:09:30.000000'
|
|
@@ -866,11 +874,11 @@ def test_datetime_default_fmt(client_class):
|
|
|
866
874
|
|
|
867
875
|
@pytest.mark.asyncio
|
|
868
876
|
async def test_mask_recursive(client_class, monkeypatch):
|
|
869
|
-
client = client_class(mask=
|
|
877
|
+
client = client_class(mask=cclient.Mask(['scrt', 'password']))
|
|
870
878
|
client.client.send = mock.AsyncMock()
|
|
871
879
|
|
|
872
880
|
log = mock.Mock()
|
|
873
|
-
monkeypatch.setattr(
|
|
881
|
+
monkeypatch.setattr(cclient, 'log', log)
|
|
874
882
|
response = httpx.Response(
|
|
875
883
|
status_code=200,
|
|
876
884
|
content='{"pub": 1, "foo": [{"scrt": "pass"}]}',
|
|
@@ -900,11 +908,11 @@ async def test_mask_recursive(client_class, monkeypatch):
|
|
|
900
908
|
'key', ('json', 'data'),
|
|
901
909
|
)
|
|
902
910
|
async def test_mask_logs(client_class, key, monkeypatch):
|
|
903
|
-
client = client_class(mask=
|
|
911
|
+
client = client_class(mask=cclient.Mask(['scrt', 'password']))
|
|
904
912
|
client.client.send = mock.AsyncMock()
|
|
905
913
|
|
|
906
914
|
log = mock.Mock()
|
|
907
|
-
monkeypatch.setattr(
|
|
915
|
+
monkeypatch.setattr(cclient, 'log', log)
|
|
908
916
|
response = httpx.Response(
|
|
909
917
|
status_code=200,
|
|
910
918
|
content='{"pub": 1, "scrt": "pass"}',
|
|
@@ -940,26 +948,26 @@ async def test_mask_exceptions(client_class):
|
|
|
940
948
|
response.request = httpx.Request('POST', '/', json=dict(a=1, b=2))
|
|
941
949
|
client.mask.keys.add('a')
|
|
942
950
|
client.mask.keys.add('c')
|
|
943
|
-
error =
|
|
951
|
+
error = cclient.ResponseError(client, response, 1)
|
|
944
952
|
expected = "\n\x1b[0m\x1b[1mPOST /\x1b[0m\n\x1b[94ma\x1b[39;49;00m:\x1b[37m \x1b[39;49;00m\x1b[33m'\x1b[39;49;00m\x1b[33m***MASKED***\x1b[39;49;00m\x1b[33m'\x1b[39;49;00m\x1b[37m\x1b[39;49;00m\n\x1b[94mb\x1b[39;49;00m:\x1b[37m \x1b[39;49;00m2\x1b[37m\x1b[39;49;00m\n\n\x1b[1mHTTP 218\x1b[0m\n\x1b[94mc\x1b[39;49;00m:\x1b[37m \x1b[39;49;00m\x1b[33m'\x1b[39;49;00m\x1b[33m***MASKED***\x1b[39;49;00m\x1b[33m'\x1b[39;49;00m\x1b[37m\x1b[39;49;00m\n\x1b[94md\x1b[39;49;00m:\x1b[37m \x1b[39;49;00m4\x1b[37m\x1b[39;49;00m\n" # noqa
|
|
945
953
|
assert str(error) == expected
|
|
946
954
|
|
|
947
955
|
# this needs to work with form data too
|
|
948
956
|
response = httpx.Response(status_code=218, content='{"c": 3, "d": 4}')
|
|
949
957
|
response.request = httpx.Request('POST', '/', data=dict(a=1, b=2))
|
|
950
|
-
client.mask =
|
|
951
|
-
error =
|
|
958
|
+
client.mask = cclient.Mask(['a', 'c'])
|
|
959
|
+
error = cclient.ResponseError(client, response, 1)
|
|
952
960
|
expected = "\n\x1b[0m\x1b[1mPOST /\x1b[0m\n\x1b[94ma\x1b[39;49;00m:\x1b[37m \x1b[39;49;00m\x1b[33m'\x1b[39;49;00m\x1b[33m***MASKED***\x1b[39;49;00m\x1b[33m'\x1b[39;49;00m\x1b[37m\x1b[39;49;00m\n\x1b[94mb\x1b[39;49;00m:\x1b[37m \x1b[39;49;00m\x1b[33m'\x1b[39;49;00m\x1b[33m2\x1b[39;49;00m\x1b[33m'\x1b[39;49;00m\x1b[37m\x1b[39;49;00m\n\n\x1b[1mHTTP 218\x1b[0m\n\x1b[94mc\x1b[39;49;00m:\x1b[37m \x1b[39;49;00m\x1b[33m'\x1b[39;49;00m\x1b[33m***MASKED***\x1b[39;49;00m\x1b[33m'\x1b[39;49;00m\x1b[37m\x1b[39;49;00m\n\x1b[94md\x1b[39;49;00m:\x1b[37m \x1b[39;49;00m4\x1b[37m\x1b[39;49;00m\n" # noqa
|
|
953
961
|
assert str(error) == expected
|
|
954
962
|
|
|
955
963
|
|
|
956
964
|
@pytest.mark.asyncio
|
|
957
965
|
async def test_request_mask(client_class, monkeypatch):
|
|
958
|
-
client = client_class(mask=
|
|
966
|
+
client = client_class(mask=cclient.Mask(['password']))
|
|
959
967
|
client.client.send = mock.AsyncMock()
|
|
960
968
|
|
|
961
969
|
log = mock.Mock()
|
|
962
|
-
monkeypatch.setattr(
|
|
970
|
+
monkeypatch.setattr(cclient, 'log', log)
|
|
963
971
|
response = httpx.Response(
|
|
964
972
|
status_code=200,
|
|
965
973
|
content='{"pub": 1, "scrt": "pass"}',
|
|
@@ -990,7 +998,7 @@ async def test_log_content(client_class, monkeypatch):
|
|
|
990
998
|
client = client_class()
|
|
991
999
|
client.client.send = mock.AsyncMock()
|
|
992
1000
|
log = mock.Mock()
|
|
993
|
-
monkeypatch.setattr(
|
|
1001
|
+
monkeypatch.setattr(cclient, 'log', log)
|
|
994
1002
|
response = httpx.Response(status_code=200, content='lol:]bar')
|
|
995
1003
|
response.request = httpx.Request('POST', '/')
|
|
996
1004
|
client.client.send.return_value = response
|
|
@@ -1011,7 +1019,7 @@ async def test_log_quiet(client_class, monkeypatch):
|
|
|
1011
1019
|
client = client_class()
|
|
1012
1020
|
client.client.send = mock.AsyncMock()
|
|
1013
1021
|
log = mock.Mock()
|
|
1014
|
-
monkeypatch.setattr(
|
|
1022
|
+
monkeypatch.setattr(cclient, 'log', log)
|
|
1015
1023
|
response = httpx.Response(status_code=200, content='[1]')
|
|
1016
1024
|
response.request = httpx.Request('GET', '/')
|
|
1017
1025
|
client.client.send.return_value = response
|
|
@@ -1039,8 +1047,8 @@ def test_class_override(client_class):
|
|
|
1039
1047
|
@pytest.mark.asyncio
|
|
1040
1048
|
async def test_save(client_class, httpx_mock):
|
|
1041
1049
|
class TestModel(client_class.Model):
|
|
1042
|
-
id =
|
|
1043
|
-
foo =
|
|
1050
|
+
id = cclient.Field()
|
|
1051
|
+
foo = cclient.Field()
|
|
1044
1052
|
|
|
1045
1053
|
client = client_class()
|
|
1046
1054
|
model = client.TestModel(id=1, foo='bar')
|
|
@@ -1073,22 +1081,22 @@ async def test_save(client_class, httpx_mock):
|
|
|
1073
1081
|
|
|
1074
1082
|
def test_id_value(client_class):
|
|
1075
1083
|
class TestModel(client_class.Model):
|
|
1076
|
-
id =
|
|
1084
|
+
id = cclient.Field()
|
|
1077
1085
|
assert client_class().TestModel(id=1).id_value == 1
|
|
1078
1086
|
|
|
1079
1087
|
class TestModel2(client_class.Model):
|
|
1080
|
-
bar =
|
|
1088
|
+
bar = cclient.Field()
|
|
1081
1089
|
id_field = 'bar'
|
|
1082
1090
|
assert client_class().TestModel2(bar=1).id_value == 1
|
|
1083
1091
|
|
|
1084
1092
|
|
|
1085
1093
|
@pytest.mark.asyncio
|
|
1086
1094
|
async def test_debug(client_class, monkeypatch):
|
|
1087
|
-
client = client_class(mask=
|
|
1095
|
+
client = client_class(mask=cclient.Mask(['scrt', 'password']), debug=True)
|
|
1088
1096
|
client.client.send = mock.AsyncMock()
|
|
1089
1097
|
|
|
1090
1098
|
log = mock.Mock()
|
|
1091
|
-
monkeypatch.setattr(
|
|
1099
|
+
monkeypatch.setattr(cclient, 'log', log)
|
|
1092
1100
|
|
|
1093
1101
|
response = httpx.Response(
|
|
1094
1102
|
status_code=200,
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# flake8: noqa
|
|
2
|
-
"""
|
|
3
|
-
Wrapping all imports in a try/except because pytest always tries to import
|
|
4
|
-
this even when we're using cli2 without ansible
|
|
5
|
-
"""
|
|
6
|
-
try:
|
|
7
|
-
from .action import (
|
|
8
|
-
ansi_escape,
|
|
9
|
-
Option,
|
|
10
|
-
AnsibleError,
|
|
11
|
-
AnsibleOptionError,
|
|
12
|
-
ActionBase,
|
|
13
|
-
)
|
|
14
|
-
from .variables import Variables
|
|
15
|
-
except ImportError:
|
|
16
|
-
pass
|