oj-toolkit 0.1.8__tar.gz → 0.2.0__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 (36) hide show
  1. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/PKG-INFO +111 -19
  2. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/README.md +109 -18
  3. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/__init__.py +4 -2
  4. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/parsing/__init__.py +3 -3
  5. oj_toolkit-0.2.0/oj_toolkit/parsing/types.py +411 -0
  6. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit.egg-info/PKG-INFO +111 -19
  7. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit.egg-info/requires.txt +1 -0
  8. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/pyproject.toml +4 -2
  9. oj_toolkit-0.1.8/oj_toolkit/parsing/types.py +0 -244
  10. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/LICENSE +0 -0
  11. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/asynchronous/__init__.py +0 -0
  12. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/asynchronous/async_chunks.py +0 -0
  13. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/asynchronous/decorators.py +0 -0
  14. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/console/__init__.py +0 -0
  15. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/console/box.py +0 -0
  16. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/console/colored_text.py +0 -0
  17. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/console/colors.py +0 -0
  18. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/console/status.py +0 -0
  19. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/console/streams.py +0 -0
  20. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/console/table.py +0 -0
  21. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/console/terminal.py +0 -0
  22. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/console/text.py +0 -0
  23. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/data/__init__.py +0 -0
  24. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/data/flex.py +0 -0
  25. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/diagnostics.py +0 -0
  26. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/logging/__init__.py +0 -0
  27. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/logging/config.py +0 -0
  28. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/logging/consts.py +0 -0
  29. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/logging/decorators.py +0 -0
  30. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/logging/formatters.py +0 -0
  31. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/logging/handlers.py +0 -0
  32. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit/parsing/consts.py +0 -0
  33. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit.egg-info/SOURCES.txt +0 -0
  34. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit.egg-info/dependency_links.txt +0 -0
  35. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/oj_toolkit.egg-info/top_level.txt +0 -0
  36. {oj_toolkit-0.1.8 → oj_toolkit-0.2.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oj-toolkit
3
- Version: 0.1.8
3
+ Version: 0.2.0
4
4
  Summary: Centralized shared utilities for ownjoo-org projects: standardized logging config, type validation, data parsing, console output, and async utilities
5
5
  Author-email: Speedy <speedy@ownjoo.org>
6
6
  License: MIT
@@ -22,6 +22,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
22
  Requires-Python: >=3.10
23
23
  Description-Content-Type: text/markdown
24
24
  License-File: LICENSE
25
+ Requires-Dist: jmespath>=1.0
25
26
  Provides-Extra: dev
26
27
  Requires-Dist: pytest>=7.0; extra == "dev"
27
28
  Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
@@ -152,7 +153,7 @@ print(text) # Rendered with ANSI codes
152
153
  ### Parsing & Validation
153
154
 
154
155
  ```python
155
- from oj_toolkit import validate, get_datetime, str_to_list, dig
156
+ from oj_toolkit import validate, get_datetime, str_to_list, dig, dig_many, Digger
156
157
 
157
158
  # Validate and convert types
158
159
  result = validate('123', exp=int, converter=int) # Returns: 123
@@ -167,12 +168,31 @@ dt = get_datetime('2024-01-15T10:30:00') # ISO 8601
167
168
  dt = get_datetime(1705318200) # Unix timestamp
168
169
  dt = get_datetime('Mon, 15 Jan 2024 10:30:00 GMT') # HTTP date
169
170
 
170
- # Extract and validate nested values
171
+ # Extract and validate nested values using a jmespath expression
171
172
  data = {'users': [{'name': 'Alice'}, {'name': 'Bob'}]}
172
- name = dig(data, path=['users', 0, 'name']) # Returns: 'Alice'
173
- name = dig(data, path=['users', 1, 'name'], exp=str) # Returns: 'Bob'
173
+ name = dig(data, path='users[0].name', exp=str) # Returns: 'Alice'
174
+ names = dig(data, path='users[*].name', exp=list) # Returns: ['Alice', 'Bob']
175
+
176
+ # Fallback chain: first matching path wins (handy for optional/renamed fields)
177
+ name = dig(data, path=['users[0].nickname', 'users[0].name'], exp=str) # Returns: 'Alice'
178
+
179
+ # Extract several fields in one call
180
+ fields = dig_many(
181
+ data,
182
+ paths={'first_name': 'users[0].name', 'second_name': 'users[1].name'},
183
+ post_processor=None, # skip validate() and return raw matches
184
+ )
185
+ # Returns: {'first_name': 'Alice', 'second_name': 'Bob'}
186
+
187
+ # Bind a path once, reuse it against many objects
188
+ get_name = Digger(path='name', exp=str, default='')
189
+ [get_name(user) for user in data['users']] # Returns: ['Alice', 'Bob']
174
190
  ```
175
191
 
192
+ > **Note:** `dig()`'s default `post_processor` (`validate()`) only accepts a value if you pass
193
+ > `exp=<type>` -- without it, validation always fails and you get `default` back (`None` unless set).
194
+ > Pass `exp=` for a real value, or `post_processor=None` to skip validation and get the raw match.
195
+
176
196
  ### Logging Setup
177
197
 
178
198
  Call `configure_logging` once at application startup (Lambda handler, CLI `main()`, FastAPI lifespan). Libraries should never call it — they only use `logging.getLogger(__name__)`.
@@ -770,19 +790,37 @@ get_datetime('Mon, 15 Jan 2024 10:30:00 GMT') # HTTP date
770
790
  get_datetime('01/15/2024 10:30:00', format_str='%m/%d/%Y %H:%M:%S') # Custom
771
791
  ```
772
792
 
773
- #### `dig(src, path=None, post_processor=validate, **kwargs)`
774
-
775
- Extract and post-process a value from a nested data structure.
793
+ #### `dig(src, path=None, pop=False, post_processor=validate, **kwargs)`
776
794
 
777
- Recursively navigates through nested dicts and lists using a path of keys/indices.
795
+ Extract and post-process a value from a nested data structure, using [jmespath](https://jmespath.org/)
796
+ under the hood (`jmespath` is a required dependency).
778
797
 
779
798
  - **Parameters:**
780
- - `src` (Union[dict, Iterable]): Data structure to navigate
781
- - `path` (Union[None, int, list, str]): List of keys/indices to navigate. Example: ['data', 0, 'value']
782
- - `post_processor` (Callable): Function to post-process the found value. Default: validate()
783
- - `**kwargs`: Passed to post_processor
784
-
785
- - **Returns:** Post-processed value, or None if extraction fails
799
+ - `src` (Mapping | Sequence): Data structure to navigate
800
+ - `path` (int | str | list | None):
801
+ - `str` a jmespath expression, e.g. `'users[0].name'`, `'users[*].name'`, `'users[?id==\`2\`].name'`
802
+ - `int` shorthand for a single top-level index, e.g. `1` is equivalent to `'[1]'`
803
+ - `list[int | str]` — a fallback chain: each candidate is tried in order and the first
804
+ one whose result isn't `None` wins (handy for optional/renamed fields)
805
+ - `None` — treat `src` itself as the value to post-process
806
+ - `pop` (bool): If `True`, delete the terminal key/index of the *winning* expression from
807
+ its container after extracting the value (mutates `src` in place). Only honored when that
808
+ expression's terminal segment is unambiguous (no wildcards, filters, or projections) --
809
+ otherwise it's refused with a logged warning and the value is still returned unpopped.
810
+ - `post_processor` (Callable): Function to post-process the found value. Default: `validate()`.
811
+ Pass `None` to skip post-processing and get the raw match.
812
+ - `**kwargs`: Passed to `post_processor`
813
+
814
+ - **Returns:** Post-processed value, or `None` if extraction fails, no candidate path matches, or
815
+ no post-processor is specified and nothing was found
816
+
817
+ > **Type checkers:** pass `exp=<type>` to get a precise `<type> | None` return type instead of `Any`
818
+ > (`dig(data, path='...', exp=str)` type-checks as `str | None`). Passing `post_processor=None` types
819
+ > as `Any` (raw, unvalidated value). A custom `post_processor` types as that callable's own return type.
820
+
821
+ > **Passing no `exp`:** the default `validate()` post-processor only accepts a value when you give
822
+ > it `exp=<type>` -- without one, validation always fails and you get `default` back (`None` unless
823
+ > set). Either pass `exp=`, or `post_processor=None` to bypass validation entirely.
786
824
 
787
825
  **Example:**
788
826
 
@@ -797,16 +835,70 @@ data = {
797
835
  }
798
836
 
799
837
  # Extract nested value
800
- name = dig(data, path=['response', 'users', 0, 'name'])
838
+ name = dig(data, path='response.users[0].name', exp=str)
801
839
  # Returns: 'Alice'
802
840
 
803
841
  # Extract with validation
804
- user = dig(data, path=['response', 'users', 1], exp=dict)
842
+ user = dig(data, path='response.users[1]', exp=dict)
805
843
  # Returns: {'id': 2, 'name': 'Bob'}
806
844
 
807
- # Extract with custom post-processor
808
- count = dig(data, path=['response', 'users'], post_processor=len)
845
+ # Extract with custom post-processor (no exp needed -- len() isn't validate())
846
+ count = dig(data, path='response.users', post_processor=len)
809
847
  # Returns: 2
848
+
849
+ # jmespath's full expression syntax is available -- wildcards, filters, functions, etc.
850
+ names = dig(data, path='response.users[*].name', exp=list)
851
+ # Returns: ['Alice', 'Bob']
852
+
853
+ # Fallback chain: try a renamed/optional field first, fall back to the old one
854
+ name = dig(data, path=['response.users[0].display_name', 'response.users[0].name'], exp=str)
855
+ # Returns: 'Alice'
856
+ ```
857
+
858
+ #### `dig_many(src, paths, **common_kwargs)`
859
+
860
+ Extract several named fields from `src` in one call.
861
+
862
+ - **Parameters:**
863
+ - `src` (Mapping | Sequence): Data structure to navigate
864
+ - `paths` (Mapping[str, Any]): Maps an output key to either a `dig()` path (uses
865
+ `common_kwargs`) or a dict of `dig()` kwargs (must include `'path'`) overriding
866
+ `common_kwargs` for just that key
867
+ - `**common_kwargs`: Default `dig()` kwargs (`exp`, `default`, `converter`, `validator`,
868
+ `post_processor`, `pop`) applied to every key that doesn't override them
869
+
870
+ - **Returns:** A dict with the same keys as `paths`, each value produced by the corresponding `dig()` call
871
+
872
+ **Example:**
873
+
874
+ ```python
875
+ data = {'user': {'name': 'Alice', 'age': '30'}}
876
+
877
+ fields = dig_many(
878
+ data,
879
+ paths={
880
+ 'name': 'user.name',
881
+ 'age': {'path': 'user.age', 'exp': int, 'converter': int},
882
+ },
883
+ exp=str,
884
+ )
885
+ # Returns: {'name': 'Alice', 'age': 30}
886
+ ```
887
+
888
+ #### `Digger(path=None, pop=False, post_processor=validate, **kwargs)`
889
+
890
+ A pre-bound, reusable `dig()` call. Validates/compiles the jmespath expression once at
891
+ construction (failing fast on a bad expression instead of on first use), then can be called
892
+ like a function against any number of `src` objects without repeating `path`/`exp`/kwargs.
893
+
894
+ **Example:**
895
+
896
+ ```python
897
+ records = [{'user': {'name': 'Alice'}}, {'user': {'name': 'Bob'}}]
898
+
899
+ get_name = Digger(path='user.name', exp=str, default='')
900
+ [get_name(record) for record in records]
901
+ # Returns: ['Alice', 'Bob']
810
902
  ```
811
903
 
812
904
  ### `data` Module
@@ -118,7 +118,7 @@ print(text) # Rendered with ANSI codes
118
118
  ### Parsing & Validation
119
119
 
120
120
  ```python
121
- from oj_toolkit import validate, get_datetime, str_to_list, dig
121
+ from oj_toolkit import validate, get_datetime, str_to_list, dig, dig_many, Digger
122
122
 
123
123
  # Validate and convert types
124
124
  result = validate('123', exp=int, converter=int) # Returns: 123
@@ -133,12 +133,31 @@ dt = get_datetime('2024-01-15T10:30:00') # ISO 8601
133
133
  dt = get_datetime(1705318200) # Unix timestamp
134
134
  dt = get_datetime('Mon, 15 Jan 2024 10:30:00 GMT') # HTTP date
135
135
 
136
- # Extract and validate nested values
136
+ # Extract and validate nested values using a jmespath expression
137
137
  data = {'users': [{'name': 'Alice'}, {'name': 'Bob'}]}
138
- name = dig(data, path=['users', 0, 'name']) # Returns: 'Alice'
139
- name = dig(data, path=['users', 1, 'name'], exp=str) # Returns: 'Bob'
138
+ name = dig(data, path='users[0].name', exp=str) # Returns: 'Alice'
139
+ names = dig(data, path='users[*].name', exp=list) # Returns: ['Alice', 'Bob']
140
+
141
+ # Fallback chain: first matching path wins (handy for optional/renamed fields)
142
+ name = dig(data, path=['users[0].nickname', 'users[0].name'], exp=str) # Returns: 'Alice'
143
+
144
+ # Extract several fields in one call
145
+ fields = dig_many(
146
+ data,
147
+ paths={'first_name': 'users[0].name', 'second_name': 'users[1].name'},
148
+ post_processor=None, # skip validate() and return raw matches
149
+ )
150
+ # Returns: {'first_name': 'Alice', 'second_name': 'Bob'}
151
+
152
+ # Bind a path once, reuse it against many objects
153
+ get_name = Digger(path='name', exp=str, default='')
154
+ [get_name(user) for user in data['users']] # Returns: ['Alice', 'Bob']
140
155
  ```
141
156
 
157
+ > **Note:** `dig()`'s default `post_processor` (`validate()`) only accepts a value if you pass
158
+ > `exp=<type>` -- without it, validation always fails and you get `default` back (`None` unless set).
159
+ > Pass `exp=` for a real value, or `post_processor=None` to skip validation and get the raw match.
160
+
142
161
  ### Logging Setup
143
162
 
144
163
  Call `configure_logging` once at application startup (Lambda handler, CLI `main()`, FastAPI lifespan). Libraries should never call it — they only use `logging.getLogger(__name__)`.
@@ -736,19 +755,37 @@ get_datetime('Mon, 15 Jan 2024 10:30:00 GMT') # HTTP date
736
755
  get_datetime('01/15/2024 10:30:00', format_str='%m/%d/%Y %H:%M:%S') # Custom
737
756
  ```
738
757
 
739
- #### `dig(src, path=None, post_processor=validate, **kwargs)`
740
-
741
- Extract and post-process a value from a nested data structure.
758
+ #### `dig(src, path=None, pop=False, post_processor=validate, **kwargs)`
742
759
 
743
- Recursively navigates through nested dicts and lists using a path of keys/indices.
760
+ Extract and post-process a value from a nested data structure, using [jmespath](https://jmespath.org/)
761
+ under the hood (`jmespath` is a required dependency).
744
762
 
745
763
  - **Parameters:**
746
- - `src` (Union[dict, Iterable]): Data structure to navigate
747
- - `path` (Union[None, int, list, str]): List of keys/indices to navigate. Example: ['data', 0, 'value']
748
- - `post_processor` (Callable): Function to post-process the found value. Default: validate()
749
- - `**kwargs`: Passed to post_processor
750
-
751
- - **Returns:** Post-processed value, or None if extraction fails
764
+ - `src` (Mapping | Sequence): Data structure to navigate
765
+ - `path` (int | str | list | None):
766
+ - `str` a jmespath expression, e.g. `'users[0].name'`, `'users[*].name'`, `'users[?id==\`2\`].name'`
767
+ - `int` shorthand for a single top-level index, e.g. `1` is equivalent to `'[1]'`
768
+ - `list[int | str]` — a fallback chain: each candidate is tried in order and the first
769
+ one whose result isn't `None` wins (handy for optional/renamed fields)
770
+ - `None` — treat `src` itself as the value to post-process
771
+ - `pop` (bool): If `True`, delete the terminal key/index of the *winning* expression from
772
+ its container after extracting the value (mutates `src` in place). Only honored when that
773
+ expression's terminal segment is unambiguous (no wildcards, filters, or projections) --
774
+ otherwise it's refused with a logged warning and the value is still returned unpopped.
775
+ - `post_processor` (Callable): Function to post-process the found value. Default: `validate()`.
776
+ Pass `None` to skip post-processing and get the raw match.
777
+ - `**kwargs`: Passed to `post_processor`
778
+
779
+ - **Returns:** Post-processed value, or `None` if extraction fails, no candidate path matches, or
780
+ no post-processor is specified and nothing was found
781
+
782
+ > **Type checkers:** pass `exp=<type>` to get a precise `<type> | None` return type instead of `Any`
783
+ > (`dig(data, path='...', exp=str)` type-checks as `str | None`). Passing `post_processor=None` types
784
+ > as `Any` (raw, unvalidated value). A custom `post_processor` types as that callable's own return type.
785
+
786
+ > **Passing no `exp`:** the default `validate()` post-processor only accepts a value when you give
787
+ > it `exp=<type>` -- without one, validation always fails and you get `default` back (`None` unless
788
+ > set). Either pass `exp=`, or `post_processor=None` to bypass validation entirely.
752
789
 
753
790
  **Example:**
754
791
 
@@ -763,16 +800,70 @@ data = {
763
800
  }
764
801
 
765
802
  # Extract nested value
766
- name = dig(data, path=['response', 'users', 0, 'name'])
803
+ name = dig(data, path='response.users[0].name', exp=str)
767
804
  # Returns: 'Alice'
768
805
 
769
806
  # Extract with validation
770
- user = dig(data, path=['response', 'users', 1], exp=dict)
807
+ user = dig(data, path='response.users[1]', exp=dict)
771
808
  # Returns: {'id': 2, 'name': 'Bob'}
772
809
 
773
- # Extract with custom post-processor
774
- count = dig(data, path=['response', 'users'], post_processor=len)
810
+ # Extract with custom post-processor (no exp needed -- len() isn't validate())
811
+ count = dig(data, path='response.users', post_processor=len)
775
812
  # Returns: 2
813
+
814
+ # jmespath's full expression syntax is available -- wildcards, filters, functions, etc.
815
+ names = dig(data, path='response.users[*].name', exp=list)
816
+ # Returns: ['Alice', 'Bob']
817
+
818
+ # Fallback chain: try a renamed/optional field first, fall back to the old one
819
+ name = dig(data, path=['response.users[0].display_name', 'response.users[0].name'], exp=str)
820
+ # Returns: 'Alice'
821
+ ```
822
+
823
+ #### `dig_many(src, paths, **common_kwargs)`
824
+
825
+ Extract several named fields from `src` in one call.
826
+
827
+ - **Parameters:**
828
+ - `src` (Mapping | Sequence): Data structure to navigate
829
+ - `paths` (Mapping[str, Any]): Maps an output key to either a `dig()` path (uses
830
+ `common_kwargs`) or a dict of `dig()` kwargs (must include `'path'`) overriding
831
+ `common_kwargs` for just that key
832
+ - `**common_kwargs`: Default `dig()` kwargs (`exp`, `default`, `converter`, `validator`,
833
+ `post_processor`, `pop`) applied to every key that doesn't override them
834
+
835
+ - **Returns:** A dict with the same keys as `paths`, each value produced by the corresponding `dig()` call
836
+
837
+ **Example:**
838
+
839
+ ```python
840
+ data = {'user': {'name': 'Alice', 'age': '30'}}
841
+
842
+ fields = dig_many(
843
+ data,
844
+ paths={
845
+ 'name': 'user.name',
846
+ 'age': {'path': 'user.age', 'exp': int, 'converter': int},
847
+ },
848
+ exp=str,
849
+ )
850
+ # Returns: {'name': 'Alice', 'age': 30}
851
+ ```
852
+
853
+ #### `Digger(path=None, pop=False, post_processor=validate, **kwargs)`
854
+
855
+ A pre-bound, reusable `dig()` call. Validates/compiles the jmespath expression once at
856
+ construction (failing fast on a bad expression instead of on first use), then can be called
857
+ like a function against any number of `src` objects without repeating `path`/`exp`/kwargs.
858
+
859
+ **Example:**
860
+
861
+ ```python
862
+ records = [{'user': {'name': 'Alice'}}, {'user': {'name': 'Bob'}}]
863
+
864
+ get_name = Digger(path='user.name', exp=str, default='')
865
+ [get_name(record) for record in records]
866
+ # Returns: ['Alice', 'Bob']
776
867
  ```
777
868
 
778
869
  ### `data` Module
@@ -11,7 +11,7 @@ Centralized utilities for all ownjoo-org projects, including:
11
11
  error can disappear silently (diagnostics module)
12
12
 
13
13
  Usage:
14
- from oj_toolkit import validate, get_datetime, str_to_list, dig
14
+ from oj_toolkit import validate, get_datetime, str_to_list, dig, dig_many, Digger
15
15
  from oj_toolkit import timed_generator, timed_async_generator
16
16
  from oj_toolkit import Output, Color, ColoredText
17
17
  from oj_toolkit import Table, Box, status_line, progress_bar
@@ -33,7 +33,7 @@ from oj_toolkit.console import (
33
33
  )
34
34
  from oj_toolkit.diagnostics import install_exception_visibility
35
35
  from oj_toolkit.logging import timed_async_generator, timed_generator
36
- from oj_toolkit.parsing import validate, get_datetime, dig, str_to_list
36
+ from oj_toolkit.parsing import validate, get_datetime, dig, dig_many, Digger, str_to_list
37
37
 
38
38
  __all__ = [
39
39
  'timed_async_generator',
@@ -42,6 +42,8 @@ __all__ = [
42
42
  'validate',
43
43
  'get_datetime',
44
44
  'dig',
45
+ 'dig_many',
46
+ 'Digger',
45
47
  'str_to_list',
46
48
  'Output',
47
49
  'Color',
@@ -4,9 +4,9 @@ Provides functions for:
4
4
  - Converting strings to lists with custom separators
5
5
  - Parsing datetime values from multiple formats
6
6
  - Validating and converting values with custom validators and converters
7
- - Extracting and validating nested values from dicts/lists
7
+ - Extracting and validating nested values from dicts/lists (jmespath-backed)
8
8
  """
9
9
 
10
- from oj_toolkit.parsing.types import validate, get_datetime, dig, str_to_list
10
+ from oj_toolkit.parsing.types import validate, get_datetime, dig, dig_many, Digger, str_to_list
11
11
 
12
- __all__ = ['validate', 'get_datetime', 'dig', 'str_to_list']
12
+ __all__ = ['validate', 'get_datetime', 'dig', 'dig_many', 'Digger', 'str_to_list']