ZhengyangZhang commited on
Commit
af0ec5a
·
verified ·
1 Parent(s): 7245dba

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. lib/python3.12/site-packages/asttokens/util.py +487 -0
  2. lib/python3.12/site-packages/charset_normalizer-3.4.4.dist-info/INSTALLER +1 -0
  3. lib/python3.12/site-packages/charset_normalizer-3.4.4.dist-info/METADATA +764 -0
  4. lib/python3.12/site-packages/charset_normalizer-3.4.4.dist-info/RECORD +35 -0
  5. lib/python3.12/site-packages/charset_normalizer-3.4.4.dist-info/WHEEL +7 -0
  6. lib/python3.12/site-packages/charset_normalizer-3.4.4.dist-info/entry_points.txt +2 -0
  7. lib/python3.12/site-packages/charset_normalizer-3.4.4.dist-info/licenses/LICENSE +21 -0
  8. lib/python3.12/site-packages/charset_normalizer-3.4.4.dist-info/top_level.txt +1 -0
  9. lib/python3.12/site-packages/cycler/__init__.py +573 -0
  10. lib/python3.12/site-packages/cycler/__pycache__/__init__.cpython-312.pyc +0 -0
  11. lib/python3.12/site-packages/cycler/py.typed +0 -0
  12. lib/python3.12/site-packages/frozenlist/__init__.py +86 -0
  13. lib/python3.12/site-packages/frozenlist/__init__.pyi +47 -0
  14. lib/python3.12/site-packages/frozenlist/__pycache__/__init__.cpython-312.pyc +0 -0
  15. lib/python3.12/site-packages/frozenlist/_frozenlist.pyx +148 -0
  16. lib/python3.12/site-packages/frozenlist/py.typed +1 -0
  17. lib/python3.12/site-packages/hjson-3.1.0.dist-info/INSTALLER +1 -0
  18. lib/python3.12/site-packages/hjson-3.1.0.dist-info/LICENSE.txt +81 -0
  19. lib/python3.12/site-packages/hjson-3.1.0.dist-info/METADATA +125 -0
  20. lib/python3.12/site-packages/hjson-3.1.0.dist-info/RECORD +76 -0
  21. lib/python3.12/site-packages/hjson-3.1.0.dist-info/WHEEL +5 -0
  22. lib/python3.12/site-packages/hjson-3.1.0.dist-info/entry_points.txt +2 -0
  23. lib/python3.12/site-packages/hjson-3.1.0.dist-info/top_level.txt +1 -0
  24. lib/python3.12/site-packages/hjson/__init__.py +642 -0
  25. lib/python3.12/site-packages/hjson/__pycache__/__init__.cpython-312.pyc +0 -0
  26. lib/python3.12/site-packages/hjson/__pycache__/compat.cpython-312.pyc +0 -0
  27. lib/python3.12/site-packages/hjson/__pycache__/decoder.cpython-312.pyc +0 -0
  28. lib/python3.12/site-packages/hjson/__pycache__/encoder.cpython-312.pyc +0 -0
  29. lib/python3.12/site-packages/hjson/__pycache__/encoderH.cpython-312.pyc +0 -0
  30. lib/python3.12/site-packages/hjson/__pycache__/ordered_dict.cpython-312.pyc +0 -0
  31. lib/python3.12/site-packages/hjson/__pycache__/scanner.cpython-312.pyc +0 -0
  32. lib/python3.12/site-packages/hjson/__pycache__/tool.cpython-312.pyc +0 -0
  33. lib/python3.12/site-packages/hjson/compat.py +46 -0
  34. lib/python3.12/site-packages/hjson/decoder.py +569 -0
  35. lib/python3.12/site-packages/hjson/encoder.py +521 -0
  36. lib/python3.12/site-packages/hjson/encoderH.py +552 -0
  37. lib/python3.12/site-packages/hjson/ordered_dict.py +119 -0
  38. lib/python3.12/site-packages/hjson/scanner.py +56 -0
  39. lib/python3.12/site-packages/hjson/tests/__init__.py +61 -0
  40. lib/python3.12/site-packages/hjson/tests/__pycache__/__init__.cpython-312.pyc +0 -0
  41. lib/python3.12/site-packages/hjson/tests/__pycache__/test_bigint_as_string.cpython-312.pyc +0 -0
  42. lib/python3.12/site-packages/hjson/tests/__pycache__/test_bitsize_int_as_string.cpython-312.pyc +0 -0
  43. lib/python3.12/site-packages/hjson/tests/__pycache__/test_check_circular.cpython-312.pyc +0 -0
  44. lib/python3.12/site-packages/hjson/tests/__pycache__/test_decimal.cpython-312.pyc +0 -0
  45. lib/python3.12/site-packages/hjson/tests/__pycache__/test_decode.cpython-312.pyc +0 -0
  46. lib/python3.12/site-packages/hjson/tests/__pycache__/test_default.cpython-312.pyc +0 -0
  47. lib/python3.12/site-packages/hjson/tests/__pycache__/test_dump.cpython-312.pyc +0 -0
  48. lib/python3.12/site-packages/hjson/tests/__pycache__/test_encode_basestring_ascii.cpython-312.pyc +0 -0
  49. lib/python3.12/site-packages/hjson/tests/__pycache__/test_errors.cpython-312.pyc +0 -0
  50. lib/python3.12/site-packages/hjson/tests/__pycache__/test_fail.cpython-312.pyc +0 -0
