nuclear 2.1.2__tar.gz → 2.2.2__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.
- {nuclear-2.1.2 → nuclear-2.2.2}/PKG-INFO +17 -8
- {nuclear-2.1.2 → nuclear-2.2.2}/README.md +16 -7
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/inspection/inspection.py +8 -7
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/sublog/context_error.py +1 -1
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/sublog/exception.py +1 -1
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/sublog/logging.py +1 -1
- nuclear-2.2.2/nuclear/utils/collections.py +44 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/utils/config.py +6 -11
- nuclear-2.2.2/nuclear/utils/datamodel.py +45 -0
- nuclear-2.2.2/nuclear/version.py +1 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear.egg-info/PKG-INFO +17 -8
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear.egg-info/requires.txt +1 -1
- nuclear-2.1.2/nuclear/utils/collections.py +0 -4
- nuclear-2.1.2/nuclear/utils/datamodel.py +0 -112
- nuclear-2.1.2/nuclear/version.py +0 -1
- {nuclear-2.1.2 → nuclear-2.2.2}/LICENSE +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/__init__.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/__init__.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/args/__init__.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/args/args_que.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/args/container.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/autocomplete/__init__.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/autocomplete/autocomplete.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/autocomplete/install.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/builder/__init__.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/builder/builder.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/builder/decorator_builder.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/builder/rule.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/builder/rule_factory.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/builder/typedef.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/completers/__init__.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/completers/file.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/help.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/parser/__init__.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/parser/context.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/parser/error.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/parser/inject.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/parser/internal_vars.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/parser/keyword.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/parser/matcher.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/parser/parser.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/parser/transform.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/parser/validate.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/parser/value.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/types/__init__.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/types/boolean.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/types/filesystem.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/cli/types/time.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/inspection/__init__.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/py.typed +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/shell/__init__.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/shell/background_cmd.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/shell/shell_utils.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/sublog/__init__.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/sublog/catch.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/utils/__init__.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/utils/env.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/utils/files.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/utils/functools.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/utils/input.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/utils/regex.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/utils/strings.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/utils/time.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear/utils/url.py +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear.egg-info/SOURCES.txt +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear.egg-info/dependency_links.txt +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/nuclear.egg-info/top_level.txt +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/setup.cfg +0 -0
- {nuclear-2.1.2 → nuclear-2.2.2}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: nuclear
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.2
|
|
4
4
|
Summary: Declarative parser for command line interfaces
|
|
5
5
|
Home-page: https://github.com/igrek51/nuclear
|
|
6
6
|
Author: igrek51
|
|
@@ -115,7 +115,7 @@ you don't even need to install **nuclear** package to use `wat` inspector.
|
|
|
115
115
|
Load it on the fly by pasting this snippet to your Python interpreter:
|
|
116
116
|
```python
|
|
117
117
|
import base64, zlib
|
|
118
|
-
code = 'eJzNWuluG0cS/q+naCg/OLTGjBTvATChd51YcQw4ycJRNjAkYTDkNKWJhzPEHJYVLoE8xD7DPtg+
|
|
118
|
+
code = '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'
|
|
119
119
|
exec(zlib.decompress(base64.b64decode(code.encode())).decode(), globals())
|
|
120
120
|
```
|
|
121
121
|
|
|
@@ -136,13 +136,13 @@ with the following **modifiers**:
|
|
|
136
136
|
- `.nodocs` to hide documentation for functions and classes
|
|
137
137
|
- `.all` to include all available information
|
|
138
138
|
|
|
139
|
-
You can chain modifiers, e.g. `wat.long.dunder / object`.
|
|
139
|
+
You can chain modifiers, e.g. `wat.long.dunder.nodocs / object`.
|
|
140
140
|
|
|
141
141
|
Call `wat()` to inspect `locals()` variables.
|
|
142
142
|
|
|
143
143
|
Type `wat` in the interpreter to learn more about this object itself.
|
|
144
144
|
|
|
145
|
-
## Use
|
|
145
|
+
## Use Cases Examples
|
|
146
146
|
|
|
147
147
|
### Determine type
|
|
148
148
|
In a dynamic typing language like Python, it's often hard to determine the type of an object. WAT Inspector can help you with that by showing the name of the type with the module it comes from.
|
|
@@ -162,12 +162,14 @@ type: django.contrib.auth.models.User
|
|
|
162
162
|
parents: django.contrib.auth.models.AbstractUser, django.contrib.auth.base_user.AbstractBaseUser, django.contrib.auth.models.PermissionsMixin, django.db.models.base.Model, django.db.models.utils.AltersData
|
|
163
163
|
```
|
|
164
164
|
|
|
165
|
+
Now that you've identified the actual type, you can put the type annotations in your code to reduce the confusion.
|
|
166
|
+
|
|
165
167
|
### Look up methods
|
|
166
168
|
Listing methods, functions and looking up their signature is extremely beneficial to see how to use them.
|
|
167
169
|
Plus, you can read their docstrings.
|
|
168
170
|
|
|
169
171
|
```python
|
|
170
|
-
wat
|
|
172
|
+
wat / 'stringy'
|
|
171
173
|
```
|
|
172
174
|
|
|
173
175
|

|
|
@@ -176,13 +178,13 @@ wat('stringy')
|
|
|
176
178
|
See the docstrings and the signature of a function or a method to see how to use it.
|
|
177
179
|
|
|
178
180
|
```python
|
|
179
|
-
wat
|
|
181
|
+
wat / str.split
|
|
180
182
|
```
|
|
181
183
|
|
|
182
184
|

|
|
183
185
|
|
|
184
|
-
### Look up
|
|
185
|
-
|
|
186
|
+
### Look up attributes
|
|
187
|
+
List the attribues and their types to see what's really inside the inspected object.
|
|
186
188
|
```python
|
|
187
189
|
wat / re.match('(\d)_(.*)', '1_title')
|
|
188
190
|
```
|
|
@@ -244,6 +246,13 @@ wat / __builtins__
|
|
|
244
246
|
### Look up local variables
|
|
245
247
|
```python
|
|
246
248
|
wat()
|
|
249
|
+
# or
|
|
250
|
+
wat.locals
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Look up global variables
|
|
254
|
+
```python
|
|
255
|
+
wat.globals
|
|
247
256
|
```
|
|
248
257
|
|
|
249
258
|
|
|
@@ -100,7 +100,7 @@ you don't even need to install **nuclear** package to use `wat` inspector.
|
|
|
100
100
|
Load it on the fly by pasting this snippet to your Python interpreter:
|
|
101
101
|
```python
|
|
102
102
|
import base64, zlib
|
|
103
|
-
code = 'eJzNWuluG0cS/q+naCg/OLTGjBTvATChd51YcQw4ycJRNjAkYTDkNKWJhzPEHJYVLoE8xD7DPtg+
|
|
103
|
+
code = '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'
|
|
104
104
|
exec(zlib.decompress(base64.b64decode(code.encode())).decode(), globals())
|
|
105
105
|
```
|
|
106
106
|
|
|
@@ -121,13 +121,13 @@ with the following **modifiers**:
|
|
|
121
121
|
- `.nodocs` to hide documentation for functions and classes
|
|
122
122
|
- `.all` to include all available information
|
|
123
123
|
|
|
124
|
-
You can chain modifiers, e.g. `wat.long.dunder / object`.
|
|
124
|
+
You can chain modifiers, e.g. `wat.long.dunder.nodocs / object`.
|
|
125
125
|
|
|
126
126
|
Call `wat()` to inspect `locals()` variables.
|
|
127
127
|
|
|
128
128
|
Type `wat` in the interpreter to learn more about this object itself.
|
|
129
129
|
|
|
130
|
-
## Use
|
|
130
|
+
## Use Cases Examples
|
|
131
131
|
|
|
132
132
|
### Determine type
|
|
133
133
|
In a dynamic typing language like Python, it's often hard to determine the type of an object. WAT Inspector can help you with that by showing the name of the type with the module it comes from.
|
|
@@ -147,12 +147,14 @@ type: django.contrib.auth.models.User
|
|
|
147
147
|
parents: django.contrib.auth.models.AbstractUser, django.contrib.auth.base_user.AbstractBaseUser, django.contrib.auth.models.PermissionsMixin, django.db.models.base.Model, django.db.models.utils.AltersData
|
|
148
148
|
```
|
|
149
149
|
|
|
150
|
+
Now that you've identified the actual type, you can put the type annotations in your code to reduce the confusion.
|
|
151
|
+
|
|
150
152
|
### Look up methods
|
|
151
153
|
Listing methods, functions and looking up their signature is extremely beneficial to see how to use them.
|
|
152
154
|
Plus, you can read their docstrings.
|
|
153
155
|
|
|
154
156
|
```python
|
|
155
|
-
wat
|
|
157
|
+
wat / 'stringy'
|
|
156
158
|
```
|
|
157
159
|
|
|
158
160
|

|
|
@@ -161,13 +163,13 @@ wat('stringy')
|
|
|
161
163
|
See the docstrings and the signature of a function or a method to see how to use it.
|
|
162
164
|
|
|
163
165
|
```python
|
|
164
|
-
wat
|
|
166
|
+
wat / str.split
|
|
165
167
|
```
|
|
166
168
|
|
|
167
169
|

|
|
168
170
|
|
|
169
|
-
### Look up
|
|
170
|
-
|
|
171
|
+
### Look up attributes
|
|
172
|
+
List the attribues and their types to see what's really inside the inspected object.
|
|
171
173
|
```python
|
|
172
174
|
wat / re.match('(\d)_(.*)', '1_title')
|
|
173
175
|
```
|
|
@@ -229,6 +231,13 @@ wat / __builtins__
|
|
|
229
231
|
### Look up local variables
|
|
230
232
|
```python
|
|
231
233
|
wat()
|
|
234
|
+
# or
|
|
235
|
+
wat.locals
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Look up global variables
|
|
239
|
+
```python
|
|
240
|
+
wat.globals
|
|
232
241
|
```
|
|
233
242
|
|
|
234
243
|
|
|
@@ -141,7 +141,7 @@ def _iter_attributes(obj: Any, config: InspectConfig) -> Iterable[InspectAttribu
|
|
|
141
141
|
def _get_attribute_value(obj: Any, key: str) -> Any:
|
|
142
142
|
try:
|
|
143
143
|
return getattr(obj, key)
|
|
144
|
-
except
|
|
144
|
+
except BaseException as e:
|
|
145
145
|
return e
|
|
146
146
|
|
|
147
147
|
|
|
@@ -171,8 +171,8 @@ def _get_callable_signature(name: str, obj: Any) -> Optional[str]:
|
|
|
171
171
|
def _get_source_code(obj: Any) -> Optional[str]:
|
|
172
172
|
try:
|
|
173
173
|
return std_inspect.getsource(obj)
|
|
174
|
-
except (OSError, TypeError, IndentationError):
|
|
175
|
-
return
|
|
174
|
+
except (OSError, TypeError, IndentationError) as e:
|
|
175
|
+
return f'failed to get source code: {type(e)}: {e}'
|
|
176
176
|
|
|
177
177
|
|
|
178
178
|
def _get_doc(obj: Any, long: bool) -> Optional[str]:
|
|
@@ -244,9 +244,9 @@ def _format_dict_value(dic: Dict, indent: int) -> str:
|
|
|
244
244
|
return f'{STYLE_YELLOW}{{}}{RESET}'
|
|
245
245
|
|
|
246
246
|
|
|
247
|
-
def _format_list_value(
|
|
247
|
+
def _format_list_value(lst: List, indent: int) -> str:
|
|
248
248
|
lines: List[str] = []
|
|
249
|
-
for value in
|
|
249
|
+
for value in lst:
|
|
250
250
|
value_str = _format_value(value, indent)
|
|
251
251
|
lines.append(' ' * indent + f'{value_str},')
|
|
252
252
|
if lines:
|
|
@@ -362,8 +362,9 @@ Call {STYLE_YELLOW}wat(){RESET} to inspect {STYLE_YELLOW}locals(){RESET} variabl
|
|
|
362
362
|
|
|
363
363
|
def __call__(self, *args: Any, **kwargs: Any) -> Union['Wat', None]:
|
|
364
364
|
if args:
|
|
365
|
-
self._params.
|
|
366
|
-
|
|
365
|
+
new_params = self._params.copy()
|
|
366
|
+
new_params.update(kwargs)
|
|
367
|
+
return inspect(*args, **new_params)
|
|
367
368
|
elif kwargs:
|
|
368
369
|
return Wat(**kwargs)
|
|
369
370
|
else:
|
|
@@ -17,7 +17,7 @@ def exception_details(e: BaseException) -> str:
|
|
|
17
17
|
traceback_str = ', '.join(traceback_lines)
|
|
18
18
|
cause = _root_cause_type(e)
|
|
19
19
|
error_msg = _error_message(e)
|
|
20
|
-
return f'{error_msg}
|
|
20
|
+
return f'{error_msg}, cause={cause}, traceback={traceback_str}'
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
def extended_exception_details(e: BaseException) -> Tuple[str, Dict]:
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from typing import Any, Callable, Iterable, TypeVar, List, Union
|
|
2
|
+
|
|
3
|
+
T = TypeVar('T')
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def chunks(lst: List[T], n: int) -> Iterable[List[T]]:
|
|
7
|
+
"""Yield successive n-sized chunks from lst."""
|
|
8
|
+
for i in range(0, len(lst), n):
|
|
9
|
+
yield lst[i:i + n]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def deduplicate_latest(items: List[T], key: Callable[[T], Any]) -> List[T]:
|
|
13
|
+
"""Deduplicate items in the list by key. Keep the earliest items first, remove the latest duplicates"""
|
|
14
|
+
ids = set()
|
|
15
|
+
dedup_items: List[T] = []
|
|
16
|
+
for item in items:
|
|
17
|
+
ikey = key(item)
|
|
18
|
+
if ikey not in ids:
|
|
19
|
+
ids.add(ikey)
|
|
20
|
+
dedup_items.append(item)
|
|
21
|
+
return dedup_items
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def deduplicate_earliest(items: List[T], key: Callable[[T], Any]) -> List[T]:
|
|
25
|
+
"""Deduplicate items in the list by key. Keep the latest items, remove the earliest duplicates"""
|
|
26
|
+
ids = set()
|
|
27
|
+
dedup_items: List[T] = []
|
|
28
|
+
for item in reversed(items):
|
|
29
|
+
ikey = key(item)
|
|
30
|
+
if ikey not in ids:
|
|
31
|
+
ids.add(ikey)
|
|
32
|
+
dedup_items.append(item)
|
|
33
|
+
return dedup_items[::-1]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def flatten(collection: Iterable[Union[T, List[T]]]) -> List[T]:
|
|
37
|
+
"""Transform a list of lists into a flat list"""
|
|
38
|
+
flat: List[T] = []
|
|
39
|
+
for item in collection:
|
|
40
|
+
if isinstance(item, list):
|
|
41
|
+
flat.extend(flatten(item))
|
|
42
|
+
else:
|
|
43
|
+
flat.append(item)
|
|
44
|
+
return flat
|
|
@@ -1,25 +1,21 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
from typing import
|
|
3
|
+
from typing import Dict
|
|
4
4
|
|
|
5
|
-
from pydantic import BaseModel
|
|
6
5
|
import yaml
|
|
7
6
|
|
|
8
7
|
from nuclear import logger
|
|
9
8
|
|
|
10
|
-
T = TypeVar("T", bound=BaseModel)
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
def load_config(clazz: Type[T]) -> T:
|
|
10
|
+
def load_config() -> Dict:
|
|
14
11
|
"""
|
|
15
12
|
Load general configuration from YAML file given in CONFIG_FILE environment var or load default config.
|
|
16
|
-
:
|
|
17
|
-
:return: configuration object of given "clazz" type
|
|
13
|
+
:return: loaded configuration dictionary object
|
|
18
14
|
"""
|
|
19
15
|
config_file_path = os.environ.get('CONFIG_FILE')
|
|
20
16
|
if not config_file_path:
|
|
21
17
|
logger.warning('CONFIG_FILE unspecified, loading default config')
|
|
22
|
-
return
|
|
18
|
+
return {}
|
|
23
19
|
|
|
24
20
|
path = Path(config_file_path)
|
|
25
21
|
if not path.is_file():
|
|
@@ -28,9 +24,8 @@ def load_config(clazz: Type[T]) -> T:
|
|
|
28
24
|
try:
|
|
29
25
|
with path.open() as file:
|
|
30
26
|
config_dict = yaml.load(file, Loader=yaml.FullLoader)
|
|
31
|
-
config = clazz.model_validate(config_dict)
|
|
32
27
|
|
|
33
|
-
logger.info(f'config loaded from {config_file_path}: {
|
|
34
|
-
return
|
|
28
|
+
logger.info(f'config loaded from {config_file_path}: {config_dict}')
|
|
29
|
+
return config_dict
|
|
35
30
|
except Exception as e:
|
|
36
31
|
raise RuntimeError('loading config failed') from e
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
from datetime import date, datetime
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import PosixPath
|
|
5
|
+
|
|
6
|
+
import yaml
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def to_json(obj) -> str:
|
|
10
|
+
obj = to_json_serializable(obj)
|
|
11
|
+
obj = remove_none(obj)
|
|
12
|
+
return json.dumps(obj)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def to_yaml(obj) -> str:
|
|
16
|
+
obj = to_json_serializable(obj)
|
|
17
|
+
obj = remove_none(obj)
|
|
18
|
+
return yaml.dump(obj, sort_keys=False)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def remove_none(obj):
|
|
22
|
+
"""Remove unwanted null values"""
|
|
23
|
+
if isinstance(obj, list):
|
|
24
|
+
return [remove_none(x) for x in obj if x is not None]
|
|
25
|
+
elif isinstance(obj, dict):
|
|
26
|
+
return {k: remove_none(v) for k, v in obj.items() if k is not None and v is not None}
|
|
27
|
+
else:
|
|
28
|
+
return obj
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def to_json_serializable(obj):
|
|
32
|
+
if dataclasses.is_dataclass(obj):
|
|
33
|
+
return to_json_serializable(dataclasses.asdict(obj))
|
|
34
|
+
elif isinstance(obj, PosixPath):
|
|
35
|
+
return str(obj)
|
|
36
|
+
elif isinstance(obj, (date, datetime)):
|
|
37
|
+
return obj.isoformat()
|
|
38
|
+
elif isinstance(obj, list):
|
|
39
|
+
return [to_json_serializable(x) for x in obj]
|
|
40
|
+
elif isinstance(obj, dict):
|
|
41
|
+
return {k: to_json_serializable(v) for k, v in obj.items()}
|
|
42
|
+
elif hasattr(obj, '__to_json__'):
|
|
43
|
+
return getattr(obj, '__to_json__')()
|
|
44
|
+
else:
|
|
45
|
+
return obj
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.2.2"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: nuclear
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.2
|
|
4
4
|
Summary: Declarative parser for command line interfaces
|
|
5
5
|
Home-page: https://github.com/igrek51/nuclear
|
|
6
6
|
Author: igrek51
|
|
@@ -115,7 +115,7 @@ you don't even need to install **nuclear** package to use `wat` inspector.
|
|
|
115
115
|
Load it on the fly by pasting this snippet to your Python interpreter:
|
|
116
116
|
```python
|
|
117
117
|
import base64, zlib
|
|
118
|
-
code = 'eJzNWuluG0cS/q+naCg/OLTGjBTvATChd51YcQw4ycJRNjAkYTDkNKWJhzPEHJYVLoE8xD7DPtg+
|
|
118
|
+
code = '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'
|
|
119
119
|
exec(zlib.decompress(base64.b64decode(code.encode())).decode(), globals())
|
|
120
120
|
```
|
|
121
121
|
|
|
@@ -136,13 +136,13 @@ with the following **modifiers**:
|
|
|
136
136
|
- `.nodocs` to hide documentation for functions and classes
|
|
137
137
|
- `.all` to include all available information
|
|
138
138
|
|
|
139
|
-
You can chain modifiers, e.g. `wat.long.dunder / object`.
|
|
139
|
+
You can chain modifiers, e.g. `wat.long.dunder.nodocs / object`.
|
|
140
140
|
|
|
141
141
|
Call `wat()` to inspect `locals()` variables.
|
|
142
142
|
|
|
143
143
|
Type `wat` in the interpreter to learn more about this object itself.
|
|
144
144
|
|
|
145
|
-
## Use
|
|
145
|
+
## Use Cases Examples
|
|
146
146
|
|
|
147
147
|
### Determine type
|
|
148
148
|
In a dynamic typing language like Python, it's often hard to determine the type of an object. WAT Inspector can help you with that by showing the name of the type with the module it comes from.
|
|
@@ -162,12 +162,14 @@ type: django.contrib.auth.models.User
|
|
|
162
162
|
parents: django.contrib.auth.models.AbstractUser, django.contrib.auth.base_user.AbstractBaseUser, django.contrib.auth.models.PermissionsMixin, django.db.models.base.Model, django.db.models.utils.AltersData
|
|
163
163
|
```
|
|
164
164
|
|
|
165
|
+
Now that you've identified the actual type, you can put the type annotations in your code to reduce the confusion.
|
|
166
|
+
|
|
165
167
|
### Look up methods
|
|
166
168
|
Listing methods, functions and looking up their signature is extremely beneficial to see how to use them.
|
|
167
169
|
Plus, you can read their docstrings.
|
|
168
170
|
|
|
169
171
|
```python
|
|
170
|
-
wat
|
|
172
|
+
wat / 'stringy'
|
|
171
173
|
```
|
|
172
174
|
|
|
173
175
|

|
|
@@ -176,13 +178,13 @@ wat('stringy')
|
|
|
176
178
|
See the docstrings and the signature of a function or a method to see how to use it.
|
|
177
179
|
|
|
178
180
|
```python
|
|
179
|
-
wat
|
|
181
|
+
wat / str.split
|
|
180
182
|
```
|
|
181
183
|
|
|
182
184
|

|
|
183
185
|
|
|
184
|
-
### Look up
|
|
185
|
-
|
|
186
|
+
### Look up attributes
|
|
187
|
+
List the attribues and their types to see what's really inside the inspected object.
|
|
186
188
|
```python
|
|
187
189
|
wat / re.match('(\d)_(.*)', '1_title')
|
|
188
190
|
```
|
|
@@ -244,6 +246,13 @@ wat / __builtins__
|
|
|
244
246
|
### Look up local variables
|
|
245
247
|
```python
|
|
246
248
|
wat()
|
|
249
|
+
# or
|
|
250
|
+
wat.locals
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Look up global variables
|
|
254
|
+
```python
|
|
255
|
+
wat.globals
|
|
247
256
|
```
|
|
248
257
|
|
|
249
258
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
colorama>=0.4.0
|
|
2
|
-
|
|
2
|
+
PyYAML>=6.0
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import dataclasses
|
|
2
|
-
from datetime import date, datetime
|
|
3
|
-
import json
|
|
4
|
-
from pathlib import Path, PosixPath
|
|
5
|
-
from typing import Dict, List, Type, TypeVar
|
|
6
|
-
|
|
7
|
-
from pydantic import BaseModel
|
|
8
|
-
import yaml
|
|
9
|
-
|
|
10
|
-
T = TypeVar("T", bound=BaseModel)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def parse_dict_datamodel(
|
|
14
|
-
obj_dict: Dict,
|
|
15
|
-
clazz: Type[T],
|
|
16
|
-
) -> T:
|
|
17
|
-
"""
|
|
18
|
-
Cast dict object to expected pydantic model
|
|
19
|
-
:param obj_dict: dict object to be transformed to pydantic.BaseModel
|
|
20
|
-
:param clazz: pydantic.BaseModel type
|
|
21
|
-
"""
|
|
22
|
-
return clazz.model_validate(obj_dict)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def parse_dict_datamodels(
|
|
26
|
-
obj_list: List[Dict],
|
|
27
|
-
clazz: Type[T],
|
|
28
|
-
) -> List[T]:
|
|
29
|
-
"""Cast list of dict objects to expected data model types (pydantic.BaseModel)"""
|
|
30
|
-
return [parse_dict_datamodel(obj_dict, clazz) for obj_dict in obj_list]
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def parse_yaml_datamodel(
|
|
34
|
-
yaml_obj: str,
|
|
35
|
-
clazz: Type[T],
|
|
36
|
-
) -> T:
|
|
37
|
-
"""
|
|
38
|
-
Parse YAML and convert it to expected data model
|
|
39
|
-
:param yaml_obj: YAML string
|
|
40
|
-
:param clazz: pydantic.BaseModel type
|
|
41
|
-
"""
|
|
42
|
-
data = yaml.load(yaml_obj, Loader=yaml.FullLoader)
|
|
43
|
-
if data is None:
|
|
44
|
-
data = {}
|
|
45
|
-
return clazz.model_validate(data)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def parse_yaml_file_datamodel(
|
|
49
|
-
path: Path,
|
|
50
|
-
clazz: Type[T],
|
|
51
|
-
) -> T:
|
|
52
|
-
"""
|
|
53
|
-
Parse YAML file and convert it to expected data model
|
|
54
|
-
:param path: Path to a YAML file
|
|
55
|
-
:param clazz: pydantic.BaseModel type
|
|
56
|
-
"""
|
|
57
|
-
assert path.is_file(), f"File doesn't exist: {path}"
|
|
58
|
-
data = path.read_text()
|
|
59
|
-
return parse_yaml_datamodel(data, clazz)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
def datamodel_to_yaml_str(dt: BaseModel) -> str:
|
|
63
|
-
data_dict = datamodel_to_dict(dt)
|
|
64
|
-
return yaml.dump(data_dict)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def to_json(obj) -> str:
|
|
68
|
-
obj = to_json_serializable(obj)
|
|
69
|
-
obj = remove_none(obj)
|
|
70
|
-
return json.dumps(obj)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def to_yaml(obj) -> str:
|
|
74
|
-
obj = to_json_serializable(obj)
|
|
75
|
-
obj = remove_none(obj)
|
|
76
|
-
return yaml.dump(obj, sort_keys=False)
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
def datamodel_to_dict(dt: BaseModel) -> Dict:
|
|
80
|
-
data_dict = dt.model_dump()
|
|
81
|
-
data_dict = remove_none(data_dict)
|
|
82
|
-
data_dict = to_json_serializable(data_dict)
|
|
83
|
-
return data_dict
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def remove_none(obj):
|
|
87
|
-
"""Remove unwanted null values"""
|
|
88
|
-
if isinstance(obj, list):
|
|
89
|
-
return [remove_none(x) for x in obj if x is not None]
|
|
90
|
-
elif isinstance(obj, dict):
|
|
91
|
-
return {k: remove_none(v) for k, v in obj.items() if k is not None and v is not None}
|
|
92
|
-
else:
|
|
93
|
-
return obj
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
def to_json_serializable(obj):
|
|
97
|
-
if dataclasses.is_dataclass(obj):
|
|
98
|
-
return to_json_serializable(dataclasses.asdict(obj))
|
|
99
|
-
elif isinstance(obj, BaseModel):
|
|
100
|
-
return obj.model_dump()
|
|
101
|
-
elif isinstance(obj, PosixPath):
|
|
102
|
-
return str(obj)
|
|
103
|
-
elif isinstance(obj, (date, datetime)):
|
|
104
|
-
return obj.isoformat()
|
|
105
|
-
elif isinstance(obj, list):
|
|
106
|
-
return [to_json_serializable(x) for x in obj]
|
|
107
|
-
elif isinstance(obj, dict):
|
|
108
|
-
return {k: to_json_serializable(v) for k, v in obj.items()}
|
|
109
|
-
elif hasattr(obj, '__to_json__'):
|
|
110
|
-
return getattr(obj, '__to_json__')()
|
|
111
|
-
else:
|
|
112
|
-
return obj
|
nuclear-2.1.2/nuclear/version.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "2.1.2"
|
|
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
|
|
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
|