cli2 5.0.2__tar.gz → 5.1.0rc1__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.
Files changed (52) hide show
  1. {cli2-5.0.2/cli2.egg-info → cli2-5.1.0rc1}/PKG-INFO +1 -1
  2. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2/__init__.py +6 -1
  3. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2/lock.py +1 -1
  4. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2/log.py +36 -13
  5. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2/mask.py +3 -3
  6. {cli2-5.0.2 → cli2-5.1.0rc1/cli2.egg-info}/PKG-INFO +1 -1
  7. {cli2-5.0.2 → cli2-5.1.0rc1}/setup.py +1 -1
  8. {cli2-5.0.2 → cli2-5.1.0rc1}/tests/test_client.py +54 -2
  9. {cli2-5.0.2 → cli2-5.1.0rc1}/MANIFEST.in +0 -0
  10. {cli2-5.0.2 → cli2-5.1.0rc1}/README.rst +0 -0
  11. {cli2-5.0.2 → cli2-5.1.0rc1}/classifiers.txt +0 -0
  12. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2/asyncio.py +0 -0
  13. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2/cli.py +0 -0
  14. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2/cli2.py +0 -0
  15. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2/colors.py +0 -0
  16. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2/configuration.py +0 -0
  17. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2/decorators.py +0 -0
  18. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2/display.py +0 -0
  19. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2/examples/__init__.py +0 -0
  20. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2/examples/conf.py +0 -0
  21. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2/examples/example.py +0 -0
  22. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2/examples/example_obj.py +0 -0
  23. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2/examples/nesting.py +0 -0
  24. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2/examples/obj.py +0 -0
  25. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2/examples/obj2.py +0 -0
  26. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2/examples/test.py +0 -0
  27. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2/node.py +0 -0
  28. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2/sphinx.py +0 -0
  29. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2/table.py +0 -0
  30. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2/test.py +0 -0
  31. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2.egg-info/SOURCES.txt +0 -0
  32. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2.egg-info/dependency_links.txt +0 -0
  33. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2.egg-info/entry_points.txt +0 -0
  34. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2.egg-info/requires.txt +0 -0
  35. {cli2-5.0.2 → cli2-5.1.0rc1}/cli2.egg-info/top_level.txt +0 -0
  36. {cli2-5.0.2 → cli2-5.1.0rc1}/setup.cfg +0 -0
  37. {cli2-5.0.2 → cli2-5.1.0rc1}/tests/test_ansible.py +0 -0
  38. {cli2-5.0.2 → cli2-5.1.0rc1}/tests/test_ansible_variables.py +0 -0
  39. {cli2-5.0.2 → cli2-5.1.0rc1}/tests/test_asyncio.py +0 -0
  40. {cli2-5.0.2 → cli2-5.1.0rc1}/tests/test_cli.py +0 -0
  41. {cli2-5.0.2 → cli2-5.1.0rc1}/tests/test_command.py +0 -0
  42. {cli2-5.0.2 → cli2-5.1.0rc1}/tests/test_configuration.py +0 -0
  43. {cli2-5.0.2 → cli2-5.1.0rc1}/tests/test_decorators.py +0 -0
  44. {cli2-5.0.2 → cli2-5.1.0rc1}/tests/test_display.py +0 -0
  45. {cli2-5.0.2 → cli2-5.1.0rc1}/tests/test_entry_point.py +0 -0
  46. {cli2-5.0.2 → cli2-5.1.0rc1}/tests/test_group.py +0 -0
  47. {cli2-5.0.2 → cli2-5.1.0rc1}/tests/test_inject.py +0 -0
  48. {cli2-5.0.2 → cli2-5.1.0rc1}/tests/test_lock.py +0 -0
  49. {cli2-5.0.2 → cli2-5.1.0rc1}/tests/test_mask.py +0 -0
  50. {cli2-5.0.2 → cli2-5.1.0rc1}/tests/test_node.py +0 -0
  51. {cli2-5.0.2 → cli2-5.1.0rc1}/tests/test_restful.py +0 -0
  52. {cli2-5.0.2 → cli2-5.1.0rc1}/tests/test_table.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: cli2
3
- Version: 5.0.2
3
+ Version: 5.1.0rc1
4
4
  Summary: image:: https://yourlabs.io/oss/cli2/badges/master/pipeline.svg
5
5
  Home-page: https://yourlabs.io/oss/cli2
6
6
  Author: James Pic
@@ -14,7 +14,12 @@ from .colors import colors as c
14
14
 
