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.
Files changed (82) hide show
  1. {dotted_notation-0.43.0/dotted_notation.egg-info → dotted_notation-0.43.2}/PKG-INFO +1 -1
  2. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/grammar.py +3 -3
  3. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/matchers.py +24 -9
  4. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/sqlize.py +50 -5
  5. {dotted_notation-0.43.0 → dotted_notation-0.43.2/dotted_notation.egg-info}/PKG-INFO +1 -1
  6. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted_notation.egg-info/SOURCES.txt +1 -0
  7. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/setup.py +1 -1
  8. dotted_notation-0.43.2/tests/test_cli.py +515 -0
  9. dotted_notation-0.43.2/tests/test_json_sentinels.py +62 -0
  10. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_named_subst.py +34 -0
  11. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_sqlize.py +53 -0
  12. dotted_notation-0.43.2/tests/test_strict.py +314 -0
  13. dotted_notation-0.43.2/tests/test_value_guard.py +280 -0
  14. dotted_notation-0.43.0/tests/test_cli.py +0 -551
  15. dotted_notation-0.43.0/tests/test_strict.py +0 -323
  16. dotted_notation-0.43.0/tests/test_value_guard.py +0 -285
  17. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/LICENSE +0 -0
  18. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/README.md +0 -0
  19. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/__init__.py +0 -0
  20. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/__main__.py +0 -0
  21. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/access.py +0 -0
  22. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/api.py +0 -0
  23. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/base.py +0 -0
  24. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/cli/__init__.py +0 -0
  25. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/cli/_compat.py +0 -0
  26. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/cli/formats.py +0 -0
  27. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/cli/main.py +0 -0
  28. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/containers.py +0 -0
  29. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/engine.py +0 -0
  30. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/filters.py +0 -0
  31. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/groups.py +0 -0
  32. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/predicates.py +0 -0
  33. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/recursive.py +0 -0
  34. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/results.py +0 -0
  35. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/transforms.py +0 -0
  36. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/utils.py +0 -0
  37. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/utypes.py +0 -0
  38. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted/wrappers.py +0 -0
  39. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted_notation.egg-info/dependency_links.txt +0 -0
  40. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted_notation.egg-info/entry_points.txt +0 -0
  41. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted_notation.egg-info/requires.txt +0 -0
  42. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/dotted_notation.egg-info/top_level.txt +0 -0
  43. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/setup.cfg +0 -0
  44. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/__init__.py +0 -0
  45. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_api.py +0 -0
  46. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_appender.py +0 -0
  47. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_assemble.py +0 -0
  48. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_attrs.py +0 -0
  49. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_bindings.py +0 -0
  50. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_concat.py +0 -0
  51. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_container_filter.py +0 -0
  52. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_cut.py +0 -0
  53. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_empty.py +0 -0
  54. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_filter_keyvalue.py +0 -0
  55. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_get.py +0 -0
  56. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_guard_transforms.py +0 -0
  57. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_invert.py +0 -0
  58. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_keys_values.py +0 -0
  59. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_match.py +0 -0
  60. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_matchable.py +0 -0
  61. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_negation.py +0 -0
  62. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_nop.py +0 -0
  63. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_numeric.py +0 -0
  64. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_opgroup.py +0 -0
  65. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_pluck.py +0 -0
  66. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_predicates.py +0 -0
  67. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_quote_idempotent.py +0 -0
  68. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_recursive.py +0 -0
  69. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_reference.py +0 -0
  70. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_replace.py +0 -0
  71. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_slice.py +0 -0
  72. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_softcut.py +0 -0
  73. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_string_glob.py +0 -0
  74. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_subst_escape.py +0 -0
  75. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_subst_transforms.py +0 -0
  76. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_threading.py +0 -0
  77. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_transforms.py +0 -0
  78. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_translate.py +0 -0
  79. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_type_restriction.py +0 -0
  80. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_unpack.py +0 -0
  81. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_update.py +0 -0
  82. {dotted_notation-0.43.0 → dotted_notation-0.43.2}/tests/test_update_if.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dotted_notation
3
- Version: 0.43.0
3
+ Version: 0.43.2
4
4
  Summary: Dotted notation for safe nested data traversal with optional chaining, pattern matching, and transforms
5
5
  Home-page: https://github.com/freywaid/dotted
6
6
  Author: Frey Waid
@@ -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] == 'True'
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
- try:
195
- val = self._apply_transforms(bindings[self.value])
196
- return ResolvedValue(val)
197
- except (KeyError, IndexError, TypeError):
198
- if partial:
199
- return self
200
- raise
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 `name`; until then the name is recorded in `missing`.
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
- name = str(name)
99
- if name not in self.params and name not in self.missing:
100
- self.missing.append(name)
101
- return name
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:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dotted_notation
3
- Version: 0.43.0
3
+ Version: 0.43.2
4
4
  Summary: Dotted notation for safe nested data traversal with optional chaining, pattern matching, and transforms
5
5
  Home-page: https://github.com/freywaid/dotted
6
6
  Author: Frey Waid
@@ -45,6 +45,7 @@ tests/test_filter_keyvalue.py
45
45
  tests/test_get.py
46
46
  tests/test_guard_transforms.py
47
47
  tests/test_invert.py
48
+ tests/test_json_sentinels.py
48
49
  tests/test_keys_values.py
49
50
  tests/test_match.py
50
51
  tests/test_matchable.py
@@ -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.0",
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",