@@ -26,8 +26,8 @@ structure using libraries like [attrs][].
2626 * The library has no dependencies of its own
2727 * It does not actually read or write JSON
2828
29- At the time of writing, the library is in ** alpha ** and the API may move around or be
30- renamed .
29+ At the time of writing, the library is in ** beta ** and the API is relatively stable but
30+ may change .
3131
3232### Supported types
3333
@@ -219,7 +219,7 @@ During encoding, the reverse sequence takes place:
219219
220220#### JSON type check hook
221221
222- Type checks are only used in ` json-syntax ` to support ` typing.Union ` ; in a nutshell, the
222+ Type checks are only used in _ json-syntax _ to support ` typing.Union ` ; in a nutshell, the
223223` unions ` rule will inspect some JSON to see which variant is present.
224224
225225If a type-check hook is not defined, ` __json_pre_decode__ ` will be called before the
@@ -249,9 +249,40 @@ encode_account = rules.lookup(typ=Union[AccountA, AccountB, AccountC],
249249
250250See [ the examples] [ ] for details on custom rules.
251251
252+ ### Debugging amibguous structures
253+
254+ (May need more docs and some test cases.)
255+
256+ As _ json-syntax_ tries to directly translate your Python types to JSON, it is possible
257+ to write ambiguous structures. To avoid this, there is a handy ` is_ambiguous ` method:
258+
259+ ``` python
260+ # This is true because both are represented as an array of numbers in JSON.
261+ rules.is_ambiguous(typ = Union[List[int ], Set[int ]])
262+
263+ @dataclass
264+ class Account :
265+ user: str
266+ address: str
267+
268+ # This is true because such a dictionary would always match the contents of the account.
269+ rules.is_ambiguous(typ = Union[Dict[str , str ], Account])
270+ ```
271+
272+ The aim of this is to let you put a check in your unit tests to make sure data can be
273+ reliably expressed given your particular case.
274+
275+ Internally, this is using the ` PATTERN ` verb to represent the JSON pattern, so this may
276+ be helpful in understanding how _ json-syntax_ is trying to represent your data:
277+
278+ ``` python
279+ print (rules.lookup(typ = MyAmbiguousClass, verb = ' show_pattern' ))
280+ ```
281+
252282### Sharp edges
253283
254- _ Alpha release status._ This API may change, there are probably bugs!
284+ _ Beta release status._ This API may change, there are probably bugs! In particular, the
285+ status of rules accepting subclasses is likely to change.
255286
256287_ The RuleSet caches encoders._ Construct a new ruleset if you want to change settings.
257288
@@ -265,28 +296,8 @@ _Everything to do with typing._ It's a bit magical and sort of wasn't designed f
265296[ We have a guide to it to try and help] [ types ] .
266297
267298_ Union types._ You can use ` typing.Union ` to allow a member to be one of some number of
268- alternates, but there are some caveats. These are documented in code in ` test_unions ` ,
269- but in plain English:
270-
271- When encoding Python to JSON:
272-
273- * ` Union[Super, Sub] ` will never match Sub when converting from Python to JSON.
274-
275- When decoding JSON to Python:
276-
277- * ` Union[str, Stringly] ` will never construct an instance that is represented as a
278- string in JSON.
279- * This includes enums, dates and special float values (` Nan ` , ` -inf ` , etc.) may be
280- represented as strings.
281- * ` Union[datetime, date] ` will never construct a date because ` YYYY-MM-DD ` is a valid
282- datetime according to ISO8601.
283- * ` Union[Dict[str, Value], MyAttrs] ` will never construct ` MyAttrs ` if all its
284- attributes are ` Value ` .
285- * ` Union[List[X], Set[X], FrozenSet[X], Tuple[X, ...]] ` will only ever construct
286- ` List[X] ` because all the others are also represented as JSON lists.
287- * ` Union[MyClassA, MyClassB, MyClassC] ` can be ambiguous if these classes all share
288- common fields. Consider using the ` __json_check__ ` hook to differentiate. Simply
289- adding a field named ` class ` or something can be unambiguous and fast.
299+ alternates, but there are some caveats. You should use the ` .is_ambiguous() ` method of
300+ RuleSet to warn you of these.
290301
291302_ Rules accept subclasses._ If you subclass ` int ` , the atoms rule will match it, and then
292303the converter will call ` int ` against your instance. I haven't taken the time to examine
@@ -306,7 +317,7 @@ This package is maintained via the [poetry][] tool. Some useful commands:
306317
307318 1 . Setup: ` poetry install `
308319 2 . Run tests: ` poetry run pytest tests/ `
309- 3 . Reformat: ` poetry run black -N json_syntax/ tests/ `
320+ 3 . Reformat: ` poetry run black json_syntax/ tests/ `
310321
311322### Setting up tox
312323
@@ -322,6 +333,10 @@ You'll want pyenv, then install the pythons:
322333
323334Once you install ` tox ` in your preferred python, running it is just ` tox ` .
324335
336+ (Caveat: ` poetry install ` is now breaking in ` tox ` because ` pip ` has changed: it now
337+ tries to create a dist in _ pip-wheel-metadata_ each time. I'm nuking that directory, but
338+ most likely there's some new config variable to hunt down.)
339+
325340### Notes
326341
327342<b id =" f1 " >1</b >: Writing the encoder is deceptively easy because the instances in
0 commit comments