15
15
  from .configuration import Configuration, cfg
16
16
  from .display import diff, diff_data, render, print, highlight, yaml_highlight
17
- from .lock import Lock
17
+ try:
18
+ import fcntl
19
+ except ImportError:
20
+ """ windows """
21
+ else:
22
+ from .lock import Lock
18
23
  from .log import configure, log
19
24
  from .mask import Mask
20
25
  from .table import Table
@@ -80,7 +80,7 @@ class Lock:
80
80
  .. py:attribute:: blocking
81
81
 
82
82
  If True, the locker automatically blocks. Otherwise, you need to check
83
- :py:attr:`acquired` and call :py:method:`block` yourself.
83
+ :py:attr:`acquired` and call :py:meth:`block` yourself.
84
84
 
85
85
  .. py:attribute:: prefix
86
86
 
@@ -37,6 +37,16 @@ variables.
37
37
 
38
38
  Setting this to ``INFO``, ``DEBUG``, or any other log level is safe.
39
39
 
40
+ .. envvar:: LOG_FILE
41
+
42
+ Path to log file to use, with a couple of special values:
43
+
44
+ - if ``LOG_FILE=auto``, then a path will be calculated in
45
+ ``~/.local/cli2/log``,
46
+ - if ``LOG_FILE=none``, then there will be no file logging.
47
+
48
+ Default: ``auto``
49
+
40
50
  .. envvar:: DEBUG
41
51
 
42
52
  Setting this will set :envvar:`LOG_LEVEL` to `DEBUG`, but also activate
@@ -72,6 +82,7 @@ class YAMLFormatter:
72
82
 
73
83
  def configure():
74
84
  LOG_LEVEL = os.getenv('LOG_LEVEL', 'WARNING').upper()
85
+ LOG_FILE = os.getenv('LOG_FILE', 'auto').upper()
75
86
 
76
87
  if os.getenv('DEBUG'):
77
88
  LOG_LEVEL = 'DEBUG'
@@ -92,11 +103,21 @@ def configure():
92
103
  for arg in sys.argv
93
104
  ])[:155]
94
105
 
95
- log_dir = Path(os.getenv("HOME")) / '.local/cli2/log'
96
- log_dir.mkdir(parents=True, exist_ok=True)
97
- ts = datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S')
98
- file_name = f'{sys.argv[0].split("/")[-1]}-{ts}-{cmd}.log'
99
- file_path = log_dir / file_name
106
+ if LOG_FILE == 'auto':
107
+ log_dir = Path(os.getenv("HOME")) / '.local/cli2/log'
108
+ log_dir.mkdir(parents=True, exist_ok=True)
109
+ ts = datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S')
110
+ file_name = f'{sys.argv[0].split("/")[-1]}-{ts}-{cmd}.log'
111
+ LOG_FILE = log_dir / file_name
112
+ elif LOG_FILE == 'none' or not LOG_FILE:
113
+ LOG_FILE = None
114
+ else:
115
+ LOG_FILE = Path(LOG_FILE)
116
+
117
+ handlers = ['default']
118
+ if LOG_FILE:
119
+ handlers.append('file')
120
+
100
121
  LOGGING = {
101
122
  'version': 1,
102
123
  'disable_existing_loggers': True,
@@ -156,16 +177,10 @@ def configure():
156
177
  'class': 'logging.StreamHandler',
157
178
  'formatter': 'colored',
158
179
  },
159
- 'file': {
160
- 'level': 'DEBUG',
161
- 'class': 'logging.handlers.WatchedFileHandler',
162
- 'formatter': 'plain',
163
- 'filename': str(file_path),
164
- },
165
180
  },