lib/python3.12/site-packages/asttokens/util.py ADDED
@@ -0,0 +1,487 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2016 Grist Labs, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import ast
16
+ import collections
17
+ import io
18
+ import sys
19
+ import token
20
+ import tokenize
21
+ from abc import ABCMeta
22
+ from ast import Module, expr, AST
23
+ from functools import lru_cache
24
+ from typing import (
25
+ Callable,
26
+ Dict,
27
+ Iterable,
28
+ Iterator,
29
+ List,
30
+ Optional,
31
+ Tuple,
32
+ Union,
33
+ cast,
34
+ Any,
35
+ TYPE_CHECKING,
36
+ Type,
37
+ )
38
+
39
+ if TYPE_CHECKING: # pragma: no cover
40
+ from .astroid_compat import NodeNG
41
+
42
+ # Type class used to expand out the definition of AST to include fields added by this library
43
+ # It's not actually used for anything other than type checking though!
44
+ class EnhancedAST(AST):
45
+ # Additional attributes set by mark_tokens
46
+ first_token = None # type: Token
47
+ last_token = None # type: Token
48
+ lineno = 0 # type: int
49
+ end_lineno = 0 # type : int
50
+ end_col_offset = 0 # type : int
51
+
52
+ AstNode = Union[EnhancedAST, NodeNG]
53
+
54
+ TokenInfo = tokenize.TokenInfo
55
+
56
+
57
+ def token_repr(tok_type, string):
58
+ # type: (int, Optional[str]) -> str
59
+ """Returns a human-friendly representation of a token with the given type and string."""
60
+ # repr() prefixes unicode with 'u' on Python2 but not Python3; strip it out for consistency.
61
+ return '%s:%s' % (token.tok_name[tok_type], repr(string).lstrip('u'))
62
+
63
+
64
+ class Token(collections.namedtuple('Token', 'type string start end line index startpos endpos')):
65
+ """
66
+ TokenInfo is an 8-tuple containing the same 5 fields as the tokens produced by the tokenize
67
+ module, and 3 additional ones useful for this module:
68
+
69
+ - [0] .type Token type (see token.py)
70
+ - [1] .string Token (a string)
71
+ - [2] .start Starting (row, column) indices of the token (a 2-tuple of ints)
72
+ - [3] .end Ending (row, column) indices of the token (a 2-tuple of ints)
73
+ - [4] .line Original line (string)
74
+ - [5] .index Index of the token in the list of tokens that it belongs to.
75
+ - [6] .startpos Starting character offset into the input text.
76
+ - [7] .endpos Ending character offset into the input text.
77
+ """
78
+ def __str__(self):
79
+ # type: () -> str
80
+ return token_repr(self.type, self.string)
81
+
82
+
83
+ def match_token(token, tok_type, tok_str=None):
84
+ # type: (Token, int, Optional[str]) -> bool
85
+ """Returns true if token is of the given type and, if a string is given, has that string."""
86
+ return token.type == tok_type and (tok_str is None or token.string == tok_str)
87
+
88
+
89
+ def expect_token(token, tok_type, tok_str=None):
90
+ # type: (Token, int, Optional[str]) -> None
91
+ """
92
+ Verifies that the given token is of the expected type. If tok_str is given, the token string
93
+ is verified too. If the token doesn't match, raises an informative ValueError.
94
+ """
95
+ if not match_token(token, tok_type, tok_str):
96
+ raise ValueError("Expected token %s, got %s on line %s col %s" % (
97
+ token_repr(tok_type, tok_str), str(token),
98
+ token.start[0], token.start[1] + 1))
99
+
100
+
101
+ def is_non_coding_token(token_type):
102
+ # type: (int) -> bool
103
+ """
104
+ These are considered non-coding tokens, as they don't affect the syntax tree.
105
+ """
106
+ return token_type in (token.NL, token.COMMENT, token.ENCODING)
107
+
108
+
109
+ def generate_tokens(text):
110
+ # type: (str) -> Iterator[TokenInfo]
111
+ """
112
+ Generates standard library tokens for the given code.
113
+ """
114
+ # tokenize.generate_tokens is technically an undocumented API for Python3, but allows us to use the same API as for
115
+ # Python2. See https://stackoverflow.com/a/4952291/328565.
116
+ # FIXME: Remove cast once https://github.com/python/typeshed/issues/7003 gets fixed
117
+ return tokenize.generate_tokens(cast(Callable[[], str], io.StringIO(text).readline))
118
+
119
+
120
+ def iter_children_func(node):
121
+ # type: (AST) -> Callable
122
+ """
123
+ Returns a function which yields all direct children of a AST node,
124
+ skipping children that are singleton nodes.
125
+ The function depends on whether ``node`` is from ``ast`` or from the ``astroid`` module.
126
+ """
127
+ return iter_children_astroid if hasattr(node, 'get_children') else iter_children_ast
128
+
129
+
130
+ def iter_children_astroid(node, include_joined_str=False):
131
+ # type: (NodeNG, bool) -> Union[Iterator, List]
132
+ if not include_joined_str and is_joined_str(node):
133
+ return []
134
+
135
+ return node.get_children()
136
+
137
+
138
+ SINGLETONS = {c for n, c in ast.__dict__.items() if isinstance(c, type) and
139
+ issubclass(c, (ast.expr_context, ast.boolop, ast.operator, ast.unaryop, ast.cmpop))}
140
+
141
+
142
+ def iter_children_ast(node, include_joined_str=False):
143
+ # type: (AST, bool) -> Iterator[Union[AST, expr]]
144
+ if not include_joined_str and is_joined_str(node):
145
+ return
146
+
147
+ if isinstance(node, ast.Dict):
148
+ # override the iteration order: instead of <all keys>, <all values>,
149
+ # yield keys and values in source order (key1, value1, key2, value2, ...)
150
+ for (key, value) in zip(node.keys, node.values):
151
+ if key is not None:
152
+ yield key
153
+ yield value
154
+ return
155
+
156
+ for child in ast.iter_child_nodes(node):
157
+ # Skip singleton children; they don't reflect particular positions in the code and break the
158
+ # assumptions about the tree consisting of distinct nodes. Note that collecting classes
159
+ # beforehand and checking them in a set is faster than using isinstance each time.
160
+ if child.__class__ not in SINGLETONS:
161
+ yield child
162
+
163
+
164
+ stmt_class_names = {n for n, c in ast.__dict__.items()
165
+ if isinstance(c, type) and issubclass(c, ast.stmt)}
166
+ expr_class_names = ({n for n, c in ast.__dict__.items()
167
+ if isinstance(c, type) and issubclass(c, ast.expr)} |
168
+ {'AssignName', 'DelName', 'Const', 'AssignAttr', 'DelAttr'})
169
+
170
+ # These feel hacky compared to isinstance() but allow us to work with both ast and astroid nodes
171
+ # in the same way, and without even importing astroid.
172
+ def is_expr(node):
173
+ # type: (AstNode) -> bool
174
+ """Returns whether node is an expression node."""
175
+ return node.__class__.__name__ in expr_class_names
176
+
177
+ def is_stmt(node):
178
+ # type: (AstNode) -> bool
179
+ """Returns whether node is a statement node."""
180
+ return node.__class__.__name__ in stmt_class_names
181
+
182
+ def is_module(node):
183
+ # type: (AstNode) -> bool
184
+ """Returns whether node is a module node."""
185
+ return node.__class__.__name__ == 'Module'
186
+
187
+ def is_joined_str(node):
188
+ # type: (AstNode) -> bool
189
+ """Returns whether node is a JoinedStr node, used to represent f-strings."""
190
+ # At the moment, nodes below JoinedStr have wrong line/col info, and trying to process them only
191
+ # leads to errors.
192
+ return node.__class__.__name__ == 'JoinedStr'
193
+
194
+
195
+ def is_expr_stmt(node):
196
+ # type: (AstNode) -> bool
197
+ """Returns whether node is an `Expr` node, which is a statement that is an expression."""
198
+ return node.__class__.__name__ == 'Expr'
199
+
200
+
201
+
202
+ CONSTANT_CLASSES: Tuple[Type, ...] = (ast.Constant,)
203
+ try:
204
+ from astroid.nodes import Const
205
+ CONSTANT_CLASSES += (Const,)
206
+ except ImportError: # pragma: no cover
207
+ # astroid is not available
208
+ pass
209
+
210
+ def is_constant(node):
211
+ # type: (AstNode) -> bool
212
+ """Returns whether node is a Constant node."""
213
+ return isinstance(node, CONSTANT_CLASSES)
214
+
215
+
216
+ def is_ellipsis(node):
217
+ # type: (AstNode) -> bool
218
+ """Returns whether node is an Ellipsis node."""
219
+ return is_constant(node) and node.value is Ellipsis # type: ignore
220
+
221
+
222
+ def is_starred(node):
223
+ # type: (AstNode) -> bool
224
+ """Returns whether node is a starred expression node."""
225
+ return node.__class__.__name__ == 'Starred'
226
+
227
+
228
+ def is_slice(node):
229
+ # type: (AstNode) -> bool
230
+ """Returns whether node represents a slice, e.g. `1:2` in `x[1:2]`"""
231
+ # Before 3.9, a tuple containing a slice is an ExtSlice,
232
+ # but this was removed in https://bugs.python.org/issue34822
233
+ return (
234
+ node.__class__.__name__ in ('Slice', 'ExtSlice')
235
+ or (
236
+ node.__class__.__name__ == 'Tuple'
237
+ and any(map(is_slice, cast(ast.Tuple, node).elts))
238
+ )
239
+ )
240
+
241
+
242
+ def is_empty_astroid_slice(node):
243
+ # type: (AstNode) -> bool
244
+ return (
245
+ node.__class__.__name__ == "Slice"
246
+ and not isinstance(node, ast.AST)
247
+ and node.lower is node.upper is node.step is None
248
+ )
249
+
250
+
251
+ # Sentinel value used by visit_tree().
252
+ _PREVISIT = object()
253
+
254
+ def visit_tree(node, previsit, postvisit):
255
+ # type: (Module, Callable[[AstNode, Optional[Token]], Tuple[Optional[Token], Optional[Token]]], Optional[Callable[[AstNode, Optional[Token], Optional[Token]], None]]) -> None
256
+ """
257
+ Scans the tree under the node depth-first using an explicit stack. It avoids implicit recursion
258
+ via the function call stack to avoid hitting 'maximum recursion depth exceeded' error.
259
+
260
+ It calls ``previsit()`` and ``postvisit()`` as follows:
261
+
262
+ * ``previsit(node, par_value)`` - should return ``(par_value, value)``
263
+ ``par_value`` is as returned from ``previsit()`` of the parent.
264
+
265
+ * ``postvisit(node, par_value, value)`` - should return ``value``
266
+ ``par_value`` is as returned from ``previsit()`` of the parent, and ``value`` is as
267
+ returned from ``previsit()`` of this node itself. The return ``value`` is ignored except
268
+ the one for the root node, which is returned from the overall ``visit_tree()`` call.
269
+
270
+ For the initial node, ``par_value`` is None. ``postvisit`` may be None.
271
+ """
272
+ if not postvisit:
273
+ postvisit = lambda node, pvalue, value: None
274
+
275
+ iter_children = iter_children_func(node)
276
+ done = set()
277
+ ret = None
278
+ stack = [(node, None, _PREVISIT)] # type: List[Tuple[AstNode, Optional[Token], Union[Optional[Token], object]]]
279
+ while stack:
280
+ current, par_value, value = stack.pop()
281
+ if value is _PREVISIT:
282
+ assert current not in done # protect againt infinite loop in case of a bad tree.
283
+ done.add(current)
284
+
285
+ pvalue, post_value = previsit(current, par_value)
286
+ stack.append((current, par_value, post_value))
287
+
288
+ # Insert all children in reverse order (so that first child ends up on top of the stack).
289
+ ins = len(stack)
290
+ for n in iter_children(current):
291
+ stack.insert(ins, (n, pvalue, _PREVISIT))
292
+ else:
293
+ ret = postvisit(current, par_value, cast(Optional[Token], value))
294
+ return ret
295
+
296
+
297
+ def walk(node, include_joined_str=False):
298
+ # type: (AST, bool) -> Iterator[Union[Module, AstNode]]
299
+ """
300
+ Recursively yield all descendant nodes in the tree starting at ``node`` (including ``node``
301
+ itself), using depth-first pre-order traversal (yieling parents before their children).
302
+
303
+ This is similar to ``ast.walk()``, but with a different order, and it works for both ``ast`` and
304
+ ``astroid`` trees. Also, as ``iter_children()``, it skips singleton nodes generated by ``ast``.
305
+
306
+ By default, ``JoinedStr`` (f-string) nodes and their contents are skipped
307
+ because they previously couldn't be handled. Set ``include_joined_str`` to True to include them.
308
+ """
309
+ iter_children = iter_children_func(node)
310
+ done = set()
311
+ stack = [node]
312
+ while stack:
313
+ current = stack.pop()
314
+ assert current not in done # protect againt infinite loop in case of a bad tree.
315
+ done.add(current)
316
+
317
+ yield current
318
+
319
+ # Insert all children in reverse order (so that first child ends up on top of the stack).
320
+ # This is faster than building a list and reversing it.
321
+ ins = len(stack)
322
+ for c in iter_children(current, include_joined_str):
323
+ stack.insert(ins, c)
324
+
325
+
326
+ def replace(text, replacements):
327
+ # type: (str, List[Tuple[int, int, str]]) -> str
328
+ """
329
+ Replaces multiple slices of text with new values. This is a convenience method for making code
330
+ modifications of ranges e.g. as identified by ``ASTTokens.get_text_range(node)``. Replacements is
331
+ an iterable of ``(start, end, new_text)`` tuples.
332
+
333
+ For example, ``replace("this is a test", [(0, 4, "X"), (8, 9, "THE")])`` produces
334
+ ``"X is THE test"``.
335
+ """
336
+ p = 0
337
+ parts = []
338
+ for (start, end, new_text) in sorted(replacements):
339
+ parts.append(text[p:start])
340
+ parts.append(new_text)
341
+ p = end
342
+ parts.append(text[p:])
343
+ return ''.join(parts)
344
+
345
+
346
+ class NodeMethods:
347
+ """
348
+ Helper to get `visit_{node_type}` methods given a node's class and cache the results.
349
+ """
350
+ def __init__(self):
351
+ # type: () -> None
352
+ self._cache = {} # type: Dict[Union[ABCMeta, type], Callable[[AstNode, Token, Token], Tuple[Token, Token]]]
353
+
354
+ def get(self, obj, cls):
355
+ # type: (Any, Union[ABCMeta, type]) -> Callable
356
+ """
357
+ Using the lowercase name of the class as node_type, returns `obj.visit_{node_type}`,
358
+ or `obj.visit_default` if the type-specific method is not found.
359
+ """
360
+ method = self._cache.get(cls)
361
+ if not method:
362
+ name = "visit_" + cls.__name__.lower()
363
+ method = getattr(obj, name, obj.visit_default)
364
+ self._cache[cls] = method
365
+ return method
366
+
367
+
368
+ def patched_generate_tokens(original_tokens):
369
+ # type: (Iterable[TokenInfo]) -> Iterator[TokenInfo]
370
+ """
371
+ Fixes tokens yielded by `tokenize.generate_tokens` to handle more non-ASCII characters in identifiers.
372
+ Workaround for https://github.com/python/cpython/issues/68382.
373
+ Should only be used when tokenizing a string that is known to be valid syntax,
374
+ because it assumes that error tokens are not actually errors.
375
+ Combines groups of consecutive NAME, NUMBER, and/or ERRORTOKEN tokens into a single NAME token.
376
+ """
377
+ group = [] # type: List[tokenize.TokenInfo]
378
+ for tok in original_tokens:
379
+ if (
380
+ tok.type in (tokenize.NAME, tokenize.ERRORTOKEN, tokenize.NUMBER)
381
+ # Only combine tokens if they have no whitespace in between
382
+ and (not group or group[-1].end == tok.start)
383
+ ):
384
+ group.append(tok)
385
+ else:
386
+ for combined_token in combine_tokens(group):
387
+ yield combined_token
388
+ group = []
389
+ yield tok
390
+ for combined_token in combine_tokens(group):
391
+ yield combined_token
392
+
393
+ def combine_tokens(group):
394
+ # type: (List[tokenize.TokenInfo]) -> List[tokenize.TokenInfo]
395
+ if not any(tok.type == tokenize.ERRORTOKEN for tok in group) or len({tok.line for tok in group}) != 1:
396
+ return group
397
+ return [
398
+ tokenize.TokenInfo(
399
+ type=tokenize.NAME,
400
+ string="".join(t.string for t in group),
401
+ start=group[0].start,
402
+ end=group[-1].end,
403
+ line=group[0].line,
404
+ )
405
+ ]
406
+
407
+
408
+ def last_stmt(node):
409
+ # type: (AstNode) -> AstNode
410
+ """
411
+ If the given AST node contains multiple statements, return the last one.
412
+ Otherwise, just return the node.
413
+ """
414
+ child_stmts = [
415
+ child for child in iter_children_func(node)(node)
416
+ if is_stmt(child) or type(child).__name__ in (
417
+ "excepthandler",
418
+ "ExceptHandler",
419
+ "match_case",
420
+ "MatchCase",
421
+ "TryExcept",
422
+ "TryFinally",
423
+ )
424
+ ]
425
+ if child_stmts:
426
+ return last_stmt(child_stmts[-1])
427
+ return node
428
+
429
+
430
+
431
+ @lru_cache(maxsize=None)
432
+ def fstring_positions_work():
433
+ # type: () -> bool
434
+ """
435
+ The positions attached to nodes inside f-string FormattedValues have some bugs
436
+ that were fixed in Python 3.9.7 in https://github.com/python/cpython/pull/27729.
437
+ This checks for those bugs more concretely without relying on the Python version.
438
+ Specifically this checks:
439
+ - Values with a format spec or conversion
440
+ - Repeated (i.e. identical-looking) expressions
441
+ - f-strings implicitly concatenated over multiple lines.
442
+ - Multiline, triple-quoted f-strings.
443
+ """
444
+ source = """(
445
+ f"a {b}{b} c {d!r} e {f:g} h {i:{j}} k {l:{m:n}}"
446
+ f"a {b}{b} c {d!r} e {f:g} h {i:{j}} k {l:{m:n}}"
447
+ f"{x + y + z} {x} {y} {z} {z} {z!a} {z:z}"
448
+ f'''
449
+ {s} {t}
450
+ {u} {v}
451
+ '''
452
+ )"""
453
+ tree = ast.parse(source)
454
+ name_nodes = [node for node in ast.walk(tree) if isinstance(node, ast.Name)]
455
+ name_positions = [(node.lineno, node.col_offset) for node in name_nodes]
456
+ positions_are_unique = len(set(name_positions)) == len(name_positions)
457
+ correct_source_segments = all(
458
+ ast.get_source_segment(source, node) == node.id
459
+ for node in name_nodes
460
+ )
461
+ return positions_are_unique and correct_source_segments
462
+
463
+ def annotate_fstring_nodes(tree):
464
+ # type: (ast.AST) -> None
465
+ """
466
+ Add a special attribute `_broken_positions` to nodes inside f-strings
467
+ if the lineno/col_offset cannot be trusted.
468
+ """
469
+ if sys.version_info >= (3, 12):
470
+ # f-strings were weirdly implemented until https://peps.python.org/pep-0701/
471
+ # In Python 3.12, inner nodes have sensible positions.
472
+ return
473
+ for joinedstr in walk(tree, include_joined_str=True):
474
+ if not isinstance(joinedstr, ast.JoinedStr):
475
+ continue
476
+ for part in joinedstr.values:
477
+ # The ast positions of the FormattedValues/Constant nodes span the full f-string, which is weird.
478
+ setattr(part, '_broken_positions', True) # use setattr for mypy
479
+
480
+ if isinstance(part, ast.FormattedValue):
481
+ if not fstring_positions_work():
482
+ for child in walk(part.value):
483
+ setattr(child, '_broken_positions', True)
484
+
485
+ if part.format_spec: # this is another JoinedStr
486
+ # Again, the standard positions span the full f-string.
487
+ setattr(part.format_spec, '_broken_positions', True)
lib/python3.12/site-packages/charset_normalizer-3.4.4.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ pip
lib/python3.12/site-packages/charset_normalizer-3.4.4.dist-info/METADATA ADDED
@@ -0,0 +1,764 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.4
2
+ Name: charset-normalizer
3
+ Version: 3.4.4
4
+ Summary: The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet.
5
+ Author-email: "Ahmed R. TAHRI" <tahri.ahmed@proton.me>
6
+ Maintainer-email: "Ahmed R. TAHRI" <tahri.ahmed@proton.me>
7
+ License: MIT
8
+ Project-URL: Changelog, https://github.com/jawah/charset_normalizer/blob/master/CHANGELOG.md
9
+ Project-URL: Documentation, https://charset-normalizer.readthedocs.io/
10
+ Project-URL: Code, https://github.com/jawah/charset_normalizer
11
+ Project-URL: Issue tracker, https://github.com/jawah/charset_normalizer/issues
12
+ Keywords: encoding,charset,charset-detector,detector,normalization,unicode,chardet,detect
13
+ Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.7
19
+ Classifier: Programming Language :: Python :: 3.8
20
+ Classifier: Programming Language :: Python :: 3.9
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Programming Language :: Python :: 3.13
25
+ Classifier: Programming Language :: Python :: 3.14
26
+ Classifier: Programming Language :: Python :: 3 :: Only
27
+ Classifier: Programming Language :: Python :: Implementation :: CPython
28
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
29
+ Classifier: Topic :: Text Processing :: Linguistic
30
+ Classifier: Topic :: Utilities
31
+ Classifier: Typing :: Typed
32
+ Requires-Python: >=3.7
33
+ Description-Content-Type: text/markdown
34
+ License-File: LICENSE
35
+ Provides-Extra: unicode-backport
36
+ Dynamic: license-file
37
+
38
+ <h1 align="center">Charset Detection, for Everyone 👋</h1>
39
+
40
+ <p align="center">
41
+ <sup>The Real First Universal Charset Detector</sup><br>
42
+ <a href="https://pypi.org/project/charset-normalizer">
43
+ <img src="https://img.shields.io/pypi/pyversions/charset_normalizer.svg?orange=blue" />
44
+ </a>
45
+ <a href="https://pepy.tech/project/charset-normalizer/">
46
+ <img alt="Download Count Total" src="https://static.pepy.tech/badge/charset-normalizer/month" />
47
+ </a>
48
+ <a href="https://bestpractices.coreinfrastructure.org/projects/7297">
49
+ <img src="https://bestpractices.coreinfrastructure.org/projects/7297/badge">
50
+ </a>
51
+ </p>
52
+ <p align="center">
53
+ <sup><i>Featured Packages</i></sup><br>
54
+ <a href="https://github.com/jawah/niquests">
55
+ <img alt="Static Badge" src="https://img.shields.io/badge/Niquests-Most_Advanced_HTTP_Client-cyan">
56
+ </a>
57
+ <a href="https://github.com/jawah/wassima">
58
+ <img alt="Static Badge" src="https://img.shields.io/badge/Wassima-Certifi_Replacement-cyan">
59
+ </a>
60
+ </p>
61
+ <p align="center">
62
+ <sup><i>In other language (unofficial port - by the community)</i></sup><br>
63
+ <a href="https://github.com/nickspring/charset-normalizer-rs">
64
+ <img alt="Static Badge" src="https://img.shields.io/badge/Rust-red">
65
+ </a>
66
+ </p>
67
+
68
+ > A library that helps you read text from an unknown charset encoding.<br /> Motivated by `chardet`,
69
+ > I'm trying to resolve the issue by taking a new approach.
70
+ > All IANA character set names for which the Python core library provides codecs are supported.
71
+
72
+ <p align="center">
73
+ >>>>> <a href="https://charsetnormalizerweb.ousret.now.sh" target="_blank">👉 Try Me Online Now, Then Adopt Me 👈 </a> <<<<<
74
+ </p>
75
+
76
+ This project offers you an alternative to **Universal Charset Encoding Detector**, also known as **Chardet**.
77
+
78
+ | Feature | [Chardet](https://github.com/chardet/chardet) | Charset Normalizer | [cChardet](https://github.com/PyYoshi/cChardet) |
79
+ |--------------------------------------------------|:---------------------------------------------:|:--------------------------------------------------------------------------------------------------:|:-----------------------------------------------:|
80
+ | `Fast` | ❌ | ✅ | ✅ |
81
+ | `Universal**` | ❌ | ✅ | ❌ |
82
+ | `Reliable` **without** distinguishable standards | ❌ | ✅ | ✅ |
83
+ | `Reliable` **with** distinguishable standards | ✅ | ✅ | ✅ |
84
+ | `License` | LGPL-2.1<br>_restrictive_ | MIT | MPL-1.1<br>_restrictive_ |
85
+ | `Native Python` | ✅ | ✅ | ❌ |
86
+ | `Detect spoken language` | ❌ | ✅ | N/A |
87
+ | `UnicodeDecodeError Safety` | ❌ | ✅ | ❌ |
88
+ | `Whl Size (min)` | 193.6 kB | 42 kB | ~200 kB |
89
+ | `Supported Encoding` | 33 | 🎉 [99](https://charset-normalizer.readthedocs.io/en/latest/user/support.html#supported-encodings) | 40 |
90
+
91
+ <p align="center">
92
+ <img src="https://i.imgflip.com/373iay.gif" alt="Reading Normalized Text" width="226"/><img src="https://media.tenor.com/images/c0180f70732a18b4965448d33adba3d0/tenor.gif" alt="Cat Reading Text" width="200"/>
93
+ </p>
94
+
95
+ *\*\* : They are clearly using specific code for a specific encoding even if covering most of used one*<br>
96
+
97
+ ## ⚡ Performance
98
+
99
+ This package offer better performance than its counterpart Chardet. Here are some numbers.
100
+
101
+ | Package | Accuracy | Mean per file (ms) | File per sec (est) |
102
+ |-----------------------------------------------|:--------:|:------------------:|:------------------:|
103
+ | [chardet](https://github.com/chardet/chardet) | 86 % | 63 ms | 16 file/sec |
104
+ | charset-normalizer | **98 %** | **10 ms** | 100 file/sec |
105
+
106
+ | Package | 99th percentile | 95th percentile | 50th percentile |
107
+ |-----------------------------------------------|:---------------:|:---------------:|:---------------:|
108
+ | [chardet](https://github.com/chardet/chardet) | 265 ms | 71 ms | 7 ms |
109
+ | charset-normalizer | 100 ms | 50 ms | 5 ms |
110
+
111
+ _updated as of december 2024 using CPython 3.12_
112
+
113
+ Chardet's performance on larger file (1MB+) are very poor. Expect huge difference on large payload.
114
+
115
+ > Stats are generated using 400+ files using default parameters. More details on used files, see GHA workflows.
116
+ > And yes, these results might change at any time. The dataset can be updated to include more files.
117
+ > The actual delays heavily depends on your CPU capabilities. The factors should remain the same.
118
+ > Keep in mind that the stats are generous and that Chardet accuracy vs our is measured using Chardet initial capability
119
+ > (e.g. Supported Encoding) Challenge-them if you want.
120
+
121
+ ## ✨ Installation
122
+
123
+ Using pip:
124
+
125
+ ```sh
126
+ pip install charset-normalizer -U
127
+ ```
128
+
129
+ ## 🚀 Basic Usage
130
+
131
+ ### CLI
132
+ This package comes with a CLI.
133
+
134
+ ```
135
+ usage: normalizer [-h] [-v] [-a] [-n] [-m] [-r] [-f] [-t THRESHOLD]
136
+ file [file ...]
137
+
138
+ The Real First Universal Charset Detector. Discover originating encoding used
139
+ on text file. Normalize text to unicode.
140
+
141
+ positional arguments:
142
+ files File(s) to be analysed
143
+
144
+ optional arguments:
145
+ -h, --help show this help message and exit
146
+ -v, --verbose Display complementary information about file if any.
147
+ Stdout will contain logs about the detection process.
148
+ -a, --with-alternative
149
+ Output complementary possibilities if any. Top-level
150
+ JSON WILL be a list.
151
+ -n, --normalize Permit to normalize input file. If not set, program
152
+ does not write anything.
153
+ -m, --minimal Only output the charset detected to STDOUT. Disabling
154
+ JSON output.
155
+ -r, --replace Replace file when trying to normalize it instead of
156
+ creating a new one.
157
+ -f, --force Replace file without asking if you are sure, use this
158
+ flag with caution.
159
+ -t THRESHOLD, --threshold THRESHOLD
160
+ Define a custom maximum amount of chaos allowed in
161
+ decoded content. 0. <= chaos <= 1.
162
+ --version Show version information and exit.
163
+ ```
164
+
165
+ ```bash
166
+ normalizer ./data/sample.1.fr.srt
167
+ ```
168
+
169
+ or
170
+
171
+ ```bash
172
+ python -m charset_normalizer ./data/sample.1.fr.srt
173
+ ```
174
+
175
+ 🎉 Since version 1.4.0 the CLI produce easily usable stdout result in JSON format.
176
+
177
+ ```json
178
+ {
179
+ "path": "/home/default/projects/charset_normalizer/data/sample.1.fr.srt",
180
+ "encoding": "cp1252",
181
+ "encoding_aliases": [
182
+ "1252",
183
+ "windows_1252"
184
+ ],
185
+ "alternative_encodings": [
186
+ "cp1254",
187
+ "cp1256",
188
+ "cp1258",
189
+ "iso8859_14",
190
+ "iso8859_15",
191
+ "iso8859_16",
192
+ "iso8859_3",
193
+ "iso8859_9",
194
+ "latin_1",
195
+ "mbcs"
196
+ ],
197
+ "language": "French",
198
+ "alphabets": [
199
+ "Basic Latin",
200
+ "Latin-1 Supplement"
201
+ ],
202
+ "has_sig_or_bom": false,
203
+ "chaos": 0.149,
204
+ "coherence": 97.152,
205
+ "unicode_path": null,
206
+ "is_preferred": true
207
+ }
208
+ ```
209
+
210
+ ### Python
211
+ *Just print out normalized text*
212
+ ```python
213
+ from charset_normalizer import from_path
214
+
215
+ results = from_path('./my_subtitle.srt')
216
+
217
+ print(str(results.best()))
218
+ ```
219
+
220
+ *Upgrade your code without effort*
221
+ ```python
222
+ from charset_normalizer import detect
223
+ ```
224
+
225
+ The above code will behave the same as **chardet**. We ensure that we offer the best (reasonable) BC result possible.
226
+
227
+ See the docs for advanced usage : [readthedocs.io](https://charset-normalizer.readthedocs.io/en/latest/)
228
+
229
+ ## 😇 Why
230
+
231
+ When I started using Chardet, I noticed that it was not suited to my expectations, and I wanted to propose a
232
+ reliable alternative using a completely different method. Also! I never back down on a good challenge!
233
+
234
+ I **don't care** about the **originating charset** encoding, because **two different tables** can
235
+ produce **two identical rendered string.**
236
+ What I want is to get readable text, the best I can.
237
+
238
+ In a way, **I'm brute forcing text decoding.** How cool is that ? 😎
239
+
240
+ Don't confuse package **ftfy** with charset-normalizer or chardet. ftfy goal is to repair Unicode string whereas charset-normalizer to convert raw file in unknown encoding to unicode.
241
+
242
+ ## 🍰 How
243
+
244
+ - Discard all charset encoding table that could not fit the binary content.
245
+ - Measure noise, or the mess once opened (by chunks) with a corresponding charset encoding.
246
+ - Extract matches with the lowest mess detected.
247
+ - Additionally, we measure coherence / probe for a language.
248
+
249
+ **Wait a minute**, what is noise/mess and coherence according to **YOU ?**
250
+
251
+ *Noise :* I opened hundred of text files, **written by humans**, with the wrong encoding table. **I observed**, then
252
+ **I established** some ground rules about **what is obvious** when **it seems like** a mess (aka. defining noise in rendered text).
253
+ I know that my interpretation of what is noise is probably incomplete, feel free to contribute in order to
254
+ improve or rewrite it.
255
+
256
+ *Coherence :* For each language there is on earth, we have computed ranked letter appearance occurrences (the best we can). So I thought
257
+ that intel is worth something here. So I use those records against decoded text to check if I can detect intelligent design.
258
+
259
+ ## ⚡ Known limitations
260
+
261
+ - Language detection is unreliable when text contains two or more languages sharing identical letters. (eg. HTML (english tags) + Turkish content (Sharing Latin characters))
262
+ - Every charset detector heavily depends on sufficient content. In common cases, do not bother run detection on very tiny content.
263
+
264
+ ## ⚠️ About Python EOLs
265
+
266
+ **If you are running:**
267
+
268
+ - Python >=2.7,<3.5: Unsupported
269
+ - Python 3.5: charset-normalizer < 2.1
270
+ - Python 3.6: charset-normalizer < 3.1
271
+ - Python 3.7: charset-normalizer < 4.0
272
+
273
+ Upgrade your Python interpreter as soon as possible.
274
+
275
+ ## 👤 Contributing
276
+
277
+ Contributions, issues and feature requests are very much welcome.<br />
278
+ Feel free to check [issues page](https://github.com/ousret/charset_normalizer/issues) if you want to contribute.
279
+
280
+ ## 📝 License
281
+
282
+ Copyright © [Ahmed TAHRI @Ousret](https://github.com/Ousret).<br />
283
+ This project is [MIT](https://github.com/Ousret/charset_normalizer/blob/master/LICENSE) licensed.
284
+
285
+ Characters frequencies used in this project © 2012 [Denny Vrandečić](http://simia.net/letters/)
286
+
287
+ ## 💼 For Enterprise
288
+
289
+ Professional support for charset-normalizer is available as part of the [Tidelift
290
+ Subscription][1]. Tidelift gives software development teams a single source for
291
+ purchasing and maintaining their software, with professional grade assurances
292
+ from the experts who know it best, while seamlessly integrating with existing
293
+ tools.
294
+
295
+ [1]: https://tidelift.com/subscription/pkg/pypi-charset-normalizer?utm_source=pypi-charset-normalizer&utm_medium=readme
296
+
297
+ [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/7297/badge)](https://www.bestpractices.dev/projects/7297)
298
+
299
+ # Changelog
300
+ All notable changes to charset-normalizer will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
301
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
302
+
303
+ ## [3.4.4](https://github.com/Ousret/charset_normalizer/compare/3.4.2...3.4.4) (2025-10-13)
304
+
305
+ ### Changed
306
+ - Bound `setuptools` to a specific constraint `setuptools>=68,<=81`.
307
+ - Raised upper bound of mypyc for the optional pre-built extension to v1.18.2
308
+
309
+ ### Removed
310
+ - `setuptools-scm` as a build dependency.
311
+
312
+ ### Misc
313
+ - Enforced hashes in `dev-requirements.txt` and created `ci-requirements.txt` for security purposes.
314
+ - Additional pre-built wheels for riscv64, s390x, and armv7l architectures.
315
+ - Restore ` multiple.intoto.jsonl` in GitHub releases in addition to individual attestation file per wheel.
316
+
317
+ ## [3.4.3](https://github.com/Ousret/charset_normalizer/compare/3.4.2...3.4.3) (2025-08-09)
318
+
319
+ ### Changed
320
+ - mypy(c) is no longer a required dependency at build time if `CHARSET_NORMALIZER_USE_MYPYC` isn't set to `1`. (#595) (#583)
321
+ - automatically lower confidence on small bytes samples that are not Unicode in `detect` output legacy function. (#391)
322
+
323
+ ### Added
324
+ - Custom build backend to overcome inability to mark mypy as an optional dependency in the build phase.
325
+ - Support for Python 3.14
326
+
327
+ ### Fixed
328
+ - sdist archive contained useless directories.
329
+ - automatically fallback on valid UTF-16 or UTF-32 even if the md says it's noisy. (#633)
330
+
331
+ ### Misc
332
+ - SBOM are automatically published to the relevant GitHub release to comply with regulatory changes.
333
+ Each published wheel comes with its SBOM. We choose CycloneDX as the format.
334
+ - Prebuilt optimized wheel are no longer distributed by default for CPython 3.7 due to a change in cibuildwheel.
335
+
336
+ ## [3.4.2](https://github.com/Ousret/charset_normalizer/compare/3.4.1...3.4.2) (2025-05-02)
337
+
338
+ ### Fixed
339
+ - Addressed the DeprecationWarning in our CLI regarding `argparse.FileType` by backporting the target class into the package. (#591)
340
+ - Improved the overall reliability of the detector with CJK Ideographs. (#605) (#587)
341
+
342
+ ### Changed
343
+ - Optional mypyc compilation upgraded to version 1.15 for Python >= 3.8
344
+
345
+ ## [3.4.1](https://github.com/Ousret/charset_normalizer/compare/3.4.0...3.4.1) (2024-12-24)
346
+
347
+ ### Changed
348
+ - Project metadata are now stored using `pyproject.toml` instead of `setup.cfg` using setuptools as the build backend.
349
+ - Enforce annotation delayed loading for a simpler and consistent types in the project.
350
+ - Optional mypyc compilation upgraded to version 1.14 for Python >= 3.8
351
+
352
+ ### Added
353
+ - pre-commit configuration.
354
+ - noxfile.
355
+
356
+ ### Removed
357
+ - `build-requirements.txt` as per using `pyproject.toml` native build configuration.
358
+ - `bin/integration.py` and `bin/serve.py` in favor of downstream integration test (see noxfile).
359
+ - `setup.cfg` in favor of `pyproject.toml` metadata configuration.
360
+ - Unused `utils.range_scan` function.
361
+
362
+ ### Fixed
363
+ - Converting content to Unicode bytes may insert `utf_8` instead of preferred `utf-8`. (#572)
364
+ - Deprecation warning "'count' is passed as positional argument" when converting to Unicode bytes on Python 3.13+
365
+
366
+ ## [3.4.0](https://github.com/Ousret/charset_normalizer/compare/3.3.2...3.4.0) (2024-10-08)
367
+
368
+ ### Added
369
+ - Argument `--no-preemptive` in the CLI to prevent the detector to search for hints.
370
+ - Support for Python 3.13 (#512)
371
+
372
+ ### Fixed
373
+ - Relax the TypeError exception thrown when trying to compare a CharsetMatch with anything else than a CharsetMatch.
374
+ - Improved the general reliability of the detector based on user feedbacks. (#520) (#509) (#498) (#407) (#537)
375
+ - Declared charset in content (preemptive detection) not changed when converting to utf-8 bytes. (#381)
376
+
377
+ ## [3.3.2](https://github.com/Ousret/charset_normalizer/compare/3.3.1...3.3.2) (2023-10-31)
378
+
379
+ ### Fixed
380
+ - Unintentional memory usage regression when using large payload that match several encoding (#376)
381
+ - Regression on some detection case showcased in the documentation (#371)
382
+
383
+ ### Added
384
+ - Noise (md) probe that identify malformed arabic representation due to the presence of letters in isolated form (credit to my wife)
385
+
386
+ ## [3.3.1](https://github.com/Ousret/charset_normalizer/compare/3.3.0...3.3.1) (2023-10-22)
387
+
388
+ ### Changed
389
+ - Optional mypyc compilation upgraded to version 1.6.1 for Python >= 3.8
390
+ - Improved the general detection reliability based on reports from the community
391
+
392
+ ## [3.3.0](https://github.com/Ousret/charset_normalizer/compare/3.2.0...3.3.0) (2023-09-30)
393
+
394
+ ### Added
395
+ - Allow to execute the CLI (e.g. normalizer) through `python -m charset_normalizer.cli` or `python -m charset_normalizer`
396
+ - Support for 9 forgotten encoding that are supported by Python but unlisted in `encoding.aliases` as they have no alias (#323)
397
+
398
+ ### Removed
399
+ - (internal) Redundant utils.is_ascii function and unused function is_private_use_only
400
+ - (internal) charset_normalizer.assets is moved inside charset_normalizer.constant
401
+
402
+ ### Changed
403
+ - (internal) Unicode code blocks in constants are updated using the latest v15.0.0 definition to improve detection
404
+ - Optional mypyc compilation upgraded to version 1.5.1 for Python >= 3.8
405
+
406
+ ### Fixed
407
+ - Unable to properly sort CharsetMatch when both chaos/noise and coherence were close due to an unreachable condition in \_\_lt\_\_ (#350)
408
+
409
+ ## [3.2.0](https://github.com/Ousret/charset_normalizer/compare/3.1.0...3.2.0) (2023-06-07)
410
+
411
+ ### Changed
412
+ - Typehint for function `from_path` no longer enforce `PathLike` as its first argument
413
+ - Minor improvement over the global detection reliability
414
+
415
+ ### Added
416
+ - Introduce function `is_binary` that relies on main capabilities, and optimized to detect binaries
417
+ - Propagate `enable_fallback` argument throughout `from_bytes`, `from_path`, and `from_fp` that allow a deeper control over the detection (default True)
418
+ - Explicit support for Python 3.12
419
+
420
+ ### Fixed
421
+ - Edge case detection failure where a file would contain 'very-long' camel cased word (Issue #289)
422
+
423
+ ## [3.1.0](https://github.com/Ousret/charset_normalizer/compare/3.0.1...3.1.0) (2023-03-06)
424
+
425
+ ### Added
426
+ - Argument `should_rename_legacy` for legacy function `detect` and disregard any new arguments without errors (PR #262)
427
+
428
+ ### Removed
429
+ - Support for Python 3.6 (PR #260)
430
+
431
+ ### Changed
432
+ - Optional speedup provided by mypy/c 1.0.1
433
+
434
+ ## [3.0.1](https://github.com/Ousret/charset_normalizer/compare/3.0.0...3.0.1) (2022-11-18)
435
+
436
+ ### Fixed
437
+ - Multi-bytes cutter/chunk generator did not always cut correctly (PR #233)
438
+
439
+ ### Changed
440
+ - Speedup provided by mypy/c 0.990 on Python >= 3.7
441
+
442
+ ## [3.0.0](https://github.com/Ousret/charset_normalizer/compare/2.1.1...3.0.0) (2022-10-20)
443
+
444
+ ### Added
445
+ - Extend the capability of explain=True when cp_isolation contains at most two entries (min one), will log in details of the Mess-detector results
446
+ - Support for alternative language frequency set in charset_normalizer.assets.FREQUENCIES
447
+ - Add parameter `language_threshold` in `from_bytes`, `from_path` and `from_fp` to adjust the minimum expected coherence ratio
448
+ - `normalizer --version` now specify if current version provide extra speedup (meaning mypyc compilation whl)
449
+
450
+ ### Changed
451
+ - Build with static metadata using 'build' frontend
452
+ - Make the language detection stricter
453
+ - Optional: Module `md.py` can be compiled using Mypyc to provide an extra speedup up to 4x faster than v2.1
454
+
455
+ ### Fixed
456
+ - CLI with opt --normalize fail when using full path for files
457
+ - TooManyAccentuatedPlugin induce false positive on the mess detection when too few alpha character have been fed to it
458
+ - Sphinx warnings when generating the documentation
459
+
460
+ ### Removed
461
+ - Coherence detector no longer return 'Simple English' instead return 'English'
462
+ - Coherence detector no longer return 'Classical Chinese' instead return 'Chinese'
463
+ - Breaking: Method `first()` and `best()` from CharsetMatch
464
+ - UTF-7 will no longer appear as "detected" without a recognized SIG/mark (is unreliable/conflict with ASCII)
465
+ - Breaking: Class aliases CharsetDetector, CharsetDoctor, CharsetNormalizerMatch and CharsetNormalizerMatches
466
+ - Breaking: Top-level function `normalize`
467
+ - Breaking: Properties `chaos_secondary_pass`, `coherence_non_latin` and `w_counter` from CharsetMatch
468
+ - Support for the backport `unicodedata2`
469
+
470
+ ## [3.0.0rc1](https://github.com/Ousret/charset_normalizer/compare/3.0.0b2...3.0.0rc1) (2022-10-18)
471
+
472
+ ### Added
473
+ - Extend the capability of explain=True when cp_isolation contains at most two entries (min one), will log in details of the Mess-detector results
474
+ - Support for alternative language frequency set in charset_normalizer.assets.FREQUENCIES
475
+ - Add parameter `language_threshold` in `from_bytes`, `from_path` and `from_fp` to adjust the minimum expected coherence ratio
476
+
477
+ ### Changed
478
+ - Build with static metadata using 'build' frontend
479
+ - Make the language detection stricter
480
+
481
+ ### Fixed
482
+ - CLI with opt --normalize fail when using full path for files
483
+ - TooManyAccentuatedPlugin induce false positive on the mess detection when too few alpha character have been fed to it
484
+
485
+ ### Removed
486
+ - Coherence detector no longer return 'Simple English' instead return 'English'
487
+ - Coherence detector no longer return 'Classical Chinese' instead return 'Chinese'
488
+
489
+ ## [3.0.0b2](https://github.com/Ousret/charset_normalizer/compare/3.0.0b1...3.0.0b2) (2022-08-21)
490
+
491
+ ### Added
492
+ - `normalizer --version` now specify if current version provide extra speedup (meaning mypyc compilation whl)
493
+
494
+ ### Removed
495
+ - Breaking: Method `first()` and `best()` from CharsetMatch
496
+ - UTF-7 will no longer appear as "detected" without a recognized SIG/mark (is unreliable/conflict with ASCII)
497
+
498
+ ### Fixed
499
+ - Sphinx warnings when generating the documentation
500
+
501
+ ## [3.0.0b1](https://github.com/Ousret/charset_normalizer/compare/2.1.0...3.0.0b1) (2022-08-15)
502
+
503
+ ### Changed
504
+ - Optional: Module `md.py` can be compiled using Mypyc to provide an extra speedup up to 4x faster than v2.1
505
+
506
+ ### Removed
507
+ - Breaking: Class aliases CharsetDetector, CharsetDoctor, CharsetNormalizerMatch and CharsetNormalizerMatches
508
+ - Breaking: Top-level function `normalize`
509
+ - Breaking: Properties `chaos_secondary_pass`, `coherence_non_latin` and `w_counter` from CharsetMatch
510
+ - Support for the backport `unicodedata2`
511
+
512
+ ## [2.1.1](https://github.com/Ousret/charset_normalizer/compare/2.1.0...2.1.1) (2022-08-19)
513
+
514
+ ### Deprecated
515
+ - Function `normalize` scheduled for removal in 3.0
516
+
517
+ ### Changed
518
+ - Removed useless call to decode in fn is_unprintable (#206)
519
+
520
+ ### Fixed
521
+ - Third-party library (i18n xgettext) crashing not recognizing utf_8 (PEP 263) with underscore from [@aleksandernovikov](https://github.com/aleksandernovikov) (#204)
522
+
523
+ ## [2.1.0](https://github.com/Ousret/charset_normalizer/compare/2.0.12...2.1.0) (2022-06-19)
524
+
525
+ ### Added
526
+ - Output the Unicode table version when running the CLI with `--version` (PR #194)
527
+
528
+ ### Changed
529
+ - Re-use decoded buffer for single byte character sets from [@nijel](https://github.com/nijel) (PR #175)
530
+ - Fixing some performance bottlenecks from [@deedy5](https://github.com/deedy5) (PR #183)
531
+
532
+ ### Fixed
533
+ - Workaround potential bug in cpython with Zero Width No-Break Space located in Arabic Presentation Forms-B, Unicode 1.1 not acknowledged as space (PR #175)
534
+ - CLI default threshold aligned with the API threshold from [@oleksandr-kuzmenko](https://github.com/oleksandr-kuzmenko) (PR #181)
535
+
536
+ ### Removed
537
+ - Support for Python 3.5 (PR #192)
538
+
539
+ ### Deprecated
540
+ - Use of backport unicodedata from `unicodedata2` as Python is quickly catching up, scheduled for removal in 3.0 (PR #194)
541
+
542
+ ## [2.0.12](https://github.com/Ousret/charset_normalizer/compare/2.0.11...2.0.12) (2022-02-12)
543
+
544
+ ### Fixed
545
+ - ASCII miss-detection on rare cases (PR #170)
546
+
547
+ ## [2.0.11](https://github.com/Ousret/charset_normalizer/compare/2.0.10...2.0.11) (2022-01-30)
548
+
549
+ ### Added
550
+ - Explicit support for Python 3.11 (PR #164)
551
+
552
+ ### Changed
553
+ - The logging behavior have been completely reviewed, now using only TRACE and DEBUG levels (PR #163 #165)
554
+
555
+ ## [2.0.10](https://github.com/Ousret/charset_normalizer/compare/2.0.9...2.0.10) (2022-01-04)
556
+
557
+ ### Fixed
558
+ - Fallback match entries might lead to UnicodeDecodeError for large bytes sequence (PR #154)
559
+
560
+ ### Changed
561
+ - Skipping the language-detection (CD) on ASCII (PR #155)
562
+
563
+ ## [2.0.9](https://github.com/Ousret/charset_normalizer/compare/2.0.8...2.0.9) (2021-12-03)
564
+
565
+ ### Changed
566
+ - Moderating the logging impact (since 2.0.8) for specific environments (PR #147)
567
+
568
+ ### Fixed
569
+ - Wrong logging level applied when setting kwarg `explain` to True (PR #146)
570
+
571
+ ## [2.0.8](https://github.com/Ousret/charset_normalizer/compare/2.0.7...2.0.8) (2021-11-24)
572
+ ### Changed
573
+ - Improvement over Vietnamese detection (PR #126)
574
+ - MD improvement on trailing data and long foreign (non-pure latin) data (PR #124)
575
+ - Efficiency improvements in cd/alphabet_languages from [@adbar](https://github.com/adbar) (PR #122)
576
+ - call sum() without an intermediary list following PEP 289 recommendations from [@adbar](https://github.com/adbar) (PR #129)
577
+ - Code style as refactored by Sourcery-AI (PR #131)
578
+ - Minor adjustment on the MD around european words (PR #133)
579
+ - Remove and replace SRTs from assets / tests (PR #139)
580
+ - Initialize the library logger with a `NullHandler` by default from [@nmaynes](https://github.com/nmaynes) (PR #135)
581
+ - Setting kwarg `explain` to True will add provisionally (bounded to function lifespan) a specific stream handler (PR #135)
582
+
583
+ ### Fixed
584
+ - Fix large (misleading) sequence giving UnicodeDecodeError (PR #137)
585
+ - Avoid using too insignificant chunk (PR #137)
586
+
587
+ ### Added
588
+ - Add and expose function `set_logging_handler` to configure a specific StreamHandler from [@nmaynes](https://github.com/nmaynes) (PR #135)
589
+ - Add `CHANGELOG.md` entries, format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) (PR #141)
590
+
591
+ ## [2.0.7](https://github.com/Ousret/charset_normalizer/compare/2.0.6...2.0.7) (2021-10-11)
592
+ ### Added
593
+ - Add support for Kazakh (Cyrillic) language detection (PR #109)
594
+
595
+ ### Changed
596
+ - Further, improve inferring the language from a given single-byte code page (PR #112)
597
+ - Vainly trying to leverage PEP263 when PEP3120 is not supported (PR #116)
598
+ - Refactoring for potential performance improvements in loops from [@adbar](https://github.com/adbar) (PR #113)
599
+ - Various detection improvement (MD+CD) (PR #117)
600
+
601
+ ### Removed
602
+ - Remove redundant logging entry about detected language(s) (PR #115)
603
+
604
+ ### Fixed
605
+ - Fix a minor inconsistency between Python 3.5 and other versions regarding language detection (PR #117 #102)
606
+
607
+ ## [2.0.6](https://github.com/Ousret/charset_normalizer/compare/2.0.5...2.0.6) (2021-09-18)
608
+ ### Fixed
609
+ - Unforeseen regression with the loss of the backward-compatibility with some older minor of Python 3.5.x (PR #100)
610
+ - Fix CLI crash when using --minimal output in certain cases (PR #103)
611
+
612
+ ### Changed
613
+ - Minor improvement to the detection efficiency (less than 1%) (PR #106 #101)
614
+
615
+ ## [2.0.5](https://github.com/Ousret/charset_normalizer/compare/2.0.4...2.0.5) (2021-09-14)
616
+ ### Changed
617
+ - The project now comply with: flake8, mypy, isort and black to ensure a better overall quality (PR #81)
618
+ - The BC-support with v1.x was improved, the old staticmethods are restored (PR #82)
619
+ - The Unicode detection is slightly improved (PR #93)
620
+ - Add syntax sugar \_\_bool\_\_ for results CharsetMatches list-container (PR #91)
621
+
622
+ ### Removed
623
+ - The project no longer raise warning on tiny content given for detection, will be simply logged as warning instead (PR #92)
624
+
625
+ ### Fixed
626
+ - In some rare case, the chunks extractor could cut in the middle of a multi-byte character and could mislead the mess detection (PR #95)
627
+ - Some rare 'space' characters could trip up the UnprintablePlugin/Mess detection (PR #96)
628
+ - The MANIFEST.in was not exhaustive (PR #78)
629
+
630
+ ## [2.0.4](https://github.com/Ousret/charset_normalizer/compare/2.0.3...2.0.4) (2021-07-30)
631
+ ### Fixed
632
+ - The CLI no longer raise an unexpected exception when no encoding has been found (PR #70)
633
+ - Fix accessing the 'alphabets' property when the payload contains surrogate characters (PR #68)
634
+ - The logger could mislead (explain=True) on detected languages and the impact of one MBCS match (PR #72)
635
+ - Submatch factoring could be wrong in rare edge cases (PR #72)
636
+ - Multiple files given to the CLI were ignored when publishing results to STDOUT. (After the first path) (PR #72)
637
+ - Fix line endings from CRLF to LF for certain project files (PR #67)
638
+
639
+ ### Changed
640
+ - Adjust the MD to lower the sensitivity, thus improving the global detection reliability (PR #69 #76)
641
+ - Allow fallback on specified encoding if any (PR #71)
642
+
643
+ ## [2.0.3](https://github.com/Ousret/charset_normalizer/compare/2.0.2...2.0.3) (2021-07-16)
644
+ ### Changed
645
+ - Part of the detection mechanism has been improved to be less sensitive, resulting in more accurate detection results. Especially ASCII. (PR #63)
646
+ - According to the community wishes, the detection will fall back on ASCII or UTF-8 in a last-resort case. (PR #64)
647
+
648
+ ## [2.0.2](https://github.com/Ousret/charset_normalizer/compare/2.0.1...2.0.2) (2021-07-15)
649
+ ### Fixed
650
+ - Empty/Too small JSON payload miss-detection fixed. Report from [@tseaver](https://github.com/tseaver) (PR #59)
651
+
652
+ ### Changed
653
+ - Don't inject unicodedata2 into sys.modules from [@akx](https://github.com/akx) (PR #57)
654
+
655
+ ## [2.0.1](https://github.com/Ousret/charset_normalizer/compare/2.0.0...2.0.1) (2021-07-13)
656
+ ### Fixed
657
+ - Make it work where there isn't a filesystem available, dropping assets frequencies.json. Report from [@sethmlarson](https://github.com/sethmlarson). (PR #55)
658
+ - Using explain=False permanently disable the verbose output in the current runtime (PR #47)
659
+ - One log entry (language target preemptive) was not show in logs when using explain=True (PR #47)
660
+ - Fix undesired exception (ValueError) on getitem of instance CharsetMatches (PR #52)
661
+
662
+ ### Changed
663
+ - Public function normalize default args values were not aligned with from_bytes (PR #53)
664
+
665
+ ### Added
666
+ - You may now use charset aliases in cp_isolation and cp_exclusion arguments (PR #47)
667
+
668
+ ## [2.0.0](https://github.com/Ousret/charset_normalizer/compare/1.4.1...2.0.0) (2021-07-02)
669
+ ### Changed
670
+ - 4x to 5 times faster than the previous 1.4.0 release. At least 2x faster than Chardet.
671
+ - Accent has been made on UTF-8 detection, should perform rather instantaneous.
672
+ - The backward compatibility with Chardet has been greatly improved. The legacy detect function returns an identical charset name whenever possible.
673
+ - The detection mechanism has been slightly improved, now Turkish content is detected correctly (most of the time)
674
+ - The program has been rewritten to ease the readability and maintainability. (+Using static typing)+
675
+ - utf_7 detection has been reinstated.
676
+
677
+ ### Removed
678
+ - This package no longer require anything when used with Python 3.5 (Dropped cached_property)
679
+ - Removed support for these languages: Catalan, Esperanto, Kazakh, Baque, Volapük, Azeri, Galician, Nynorsk, Macedonian, and Serbocroatian.
680
+ - The exception hook on UnicodeDecodeError has been removed.
681
+
682
+ ### Deprecated
683
+ - Methods coherence_non_latin, w_counter, chaos_secondary_pass of the class CharsetMatch are now deprecated and scheduled for removal in v3.0
684
+
685
+ ### Fixed
686
+ - The CLI output used the relative path of the file(s). Should be absolute.
687
+
688
+ ## [1.4.1](https://github.com/Ousret/charset_normalizer/compare/1.4.0...1.4.1) (2021-05-28)
689
+ ### Fixed
690
+ - Logger configuration/usage no longer conflict with others (PR #44)
691
+
692
+ ## [1.4.0](https://github.com/Ousret/charset_normalizer/compare/1.3.9...1.4.0) (2021-05-21)
693
+ ### Removed
694
+ - Using standard logging instead of using the package loguru.
695
+ - Dropping nose test framework in favor of the maintained pytest.
696
+ - Choose to not use dragonmapper package to help with gibberish Chinese/CJK text.
697
+ - Require cached_property only for Python 3.5 due to constraint. Dropping for every other interpreter version.
698
+ - Stop support for UTF-7 that does not contain a SIG.
699
+ - Dropping PrettyTable, replaced with pure JSON output in CLI.
700
+
701
+ ### Fixed
702
+ - BOM marker in a CharsetNormalizerMatch instance could be False in rare cases even if obviously present. Due to the sub-match factoring process.
703
+ - Not searching properly for the BOM when trying utf32/16 parent codec.
704
+
705
+ ### Changed
706
+ - Improving the package final size by compressing frequencies.json.
707
+ - Huge improvement over the larges payload.
708
+
709
+ ### Added
710
+ - CLI now produces JSON consumable output.
711
+ - Return ASCII if given sequences fit. Given reasonable confidence.
712
+
713
+ ## [1.3.9](https://github.com/Ousret/charset_normalizer/compare/1.3.8...1.3.9) (2021-05-13)
714
+
715
+ ### Fixed
716
+ - In some very rare cases, you may end up getting encode/decode errors due to a bad bytes payload (PR #40)
717
+
718
+ ## [1.3.8](https://github.com/Ousret/charset_normalizer/compare/1.3.7...1.3.8) (2021-05-12)
719
+
720
+ ### Fixed
721
+ - Empty given payload for detection may cause an exception if trying to access the `alphabets` property. (PR #39)
722
+
723
+ ## [1.3.7](https://github.com/Ousret/charset_normalizer/compare/1.3.6...1.3.7) (2021-05-12)
724
+
725
+ ### Fixed
726
+ - The legacy detect function should return UTF-8-SIG if sig is present in the payload. (PR #38)
727
+
728
+ ## [1.3.6](https://github.com/Ousret/charset_normalizer/compare/1.3.5...1.3.6) (2021-02-09)
729
+
730
+ ### Changed
731
+ - Amend the previous release to allow prettytable 2.0 (PR #35)
732
+
733
+ ## [1.3.5](https://github.com/Ousret/charset_normalizer/compare/1.3.4...1.3.5) (2021-02-08)
734
+
735
+ ### Fixed
736
+ - Fix error while using the package with a python pre-release interpreter (PR #33)
737
+
738
+ ### Changed
739
+ - Dependencies refactoring, constraints revised.
740
+
741
+ ### Added
742
+ - Add python 3.9 and 3.10 to the supported interpreters
743
+
744
+ MIT License
745
+
746
+ Copyright (c) 2025 TAHRI Ahmed R.
747
+
748
+ Permission is hereby granted, free of charge, to any person obtaining a copy
749
+ of this software and associated documentation files (the "Software"), to deal
750
+ in the Software without restriction, including without limitation the rights
751
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
752
+ copies of the Software, and to permit persons to whom the Software is
753
+ furnished to do so, subject to the following conditions:
754
+
755
+ The above copyright notice and this permission notice shall be included in all
756
+ copies or substantial portions of the Software.
757
+
758
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
759
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
760
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
761
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
762
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
763
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
764
+ SOFTWARE.
lib/python3.12/site-packages/charset_normalizer-3.4.4.dist-info/RECORD ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ../../../bin/normalizer,sha256=n68xuWjXo6taHTYOiNut7Va3FDsRj1XCmzJUDDTkTr4,269
2
+ charset_normalizer-3.4.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
3
+ charset_normalizer-3.4.4.dist-info/METADATA,sha256=jVuUFBti8dav19YLvWissTihVdF2ozUY4KKMw7jdkBQ,37303
4
+ charset_normalizer-3.4.4.dist-info/RECORD,,
5
+ charset_normalizer-3.4.4.dist-info/WHEEL,sha256=DxRnWQz-Kp9-4a4hdDHsSv0KUC3H7sN9Nbef3-8RjXU,190
6
+ charset_normalizer-3.4.4.dist-info/entry_points.txt,sha256=ADSTKrkXZ3hhdOVFi6DcUEHQRS0xfxDIE_pEz4wLIXA,65
7
+ charset_normalizer-3.4.4.dist-info/licenses/LICENSE,sha256=bQ1Bv-FwrGx9wkjJpj4lTQ-0WmDVCoJX0K-SxuJJuIc,1071
8
+ charset_normalizer-3.4.4.dist-info/top_level.txt,sha256=7ASyzePr8_xuZWJsnqJjIBtyV8vhEo0wBCv1MPRRi3Q,19
9
+ charset_normalizer/__init__.py,sha256=OKRxRv2Zhnqk00tqkN0c1BtJjm165fWXLydE52IKuHc,1590
10
+ charset_normalizer/__main__.py,sha256=yzYxMR-IhKRHYwcSlavEv8oGdwxsR89mr2X09qXGdps,109
11
+ charset_normalizer/__pycache__/__init__.cpython-312.pyc,,
12
+ charset_normalizer/__pycache__/__main__.cpython-312.pyc,,
13
+ charset_normalizer/__pycache__/api.cpython-312.pyc,,
14
+ charset_normalizer/__pycache__/cd.cpython-312.pyc,,
15
+ charset_normalizer/__pycache__/constant.cpython-312.pyc,,
16
+ charset_normalizer/__pycache__/legacy.cpython-312.pyc,,
17
+ charset_normalizer/__pycache__/md.cpython-312.pyc,,
18
+ charset_normalizer/__pycache__/models.cpython-312.pyc,,
19
+ charset_normalizer/__pycache__/utils.cpython-312.pyc,,
20
+ charset_normalizer/__pycache__/version.cpython-312.pyc,,
21
+ charset_normalizer/api.py,sha256=V07i8aVeCD8T2fSia3C-fn0i9t8qQguEBhsqszg32Ns,22668
22
+ charset_normalizer/cd.py,sha256=WKTo1HDb-H9HfCDc3Bfwq5jzS25Ziy9SE2a74SgTq88,12522
23
+ charset_normalizer/cli/__init__.py,sha256=D8I86lFk2-py45JvqxniTirSj_sFyE6sjaY_0-G1shc,136
24
+ charset_normalizer/cli/__main__.py,sha256=dMaXG6IJXRvqq8z2tig7Qb83-BpWTln55ooiku5_uvg,12646
25
+ charset_normalizer/cli/__pycache__/__init__.cpython-312.pyc,,
26
+ charset_normalizer/cli/__pycache__/__main__.cpython-312.pyc,,
27
+ charset_normalizer/constant.py,sha256=7UVY4ldYhmQMHUdgQ_sgZmzcQ0xxYxpBunqSZ-XJZ8U,42713
28
+ charset_normalizer/legacy.py,sha256=sYBzSpzsRrg_wF4LP536pG64BItw7Tqtc3SMQAHvFLM,2731
29
+ charset_normalizer/md.cpython-312-x86_64-linux-gnu.so,sha256=sZ7umtJLjKfA83NFJ7npkiDyr06zDT8cWtl6uIx2MsM,15912
30
+ charset_normalizer/md.py,sha256=-_oN3h3_X99nkFfqamD3yu45DC_wfk5odH0Tr_CQiXs,20145
31
+ charset_normalizer/md__mypyc.cpython-312-x86_64-linux-gnu.so,sha256=J2WWgLBQiO8sqdFsENp9u5V9uEH0tTwvTLszPdqhsv0,290584
32
+ charset_normalizer/models.py,sha256=lKXhOnIPtiakbK3i__J9wpOfzx3JDTKj7Dn3Rg0VaRI,12394
33
+ charset_normalizer/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
+ charset_normalizer/utils.py,sha256=sTejPgrdlNsKNucZfJCxJ95lMTLA0ShHLLE3n5wpT9Q,12170
35
+ charset_normalizer/version.py,sha256=nKE4qBNk5WA4LIJ_yIH_aSDfvtsyizkWMg-PUG-UZVk,115
lib/python3.12/site-packages/charset_normalizer-3.4.4.dist-info/WHEEL ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: false
4
+ Tag: cp312-cp312-manylinux_2_17_x86_64
5
+ Tag: cp312-cp312-manylinux2014_x86_64
6
+ Tag: cp312-cp312-manylinux_2_28_x86_64
7
+
lib/python3.12/site-packages/charset_normalizer-3.4.4.dist-info/entry_points.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ [console_scripts]
2
+ normalizer = charset_normalizer.cli:cli_detect
lib/python3.12/site-packages/charset_normalizer-3.4.4.dist-info/licenses/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2025 TAHRI Ahmed R.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
lib/python3.12/site-packages/charset_normalizer-3.4.4.dist-info/top_level.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ charset_normalizer
lib/python3.12/site-packages/cycler/__init__.py ADDED
@@ -0,0 +1,573 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Cycler
3
+ ======
4
+
5
+ Cycling through combinations of values, producing dictionaries.
6
+
7
+ You can add cyclers::
8
+
9
+ from cycler import cycler
10
+ cc = (cycler(color=list('rgb')) +
11
+ cycler(linestyle=['-', '--', '-.']))
12
+ for d in cc:
13
+ print(d)
14
+
15
+ Results in::
16
+
17
+ {'color': 'r', 'linestyle': '-'}
18
+ {'color': 'g', 'linestyle': '--'}
19
+ {'color': 'b', 'linestyle': '-.'}
20
+
21
+
22
+ You can multiply cyclers::
23
+
24
+ from cycler import cycler
25
+ cc = (cycler(color=list('rgb')) *
26
+ cycler(linestyle=['-', '--', '-.']))
27
+ for d in cc:
28
+ print(d)
29
+
30
+ Results in::
31
+
32
+ {'color': 'r', 'linestyle': '-'}
33
+ {'color': 'r', 'linestyle': '--'}
34
+ {'color': 'r', 'linestyle': '-.'}
35
+ {'color': 'g', 'linestyle': '-'}
36
+ {'color': 'g', 'linestyle': '--'}
37
+ {'color': 'g', 'linestyle': '-.'}
38
+ {'color': 'b', 'linestyle': '-'}
39
+ {'color': 'b', 'linestyle': '--'}
40
+ {'color': 'b', 'linestyle': '-.'}
41
+ """
42
+
43
+
44
+ from __future__ import annotations
45
+
46
+ from collections.abc import Hashable, Iterable, Generator
47
+ import copy
48
+ from functools import reduce
49
+ from itertools import product, cycle
50
+ from operator import mul, add
51
+ # Dict, List, Union required for runtime cast calls
52
+ from typing import TypeVar, Generic, Callable, Union, Dict, List, Any, overload, cast
53
+
54
+ __version__ = "0.12.1"
55
+
56
+ K = TypeVar("K", bound=Hashable)
57
+ L = TypeVar("L", bound=Hashable)
58
+ V = TypeVar("V")
59
+ U = TypeVar("U")
60
+
61
+
62
+ def _process_keys(
63
+ left: Cycler[K, V] | Iterable[dict[K, V]],
64
+ right: Cycler[K, V] | Iterable[dict[K, V]] | None,
65
+ ) -> set[K]:
66
+ """
67
+ Helper function to compose cycler keys.
68
+
69
+ Parameters
70
+ ----------
71
+ left, right : iterable of dictionaries or None
72
+ The cyclers to be composed.
73
+
74
+ Returns
75
+ -------
76
+ keys : set
77
+ The keys in the composition of the two cyclers.
78
+ """
79
+ l_peek: dict[K, V] = next(iter(left)) if left != [] else {}
80
+ r_peek: dict[K, V] = next(iter(right)) if right is not None else {}
81
+ l_key: set[K] = set(l_peek.keys())
82
+ r_key: set[K] = set(r_peek.keys())
83
+ if l_key & r_key:
84
+ raise ValueError("Can not compose overlapping cycles")
85
+ return l_key | r_key
86
+
87
+
88
+ def concat(left: Cycler[K, V], right: Cycler[K, U]) -> Cycler[K, V | U]:
89
+ r"""
90
+ Concatenate `Cycler`\s, as if chained using `itertools.chain`.
91
+
92
+ The keys must match exactly.
93
+
94
+ Examples
95
+ --------
96
+ >>> num = cycler('a', range(3))
97
+ >>> let = cycler('a', 'abc')
98
+ >>> num.concat(let)
99
+ cycler('a', [0, 1, 2, 'a', 'b', 'c'])
100
+
101
+ Returns
102
+ -------
103
+ `Cycler`
104
+ The concatenated cycler.
105
+ """
106
+ if left.keys != right.keys:
107
+ raise ValueError(
108
+ "Keys do not match:\n"
109
+ "\tIntersection: {both!r}\n"
110
+ "\tDisjoint: {just_one!r}".format(
111
+ both=left.keys & right.keys, just_one=left.keys ^ right.keys
112
+ )
113
+ )
114
+ _l = cast(Dict[K, List[Union[V, U]]], left.by_key())
115
+ _r = cast(Dict[K, List[Union[V, U]]], right.by_key())
116
+ return reduce(add, (_cycler(k, _l[k] + _r[k]) for k in left.keys))
117
+
118
+
119
+ class Cycler(Generic[K, V]):
120
+ """
121
+ Composable cycles.
122
+
123
+ This class has compositions methods:
124
+
125
+ ``+``
126
+ for 'inner' products (zip)
127
+
128
+ ``+=``
129
+ in-place ``+``
130
+
131
+ ``*``
132
+ for outer products (`itertools.product`) and integer multiplication
133
+
134
+ ``*=``
135
+ in-place ``*``
136
+
137
+ and supports basic slicing via ``[]``.
138
+
139
+ Parameters
140
+ ----------
141
+ left, right : Cycler or None
142
+ The 'left' and 'right' cyclers.
143
+ op : func or None
144
+ Function which composes the 'left' and 'right' cyclers.
145
+ """
146
+
147
+ def __call__(self):
148
+ return cycle(self)
149
+
150
+ def __init__(
151
+ self,
152
+ left: Cycler[K, V] | Iterable[dict[K, V]] | None,
153
+ right: Cycler[K, V] | None = None,
154
+ op: Any = None,
155
+ ):
156
+ """
157
+ Semi-private init.
158
+
159
+ Do not use this directly, use `cycler` function instead.
160
+ """
161
+ if isinstance(left, Cycler):
162
+ self._left: Cycler[K, V] | list[dict[K, V]] = Cycler(
163
+ left._left, left._right, left._op
164
+ )
165
+ elif left is not None:
166
+ # Need to copy the dictionary or else that will be a residual
167
+ # mutable that could lead to strange errors
168
+ self._left = [copy.copy(v) for v in left]
169
+ else:
170
+ self._left = []
171
+
172
+ if isinstance(right, Cycler):
173
+ self._right: Cycler[K, V] | None = Cycler(
174
+ right._left, right._right, right._op
175
+ )
176
+ else:
177
+ self._right = None
178
+
179
+ self._keys: set[K] = _process_keys(self._left, self._right)
180
+ self._op: Any = op
181
+
182
+ def __contains__(self, k):
183
+ return k in self._keys
184
+
185
+ @property
186
+ def keys(self) -> set[K]:
187
+ """The keys this Cycler knows about."""
188
+ return set(self._keys)
189
+
190
+ def change_key(self, old: K, new: K) -> None:
191
+ """
192
+ Change a key in this cycler to a new name.
193
+ Modification is performed in-place.
194
+
195
+ Does nothing if the old key is the same as the new key.
196
+ Raises a ValueError if the new key is already a key.
197
+ Raises a KeyError if the old key isn't a key.
198
+ """
199
+ if old == new:
200
+ return
201
+ if new in self._keys:
202
+ raise ValueError(
203
+ f"Can't replace {old} with {new}, {new} is already a key"
204
+ )
205
+ if old not in self._keys:
206
+ raise KeyError(
207
+ f"Can't replace {old} with {new}, {old} is not a key"
208
+ )
209
+
210
+ self._keys.remove(old)
211
+ self._keys.add(new)
212
+
213
+ if self._right is not None and old in self._right.keys:
214
+ self._right.change_key(old, new)
215
+
216
+ # self._left should always be non-None
217
+ # if self._keys is non-empty.
218
+ elif isinstance(self._left, Cycler):
219
+ self._left.change_key(old, new)
220
+ else:
221
+ # It should be completely safe at this point to
222
+ # assume that the old key can be found in each
223
+ # iteration.
224
+ self._left = [{new: entry[old]} for entry in self._left]
225
+
226
+ @classmethod
227
+ def _from_iter(cls, label: K, itr: Iterable[V]) -> Cycler[K, V]:
228
+ """
229
+ Class method to create 'base' Cycler objects
230
+ that do not have a 'right' or 'op' and for which
231
+ the 'left' object is not another Cycler.
232
+
233
+ Parameters
234
+ ----------
235
+ label : hashable
236
+ The property key.
237
+
238
+ itr : iterable
239
+ Finite length iterable of the property values.
240
+
241
+ Returns
242
+ -------
243
+ `Cycler`
244
+ New 'base' cycler.
245
+ """
246
+ ret: Cycler[K, V] = cls(None)
247
+ ret._left = list({label: v} for v in itr)
248
+ ret._keys = {label}
249
+ return ret
250
+
251
+ def __getitem__(self, key: slice) -> Cycler[K, V]:
252
+ # TODO : maybe add numpy style fancy slicing
253
+ if isinstance(key, slice):
254
+ trans = self.by_key()
255
+ return reduce(add, (_cycler(k, v[key]) for k, v in trans.items()))
256
+ else:
257
+ raise ValueError("Can only use slices with Cycler.__getitem__")
258
+
259
+ def __iter__(self) -> Generator[dict[K, V], None, None]:
260
+ if self._right is None:
261
+ for left in self._left:
262
+ yield dict(left)
263
+ else:
264
+ if self._op is None:
265
+ raise TypeError(
266
+ "Operation cannot be None when both left and right are defined"
267
+ )
268
+ for a, b in self._op(self._left, self._right):
269
+ out = {}
270
+ out.update(a)
271
+ out.update(b)
272
+ yield out
273
+
274
+ def __add__(self, other: Cycler[L, U]) -> Cycler[K | L, V | U]:
275
+ """
276
+ Pair-wise combine two equal length cyclers (zip).
277
+
278
+ Parameters
279
+ ----------
280
+ other : Cycler
281
+ """
282
+ if len(self) != len(other):
283
+ raise ValueError(
284
+ f"Can only add equal length cycles, not {len(self)} and {len(other)}"
285
+ )
286
+ return Cycler(
287
+ cast(Cycler[Union[K, L], Union[V, U]], self),
288
+ cast(Cycler[Union[K, L], Union[V, U]], other),
289
+ zip
290
+ )
291
+
292
+ @overload
293
+ def __mul__(self, other: Cycler[L, U]) -> Cycler[K | L, V | U]:
294
+ ...
295
+
296
+ @overload
297
+ def __mul__(self, other: int) -> Cycler[K, V]:
298
+ ...
299
+
300
+ def __mul__(self, other):
301
+ """
302
+ Outer product of two cyclers (`itertools.product`) or integer
303
+ multiplication.
304
+
305
+ Parameters
306
+ ----------
307
+ other : Cycler or int
308
+ """
309
+ if isinstance(other, Cycler):
310
+ return Cycler(
311
+ cast(Cycler[Union[K, L], Union[V, U]], self),
312
+ cast(Cycler[Union[K, L], Union[V, U]], other),
313
+ product
314
+ )
315
+ elif isinstance(other, int):
316
+ trans = self.by_key()
317
+ return reduce(
318
+ add, (_cycler(k, v * other) for k, v in trans.items())
319
+ )
320
+ else:
321
+ return NotImplemented
322
+
323
+ @overload
324
+ def __rmul__(self, other: Cycler[L, U]) -> Cycler[K | L, V | U]:
325
+ ...
326
+
327
+ @overload
328
+ def __rmul__(self, other: int) -> Cycler[K, V]:
329
+ ...
330
+
331
+ def __rmul__(self, other):
332
+ return self * other
333
+
334
+ def __len__(self) -> int:
335
+ op_dict: dict[Callable, Callable[[int, int], int]] = {zip: min, product: mul}
336
+ if self._right is None:
337
+ return len(self._left)
338
+ l_len = len(self._left)
339
+ r_len = len(self._right)
340
+ return op_dict[self._op](l_len, r_len)
341
+
342
+ # iadd and imul do not exapand the the type as the returns must be consistent with
343
+ # self, thus they flag as inconsistent with add/mul
344
+ def __iadd__(self, other: Cycler[K, V]) -> Cycler[K, V]: # type: ignore[misc]
345
+ """
346
+ In-place pair-wise combine two equal length cyclers (zip).
347
+
348
+ Parameters
349
+ ----------
350
+ other : Cycler
351
+ """
352
+ if not isinstance(other, Cycler):
353
+ raise TypeError("Cannot += with a non-Cycler object")
354
+ # True shallow copy of self is fine since this is in-place
355
+ old_self = copy.copy(self)
356
+ self._keys = _process_keys(old_self, other)
357
+ self._left = old_self
358
+ self._op = zip
359
+ self._right = Cycler(other._left, other._right, other._op)
360
+ return self
361
+
362
+ def __imul__(self, other: Cycler[K, V] | int) -> Cycler[K, V]: # type: ignore[misc]
363
+ """
364
+ In-place outer product of two cyclers (`itertools.product`).
365
+
366
+ Parameters
367
+ ----------
368
+ other : Cycler
369
+ """
370
+ if not isinstance(other, Cycler):
371
+ raise TypeError("Cannot *= with a non-Cycler object")
372
+ # True shallow copy of self is fine since this is in-place
373
+ old_self = copy.copy(self)
374
+ self._keys = _process_keys(old_self, other)
375
+ self._left = old_self
376
+ self._op = product
377
+ self._right = Cycler(other._left, other._right, other._op)
378
+ return self
379
+
380
+ def __eq__(self, other: object) -> bool:
381
+ if not isinstance(other, Cycler):
382
+ return False
383
+ if len(self) != len(other):
384
+ return False
385
+ if self.keys ^ other.keys:
386
+ return False
387
+ return all(a == b for a, b in zip(self, other))
388
+
389
+ __hash__ = None # type: ignore
390
+
391
+ def __repr__(self) -> str:
392
+ op_map = {zip: "+", product: "*"}
393
+ if self._right is None:
394
+ lab = self.keys.pop()
395
+ itr = list(v[lab] for v in self)
396
+ return f"cycler({lab!r}, {itr!r})"
397
+ else:
398
+ op = op_map.get(self._op, "?")
399
+ msg = "({left!r} {op} {right!r})"
400
+ return msg.format(left=self._left, op=op, right=self._right)
401
+
402
+ def _repr_html_(self) -> str:
403
+ # an table showing the value of each key through a full cycle
404
+ output = "<table>"
405
+ sorted_keys = sorted(self.keys, key=repr)
406
+ for key in sorted_keys:
407
+ output += f"<th>{key!r}</th>"
408
+ for d in iter(self):
409
+ output += "<tr>"
410
+ for k in sorted_keys:
411
+ output += f"<td>{d[k]!r}</td>"
412
+ output += "</tr>"
413
+ output += "</table>"
414
+ return output
415
+
416
+ def by_key(self) -> dict[K, list[V]]:
417
+ """
418
+ Values by key.
419
+
420
+ This returns the transposed values of the cycler. Iterating
421
+ over a `Cycler` yields dicts with a single value for each key,
422
+ this method returns a `dict` of `list` which are the values
423
+ for the given key.
424
+
425
+ The returned value can be used to create an equivalent `Cycler`
426
+ using only `+`.
427
+
428
+ Returns
429
+ -------
430
+ transpose : dict
431
+ dict of lists of the values for each key.
432
+ """
433
+
434
+ # TODO : sort out if this is a bottle neck, if there is a better way
435
+ # and if we care.
436
+
437
+ keys = self.keys
438
+ out: dict[K, list[V]] = {k: list() for k in keys}
439
+
440
+ for d in self:
441
+ for k in keys:
442
+ out[k].append(d[k])
443
+ return out
444
+
445
+ # for back compatibility
446
+ _transpose = by_key
447
+
448
+ def simplify(self) -> Cycler[K, V]:
449
+ """
450
+ Simplify the cycler into a sum (but no products) of cyclers.
451
+
452
+ Returns
453
+ -------
454
+ simple : Cycler
455
+ """
456
+ # TODO: sort out if it is worth the effort to make sure this is
457
+ # balanced. Currently it is is
458
+ # (((a + b) + c) + d) vs
459
+ # ((a + b) + (c + d))
460
+ # I would believe that there is some performance implications
461
+ trans = self.by_key()
462
+ return reduce(add, (_cycler(k, v) for k, v in trans.items()))
463
+
464
+ concat = concat
465
+
466
+
467
+ @overload
468
+ def cycler(arg: Cycler[K, V]) -> Cycler[K, V]:
469
+ ...
470
+
471
+
472
+ @overload
473
+ def cycler(**kwargs: Iterable[V]) -> Cycler[str, V]:
474
+ ...
475
+
476
+
477
+ @overload
478
+ def cycler(label: K, itr: Iterable[V]) -> Cycler[K, V]:
479
+ ...
480
+
481
+
482
+ def cycler(*args, **kwargs):
483
+ """
484
+ Create a new `Cycler` object from a single positional argument,
485
+ a pair of positional arguments, or the combination of keyword arguments.
486
+
487
+ cycler(arg)
488
+ cycler(label1=itr1[, label2=iter2[, ...]])
489
+ cycler(label, itr)
490
+
491
+ Form 1 simply copies a given `Cycler` object.
492
+
493
+ Form 2 composes a `Cycler` as an inner product of the
494
+ pairs of keyword arguments. In other words, all of the
495
+ iterables are cycled simultaneously, as if through zip().
496
+
497
+ Form 3 creates a `Cycler` from a label and an iterable.
498
+ This is useful for when the label cannot be a keyword argument
499
+ (e.g., an integer or a name that has a space in it).
500
+
501
+ Parameters
502
+ ----------
503
+ arg : Cycler
504
+ Copy constructor for Cycler (does a shallow copy of iterables).
505
+ label : name
506
+ The property key. In the 2-arg form of the function,
507
+ the label can be any hashable object. In the keyword argument
508
+ form of the function, it must be a valid python identifier.
509
+ itr : iterable
510
+ Finite length iterable of the property values.
511
+ Can be a single-property `Cycler` that would
512
+ be like a key change, but as a shallow copy.
513
+
514
+ Returns
515
+ -------
516
+ cycler : Cycler
517
+ New `Cycler` for the given property
518
+
519
+ """
520
+ if args and kwargs:
521
+ raise TypeError(
522
+ "cycler() can only accept positional OR keyword arguments -- not both."
523
+ )
524
+
525
+ if len(args) == 1:
526
+ if not isinstance(args[0], Cycler):
527
+ raise TypeError(
528
+ "If only one positional argument given, it must "
529
+ "be a Cycler instance."
530
+ )
531
+ return Cycler(args[0])
532
+ elif len(args) == 2:
533
+ return _cycler(*args)
534
+ elif len(args) > 2:
535
+ raise TypeError(
536
+ "Only a single Cycler can be accepted as the lone "
537
+ "positional argument. Use keyword arguments instead."
538
+ )
539
+
540
+ if kwargs:
541
+ return reduce(add, (_cycler(k, v) for k, v in kwargs.items()))
542
+
543
+ raise TypeError("Must have at least a positional OR keyword arguments")
544
+
545
+
546
+ def _cycler(label: K, itr: Iterable[V]) -> Cycler[K, V]:
547
+ """
548
+ Create a new `Cycler` object from a property name and iterable of values.
549
+
550
+ Parameters
551
+ ----------
552
+ label : hashable
553
+ The property key.
554
+ itr : iterable
555
+ Finite length iterable of the property values.
556
+
557
+ Returns
558
+ -------
559
+ cycler : Cycler
560
+ New `Cycler` for the given property
561
+ """
562
+ if isinstance(itr, Cycler):
563
+ keys = itr.keys
564
+ if len(keys) != 1:
565
+ msg = "Can not create Cycler from a multi-property Cycler"
566
+ raise ValueError(msg)
567
+
568
+ lab = keys.pop()
569
+ # Doesn't need to be a new list because
570
+ # _from_iter() will be creating that new list anyway.
571
+ itr = (v[lab] for v in itr)
572
+
573
+ return Cycler._from_iter(label, itr)
lib/python3.12/site-packages/cycler/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (22.9 kB). View file
 
lib/python3.12/site-packages/cycler/py.typed ADDED
File without changes
lib/python3.12/site-packages/frozenlist/__init__.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import types
3
+ from collections.abc import MutableSequence
4
+ from functools import total_ordering
5
+
6
+ __version__ = "1.8.0"
7
+
8
+ __all__ = ("FrozenList", "PyFrozenList") # type: Tuple[str, ...]
9
+
10
+
11
+ NO_EXTENSIONS = bool(os.environ.get("FROZENLIST_NO_EXTENSIONS")) # type: bool
12
+
13
+
14
+ @total_ordering
15
+ class FrozenList(MutableSequence):
16
+ __slots__ = ("_frozen", "_items")
17
+ __class_getitem__ = classmethod(types.GenericAlias)
18
+
19
+ def __init__(self, items=None):
20
+ self._frozen = False
21
+ if items is not None:
22
+ items = list(items)
23
+ else:
24
+ items = []
25
+ self._items = items
26
+
27
+ @property
28
+ def frozen(self):
29
+ return self._frozen
30
+
31
+ def freeze(self):
32
+ self._frozen = True
33
+
34
+ def __getitem__(self, index):
35
+ return self._items[index]
36
+
37
+ def __setitem__(self, index, value):
38
+ if self._frozen:
39
+ raise RuntimeError("Cannot modify frozen list.")
40
+ self._items[index] = value
41
+
42
+ def __delitem__(self, index):
43
+ if self._frozen:
44
+ raise RuntimeError("Cannot modify frozen list.")
45
+ del self._items[index]
46
+
47
+ def __len__(self):
48
+ return self._items.__len__()
49
+
50
+ def __iter__(self):
51
+ return self._items.__iter__()
52
+
53
+ def __reversed__(self):
54
+ return self._items.__reversed__()
55
+
56
+ def __eq__(self, other):
57
+ return list(self) == other
58
+
59
+ def __le__(self, other):
60
+ return list(self) <= other
61
+
62
+ def insert(self, pos, item):
63
+ if self._frozen:
64
+ raise RuntimeError("Cannot modify frozen list.")
65
+ self._items.insert(pos, item)
66
+
67
+ def __repr__(self):
68
+ return f"<FrozenList(frozen={self._frozen}, {self._items!r})>"
69
+
70
+ def __hash__(self):
71
+ if self._frozen:
72
+ return hash(tuple(self))
73
+ else:
74
+ raise RuntimeError("Cannot hash unfrozen list.")
75
+
76
+
77
+ PyFrozenList = FrozenList
78
+
79
+
80
+ if not NO_EXTENSIONS:
81
+ try:
82
+ from ._frozenlist import FrozenList as CFrozenList # type: ignore
83
+ except ImportError: # pragma: no cover
84
+ pass
85
+ else:
86
+ FrozenList = CFrozenList # type: ignore
lib/python3.12/site-packages/frozenlist/__init__.pyi ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import (
2
+ Generic,
3
+ Iterable,
4
+ Iterator,
5
+ List,
6
+ MutableSequence,
7
+ Optional,
8
+ TypeVar,
9
+ Union,
10
+ overload,
11
+ )
12
+
13
+ _T = TypeVar("_T")
14
+ _Arg = Union[List[_T], Iterable[_T]]
15
+
16
+ class FrozenList(MutableSequence[_T], Generic[_T]):
17
+ def __init__(self, items: Optional[_Arg[_T]] = None) -> None: ...
18
+ @property
19
+ def frozen(self) -> bool: ...
20
+ def freeze(self) -> None: ...
21
+ @overload
22
+ def __getitem__(self, i: int) -> _T: ...
23
+ @overload
24
+ def __getitem__(self, s: slice) -> FrozenList[_T]: ...
25
+ @overload
26
+ def __setitem__(self, i: int, o: _T) -> None: ...
27
+ @overload
28
+ def __setitem__(self, s: slice, o: Iterable[_T]) -> None: ...
29
+ @overload
30
+ def __delitem__(self, i: int) -> None: ...
31
+ @overload
32
+ def __delitem__(self, i: slice) -> None: ...
33
+ def __len__(self) -> int: ...
34
+ def __iter__(self) -> Iterator[_T]: ...
35
+ def __reversed__(self) -> Iterator[_T]: ...
36
+ def __eq__(self, other: object) -> bool: ...
37
+ def __le__(self, other: FrozenList[_T]) -> bool: ...
38
+ def __ne__(self, other: object) -> bool: ...
39
+ def __lt__(self, other: FrozenList[_T]) -> bool: ...
40
+ def __ge__(self, other: FrozenList[_T]) -> bool: ...
41
+ def __gt__(self, other: FrozenList[_T]) -> bool: ...
42
+ def insert(self, pos: int, item: _T) -> None: ...
43
+ def __repr__(self) -> str: ...
44
+ def __hash__(self) -> int: ...
45
+
46
+ # types for C accelerators are the same
47
+ CFrozenList = PyFrozenList = FrozenList
lib/python3.12/site-packages/frozenlist/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (4.07 kB). View file
 
lib/python3.12/site-packages/frozenlist/_frozenlist.pyx ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # cython: freethreading_compatible = True
2
+ # distutils: language = c++
3
+
4
+ from cpython.bool cimport PyBool_FromLong
5
+ from libcpp.atomic cimport atomic
6
+
7
+ import copy
8
+ import types
9
+ from collections.abc import MutableSequence
10
+
11
+
12
+ cdef class FrozenList:
13
+ __class_getitem__ = classmethod(types.GenericAlias)
14
+
15
+ cdef atomic[bint] _frozen
16
+ cdef list _items
17
+
18
+ def __init__(self, items=None):
19
+ self._frozen.store(False)
20
+ if items is not None:
21
+ items = list(items)
22
+ else:
23
+ items = []
24
+ self._items = items
25
+
26
+ @property
27
+ def frozen(self):
28
+ return PyBool_FromLong(self._frozen.load())
29
+
30
+ cdef object _check_frozen(self):
31
+ if self._frozen.load():
32
+ raise RuntimeError("Cannot modify frozen list.")
33
+
34
+ cdef inline object _fast_len(self):
35
+ return len(self._items)
36
+
37
+ def freeze(self):
38
+ self._frozen.store(True)
39
+
40
+ def __getitem__(self, index):
41
+ return self._items[index]
42
+
43
+ def __setitem__(self, index, value):
44
+ self._check_frozen()
45
+ self._items[index] = value
46
+
47
+ def __delitem__(self, index):
48
+ self._check_frozen()
49
+ del self._items[index]
50
+
51
+ def __len__(self):
52
+ return self._fast_len()
53
+
54
+ def __iter__(self):
55
+ return self._items.__iter__()
56
+
57
+ def __reversed__(self):
58
+ return self._items.__reversed__()
59
+
60
+ def __richcmp__(self, other, op):
61
+ if op == 0: # <
62
+ return list(self) < other
63
+ if op == 1: # <=
64
+ return list(self) <= other
65
+ if op == 2: # ==
66
+ return list(self) == other
67
+ if op == 3: # !=
68
+ return list(self) != other
69
+ if op == 4: # >
70
+ return list(self) > other
71
+ if op == 5: # =>
72
+ return list(self) >= other
73
+
74
+ def insert(self, pos, item):
75
+ self._check_frozen()
76
+ self._items.insert(pos, item)
77
+
78
+ def __contains__(self, item):
79
+ return item in self._items
80
+
81
+ def __iadd__(self, items):
82
+ self._check_frozen()
83
+ self._items += list(items)
84
+ return self
85
+
86
+ def index(self, item):
87
+ return self._items.index(item)
88
+
89
+ def remove(self, item):
90
+ self._check_frozen()
91
+ self._items.remove(item)
92
+
93
+ def clear(self):
94
+ self._check_frozen()
95
+ self._items.clear()
96
+
97
+ def extend(self, items):
98
+ self._check_frozen()
99
+ self._items += list(items)
100
+
101
+ def reverse(self):
102
+ self._check_frozen()
103
+ self._items.reverse()
104
+
105
+ def pop(self, index=-1):
106
+ self._check_frozen()
107
+ return self._items.pop(index)
108
+
109
+ def append(self, item):
110
+ self._check_frozen()
111
+ return self._items.append(item)
112
+
113
+ def count(self, item):
114
+ return self._items.count(item)
115
+
116
+ def __repr__(self):
117
+ return '<FrozenList(frozen={}, {!r})>'.format(self._frozen.load(),
118
+ self._items)
119
+
120
+ def __hash__(self):
121
+ if self._frozen.load():
122
+ return hash(tuple(self._items))
123
+ else:
124
+ raise RuntimeError("Cannot hash unfrozen list.")
125
+
126
+ def __deepcopy__(self, memo):
127
+ cdef FrozenList new_list
128
+ obj_id = id(self)
129
+
130
+ # Return existing copy if already processed (circular reference)
131
+ if obj_id in memo:
132
+ return memo[obj_id]
133
+
134
+ # Create new instance and register immediately
135
+ new_list = self.__class__([])
136
+ memo[obj_id] = new_list
137
+
138
+ # Deep copy items
139
+ new_list._items[:] = [copy.deepcopy(item, memo) for item in self._items]
140
+
141
+ # Preserve frozen state
142
+ if self._frozen.load():
143
+ new_list.freeze()
144
+
145
+ return new_list
146
+
147
+
148
+ MutableSequence.register(FrozenList)
lib/python3.12/site-packages/frozenlist/py.typed ADDED
@@ -0,0 +1 @@
 
 
1
+ Marker
lib/python3.12/site-packages/hjson-3.1.0.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ pip
lib/python3.12/site-packages/hjson-3.1.0.dist-info/LICENSE.txt ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ hjson (based on simplejson) is dual-licensed software. It is available under the terms
2
+ of the MIT license, or the Academic Free License version 2.1. The full
3
+ text of each license agreement is included below. This code is also
4
+ licensed to the Python Software Foundation (PSF) under a Contributor
5
+ Agreement.
6
+
7
+ MIT License
8
+ ===========
9
+
10
+ Copyright (c) 2006 Bob Ippolito
11
+ Copyright (c) 2015 Christian Zangl
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
14
+ this software and associated documentation files (the "Software"), to deal in
15
+ the Software without restriction, including without limitation the rights to
16
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
17
+ of the Software, and to permit persons to whom the Software is furnished to do
18
+ so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in all
21
+ copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
30
+
31
+ Academic Free License v. 2.1
32
+ ============================
33
+
34
+ Copyright (c) 2006 Bob Ippolito. All rights reserved.
35
+ Copyright (c) 2015 Christian Zangl
36
+
37
+ This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following notice immediately following the copyright notice for the Original Work:
38
+
39
+ Licensed under the Academic Free License version 2.1
40
+
41
+ 1) Grant of Copyright License. Licensor hereby grants You a world-wide, royalty-free, non-exclusive, perpetual, sublicenseable license to do the following:
42
+
43
+ a) to reproduce the Original Work in copies;
44
+
45
+ b) to prepare derivative works ("Derivative Works") based upon the Original Work;
46
+
47
+ c) to distribute copies of the Original Work and Derivative Works to the public;
48
+
49
+ d) to perform the Original Work publicly; and
50
+
51
+ e) to display the Original Work publicly.
52
+
53
+ 2) Grant of Patent License. Licensor hereby grants You a world-wide, royalty-free, non-exclusive, perpetual, sublicenseable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, to make, use, sell and offer for sale the Original Work and Derivative Works.
54
+
55
+ 3) Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor hereby agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work, and by publishing the address of that information repository in a notice immediately following the copyright notice that applies to the Original Work.
56
+
57
+ 4) Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior written permission of the Licensor. Nothing in this License shall be deemed to grant any rights to trademarks, copyrights, patents, trade secrets or any other intellectual property of Licensor except as expressly stated herein. No patent license is granted to make, use, sell or offer to sell embodiments of any patent claims other than the licensed claims defined in Section 2. No right is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under different terms from this License any Original Work that Licensor otherwise would have a right to license.
58
+
59
+ 5) This section intentionally omitted.
60
+
61
+ 6) Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work.
62
+
63
+ 7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately proceeding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to Original Work is granted hereunder except under this disclaimer.
64
+
65
+ 8) Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to any person for any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to liability for death or personal injury resulting from Licensor's negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You.
66
+
67
+ 9) Acceptance and Termination. If You distribute copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. Nothing else but this License (or another written agreement between Licensor and You) grants You permission to create Derivative Works based upon the Original Work or to exercise any of the rights granted in Section 1 herein, and any attempt to do so except under the terms of this License (or another written agreement between Licensor and You) is expressly prohibited by U.S. copyright law, the equivalent laws of other countries, and by international treaty. Therefore, by exercising any of the rights granted to You in Section 1 herein, You indicate Your acceptance of this License and all of its terms and conditions.
68
+
69
+ 10) Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware.
70
+
71
+ 11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of the U.S. Copyright Act, 17 U.S.C. § 101 et seq., the equivalent laws of other countries, and international treaty. This section shall survive the termination of this License.
72
+
73
+ 12) Attorneys Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License.
74
+
75
+ 13) Miscellaneous. This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable.
76
+
77
+ 14) Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
78
+
79
+ 15) Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You.
80
+
81
+ This license is Copyright (C) 2003-2004 Lawrence E. Rosen. All rights reserved. Permission is hereby granted to copy and distribute this license without modification. This license may not be modified without the express written permission of its copyright owner.
lib/python3.12/site-packages/hjson-3.1.0.dist-info/METADATA ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.1
2
+ Name: hjson
3
+ Version: 3.1.0
4
+ Summary: Hjson, a user interface for JSON.
5
+ Home-page: http://github.com/hjson/hjson-py
6
+ Author: Christian Zangl
7
+ Author-email: laktak@cdak.net
8
+ License: MIT License
9
+ Keywords: json comments configuration
10
+ Platform: any
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: License :: OSI Approved :: Academic Free License (AFL)
15
+ Classifier: Programming Language :: Python
16
+ Classifier: Programming Language :: Python :: 2
17
+ Classifier: Programming Language :: Python :: 2.6
18
+ Classifier: Programming Language :: Python :: 2.7
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.3
21
+ Classifier: Programming Language :: Python :: 3.4
22
+ Classifier: Programming Language :: Python :: 3.5
23
+ Classifier: Programming Language :: Python :: Implementation :: CPython
24
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
25
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
+ License-File: LICENSE.txt
27
+
28
+ hjson-py
29
+ ========
30
+
31
+ `Hjson`_, a user interface for JSON
32
+
33
+ Hjson works with Python 2.5+ and Python 3.3+ (based on `simplejson`_)
34
+
35
+ Installation
36
+ ============
37
+
38
+ - ``pip install hjson``
39
+
40
+ - or download from https://pypi.python.org/pypi/hjson
41
+
42
+ Commandline
43
+ -----------
44
+
45
+ ::
46
+
47
+ Usage:
48
+ hjson [options]
49
+ hjson [options] <input>
50
+ hjson (-h | --help)
51
+ hjson (-V | --version)
52
+
53
+ Options:
54
+ -h --help Show this screen.
55
+ -j Output as formatted JSON.
56
+ -c Output as JSON.
57
+ -V --version Show version.
58
+
59
+ E.g. ``echo '{"json":"obj"}' | hjson``
60
+
61
+
62
+ Usage
63
+ =====
64
+
65
+ .. code-block:: python
66
+
67
+ import hjson
68
+
69
+ Decoding Hjson
70
+ --------------
71
+
72
+ .. code-block:: python
73
+
74
+ text = """{
75
+ foo: a
76
+ bar: 1
77
+ }"""
78
+
79
+ hjson.loads(text)
80
+
81
+ Result:
82
+
83
+ .. code-block:: python
84
+
85
+ OrderedDict([('foo', 'a'), ('bar', 1)])
86
+
87
+ Encoding Python object hierarchies
88
+ ----------------------------------
89
+
90
+ .. code-block:: python
91
+
92
+ hjson.dumps({'foo': 'text', 'bar': (1, 2)})
93
+
94
+ Result:
95
+
96
+ ::
97
+
98
+ {
99
+ foo: text
100
+ bar:
101
+ [
102
+ 1
103
+ 2
104
+ ]
105
+ }
106
+
107
+ Encoding as JSON
108
+ ----------------
109
+
110
+ Note that this is probably not as performant as the simplejson version.
111
+
112
+ .. code-block:: python
113
+
114
+ hjson.dumpsJSON(['foo', {'bar': ('baz', None, 1.0, 2)}])
115
+
116
+ Result: ``'["foo", {"bar": ["baz", null, 1.0, 2]}]'``
117
+
118
+ API
119
+ ===
120
+
121
+ `hjson-py`_
122
+
123
+ .. _Hjson: https://hjson.github.io
124
+ .. _simplejson: https://github.com/simplejson/simplejson
125
+ .. _hjson-py: http://hjson.github.io/hjson-py/
lib/python3.12/site-packages/hjson-3.1.0.dist-info/RECORD ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ../../../bin/hjson,sha256=clpm0xqd9FMuLXKV748jrsYgIxZoerUz3H-BSH_7TkA,245
2
+ hjson-3.1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
3
+ hjson-3.1.0.dist-info/LICENSE.txt,sha256=WRxR9JxoM7zhpdU-Y3haBGet1nRaWogOTRD05kzETEw,10462
4
+ hjson-3.1.0.dist-info/METADATA,sha256=ws3nEqUXFpWNgmH-FYScGumUSgt2dkiPHNm7RZh-gcU,2610
5
+ hjson-3.1.0.dist-info/RECORD,,
6
+ hjson-3.1.0.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
7
+ hjson-3.1.0.dist-info/entry_points.txt,sha256=sghBTcTrqdK0kKuznOZXeEBtjoBnLweHF83S9NK-r0E,42
8
+ hjson-3.1.0.dist-info/top_level.txt,sha256=earxK7niVoW6ADlKRFHCs3JpUL4FBSnJn9qmrYgnEUE,6
9
+ hjson/__init__.py,sha256=Py1drAVt-Xpi2xJAHxVXDdX-NniC4llxZVPjY7MyPCY,26580
10
+ hjson/__pycache__/__init__.cpython-312.pyc,,
11
+ hjson/__pycache__/compat.cpython-312.pyc,,
12
+ hjson/__pycache__/decoder.cpython-312.pyc,,
13
+ hjson/__pycache__/encoder.cpython-312.pyc,,
14
+ hjson/__pycache__/encoderH.cpython-312.pyc,,
15
+ hjson/__pycache__/ordered_dict.cpython-312.pyc,,
16
+ hjson/__pycache__/scanner.cpython-312.pyc,,
17
+ hjson/__pycache__/tool.cpython-312.pyc,,
18
+ hjson/compat.py,sha256=uvmTYe1Oa18tT_6tFRtYnzTdAkyd73B9zwMF7ZafI04,1036
19
+ hjson/decoder.py,sha256=oHz7g2sQd4S-AJbSzur9VJWqAHDWL25FVQ-G35XlGCA,19563
20
+ hjson/encoder.py,sha256=NhR3YSMVzL3UP8OLAtP2Dr6dW9UbJzjVS-SXp1DzvcY,19168
21
+ hjson/encoderH.py,sha256=wJ8D0gAyR3n6e3MahCIU3OahI5_xuHPWV_ZlI839xCs,20481
22
+ hjson/ordered_dict.py,sha256=DXtgiqkkaNWXDLZ0DGXIjF_CPzGV5qpC-PSeS1zcps8,3370
23
+ hjson/scanner.py,sha256=IL8poQGvCsb82y7qY5jrlSrZ5xcENpPUti3tNKhprYw,1779
24
+ hjson/tests/__init__.py,sha256=_A-1Tn7q7ccNPro_QfbKiXo_bTL9ED5RUX9AeSLG4TA,2011
25
+ hjson/tests/__pycache__/__init__.cpython-312.pyc,,
26
+ hjson/tests/__pycache__/test_bigint_as_string.cpython-312.pyc,,
27
+ hjson/tests/__pycache__/test_bitsize_int_as_string.cpython-312.pyc,,
28
+ hjson/tests/__pycache__/test_check_circular.cpython-312.pyc,,
29
+ hjson/tests/__pycache__/test_decimal.cpython-312.pyc,,
30
+ hjson/tests/__pycache__/test_decode.cpython-312.pyc,,
31
+ hjson/tests/__pycache__/test_default.cpython-312.pyc,,
32
+ hjson/tests/__pycache__/test_dump.cpython-312.pyc,,
33
+ hjson/tests/__pycache__/test_encode_basestring_ascii.cpython-312.pyc,,
34
+ hjson/tests/__pycache__/test_errors.cpython-312.pyc,,
35
+ hjson/tests/__pycache__/test_fail.cpython-312.pyc,,
36
+ hjson/tests/__pycache__/test_float.cpython-312.pyc,,
37
+ hjson/tests/__pycache__/test_for_json.cpython-312.pyc,,
38
+ hjson/tests/__pycache__/test_hjson.cpython-312.pyc,,
39
+ hjson/tests/__pycache__/test_indent.cpython-312.pyc,,
40
+ hjson/tests/__pycache__/test_item_sort_key.cpython-312.pyc,,
41
+ hjson/tests/__pycache__/test_namedtuple.cpython-312.pyc,,
42
+ hjson/tests/__pycache__/test_pass1.cpython-312.pyc,,
43
+ hjson/tests/__pycache__/test_pass2.cpython-312.pyc,,
44
+ hjson/tests/__pycache__/test_pass3.cpython-312.pyc,,
45
+ hjson/tests/__pycache__/test_recursion.cpython-312.pyc,,
46
+ hjson/tests/__pycache__/test_scanstring.cpython-312.pyc,,
47
+ hjson/tests/__pycache__/test_separators.cpython-312.pyc,,
48
+ hjson/tests/__pycache__/test_tool.cpython-312.pyc,,
49
+ hjson/tests/__pycache__/test_tuple.cpython-312.pyc,,
50
+ hjson/tests/__pycache__/test_unicode.cpython-312.pyc,,
51
+ hjson/tests/test_bigint_as_string.py,sha256=bhEtYEXWUhxyi25iLm4sPWFrt5RZ9PfFEknX1cdzP-Y,2265
52
+ hjson/tests/test_bitsize_int_as_string.py,sha256=-73xJ8CE2hDjGOWTERRrYbDHaY0kgBNQXC0g8nIgd4k,2332
53
+ hjson/tests/test_check_circular.py,sha256=64kZhsab6OcwYmJNLRqNW-19dp1UdgYbZiGzopKyR9s,940
54
+ hjson/tests/test_decimal.py,sha256=Qw0IBPSPYoGZXwvXkkM1cz6lpqjkPRzNDBSul-RdR_4,2556
55
+ hjson/tests/test_decode.py,sha256=Sm4052xVjv7ZtZFdRVMsnvQeh2eCNoXv24YOUJJLMdg,4437
56
+ hjson/tests/test_default.py,sha256=WWDLhDVfih4PrenmiEcvshhUOl_bNsm3jML96-AtGmo,224
57
+ hjson/tests/test_dump.py,sha256=5WU4Rd6vsHOwXGpGqQKIw1ZBNgRWUqMY8w3DnJVWfxo,5061
58
+ hjson/tests/test_encode_basestring_ascii.py,sha256=up4y9JMdGXdBXkEjfqwiG-sudSdcKw0RQfO_76za-To,2102
59
+ hjson/tests/test_errors.py,sha256=vg3-z36T9O-UeDHG4ZtW-nQBNAvraWKBrDA70yG989c,1549
60
+ hjson/tests/test_fail.py,sha256=Giinb944NX0bPwBHYUjVZ4ZlNB611Wg0wxVWxv4bDaU,5688
61
+ hjson/tests/test_float.py,sha256=LCUL-2xT8PYq99jQi6-Ddk9pMuC1mLrcJboTfvR08HM,1011
62
+ hjson/tests/test_for_json.py,sha256=ZLtypdX0ALctxMB8c3fQvx3k9OHY5t71gBxGNOXemrc,2778
63
+ hjson/tests/test_hjson.py,sha256=CdvXR05nu8bF_jZ-Hhj3bh8LRi8tdSJTruayj69HoDk,2327
64
+ hjson/tests/test_indent.py,sha256=8oUK5E8DTz1c3RkUU-nOELmr9wOKoaHHOAsxDai66iE,2589
65
+ hjson/tests/test_item_sort_key.py,sha256=piYy-ntwdcb_qS-y8jPFI6rVZlHCNqtTFGnaZSEvWH8,1134
66
+ hjson/tests/test_namedtuple.py,sha256=iK7B95JH4f2L3_MB3rY9NagEVZ1X62JHpjlm1J4t5uM,4066
67
+ hjson/tests/test_pass1.py,sha256=wdnBz55dY4ou8IIdZFypJ_72J6HCtLZw0YesoNOTopQ,1745
68
+ hjson/tests/test_pass2.py,sha256=O389C8IeJ9ysqWKUftXOeHvBi5_47VSdBM_2bCee1SQ,385
69
+ hjson/tests/test_pass3.py,sha256=wwemRholrfv4lwgC0ArnXiS_tfA-NnbRrZqo71YZXaA,481
70
+ hjson/tests/test_recursion.py,sha256=APQAtnchO6KZdduYqvEJDrBOmAKqyORwAX4ldbzAW7A,1694
71
+ hjson/tests/test_scanstring.py,sha256=U-5gUsaO7jEai6zfKMKADfBi-xFg8IHC1dBeElvTsn4,5953
72
+ hjson/tests/test_separators.py,sha256=krudtyZbx0k7OrZZ-jGCZH6yrmsj1seRkUblQLRq4Rw,945
73
+ hjson/tests/test_tool.py,sha256=PyDhrmMTpJSvBXvsWG8P-yrw1BT5kSp6OcSrMLvzmIw,2826
74
+ hjson/tests/test_tuple.py,sha256=FkOyw4s7WZ1HUGxtHYiwaBwhW2thlDB3JFSpUZCbI_I,1976
75
+ hjson/tests/test_unicode.py,sha256=5npz25rj4T3ZhXF_OsSmVveBUtTuz92DQ_cHDe-Jfrw,7099
76
+ hjson/tool.py,sha256=PVlr-lSDWfrGdkh5exWQo_21HGgHLR4OpZ1S41Dqjgo,1897
lib/python3.12/site-packages/hjson-3.1.0.dist-info/WHEEL ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: bdist_wheel (0.37.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
lib/python3.12/site-packages/hjson-3.1.0.dist-info/entry_points.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ [console_scripts]
2
+ hjson = hjson.tool:main
lib/python3.12/site-packages/hjson-3.1.0.dist-info/top_level.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ hjson
lib/python3.12/site-packages/hjson/__init__.py ADDED
@@ -0,0 +1,642 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ r"""Hjson, the Human JSON. A configuration file format that caters to
2
+ humans and helps reduce the errors they make.
3
+
4
+ For details and syntax see <https://hjson.github.io>.
5
+
6
+ Decoding Hjson::
7
+
8
+ >>> import hjson
9
+ >>> text = "{\n foo: a\n bar: 1\n}"
10
+ >>> hjson.loads(text)
11
+ OrderedDict([('foo', 'a'), ('bar', 1)])
12
+
13
+ Encoding Python object hierarchies::
14
+
15
+ >>> import hjson
16
+ >>> # hjson.dumps({'foo': 'text', 'bar': (1, 2)})
17
+ >>> hjson.dumps(OrderedDict([('foo', 'text'), ('bar', (1, 2))]))
18
+ '{\n foo: text\n bar:\n [\n 1\n 2\n ]\n}'
19
+
20
+ Encoding as JSON::
21
+
22
+ Note that this is probably not as performant as the simplejson version.
23
+
24
+ >>> import hjson
25
+ >>> hjson.dumpsJSON(['foo', {'bar': ('baz', None, 1.0, 2)}])
26
+ '["foo", {"bar": ["baz", null, 1.0, 2]}]'
27
+
28
+ Using hjson.tool from the shell to validate and pretty-print::
29
+
30
+ $ echo '{"json":"obj"}' | python -m hjson.tool
31
+ {
32
+ json: obj
33
+ }
34
+
35
+ Other formats are -c for compact or -j for formatted JSON.
36
+
37
+ """
38
+ from __future__ import absolute_import
39
+ __version__ = '3.1.0'
40
+ __all__ = [
41
+ 'dump', 'dumps', 'load', 'loads',
42
+ 'dumpJSON', 'dumpsJSON',
43
+ 'HjsonDecoder', 'HjsonDecodeError', 'HjsonEncoder', 'JSONEncoder',
44
+ 'OrderedDict', 'simple_first',
45
+ ]
46
+
47
+ # based on simplejson by
48
+ # __author__ = 'Bob Ippolito <bob@redivi.com>'
49
+ __author__ = 'Christian Zangl <coralllama@gmail.com>'
50
+
51
+ from decimal import Decimal
52
+
53
+ from .scanner import HjsonDecodeError
54
+ from .decoder import HjsonDecoder
55
+ from .encoderH import HjsonEncoder
56
+ from .encoder import JSONEncoder
57
+ def _import_OrderedDict():
58
+ import collections
59
+ try:
60
+ return collections.OrderedDict
61
+ except AttributeError:
62
+ from . import ordered_dict
63
+ return ordered_dict.OrderedDict
64
+ OrderedDict = _import_OrderedDict()
65
+
66
+
67
+ _default_decoder = HjsonDecoder(encoding=None, object_hook=None,
68
+ object_pairs_hook=OrderedDict)
69
+
70
+
71
+ def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None,
72
+ parse_int=None, object_pairs_hook=OrderedDict,
73
+ use_decimal=False, namedtuple_as_object=True, tuple_as_array=True,
74
+ **kw):
75
+ """Deserialize ``fp`` (a ``.read()``-supporting file-like object containing
76
+ a JSON document) to a Python object.
77
+
78
+ *encoding* determines the encoding used to interpret any
79
+ :class:`str` objects decoded by this instance (``'utf-8'`` by
80
+ default). It has no effect when decoding :class:`unicode` objects.
81
+
82
+ Note that currently only encodings that are a superset of ASCII work,
83
+ strings of other encodings should be passed in as :class:`unicode`.
84
+
85
+ *object_hook*, if specified, will be called with the result of every
86
+ JSON object decoded and its return value will be used in place of the
87
+ given :class:`dict`. This can be used to provide custom
88
+ deserializations (e.g. to support JSON-RPC class hinting).
89
+
90
+ *object_pairs_hook* is an optional function that will be called with
91
+ the result of any object literal decode with an ordered list of pairs.
92
+ The return value of *object_pairs_hook* will be used instead of the
93
+ :class:`dict`. This feature can be used to implement custom decoders
94
+ that rely on the order that the key and value pairs are decoded (for
95
+ example, :func:`collections.OrderedDict` will remember the order of
96
+ insertion). If *object_hook* is also defined, the *object_pairs_hook*
97
+ takes priority.
98
+
99
+ *parse_float*, if specified, will be called with the string of every
100
+ JSON float to be decoded. By default, this is equivalent to
101
+ ``float(num_str)``. This can be used to use another datatype or parser
102
+ for JSON floats (e.g. :class:`decimal.Decimal`).
103
+
104
+ *parse_int*, if specified, will be called with the string of every
105
+ JSON int to be decoded. By default, this is equivalent to
106
+ ``int(num_str)``. This can be used to use another datatype or parser
107
+ for JSON integers (e.g. :class:`float`).
108
+
109
+ If *use_decimal* is true (default: ``False``) then it implies
110
+ parse_float=decimal.Decimal for parity with ``dump``.
111
+
112
+ To use a custom ``HjsonDecoder`` subclass, specify it with the ``cls``
113
+ kwarg. NOTE: You should use *object_hook* or *object_pairs_hook* instead
114
+ of subclassing whenever possible.
115
+
116
+ """
117
+ return loads(fp.read(),
118
+ encoding=encoding, cls=cls, object_hook=object_hook,
119
+ parse_float=parse_float, parse_int=parse_int,
120
+ object_pairs_hook=object_pairs_hook,
121
+ use_decimal=use_decimal, **kw)
122
+
123
+
124
+ def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None,
125
+ parse_int=None, object_pairs_hook=None,
126
+ use_decimal=False, **kw):
127
+ """Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON
128
+ document) to a Python object.
129
+
130
+ *encoding* determines the encoding used to interpret any
131
+ :class:`str` objects decoded by this instance (``'utf-8'`` by
132
+ default). It has no effect when decoding :class:`unicode` objects.
133
+
134
+ Note that currently only encodings that are a superset of ASCII work,
135
+ strings of other encodings should be passed in as :class:`unicode`.
136
+
137
+ *object_hook*, if specified, will be called with the result of every
138
+ JSON object decoded and its return value will be used in place of the
139
+ given :class:`dict`. This can be used to provide custom
140
+ deserializations (e.g. to support JSON-RPC class hinting).
141
+
142
+ *object_pairs_hook* is an optional function that will be called with
143
+ the result of any object literal decode with an ordered list of pairs.
144
+ The return value of *object_pairs_hook* will be used instead of the
145
+ :class:`dict`. This feature can be used to implement custom decoders
146
+ that rely on the order that the key and value pairs are decoded (for
147
+ example, :func:`collections.OrderedDict` will remember the order of
148
+ insertion). If *object_hook* is also defined, the *object_pairs_hook*
149
+ takes priority.
150
+
151
+ *parse_float*, if specified, will be called with the string of every
152
+ JSON float to be decoded. By default, this is equivalent to
153
+ ``float(num_str)``. This can be used to use another datatype or parser
154
+ for JSON floats (e.g. :class:`decimal.Decimal`).
155
+
156
+ *parse_int*, if specified, will be called with the string of every
157
+ JSON int to be decoded. By default, this is equivalent to
158
+ ``int(num_str)``. This can be used to use another datatype or parser
159
+ for JSON integers (e.g. :class:`float`).
160
+
161
+ If *use_decimal* is true (default: ``False``) then it implies
162
+ parse_float=decimal.Decimal for parity with ``dump``.
163
+
164
+ To use a custom ``HjsonDecoder`` subclass, specify it with the ``cls``
165
+ kwarg. NOTE: You should use *object_hook* or *object_pairs_hook* instead
166
+ of subclassing whenever possible.
167
+
168
+ """
169
+ if (cls is None and encoding is None and object_hook is None and
170
+ parse_int is None and parse_float is None and
171
+ object_pairs_hook is None
172
+ and not use_decimal and not kw):
173
+ return _default_decoder.decode(s)
174
+ if cls is None:
175
+ cls = HjsonDecoder
176
+ if object_hook is not None:
177
+ kw['object_hook'] = object_hook
178
+ if object_pairs_hook is not None:
179
+ kw['object_pairs_hook'] = object_pairs_hook
180
+ if parse_float is not None:
181
+ kw['parse_float'] = parse_float
182
+ if parse_int is not None:
183
+ kw['parse_int'] = parse_int
184
+ if use_decimal:
185
+ if parse_float is not None:
186
+ raise TypeError("use_decimal=True implies parse_float=Decimal")
187
+ kw['parse_float'] = Decimal
188
+ return cls(encoding=encoding, **kw).decode(s)
189
+
190
+
191
+ _default_hjson_encoder = HjsonEncoder(
192
+ skipkeys=False,
193
+ ensure_ascii=True,
194
+ check_circular=True,
195
+ indent=None,
196
+ encoding='utf-8',
197
+ default=None,
198
+ use_decimal=True,
199
+ namedtuple_as_object=True,
200
+ tuple_as_array=True,
201
+ bigint_as_string=False,
202
+ item_sort_key=None,
203
+ for_json=False,
204
+ int_as_string_bitcount=None,
205
+ )
206
+
207
+ def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True,
208
+ cls=None, indent=None,
209
+ encoding='utf-8', default=None, use_decimal=True,
210
+ namedtuple_as_object=True, tuple_as_array=True,
211
+ bigint_as_string=False, sort_keys=False, item_sort_key=None,
212
+ for_json=False, int_as_string_bitcount=None, **kw):
213
+ """Serialize ``obj`` as a JSON formatted stream to ``fp`` (a
214
+ ``.write()``-supporting file-like object).
215
+
216
+ If *skipkeys* is true then ``dict`` keys that are not basic types
217
+ (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``)
218
+ will be skipped instead of raising a ``TypeError``.
219
+
220
+ If *ensure_ascii* is false, then the some chunks written to ``fp``
221
+ may be ``unicode`` instances, subject to normal Python ``str`` to
222
+ ``unicode`` coercion rules. Unless ``fp.write()`` explicitly
223
+ understands ``unicode`` (as in ``codecs.getwriter()``) this is likely
224
+ to cause an error.
225
+
226
+ If *check_circular* is false, then the circular reference check
227
+ for container types will be skipped and a circular reference will
228
+ result in an ``OverflowError`` (or worse).
229
+
230
+ *indent* defines the amount of whitespace that the JSON array elements
231
+ and object members will be indented for each level of nesting.
232
+ The default is two spaces.
233
+
234
+ *encoding* is the character encoding for str instances, default is UTF-8.
235
+
236
+ *default(obj)* is a function that should return a serializable version
237
+ of obj or raise ``TypeError``. The default simply raises ``TypeError``.
238
+
239
+ If *use_decimal* is true (default: ``True``) then decimal.Decimal
240
+ will be natively serialized to JSON with full precision.
241
+
242
+ If *namedtuple_as_object* is true (default: ``True``),
243
+ :class:`tuple` subclasses with ``_asdict()`` methods will be encoded
244
+ as JSON objects.
245
+
246
+ If *tuple_as_array* is true (default: ``True``),
247
+ :class:`tuple` (and subclasses) will be encoded as JSON arrays.
248
+
249
+ If *bigint_as_string* is true (default: ``False``), ints 2**53 and higher
250
+ or lower than -2**53 will be encoded as strings. This is to avoid the
251
+ rounding that happens in Javascript otherwise. Note that this is still a
252
+ lossy operation that will not round-trip correctly and should be used
253
+ sparingly.
254
+
255
+ If *int_as_string_bitcount* is a positive number (n), then int of size
256
+ greater than or equal to 2**n or lower than or equal to -2**n will be
257
+ encoded as strings.
258
+
259
+ If specified, *item_sort_key* is a callable used to sort the items in
260
+ each dictionary. This is useful if you want to sort items other than
261
+ in alphabetical order by key. This option takes precedence over
262
+ *sort_keys*.
263
+
264
+ If *sort_keys* is true (default: ``False``), the output of dictionaries
265
+ will be sorted by item.
266
+
267
+ If *for_json* is true (default: ``False``), objects with a ``for_json()``
268
+ method will use the return value of that method for encoding as JSON
269
+ instead of the object.
270
+
271
+ To use a custom ``HjsonEncoder`` subclass (e.g. one that overrides the
272
+ ``.default()`` method to serialize additional types), specify it with
273
+ the ``cls`` kwarg. NOTE: You should use *default* or *for_json* instead
274
+ of subclassing whenever possible.
275
+
276
+ """
277
+ # cached encoder
278
+ if (not skipkeys and ensure_ascii and
279
+ check_circular and
280
+ cls is None and indent is None and
281
+ encoding == 'utf-8' and default is None and use_decimal
282
+ and namedtuple_as_object and tuple_as_array
283
+ and not bigint_as_string and not sort_keys
284
+ and not item_sort_key and not for_json
285
+ and int_as_string_bitcount is None
286
+ and not kw
287
+ ):
288
+ iterable = _default_hjson_encoder.iterencode(obj)
289
+ else:
290
+ if cls is None:
291
+ cls = HjsonEncoder
292
+ iterable = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii,
293
+ check_circular=check_circular, indent=indent,
294
+ encoding=encoding,
295
+ default=default, use_decimal=use_decimal,
296
+ namedtuple_as_object=namedtuple_as_object,
297
+ tuple_as_array=tuple_as_array,
298
+ bigint_as_string=bigint_as_string,
299
+ sort_keys=sort_keys,
300
+ item_sort_key=item_sort_key,
301
+ for_json=for_json,
302
+ int_as_string_bitcount=int_as_string_bitcount,
303
+ **kw).iterencode(obj)
304
+ # could accelerate with writelines in some versions of Python, at
305
+ # a debuggability cost
306
+ for chunk in iterable:
307
+ fp.write(chunk)
308
+
309
+
310
+ def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
311
+ cls=None, indent=None,
312
+ encoding='utf-8', default=None, use_decimal=True,
313
+ namedtuple_as_object=True, tuple_as_array=True,
314
+ bigint_as_string=False, sort_keys=False, item_sort_key=None,
315
+ for_json=False, int_as_string_bitcount=None, **kw):
316
+ """Serialize ``obj`` to a JSON formatted ``str``.
317
+
318
+ If ``skipkeys`` is false then ``dict`` keys that are not basic types
319
+ (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``)
320
+ will be skipped instead of raising a ``TypeError``.
321
+
322
+ If ``ensure_ascii`` is false, then the return value will be a
323
+ ``unicode`` instance subject to normal Python ``str`` to ``unicode``
324
+ coercion rules instead of being escaped to an ASCII ``str``.
325
+
326
+ If ``check_circular`` is false, then the circular reference check
327
+ for container types will be skipped and a circular reference will
328
+ result in an ``OverflowError`` (or worse).
329
+
330
+ *indent* defines the amount of whitespace that the JSON array elements
331
+ and object members will be indented for each level of nesting.
332
+ The default is two spaces.
333
+
334
+ ``encoding`` is the character encoding for str instances, default is UTF-8.
335
+
336
+ ``default(obj)`` is a function that should return a serializable version
337
+ of obj or raise TypeError. The default simply raises TypeError.
338
+
339
+ If *use_decimal* is true (default: ``True``) then decimal.Decimal
340
+ will be natively serialized to JSON with full precision.
341
+
342
+ If *namedtuple_as_object* is true (default: ``True``),
343
+ :class:`tuple` subclasses with ``_asdict()`` methods will be encoded
344
+ as JSON objects.
345
+
346
+ If *tuple_as_array* is true (default: ``True``),
347
+ :class:`tuple` (and subclasses) will be encoded as JSON arrays.
348
+
349
+ If *bigint_as_string* is true (not the default), ints 2**53 and higher
350
+ or lower than -2**53 will be encoded as strings. This is to avoid the
351
+ rounding that happens in Javascript otherwise.
352
+
353
+ If *int_as_string_bitcount* is a positive number (n), then int of size
354
+ greater than or equal to 2**n or lower than or equal to -2**n will be
355
+ encoded as strings.
356
+
357
+ If specified, *item_sort_key* is a callable used to sort the items in
358
+ each dictionary. This is useful if you want to sort items other than
359
+ in alphabetical order by key. This option takes precendence over
360
+ *sort_keys*.
361
+
362
+ If *sort_keys* is true (default: ``False``), the output of dictionaries
363
+ will be sorted by item.
364
+
365
+ If *for_json* is true (default: ``False``), objects with a ``for_json()``
366
+ method will use the return value of that method for encoding as JSON
367
+ instead of the object.
368
+
369
+ To use a custom ``HjsonEncoder`` subclass (e.g. one that overrides the
370
+ ``.default()`` method to serialize additional types), specify it with
371
+ the ``cls`` kwarg. NOTE: You should use *default* instead of subclassing
372
+ whenever possible.
373
+
374
+ """
375
+ # cached encoder
376
+ if (
377
+ not skipkeys and ensure_ascii and
378
+ check_circular and
379
+ cls is None and indent is None and
380
+ encoding == 'utf-8' and default is None and use_decimal
381
+ and namedtuple_as_object and tuple_as_array
382
+ and not bigint_as_string and not sort_keys
383
+ and not item_sort_key and not for_json
384
+ and int_as_string_bitcount is None
385
+ and not kw
386
+ ):
387
+ return _default_hjson_encoder.encode(obj)
388
+ if cls is None:
389
+ cls = HjsonEncoder
390
+ return cls(
391
+ skipkeys=skipkeys, ensure_ascii=ensure_ascii,
392
+ check_circular=check_circular, indent=indent,
393
+ encoding=encoding, default=default,
394
+ use_decimal=use_decimal,
395
+ namedtuple_as_object=namedtuple_as_object,
396
+ tuple_as_array=tuple_as_array,
397
+ bigint_as_string=bigint_as_string,
398
+ sort_keys=sort_keys,
399
+ item_sort_key=item_sort_key,
400
+ for_json=for_json,
401
+ int_as_string_bitcount=int_as_string_bitcount,
402
+ **kw).encode(obj)
403
+
404
+
405
+
406
+ _default_json_encoder = JSONEncoder(
407
+ skipkeys=False,
408
+ ensure_ascii=True,
409
+ check_circular=True,
410
+ indent=None,
411
+ separators=None,
412
+ encoding='utf-8',
413
+ default=None,
414
+ use_decimal=True,
415
+ namedtuple_as_object=True,
416
+ tuple_as_array=True,
417
+ bigint_as_string=False,
418
+ item_sort_key=None,
419
+ for_json=False,
420
+ int_as_string_bitcount=None,
421
+ )
422
+
423
+ def dumpJSON(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True,
424
+ cls=None, indent=None, separators=None,
425
+ encoding='utf-8', default=None, use_decimal=True,
426
+ namedtuple_as_object=True, tuple_as_array=True,
427
+ bigint_as_string=False, sort_keys=False, item_sort_key=None,
428
+ for_json=False, int_as_string_bitcount=None, **kw):
429
+ """Serialize ``obj`` as a JSON formatted stream to ``fp`` (a
430
+ ``.write()``-supporting file-like object).
431
+
432
+ If *skipkeys* is true then ``dict`` keys that are not basic types
433
+ (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``)
434
+ will be skipped instead of raising a ``TypeError``.
435
+
436
+ If *ensure_ascii* is false, then the some chunks written to ``fp``
437
+ may be ``unicode`` instances, subject to normal Python ``str`` to
438
+ ``unicode`` coercion rules. Unless ``fp.write()`` explicitly
439
+ understands ``unicode`` (as in ``codecs.getwriter()``) this is likely
440
+ to cause an error.
441
+
442
+ If *check_circular* is false, then the circular reference check
443
+ for container types will be skipped and a circular reference will
444
+ result in an ``OverflowError`` (or worse).
445
+
446
+ If *indent* is a string, then JSON array elements and object members
447
+ will be pretty-printed with a newline followed by that string repeated
448
+ for each level of nesting. ``None`` (the default) selects the most compact
449
+ representation without any newlines. An integer is also accepted
450
+ and is converted to a string with that many spaces.
451
+
452
+ If specified, *separators* should be an
453
+ ``(item_separator, key_separator)`` tuple. The default is ``(', ', ': ')``
454
+ if *indent* is ``None`` and ``(',', ': ')`` otherwise. To get the most
455
+ compact JSON representation, you should specify ``(',', ':')`` to eliminate
456
+ whitespace.
457
+
458
+ *encoding* is the character encoding for str instances, default is UTF-8.
459
+
460
+ *default(obj)* is a function that should return a serializable version
461
+ of obj or raise ``TypeError``. The default simply raises ``TypeError``.
462
+
463
+ If *use_decimal* is true (default: ``True``) then decimal.Decimal
464
+ will be natively serialized to JSON with full precision.
465
+
466
+ If *namedtuple_as_object* is true (default: ``True``),
467
+ :class:`tuple` subclasses with ``_asdict()`` methods will be encoded
468
+ as JSON objects.
469
+
470
+ If *tuple_as_array* is true (default: ``True``),
471
+ :class:`tuple` (and subclasses) will be encoded as JSON arrays.
472
+
473
+ If *bigint_as_string* is true (default: ``False``), ints 2**53 and higher
474
+ or lower than -2**53 will be encoded as strings. This is to avoid the
475
+ rounding that happens in Javascript otherwise. Note that this is still a
476
+ lossy operation that will not round-trip correctly and should be used
477
+ sparingly.
478
+
479
+ If *int_as_string_bitcount* is a positive number (n), then int of size
480
+ greater than or equal to 2**n or lower than or equal to -2**n will be
481
+ encoded as strings.
482
+
483
+ If specified, *item_sort_key* is a callable used to sort the items in
484
+ each dictionary. This is useful if you want to sort items other than
485
+ in alphabetical order by key. This option takes precedence over
486
+ *sort_keys*.
487
+
488
+ If *sort_keys* is true (default: ``False``), the output of dictionaries
489
+ will be sorted by item.
490
+
491
+ If *for_json* is true (default: ``False``), objects with a ``for_json()``
492
+ method will use the return value of that method for encoding as JSON
493
+ instead of the object.
494
+
495
+ To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
496
+ ``.default()`` method to serialize additional types), specify it with
497
+ the ``cls`` kwarg. NOTE: You should use *default* or *for_json* instead
498
+ of subclassing whenever possible.
499
+
500
+ """
501
+ # cached encoder
502
+ if (not skipkeys and ensure_ascii and
503
+ check_circular and
504
+ cls is None and indent is None and separators is None and
505
+ encoding == 'utf-8' and default is None and use_decimal
506
+ and namedtuple_as_object and tuple_as_array
507
+ and not bigint_as_string and not sort_keys
508
+ and not item_sort_key and not for_json
509
+ and int_as_string_bitcount is None
510
+ and not kw
511
+ ):
512
+ iterable = _default_json_encoder.iterencode(obj)
513
+ else:
514
+ if cls is None:
515
+ cls = JSONEncoder
516
+ iterable = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii,
517
+ check_circular=check_circular, indent=indent,
518
+ separators=separators, encoding=encoding,
519
+ default=default, use_decimal=use_decimal,
520
+ namedtuple_as_object=namedtuple_as_object,
521
+ tuple_as_array=tuple_as_array,
522
+ bigint_as_string=bigint_as_string,
523
+ sort_keys=sort_keys,
524
+ item_sort_key=item_sort_key,
525
+ for_json=for_json,
526
+ int_as_string_bitcount=int_as_string_bitcount,
527
+ **kw).iterencode(obj)
528
+ # could accelerate with writelines in some versions of Python, at
529
+ # a debuggability cost
530
+ for chunk in iterable:
531
+ fp.write(chunk)
532
+
533
+
534
+ def dumpsJSON(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
535
+ cls=None, indent=None, separators=None,
536
+ encoding='utf-8', default=None, use_decimal=True,
537
+ namedtuple_as_object=True, tuple_as_array=True,
538
+ bigint_as_string=False, sort_keys=False, item_sort_key=None,
539
+ for_json=False, int_as_string_bitcount=None, **kw):
540
+ """Serialize ``obj`` to a JSON formatted ``str``.
541
+
542
+ If ``skipkeys`` is false then ``dict`` keys that are not basic types
543
+ (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``)
544
+ will be skipped instead of raising a ``TypeError``.
545
+
546
+ If ``ensure_ascii`` is false, then the return value will be a
547
+ ``unicode`` instance subject to normal Python ``str`` to ``unicode``
548
+ coercion rules instead of being escaped to an ASCII ``str``.
549
+
550
+ If ``check_circular`` is false, then the circular reference check
551
+ for container types will be skipped and a circular reference will
552
+ result in an ``OverflowError`` (or worse).
553
+
554
+ If ``indent`` is a string, then JSON array elements and object members
555
+ will be pretty-printed with a newline followed by that string repeated
556
+ for each level of nesting. ``None`` (the default) selects the most compact
557
+ representation without any newlines. An integer is also accepted
558
+ and is converted to a string with that many spaces.
559
+
560
+ If specified, ``separators`` should be an
561
+ ``(item_separator, key_separator)`` tuple. The default is ``(', ', ': ')``
562
+ if *indent* is ``None`` and ``(',', ': ')`` otherwise. To get the most
563
+ compact JSON representation, you should specify ``(',', ':')`` to eliminate
564
+ whitespace.
565
+
566
+ ``encoding`` is the character encoding for str instances, default is UTF-8.
567
+
568
+ ``default(obj)`` is a function that should return a serializable version
569
+ of obj or raise TypeError. The default simply raises TypeError.
570
+
571
+ If *use_decimal* is true (default: ``True``) then decimal.Decimal
572
+ will be natively serialized to JSON with full precision.
573
+
574
+ If *namedtuple_as_object* is true (default: ``True``),
575
+ :class:`tuple` subclasses with ``_asdict()`` methods will be encoded
576
+ as JSON objects.
577
+
578
+ If *tuple_as_array* is true (default: ``True``),
579
+ :class:`tuple` (and subclasses) will be encoded as JSON arrays.
580
+
581
+ If *bigint_as_string* is true (not the default), ints 2**53 and higher
582
+ or lower than -2**53 will be encoded as strings. This is to avoid the
583
+ rounding that happens in Javascript otherwise.
584
+
585
+ If *int_as_string_bitcount* is a positive number (n), then int of size
586
+ greater than or equal to 2**n or lower than or equal to -2**n will be
587
+ encoded as strings.
588
+
589
+ If specified, *item_sort_key* is a callable used to sort the items in
590
+ each dictionary. This is useful if you want to sort items other than
591
+ in alphabetical order by key. This option takes precendence over
592
+ *sort_keys*.
593
+
594
+ If *sort_keys* is true (default: ``False``), the output of dictionaries
595
+ will be sorted by item.
596
+
597
+ If *for_json* is true (default: ``False``), objects with a ``for_json()``
598
+ method will use the return value of that method for encoding as JSON
599
+ instead of the object.
600
+
601
+ To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
602
+ ``.default()`` method to serialize additional types), specify it with
603
+ the ``cls`` kwarg. NOTE: You should use *default* instead of subclassing
604
+ whenever possible.
605
+
606
+ """
607
+ # cached encoder
608
+ if (
609
+ not skipkeys and ensure_ascii and
610
+ check_circular and
611
+ cls is None and indent is None and separators is None and
612
+ encoding == 'utf-8' and default is None and use_decimal
613
+ and namedtuple_as_object and tuple_as_array
614
+ and not bigint_as_string and not sort_keys
615
+ and not item_sort_key and not for_json
616
+ and int_as_string_bitcount is None
617
+ and not kw
618
+ ):
619
+ return _default_json_encoder.encode(obj)
620
+ if cls is None:
621
+ cls = JSONEncoder
622
+ return cls(
623
+ skipkeys=skipkeys, ensure_ascii=ensure_ascii,
624
+ check_circular=check_circular, indent=indent,
625
+ separators=separators, encoding=encoding, default=default,
626
+ use_decimal=use_decimal,
627
+ namedtuple_as_object=namedtuple_as_object,
628
+ tuple_as_array=tuple_as_array,
629
+ bigint_as_string=bigint_as_string,
630
+ sort_keys=sort_keys,
631
+ item_sort_key=item_sort_key,
632
+ for_json=for_json,
633
+ int_as_string_bitcount=int_as_string_bitcount,
634
+ **kw).encode(obj)
635
+
636
+
637
+
638
+ def simple_first(kv):
639
+ """Helper function to pass to item_sort_key to sort simple
640
+ elements to the top, then container elements.
641
+ """
642
+ return (isinstance(kv[1], (list, dict, tuple)), kv[0])
lib/python3.12/site-packages/hjson/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (23.2 kB). View file
 
lib/python3.12/site-packages/hjson/__pycache__/compat.cpython-312.pyc ADDED
Binary file (1.93 kB). View file
 
lib/python3.12/site-packages/hjson/__pycache__/decoder.cpython-312.pyc ADDED
Binary file (21 kB). View file
 
lib/python3.12/site-packages/hjson/__pycache__/encoder.cpython-312.pyc ADDED
Binary file (18.8 kB). View file
 
lib/python3.12/site-packages/hjson/__pycache__/encoderH.cpython-312.pyc ADDED
Binary file (20 kB). View file
 
lib/python3.12/site-packages/hjson/__pycache__/ordered_dict.cpython-312.pyc ADDED
Binary file (5.99 kB). View file
 
lib/python3.12/site-packages/hjson/__pycache__/scanner.cpython-312.pyc ADDED
Binary file (2.81 kB). View file
 
lib/python3.12/site-packages/hjson/__pycache__/tool.cpython-312.pyc ADDED
Binary file (3 kB). View file
 
lib/python3.12/site-packages/hjson/compat.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Python 3 compatibility shims
2
+ """
3
+ import sys
4
+ if sys.version_info[0] < 3:
5
+ PY3 = False
6
+ def b(s):
7
+ return s
8
+ def u(s):
9
+ return unicode(s, 'unicode_escape')
10
+ import cStringIO as StringIO
11
+ StringIO = BytesIO = StringIO.StringIO
12
+ text_type = unicode
13
+ binary_type = str
14
+ string_types = (basestring,)
15
+ integer_types = (int, long)
16
+ unichr = unichr
17
+ reload_module = reload
18
+ def fromhex(s):
19
+ return s.decode('hex')
20
+
21
+ else:
22
+ PY3 = True
23
+ if sys.version_info[:2] >= (3, 4):
24
+ from importlib import reload as reload_module
25
+ else:
26
+ from imp import reload as reload_module
27
+ import codecs
28
+ def b(s):
29
+ return codecs.latin_1_encode(s)[0]
30
+ def u(s):
31
+ return s
32
+ import io
33
+ StringIO = io.StringIO
34
+ BytesIO = io.BytesIO
35
+ text_type = str
36
+ binary_type = bytes
37
+ string_types = (str,)
38
+ integer_types = (int,)
39
+
40
+ def unichr(s):
41
+ return u(chr(s))
42
+
43
+ def fromhex(s):
44
+ return bytes.fromhex(s)
45
+
46
+ long_type = integer_types[-1]
lib/python3.12/site-packages/hjson/decoder.py ADDED
@@ -0,0 +1,569 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of HjsonDecoder
2
+ """
3
+ from __future__ import absolute_import
4
+ import re
5
+ import sys
6
+ import struct
7
+ from .compat import fromhex, b, u, text_type, binary_type, PY3, unichr
8
+ from .scanner import HjsonDecodeError
9
+
10
+ # NOTE (3.1.0): HjsonDecodeError may still be imported from this module for
11
+ # compatibility, but it was never in the __all__
12
+ __all__ = ['HjsonDecoder']
13
+
14
+ FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL
15
+
16
+ def _floatconstants():
17
+ _BYTES = fromhex('7FF80000000000007FF0000000000000')
18
+ # The struct module in Python 2.4 would get frexp() out of range here
19
+ # when an endian is specified in the format string. Fixed in Python 2.5+
20
+ if sys.byteorder != 'big':
21
+ _BYTES = _BYTES[:8][::-1] + _BYTES[8:][::-1]
22
+ nan, inf = struct.unpack('dd', _BYTES)
23
+ return nan, inf, -inf
24
+
25
+ NaN, PosInf, NegInf = _floatconstants()
26
+
27
+ WHITESPACE = ' \t\n\r'
28
+ PUNCTUATOR = '{}[],:'
29
+
30
+ NUMBER_RE = re.compile(r'[\t ]*(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?[\t ]*')
31
+ STRINGCHUNK = re.compile(r'(.*?)([\'"\\\x00-\x1f])', FLAGS)
32
+ BACKSLASH = {
33
+ '"': u('"'), '\'': u('\''), '\\': u('\u005c'), '/': u('/'),
34
+ 'b': u('\b'), 'f': u('\f'), 'n': u('\n'), 'r': u('\r'), 't': u('\t'),
35
+ }
36
+
37
+ DEFAULT_ENCODING = "utf-8"
38
+
39
+ def getNext(s, end):
40
+ while 1:
41
+ # Use a slice to prevent IndexError from being raised
42
+ ch = s[end:end + 1]
43
+ # Skip whitespace.
44
+ while ch in WHITESPACE:
45
+ if ch == '': return ch, end
46
+ end += 1
47
+ ch = s[end:end + 1]
48
+
49
+ # Hjson allows comments
50
+ ch2 = s[end + 1:end + 2]
51
+ if ch == '#' or ch == '/' and ch2 == '/':
52
+ end = getEol(s, end)
53
+ elif ch == '/' and ch2 == '*':
54
+ end += 2
55
+ ch = s[end]
56
+ while ch != '' and not (ch == '*' and s[end + 1] == '/'):
57
+ end += 1
58
+ ch = s[end]
59
+ if ch != '':
60
+ end += 2
61
+ else:
62
+ break
63
+
64
+ return ch, end
65
+
66
+ def getEol(s, end):
67
+ # skip until eol
68
+
69
+ while 1:
70
+ ch = s[end:end + 1]
71
+ if ch == '\r' or ch == '\n' or ch == '':
72
+ return end
73
+ end += 1
74
+
75
+ def skipIndent(s, end, n):
76
+ ch = s[end:end + 1]
77
+ while ch != '' and ch in " \t\r" and (n > 0 or n < 0):
78
+ end += 1
79
+ n -= 1
80
+ ch = s[end:end + 1]
81
+ return end
82
+
83
+
84
+ def scanstring(s, end, encoding=None, strict=True,
85
+ _b=BACKSLASH, _m=STRINGCHUNK.match, _join=u('').join,
86
+ _PY3=PY3, _maxunicode=sys.maxunicode):
87
+ """Scan the string s for a JSON string. End is the index of the
88
+ character in s after the quote that started the JSON string.
89
+ Unescapes all valid JSON string escape sequences and raises ValueError
90
+ on attempt to decode an invalid string. If strict is False then literal
91
+ control characters are allowed in the string.
92
+
93
+ Returns a tuple of the decoded string and the index of the character in s
94
+ after the end quote."""
95
+ if encoding is None:
96
+ encoding = DEFAULT_ENCODING
97
+ chunks = []
98
+ _append = chunks.append
99
+ begin = end - 1
100
+ # callers make sure that string starts with " or '
101
+ exitCh = s[begin]
102
+ while 1:
103
+ chunk = _m(s, end)
104
+ if chunk is None:
105
+ raise HjsonDecodeError(
106
+ "Unterminated string starting at", s, begin)
107
+ end = chunk.end()
108
+ content, terminator = chunk.groups()
109
+ # Content is contains zero or more unescaped string characters
110
+ if content:
111
+ if not _PY3 and not isinstance(content, text_type):
112
+ content = text_type(content, encoding)
113
+ _append(content)
114
+ # Terminator is the end of string, a literal control character,
115
+ # or a backslash denoting that an escape sequence follows
116
+ if terminator == exitCh:
117
+ break
118
+ elif terminator == '"' or terminator == '\'':
119
+ _append(terminator)
120
+ continue
121
+ elif terminator != '\\':
122
+ if strict:
123
+ msg = "Invalid control character %r at"
124
+ raise HjsonDecodeError(msg, s, end)
125
+ else:
126
+ _append(terminator)
127
+ continue
128
+ try:
129
+ esc = s[end]
130
+ except IndexError:
131
+ raise HjsonDecodeError(
132
+ "Unterminated string starting at", s, begin)
133
+ # If not a unicode escape sequence, must be in the lookup table
134
+ if esc != 'u':
135
+ try:
136
+ char = _b[esc]
137
+ except KeyError:
138
+ msg = "Invalid \\X escape sequence %r"
139
+ raise HjsonDecodeError(msg, s, end)
140
+ end += 1
141
+ else:
142
+ # Unicode escape sequence
143
+ msg = "Invalid \\uXXXX escape sequence"
144
+ esc = s[end + 1:end + 5]
145
+ escX = esc[1:2]
146
+ if len(esc) != 4 or escX == 'x' or escX == 'X':
147
+ raise HjsonDecodeError(msg, s, end - 1)
148
+ try:
149
+ uni = int(esc, 16)
150
+ except ValueError:
151
+ raise HjsonDecodeError(msg, s, end - 1)
152
+ end += 5
153
+ # Check for surrogate pair on UCS-4 systems
154
+ # Note that this will join high/low surrogate pairs
155
+ # but will also pass unpaired surrogates through
156
+ if (_maxunicode > 65535 and
157
+ uni & 0xfc00 == 0xd800 and
158
+ s[end:end + 2] == '\\u'):
159
+ esc2 = s[end + 2:end + 6]
160
+ escX = esc2[1:2]
161
+ if len(esc2) == 4 and not (escX == 'x' or escX == 'X'):
162
+ try:
163
+ uni2 = int(esc2, 16)
164
+ except ValueError:
165
+ raise HjsonDecodeError(msg, s, end)
166
+ if uni2 & 0xfc00 == 0xdc00:
167
+ uni = 0x10000 + (((uni - 0xd800) << 10) |
168
+ (uni2 - 0xdc00))
169
+ end += 6
170
+ char = unichr(uni)
171
+ # Append the unescaped character
172
+ _append(char)
173
+ return _join(chunks), end
174
+
175
+ def mlscanstring(s, end):
176
+ """Scan a multiline string"""
177
+
178
+ string = ""
179
+ triple = 0
180
+
181
+ # we are at ''' - get indent
182
+ indent = 0
183
+ while 1:
184
+ ch = s[end-indent-1]
185
+ if ch == '\n': break
186
+ indent += 1
187
+
188
+ # skip white/to (newline)
189
+ end = skipIndent(s, end + 3, -1)
190
+
191
+ ch = s[end]
192
+ if ch == '\n': end = skipIndent(s, end + 1, indent)
193
+
194
+ # When parsing multiline string values, we must look for ' characters
195
+ while 1:
196
+ ch = s[end:end + 1]
197
+ if ch == '':
198
+ raise HjsonDecodeError("Bad multiline string", s, end);
199
+ elif ch == '\'':
200
+ triple += 1
201
+ end += 1
202
+ if triple == 3:
203
+ if string and string[-1] == '\n':
204
+ string = string[:-1] # remove last EOL
205
+ return string, end
206
+ else:
207
+ continue
208
+ else:
209
+ while triple > 0:
210
+ string += '\''
211
+ triple -= 1
212
+
213
+ if ch == '\n':
214
+ string += ch
215
+ end = skipIndent(s, end + 1, indent)
216
+ else:
217
+ if ch != '\r':
218
+ string += ch
219
+ end += 1
220
+
221
+ def scantfnns(context, s, end):
222
+ """Scan s until eol. return string, True, False or None"""
223
+
224
+ chf, begin = getNext(s, end)
225
+ end = begin
226
+
227
+ if chf in PUNCTUATOR:
228
+ raise HjsonDecodeError("Found a punctuator character when expecting a quoteless string (check your syntax)", s, end);
229
+
230
+ while 1:
231
+ ch = s[end:end + 1]
232
+
233
+ isEol = ch == '\r' or ch == '\n' or ch == ''
234
+ if isEol or ch == ',' or \
235
+ ch == '}' or ch == ']' or \
236
+ ch == '#' or \
237
+ ch == '/' and (s[end + 1:end + 2] == '/' or s[end + 1:end + 2] == '*'):
238
+
239
+ m = None
240
+ mend = end
241
+ if next: mend -= 1
242
+
243
+ if chf == 'n' and s[begin:end].strip() == 'null':
244
+ return None, end
245
+ elif chf == 't' and s[begin:end].strip() == 'true':
246
+ return True, end
247
+ elif chf == 'f' and s[begin:end].strip() == 'false':
248
+ return False, end
249
+ elif chf == '-' or chf >= '0' and chf <= '9':
250
+ m = NUMBER_RE.match(s, begin)
251
+
252
+ if m is not None and m.end() == end:
253
+ integer, frac, exp = m.groups()
254
+ if frac or exp:
255
+ res = context.parse_float(integer + (frac or '') + (exp or ''))
256
+ if int(res) == res and abs(res)<1e10: res = int(res)
257
+ else:
258
+ res = context.parse_int(integer)
259
+ return res, end
260
+
261
+ if isEol:
262
+ return s[begin:end].strip(), end
263
+
264
+ end += 1
265
+
266
+ def scanKeyName(s, end, encoding=None, strict=True):
267
+ """Scan the string s for a JSON/Hjson key. see scanstring"""
268
+
269
+ ch, end = getNext(s, end)
270
+
271
+ if ch == '"' or ch == '\'':
272
+ return scanstring(s, end + 1, encoding, strict)
273
+
274
+ begin = end
275
+ space = -1
276
+ while 1:
277
+ ch = s[end:end + 1]
278
+
279
+ if ch == '':
280
+ raise HjsonDecodeError("Bad key name (eof)", s, end);
281
+ elif ch == ':':
282
+ if begin == end:
283
+ raise HjsonDecodeError("Found ':' but no key name (for an empty key name use quotes)", s, begin)
284
+ elif space >= 0:
285
+ if space != end - 1: raise HjsonDecodeError("Found whitespace in your key name (use quotes to include)", s, space)
286
+ return s[begin:end].rstrip(), end
287
+ else:
288
+ return s[begin:end], end
289
+ elif ch in WHITESPACE:
290
+ if space < 0 or space == end - 1: space = end
291
+ elif ch == '{' or ch == '}' or ch == '[' or ch == ']' or ch == ',':
292
+ raise HjsonDecodeError("Found '" + ch + "' where a key name was expected (check your syntax or use quotes if the key name includes {}[],: or whitespace)", s, begin)
293
+ end += 1
294
+
295
+ def make_scanner(context):
296
+ parse_object = context.parse_object
297
+ parse_array = context.parse_array
298
+ parse_string = context.parse_string
299
+ parse_mlstring = context.parse_mlstring
300
+ parse_tfnns = context.parse_tfnns
301
+ encoding = context.encoding
302
+ strict = context.strict
303
+ object_hook = context.object_hook
304
+ object_pairs_hook = context.object_pairs_hook
305
+ memo = context.memo
306
+
307
+ def _scan_once(string, idx):
308
+ try:
309
+ ch = string[idx]
310
+ except IndexError:
311
+ raise HjsonDecodeError('Expecting value', string, idx)
312
+
313
+ if ch == '"' or ch == '\'':
314
+ if string[idx:idx + 3] == '\'\'\'':
315
+ return parse_mlstring(string, idx)
316
+ else:
317
+ return parse_string(string, idx + 1, encoding, strict)
318
+ elif ch == '{':
319
+ return parse_object((string, idx + 1), encoding, strict,
320
+ _scan_once, object_hook, object_pairs_hook, memo)
321
+ elif ch == '[':
322
+ return parse_array((string, idx + 1), _scan_once)
323
+
324
+ return parse_tfnns(context, string, idx)
325
+
326
+ def scan_once(string, idx):
327
+ if idx < 0: raise HjsonDecodeError('Expecting value', string, idx)
328
+ try:
329
+ return _scan_once(string, idx)
330
+ finally:
331
+ memo.clear()
332
+
333
+ def scan_object_once(string, idx):
334
+ if idx < 0: raise HjsonDecodeError('Expecting value', string, idx)
335
+ try:
336
+ return parse_object((string, idx), encoding, strict,
337
+ _scan_once, object_hook, object_pairs_hook, memo, True)
338
+ finally:
339
+ memo.clear()
340
+
341
+ return scan_once, scan_object_once
342
+
343
+
344
+ def JSONObject(state, encoding, strict, scan_once, object_hook,
345
+ object_pairs_hook, memo=None, objectWithoutBraces=False):
346
+ (s, end) = state
347
+ # Backwards compatibility
348
+ if memo is None:
349
+ memo = {}
350
+ memo_get = memo.setdefault
351
+ pairs = []
352
+
353
+ ch, end = getNext(s, end)
354
+
355
+ # Trivial empty object
356
+ if not objectWithoutBraces and ch == '}':
357
+ if object_pairs_hook is not None:
358
+ result = object_pairs_hook(pairs)
359
+ return result, end + 1
360
+ pairs = {}
361
+ if object_hook is not None:
362
+ pairs = object_hook(pairs)
363
+ return pairs, end + 1
364
+
365
+ while True:
366
+ key, end = scanKeyName(s, end, encoding, strict)
367
+ key = memo_get(key, key)
368
+
369
+ ch, end = getNext(s, end)
370
+ if ch != ':':
371
+ raise HjsonDecodeError("Expecting ':' delimiter", s, end)
372
+
373
+ ch, end = getNext(s, end + 1)
374
+
375
+ value, end = scan_once(s, end)
376
+ pairs.append((key, value))
377
+
378
+ ch, end = getNext(s, end)
379
+
380
+ if ch == ',':
381
+ ch, end = getNext(s, end + 1)
382
+
383
+ if objectWithoutBraces:
384
+ if ch == '': break;
385
+ else:
386
+ if ch == '}':
387
+ end += 1
388
+ break
389
+
390
+ ch, end = getNext(s, end)
391
+
392
+ if object_pairs_hook is not None:
393
+ result = object_pairs_hook(pairs)
394
+ return result, end
395
+ pairs = dict(pairs)
396
+ if object_hook is not None:
397
+ pairs = object_hook(pairs)
398
+ return pairs, end
399
+
400
+ def JSONArray(state, scan_once):
401
+ (s, end) = state
402
+ values = []
403
+
404
+ ch, end = getNext(s, end)
405
+
406
+ # Look-ahead for trivial empty array
407
+ if ch == ']':
408
+ return values, end + 1
409
+ elif ch == '':
410
+ raise HjsonDecodeError("End of input while parsing an array (did you forget a closing ']'?)", s, end)
411
+ _append = values.append
412
+ while True:
413
+ value, end = scan_once(s, end)
414
+ _append(value)
415
+
416
+ ch, end = getNext(s, end)
417
+ if ch == ',':
418
+ ch, end = getNext(s, end + 1)
419
+
420
+ if ch == ']':
421
+ end += 1
422
+ break
423
+
424
+ ch, end = getNext(s, end)
425
+
426
+ return values, end
427
+
428
+
429
+ class HjsonDecoder(object):
430
+ """Hjson decoder
431
+
432
+ Performs the following translations in decoding by default:
433
+
434
+ +---------------+-------------------+
435
+ | JSON | Python |
436
+ +===============+===================+
437
+ | object | dict |
438
+ +---------------+-------------------+
439
+ | array | list |
440
+ +---------------+-------------------+
441
+ | string | str, unicode |
442
+ +---------------+-------------------+
443
+ | number (int) | int, long |
444
+ +---------------+-------------------+
445
+ | number (real) | float |
446
+ +---------------+-------------------+
447
+ | true | True |
448
+ +---------------+-------------------+
449
+ | false | False |
450
+ +---------------+-------------------+
451
+ | null | None |
452
+ +---------------+-------------------+
453
+
454
+ """
455
+
456
+ def __init__(self, encoding=None, object_hook=None, parse_float=None,
457
+ parse_int=None, strict=True,
458
+ object_pairs_hook=None):
459
+ """
460
+ *encoding* determines the encoding used to interpret any
461
+ :class:`str` objects decoded by this instance (``'utf-8'`` by
462
+ default). It has no effect when decoding :class:`unicode` objects.
463
+
464
+ Note that currently only encodings that are a superset of ASCII work,
465
+ strings of other encodings should be passed in as :class:`unicode`.
466
+
467
+ *object_hook*, if specified, will be called with the result of every
468
+ JSON object decoded and its return value will be used in place of the
469
+ given :class:`dict`. This can be used to provide custom
470
+ deserializations (e.g. to support JSON-RPC class hinting).
471
+
472
+ *object_pairs_hook* is an optional function that will be called with
473
+ the result of any object literal decode with an ordered list of pairs.
474
+ The return value of *object_pairs_hook* will be used instead of the
475
+ :class:`dict`. This feature can be used to implement custom decoders
476
+ that rely on the order that the key and value pairs are decoded (for
477
+ example, :func:`collections.OrderedDict` will remember the order of
478
+ insertion). If *object_hook* is also defined, the *object_pairs_hook*
479
+ takes priority.
480
+
481
+ *parse_float*, if specified, will be called with the string of every
482
+ JSON float to be decoded. By default, this is equivalent to
483
+ ``float(num_str)``. This can be used to use another datatype or parser
484
+ for JSON floats (e.g. :class:`decimal.Decimal`).
485
+
486
+ *parse_int*, if specified, will be called with the string of every
487
+ JSON int to be decoded. By default, this is equivalent to
488
+ ``int(num_str)``. This can be used to use another datatype or parser
489
+ for JSON integers (e.g. :class:`float`).
490
+
491
+ *strict* controls the parser's behavior when it encounters an
492
+ invalid control character in a string. The default setting of
493
+ ``True`` means that unescaped control characters are parse errors, if
494
+ ``False`` then control characters will be allowed in strings.
495
+
496
+ """
497
+ if encoding is None:
498
+ encoding = DEFAULT_ENCODING
499
+ self.encoding = encoding
500
+ self.object_hook = object_hook
501
+ self.object_pairs_hook = object_pairs_hook
502
+ self.parse_float = parse_float or float
503
+ self.parse_int = parse_int or int
504
+ self.strict = strict
505
+ self.parse_object = JSONObject
506
+ self.parse_array = JSONArray
507
+ self.parse_string = scanstring
508
+ self.parse_mlstring = mlscanstring
509
+ self.parse_tfnns = scantfnns
510
+ self.memo = {}
511
+ (self.scan_once, self.scan_object_once) = make_scanner(self)
512
+
513
+ def decode(self, s, _PY3=PY3):
514
+ """Return the Python representation of ``s`` (a ``str`` or ``unicode``
515
+ instance containing a JSON document)
516
+
517
+ """
518
+ if _PY3 and isinstance(s, binary_type):
519
+ s = s.decode(self.encoding)
520
+ obj, end = self.raw_decode(s)
521
+ ch, end = getNext(s, end)
522
+ if end != len(s):
523
+ raise HjsonDecodeError("Extra data", s, end, len(s))
524
+ return obj
525
+
526
+ def raw_decode(self, s, idx=0, _PY3=PY3):
527
+ """Decode a JSON document from ``s`` (a ``str`` or ``unicode``
528
+ beginning with a JSON document) and return a 2-tuple of the Python
529
+ representation and the index in ``s`` where the document ended.
530
+ Optionally, ``idx`` can be used to specify an offset in ``s`` where
531
+ the JSON document begins.
532
+
533
+ This can be used to decode a JSON document from a string that may
534
+ have extraneous data at the end.
535
+
536
+ """
537
+ if idx < 0:
538
+ # Ensure that raw_decode bails on negative indexes, the regex
539
+ # would otherwise mask this behavior. #98
540
+ raise HjsonDecodeError('Expecting value', s, idx)
541
+ if _PY3 and not isinstance(s, text_type):
542
+ raise TypeError("Input string must be text")
543
+ # strip UTF-8 bom
544
+ if len(s) > idx:
545
+ ord0 = ord(s[idx])
546
+ if ord0 == 0xfeff:
547
+ idx += 1
548
+ elif ord0 == 0xef and s[idx:idx + 3] == '\xef\xbb\xbf':
549
+ idx += 3
550
+
551
+ start_index = idx
552
+ ch, idx = getNext(s, idx)
553
+
554
+ # If blank or comment only file, return dict
555
+ if start_index == 0 and ch == '':
556
+ return {}, 0
557
+
558
+ if ch == '{' or ch == '[':
559
+ return self.scan_once(s, idx)
560
+ else:
561
+ # assume we have a root object without braces
562
+ try:
563
+ return self.scan_object_once(s, idx)
564
+ except HjsonDecodeError as e:
565
+ # test if we are dealing with a single JSON value instead (true/false/null/num/"")
566
+ try:
567
+ return self.scan_once(s, idx)
568
+ except:
569
+ raise e
lib/python3.12/site-packages/hjson/encoder.py ADDED
@@ -0,0 +1,521 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of JSONEncoder
2
+ """
3
+ from __future__ import absolute_import
4
+ import re
5
+ from operator import itemgetter
6
+ from decimal import Decimal
7
+ from .compat import u, unichr, binary_type, string_types, integer_types, PY3
8
+ from .decoder import PosInf
9
+
10
+ #ESCAPE = re.compile(ur'[\x00-\x1f\\"\b\f\n\r\t\u2028\u2029]')
11
+ # This is required because u() will mangle the string and ur'' isn't valid
12
+ # python3 syntax
13
+ ESCAPE = re.compile(u'[\\x00-\\x1f\\\\"\\b\\f\\n\\r\\t\u2028\u2029]')
14
+ ESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])')
15
+ HAS_UTF8 = re.compile(r'[\x80-\xff]')
16
+ ESCAPE_DCT = {
17
+ '\\': '\\\\',
18
+ '"': '\\"',
19
+ '\b': '\\b',
20
+ '\f': '\\f',
21
+ '\n': '\\n',
22
+ '\r': '\\r',
23
+ '\t': '\\t',
24
+ }
25
+ for i in range(0x20):
26
+ #ESCAPE_DCT.setdefault(chr(i), '\\u{0:04x}'.format(i))
27
+ ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,))
28
+ for i in [0x2028, 0x2029]:
29
+ ESCAPE_DCT.setdefault(unichr(i), '\\u%04x' % (i,))
30
+
31
+ FLOAT_REPR = repr
32
+
33
+ def encode_basestring(s, _PY3=PY3, _q=u('"')):
34
+ """Return a JSON representation of a Python string
35
+
36
+ """
37
+ if _PY3:
38
+ if isinstance(s, binary_type):
39
+ s = s.decode('utf-8')
40
+ else:
41
+ if isinstance(s, str) and HAS_UTF8.search(s) is not None:
42
+ s = s.decode('utf-8')
43
+ def replace(match):
44
+ return ESCAPE_DCT[match.group(0)]
45
+ return _q + ESCAPE.sub(replace, s) + _q
46
+
47
+
48
+ def py_encode_basestring_ascii(s, _PY3=PY3):
49
+ """Return an ASCII-only JSON representation of a Python string
50
+
51
+ """
52
+ if _PY3:
53
+ if isinstance(s, binary_type):
54
+ s = s.decode('utf-8')
55
+ else:
56
+ if isinstance(s, str) and HAS_UTF8.search(s) is not None:
57
+ s = s.decode('utf-8')
58
+ def replace(match):
59
+ s = match.group(0)
60
+ try:
61
+ return ESCAPE_DCT[s]
62
+ except KeyError:
63
+ n = ord(s)
64
+ if n < 0x10000:
65
+ #return '\\u{0:04x}'.format(n)
66
+ return '\\u%04x' % (n,)
67
+ else:
68
+ # surrogate pair
69
+ n -= 0x10000
70
+ s1 = 0xd800 | ((n >> 10) & 0x3ff)
71
+ s2 = 0xdc00 | (n & 0x3ff)
72
+ #return '\\u{0:04x}\\u{1:04x}'.format(s1, s2)
73
+ return '\\u%04x\\u%04x' % (s1, s2)
74
+ return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"'
75
+
76
+
77
+ encode_basestring_ascii = (
78
+ py_encode_basestring_ascii)
79
+
80
+ class JSONEncoder(object):
81
+ """Extensible JSON <http://json.org> encoder for Python data structures.
82
+
83
+ Supports the following objects and types by default:
84
+
85
+ +-------------------+---------------+
86
+ | Python | JSON |
87
+ +===================+===============+
88
+ | dict, namedtuple | object |
89
+ +-------------------+---------------+
90
+ | list, tuple | array |
91
+ +-------------------+---------------+
92
+ | str, unicode | string |
93
+ +-------------------+---------------+
94
+ | int, long, float | number |
95
+ +-------------------+---------------+
96
+ | True | true |
97
+ +-------------------+---------------+
98
+ | False | false |
99
+ +-------------------+---------------+
100
+ | None | null |
101
+ +-------------------+---------------+
102
+
103
+ To extend this to recognize other objects, subclass and implement a
104
+ ``.default()`` method with another method that returns a serializable
105
+ object for ``o`` if possible, otherwise it should call the superclass
106
+ implementation (to raise ``TypeError``).
107
+
108
+ """
109
+ item_separator = ', '
110
+ key_separator = ': '
111
+
112
+ def __init__(self, skipkeys=False, ensure_ascii=True,
113
+ check_circular=True, sort_keys=False,
114
+ indent=None, separators=None, encoding='utf-8', default=None,
115
+ use_decimal=True, namedtuple_as_object=True,
116
+ tuple_as_array=True, bigint_as_string=False,
117
+ item_sort_key=None, for_json=False,
118
+ int_as_string_bitcount=None):
119
+ """Constructor for JSONEncoder, with sensible defaults.
120
+
121
+ If skipkeys is false, then it is a TypeError to attempt
122
+ encoding of keys that are not str, int, long, float or None. If
123
+ skipkeys is True, such items are simply skipped.
124
+
125
+ If ensure_ascii is true, the output is guaranteed to be str
126
+ objects with all incoming unicode characters escaped. If
127
+ ensure_ascii is false, the output will be unicode object.
128
+
129
+ If check_circular is true, then lists, dicts, and custom encoded
130
+ objects will be checked for circular references during encoding to
131
+ prevent an infinite recursion (which would cause an OverflowError).
132
+ Otherwise, no such check takes place.
133
+
134
+ If sort_keys is true, then the output of dictionaries will be
135
+ sorted by key; this is useful for regression tests to ensure
136
+ that JSON serializations can be compared on a day-to-day basis.
137
+
138
+ If indent is a string, then JSON array elements and object members
139
+ will be pretty-printed with a newline followed by that string repeated
140
+ for each level of nesting. ``None`` (the default) selects the most compact
141
+ representation without any newlines. For backwards compatibility with
142
+ versions of hjson earlier than 2.1.0, an integer is also accepted
143
+ and is converted to a string with that many spaces.
144
+
145
+ If specified, separators should be an (item_separator, key_separator)
146
+ tuple. The default is (', ', ': ') if *indent* is ``None`` and
147
+ (',', ': ') otherwise. To get the most compact JSON representation,
148
+ you should specify (',', ':') to eliminate whitespace.
149
+
150
+ If specified, default is a function that gets called for objects
151
+ that can't otherwise be serialized. It should return a JSON encodable
152
+ version of the object or raise a ``TypeError``.
153
+
154
+ If encoding is not None, then all input strings will be
155
+ transformed into unicode using that encoding prior to JSON-encoding.
156
+ The default is UTF-8.
157
+
158
+ If use_decimal is true (not the default), ``decimal.Decimal`` will
159
+ be supported directly by the encoder. For the inverse, decode JSON
160
+ with ``parse_float=decimal.Decimal``.
161
+
162
+ If namedtuple_as_object is true (the default), objects with
163
+ ``_asdict()`` methods will be encoded as JSON objects.
164
+
165
+ If tuple_as_array is true (the default), tuple (and subclasses) will
166
+ be encoded as JSON arrays.
167
+
168
+ If bigint_as_string is true (not the default), ints 2**53 and higher
169
+ or lower than -2**53 will be encoded as strings. This is to avoid the
170
+ rounding that happens in Javascript otherwise.
171
+
172
+ If int_as_string_bitcount is a positive number (n), then int of size
173
+ greater than or equal to 2**n or lower than or equal to -2**n will be
174
+ encoded as strings.
175
+
176
+ If specified, item_sort_key is a callable used to sort the items in
177
+ each dictionary. This is useful if you want to sort items other than
178
+ in alphabetical order by key.
179
+
180
+ If for_json is true (not the default), objects with a ``for_json()``
181
+ method will use the return value of that method for encoding as JSON
182
+ instead of the object.
183
+
184
+ """
185
+
186
+ self.skipkeys = skipkeys
187
+ self.ensure_ascii = ensure_ascii
188
+ self.check_circular = check_circular
189
+ self.sort_keys = sort_keys
190
+ self.use_decimal = use_decimal
191
+ self.namedtuple_as_object = namedtuple_as_object
192
+ self.tuple_as_array = tuple_as_array
193
+ self.bigint_as_string = bigint_as_string
194
+ self.item_sort_key = item_sort_key
195
+ self.for_json = for_json
196
+ self.int_as_string_bitcount = int_as_string_bitcount
197
+ if indent is not None and not isinstance(indent, string_types):
198
+ indent = indent * ' '
199
+ self.indent = indent
200
+ if separators is not None:
201
+ self.item_separator, self.key_separator = separators
202
+ elif indent is not None:
203
+ self.item_separator = ','
204
+ if default is not None:
205
+ self.default = default
206
+ self.encoding = encoding
207
+
208
+ def default(self, o):
209
+ """Implement this method in a subclass such that it returns
210
+ a serializable object for ``o``, or calls the base implementation
211
+ (to raise a ``TypeError``).
212
+
213
+ For example, to support arbitrary iterators, you could
214
+ implement default like this::
215
+
216
+ def default(self, o):
217
+ try:
218
+ iterable = iter(o)
219
+ except TypeError:
220
+ pass
221
+ else:
222
+ return list(iterable)
223
+ return JSONEncoder.default(self, o)
224
+
225
+ """
226
+ raise TypeError(repr(o) + " is not JSON serializable")
227
+
228
+ def encode(self, o):
229
+ """Return a JSON string representation of a Python data structure.
230
+
231
+ >>> from hjson import JSONEncoder
232
+ >>> JSONEncoder().encode({"foo": ["bar", "baz"]})
233
+ '{"foo": ["bar", "baz"]}'
234
+
235
+ """
236
+ # This is for extremely simple cases and benchmarks.
237
+ if isinstance(o, binary_type):
238
+ _encoding = self.encoding
239
+ if (_encoding is not None and not (_encoding == 'utf-8')):
240
+ o = o.decode(_encoding)
241
+ if isinstance(o, string_types):
242
+ if self.ensure_ascii:
243
+ return encode_basestring_ascii(o)
244
+ else:
245
+ return encode_basestring(o)
246
+ # This doesn't pass the iterator directly to ''.join() because the
247
+ # exceptions aren't as detailed. The list call should be roughly
248
+ # equivalent to the PySequence_Fast that ''.join() would do.
249
+ chunks = self.iterencode(o, _one_shot=True)
250
+ if not isinstance(chunks, (list, tuple)):
251
+ chunks = list(chunks)
252
+ if self.ensure_ascii:
253
+ return ''.join(chunks)
254
+ else:
255
+ return u''.join(chunks)
256
+
257
+ def iterencode(self, o, _one_shot=False):
258
+ """Encode the given object and yield each string
259
+ representation as available.
260
+
261
+ For example::
262
+
263
+ for chunk in JSONEncoder().iterencode(bigobject):
264
+ mysocket.write(chunk)
265
+
266
+ """
267
+ if self.check_circular:
268
+ markers = {}
269
+ else:
270
+ markers = None
271
+ if self.ensure_ascii:
272
+ _encoder = encode_basestring_ascii
273
+ else:
274
+ _encoder = encode_basestring
275
+ if self.encoding != 'utf-8':
276
+ def _encoder(o, _orig_encoder=_encoder, _encoding=self.encoding):
277
+ if isinstance(o, binary_type):
278
+ o = o.decode(_encoding)
279
+ return _orig_encoder(o)
280
+
281
+ def floatstr(o, _repr=FLOAT_REPR, _inf=PosInf, _neginf=-PosInf):
282
+ # Check for specials. Note that this type of test is processor
283
+ # and/or platform-specific, so do tests which don't depend on
284
+ # the internals.
285
+
286
+ if o != o:
287
+ text = 'null'
288
+ elif o == _inf:
289
+ text = 'null'
290
+ elif o == _neginf:
291
+ text = 'null'
292
+ else:
293
+ return _repr(o)
294
+
295
+ return text
296
+
297
+ key_memo = {}
298
+ int_as_string_bitcount = (
299
+ 53 if self.bigint_as_string else self.int_as_string_bitcount)
300
+ _iterencode = _make_iterencode(
301
+ markers, self.default, _encoder, self.indent, floatstr,
302
+ self.key_separator, self.item_separator, self.sort_keys,
303
+ self.skipkeys, _one_shot, self.use_decimal,
304
+ self.namedtuple_as_object, self.tuple_as_array,
305
+ int_as_string_bitcount,
306
+ self.item_sort_key, self.encoding, self.for_json,
307
+ Decimal=Decimal)
308
+ try:
309
+ return _iterencode(o, 0)
310
+ finally:
311
+ key_memo.clear()
312
+
313
+
314
+ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
315
+ _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot,
316
+ _use_decimal, _namedtuple_as_object, _tuple_as_array,
317
+ _int_as_string_bitcount, _item_sort_key,
318
+ _encoding,_for_json,
319
+ ## HACK: hand-optimized bytecode; turn globals into locals
320
+ _PY3=PY3,
321
+ ValueError=ValueError,
322
+ string_types=string_types,
323
+ Decimal=Decimal,
324
+ dict=dict,
325
+ float=float,
326
+ id=id,
327
+ integer_types=integer_types,
328
+ isinstance=isinstance,
329
+ list=list,
330
+ str=str,
331
+ tuple=tuple,
332
+ ):
333
+ if _item_sort_key and not callable(_item_sort_key):
334
+ raise TypeError("item_sort_key must be None or callable")
335
+ elif _sort_keys and not _item_sort_key:
336
+ _item_sort_key = itemgetter(0)
337
+
338
+ if (_int_as_string_bitcount is not None and
339
+ (_int_as_string_bitcount <= 0 or
340
+ not isinstance(_int_as_string_bitcount, integer_types))):
341
+ raise TypeError("int_as_string_bitcount must be a positive integer")
342
+
343
+ def _encode_int(value):
344
+ skip_quoting = (
345
+ _int_as_string_bitcount is None
346
+ or
347
+ _int_as_string_bitcount < 1
348
+ )
349
+ if (
350
+ skip_quoting or
351
+ (-1 << _int_as_string_bitcount)
352
+ < value <
353
+ (1 << _int_as_string_bitcount)
354
+ ):
355
+ return str(value)
356
+ return '"' + str(value) + '"'
357
+
358
+ def _iterencode_list(lst, _current_indent_level):
359
+ if not lst:
360
+ yield '[]'
361
+ return
362
+ if markers is not None:
363
+ markerid = id(lst)
364
+ if markerid in markers:
365
+ raise ValueError("Circular reference detected")
366
+ markers[markerid] = lst
367
+ buf = '['
368
+ if _indent is not None:
369
+ _current_indent_level += 1
370
+ newline_indent = '\n' + (_indent * _current_indent_level)
371
+ separator = _item_separator + newline_indent
372
+ buf += newline_indent
373
+ else:
374
+ newline_indent = None
375
+ separator = _item_separator
376
+ first = True
377
+ for value in lst:
378
+ if first:
379
+ first = False
380
+ else:
381
+ buf = separator
382
+ yield buf
383
+
384
+ for chunk in _iterencode(value, _current_indent_level):
385
+ yield chunk
386
+
387
+ if newline_indent is not None:
388
+ _current_indent_level -= 1
389
+ yield '\n' + (_indent * _current_indent_level)
390
+ yield ']'
391
+ if markers is not None:
392
+ del markers[markerid]
393
+
394
+ def _stringify_key(key):
395
+ if isinstance(key, string_types): # pragma: no cover
396
+ pass
397
+ elif isinstance(key, binary_type):
398
+ key = key.decode(_encoding)
399
+ elif isinstance(key, float):
400
+ key = _floatstr(key)
401
+ elif key is True:
402
+ key = 'true'
403
+ elif key is False:
404
+ key = 'false'
405
+ elif key is None:
406
+ key = 'null'
407
+ elif isinstance(key, integer_types):
408
+ key = str(key)
409
+ elif _use_decimal and isinstance(key, Decimal):
410
+ key = str(key)
411
+ elif _skipkeys:
412
+ key = None
413
+ else:
414
+ raise TypeError("key " + repr(key) + " is not a string")
415
+ return key
416
+
417
+ def _iterencode_dict(dct, _current_indent_level):
418
+ if not dct:
419
+ yield '{}'
420
+ return
421
+ if markers is not None:
422
+ markerid = id(dct)
423
+ if markerid in markers:
424
+ raise ValueError("Circular reference detected")
425
+ markers[markerid] = dct
426
+ yield '{'
427
+ if _indent is not None:
428
+ _current_indent_level += 1
429
+ newline_indent = '\n' + (_indent * _current_indent_level)
430
+ item_separator = _item_separator + newline_indent
431
+ yield newline_indent
432
+ else:
433
+ newline_indent = None
434
+ item_separator = _item_separator
435
+ first = True
436
+ if _PY3:
437
+ iteritems = dct.items()
438
+ else:
439
+ iteritems = dct.iteritems()
440
+ if _item_sort_key:
441
+ items = []
442
+ for k, v in dct.items():
443
+ if not isinstance(k, string_types):
444
+ k = _stringify_key(k)
445
+ if k is None:
446
+ continue
447
+ items.append((k, v))
448
+ items.sort(key=_item_sort_key)
449
+ else:
450
+ items = iteritems
451
+ for key, value in items:
452
+ if not (_item_sort_key or isinstance(key, string_types)):
453
+ key = _stringify_key(key)
454
+ if key is None:
455
+ # _skipkeys must be True
456
+ continue
457
+ if first:
458
+ first = False
459
+ else:
460
+ yield item_separator
461
+ yield _encoder(key)
462
+ yield _key_separator
463
+
464
+ for chunk in _iterencode(value, _current_indent_level):
465
+ yield chunk
466
+
467
+ if newline_indent is not None:
468
+ _current_indent_level -= 1
469
+ yield '\n' + (_indent * _current_indent_level)
470
+ yield '}'
471
+ if markers is not None:
472
+ del markers[markerid]
473
+
474
+ def _iterencode(o, _current_indent_level):
475
+ if (isinstance(o, string_types) or
476
+ (_PY3 and isinstance(o, binary_type))):
477
+ yield _encoder(o)
478
+ elif o is None:
479
+ yield 'null'
480
+ elif o is True:
481
+ yield 'true'
482
+ elif o is False:
483
+ yield 'false'
484
+ elif isinstance(o, integer_types):
485
+ yield _encode_int(o)
486
+ elif isinstance(o, float):
487
+ yield _floatstr(o)
488
+ else:
489
+ for_json = _for_json and getattr(o, 'for_json', None)
490
+ if for_json and callable(for_json):
491
+ for chunk in _iterencode(for_json(), _current_indent_level):
492
+ yield chunk
493
+ elif isinstance(o, list):
494
+ for chunk in _iterencode_list(o, _current_indent_level):
495
+ yield chunk
496
+ else:
497
+ _asdict = _namedtuple_as_object and getattr(o, '_asdict', None)
498
+ if _asdict and callable(_asdict):
499
+ for chunk in _iterencode_dict(_asdict(), _current_indent_level):
500
+ yield chunk
501
+ elif (_tuple_as_array and isinstance(o, tuple)):
502
+ for chunk in _iterencode_list(o, _current_indent_level):
503
+ yield chunk
504
+ elif isinstance(o, dict):
505
+ for chunk in _iterencode_dict(o, _current_indent_level):
506
+ yield chunk
507
+ elif _use_decimal and isinstance(o, Decimal):
508
+ yield str(o)
509
+ else:
510
+ if markers is not None:
511
+ markerid = id(o)
512
+ if markerid in markers:
513
+ raise ValueError("Circular reference detected")
514
+ markers[markerid] = o
515
+ o = _default(o)
516
+ for chunk in _iterencode(o, _current_indent_level):
517
+ yield chunk
518
+ if markers is not None:
519
+ del markers[markerid]
520
+
521
+ return _iterencode
lib/python3.12/site-packages/hjson/encoderH.py ADDED
@@ -0,0 +1,552 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementation of HjsonEncoder
2
+ """
3
+ from __future__ import absolute_import
4
+ import re
5
+ from operator import itemgetter
6
+ from decimal import Decimal
7
+ from .compat import u, unichr, binary_type, string_types, integer_types, PY3
8
+ from .decoder import PosInf
9
+
10
+ # This is required because u() will mangle the string and ur'' isn't valid
11
+ # python3 syntax
12
+ ESCAPE = re.compile(u'[\\x00-\\x1f\\\\"\\b\\f\\n\\r\\t\u2028\u2029\uffff]')
13
+ ESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])')
14
+ HAS_UTF8 = re.compile(r'[\x80-\xff]')
15
+ ESCAPE_DCT = {
16
+ '\\': '\\\\',
17
+ '"': '\\"',
18
+ '\b': '\\b',
19
+ '\f': '\\f',
20
+ '\n': '\\n',
21
+ '\r': '\\r',
22
+ '\t': '\\t',
23
+ }
24
+ for i in range(0x20):
25
+ #ESCAPE_DCT.setdefault(chr(i), '\\u{0:04x}'.format(i))
26
+ ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,))
27
+ for i in [0x2028, 0x2029, 0xffff]:
28
+ ESCAPE_DCT.setdefault(unichr(i), '\\u%04x' % (i,))
29
+
30
+ COMMONRANGE=u'\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff'
31
+
32
+ # NEEDSESCAPE tests if the string can be written without escapes
33
+ NEEDSESCAPE = re.compile(u'[\\\"\x00-\x1f'+COMMONRANGE+']')
34
+ # NEEDSQUOTES tests if the string can be written as a quoteless string (like needsEscape but without \\ and \")
35
+ NEEDSQUOTES = re.compile(u'^\\s|^"|^\'|^#|^\\/\\*|^\\/\\/|^\\{|^\\}|^\\[|^\\]|^:|^,|\\s$|[\x00-\x1f'+COMMONRANGE+u']')
36
+ # NEEDSESCAPEML tests if the string can be written as a multiline string (like needsEscape but without \n, \r, \\, \", \t)
37
+ NEEDSESCAPEML = re.compile(u'\'\'\'|^[\\s]+$|[\x00-\x08\x0b\x0c\x0e-\x1f'+COMMONRANGE+u']')
38
+
39
+ WHITESPACE = ' \t\n\r'
40
+ STARTSWITHNUMBER = re.compile(r'^[\t ]*(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?\s*((,|\]|\}|#|\/\/|\/\*).*)?$');
41
+ STARTSWITHKEYWORD = re.compile(r'^(true|false|null)\s*((,|\]|\}|#|\/\/|\/\*).*)?$');
42
+ NEEDSESCAPENAME = re.compile(r'[,\{\[\}\]\s:#"\']|\/\/|\/\*|'+"'''")
43
+
44
+ FLOAT_REPR = repr
45
+
46
+ def encode_basestring(s, _PY3=PY3, _q=u('"')):
47
+ """Return a JSON representation of a Python string
48
+
49
+ """
50
+ if _PY3:
51
+ if isinstance(s, binary_type):
52
+ s = s.decode('utf-8')
53
+ else:
54
+ if isinstance(s, str) and HAS_UTF8.search(s) is not None:
55
+ s = s.decode('utf-8')
56
+ def replace(match):
57
+ return ESCAPE_DCT[match.group(0)]
58
+ return _q + ESCAPE.sub(replace, s) + _q
59
+
60
+
61
+ def encode_basestring_ascii(s, _PY3=PY3):
62
+ """Return an ASCII-only JSON representation of a Python string
63
+
64
+ """
65
+ if _PY3:
66
+ if isinstance(s, binary_type):
67
+ s = s.decode('utf-8')
68
+ else:
69
+ if isinstance(s, str) and HAS_UTF8.search(s) is not None:
70
+ s = s.decode('utf-8')
71
+ def replace(match):
72
+ s = match.group(0)
73
+ try:
74
+ return ESCAPE_DCT[s]
75
+ except KeyError:
76
+ n = ord(s)
77
+ if n < 0x10000:
78
+ #return '\\u{0:04x}'.format(n)
79
+ return '\\u%04x' % (n,)
80
+ else:
81
+ # surrogate pair
82
+ n -= 0x10000
83
+ s1 = 0xd800 | ((n >> 10) & 0x3ff)
84
+ s2 = 0xdc00 | (n & 0x3ff)
85
+ #return '\\u{0:04x}\\u{1:04x}'.format(s1, s2)
86
+ return '\\u%04x\\u%04x' % (s1, s2)
87
+ return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"'
88
+
89
+
90
+ class HjsonEncoder(object):
91
+ """Extensible JSON <http://json.org> encoder for Python data structures.
92
+
93
+ Supports the following objects and types by default:
94
+
95
+ +-------------------+---------------+
96
+ | Python | JSON |
97
+ +===================+===============+
98
+ | dict, namedtuple | object |
99
+ +-------------------+---------------+
100
+ | list, tuple | array |
101
+ +-------------------+---------------+
102
+ | str, unicode | string |
103
+ +-------------------+---------------+
104
+ | int, long, float | number |
105
+ +-------------------+---------------+
106
+ | True | true |
107
+ +-------------------+---------------+
108
+ | False | false |
109
+ +-------------------+---------------+
110
+ | None | null |
111
+ +-------------------+---------------+
112
+
113
+ To extend this to recognize other objects, subclass and implement a
114
+ ``.default()`` method with another method that returns a serializable
115
+ object for ``o`` if possible, otherwise it should call the superclass
116
+ implementation (to raise ``TypeError``).
117
+
118
+ """
119
+
120
+ def __init__(self, skipkeys=False, ensure_ascii=True,
121
+ check_circular=True, sort_keys=False,
122
+ indent=' ', encoding='utf-8', default=None,
123
+ use_decimal=True, namedtuple_as_object=True,
124
+ tuple_as_array=True, bigint_as_string=False,
125
+ item_sort_key=None, for_json=False,
126
+ int_as_string_bitcount=None):
127
+ """Constructor for HjsonEncoder, with sensible defaults.
128
+
129
+ If skipkeys is false, then it is a TypeError to attempt
130
+ encoding of keys that are not str, int, long, float or None. If
131
+ skipkeys is True, such items are simply skipped.
132
+
133
+ If ensure_ascii is true, the output is guaranteed to be str
134
+ objects with all incoming unicode characters escaped. If
135
+ ensure_ascii is false, the output will be unicode object.
136
+
137
+ If check_circular is true, then lists, dicts, and custom encoded
138
+ objects will be checked for circular references during encoding to
139
+ prevent an infinite recursion (which would cause an OverflowError).
140
+ Otherwise, no such check takes place.
141
+
142
+ If sort_keys is true, then the output of dictionaries will be
143
+ sorted by key; this is useful for regression tests to ensure
144
+ that JSON serializations can be compared on a day-to-day basis.
145
+
146
+ If indent is a string, then JSON array elements and object members
147
+ will be pretty-printed with a newline followed by that string repeated
148
+ for each level of nesting.
149
+
150
+ If specified, default is a function that gets called for objects
151
+ that can't otherwise be serialized. It should return a JSON encodable
152
+ version of the object or raise a ``TypeError``.
153
+
154
+ If encoding is not None, then all input strings will be
155
+ transformed into unicode using that encoding prior to JSON-encoding.
156
+ The default is UTF-8.
157
+
158
+ If use_decimal is true (not the default), ``decimal.Decimal`` will
159
+ be supported directly by the encoder. For the inverse, decode JSON
160
+ with ``parse_float=decimal.Decimal``.
161
+
162
+ If namedtuple_as_object is true (the default), objects with
163
+ ``_asdict()`` methods will be encoded as JSON objects.
164
+
165
+ If tuple_as_array is true (the default), tuple (and subclasses) will
166
+ be encoded as JSON arrays.
167
+
168
+ If bigint_as_string is true (not the default), ints 2**53 and higher
169
+ or lower than -2**53 will be encoded as strings. This is to avoid the
170
+ rounding that happens in Javascript otherwise.
171
+
172
+ If int_as_string_bitcount is a positive number (n), then int of size
173
+ greater than or equal to 2**n or lower than or equal to -2**n will be
174
+ encoded as strings.
175
+
176
+ If specified, item_sort_key is a callable used to sort the items in
177
+ each dictionary. This is useful if you want to sort items other than
178
+ in alphabetical order by key.
179
+
180
+ If for_json is true (not the default), objects with a ``for_json()``
181
+ method will use the return value of that method for encoding as JSON
182
+ instead of the object.
183
+
184
+ """
185
+
186
+ self.skipkeys = skipkeys
187
+ self.ensure_ascii = ensure_ascii
188
+ self.check_circular = check_circular
189
+ self.sort_keys = sort_keys
190
+ self.use_decimal = use_decimal
191
+ self.namedtuple_as_object = namedtuple_as_object
192
+ self.tuple_as_array = tuple_as_array
193
+ self.bigint_as_string = bigint_as_string
194
+ self.item_sort_key = item_sort_key
195
+ self.for_json = for_json
196
+ self.int_as_string_bitcount = int_as_string_bitcount
197
+ if indent is not None and not isinstance(indent, string_types):
198
+ indent = indent * ' '
199
+ elif indent is None:
200
+ indent = ' '
201
+ self.indent = indent
202
+ if default is not None:
203
+ self.default = default
204
+ self.encoding = encoding
205
+
206
+ def default(self, o):
207
+ """Implement this method in a subclass such that it returns
208
+ a serializable object for ``o``, or calls the base implementation
209
+ (to raise a ``TypeError``).
210
+
211
+ For example, to support arbitrary iterators, you could
212
+ implement default like this::
213
+
214
+ def default(self, o):
215
+ try:
216
+ iterable = iter(o)
217
+ except TypeError:
218
+ pass
219
+ else:
220
+ return list(iterable)
221
+ return HjsonEncoder.default(self, o)
222
+
223
+ """
224
+ raise TypeError(repr(o) + " is not JSON serializable")
225
+
226
+ def encode(self, o):
227
+ """Return a JSON string representation of a Python data structure.
228
+
229
+ >>> from hjson import HjsonEncoder
230
+ >>> HjsonEncoder().encode({"foo": ["bar", "baz"]})
231
+ '{"foo": ["bar", "baz"]}'
232
+
233
+ """
234
+ # This is for extremely simple cases and benchmarks.
235
+ if isinstance(o, binary_type):
236
+ _encoding = self.encoding
237
+ if (_encoding is not None and not (_encoding == 'utf-8')):
238
+ o = o.decode(_encoding)
239
+
240
+ # This doesn't pass the iterator directly to ''.join() because the
241
+ # exceptions aren't as detailed. The list call should be roughly
242
+ # equivalent to the PySequence_Fast that ''.join() would do.
243
+ chunks = self.iterencode(o, _one_shot=True)
244
+ if not isinstance(chunks, (list, tuple)):
245
+ chunks = list(chunks)
246
+ if self.ensure_ascii:
247
+ return ''.join(chunks)
248
+ else:
249
+ return u''.join(chunks)
250
+
251
+ def iterencode(self, o, _one_shot=False):
252
+ """Encode the given object and yield each string
253
+ representation as available.
254
+
255
+ For example::
256
+
257
+ for chunk in HjsonEncoder().iterencode(bigobject):
258
+ mysocket.write(chunk)
259
+
260
+ """
261
+ if self.check_circular:
262
+ markers = {}
263
+ else:
264
+ markers = None
265
+ if self.ensure_ascii:
266
+ _encoder = encode_basestring_ascii
267
+ else:
268
+ _encoder = encode_basestring
269
+ if self.encoding != 'utf-8':
270
+ def _encoder(o, _orig_encoder=_encoder, _encoding=self.encoding):
271
+ if isinstance(o, binary_type):
272
+ o = o.decode(_encoding)
273
+ return _orig_encoder(o)
274
+
275
+ def floatstr(o, _repr=FLOAT_REPR, _inf=PosInf, _neginf=-PosInf):
276
+ # Check for specials. Note that this type of test is processor
277
+ # and/or platform-specific, so do tests which don't depend on
278
+ # the internals.
279
+
280
+ if o != o or o == _inf or o == _neginf:
281
+ return 'null'
282
+ else:
283
+ return _repr(o)
284
+
285
+ key_memo = {}
286
+ int_as_string_bitcount = (
287
+ 53 if self.bigint_as_string else self.int_as_string_bitcount)
288
+ _iterencode = _make_iterencode(
289
+ markers, self.default, _encoder, self.indent, floatstr,
290
+ self.sort_keys, self.skipkeys, _one_shot, self.use_decimal,
291
+ self.namedtuple_as_object, self.tuple_as_array,
292
+ int_as_string_bitcount,
293
+ self.item_sort_key, self.encoding, self.for_json,
294
+ Decimal=Decimal)
295
+ try:
296
+ return _iterencode(o, 0, True)
297
+ finally:
298
+ key_memo.clear()
299
+
300
+
301
+ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
302
+ _sort_keys, _skipkeys, _one_shot,
303
+ _use_decimal, _namedtuple_as_object, _tuple_as_array,
304
+ _int_as_string_bitcount, _item_sort_key,
305
+ _encoding,_for_json,
306
+ ## HACK: hand-optimized bytecode; turn globals into locals
307
+ _PY3=PY3,
308
+ ValueError=ValueError,
309
+ string_types=string_types,
310
+ Decimal=Decimal,
311
+ dict=dict,
312
+ float=float,
313
+ id=id,
314
+ integer_types=integer_types,
315
+ isinstance=isinstance,
316
+ list=list,
317
+ str=str,
318
+ tuple=tuple,
319
+ ):
320
+ if _item_sort_key and not callable(_item_sort_key):
321
+ raise TypeError("item_sort_key must be None or callable")
322
+ elif _sort_keys and not _item_sort_key:
323
+ _item_sort_key = itemgetter(0)
324
+
325
+ if (_int_as_string_bitcount is not None and
326
+ (_int_as_string_bitcount <= 0 or
327
+ not isinstance(_int_as_string_bitcount, integer_types))):
328
+ raise TypeError("int_as_string_bitcount must be a positive integer")
329
+
330
+ def _encode_int(value):
331
+ return str(value)
332
+
333
+ def _stringify_key(key):
334
+ if isinstance(key, string_types): # pragma: no cover
335
+ pass
336
+ elif isinstance(key, binary_type):
337
+ key = key.decode(_encoding)
338
+ elif isinstance(key, float):
339
+ key = _floatstr(key)
340
+ elif key is True:
341
+ key = 'true'
342
+ elif key is False:
343
+ key = 'false'
344
+ elif key is None:
345
+ key = 'null'
346
+ elif isinstance(key, integer_types):
347
+ key = str(key)
348
+ elif _use_decimal and isinstance(key, Decimal):
349
+ key = str(key)
350
+ elif _skipkeys:
351
+ key = None
352
+ else:
353
+ raise TypeError("key " + repr(key) + " is not a string")
354
+ return key
355
+
356
+ def _encoder_key(name):
357
+ if not name: return '""'
358
+
359
+ # Check if we can insert this name without quotes
360
+ if NEEDSESCAPENAME.search(name):
361
+ return _encoder(name)
362
+ else:
363
+ # return without quotes
364
+ return name
365
+
366
+ def _encoder_str(str, _current_indent_level):
367
+ if not str: return '""'
368
+
369
+ # Check if we can insert this string without quotes
370
+ # see hjson syntax (must not parse as true, false, null or number)
371
+
372
+ first = str[0]
373
+ isNumber = False
374
+ if first == '-' or first >= '0' and first <= '9':
375
+ isNumber = STARTSWITHNUMBER.match(str) is not None
376
+
377
+ if (NEEDSQUOTES.search(str) or
378
+ isNumber or
379
+ STARTSWITHKEYWORD.match(str) is not None):
380
+
381
+ # If the string contains no control characters, no quote characters, and no
382
+ # backslash characters, then we can safely slap some quotes around it.
383
+ # Otherwise we first check if the string can be expressed in multiline
384
+ # format or we must replace the offending characters with safe escape
385
+ # sequences.
386
+
387
+ if not NEEDSESCAPE.search(str):
388
+ return '"' + str + '"'
389
+ elif not NEEDSESCAPEML.search(str):
390
+ return _encoder_str_ml(str, _current_indent_level + 1)
391
+ else:
392
+ return _encoder(str)
393
+ else:
394
+ # return without quotes
395
+ return str
396
+
397
+ def _encoder_str_ml(str, _current_indent_level):
398
+
399
+ a = str.replace('\r', '').split('\n')
400
+ # gap += indent;
401
+
402
+ if len(a) == 1:
403
+ # The string contains only a single line. We still use the multiline
404
+ # format as it avoids escaping the \ character (e.g. when used in a
405
+ # regex).
406
+ return "'''" + a[0] + "'''"
407
+ else:
408
+ gap = _indent * _current_indent_level
409
+ res = '\n' + gap + "'''"
410
+ for line in a:
411
+ res += '\n'
412
+ if line: res += gap + line
413
+ return res + '\n' + gap + "'''"
414
+
415
+ def _iterencode_dict(dct, _current_indent_level, _isRoot=False):
416
+ if not dct:
417
+ yield '{}'
418
+ return
419
+ if markers is not None:
420
+ markerid = id(dct)
421
+ if markerid in markers:
422
+ raise ValueError("Circular reference detected")
423
+ markers[markerid] = dct
424
+
425
+ if not _isRoot:
426
+ yield '\n' + (_indent * _current_indent_level)
427
+
428
+ _current_indent_level += 1
429
+ newline_indent = '\n' + (_indent * _current_indent_level)
430
+
431
+ yield '{'
432
+
433
+ if _PY3:
434
+ iteritems = dct.items()
435
+ else:
436
+ iteritems = dct.iteritems()
437
+ if _item_sort_key:
438
+ items = []
439
+ for k, v in dct.items():
440
+ if not isinstance(k, string_types):
441
+ k = _stringify_key(k)
442
+ if k is None:
443
+ continue
444
+ items.append((k, v))
445
+ items.sort(key=_item_sort_key)
446
+ else:
447
+ items = iteritems
448
+ for key, value in items:
449
+ if not (_item_sort_key or isinstance(key, string_types)):
450
+ key = _stringify_key(key)
451
+ if key is None:
452
+ # _skipkeys must be True
453
+ continue
454
+
455
+ yield newline_indent
456
+ yield _encoder_key(key)
457
+
458
+ first = True
459
+ for chunk in _iterencode(value, _current_indent_level):
460
+ if first:
461
+ first = False
462
+ if chunk[0 : 1] == '\n': yield ':'
463
+ else: yield ': '
464
+ yield chunk
465
+
466
+ if newline_indent is not None:
467
+ _current_indent_level -= 1
468
+ yield '\n' + (_indent * _current_indent_level)
469
+ yield '}'
470
+ if markers is not None:
471
+ del markers[markerid]
472
+
473
+
474
+ def _iterencode_list(lst, _current_indent_level, _isRoot=False):
475
+ if not lst:
476
+ yield '[]'
477
+ return
478
+ if markers is not None:
479
+ markerid = id(lst)
480
+ if markerid in markers:
481
+ raise ValueError("Circular reference detected")
482
+ markers[markerid] = lst
483
+
484
+ if not _isRoot:
485
+ yield '\n' + (_indent * _current_indent_level)
486
+
487
+ _current_indent_level += 1
488
+ newline_indent = '\n' + (_indent * _current_indent_level)
489
+ yield '['
490
+
491
+ for value in lst:
492
+ yield newline_indent
493
+
494
+ for chunk in _iterencode(value, _current_indent_level, True):
495
+ yield chunk
496
+
497
+ if newline_indent is not None:
498
+ _current_indent_level -= 1
499
+ yield '\n' + (_indent * _current_indent_level)
500
+ yield ']'
501
+ if markers is not None:
502
+ del markers[markerid]
503
+
504
+
505
+ def _iterencode(o, _current_indent_level, _isRoot=False):
506
+ if (isinstance(o, string_types) or
507
+ (_PY3 and isinstance(o, binary_type))):
508
+ yield _encoder_str(o, _current_indent_level)
509
+ elif o is None:
510
+ yield 'null'
511
+ elif o is True:
512
+ yield 'true'
513
+ elif o is False:
514
+ yield 'false'
515
+ elif isinstance(o, integer_types):
516
+ yield _encode_int(o)
517
+ elif isinstance(o, float):
518
+ yield _floatstr(o)
519
+ else:
520
+ for_json = _for_json and getattr(o, 'for_json', None)
521
+ if for_json and callable(for_json):
522
+ for chunk in _iterencode(for_json(), _current_indent_level, _isRoot):
523
+ yield chunk
524
+ elif isinstance(o, list):
525
+ for chunk in _iterencode_list(o, _current_indent_level, _isRoot):
526
+ yield chunk
527
+ else:
528
+ _asdict = _namedtuple_as_object and getattr(o, '_asdict', None)
529
+ if _asdict and callable(_asdict):
530
+ for chunk in _iterencode_dict(_asdict(), _current_indent_level, _isRoot):
531
+ yield chunk
532
+ elif (_tuple_as_array and isinstance(o, tuple)):
533
+ for chunk in _iterencode_list(o, _current_indent_level, _isRoot):
534
+ yield chunk
535
+ elif isinstance(o, dict):
536
+ for chunk in _iterencode_dict(o, _current_indent_level, _isRoot):
537
+ yield chunk
538
+ elif _use_decimal and isinstance(o, Decimal):
539
+ yield str(o)
540
+ else:
541
+ if markers is not None:
542
+ markerid = id(o)
543
+ if markerid in markers:
544
+ raise ValueError("Circular reference detected")
545
+ markers[markerid] = o
546
+ o = _default(o)
547
+ for chunk in _iterencode(o, _current_indent_level, _isRoot):
548
+ yield chunk
549
+ if markers is not None:
550
+ del markers[markerid]
551
+
552
+ return _iterencode
lib/python3.12/site-packages/hjson/ordered_dict.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Drop-in replacement for collections.OrderedDict by Raymond Hettinger
2
+
3
+ http://code.activestate.com/recipes/576693/
4
+
5
+ """
6
+ from UserDict import DictMixin
7
+
8
+ # Modified from original to support Python 2.4, see
9
+ # http://code.google.com/p/simplejson/issues/detail?id=53
10
+ try:
11
+ all
12
+ except NameError:
13
+ def all(seq):
14
+ for elem in seq:
15
+ if not elem:
16
+ return False
17
+ return True
18
+
19
+ class OrderedDict(dict, DictMixin):
20
+
21
+ def __init__(self, *args, **kwds):
22
+ if len(args) > 1:
23
+ raise TypeError('expected at most 1 arguments, got %d' % len(args))
24
+ try:
25
+ self.__end
26
+ except AttributeError:
27
+ self.clear()
28
+ self.update(*args, **kwds)
29
+
30
+ def clear(self):
31
+ self.__end = end = []
32
+ end += [None, end, end] # sentinel node for doubly linked list
33
+ self.__map = {} # key --> [key, prev, next]
34
+ dict.clear(self)
35
+
36
+ def __setitem__(self, key, value):
37
+ if key not in self:
38
+ end = self.__end
39
+ curr = end[1]
40
+ curr[2] = end[1] = self.__map[key] = [key, curr, end]
41
+ dict.__setitem__(self, key, value)
42
+
43
+ def __delitem__(self, key):
44
+ dict.__delitem__(self, key)
45
+ key, prev, next = self.__map.pop(key)
46
+ prev[2] = next
47
+ next[1] = prev
48
+
49
+ def __iter__(self):
50
+ end = self.__end
51
+ curr = end[2]
52
+ while curr is not end:
53
+ yield curr[0]
54
+ curr = curr[2]
55
+
56
+ def __reversed__(self):
57
+ end = self.__end
58
+ curr = end[1]
59
+ while curr is not end:
60
+ yield curr[0]
61
+ curr = curr[1]
62
+
63
+ def popitem(self, last=True):
64
+ if not self:
65
+ raise KeyError('dictionary is empty')
66
+ # Modified from original to support Python 2.4, see
67
+ # http://code.google.com/p/simplejson/issues/detail?id=53
68
+ if last:
69
+ key = reversed(self).next()
70
+ else:
71
+ key = iter(self).next()
72
+ value = self.pop(key)
73
+ return key, value
74
+
75
+ def __reduce__(self):
76
+ items = [[k, self[k]] for k in self]
77
+ tmp = self.__map, self.__end
78
+ del self.__map, self.__end
79
+ inst_dict = vars(self).copy()
80
+ self.__map, self.__end = tmp
81
+ if inst_dict:
82
+ return (self.__class__, (items,), inst_dict)
83
+ return self.__class__, (items,)
84
+
85
+ def keys(self):
86
+ return list(self)
87
+
88
+ setdefault = DictMixin.setdefault
89
+ update = DictMixin.update
90
+ pop = DictMixin.pop
91
+ values = DictMixin.values
92
+ items = DictMixin.items
93
+ iterkeys = DictMixin.iterkeys
94
+ itervalues = DictMixin.itervalues
95
+ iteritems = DictMixin.iteritems
96
+
97
+ def __repr__(self):
98
+ if not self:
99
+ return '%s()' % (self.__class__.__name__,)
100
+ return '%s(%r)' % (self.__class__.__name__, self.items())
101
+
102
+ def copy(self):
103
+ return self.__class__(self)
104
+
105
+ @classmethod
106
+ def fromkeys(cls, iterable, value=None):
107
+ d = cls()
108
+ for key in iterable:
109
+ d[key] = value
110
+ return d
111
+
112
+ def __eq__(self, other):
113
+ if isinstance(other, OrderedDict):
114
+ return len(self)==len(other) and \
115
+ all(p==q for p, q in zip(self.items(), other.items()))
116
+ return dict.__eq__(self, other)
117
+
118
+ def __ne__(self, other):
119
+ return not self == other
lib/python3.12/site-packages/hjson/scanner.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """JSON token scanner
2
+ """
3
+ import re
4
+
5
+ __all__ = ['HjsonDecodeError']
6
+
7
+ class HjsonDecodeError(ValueError):
8
+ """Subclass of ValueError with the following additional properties:
9
+
10
+ msg: The unformatted error message
11
+ doc: The JSON document being parsed
12
+ pos: The start index of doc where parsing failed
13
+ end: The end index of doc where parsing failed (may be None)
14
+ lineno: The line corresponding to pos
15
+ colno: The column corresponding to pos
16
+ endlineno: The line corresponding to end (may be None)
17
+ endcolno: The column corresponding to end (may be None)
18
+
19
+ """
20
+ # Note that this exception is used from _speedups
21
+ def __init__(self, msg, doc, pos, end=None):
22
+ ValueError.__init__(self, errmsg(msg, doc, pos, end=end))
23
+ self.msg = msg
24
+ self.doc = doc
25
+ self.pos = pos
26
+ self.end = end
27
+ self.lineno, self.colno = linecol(doc, pos)
28
+ if end is not None:
29
+ self.endlineno, self.endcolno = linecol(doc, end)
30
+ else:
31
+ self.endlineno, self.endcolno = None, None
32
+
33
+ def __reduce__(self):
34
+ return self.__class__, (self.msg, self.doc, self.pos, self.end)
35
+
36
+
37
+ def linecol(doc, pos):
38
+ lineno = doc.count('\n', 0, pos) + 1
39
+ if lineno == 1:
40
+ colno = pos + 1
41
+ else:
42
+ colno = pos - doc.rindex('\n', 0, pos)
43
+ return lineno, colno
44
+
45
+
46
+ def errmsg(msg, doc, pos, end=None):
47
+ lineno, colno = linecol(doc, pos)
48
+ msg = msg.replace('%r', repr(doc[pos:pos + 1]))
49
+ if end is None:
50
+ fmt = '%s: line %d column %d (char %d)'
51
+ return fmt % (msg, lineno, colno, pos)
52
+ endlineno, endcolno = linecol(doc, end)
53
+ fmt = '%s: line %d column %d - line %d column %d (char %d - %d)'
54
+ return fmt % (msg, lineno, colno, endlineno, endcolno, pos, end)
55
+
56
+
lib/python3.12/site-packages/hjson/tests/__init__.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import absolute_import
2
+ import unittest
3
+ import doctest
4
+ import sys
5
+
6
+
7
+ def additional_tests(suite=None):
8
+ import hjson
9
+ import hjson.encoder
10
+ import hjson.decoder
11
+ if suite is None:
12
+ suite = unittest.TestSuite()
13
+ for mod in (hjson, hjson.encoder, hjson.decoder):
14
+ suite.addTest(doctest.DocTestSuite(mod))
15
+ return suite
16
+
17
+
18
+ def all_tests_suite():
19
+ def get_suite():
20
+ return additional_tests(
21
+ unittest.TestLoader().loadTestsFromNames([
22
+ 'hjson.tests.test_hjson',
23
+ 'hjson.tests.test_bitsize_int_as_string',
24
+ 'hjson.tests.test_bigint_as_string',
25
+ 'hjson.tests.test_check_circular',
26
+ 'hjson.tests.test_decode',
27
+ 'hjson.tests.test_default',
28
+ 'hjson.tests.test_dump',
29
+ 'hjson.tests.test_encode_basestring_ascii',
30
+ 'hjson.tests.test_errors',
31
+ 'hjson.tests.test_fail',
32
+ 'hjson.tests.test_float',
33
+ 'hjson.tests.test_indent',
34
+ 'hjson.tests.test_pass1',
35
+ 'hjson.tests.test_pass2',
36
+ 'hjson.tests.test_pass3',
37
+ 'hjson.tests.test_recursion',
38
+ 'hjson.tests.test_scanstring',
39
+ 'hjson.tests.test_separators',
40
+ 'hjson.tests.test_unicode',
41
+ 'hjson.tests.test_decimal',
42
+ 'hjson.tests.test_tuple',
43
+ 'hjson.tests.test_namedtuple',
44
+ #'hjson.tests.test_tool', # fails on windows
45
+ 'hjson.tests.test_for_json',
46
+ ]))
47
+ suite = get_suite()
48
+ return suite
49
+
50
+
51
+ def main():
52
+ runner = unittest.TextTestRunner(verbosity=1 + sys.argv.count('-v'))
53
+ suite = all_tests_suite()
54
+ raise SystemExit(not runner.run(suite).wasSuccessful())
55
+
56
+
57
+ if __name__ == '__main__':
58
+ import os
59
+ import sys
60
+ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
61
+ main()
lib/python3.12/site-packages/hjson/tests/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (2.84 kB). View file
 
lib/python3.12/site-packages/hjson/tests/__pycache__/test_bigint_as_string.cpython-312.pyc ADDED
Binary file (3.23 kB). View file
 
lib/python3.12/site-packages/hjson/tests/__pycache__/test_bitsize_int_as_string.cpython-312.pyc ADDED
Binary file (3.78 kB). View file
 
lib/python3.12/site-packages/hjson/tests/__pycache__/test_check_circular.cpython-312.pyc ADDED
Binary file (2.41 kB). View file
 
lib/python3.12/site-packages/hjson/tests/__pycache__/test_decimal.cpython-312.pyc ADDED
Binary file (4.57 kB). View file
 
lib/python3.12/site-packages/hjson/tests/__pycache__/test_decode.cpython-312.pyc ADDED
Binary file (8.26 kB). View file
 
lib/python3.12/site-packages/hjson/tests/__pycache__/test_default.cpython-312.pyc ADDED
Binary file (819 Bytes). View file
 
lib/python3.12/site-packages/hjson/tests/__pycache__/test_dump.cpython-312.pyc ADDED
Binary file (8.24 kB). View file
 
lib/python3.12/site-packages/hjson/tests/__pycache__/test_encode_basestring_ascii.cpython-312.pyc ADDED
Binary file (2.49 kB). View file
 
lib/python3.12/site-packages/hjson/tests/__pycache__/test_errors.cpython-312.pyc ADDED
Binary file (3.49 kB). View file
 
lib/python3.12/site-packages/hjson/tests/__pycache__/test_fail.cpython-312.pyc ADDED
Binary file (4.02 kB). View file