dotted-notation 0.47.1__tar.gz → 0.48.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.
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/CHANGELOG.md +26 -0
- {dotted_notation-0.47.1/dotted_notation.egg-info → dotted_notation-0.48.0}/PKG-INFO +74 -1
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/README.md +73 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/__init__.py +4 -1
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/access.py +20 -10
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/api.py +123 -70
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/base.pxd +1 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/base.py +99 -13
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/engine.pxd +4 -4
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/engine.py +18 -17
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/filters.py +2 -2
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/grammar.py +4 -1
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/matchers.py +7 -31
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/results.py +83 -18
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/wrappers.py +30 -3
- {dotted_notation-0.47.1 → dotted_notation-0.48.0/dotted_notation.egg-info}/PKG-INFO +74 -1
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/pyproject.toml +1 -1
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/LICENSE +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/MANIFEST.in +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/__main__.py +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/access.pxd +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/cli/__init__.py +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/cli/_compat.py +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/cli/formats.py +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/cli/main.py +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/containers.py +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/filters.pxd +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/groups.pxd +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/groups.py +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/matchers.pxd +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/native.py +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/predicates.py +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/recursive.pxd +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/recursive.py +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/sql/__init__.py +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/sql/core.py +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/sql/pg.py +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/transforms.py +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/utils.py +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/utypes.py +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted/wrappers.pxd +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted_notation.egg-info/SOURCES.txt +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted_notation.egg-info/dependency_links.txt +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted_notation.egg-info/entry_points.txt +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted_notation.egg-info/requires.txt +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/dotted_notation.egg-info/top_level.txt +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/setup.cfg +0 -0
- {dotted_notation-0.47.1 → dotted_notation-0.48.0}/setup.py +0 -0
|
@@ -3,6 +3,32 @@
|
|
|
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.48.0]
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
- `dotted.ReferenceResolver`: what a reference means at run time, as a
|
|
10
|
+
class a host subclasses. `resolve(ref, settings, node, parents)` is
|
|
11
|
+
called for every `$$(path)` a traversal meets, in an access position,
|
|
12
|
+
a transform argument, a guard or a filter value; `super().resolve` is
|
|
13
|
+
dotted's own reading. With `literals = True` it is offered every plain
|
|
14
|
+
token in those positions too, so a host sigil such as `$sel` can be a
|
|
15
|
+
variable. `fold(segments)` is called once per path with its segment
|
|
16
|
+
strings and folds runs of them into pre-resolved keys, so a
|
|
17
|
+
multi-segment host variable, `$amount.value`, is one name. Pass a
|
|
18
|
+
resolver as `resolver=` to `get`, `update`, `remove` and the other
|
|
19
|
+
traversal calls, or install one for the process with
|
|
20
|
+
`dotted.set_resolver(r)`; `get_resolver()` reads it back.
|
|
21
|
+
`UnresolvedReference` is exported for resolvers to raise.
|
|
22
|
+
- `Dotted.segments()`, each segment's plain value with its wrappers
|
|
23
|
+
aside, and slicing a parsed path, `ops[1:]`, gives a path.
|
|
24
|
+
|
|
25
|
+
## [0.47.2]
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
- `$str`, a `$` before a word, is a plain string wherever a key, guard
|
|
29
|
+
value or transform argument may stand, as `^str` already was. It was a
|
|
30
|
+
`ParseError`. `$0`, `$(name)` and `$$(path)` are unchanged.
|
|
31
|
+
|
|
6
32
|
## [0.47.1]
|
|
7
33
|
|
|
8
34
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dotted_notation
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.48.0
|
|
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
|
|
@@ -145,6 +145,7 @@ For faster `mutable=False` updates and removes, install the
|
|
|
145
145
|
- [References](#references)
|
|
146
146
|
- [Relative References](#relative-references)
|
|
147
147
|
- [References in transforms and guards](#references-in-transforms-and-guards)
|
|
148
|
+
- [Custom resolvers](#custom-resolvers)
|
|
148
149
|
- [Escaping](#escaping)
|
|
149
150
|
- [Type Restrictions](#type-restrictions)
|
|
150
151
|
- [Positive restrictions](#positive-restrictions)
|
|
@@ -1631,6 +1632,71 @@ A reference that does not resolve matches nothing, as in an access position:
|
|
|
1631
1632
|
>>> dotted.get({'a': 1}, 'a|add:$$(missing)', default='fallback')
|
|
1632
1633
|
'fallback'
|
|
1633
1634
|
|
|
1635
|
+
<a id="custom-resolvers"></a>
|
|
1636
|
+
### Custom resolvers
|
|
1637
|
+
|
|
1638
|
+
What a reference means at run time is decided by a **resolver**. The default
|
|
1639
|
+
is dotted's own reading above. A host with its own namespaces subclasses
|
|
1640
|
+
`dotted.ReferenceResolver`, passes an instance as `resolver=` to `get`,
|
|
1641
|
+
`update`, `remove` and the rest, or installs one for the process with
|
|
1642
|
+
`dotted.set_resolver(r)`; `set_resolver()` with no argument restores the
|
|
1643
|
+
default.
|
|
1644
|
+
|
|
1645
|
+
`resolve(ref, settings, node, parents)` is called for every `$$(...)` the
|
|
1646
|
+
traversal meets, in an access position, a transform argument, a guard or a
|
|
1647
|
+
filter value. `ref.is_reference()` is true for those, `ref.inner_path` is the
|
|
1648
|
+
text inside, and `super().resolve(...)` is dotted's reading, so a host can
|
|
1649
|
+
claim some references and leave the rest:
|
|
1650
|
+
|
|
1651
|
+
>>> class Store(dotted.ReferenceResolver):
|
|
1652
|
+
... def __init__(self, store):
|
|
1653
|
+
... self.store = store
|
|
1654
|
+
... def resolve(self, ref, settings, node=None, parents=()):
|
|
1655
|
+
... return dotted.get(self.store, ref.inner_path)
|
|
1656
|
+
>>> store = {'lots': {'taken': 3}}
|
|
1657
|
+
>>> dotted.get({'amount': 10}, 'amount|sub:$$(lots.taken)', resolver=Store(store))
|
|
1658
|
+
7
|
|
1659
|
+
|
|
1660
|
+
A resolver that sets `literals = True` is also offered every plain token in
|
|
1661
|
+
those positions, so a host sigil such as `$sel` can be a variable. Return
|
|
1662
|
+
`ref.value` to leave a token the literal it is; a key the resolver answers
|
|
1663
|
+
is not offered again:
|
|
1664
|
+
|
|
1665
|
+
>>> class Sigils(dotted.ReferenceResolver):
|
|
1666
|
+
... literals = True
|
|
1667
|
+
... def __init__(self, names):
|
|
1668
|
+
... self.names = names
|
|
1669
|
+
... def resolve(self, ref, settings, node=None, parents=()):
|
|
1670
|
+
... if ref.is_reference():
|
|
1671
|
+
... return super().resolve(ref, settings, node, parents)
|
|
1672
|
+
... if isinstance(ref.value, str) and ref.value.startswith('$'):
|
|
1673
|
+
... return self.names[ref.value]
|
|
1674
|
+
... return ref.value
|
|
1675
|
+
>>> users = {'users': [{'name': 'alice'}, {'name': 'bob'}]}
|
|
1676
|
+
>>> dotted.get(users, 'users[*&name=$sel].name', resolver=Sigils({'$sel': 'bob'}))
|
|
1677
|
+
('bob',)
|
|
1678
|
+
|
|
1679
|
+
A host variable may span several segments, `$amount.value`, which dotted has
|
|
1680
|
+
parsed as two. The path-level hook `fold(segments)` is called once with a
|
|
1681
|
+
path's segment strings, `('$amount', 'value')`, and returns the runs it
|
|
1682
|
+
resolves as `(start, stop, value)` triples; each run becomes one segment
|
|
1683
|
+
whose key is the value, keeping the last segment's guard, filter and
|
|
1684
|
+
transforms. An inner segment of a run may carry none.
|
|
1685
|
+
|
|
1686
|
+
>>> class Folding(Sigils):
|
|
1687
|
+
... def fold(self, segments):
|
|
1688
|
+
... name = '.'.join(str(s) for s in segments)
|
|
1689
|
+
... if name in self.names:
|
|
1690
|
+
... return [(0, len(segments), self.names[name])]
|
|
1691
|
+
... return []
|
|
1692
|
+
>>> r = Folding({'$amount.value': 'amt'})
|
|
1693
|
+
>>> dotted.get({'amt': 10}, '$amount.value|sub:3', resolver=r)
|
|
1694
|
+
7
|
|
1695
|
+
|
|
1696
|
+
A path handed in already parsed goes through `fold()` again, so a hook must
|
|
1697
|
+
be content to see its own output. `Dotted.segments()` gives any parsed
|
|
1698
|
+
path's segment values, and a slice of a parsed path, `ops[1:]`, is a path.
|
|
1699
|
+
|
|
1634
1700
|
<a id="escaping"></a>
|
|
1635
1701
|
### Escaping
|
|
1636
1702
|
|
|
@@ -1655,6 +1721,13 @@ Quoting also works — a quoted string is always literal:
|
|
|
1655
1721
|
To use a literal `$$` as a key, escape with backslash (`\$$`) or quote it
|
|
1656
1722
|
(`'$$(…)'`).
|
|
1657
1723
|
|
|
1724
|
+
A `$` before a word is not a substitution at all: `$str` is the plain string
|
|
1725
|
+
`$str`, in a segment, a guard value or a transform argument alike, just as
|
|
1726
|
+
`^str` is. Only `$0`, `$(name)` and `$$(path)` have meaning:
|
|
1727
|
+
|
|
1728
|
+
>>> dotted.get({'$amount': {'value': 2}}, '$amount.value')
|
|
1729
|
+
2
|
|
1730
|
+
|
|
1658
1731
|
<a id="type-restrictions"></a>
|
|
1659
1732
|
## Type Restrictions
|
|
1660
1733
|
|
|
@@ -98,6 +98,7 @@ For faster `mutable=False` updates and removes, install the
|
|
|
98
98
|
- [References](#references)
|
|
99
99
|
- [Relative References](#relative-references)
|
|
100
100
|
- [References in transforms and guards](#references-in-transforms-and-guards)
|
|
101
|
+
- [Custom resolvers](#custom-resolvers)
|
|
101
102
|
- [Escaping](#escaping)
|
|
102
103
|
- [Type Restrictions](#type-restrictions)
|
|
103
104
|
- [Positive restrictions](#positive-restrictions)
|
|
@@ -1584,6 +1585,71 @@ A reference that does not resolve matches nothing, as in an access position:
|
|
|
1584
1585
|
>>> dotted.get({'a': 1}, 'a|add:$$(missing)', default='fallback')
|
|
1585
1586
|
'fallback'
|
|
1586
1587
|
|
|
1588
|
+
<a id="custom-resolvers"></a>
|
|
1589
|
+
### Custom resolvers
|
|
1590
|
+
|
|
1591
|
+
What a reference means at run time is decided by a **resolver**. The default
|
|
1592
|
+
is dotted's own reading above. A host with its own namespaces subclasses
|
|
1593
|
+
`dotted.ReferenceResolver`, passes an instance as `resolver=` to `get`,
|
|
1594
|
+
`update`, `remove` and the rest, or installs one for the process with
|
|
1595
|
+
`dotted.set_resolver(r)`; `set_resolver()` with no argument restores the
|
|
1596
|
+
default.
|
|
1597
|
+
|
|
1598
|
+
`resolve(ref, settings, node, parents)` is called for every `$$(...)` the
|
|
1599
|
+
traversal meets, in an access position, a transform argument, a guard or a
|
|
1600
|
+
filter value. `ref.is_reference()` is true for those, `ref.inner_path` is the
|
|
1601
|
+
text inside, and `super().resolve(...)` is dotted's reading, so a host can
|
|
1602
|
+
claim some references and leave the rest:
|
|
1603
|
+
|
|
1604
|
+
>>> class Store(dotted.ReferenceResolver):
|
|
1605
|
+
... def __init__(self, store):
|
|
1606
|
+
... self.store = store
|
|
1607
|
+
... def resolve(self, ref, settings, node=None, parents=()):
|
|
1608
|
+
... return dotted.get(self.store, ref.inner_path)
|
|
1609
|
+
>>> store = {'lots': {'taken': 3}}
|
|
1610
|
+
>>> dotted.get({'amount': 10}, 'amount|sub:$$(lots.taken)', resolver=Store(store))
|
|
1611
|
+
7
|
|
1612
|
+
|
|
1613
|
+
A resolver that sets `literals = True` is also offered every plain token in
|
|
1614
|
+
those positions, so a host sigil such as `$sel` can be a variable. Return
|
|
1615
|
+
`ref.value` to leave a token the literal it is; a key the resolver answers
|
|
1616
|
+
is not offered again:
|
|
1617
|
+
|
|
1618
|
+
>>> class Sigils(dotted.ReferenceResolver):
|
|
1619
|
+
... literals = True
|
|
1620
|
+
... def __init__(self, names):
|
|
1621
|
+
... self.names = names
|
|
1622
|
+
... def resolve(self, ref, settings, node=None, parents=()):
|
|
1623
|
+
... if ref.is_reference():
|
|
1624
|
+
... return super().resolve(ref, settings, node, parents)
|
|
1625
|
+
... if isinstance(ref.value, str) and ref.value.startswith('$'):
|
|
1626
|
+
... return self.names[ref.value]
|
|
1627
|
+
... return ref.value
|
|
1628
|
+
>>> users = {'users': [{'name': 'alice'}, {'name': 'bob'}]}
|
|
1629
|
+
>>> dotted.get(users, 'users[*&name=$sel].name', resolver=Sigils({'$sel': 'bob'}))
|
|
1630
|
+
('bob',)
|
|
1631
|
+
|
|
1632
|
+
A host variable may span several segments, `$amount.value`, which dotted has
|
|
1633
|
+
parsed as two. The path-level hook `fold(segments)` is called once with a
|
|
1634
|
+
path's segment strings, `('$amount', 'value')`, and returns the runs it
|
|
1635
|
+
resolves as `(start, stop, value)` triples; each run becomes one segment
|
|
1636
|
+
whose key is the value, keeping the last segment's guard, filter and
|
|
1637
|
+
transforms. An inner segment of a run may carry none.
|
|
1638
|
+
|
|
1639
|
+
>>> class Folding(Sigils):
|
|
1640
|
+
... def fold(self, segments):
|
|
1641
|
+
... name = '.'.join(str(s) for s in segments)
|
|
1642
|
+
... if name in self.names:
|
|
1643
|
+
... return [(0, len(segments), self.names[name])]
|
|
1644
|
+
... return []
|
|
1645
|
+
>>> r = Folding({'$amount.value': 'amt'})
|
|
1646
|
+
>>> dotted.get({'amt': 10}, '$amount.value|sub:3', resolver=r)
|
|
1647
|
+
7
|
|
1648
|
+
|
|
1649
|
+
A path handed in already parsed goes through `fold()` again, so a hook must
|
|
1650
|
+
be content to see its own output. `Dotted.segments()` gives any parsed
|
|
1651
|
+
path's segment values, and a slice of a parsed path, `ops[1:]`, is a path.
|
|
1652
|
+
|
|
1587
1653
|
<a id="escaping"></a>
|
|
1588
1654
|
### Escaping
|
|
1589
1655
|
|
|
@@ -1608,6 +1674,13 @@ Quoting also works — a quoted string is always literal:
|
|
|
1608
1674
|
To use a literal `$$` as a key, escape with backslash (`\$$`) or quote it
|
|
1609
1675
|
(`'$$(…)'`).
|
|
1610
1676
|
|
|
1677
|
+
A `$` before a word is not a substitution at all: `$str` is the plain string
|
|
1678
|
+
`$str`, in a segment, a guard value or a transform argument alike, just as
|
|
1679
|
+
`^str` is. Only `$0`, `$(name)` and `$$(path)` have meaning:
|
|
1680
|
+
|
|
1681
|
+
>>> dotted.get({'$amount': {'value': 2}}, '$amount.value')
|
|
1682
|
+
2
|
|
1683
|
+
|
|
1611
1684
|
<a id="type-restrictions"></a>
|
|
1612
1685
|
## Type Restrictions
|
|
1613
1686
|
|
|
@@ -65,7 +65,7 @@ from .api import \
|
|
|
65
65
|
parse, compile, is_pattern, is_template, is_reference, is_indeterminate, is_simple, \
|
|
66
66
|
is_inverted, is_mutable, mutable, quote, ANY, AUTO, Attrs, GroupMode, \
|
|
67
67
|
set_simple_fastpath, set_parse_cache, \
|
|
68
|
-
register, transform, \
|
|
68
|
+
register, transform, set_resolver, get_resolver, \
|
|
69
69
|
assemble, assemble_multi, \
|
|
70
70
|
build, build_multi, \
|
|
71
71
|
expand, expand_multi, \
|
|
@@ -77,10 +77,13 @@ from .api import \
|
|
|
77
77
|
remove, remove_multi, remove_if, remove_if_multi, \
|
|
78
78
|
pluck, pluck_multi, walk, walk_multi, unpack, keys, values, items
|
|
79
79
|
from .sql import sqlize, TranslationError, SQLFragment, Resolver, ParamStyle, ParamPool
|
|
80
|
+
# the run-time reference resolver; sqlize's Resolver, above, has the plain name
|
|
81
|
+
from .base import Resolver as ReferenceResolver, UnresolvedReference
|
|
80
82
|
|
|
81
83
|
__all__ = [
|
|
82
84
|
# Core
|
|
83
85
|
'get', 'update', 'remove', 'has', 'setdefault',
|
|
86
|
+
'ReferenceResolver', 'UnresolvedReference', 'set_resolver', 'get_resolver',
|
|
84
87
|
# Multi
|
|
85
88
|
'get_multi', 'update_multi', 'pack', 'update_if', 'update_if_multi', 'remove_multi', 'remove_if', 'remove_if_multi', 'setdefault_multi',
|
|
86
89
|
# Pattern
|
|
@@ -248,6 +248,16 @@ class AccessOp(SimpleOp):
|
|
|
248
248
|
"""
|
|
249
249
|
return self.op.is_reference()
|
|
250
250
|
|
|
251
|
+
def _offered(self, settings):
|
|
252
|
+
"""
|
|
253
|
+
True if the match op goes to the resolver: a reference, or a
|
|
254
|
+
plain constant when the resolver in force takes literals.
|
|
255
|
+
"""
|
|
256
|
+
if self.op.is_reference():
|
|
257
|
+
return True
|
|
258
|
+
return (settings.literals() and isinstance(self.op, matchers.Const)
|
|
259
|
+
and not isinstance(self.op, matchers.ResolvedValue))
|
|
260
|
+
|
|
251
261
|
def resolve(self, bindings, partial=False):
|
|
252
262
|
"""
|
|
253
263
|
Resolve $N in the inner match op.
|
|
@@ -263,21 +273,21 @@ class AccessOp(SimpleOp):
|
|
|
263
273
|
tuple of concrete ops (empty if the reference path is not found).
|
|
264
274
|
Callers must guard with is_reference() before calling.
|
|
265
275
|
"""
|
|
266
|
-
root = settings.root
|
|
267
|
-
parents = settings.parents or ()
|
|
268
276
|
try:
|
|
269
|
-
val = self.op
|
|
277
|
+
val = settings.resolve(self.op, node, settings.parents or ())
|
|
270
278
|
except KeyError:
|
|
271
279
|
return ()
|
|
280
|
+
# ResolvedValue, not Const: a resolved key is not offered to the
|
|
281
|
+
# resolver again (see _offered)
|
|
272
282
|
if self.op.is_pattern():
|
|
273
|
-
return tuple(self.__class__(matchers.
|
|
274
|
-
return (self.__class__(matchers.
|
|
283
|
+
return tuple(self.__class__(matchers.ResolvedValue(v)) for v in val)
|
|
284
|
+
return (self.__class__(matchers.ResolvedValue(val)),)
|
|
275
285
|
|
|
276
286
|
def do_update(self, ops, node, val, has_defaults, _path, nop, nop_from_unwrap=False, settings=base.SETTINGS):
|
|
277
287
|
"""
|
|
278
288
|
Resolve references before updating.
|
|
279
289
|
"""
|
|
280
|
-
if self.
|
|
290
|
+
if self._offered(settings):
|
|
281
291
|
for r in self._resolved(node=node, settings=settings):
|
|
282
292
|
node = r.do_update(ops, node, val, has_defaults, _path, nop, nop_from_unwrap=nop_from_unwrap, settings=settings)
|
|
283
293
|
return node
|
|
@@ -287,7 +297,7 @@ class AccessOp(SimpleOp):
|
|
|
287
297
|
"""
|
|
288
298
|
Resolve references before removing.
|
|
289
299
|
"""
|
|
290
|
-
if self.
|
|
300
|
+
if self._offered(settings):
|
|
291
301
|
for r in self._resolved(node=node, settings=settings):
|
|
292
302
|
node = r.do_remove(ops, node, val, nop, settings=settings)
|
|
293
303
|
return node
|
|
@@ -395,7 +405,7 @@ class Key(AccessOp):
|
|
|
395
405
|
return iter(pairs)
|
|
396
406
|
|
|
397
407
|
def items(self, node, settings=base.SETTINGS, filtered=True):
|
|
398
|
-
if self.
|
|
408
|
+
if self._offered(settings):
|
|
399
409
|
return self._reference_items(node, filtered, settings)
|
|
400
410
|
# Dict-like: use key matching
|
|
401
411
|
if hasattr(node, 'keys'):
|
|
@@ -586,7 +596,7 @@ class Attr(Key):
|
|
|
586
596
|
yield (key, v)
|
|
587
597
|
|
|
588
598
|
def items(self, node, settings=base.SETTINGS, filtered=True):
|
|
589
|
-
if self.
|
|
599
|
+
if self._offered(settings):
|
|
590
600
|
return self._reference_items(node, filtered, settings)
|
|
591
601
|
all_keys = self._all_keys(node)
|
|
592
602
|
keys = self.op.matches(all_keys) if filtered else all_keys
|
|
@@ -673,7 +683,7 @@ class Slot(Key):
|
|
|
673
683
|
return '[' + self.op.quote() + ']'
|
|
674
684
|
|
|
675
685
|
def items(self, node, settings=base.SETTINGS, filtered=True):
|
|
676
|
-
if self.
|
|
686
|
+
if self._offered(settings):
|
|
677
687
|
return self._reference_items(node, filtered, settings)
|
|
678
688
|
if hasattr(node, 'keys'):
|
|
679
689
|
if settings.strict:
|