166
181
  'loggers': {
167
182
  'cli2': {
168
- 'handlers': ['default', 'file'],
183
+ 'handlers': handlers,
169
184
  'level': 'DEBUG',
170
185
  'propagate': True,
171
186
  }
@@ -175,12 +190,20 @@ def configure():
175
190
  if os.getenv('HTTP_DEBUG'):
176
191
  LOGGING['loggers'].update({
177
192
  key: {
178
- 'handlers': ['default', 'file'],
193
+ 'handlers': handlers,
179
194
  'level': 'DEBUG',
180
195
  'propagate': True,
181
196
  } for key in ('httpx', 'httpcore')
182
197
  })
183
198
 
199
+ if LOG_FILE:
200
+ LOGGING['handlers']['file'] = {
201
+ 'level': 'DEBUG',
202
+ 'class': 'logging.handlers.WatchedFileHandler',
203
+ 'formatter': 'plain',
204
+ 'filename': str(LOG_FILE),
205
+ }
206
+
184
207
  logging.config.dictConfig(LOGGING)
185
208
 
186
209
  structlog.configure(
@@ -19,8 +19,8 @@ class Mask:
19
19
 
20
20
  .. code-block:: python
21
21
 
22
- mask = cli2.Mask(keys=['password'], values=['1337p4ssw0rD'])
23
- result = mask(dict(password='xx', text='some 1337p4ssw0rD noise xx'))
22
+ mask = cli2.Mask(keys=['password'], values=['secretval'])
23
+ result = mask(dict(password='xx', text='some secretval noise xx'))
24
24
 
25
25
  Will cause result to be:
26
26
 
@@ -31,7 +31,7 @@ class Mask:
31
31
 
32
32
  Because:
33
33
 
34
- - ``1337p4ssw0rD`` was given as a value to mask
34
+ - ``secretval`` was given as a value to mask
35
35
  - ``password``'s value because ``password`` was given as a key to match
36
36
  - the Mask object learned the value of the ``password`` key, and masked it
37
37
  in ``text``
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: cli2
3
- Version: 5.0.2
3
+ Version: 5.1.0rc1
4
4
  Summary: image:: https://yourlabs.io/oss/cli2/badges/master/pipeline.svg
5
5
  Home-page: https://yourlabs.io/oss/cli2
6
6
  Author: James Pic
@@ -44,7 +44,7 @@ from setuptools import setup
44
44
 
45
45
  setup(
46
46
  name='cli2',
47
- version='5.0.2',
47
+ version='5.1.0rc1',
48
48
  setup_requires='setupmeta',
49
49
  packages=['cli2'],
50
50
  install_requires=[
@@ -645,10 +645,11 @@ def test_descriptor(client_class):
645
645
  assert model.data['undeclared']['foo'] == 3
646
646
 
647
647
  model = Model()
648
- assert model.foo == ''
648
+ assert model.foo is None
649
+ assert 'foo' not in model._data
649
650
  assert not model.changed_fields
650
651
  model.foo = 'bar'
651
- assert model.changed_fields == dict(foo='')
652
+ assert model.changed_fields == dict(foo=None)
652
653
  model = Model(foo='bar')
653
654
  model.foo = 'foo'
654
655
  assert model.changed_fields == dict(foo='bar')
@@ -1246,3 +1247,54 @@ def test_client_command(client_class, httpx_mock):
1246
1247
  cmd = Client.cli['request']
1247
1248
  cmd()
1248
1249
  assert not Client.post_call_called
1250
+
1251
+
1252
+ def test_field_callback(client_class):
1253
+ class TestModel(client_class.Model):
1254
+ foo = chttpx.Field()
1255
+ bar = chttpx.Field()
1256
+ other = chttpx.Field()
1257
+
1258
+ @other.factory
1259
+ def other_factory(self):
1260
+ return 'nice'
1261
+
1262
+ @bar.factory(foo)
1263
+ def bar_factory(self):
1264
+ return f'bar{self.foo}'
1265
+
1266
+ model = client_class().TestModel(foo='test')
1267
+ assert model.bar == 'bartest'
1268
+ assert model.other == 'nice'
1269
+
1270
+ model = client_class().TestModel(foo='test')
1271
+ assert model.data['bar'] == 'bartest'
1272
+ assert model.data['other'] == 'nice'
1273
+
1274
+ model = client_class().TestModel()
1275
+ assert model.data == dict(other='nice')
1276
+
1277
+ model = client_class().TestModel(bar='lol')
1278
+ assert model.bar == 'lol'
1279
+ assert model.data['bar'] == 'lol'
1280
+
1281
+
1282
+ def test_field_callback_recursion(client_class):
1283
+ class TestModel(client_class.Model):
1284
+ final = chttpx.Field()
1285
+ req2 = chttpx.Field()
1286
+ req1 = chttpx.Field()
1287
+
1288
+ @final.factory(req2)
1289
+ def final_factory(self):
1290
+ return f'{self.req2}val3'
1291
+
1292
+ @req2.factory(req1)
1293
+ def req2_factory(self):
1294
+ return f'{self.req1}val2'
1295
+
1296
+ model = client_class().TestModel(req1='lol')
1297
+ assert model.data['final'] == 'lolval2val3'
1298
+
1299
+ model = client_class().TestModel(req1='lol')
1300
+ assert model.final == 'lolval2val3'
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
File without changes