dotted-notation 0.43.0__tar.gz → 0.43.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.43.0/dotted_notation.egg-info → dotted_notation-0.43.2}/PKG-INFO +1 -1
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/grammar.py +3 -3
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/matchers.py +24 -9
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/sqlize.py +50 -5
- {dotted_notation-0.43.0 → dotted_notation-0.43.2/dotted_notation.egg-info}/PKG-INFO +1 -1
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted_notation.egg-info/SOURCES.txt +1 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/setup.py +1 -1
- dotted_notation-0.43.2/tests/test_cli.py +515 -0
- dotted_notation-0.43.2/tests/test_json_sentinels.py +62 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_named_subst.py +34 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_sqlize.py +53 -0
- dotted_notation-0.43.2/tests/test_strict.py +314 -0
- dotted_notation-0.43.2/tests/test_value_guard.py +280 -0
- dotted_notation-0.43.0/tests/test_cli.py +0 -551
- dotted_notation-0.43.0/tests/test_strict.py +0 -323
- dotted_notation-0.43.0/tests/test_value_guard.py +0 -285
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/LICENSE +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/README.md +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/__init__.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/__main__.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/access.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/api.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/base.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/cli/__init__.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/cli/_compat.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/cli/formats.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/cli/main.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/containers.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/engine.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/filters.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/groups.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/predicates.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/recursive.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/results.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/transforms.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/utils.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/utypes.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/wrappers.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted_notation.egg-info/dependency_links.txt +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted_notation.egg-info/entry_points.txt +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted_notation.egg-info/requires.txt +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted_notation.egg-info/top_level.txt +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/setup.cfg +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/__init__.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_api.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_appender.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_assemble.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_attrs.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_bindings.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_concat.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_container_filter.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_cut.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_empty.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_filter_keyvalue.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_get.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_guard_transforms.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_invert.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_keys_values.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_match.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_matchable.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_negation.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_nop.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_numeric.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_opgroup.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_pluck.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_predicates.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_quote_idempotent.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_recursive.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_reference.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_replace.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_slice.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_softcut.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_string_glob.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_subst_escape.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_subst_transforms.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_threading.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_transforms.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_translate.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_type_restriction.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_unpack.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_update.py +0 -0
- {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_update_if.py +0 -0
|
@@ -69,9 +69,9 @@ transform_name = pp.Word(pp.alphas + '_', pp.alphanums + '_.')
|
|
|
69
69
|
quoted = pp.QuotedString('"', esc_char='\\') | pp.QuotedString("'", esc_char='\\')
|
|
70
70
|
plus = pp.Literal('+')
|
|
71
71
|
integer = ppc.signed_integer
|
|
72
|
-
none = pp.Literal('None').set_parse_action(matchers.NoneValue)
|
|
73
|
-
true = pp.Literal('True').set_parse_action(matchers.Boolean)
|
|
74
|
-
false = pp.Literal('False').set_parse_action(matchers.Boolean)
|
|
72
|
+
none = (pp.Literal('None') | pp.Literal('null')).set_parse_action(matchers.NoneValue)
|
|
73
|
+
true = (pp.Literal('True') | pp.Literal('true')).set_parse_action(matchers.Boolean)
|
|
74
|
+
false = (pp.Literal('False') | pp.Literal('false')).set_parse_action(matchers.Boolean)
|
|
75
75
|
|
|
76
76
|
reserved = '.[]*:|+?/=,@&()!~#{}$<>' # {} for container syntax, $ for substitution, <> for comparisons
|
|
77
77
|
breserved = ''.join('\\' + i for i in reserved)
|
|
@@ -13,6 +13,9 @@ from .base import MatchOp
|
|
|
13
13
|
from .utypes import ANY
|
|
14
14
|
|
|
15
15
|
|
|
16
|
+
_MISSING = object()
|
|
17
|
+
|
|
18
|
+
|
|
16
19
|
class Const(MatchOp):
|
|
17
20
|
_match_from = ('Const',)
|
|
18
21
|
|
|
@@ -119,7 +122,7 @@ class Boolean(Const):
|
|
|
119
122
|
"""
|
|
120
123
|
@property
|
|
121
124
|
def value(self):
|
|
122
|
-
return self.args[0] == '
|
|
125
|
+
return self.args[0].lower() == 'true'
|
|
123
126
|
def __repr__(self):
|
|
124
127
|
return str(self.value)
|
|
125
128
|
|
|
@@ -190,14 +193,26 @@ class Subst(Pattern):
|
|
|
190
193
|
def resolve(self, bindings, partial=False):
|
|
191
194
|
"""
|
|
192
195
|
Resolve this substitution against bindings.
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
196
|
+
|
|
197
|
+
For string names, honor dotted notation for nested lookup: `$(a.b)`
|
|
198
|
+
resolves to `bindings['a']['b']` when present. Falls back to a
|
|
199
|
+
literal `bindings[name]` lookup (preserves the rare case of a key
|
|
200
|
+
that actually contains a dot). Integer names always use positional
|
|
201
|
+
lookup via __getitem__.
|
|
202
|
+
"""
|
|
203
|
+
name = self.value
|
|
204
|
+
val = _MISSING
|
|
205
|
+
if isinstance(name, str):
|
|
206
|
+
from .api import get
|
|
207
|
+
val = get(bindings, name, default=_MISSING)
|
|
208
|
+
if val is _MISSING:
|
|
209
|
+
try:
|
|
210
|
+
val = bindings[name]
|
|
211
|
+
except (KeyError, IndexError, TypeError):
|
|
212
|
+
if partial:
|
|
213
|
+
return self
|
|
214
|
+
raise
|
|
215
|
+
return ResolvedValue(self._apply_transforms(val))
|
|
201
216
|
|
|
202
217
|
def __repr__(self):
|
|
203
218
|
suffix = self._transform_suffix()
|
|
@@ -46,6 +46,46 @@ def _quote_ident(name):
|
|
|
46
46
|
return '"' + name.replace('"', '""') + '"'
|
|
47
47
|
|
|
48
48
|
|
|
49
|
+
# Subst names may themselves be dotted paths. To survive as SQL bind
|
|
50
|
+
# parameter names (which must be plain identifiers), the access operators
|
|
51
|
+
# are encoded with mnemonic tokens. This preserves the distinction
|
|
52
|
+
# between `a.b`, `a@b`, and `a[0]` in the placeholder name.
|
|
53
|
+
_OP_ENCODE = {
|
|
54
|
+
'.': '_dot_',
|
|
55
|
+
'@': '_at_',
|
|
56
|
+
'[': '_br_',
|
|
57
|
+
']': '',
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _encode_subst_name(name):
|
|
62
|
+
"""
|
|
63
|
+
Encode a subst name (a dotted path) into a plain SQL identifier.
|
|
64
|
+
Recognised access ops become mnemonic tokens; unsupported characters
|
|
65
|
+
raise TranslationError.
|
|
66
|
+
"""
|
|
67
|
+
if _IDENT_RE.fullmatch(name):
|
|
68
|
+
return name
|
|
69
|
+
out = []
|
|
70
|
+
for c in name:
|
|
71
|
+
if c in _OP_ENCODE:
|
|
72
|
+
out.append(_OP_ENCODE[c])
|
|
73
|
+
elif c.isalnum() or c == '_':
|
|
74
|
+
out.append(c)
|
|
75
|
+
else:
|
|
76
|
+
raise TranslationError(
|
|
77
|
+
f'cannot encode character {c!r} in substitution name {name!r}; '
|
|
78
|
+
'resolve via bindings= at sqlize time'
|
|
79
|
+
)
|
|
80
|
+
encoded = ''.join(out)
|
|
81
|
+
if not _IDENT_RE.fullmatch(encoded):
|
|
82
|
+
raise TranslationError(
|
|
83
|
+
f'substitution name {name!r} does not encode to a valid '
|
|
84
|
+
'SQL identifier'
|
|
85
|
+
)
|
|
86
|
+
return encoded
|
|
87
|
+
|
|
88
|
+
|
|
49
89
|
def _pg_path_segment(seg):
|
|
50
90
|
"""
|
|
51
91
|
Escape a segment for a Postgres text[] path literal like '{a,b,c}'.
|
|
@@ -93,12 +133,17 @@ class _ParamState:
|
|
|
93
133
|
def hoist_named(self, name):
|
|
94
134
|
"""
|
|
95
135
|
Hoist a named substitution. If a value is supplied later it lands
|
|
96
|
-
under
|
|
136
|
+
under the encoded name; until then it's recorded in `missing`.
|
|
137
|
+
|
|
138
|
+
Names that already are plain identifiers are used as-is. Dotted
|
|
139
|
+
paths (`$(user.age)`, `$(users[0].name)`, `$(obj@attr)`) are
|
|
140
|
+
encoded into plain identifiers using mnemonic tokens for access
|
|
141
|
+
ops so they can serve as SQL bind-parameter names.
|
|
97
142
|
"""
|
|
98
|
-
|
|
99
|
-
if
|
|
100
|
-
self.missing.append(
|
|
101
|
-
return
|
|
143
|
+
encoded = _encode_subst_name(str(name))
|
|
144
|
+
if encoded not in self.params and encoded not in self.missing:
|
|
145
|
+
self.missing.append(encoded)
|
|
146
|
+
return encoded
|
|
102
147
|
|
|
103
148
|
|
|
104
149
|
class _Translator:
|
|
@@ -5,7 +5,7 @@ with open("README.md", "rt") as f:
|
|
|
5
5
|
|
|
6
6
|
setuptools.setup(
|
|
7
7
|
name="dotted_notation",
|
|
8
|
-
version="0.43.
|
|
8
|
+
version="0.43.2",
|
|
9
9
|
author="Frey Waid",
|
|
10
10
|
author_email="logophage1@gmail.com",
|
|
11
11
|
description="Dotted notation for safe nested data traversal with optional chaining, pattern matching, and transforms",
|