dotted-notation 0.49.1__tar.gz → 0.49.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.
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/CHANGELOG.md +15 -0
- {dotted_notation-0.49.1/dotted_notation.egg-info → dotted_notation-0.49.2}/PKG-INFO +18 -4
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/README.md +17 -3
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/access.py +3 -2
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/api.py +5 -4
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/base.py +60 -6
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/filters.py +1 -1
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/results.py +8 -7
- {dotted_notation-0.49.1 → dotted_notation-0.49.2/dotted_notation.egg-info}/PKG-INFO +18 -4
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/pyproject.toml +1 -1
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/LICENSE +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/MANIFEST.in +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/__init__.py +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/__main__.py +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/access.pxd +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/base.pxd +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/cli/__init__.py +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/cli/_compat.py +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/cli/formats.py +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/cli/main.py +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/containers.py +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/engine.pxd +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/engine.py +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/filters.pxd +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/grammar.py +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/groups.pxd +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/groups.py +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/matchers.pxd +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/matchers.py +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/native.py +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/predicates.py +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/recursive.pxd +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/recursive.py +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/sql/__init__.py +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/sql/core.py +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/sql/pg.py +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/transforms.py +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/utils.py +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/utypes.py +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/wrappers.pxd +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted/wrappers.py +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted_notation.egg-info/SOURCES.txt +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted_notation.egg-info/dependency_links.txt +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted_notation.egg-info/entry_points.txt +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted_notation.egg-info/requires.txt +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted_notation.egg-info/top_level.txt +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/setup.cfg +0 -0
- {dotted_notation-0.49.1 → dotted_notation-0.49.2}/setup.py +0 -0
|
@@ -3,6 +3,21 @@
|
|
|
3
3
|
All notable changes to `dotted` are recorded here. Versions prior to
|
|
4
4
|
the ones listed are omitted — browse git history for earlier entries.
|
|
5
5
|
|
|
6
|
+
## [0.49.2]
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
- `ReferenceResolver.literals` may name the positions a resolver is
|
|
10
|
+
offered plain tokens in, as a list or tuple of `'segments'`,
|
|
11
|
+
`'transforms'`, `'guards'` and `'filters'`. A host whose variables are
|
|
12
|
+
sigiled arguments, `|add:^fee`, leaves `'segments'` out and no longer
|
|
13
|
+
pays a call per key (#63); `get` then keeps its fast path for a plain
|
|
14
|
+
chain of keys. An unknown name is a `ValueError`. `True` and `False`
|
|
15
|
+
are unchanged.
|
|
16
|
+
- `ReferenceResolver(literals=...)` sets `literals` per instance,
|
|
17
|
+
overriding the class's, so a resolver need not be subclassed only to
|
|
18
|
+
change it. A subclass with its own `__init__` passes it on with
|
|
19
|
+
`super().__init__(literals)`.
|
|
20
|
+
|
|
6
21
|
## [0.49.1]
|
|
7
22
|
|
|
8
23
|
### Documentation
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dotted_notation
|
|
3
|
-
Version: 0.49.
|
|
3
|
+
Version: 0.49.2
|
|
4
4
|
Summary: Dotted notation for safe nested data traversal with optional chaining, pattern matching, and transforms
|
|
5
5
|
Author-email: Frey Waid <logophage1@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -1677,14 +1677,16 @@ claim some references and leave the rest:
|
|
|
1677
1677
|
>>> dotted.get({'amount': 10}, 'amount|sub:$$(lots.taken)', resolver=Store(store))
|
|
1678
1678
|
7
|
|
1679
1679
|
|
|
1680
|
-
A resolver
|
|
1681
|
-
those positions, so a host sigil such as `$sel` can be a variable.
|
|
1680
|
+
A resolver with `literals = True` is also offered every plain token in
|
|
1681
|
+
those positions, so a host sigil such as `$sel` can be a variable. Set it on
|
|
1682
|
+
the class, or per instance with `literals=` on the constructor. Return
|
|
1682
1683
|
`ref.value` to leave a token the literal it is; a key the resolver answers
|
|
1683
1684
|
is not offered again:
|
|
1684
1685
|
|
|
1685
1686
|
>>> class Sigils(dotted.ReferenceResolver):
|
|
1686
1687
|
... literals = True
|
|
1687
|
-
... def __init__(self, names):
|
|
1688
|
+
... def __init__(self, names, literals=None):
|
|
1689
|
+
... super().__init__(literals)
|
|
1688
1690
|
... self.names = names
|
|
1689
1691
|
... def resolve(self, ref, settings, node=None, parents=()):
|
|
1690
1692
|
... if ref.is_reference():
|
|
@@ -1696,6 +1698,18 @@ is not offered again:
|
|
|
1696
1698
|
>>> dotted.get(users, 'users[*&name=$sel].name', resolver=Sigils({'$sel': 'bob'}))
|
|
1697
1699
|
('bob',)
|
|
1698
1700
|
|
|
1701
|
+
`literals` may instead name the positions it wants, as a list or tuple of
|
|
1702
|
+
`'segments'` (key, slot and attr segments), `'transforms'` (transform
|
|
1703
|
+
arguments), `'guards'` (guard values) and `'filters'` (filter values). A host
|
|
1704
|
+
whose variables only ever stand as arguments leaves `'segments'` out, so the
|
|
1705
|
+
keys of a path cost no call:
|
|
1706
|
+
|
|
1707
|
+
>>> r = Sigils({'$inc': 3}, literals=('transforms', 'guards', 'filters'))
|
|
1708
|
+
>>> dotted.get({'n': 5}, 'n|add:$inc', resolver=r)
|
|
1709
|
+
8
|
|
1710
|
+
|
|
1711
|
+
An unknown name is a `ValueError`, on the class or the constructor.
|
|
1712
|
+
|
|
1699
1713
|
A host variable may span several segments, `$amount.value`, which dotted has
|
|
1700
1714
|
parsed as two. The path-level hook `fold(segments)` is called once with a
|
|
1701
1715
|
path's segment strings, `('$amount', 'value')`, and returns the runs it
|
|
@@ -1630,14 +1630,16 @@ claim some references and leave the rest:
|
|
|
1630
1630
|
>>> dotted.get({'amount': 10}, 'amount|sub:$$(lots.taken)', resolver=Store(store))
|
|
1631
1631
|
7
|
|
1632
1632
|
|
|
1633
|
-
A resolver
|
|
1634
|
-
those positions, so a host sigil such as `$sel` can be a variable.
|
|
1633
|
+
A resolver with `literals = True` is also offered every plain token in
|
|
1634
|
+
those positions, so a host sigil such as `$sel` can be a variable. Set it on
|
|
1635
|
+
the class, or per instance with `literals=` on the constructor. Return
|
|
1635
1636
|
`ref.value` to leave a token the literal it is; a key the resolver answers
|
|
1636
1637
|
is not offered again:
|
|
1637
1638
|
|
|
1638
1639
|
>>> class Sigils(dotted.ReferenceResolver):
|
|
1639
1640
|
... literals = True
|
|
1640
|
-
... def __init__(self, names):
|
|
1641
|
+
... def __init__(self, names, literals=None):
|
|
1642
|
+
... super().__init__(literals)
|
|
1641
1643
|
... self.names = names
|
|
1642
1644
|
... def resolve(self, ref, settings, node=None, parents=()):
|
|
1643
1645
|
... if ref.is_reference():
|
|
@@ -1649,6 +1651,18 @@ is not offered again:
|
|
|
1649
1651
|
>>> dotted.get(users, 'users[*&name=$sel].name', resolver=Sigils({'$sel': 'bob'}))
|
|
1650
1652
|
('bob',)
|
|
1651
1653
|
|
|
1654
|
+
`literals` may instead name the positions it wants, as a list or tuple of
|
|
1655
|
+
`'segments'` (key, slot and attr segments), `'transforms'` (transform
|
|
1656
|
+
arguments), `'guards'` (guard values) and `'filters'` (filter values). A host
|
|
1657
|
+
whose variables only ever stand as arguments leaves `'segments'` out, so the
|
|
1658
|
+
keys of a path cost no call:
|
|
1659
|
+
|
|
1660
|
+
>>> r = Sigils({'$inc': 3}, literals=('transforms', 'guards', 'filters'))
|
|
1661
|
+
>>> dotted.get({'n': 5}, 'n|add:$inc', resolver=r)
|
|
1662
|
+
8
|
|
1663
|
+
|
|
1664
|
+
An unknown name is a `ValueError`, on the class or the constructor.
|
|
1665
|
+
|
|
1652
1666
|
A host variable may span several segments, `$amount.value`, which dotted has
|
|
1653
1667
|
parsed as two. The path-level hook `fold(segments)` is called once with a
|
|
1654
1668
|
path's segment strings, `('$amount', 'value')`, and returns the runs it
|
|
@@ -251,11 +251,12 @@ class AccessOp(SimpleOp):
|
|
|
251
251
|
def _offered(self, settings):
|
|
252
252
|
"""
|
|
253
253
|
True if the match op goes to the resolver: a reference, or a
|
|
254
|
-
plain constant when the resolver in force takes literals
|
|
254
|
+
plain constant when the resolver in force takes literals in path
|
|
255
|
+
segments.
|
|
255
256
|
"""
|
|
256
257
|
if self.op.is_reference():
|
|
257
258
|
return True
|
|
258
|
-
return (settings.literals() and isinstance(self.op, matchers.Const)
|
|
259
|
+
return (settings.literals('segments') and isinstance(self.op, matchers.Const)
|
|
259
260
|
and not isinstance(self.op, matchers.ResolvedValue))
|
|
260
261
|
|
|
261
262
|
def resolve(self, bindings, partial=False):
|
|
@@ -448,9 +448,11 @@ def build(obj, path, strict=False, bindings=None, resolver=None):
|
|
|
448
448
|
def _literals(resolver):
|
|
449
449
|
"""
|
|
450
450
|
True if the resolver a call will run under, its own or the process
|
|
451
|
-
default, takes plain tokens: the simple fast path must
|
|
451
|
+
default, takes plain tokens in path segments: the simple fast path must
|
|
452
|
+
then step aside. Other positions it can serve, as its transforms
|
|
453
|
+
resolve through Settings.
|
|
452
454
|
"""
|
|
453
|
-
return (base.RESOLVER if resolver is None else resolver)
|
|
455
|
+
return base.takes_literals(base.RESOLVER if resolver is None else resolver, 'segments')
|
|
454
456
|
|
|
455
457
|
|
|
456
458
|
def _prepare(ops, resolver):
|
|
@@ -1365,12 +1367,11 @@ def set_resolver(resolver=None):
|
|
|
1365
1367
|
restores dotted's own (see Resolver).
|
|
1366
1368
|
>>> import dotted
|
|
1367
1369
|
>>> class Upper(dotted.ReferenceResolver):
|
|
1368
|
-
... literals = True
|
|
1369
1370
|
... def resolve(self, ref, settings, node=None, parents=()):
|
|
1370
1371
|
... if ref.is_reference():
|
|
1371
1372
|
... return super().resolve(ref, settings, node, parents)
|
|
1372
1373
|
... return ref.value.upper()
|
|
1373
|
-
>>> dotted.set_resolver(Upper())
|
|
1374
|
+
>>> dotted.set_resolver(Upper(literals=True))
|
|
1374
1375
|
>>> dotted.get({'A': 1}, 'a')
|
|
1375
1376
|
1
|
|
1376
1377
|
>>> dotted.set_resolver()
|
|
@@ -149,6 +149,12 @@ class NOP(metaclass=MetaNOP):
|
|
|
149
149
|
return False
|
|
150
150
|
|
|
151
151
|
|
|
152
|
+
# The positions a resolver may be offered plain tokens in, named in its
|
|
153
|
+
# literals: key, slot and attr segments, transform arguments, guard values
|
|
154
|
+
# and filter values.
|
|
155
|
+
LITERALS = ('segments', 'transforms', 'guards', 'filters')
|
|
156
|
+
|
|
157
|
+
|
|
152
158
|
class Resolver:
|
|
153
159
|
"""
|
|
154
160
|
What a reference means at run time. Every $$(path) a traversal meets,
|
|
@@ -161,10 +167,30 @@ class Resolver:
|
|
|
161
167
|
|
|
162
168
|
# True to be offered every plain token in a var-permitting position as
|
|
163
169
|
# well: key, slot and attr segments, transform arguments, guard and
|
|
164
|
-
# filter values.
|
|
165
|
-
#
|
|
170
|
+
# filter values. A list or tuple of LITERALS names to be offered them in
|
|
171
|
+
# those positions only, ('transforms', 'guards', 'filters') to leave
|
|
172
|
+
# segments out. The host decides which are its variables; returning
|
|
173
|
+
# ref.value leaves a token the literal it is. Set here, on a subclass,
|
|
174
|
+
# or per instance with literals=.
|
|
166
175
|
literals = False
|
|
167
176
|
|
|
177
|
+
def __init_subclass__(cls, **kwargs):
|
|
178
|
+
"""
|
|
179
|
+
Check a subclass's literals (see check_literals).
|
|
180
|
+
"""
|
|
181
|
+
super().__init_subclass__(**kwargs)
|
|
182
|
+
check_literals(cls.literals)
|
|
183
|
+
|
|
184
|
+
def __init__(self, literals=None):
|
|
185
|
+
"""
|
|
186
|
+
literals, when given, overrides the class's for this instance (see
|
|
187
|
+
check_literals).
|
|
188
|
+
"""
|
|
189
|
+
if literals is None:
|
|
190
|
+
return
|
|
191
|
+
check_literals(literals)
|
|
192
|
+
self.literals = literals
|
|
193
|
+
|
|
168
194
|
def fold(self, segments):
|
|
169
195
|
"""
|
|
170
196
|
The path-level hook, called once with a path's segment strings
|
|
@@ -211,6 +237,33 @@ class Resolver:
|
|
|
211
237
|
RESOLVER = Resolver()
|
|
212
238
|
|
|
213
239
|
|
|
240
|
+
def check_literals(literals):
|
|
241
|
+
"""
|
|
242
|
+
Raise unless literals is True, False, or a list or tuple of LITERALS
|
|
243
|
+
names.
|
|
244
|
+
"""
|
|
245
|
+
if isinstance(literals, bool):
|
|
246
|
+
return
|
|
247
|
+
if not isinstance(literals, (list, tuple)):
|
|
248
|
+
raise TypeError(f'literals is True, False or a list or tuple of {LITERALS}, not {literals!r}')
|
|
249
|
+
unknown = [name for name in literals if name not in LITERALS]
|
|
250
|
+
if unknown:
|
|
251
|
+
raise ValueError(f'literals names {unknown}, not among {LITERALS}')
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def takes_literals(resolver, position):
|
|
255
|
+
"""
|
|
256
|
+
True if resolver takes plain tokens at position, one of LITERALS: its
|
|
257
|
+
literals is True, or names it.
|
|
258
|
+
"""
|
|
259
|
+
lit = resolver.literals
|
|
260
|
+
if lit is True:
|
|
261
|
+
return True
|
|
262
|
+
if not lit:
|
|
263
|
+
return False
|
|
264
|
+
return position in lit
|
|
265
|
+
|
|
266
|
+
|
|
214
267
|
class Settings:
|
|
215
268
|
"""
|
|
216
269
|
What holds for the whole of one traversal: the root node, the chain of
|
|
@@ -242,11 +295,12 @@ class Settings:
|
|
|
242
295
|
"""
|
|
243
296
|
return RESOLVER if self.resolver is None else self.resolver
|
|
244
297
|
|
|
245
|
-
def literals(self):
|
|
298
|
+
def literals(self, position):
|
|
246
299
|
"""
|
|
247
|
-
True if the resolver in force wants plain tokens
|
|
300
|
+
True if the resolver in force wants plain tokens at position, one
|
|
301
|
+
of LITERALS, offered too.
|
|
248
302
|
"""
|
|
249
|
-
return self.resolving()
|
|
303
|
+
return takes_literals(self.resolving(), position)
|
|
250
304
|
|
|
251
305
|
def resolve(self, ref, node=None, parents=()):
|
|
252
306
|
"""
|
|
@@ -551,7 +605,7 @@ class Transform(Op):
|
|
|
551
605
|
return ()
|
|
552
606
|
if settings is None:
|
|
553
607
|
settings = SETTINGS
|
|
554
|
-
literals = settings.literals()
|
|
608
|
+
literals = settings.literals('transforms')
|
|
555
609
|
args = []
|
|
556
610
|
for p in self.params:
|
|
557
611
|
if isinstance(p, Op) and (p.is_reference() or (literals and isinstance(p, matchers.Const))):
|
|
@@ -285,7 +285,7 @@ class FilterKeyValue(FilterOp):
|
|
|
285
285
|
val = results.apply_transforms(val, self.guard_transforms, settings, parents)
|
|
286
286
|
except base.UnresolvedReference:
|
|
287
287
|
continue
|
|
288
|
-
if results.guard_passes(pred_op, val, self.val, settings, val, parents):
|
|
288
|
+
if results.guard_passes(pred_op, val, self.val, settings, val, parents, 'filters'):
|
|
289
289
|
return True
|
|
290
290
|
return False
|
|
291
291
|
|
|
@@ -256,18 +256,19 @@ def apply_transforms(val, transforms, settings=base.SETTINGS, parents=()):
|
|
|
256
256
|
return val
|
|
257
257
|
|
|
258
258
|
|
|
259
|
-
def guard_matcher(guard, settings=base.SETTINGS, node=None, parents=()):
|
|
259
|
+
def guard_matcher(guard, settings=base.SETTINGS, node=None, parents=(), position='guards'):
|
|
260
260
|
"""
|
|
261
261
|
The match op a guard or filter value compares with: the value as
|
|
262
262
|
parsed, or a reference resolved through the traversal's resolver
|
|
263
263
|
against node and parents, node being the value under test (so
|
|
264
|
-
$$(^x) looks x up in it). A
|
|
265
|
-
|
|
266
|
-
|
|
264
|
+
$$(^x) looks x up in it). A plain value is resolved too when the
|
|
265
|
+
resolver takes literals at position, 'guards' or 'filters'. A reference
|
|
266
|
+
path that is a pattern becomes a value group of what it resolves to.
|
|
267
|
+
Raises UnresolvedReference when the reference does not resolve.
|
|
267
268
|
"""
|
|
268
269
|
# container values (ContainerList and kin) are ops without is_reference
|
|
269
270
|
reference = hasattr(guard, 'is_reference') and guard.is_reference()
|
|
270
|
-
if not (reference or (settings.literals() and isinstance(guard, Const))):
|
|
271
|
+
if not (reference or (settings.literals(position) and isinstance(guard, Const))):
|
|
271
272
|
return guard
|
|
272
273
|
val = settings.resolve(guard, node, parents)
|
|
273
274
|
if not guard.is_pattern():
|
|
@@ -276,13 +277,13 @@ def guard_matcher(guard, settings=base.SETTINGS, node=None, parents=()):
|
|
|
276
277
|
return containers.ValueGroup(*(Const(v) for v in val))
|
|
277
278
|
|
|
278
279
|
|
|
279
|
-
def guard_passes(pred_op, val, guard, settings=base.SETTINGS, node=None, parents=()):
|
|
280
|
+
def guard_passes(pred_op, val, guard, settings=base.SETTINGS, node=None, parents=(), position='guards'):
|
|
280
281
|
"""
|
|
281
282
|
True if val satisfies pred_op against guard (see guard_matcher); a
|
|
282
283
|
guard reference that does not resolve passes nothing.
|
|
283
284
|
"""
|
|
284
285
|
try:
|
|
285
|
-
matcher = guard_matcher(guard, settings, node, parents)
|
|
286
|
+
matcher = guard_matcher(guard, settings, node, parents, position)
|
|
286
287
|
except base.UnresolvedReference:
|
|
287
288
|
return False
|
|
288
289
|
return any(True for _ in pred_op.matches((val,), matcher))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dotted_notation
|
|
3
|
-
Version: 0.49.
|
|
3
|
+
Version: 0.49.2
|
|
4
4
|
Summary: Dotted notation for safe nested data traversal with optional chaining, pattern matching, and transforms
|
|
5
5
|
Author-email: Frey Waid <logophage1@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -1677,14 +1677,16 @@ claim some references and leave the rest:
|
|
|
1677
1677
|
>>> dotted.get({'amount': 10}, 'amount|sub:$$(lots.taken)', resolver=Store(store))
|
|
1678
1678
|
7
|
|
1679
1679
|
|
|
1680
|
-
A resolver
|
|
1681
|
-
those positions, so a host sigil such as `$sel` can be a variable.
|
|
1680
|
+
A resolver with `literals = True` is also offered every plain token in
|
|
1681
|
+
those positions, so a host sigil such as `$sel` can be a variable. Set it on
|
|
1682
|
+
the class, or per instance with `literals=` on the constructor. Return
|
|
1682
1683
|
`ref.value` to leave a token the literal it is; a key the resolver answers
|
|
1683
1684
|
is not offered again:
|
|
1684
1685
|
|
|
1685
1686
|
>>> class Sigils(dotted.ReferenceResolver):
|
|
1686
1687
|
... literals = True
|
|
1687
|
-
... def __init__(self, names):
|
|
1688
|
+
... def __init__(self, names, literals=None):
|
|
1689
|
+
... super().__init__(literals)
|
|
1688
1690
|
... self.names = names
|
|
1689
1691
|
... def resolve(self, ref, settings, node=None, parents=()):
|
|
1690
1692
|
... if ref.is_reference():
|
|
@@ -1696,6 +1698,18 @@ is not offered again:
|
|
|
1696
1698
|
>>> dotted.get(users, 'users[*&name=$sel].name', resolver=Sigils({'$sel': 'bob'}))
|
|
1697
1699
|
('bob',)
|
|
1698
1700
|
|
|
1701
|
+
`literals` may instead name the positions it wants, as a list or tuple of
|
|
1702
|
+
`'segments'` (key, slot and attr segments), `'transforms'` (transform
|
|
1703
|
+
arguments), `'guards'` (guard values) and `'filters'` (filter values). A host
|
|
1704
|
+
whose variables only ever stand as arguments leaves `'segments'` out, so the
|
|
1705
|
+
keys of a path cost no call:
|
|
1706
|
+
|
|
1707
|
+
>>> r = Sigils({'$inc': 3}, literals=('transforms', 'guards', 'filters'))
|
|
1708
|
+
>>> dotted.get({'n': 5}, 'n|add:$inc', resolver=r)
|
|
1709
|
+
8
|
|
1710
|
+
|
|
1711
|
+
An unknown name is a `ValueError`, on the class or the constructor.
|
|
1712
|
+
|
|
1699
1713
|
A host variable may span several segments, `$amount.value`, which dotted has
|
|
1700
1714
|
parsed as two. The path-level hook `fold(segments)` is called once with a
|
|
1701
1715
|
path's segment strings, `('$amount', 'value')`, and returns the runs it
|
|
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "dotted_notation"
|
|
9
|
-
version = "0.49.
|
|
9
|
+
version = "0.49.2"
|
|
10
10
|
description = "Dotted notation for safe nested data traversal with optional chaining, pattern matching, and transforms"
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
requires-python = ">=3.6"
|
|
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
|
{dotted_notation-0.49.1 → dotted_notation-0.49.2}/dotted_notation.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|