From e9f00f232293895f17b64ac4229738e619ae7cd4 Mon Sep 17 00:00:00 2001 From: Brad Cowie Date: Thu, 16 Nov 2023 14:18:25 +1300 Subject: [PATCH 1/2] Import ruamel.yaml 0.18.5 source. --- .hgignore | 1 + .hgtags | 11 + .readthedocs.yaml | 16 +- CHANGES | 2263 +++++++++++++++++----------------- README.md | 396 ++++++ README.rst | 363 ------ __init__.py | 12 +- _doc/README.ryd | 120 ++ _doc/_static/pypi.svg | 2 +- _doc/api.ryd | 320 +++-- _doc/basicuse.ryd | 52 +- _doc/conf.py | 1 + _doc/contributing.ryd | 209 ++-- _doc/detail.ryd | 315 +++-- _doc/dumpcls.ryd | 260 +++- _doc/example.ryd | 125 +- _doc/index.ryd | 56 - _doc/install.ryd | 45 +- _doc/overview.ryd | 80 +- _doc/pyyaml.ryd | 100 +- _test/test_add_xxx.py | 18 +- _test/test_class_register.py | 7 +- _test/test_deprecation.py | 118 ++ _test/test_docinfo.py | 44 + _test/test_issues.py | 59 +- _test/test_yamlfile.py | 9 +- _test/test_yamlobject.py | 3 +- comments.py | 14 +- compat.py | 22 +- constructor.py | 13 +- docinfo.py | 67 + emitter.py | 33 +- main.py | 420 ++----- nodes.py | 1 + parser.py | 15 +- representer.py | 3 +- resolver.py | 1 + scanner.py | 12 +- setup.py | 38 +- tox.ini | 2 +- 40 files changed, 3090 insertions(+), 2556 deletions(-) create mode 100644 README.md delete mode 100644 README.rst create mode 100644 _doc/README.ryd delete mode 100644 _doc/index.ryd create mode 100644 _test/test_docinfo.py create mode 100644 docinfo.py diff --git a/.hgignore b/.hgignore index c305fec..4408f71 100644 --- a/.hgignore +++ b/.hgignore @@ -14,6 +14,7 @@ try_* _doc/*.pdf _doc/*.html _doc/*.rst +_doc/*.md *.py_alt ziglib diff --git a/.hgtags b/.hgtags index 925fdba..e4d13e3 100644 --- a/.hgtags +++ b/.hgtags @@ -220,3 +220,14 @@ b01b2f5c1ff21d561193de37b7e843baa2b91c91 0.17.31 e2d9ee085ae698c4dca733b83a718b9e4a6ec8c0 0.17.32 c4b4f7766d1845b67606fba5dd7d753e614417ea 0.17.33 31cd820ffa1ae47947343603617be8294d8f1657 0.17.34 +2088c8ea914f2626e8dc1da8ef7b43404c69a7ee 0.17.35 +c454afd9526435757eb797c6afedc6a308a139b7 0.17.36 +d8202d5a430253db5393dc52048db0f00fc8a595 0.17.37 +a255af9575de872dae9c19825beccd6f288a215a 0.17.38 +5ee159ab1327c416b94ffd065018c526e518e19b 0.17.39 +c87a704e4aeabc56009de61872b97db39f4d1a72 0.17.40 +3a3b56f6bf0a8944a399c58a9ca430330afadbe3 0.18.0 +c0da0ba934877fdfe63bee77ec12a7d2341f5398 0.18.1 +a35908655d678b8463ee6198869a0708b3446e06 0.18.2 +e32fbfcda1a48d808542670d91f1e84d14f69956 0.18.3 +08d87cada1f6e5fedde079b55536061e4fe246a0 0.18.4 diff --git a/.readthedocs.yaml b/.readthedocs.yaml index e6fdcb4..5662c98 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,13 +1,19 @@ version: 2 -sphinx: - configuration: _doc/conf.py - -formats: [epub, pdf] +build: + os: ubuntu-22.04 + tools: + python: "3.11" + jobs: + pre_build: + - pip install ryd>=0.8.2 + - ryd convert --generate-mkdocs-config mkdocs.yaml _doc python: - version: 3.7 install: - method: pip path: . extra_requirements: [docs] + +mkdocs: + configuration: mkdocs.yaml diff --git a/CHANGES b/CHANGES index bfde04b..2fc13eb 100644 --- a/CHANGES +++ b/CHANGES @@ -1,1175 +1,1193 @@ -[0, 17, 35]: 2023-10-04 - - support for loading dataclasses with ``InitVar`` variables (some - special coding was necessary to get the, unexecpected, default value - in the corresponding instance attribute ( example of usage in - `this question `__ ) - -[0, 17, 34]: 2023-10-03 - - Python 3.12 also loads C version when using `typ='safe'` - - initial support for loading invoking `__post_init__()` on dataclasses that have that method - after loading a registered dataclass (`@yaml.register_class\n@dataclass\nclass ...`). - (Originally `asked `__ on Stackoverflow by - `nyanpasu64 `__ and as - `ticket `__ - by `Patrick Lehmann `__ - -[0, 17, 33]: 2023-09-28 - - added `flow_seq_start`, `flow_seq_end`, `flow_seq_separator`, `flow_map_start`, `flow_map_end`, - `flow_map_separator` **class** attributes to the `Emitter` class so flow style output - can more easily be influenced (based on `this answer `__ - on a StackOverflow question by `Huw Walters `__). - -[0, 17, 32]: 2023-06-17 - - fix issue with scanner getting stuck in infinite loop - -[0, 17, 31]: 2023-05-31 - - added tag.setter on `ScalarEvent` and on `Node`, that takes either - a `Tag` instance, or a str - (reported by `Sorin Sbarnea `__) - -[0, 17, 30]: 2023-05-30 - - fix issue 467, caused by Tag instances not being hashable (reported by - `Douglas Raillard - `__) - -[0, 17, 29]: 2023-05-30 - - changed the internals of the tag property from a string to a class which allows - for preservation of the original handle and suffix. This should - result in better results using documents with %TAG directives, as well - as preserving URI escapes in tag suffixes. - -[0, 17, 28]: 2023-05-26 - - fix for issue 464: documents ending with document end marker without final newline - fail to load (reported by `Mariusz Rusiniak `__) - -[0, 17, 27]: 2023-05-25 - - fix issue with inline mappings as value for merge keys - (reported by Sirish on `StackOverflow `__) - - fix for 468, error inserting after accessing merge attribute on ``CommentedMap`` - (reported by `Bastien gerard `__) - - fix for issue 461 pop + insert on same `CommentedMap` key throwing error - (reported by `John Thorvald Wodder II `__) - -[0, 17, 26]: 2023-05-09 - - Fix for error on edge cage for issue 459 - -[0, 17, 25]: 2023-05-09 - - fix for regression while dumping wrapped strings with too many backslashes removed - (issue 459, reported by `Lele Gaifax `__) - -[0, 17, 24]: 2023-05-06 - - rewrite of ``CommentedMap.insert()``. If you have a merge key in - the YAML document for the mapping you insert to, the position value should - be the one as you look at the YAML input. - This fixes issue 453 where other - keys of a merged in mapping would show up after an insert (reported by - `Alex Miller `__). It - also fixes a call to `.insert()` resulting into the merge key to move - to be the first key if it wasn't already and it is also now possible - to insert a key before a merge key (even if the fist key in the mapping). - - fix (in the pure Python implementation including default) for issue 447. - (reported by `Jack Cherng `__, - also brought up by brent on - `StackOverflow `__) - -[0, 17, 23]: 2023-05-05 - - fix 458, error on plain scalars starting with word longer than width. - (reported by `Kyle Larose `__) - - fix for ``.update()`` no longer correctly handling keyword arguments - (reported by John Lin on `__) - - fix issue 454: high Unicode (emojis) in quoted strings always - escaped (reported by `Michal Čihař `__ - based on a question on StackOverflow). - - fix issue with emitter conservatively inserting extra backslashes in wrapped - quoted strings (reported by thebenman on `StackOverflow - `__) - -[0, 17, 22]: 2023-05-02 - - - fix issue 449 where the second exclamation marks got URL encoded (reported - and fixing PR provided by `John Stark `__) - - fix issue with indent != 2 and literal scalars with empty first line - (reported by wrdis on `StackOverflow `__) - - updated __repr__ of CommentedMap, now that Python's dict is ordered -> no more - ordereddict(list-of-tuples) - - merge MR 4, handling OctalInt in YAML 1.1 - (provided by `Jacob Floyd `_) - - fix loading of `!!float 42` (reported by Eric on - `Stack overflow `_) - - line numbers are now set on `CommentedKeySeq` and `CommentedKeyMap` (which - are created if you have a sequence resp. mapping as the key in a mapping) - - plain scalars: put single words longer than width on a line of their own, instead - of after the previous line (issue 427, reported by `Antoine Cotten - `_). Caveat: this currently results in a - space ending the previous line. - - fix for folded scalar part of 421: comments after ">" on first line of folded - scalars are now preserved (as were those in the same position on literal scalars). - Issue reported by Jacob Floyd. - - added stacklevel to warnings - - typing changed from Py2 compatible comments to Py3, removed various Py2-isms - -[0, 17, 21]: 2022-02-12 - - fix bug in calling `.compose()` method with `pathlib.Path` instance. - -[0, 17, 20]: today - - fix error in microseconds while rounding datetime fractions >= 9999995 - (reported by `Luis Ferreira `__) - -[0, 17, 19]: 2021-12-26 - - fix mypy problems (reported by `Arun `__) - -[0, 17, 18]: 2021-12-24 - - copy-paste error in folded scalar comment attachment (reported by `Stephan Geulette - `__) - - fix 411, indent error comment between key empty seq value (reported by `Guillermo Julián - `__) - -[0, 17, 17]: 2021-10-31 - - extract timestamp matching/creation to util - -[0, 17, 16]: 2021-08-28 - - also handle issue 397 when comment is newline - -[0, 17, 15]: 2021-08-28 - - fix issue 397, insert comment before key when a comment between key and value exists - (reported by `Bastien gerard `__) - -[0, 17, 14]: 2021-08-25 - - fix issue 396, inserting key/val in merged-in dictionary (reported by `Bastien gerard - `__) - -[0, 17, 13]: 2021-08-21 - - minor fix in attr handling - -[0, 17, 12]: 2021-08-21 - - fix issue with anchor on registered class not preserved and those classes using package - attrs with `@attr.s()` (both reported by `ssph `__) - -[0, 17, 11]: 2021-08-19 - - fix error baseclass for ``DuplicateKeyErorr`` (reported by `Łukasz Rogalski - `__) - - fix typo in reader error message, causing `KeyError` during reader error - (reported by `MTU `__) - -[0, 17, 10]: 2021-06-24 - - fix issue 388, token with old comment structure != two elements - (reported by `Dimitrios Bariamis `__) - -[0, 17, 9]: 2021-06-10 - - fix issue with updating CommentedMap (reported by sri on - `StackOverlow `__) - -[0, 17, 8]: 2021-06-09 - - fix for issue 387 where templated anchors on tagged object did get set - resulting in potential id reuse. (reported by `Artem Ploujnikov - `__) - -[0, 17, 7]: 2021-05-31 - - issue 385 also affected other deprecated loaders (reported via email - by Oren Watson) - -[0, 17, 6]: 2021-05-31 - - merged type annotations update provided by - `Jochen Sprickerhof `__ - - fix for issue 385: deprecated round_trip_loader function not working - (reported by `Mike Gouline `__) - - wasted a few hours getting rid of mypy warnings/errors - -[0, 17, 5]: 2021-05-30 - - fix for issue 384 !!set with aliased entry resulting in broken YAML on rt - reported by `William Kimball `__) - -[0, 17, 4]: 2021-04-07 - - prevent (empty) comments from throwing assertion error (issue 351 - reported by `William Kimball `__) - comments (or empty line) will be dropped - -[0, 17, 3]: 2021-04-07 - - fix for issue 382 caused by an error in a format string (reported by - `William Kimball `__) - - allow expansion of aliases by setting ``yaml.composer.return_alias = lambda s: copy.deepcopy(s)`` - (as per `Stackoverflow answer `__) - -[0, 17, 2]: 2021-03-29 - - change -py2.py3-none-any.whl to -py3-none-any.whl, and remove 0.17.1 - -[0, 17, 1]: 2021-03-29 - - added 'Programming Language :: Python :: 3 :: Only', and removing - 0.17.0 from PyPI (reported by `Alasdair Nicol `__) - -[0, 17, 0]: 2021-03-26 - - this release no longer supports Python 2.7, most if not all Python 2 - specific code is removed. The 0.17.x series is the last to support Python 3.5 - (this also allowed for removal of the dependency on ``ruamel.std.pathlib``) - - remove Python2 specific code branches and adaptations (u-strings) - - prepare % code for f-strings using ``_F`` - - allow PyOxidisation (`issue 324 `__ - resp. `issue 171 `__) - - replaced Python 2 compatible enforcement of keyword arguments with '*' - - the old top level *functions* ``load``, ``safe_load``, ``round_trip_load``, - ``dump``, ``safe_dump``, ``round_trip_dump``, ``scan``, ``parse``, - ``compose``, ``emit``, ``serialize`` as well as their ``_all`` variants for - multi-document streams, now issue a ``PendingDeprecationning`` (e.g. when run - from pytest, but also Python is started with ``-Wd``). Use the methods on - ``YAML()``, which have been extended. - - fix for issue 376: indentation changes could put literal/folded scalar to start - before the ``#`` column of a following comment. Effectively making the comment - part of the scalar in the output. (reported by - `Bence Nagy `__) - - -[0, 16, 13]: 2021-03-05 - - fix for issue 359: could not update() CommentedMap with keyword arguments - (reported by `Steve Franchak `__) - - fix for issue 365: unable to dump mutated TimeStamp objects - (reported by Anton Akmerov `__) - - fix for issue 371: unable to addd comment without starting space - (reported by 'Mark Grandi `__) - - fix for issue 373: recursive call to walk_tree not preserving all params - (reported by `eulores `__) - - a None value in a flow-style sequence is now dumped as `null` instead - of `!!null ''` (reported by mcarans on - `StackOverlow `__) - -[0, 16, 12]: 2020-09-04 - - update links in doc - -[0, 16, 11]: 2020-09-03 - - workaround issue with setuptools 0.50 and importing pip ( fix by jaraco - https://github.com/pypa/setuptools/issues/2355#issuecomment-685159580 ) - -[0, 16, 10]: 2020-02-12 - - (auto) updated image references in README to sourceforge - -[0, 16, 9]: 2020-02-11 - - update CHANGES - -[0, 16, 8]: 2020-02-11 - - update requirements so that ruamel.yaml.clib is installed for 3.8, - as it has become available (via manylinux builds) - -[0, 16, 7]: 2020-01-30 - - fix typchecking issue on TaggedScalar (reported by Jens Nielsen) - - fix error in dumping literal scalar in sequence with comments before element - (reported by `EJ Etherington `__) - -[0, 16, 6]: 2020-01-20 - - fix empty string mapping key roundtripping with preservation of quotes as `? ''` - (reported via email by Tomer Aharoni). - - fix incorrect state setting in class constructor (reported by `Douglas Raillard - `__) - - adjust deprecation warning test for Hashable, as that no longer warns (reported - by `Jason Montleon `__) - -[0, 16, 5]: 2019-08-18 - - allow for ``YAML(typ=['unsafe', 'pytypes'])`` - -[0, 16, 4]: 2019-08-16 - - fix output of TAG directives with # (reported by `Thomas Smith - `__) - - -[0, 16, 3]: 2019-08-15 - - move setting of version based on YAML directive to scanner, allowing to - check for file version during TAG directive scanning - -[0, 16, 2]: 2019-08-15 - - preserve YAML and TAG directives on roundtrip, correctly output # - in URL for YAML 1.2 (both reported by `Thomas Smith - `__) - -[0, 16, 1]: 2019-08-08 - - Force the use of new version of ruamel.yaml.clib (reported by `Alex Joz - `__) - - Allow '#' in tag URI as these are allowed in YAML 1.2 (reported by - `Thomas Smith - `__) - -[0, 16, 0]: 2019-07-25 - - split of C source that generates .so file to ruamel.yaml.clib - - duplicate keys are now an error when working with the old API as well - -[0, 15, 100]: 2019-07-17 - - fixing issue with dumping deep-copied data from commented YAML, by - providing both the memo parameter to __deepcopy__, and by allowing - startmarks to be compared on their content (reported by `Theofilos - Petsios - `__) - -[0, 15, 99]: 2019-07-12 - - add `py.typed` to distribution, based on a PR submitted by - `Michael Crusoe - `__ - - merge PR 40 (also by Michael Crusoe) to more accurately specify - repository in the README (also reported in a misunderstood issue - some time ago) - -[0, 15, 98]: 2019-07-09 - - regenerate ext/_ruamel_yaml.c with Cython version 0.29.12, needed - for Python 3.8.0b2 (reported by `John Vandenberg - `__) - -[0, 15, 97]: 2019-06-06 - - regenerate ext/_ruamel_yaml.c with Cython version 0.29.10, needed for - Python 3.8.0b1 - - regenerate ext/_ruamel_yaml.c with Cython version 0.29.9, needed for - Python 3.8.0a4 (reported by `Anthony Sottile - `__) - -[0, 15, 96]: 2019-05-16 - - fix failure to indent comments on round-trip anchored block style - scalars in block sequence (reported by `William Kimball - `__) - -[0, 15, 95]: 2019-05-16 - - fix failure to round-trip anchored scalars in block sequence - (reported by `William Kimball - `__) - - wheel files for Python 3.4 no longer provided (`Python 3.4 EOL 2019-03-18 - `__) - -[0, 15, 94]: 2019-04-23 - - fix missing line-break after end-of-file comments not ending in - line-break (reported by `Philip Thompson - `__) - -[0, 15, 93]: 2019-04-21 - - fix failure to parse empty implicit flow mapping key - - in YAML 1.1 plains scalars `y`, 'n', `Y`, and 'N' are now - correctly recognised as booleans and such strings dumped quoted - (reported by `Marcel Bollmann - `__) - -[0, 15, 92]: 2019-04-16 - - fix failure to parse empty implicit block mapping key (reported by - `Nolan W `__) - -[0, 15, 91]: 2019-04-05 - - allowing duplicate keys would not work for merge keys (reported by mamacdon on - `StackOverflow `__ - -[0, 15, 90]: 2019-04-04 - - fix issue with updating `CommentedMap` from list of tuples (reported by - `Peter Henry `__) - -[0, 15, 89]: 2019-02-27 - - fix for items with flow-mapping in block sequence output on single line - (reported by `Zahari Dim `__) - - fix for safe dumping erroring in creation of representereror when dumping namedtuple - (reported and solution by `Jaakko Kantojärvi `__) - -[0, 15, 88]: 2019-02-12 - - fix inclusing of python code from the subpackage data (containing extra tests, - reported by `Florian Apolloner `__) - -[0, 15, 87]: 2019-01-22 - - fix problem with empty lists and the code to reinsert merge keys (reported via email - by Zaloo) - -[0, 15, 86]: 2019-01-16 - - reinsert merge key in its old position (reported by grumbler on - `__) - - fix for issue with non-ASCII anchor names (reported and fix - provided by Dandaleon Flux via email) - - fix for issue when parsing flow mapping value starting with colon (in pure Python only) - (reported by `FichteFoll `__) - -[0, 15, 85]: 2019-01-08 - - the types used by `SafeConstructor` for mappings and sequences can - now by set by assigning to `XXXConstructor.yaml_base_dict_type` - (and `..._list_type`), preventing the need to copy two methods - with 50+ lines that had `var = {}` hardcoded. (Implemented to - help solve an feature request by `Anthony Sottile - `__ in an easier way) - -[0, 15, 84]: 2019-01-07 - - fix for `CommentedMap.copy()` not returning `CommentedMap`, let alone copying comments etc. - (reported by `Anthony Sottile `__) - -[0, 15, 83]: 2019-01-02 - - fix for bug in roundtripping aliases used as key (reported via email by Zaloo) - -[0, 15, 82]: 2018-12-28 - - anchors and aliases on scalar int, float, string and bool are now preserved. Anchors - do not need a referring alias for these (reported by - `Alex Harvey `__) - - anchors no longer lost on tagged objects when roundtripping (reported by `Zaloo - `__) - -[0, 15, 81]: 2018-12-06 - - fix issue saving methods of metaclass derived classes (reported and fix provided - by `Douglas Raillard `__) - -[0, 15, 80]: 2018-11-26 - - fix issue emitting BEL character when round-tripping invalid folded input - (reported by Isaac on `StackOverflow `__) - -[0, 15, 79]: 2018-11-21 - - fix issue with anchors nested deeper than alias (reported by gaFF on - `StackOverflow `__) - -[0, 15, 78]: 2018-11-15 - - fix setup issue for 3.8 (reported by `Sidney Kuyateh - `__) - -[0, 15, 77]: 2018-11-09 - - setting `yaml.sort_base_mapping_type_on_output = False`, will prevent - explicit sorting by keys in the base representer of mappings. Roundtrip - already did not do this. Usage only makes real sense for Python 3.6+ - (feature request by `Sebastian Gerber `__). - - implement Python version check in YAML metadata in ``_test/test_z_data.py`` - -[0, 15, 76]: 2018-11-01 - - fix issue with empty mapping and sequence loaded as flow-style - (mapping reported by `Min RK `__, sequence - by `Maged Ahmed `__) - -[0, 15, 75]: 2018-10-27 - - fix issue with single '?' scalar (reported by `Terrance - `__) - - fix issue with duplicate merge keys (prompted by `answering - `__ a - `StackOverflow question `__ - by `math `__) - -[0, 15, 74]: 2018-10-17 - - fix dropping of comment on rt before sequence item that is sequence item - (reported by `Thorsten Kampe `__) - -[0, 15, 73]: 2018-10-16 - - fix irregular output on pre-comment in sequence within sequence (reported - by `Thorsten Kampe `__) - - allow non-compact (i.e. next line) dumping sequence/mapping within sequence. - -[0, 15, 72]: 2018-10-06 - - fix regression on explicit 1.1 loading with the C based scanner/parser - (reported by `Tomas Vavra `__) - -[0, 15, 71]: 2018-09-26 - - fix regression where handcrafted CommentedMaps could not be initiated (reported by - `Dan Helfman `__) - - fix regression with non-root literal scalars that needed indent indicator - (reported by `Clark Breyman `__) - - tag:yaml.org,2002:python/object/apply now also uses __qualname__ on PY3 - (reported by `Douglas RAILLARD `__) - -[0, 15, 70]: 2018-09-21 - - reverted CommentedMap and CommentedSeq to subclass ordereddict resp. list, - reimplemented merge maps so that both ``dict(**commented_map_instance)`` and JSON - dumping works. This also allows checking with ``isinstance()`` on ``dict`` resp. ``list``. - (Proposed by `Stuart Berg `__, with feedback - from `blhsing `__ on - `StackOverflow `__) - -[0, 15, 69]: 2018-09-20 - - fix issue with dump_all gobbling end-of-document comments on parsing - (reported by `Pierre B. `__) - -[0, 15, 68]: 2018-09-20 - - fix issue with parsabel, but incorrect output with nested flow-style sequences - (reported by `Dougal Seeley `__) - - fix issue with loading Python objects that have __setstate__ and recursion in parameters - (reported by `Douglas RAILLARD `__) - -[0, 15, 67]: 2018-09-19 - - fix issue with extra space inserted with non-root literal strings - (Issue reported and PR with fix provided by - `Naomi Seyfer `__.) - -[0, 15, 66]: 2018-09-07 - - fix issue with fold indicating characters inserted in safe_load-ed folded strings - (reported by `Maximilian Hils `__). - -[0, 15, 65]: 2018-09-07 - - fix issue #232 revert to throw ParserError for unexcpected ``]`` - and ``}`` instead of IndexError. (Issue reported and PR with fix - provided by `Naomi Seyfer `__.) - - added ``key`` and ``reverse`` parameter (suggested by Jannik Klemm via email) - - indent root level literal scalars that have directive or document end markers - at the beginning of a line - -[0, 15, 64]: 2018-08-30 - - support round-trip of tagged sequences: ``!Arg [a, {b: 1}]`` - - single entry mappings in flow sequences now written by default without quotes - set ``yaml.brace_single_entry_mapping_in_flow_sequence=True`` to force - getting ``[a, {b: 1}, {c: {d: 2}}]`` instead of the default ``[a, b: 1, c: {d: 2}]`` - - fix issue when roundtripping floats starting with a dot such as ``.5`` - (reported by `Harrison Gregg `__) - -[0, 15, 63]: 2018-08-29 - - small fix only necessary for Windows users that don't use wheels. - -[0, 15, 62]: 2018-08-29 - - C based reader/scanner & emitter now allow setting of 1.2 as YAML version. - ** The loading/dumping is still YAML 1.1 code**, so use the common subset of - YAML 1.2 and 1.1 (reported by `Ge Yang `__) - -[0, 15, 61]: 2018-08-23 - - support for round-tripping folded style scalars (initially requested - by `Johnathan Viduchinsky `__) - - update of C code - - speed up of scanning (~30% depending on the input) - -[0, 15, 60]: 2018-08-18 - - cleanup for mypy - - spurious print in library (reported by - `Lele Gaifax `__), now automatically checked - -[0, 15, 59]: 2018-08-17 - - issue with C based loader and leading zeros (reported by - `Tom Hamilton Stubber `__) - -[0, 15, 58]: 2018-08-17 - - simple mappings can now be used as keys when round-tripping:: - - {a: 1, b: 2}: hello world +[0.18.5, 2023-11-03]: +- there is some indication that dependent packages have been pinned to use specific + (tested) and just install the latest even in Python versions that have end-of-life + +[0.18.4, 2023-11-01]: +- YAML() instance has a `doc_infos` attribute which is a cumulative list of DocInfo + instances (one for `load()`, one per document for `load_all()`). DocInfo instances + contain version information (requested, directive) and tag directive information +- fix issue that the YAML instance tags attribute was not reset between documents, + resulting in mixing of tag directives of multiple documents. Now only provides tag + directive information on latest document after loading. This means tags for dumping + must be set **again** after a document is loaded with the same instance. (because + of this tags will be removed in a favour of a different mechanism in the future) +- fix issue with multiple document intermixing YAML 1.2 and YAML 1.1, the VersionedResolver + now resets +- fix issue with disappearing comment when next token was Tag (still can't have both + a comment before a tag and after a tag, before node) + +[0.18.3, 2023-10-29]: +- fix issue with spurious newline on first item after comment + nested block sequence +- additional links in the metadata on PyPI (Reported, with pointers how to fix, by + [Sorin](https://sourceforge.net/u/ssbarnea/profile/)). + +[0.18.2, 2023-10-24]: +- calling the deprecated functions now raises an `AttributeError` with the, somewhat + more informative, orginal warning message. Instead of calling `sys.exit(1)` + +[0.18.1, 2023-10-24]: +- calling the deprecated functions now always displays the warning message. (reported + by [Trend Lloyd](https://sourceforge.net/u/lathiat2/profile/)) + +[0.18.0, 2023-10-23]: +- the **functions** `scan`, `parse`, `compose`, `load`, `emit`, `serialize`, `dump` + and their variants (`_all`, `safe_`, `round_trip_`, etc) have been deprecated (the + same named **methods** on `YAML()` instances are, of course, still there. +- |- + `YAML(typ='unsafe')` now issues a `PendingDeprecationWarning`. This will become deprecated in the 0.18 series + (probably before the end of 2023). + You can use `YAML(typ='full')` to dump unregistered Python classes/functions. + For loading you'll have to register your classes/functions + if you want the old, unsafe, functionality. You can still load any tag, like `!!python/name:posix.system', **safely** + with the (default) round-trip parser. +- fix for `bytes-like object is required not 'str' while dumping binary streams`. + This was reported, analysed and a fix provided by [Vit Zikmund](https://sourceforge.net/u/tlwhitec/profile/) + +[0.17.40, 2023-10-20]: +- flow style sets are now preserved ( `!!set {a, b, c} )`. Any values specified when + loading are dropped, including `!!null ""`. +- |- + potential workaround for issue 484: the long_description_content_type including the variant specification `CommonMark` + can result in problems on Azure. If you can install from `.tar.gz` using + `RUAMEL_NO_LONG_DESCRIPTION=1 pip install ruamel.yaml --no-binary :all:` then the long description, and its + offending type, are nog included (in the METADATA). + (Reported by [Coury Ditch](https://sourceforge.net/u/cmditch/profile/)) +- links in documentation update (reported by [David Hoese](https://sourceforge.net/u/daveydave400/profile/)) +- Added some `__repr__` for internally used classes + +[0.17.39, 2023-10-19]: +- update README generation, no code changes + +[0.17.36, 2023-10-19]: +- fixed issue 480, dumping of a loaded empty flow-style mapping with comment failed + (Reported by [Stéphane Brunner](https://sourceforge.net/u/stbrunner/profile/)) +- fixed issue 482, caused by DEFAULT_MAPPING_TAG having changes to being a `Tag()` + instance, not a string (reported by [yan12125](https://sourceforge.net/u/yan12125/profile/)) +- updated documentation to use mkdocs + +[0.17.35, 2023-10-04]: +- support for loading dataclasses with `InitVar` variables (some special coding was + necessary to get the, unexecpected, default value in the corresponding instance + attribute ( example of usage in [this question](https://stackoverflow.com/q/77228378/1307905)) + +[0.17.34, 2023-10-03]: +- Python 3.12 also loads C version when using `typ='safe'` +- |- + initial support for loading invoking + `__post_init__()` on dataclasses that have that + method after loading a registered dataclass. + (Originally + [asked](https://stackoverflow.com/q/51529458/1307905) on + Stackoverflow by + [nyanpasu64](https://stackoverflow.com/users/2683842/nyanpasu64) + and as + [ticket](https://sourceforge.net/p/ruamel-yaml/tickets/355/) by + [Patrick Lehmann](https://sourceforge.net/u/paebbels/profile/)) + + ``` + @yaml.register_class + @dataclass + class ... + ``` + + +[0.17.33, 2023-09-28]: +- added `flow_seq_start`, `flow_seq_end`, `flow_seq_separator`, `flow_map_start`, + `flow_map_end`, `flow_map_separator` **class** attributes to the `Emitter` class + so flow style output can more easily be influenced (based on [this answer](https://stackoverflow.com/a/76547814/1307905) + on a StackOverflow question by [Huw Walters](https://stackoverflow.com/users/291033/huw-walters)). + +[0.17.32, 2023-06-17]: +- fix issue with scanner getting stuck in infinite loop + +[0.17.31, 2023-05-31]: +- added tag.setter on `ScalarEvent` and on `Node`, that takes either a `Tag` instance, + or a str (reported by [Sorin Sbarnea](https://sourceforge.net/u/ssbarnea/profile/)) + +[0.17.30, 2023-05-30]: +- fix issue 467, caused by Tag instances not being hashable (reported by [Douglas + Raillard](https://bitbucket.org/%7Bcf052d92-a278-4339-9aa8-de41923bb556%7D/)) + +[0.17.29, 2023-05-30]: +- changed the internals of the tag property from a string to a class which allows + for preservation of the original handle and suffix. This should result in better + results using documents with %TAG directives, as well as preserving URI escapes + in tag suffixes. + +[0.17.28, 2023-05-26]: +- |- + fix for issue 464: documents ending with document end marker + without final newline fail to load (reported by [Mariusz + Rusiniak](https://sourceforge.net/u/r2dan/profile/)) + +[0.17.27, 2023-05-25]: +- fix issue with inline mappings as value for merge keys (reported by Sirish on [StackOverflow](https://stackoverflow.com/q/76331049/1307905)) +- fix for 468, error inserting after accessing merge attribute on `CommentedMap` (reported + by [Bastien gerard](https://sourceforge.net/u/bagerard/)) +- fix for issue 461 pop + insert on same `CommentedMap` key throwing error (reported + by [John Thorvald Wodder II](https://sourceforge.net/u/jwodder/profile/)) + +[0.17.26, 2023-05-09]: +- fix for error on edge cage for issue 459 + +[0.17.25, 2023-05-09]: +- fix for regression while dumping wrapped strings with too many backslashes removed + (issue 459, reported by [Lele Gaifax](https://sourceforge.net/u/lele/profile/)) + +[0.17.24, 2023-05-06]: +- rewrite of `CommentedMap.insert()`. If you have a merge key in the YAML document + for the mapping you insert to, the position value should be the one as you look + at the YAML input. This fixes issue 453 where other keys of a merged in mapping + would show up after an insert (reported by [Alex Miller](https://sourceforge.net/u/millerdevel/profile/)). + It also fixes a call to `.insert()` resulting into the merge key to move to be the + first key if it wasn't already and it is also now possible to insert a key before + a merge key (even if the fist key in the mapping). +- fix (in the pure Python implementation including default) for issue 447. (reported + by [Jack Cherng](https://sourceforge.net/u/jfcherng/profile/), also brought up by + brent on [StackOverflow](https://stackoverflow.com/q/40072485/1307905)) + +[0.17.23, 2023-05-05]: +- fix 458, error on plain scalars starting with word longer than width. (reported + by [Kyle Larose](https://sourceforge.net/u/klarose/profile/)) +- fix for `.update()` no longer correctly handling keyword arguments (reported by + John Lin on [StackOverflow]( https://stackoverflow.com/q/76089100/1307905)) +- |- + fix issue 454: high Unicode (emojis) in quoted strings always + escaped (reported by [Michal + Čihař](https://sourceforge.net/u/nijel/profile/) based on a + question on StackOverflow). +- fix issue with emitter conservatively inserting extra backslashes in wrapped quoted + strings (reported by thebenman on [StackOverflow](https://stackoverflow.com/q/75631454/1307905)) + +[0.17.22, 2023-05-02]: +- fix issue 449 where the second exclamation marks got URL encoded (reported and fixing + PR provided by [John Stark](https://sourceforge.net/u/jods/profile/)) +- fix issue with indent != 2 and literal scalars with empty first line (reported by + wrdis on [StackOverflow](https://stackoverflow.com/q/75584262/1307905)) +- updated `__repr__` of CommentedMap, now that Python's dict is ordered -> no more + `ordereddict(list-of-tuples)` +- merge MR 4, handling OctalInt in YAML 1.1 (provided by [Jacob Floyd](https://sourceforge.net/u/cognifloyd/profile/)) +- fix loading of `!!float 42` (reported by Eric on [Stack overflow](https://stackoverflow.com/a/71555107/1307905)) +- line numbers are now set on `CommentedKeySeq` and `CommentedKeyMap` (which are created + if you have a sequence resp. mapping as the key in a mapping) +- |- + plain scalars: put single words longer than width on a line of + their own, instead of after the previous line (issue 427, reported + by [Antoine + Cotten](https://sourceforge.net/u/antoineco/profile/)). Caveat: + this currently results in a space ending the previous line. +- |- + fix for folded scalar part of 421: comments after ">" on first + line of folded scalars are now preserved (as were those in the + same position on literal scalars). Issue reported by Jacob Floyd. +- added stacklevel to warnings +- typing changed from Py2 compatible comments to Py3, removed various Py2-isms + +[0.17.21, 2022-02-12]: +- fix bug in calling `.compose()` method with `pathlib.Path` instance. + +[0.17.20, 2022-01-03]: +- fix error in microseconds while rounding datetime fractions >= 9999995 (reported + by [Luis Ferreira](https://sourceforge.net/u/ljmf00/)) + +[0.17.19, 2021-12-26]: +- fix mypy problems (reported by [Arun](https://sourceforge.net/u/arunppsg/profile/)) + +[0.17.18, 2021-12-24]: +- copy-paste error in folded scalar comment attachment (reported by [Stephan Geulette](https://sourceforge.net/u/sgeulette/profile/)) +- fix 411, indent error comment between key empty seq value (reported by [Guillermo + Julián](https://sourceforge.net/u/gjulianm/profile/)) + +[0.17.17, 2021-10-31]: +- extract timestamp matching/creation to util + +[0.17.16, 2021-08-28]: +- 398 also handle issue 397 when comment is newline + +[0.17.15, 2021-08-28]: +- fix issue 397, insert comment before key when a comment between key and value exists + (reported by [Bastien gerard](https://sourceforge.net/u/bagerard/)) + +[0.17.14, 2021-08-25]: +- fix issue 396, inserting key/val in merged-in dictionary (reported by [Bastien gerard](https://sourceforge.net/u/bagerard/)) + +[0.17.13, 2021-08-21]: +- minor fix in attr handling + +[0.17.12, 2021-08-21]: +- fix issue with anchor on registered class not preserved and those classes using + package attrs with `@attr.s()` (both reported by [ssph](https://sourceforge.net/u/sph/)) + +[0.17.11, 2021-08-19]: +- fix error baseclass for `DuplicateKeyError` (reported by [Łukasz Rogalski](https://sourceforge.net/u/lrogalski/)) +- fix typo in reader error message, causing `KeyError` during reader error (reported + by [MTU](https://sourceforge.net/u/mtu/)) + +[0.17.10, 2021-06-24]: +- fix issue 388, token with old comment structure != two elements (reported by [Dimitrios + Bariamis](https://sourceforge.net/u/dbdbc/)) + +[0.17.9, 2021-06-10]: +- fix issue with updating CommentedMap (reported by sri on [StackOverflow](https://stackoverflow.com/q/67911659/1307905)) + +[0.17.8, 2021-06-09]: +- fix for issue 387 where templated anchors on tagged object did get set resulting + in potential id reuse. (reported by [Artem Ploujnikov](https://sourceforge.net/u/flexthink/)) + +[0.17.7, 2021-05-31]: +- issue 385 also affected other deprecated loaders (reported via email by Oren Watson) + +[0.17.6, 2021-05-31]: +- merged type annotations update provided by [Jochen Sprickerhof](https://sourceforge.net/u/jspricke/) +- |- + fix for issue 385: deprecated round_trip_loader function not + working (reported by [Mike + Gouline](https://sourceforge.net/u/gouline/)) +- wasted a few hours getting rid of mypy warnings/errors + +[0.17.5, 2021-05-30]: +- fix for issue 384 `!!set` with aliased entry resulting in broken YAML on rt reported + by [William Kimball](https://sourceforge.net/u/william303/)) + +[0.17.4, 2021-04-07]: +- prevent (empty) comments from throwing assertion error (issue 351 reported by [William + Kimball](https://sourceforge.net/u/william303/)) comments (or empty line) will be + dropped + +[0.17.3, 2021-04-07]: +- fix for issue 382 caused by an error in a format string (reported by [William Kimball](https://sourceforge.net/u/william303/)) +- |- + allow expansion of aliases by setting `yaml.composer.return_alias = lambda s: copy.deepcopy(s)` + (as per [Stackoverflow answer](https://stackoverflow.com/a/66983530/1307905)) + +[0.17.2, 2021-03-29]: +- change -py2.py3-none-any.whl to -py3-none-any.whl, and remove 0.17.1 + +[0.17.1, 2021-03-29]: +- |- + added 'Programming Language :: Python :: 3 :: Only', and + removing 0.17.0 from PyPI (reported by [Alasdair + Nicol](https://sourceforge.net/u/alasdairnicol/)) + +[0.17.0, 2021-03-26]: +- removed because of incomplete classifiers +- this release no longer supports Python 2.7, most if not all Python 2 specific code + is removed. The 0.17.x series is the last to support Python 3.5 (this also allowed + for removal of the dependency on `ruamel.std.pathlib`) +- remove Python2 specific code branches and adaptations (u-strings) +- prepare % code for f-strings using `_F` +- allow PyOxidisation ([issue 324](https://sourceforge.net/p/ruamel-yaml/tickets/324/) + resp. [issue 171](https://github.com/indygreg/PyOxidizer/issues/171)) +- replaced Python 2 compatible enforcement of keyword arguments with '*' +- the old top level *functions* `load`, `safe_load`, `round_trip_load`, `dump`, `safe_dump`, + `round_trip_dump`, `scan`, `parse`, `compose`, `emit`, `serialize` as well as their + `_all` variants for multi-document streams, now issue a `PendingDeprecationning` + (e.g. when run from pytest, but also Python is started with `-Wd`). Use the methods + on `YAML()`, which have been extended. +- |- + fix for issue 376: indentation changes could put literal/folded + scalar to start before the `#` column of a following comment. + Effectively making the comment part of the scalar in the output. + (reported by [Bence Nagy](https://sourceforge.net/u/underyx/)) + +[0.16.13, 2021-03-05]: +- |- + fix for issue 359: could not update() CommentedMap with keyword + arguments (reported by [Steve + Franchak](https://sourceforge.net/u/binaryadder/)) +- |- + fix for issue 365: unable to dump mutated TimeStamp objects + (reported by [Anton Akmerov](https://sourceforge.net/u/akhmerov)) +- |- + fix for issue 371: unable to add comment without starting space + (reported by [Mark Grandi](https://sourceforge.net/u/mgrandi)) +- |- + fix for issue 373: recursive call to walk_tree not preserving + all params (reported by [eulores](https://sourceforge.net/u/eulores/)) +- a None value in a flow-style sequence is now dumped as `null` instead of `!!null + ''` (reported by mcarans on [StackOverflow](https://stackoverflow.com/a/66489600/1307905)) + +[0.16.12, 2020-09-04]: +- update links in doc + +[0.16.11, 2020-09-03]: +- workaround issue with setuptools 0.50 and importing pip (fix by [jaraco](https://github.com/pypa/setuptools/issues/2355#issuecomment-685159580) + +[0.16.10, 2020-02-12]: +- (auto) updated image references in README to sourceforge + +[0.16.9, 2020-02-11]: +- update CHANGES + +[0.16.8, 2020-02-11]: +- update requirements so that ruamel.yaml.clib is installed for 3.8, as it has become + available (via manylinux builds) + +[0.16.7, 2020-01-30]: +- fix typchecking issue on TaggedScalar (reported by Jens Nielsen) +- fix error in dumping literal scalar in sequence with comments before element (reported + by [EJ Etherington](https://sourceforge.net/u/ejether/)) + +[0.16.6, 2020-01-20]: +- fix empty string mapping key roundtripping with preservation of quotes as `? ''` + (reported via email by Tomer Aharoni). +- fix incorrect state setting in class constructor (reported by [Douglas Raillard](https://bitbucket.org/%7Bcf052d92-a278-4339-9aa8-de41923bb556%7D/)) +- adjust deprecation warning test for Hashable, as that no longer warns (reported + by [Jason Montleon](https://bitbucket.org/%7B8f377d12-8d5b-4069-a662-00a2674fee4e%7D/)) + +[0.16.5, 2019-08-18]: +- allow for `YAML(typ=['unsafe', 'pytypes'])` + +[0.16.4, 2019-08-16]: +- fix output of TAG directives with `#` (reported by [Thomas Smith](https://bitbucket.org/%7Bd4c57a72-f041-4843-8217-b4d48b6ece2f%7D/)) + +[0.16.3, 2019-08-15]: +- split construct_object +- change stuff back to keep mypy happy +- move setting of version based on YAML directive to scanner, allowing to check for + file version during TAG directive scanning + +[0.16.2, 2019-08-15]: +- preserve YAML and TAG directives on roundtrip, correctly output `#` in URL for YAML + 1.2 (both reported by [Thomas Smith](https://bitbucket.org/%7Bd4c57a72-f041-4843-8217-b4d48b6ece2f%7D/)) + +[0.16.1, 2019-08-08]: +- Force the use of new version of ruamel.yaml.clib (reported by [Alex Joz](https://bitbucket.org/%7B9af55900-2534-4212-976c-61339b6ffe14%7D/)) +- Allow `#` in tag URI as these are allowed in YAML 1.2 (reported by [Thomas Smith](https://bitbucket.org/%7Bd4c57a72-f041-4843-8217-b4d48b6ece2f%7D/)) + +[0.16.0, 2019-07-25]: +- split of C source that generates `.so` file to [ruamel.yaml.clib]( https://pypi.org/project/ruamel.yaml.clib/) +- duplicate keys are now an error when working with the old API as well + +[0.15.100, 2019-07-17]: +- fixing issue with dumping deep-copied data from commented YAML, by providing both + the memo parameter to __deepcopy__, and by allowing startmarks to be compared on + their content (reported by `Theofilos Petsios `__) + +[0.15.99, 2019-07-12]: +- add `py.typed` to distribution, based on a PR submitted by `Michael Crusoe `__ +- merge PR 40 (also by Michael Crusoe) to more accurately specify repository in the + README (also reported in a misunderstood issue some time ago) + +[0.15.98, 2019-07-09]: +- regenerate ext/_ruamel_yaml.c with Cython version 0.29.12, needed for Python 3.8.0b2 + (reported by `John Vandenberg `__) + +[0.15.97, 2019-06-06]: +- regenerate ext/_ruamel_yaml.c with Cython version 0.29.10, needed for Python 3.8.0b1 +- regenerate ext/_ruamel_yaml.c with Cython version 0.29.9, needed for Python 3.8.0a4 + (reported by `Anthony Sottile `__) + +[0.15.96, 2019-05-16]: +- fix failure to indent comments on round-trip anchored block style scalars in block + sequence (reported by `William Kimball `__) + +[0.15.95, 2019-05-16]: +- fix failure to round-trip anchored scalars in block sequence (reported by `William + Kimball `__) +- wheel files for Python 3.4 no longer provided (`Python 3.4 EOL 2019-03-18 `__) + +[0.15.94, 2019-04-23]: +- fix missing line-break after end-of-file comments not ending in line-break (reported + by `Philip Thompson `__) + +[0.15.93, 2019-04-21]: +- fix failure to parse empty implicit flow mapping key +- in YAML 1.1 plains scalars `y`, 'n', `Y`, and 'N' are now correctly recognised as + booleans and such strings dumped quoted (reported by `Marcel Bollmann `__) + +[0.15.92, 2019-04-16]: +- fix failure to parse empty implicit block mapping key (reported by `Nolan W `__) + +[0.15.91, 2019-04-05]: +- allowing duplicate keys would not work for merge keys (reported by mamacdon on `StackOverflow + `__ + +[0.15.90, 2019-04-04]: +- fix issue with updating `CommentedMap` from list of tuples (reported by `Peter Henry + `__) + +[0.15.89, 2019-02-27]: +- fix for items with flow-mapping in block sequence output on single line (reported + by `Zahari Dim `__) +- fix for safe dumping erroring in creation of representereror when dumping namedtuple + (reported and solution by `Jaakko Kantojärvi `__) + +[0.15.88, 2019-02-12]: +- fix inclusing of python code from the subpackage data (containing extra tests, reported + by `Florian Apolloner `__) + +[0.15.87, 2019-01-22]: +- fix problem with empty lists and the code to reinsert merge keys (reported via email + by Zaloo) + +[0.15.86, 2019-01-16]: +- reinsert merge key in its old position (reported by grumbler on `__) +- fix for issue with non-ASCII anchor names (reported and fix provided by Dandaleon + Flux via email) +- fix for issue when parsing flow mapping value starting with colon (in pure Python + only) (reported by `FichteFoll `__) + +[0.15.85, 2019-01-08]: +- the types used by `SafeConstructor` for mappings and sequences can now by set by + assigning to `XXXConstructor.yaml_base_dict_type` (and `..._list_type`), preventing + the need to copy two methods with 50+ lines that had `var = {}` hardcoded. (Implemented + to help solve an feature request by `Anthony Sottile `__ + in an easier way) + +[0.15.84, 2019-01-07]: +- fix for `CommentedMap.copy()` not returning `CommentedMap`, let alone copying comments + etc. (reported by `Anthony Sottile `__) + +[0.15.83, 2019-01-02]: +- fix for bug in roundtripping aliases used as key (reported via email by Zaloo) + +[0.15.82, 2018-12-28]: +- anchors and aliases on scalar int, float, string and bool are now preserved. Anchors + do not need a referring alias for these (reported by `Alex Harvey `__) +- anchors no longer lost on tagged objects when roundtripping (reported by `Zaloo + `__) + +[0.15.81, 2018-12-06]: +- fix issue saving methods of metaclass derived classes (reported and fix provided + by `Douglas Raillard `__) + +[0.15.80, 2018-11-26]: +- fix issue emitting BEL character when round-tripping invalid folded input (reported + by Isaac on `StackOverflow `__) + +[0.15.79, 2018-11-21]: +- fix issue with anchors nested deeper than alias (reported by gaFF on `StackOverflow + `__) + +[0.15.78, 2018-11-15]: +- fix setup issue for 3.8 (reported by `Sidney Kuyateh `__) + +[0.15.77, 2018-11-09]: +- setting `yaml.sort_base_mapping_type_on_output = False`, will prevent explicit sorting + by keys in the base representer of mappings. Roundtrip already did not do this. + Usage only makes real sense for Python 3.6+ (feature request by `Sebastian Gerber + `__). +- implement Python version check in YAML metadata in `_test/test_z_data.py` + +[0.15.76, 2018-11-01]: +- fix issue with empty mapping and sequence loaded as flow-style (mapping reported + by `Min RK `__, sequence by `Maged Ahmed `__) + +[0.15.75, 2018-10-27]: +- fix issue with single '?' scalar (reported by `Terrance `__) +- fix issue with duplicate merge keys (prompted by `answering `__ + a `StackOverflow question `__ by `math + `__) + +[0.15.74, 2018-10-17]: +- fix dropping of comment on rt before sequence item that is sequence item (reported + by `Thorsten Kampe `__) + +[0.15.73, 2018-10-16]: +- fix irregular output on pre-comment in sequence within sequence (reported by `Thorsten + Kampe `__) +- allow non-compact (i.e. next line) dumping sequence/mapping within sequence. + +[0.15.72, 2018-10-06]: +- fix regression on explicit 1.1 loading with the C based scanner/parser (reported + by `Tomas Vavra `__) + +[0.15.71, 2018-09-26]: +- fix regression where handcrafted CommentedMaps could not be initiated (reported + by `Dan Helfman `__) +- fix regression with non-root literal scalars that needed indent indicator (reported + by `Clark Breyman `__) +- tag:yaml.org,2002:python/object/apply now also uses __qualname__ on PY3 (reported + by `Douglas RAILLARD `__) + +[0.15.70, 2018-09-21]: +- reverted CommentedMap and CommentedSeq to subclass ordereddict resp. list, reimplemented + merge maps so that both `dict(**commented_map_instance)` and JSON dumping works. + This also allows checking with `isinstance()` on `dict` resp. `list`. (Proposed + by `Stuart Berg `__, with feedback from `blhsing + `__ on `StackOverflow `__) + +[0.15.69, 2018-09-20]: +- fix issue with dump_all gobbling end-of-document comments on parsing (reported by + `Pierre B. `__) + +[0.15.68, 2018-09-20]: +- fix issue with parsabel, but incorrect output with nested flow-style sequences (reported + by `Dougal Seeley `__) +- fix issue with loading Python objects that have __setstate__ and recursion in parameters + (reported by `Douglas RAILLARD `__) + +[0.15.67, 2018-09-19]: +- fix issue with extra space inserted with non-root literal strings (Issue reported + and PR with fix provided by `Naomi Seyfer `__.) + +[0.15.66, 2018-09-07]: +- fix issue with fold indicating characters inserted in safe_load-ed folded strings + (reported by `Maximilian Hils `__). + +[0.15.65, 2018-09-07]: +- |- + fix issue #232 revert to throw ParserError for unexcpected `]` + and `}` instead of IndexError. (Issue reported and PR with fix + provided by `Naomi Seyfer `__.) +- added `key` and `reverse` parameter (suggested by Jannik Klemm via email) +- indent root level literal scalars that have directive or document end markers at + the beginning of a line + +[0.15.64, 2018-08-30]: +- |- + support round-trip of tagged sequences: `!Arg [a, {b: 1}]` +- |- + single entry mappings in flow sequences now written by default without quotes + set `yaml.brace_single_entry_mapping_in_flow_sequence=True` to force + getting `[a, {b: 1}, {c: {d: 2}}]` instead of the default `[a, b: 1, c: {d: 2}]` +- fix issue when roundtripping floats starting with a dot such as `.5` (reported by + `Harrison Gregg `__) + +[0.15.63, 2018-08-29]: +- small fix only necessary for Windows users that don't use wheels. + +[0.15.62, 2018-08-29]: +- C based reader/scanner & emitter now allow setting of 1.2 as YAML version. ** The + loading/dumping is still YAML 1.1 code**, so use the common subset of YAML 1.2 and + 1.1 (reported by `Ge Yang `__) + +[0.15.61, 2018-08-23]: +- support for round-tripping folded style scalars (initially requested by `Johnathan + Viduchinsky `__) +- update of C code +- speed up of scanning (~30% depending on the input) + +[0.15.60, 2018-08-18]: +- cleanup for mypy +- spurious print in library (reported by `Lele Gaifax `__), + now automatically checked + +[0.15.59, 2018-08-17]: +- issue with C based loader and leading zeros (reported by `Tom Hamilton Stubber `__) + +[0.15.58, 2018-08-17]: +- |- + simple mappings can now be used as keys when round-tripping:: + + {a: 1, b: 2}: hello world - although using the obvious operations (del, popitem) on the key will - fail, you can mutilate it by going through its attributes. If you load the - above YAML in `d`, then changing the value is cumbersome: - - d = {CommentedKeyMap([('a', 1), ('b', 2)]): "goodbye"} - - and changing the key even more so: - - d[CommentedKeyMap([('b', 1), ('a', 2)])] = d.pop( - CommentedKeyMap([('a', 1), ('b', 2)])) - - (you can use a `dict` instead of a list of tuples (or ordereddict), but that might result - in a different order, of the keys of the key, in the output) - - check integers to dump with 1.2 patterns instead of 1.1 (reported by - `Lele Gaifax `__) - - -[0, 15, 57]: 2018-08-15 - - Fix that CommentedSeq could no longer be used in adding or do a copy - (reported by `Christopher Wright `__) - -[0, 15, 56]: 2018-08-15 - - fix issue with ``python -O`` optimizing away code (reported, and detailed cause - pinpointed, by `Alex Grönholm `__ - -[0, 15, 55]: 2018-08-14 - - - unmade ``CommentedSeq`` a subclass of ``list``. It is now - indirectly a subclass of the standard - ``collections.abc.MutableSequence`` (without .abc if you are - still on Python2.7). If you do ``isinstance(yaml.load('[1, 2]'), - list)``) anywhere in your code replace ``list`` with - ``MutableSequence``. Directly, ``CommentedSeq`` is a subclass of - the abstract baseclass ``ruamel.yaml.compat.MutableScliceableSequence``, - with the result that *(extended) slicing is supported on - ``CommentedSeq``*. - (reported by `Stuart Berg `__) - - duplicate keys (or their values) with non-ascii now correctly - report in Python2, instead of raising a Unicode error. - (Reported by `Jonathan Pyle `__) - -[0, 15, 54]: 2018-08-13 - - - fix issue where a comment could pop-up twice in the output (reported by - `Mike Kazantsev `__ and by - `Nate Peterson `__) - - fix issue where JSON object (mapping) without spaces was not parsed - properly (reported by `Marc Schmidt `__) - - fix issue where comments after empty flow-style mappings were not emitted - (reported by `Qinfench Chen `__) - -[0, 15, 53]: 2018-08-12 - - fix issue with flow style mapping with comments gobbled newline (reported - by `Christopher Lambert `__) - - fix issue where single '+' under YAML 1.2 was interpreted as - integer, erroring out (reported by `Jethro Yu - `__) - -[0, 15, 52]: 2018-08-09 - - added `.copy()` mapping representation for round-tripping - (``CommentedMap``) to fix incomplete copies of merged mappings - (reported by `Will Richards - `__) - - Also unmade that class a subclass of ordereddict to solve incorrect behaviour - for ``{**merged-mapping}`` and ``dict(**merged-mapping)`` (reported by - `Filip Matzner `__) - -[0, 15, 51]: 2018-08-08 - - Fix method name dumps (were not dotted) and loads (reported by `Douglas Raillard - `__) - - Fix spurious trailing white-space caused when the comment start - column was no longer reached and there was no actual EOL comment - (e.g. following empty line) and doing substitutions, or when - quotes around scalars got dropped. (reported by `Thomas Guillet - `__) - -[0, 15, 50]: 2018-08-05 - - Allow ``YAML()`` as a context manager for output, thereby making it much easier - to generate multi-documents in a stream. - - Fix issue with incorrect type information for `load()` and `dump()` (reported - by `Jimbo Jim `__) - -[0, 15, 49]: 2018-08-05 - - fix preservation of leading newlines in root level literal style scalar, - and preserve comment after literal style indicator (``| # some comment``) + although using the obvious operations (del, popitem) on the key will + fail, you can mutilate it by going through its attributes. If you load the + above YAML in `d`, then changing the value is cumbersome: + + d = {CommentedKeyMap([('a', 1), ('b', 2)]): "goodbye"} + + and changing the key even more so: + + d[CommentedKeyMap([('b', 1), ('a', 2)])] = d.pop( + CommentedKeyMap([('a', 1), ('b', 2)])) + + (you can use a `dict` instead of a list of tuples (or ordereddict), but that might result + in a different order, of the keys of the key, in the output) +- check integers to dump with 1.2 patterns instead of 1.1 (reported by `Lele Gaifax + `__) + + +[0.15.57, 2018-08-15]: +- Fix that CommentedSeq could no longer be used in adding or do a copy (reported by + `Christopher Wright `__) + +[0.15.56, 2018-08-15]: +- fix issue with `python -O` optimizing away code (reported, and detailed cause pinpointed, + by `Alex Grönholm `__ + +[0.15.55, 2018-08-14]: + +- unmade `CommentedSeq` a subclass of `list`. It is now indirectly a subclass of the + standard `collections.abc.MutableSequence` (without .abc if you are still on Python2.7). + If you do `isinstance(yaml.load('[1, 2]'), list)`) anywhere in your code replace + `list` with `MutableSequence`. Directly, `CommentedSeq` is a subclass of the abstract + baseclass `ruamel.yaml.compat.MutableScliceableSequence`, with the result that *(extended) + slicing is supported on `CommentedSeq`*. (reported by `Stuart Berg `__) +- duplicate keys (or their values) with non-ascii now correctly report in Python2, + instead of raising a Unicode error. (Reported by `Jonathan Pyle `__) + +[0.15.54, 2018-08-13]: + +- fix issue where a comment could pop-up twice in the output (reported by `Mike Kazantsev + `__ and by `Nate Peterson `__) +- fix issue where JSON object (mapping) without spaces was not parsed properly (reported + by `Marc Schmidt `__) +- fix issue where comments after empty flow-style mappings were not emitted (reported + by `Qinfench Chen `__) + +[0.15.53, 2018-08-12]: +- fix issue with flow style mapping with comments gobbled newline (reported by `Christopher + Lambert `__) +- fix issue where single '+' under YAML 1.2 was interpreted as integer, erroring out + (reported by `Jethro Yu `__) + +[0.15.52, 2018-08-09]: +- added `.copy()` mapping representation for round-tripping (`CommentedMap`) to fix + incomplete copies of merged mappings (reported by `Will Richards `__) +- Also unmade that class a subclass of ordereddict to solve incorrect behaviour for + `{**merged-mapping}` and `dict(**merged-mapping)` (reported by `Filip Matzner `__) + +[0.15.51, 2018-08-08]: +- Fix method name dumps (were not dotted) and loads (reported by `Douglas Raillard + `__) +- Fix spurious trailing white-space caused when the comment start column was no longer + reached and there was no actual EOL comment (e.g. following empty line) and doing + substitutions, or when quotes around scalars got dropped. (reported by `Thomas + Guillet `__) + +[0.15.50, 2018-08-05]: +- Allow `YAML()` as a context manager for output, thereby making it much easier to + generate multi-documents in a stream. +- Fix issue with incorrect type information for `load()` and `dump()` (reported by + `Jimbo Jim `__) + +[0.15.49, 2018-08-05]: +- |- + fix preservation of leading newlines in root level literal style scalar, + and preserve comment after literal style indicator (`| # some comment`) Both needed for round-tripping multi-doc streams in `ryd `__. -[0, 15, 48]: 2018-08-03 - - housekeeping: ``oitnb`` for formatting, mypy 0.620 upgrade and conformity - -[0, 15, 47]: 2018-07-31 - - fix broken 3.6 manylinux1 (result of an unclean ``build`` (reported by - `Roman Sichnyi `__) - - -[0, 15, 46]: 2018-07-29 - - fixed DeprecationWarning for importing from ``collections`` on 3.7 - (issue 210, reported by `Reinoud Elhorst - `__). It was `difficult to find - why tox/pytest did not report - `__ and as time - consuming to actually `fix - `__ the tests. - -[0, 15, 45]: 2018-07-26 - - After adding failing test for ``YAML.load_all(Path())``, remove StopIteration - (PR provided by `Zachary Buhman `__, - also reported by `Steven Hiscocks `__. - -[0, 15, 44]: 2018-07-14 - - Correct loading plain scalars consisting of numerals only and - starting with `0`, when not explicitly specifying YAML version - 1.1. This also fixes the issue about dumping string `'019'` as - plain scalars as reported by `Min RK - `__, that prompted this chance. - -[0, 15, 43]: 2018-07-12 - - merge PR33: Python2.7 on Windows is narrow, but has no - ``sysconfig.get_config_var('Py_UNICODE_SIZE')``. (merge provided by +[0.15.48, 2018-08-03]: +- |- + housekeeping: `oitnb` for formatting, mypy 0.620 upgrade and conformity + +[0.15.47, 2018-07-31]: +- fix broken 3.6 manylinux1 (result of an unclean `build` (reported by `Roman Sichnyi + `__) + + +[0.15.46, 2018-07-29]: +- fixed DeprecationWarning for importing from `collections` on 3.7 (issue 210, reported + by `Reinoud Elhorst `__). It was `difficult to + find why tox/pytest did not report `__ + and as time consuming to actually `fix `__ + the tests. + +[0.15.45, 2018-07-26]: +- After adding failing test for `YAML.load_all(Path())`, remove StopIteration (PR + provided by `Zachary Buhman `__, also reported by + `Steven Hiscocks `__. + +[0.15.44, 2018-07-14]: +- Correct loading plain scalars consisting of numerals only and starting with `0`, + when not explicitly specifying YAML version 1.1. This also fixes the issue about + dumping string `'019'` as plain scalars as reported by `Min RK `__, + that prompted this chance. + +[0.15.43, 2018-07-12]: +- |- + merge PR33: Python2.7 on Windows is narrow, but has no + `sysconfig.get_config_var('Py_UNICODE_SIZE')`. (merge provided by `Marcel Bargull `__) - - ``register_class()`` now returns class (proposed by + - `register_class()` now returns class (proposed by `Mike Nerone `__} -[0, 15, 42]: 2018-07-01 - - fix regression showing only on narrow Python 2.7 (py27mu) builds - (with help from - `Marcel Bargull `__ and - `Colm O'Connor <>`__). - - run pre-commit ``tox`` on Python 2.7 wide and narrow, as well as - 3.4/3.5/3.6/3.7/pypy - -[0, 15, 41]: 2018-06-27 - - add detection of C-compile failure (investigation prompted by - `StackOverlow `__ by - `Emmanuel Blot `__), - which was removed while no longer dependent on ``libyaml``, C-extensions - compilation still needs a compiler though. - -[0, 15, 40]: 2018-06-18 - - added links to landing places as suggested in issue 190 by - `KostisA `__ - - fixes issue #201: decoding unicode escaped tags on Python2, reported - by `Dan Abolafia `__ - -[0, 15, 39]: 2018-06-16 - - merge PR27 improving package startup time (and loading when regexp not - actually used), provided by - `Marcel Bargull `__ - -[0, 15, 38]: 2018-06-13 - - fix for losing precision when roundtripping floats by - `Rolf Wojtech `__ - - fix for hardcoded dir separator not working for Windows by - `Nuno André `__ - - typo fix by `Andrey Somov `__ - -[0, 15, 37]: 2018-03-21 - - again trying to create installable files for 187 - -[0, 15, 36]: 2018-02-07 - - fix issue 187, incompatibility of C extension with 3.7 (reported by - Daniel Blanchard) - -[0, 15, 35]: 2017-12-03 - - allow ``None`` as stream when specifying ``transform`` parameters to - ``YAML.dump()``. - This is useful if the transforming function doesn't return a meaningful value - (inspired by `StackOverflow `__ by - `rsaw `__). - -[0, 15, 34]: 2017-09-17 - - fix for issue 157: CDumper not dumping floats (reported by Jan Smitka) - -[0, 15, 33]: 2017-08-31 - - support for "undefined" round-tripping tagged scalar objects (in addition to - tagged mapping object). Inspired by a use case presented by Matthew Patton - on `StackOverflow `__. - - fix issue 148: replace cryptic error message when using !!timestamp with an - incorrectly formatted or non- scalar. Reported by FichteFoll. - -[0, 15, 32]: 2017-08-21 - - allow setting ``yaml.default_flow_style = None`` (default: ``False``) for - for ``typ='rt'``. - - fix for issue 149: multiplications on ``ScalarFloat`` now return ``float`` - -[0, 15, 31]: 2017-08-15 - - fix Comment dumping - -[0, 15, 30]: 2017-08-14 - - fix for issue with "compact JSON" not parsing: ``{"in":{},"out":{}}`` - (reported on `StackOverflow `_ by - `mjalkio `_ - -[0, 15, 29]: 2017-08-14 - - fix issue #51: different indents for mappings and sequences (reported by - Alex Harvey) - - fix for flow sequence/mapping as element/value of block sequence with - sequence-indent minus dash-offset not equal two. - -[0, 15, 28]: 2017-08-13 - - fix issue #61: merge of merge cannot be __repr__-ed (reported by Tal Liron) - -[0, 15, 27]: 2017-08-13 - - fix issue 62, YAML 1.2 allows ``?`` and ``:`` in plain scalars if non-ambigious - (reported by nowox) - - fix lists within lists which would make comments disappear - -[0, 15, 26]: 2017-08-10 - - fix for disappearing comment after empty flow sequence (reported by - oit-tzhimmash) - -[0, 15, 25]: 2017-08-09 - - fix for problem with dumping (unloaded) floats (reported by eyenseo) - -[0, 15, 24]: 2017-08-09 - - added ScalarFloat which supports roundtripping of 23.1, 23.100, - 42.00E+56, 0.0, -0.0 etc. while keeping the format. Underscores in mantissas - are not preserved/supported (yet, is anybody using that?). - - (finally) fixed longstanding issue 23 (reported by `Antony Sottile - `_), now handling comment between block - mapping key and value correctly - - warn on YAML 1.1 float input that is incorrect (triggered by invalid YAML - provided by Cecil Curry) - - allow setting of boolean representation (`false`, `true`) by using: - ``yaml.boolean_representation = [u'False', u'True']`` - -[0, 15, 23]: 2017-08-01 - - fix for round_tripping integers on 2.7.X > sys.maxint (reported by ccatterina) - -[0, 15, 22]: 2017-07-28 - - fix for round_tripping singe excl. mark tags doubling (reported and fix by Jan Brezina) - -[0, 15, 21]: 2017-07-25 - - fix for writing unicode in new API, https://stackoverflow.com/a/45281922/1307905 - -[0, 15, 20]: 2017-07-23 - - wheels for windows including C extensions - -[0, 15, 19]: 2017-07-13 - - added object constructor for rt, decorator ``yaml_object`` to replace YAMLObject. - - fix for problem using load_all with Path() instance - - fix for load_all in combination with zero indent block style literal - (``pure=True`` only!) - -[0, 15, 18]: 2017-07-04 - - missing ``pure`` attribute on ``YAML`` useful for implementing `!include` tag - constructor for `including YAML files in a YAML file - `_ - - some documentation improvements - - trigger of doc build on new revision - -[0, 15, 17]: 2017-07-03 - - support for Unicode supplementary Plane **output** with allow_unicode - (input was already supported, triggered by - `this `_ Stack Overflow Q&A) - -[0, 15, 16]: 2017-07-01 - - minor typing issues (reported and fix provided by - `Manvendra Singh `_) - - small doc improvements - -[0, 15, 15]: 2017-06-27 - - fix for issue 135, typ='safe' not dumping in Python 2.7 - (reported by Andrzej Ostrowski `_) - -[0, 15, 14]: 2017-06-25 - - setup.py: change ModuleNotFoundError to ImportError (reported and fix by Asley Drake) - -[0, 15, 13]: 2017-06-24 - - suppress duplicate key warning on mappings with merge keys (reported by - Cameron Sweeney) - -[0, 15, 12]: 2017-06-24 - - remove fatal dependency of setup.py on wheel package (reported by - Cameron Sweeney) - -[0, 15, 11]: 2017-06-24 - - fix for issue 130, regression in nested merge keys (reported by - `David Fee `_) - -[0, 15, 10]: 2017-06-23 - - top level PreservedScalarString not indented if not explicitly asked to - - remove Makefile (not very useful anyway) - - some mypy additions - -[0, 15, 9]: 2017-06-16 - - fix for issue 127: tagged scalars were always quoted and seperated - by a newline when in a block sequence (reported and largely fixed by - `Tommy Wang `_) - -[0, 15, 8]: 2017-06-15 - - allow plug-in install via ``install ruamel.yaml[jinja2]`` - -[0, 15, 7]: 2017-06-14 - - add plug-in mechanism for load/dump pre resp. post-processing - -[0, 15, 6]: 2017-06-10 - - a set() with duplicate elements now throws error in rt loading - - support for toplevel column zero literal/folded scalar in explicit documents - -[0, 15, 5]: 2017-06-08 - - repeat `load()` on a single `YAML()` instance would fail. - -(0, 15, 4) 2017-06-08: | - - `transform` parameter on dump that expects a function taking a - string and returning a string. This allows transformation of the output - before it is written to stream. - - some updates to the docs - -(0, 15, 3) 2017-06-07: - - No longer try to compile C extensions on Windows. Compilation can be forced by setting - the environment variable `RUAMEL_FORCE_EXT_BUILD` to some value - before starting the `pip install`. - -(0, 15, 2) 2017-06-07: - - update to conform to mypy 0.511:mypy --strict - -(0, 15, 1) 2017-06-07: - - Any `duplicate keys `_ - in mappings generate an error (in the old API this change generates a warning until 0.16) - - dependecy on ruamel.ordereddict for 2.7 now via extras_require - -(0, 15, 0) 2017-06-04: - - it is now allowed to pass in a ``pathlib.Path`` as "stream" parameter to all - load/dump functions - - passing in a non-supported object (e.g. a string) as "stream" will result in a - much more meaningful YAMLStreamError. - - assigning a normal string value to an existing CommentedMap key or CommentedSeq - element will result in a value cast to the previous value's type if possible. - -(0, 14, 12) 2017-05-14: - - fix for issue 119, deepcopy not returning subclasses (reported and PR by - Constantine Evans ) - -(0, 14, 11) 2017-05-01: - - fix for issue 103 allowing implicit documents after document end marker line (``...``) - in YAML 1.2 - -(0, 14, 10) 2017-04-26: - - fix problem with emitting using cyaml - -(0, 14, 9) 2017-04-22: - - remove dependency on ``typing`` while still supporting ``mypy`` - (http://stackoverflow.com/a/43516781/1307905) - - fix unclarity in doc that stated 2.6 is supported (reported by feetdust) - -(0, 14, 8) 2017-04-19: - - fix Text not available on 3.5.0 and 3.5.1, now proactively setting version guards - on all files (reported by `João Paulo Magalhães `_) - -(0, 14, 7) 2017-04-18: - - round trip of integers (decimal, octal, hex, binary) now preserve - leading zero(s) padding and underscores. Underscores are presumed - to be at regular distances (i.e. ``0o12_345_67`` dumps back as - ``0o1_23_45_67`` as the space from the last digit to the - underscore before that is the determining factor). - -(0, 14, 6) 2017-04-14: - - binary, octal and hex integers are now preserved by default. This - was a known deficiency. Working on this was prompted by the issue report (112) - from devnoname120, as well as the additional experience with `.replace()` - on `scalarstring` classes. - - fix issues 114 cannot install on Buildozer (reported by mixmastamyk). - Setting env. var ``RUAMEL_NO_PIP_INSTALL_CHECK`` will suppress ``pip``-check. - -(0, 14, 5) 2017-04-04: - - fix issue 109 None not dumping correctly at top level (reported by Andrea Censi) - - fix issue 110 .replace on Preserved/DoubleQuoted/SingleQuoted ScalarString - would give back "normal" string (reported by sandres23) - -(0, 14, 4) 2017-03-31: - - fix readme - -(0, 14, 3) 2017-03-31: - - fix for 0o52 not being a string in YAML 1.1 (reported on - `StackOverflow Q&A 43138503>`_ by - `Frank D `_ - -(0, 14, 2) 2017-03-23: - - fix for old default pip on Ubuntu 14.04 (reported by Sébastien Maccagnoni-Munch) - -(0.14.1) 2017-03-22: - - fix Text not available on 3.5.0 and 3.5.1 (reported by Charles Bouchard-Légaré) - -(0.14.0) 2017-03-21: - - updates for mypy --strict - - preparation for moving away from inheritance in Loader and Dumper, calls from e.g. - the Representer to the Serializer.serialize() are now done via the attribute - .serializer.serialize(). Usage of .serialize() outside of Serializer will be - deprecated soon - - some extra tests on main.py functions - -(0.13.14) 2017-02-12: - - fix for issue 97, clipped block scalar followed by empty lines and comment - would result in two CommentTokens of which the first was dropped. - (reported by Colm O'Connor) - -(0.13.13) 2017-01-28: - - fix for issue 96, prevent insertion of extra empty line if indented mapping entries - are separated by an empty line (reported by Derrick Sawyer) - -(0.13.11) 2017-01-23: - - allow ':' in flow style scalars if not followed by space. Also don't - quote such scalar as this is no longer necessary. - - add python 3.6 manylinux wheel to PyPI - -(0.13.10) 2017-01-22: - - fix for issue 93, insert spurious blank line before single line comment - between indented sequence elements (reported by Alex) - -(0.13.9) 2017-01-18: - - fix for issue 92, wrong import name reported by the-corinthian - -(0.13.8) 2017-01-18: - - fix for issue 91, when a compiler is unavailable reported by Maximilian Hils - - fix for deepcopy issue with TimeStamps not preserving 'T', reported on - `StackOverflow Q&A `_ by - `Quuxplusone `_ - -(0.13.7) 2016-12-27: - - fix for issue 85, constructor.py importing unicode_literals caused mypy to fail - on 2.7 (reported by Peter Amstutz) - -(0.13.6) 2016-12-27: - - fix for issue 83, collections.OrderedDict not representable by SafeRepresenter - (reported by Frazer McLean) - -(0.13.5) 2016-12-25: - - fix for issue 84, deepcopy not properly working (reported by Peter Amstutz) - -(0.13.4) 2016-12-05: - - another fix for issue 82, change to non-global resolver data broke implicit type - specification - -(0.13.3) 2016-12-05: - - fix for issue 82, deepcopy not working (reported by code monk) - -(0.13.2) 2016-11-28: - - fix for comments after empty (null) values (reported by dsw2127 and cokelaer) - -(0.13.1) 2016-11-22: - - optimisations on memory usage when loading YAML from large files (py3 -50%, py2 -85%) - -(0.13.0) 2016-11-20: - - if ``load()`` or ``load_all()`` is called with only a single argument - (stream or string) - a UnsafeLoaderWarning will be issued once. If appropriate you can surpress this - warning by filtering it. Explicitly supplying the ``Loader=ruamel.yaml.Loader`` - argument, will also prevent it from being issued. You should however consider - using ``safe_load()``, ``safe_load_all()`` if your YAML input does not use tags. - - allow adding comments before and after keys (based on - `StackOveflow Q&A `_ by - `msinn `_) - -(0.12.18) 2016-11-16: - - another fix for numpy (re-reported independently by PaulG & Nathanial Burdic) - -(0.12.17) 2016-11-15: - - only the RoundTripLoader included the Resolver that supports YAML 1.2 - now all loaders do (reported by mixmastamyk) - -(0.12.16) 2016-11-13: - - allow dot char (and many others) in anchor name - Fix issue 72 (reported by Shalon Wood) - - | - Slightly smarter behaviour dumping strings when no style is - specified. Single string scalars that start with single quotes - or have newlines now are dumped double quoted "'abc\nklm'" instead of - - '''abc - - klm''' - -(0.12.14) 2016-09-21: - - preserve round-trip sequences that are mapping keys - (prompted by stackoverflow question 39595807 from Nowox) - -(0.12.13) 2016-09-15: - - Fix for issue #60 representation of CommentedMap with merge - keys incorrect (reported by Tal Liron) - -(0.12.11) 2016-09-06: - - Fix issue 58 endless loop in scanning tokens (reported by - Christopher Lambert) - -(0.12.10) 2016-09-05: - - Make previous fix depend on unicode char width (32 bit unicode support - is a problem on MacOS reported by David Tagatac) - -(0.12.8) 2016-09-05: - - To be ignored Unicode characters were not properly regex matched - (no specific tests, PR by Haraguroicha Hsu) - -(0.12.7) 2016-09-03: - - fixing issue 54 empty lines with spaces (reported by Alex Harvey) - -(0.12.6) 2016-09-03: - - fixing issue 46 empty lines between top-level keys were gobbled (but - not between sequence elements, nor between keys in netsted mappings - (reported by Alex Harvey) - -(0.12.5) 2016-08-20: - - fixing issue 45 preserving datetime formatting (submitted by altuin) - Several formatting parameters are preserved with some normalisation: - - preserve 'T', 't' is replaced by 'T', multiple spaces between date - and time reduced to one. - - optional space before timezone is removed - - still using microseconds, but now rounded (.1234567 -> .123457) - - Z/-5/+01:00 preserved - -(0.12.4) 2016-08-19: - - Fix for issue 44: missing preserve_quotes keyword argument (reported - by M. Crusoe) - -(0.12.3) 2016-08-17: - - correct 'in' operation for merged CommentedMaps in round-trip mode - (implementation inspired by J.Ngo, but original not working for merges) - - iteration over round-trip loaded mappings, that contain merges. Also - keys(), items(), values() (Py3/Py2) and iterkeys(), iteritems(), - itervalues(), viewkeys(), viewitems(), viewvalues() (Py2) - - reuse of anchor name now generates warning, not an error. Round-tripping such - anchors works correctly. This inherited PyYAML issue was brought to attention - by G. Coddut (and was long standing https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=515634) - suppressing the warning:: - - import warnings - from ruamel.yaml.error import ReusedAnchorWarning - warnings.simplefilter("ignore", ReusedAnchorWarning) - -(0.12.2) 2016-08-16: - - minor improvements based on feedback from M. Crusoe - https://bitbucket.org/ruamel/yaml/issues/42/ - -(0.12.0) 2016-08-16: - - drop support for Python 2.6 - - include initial Type information (inspired by M. Crusoe) - -(0.11.15) 2016-08-07: - - Change to prevent FutureWarning in NumPy, as reported by tgehring - ("comparison to None will result in an elementwise object comparison in the future") - -(0.11.14) 2016-07-06: - - fix preserve_quotes missing on original Loaders (as reported - by Leynos, bitbucket issue 38) - -(0.11.13) 2016-07-06: - - documentation only, automated linux wheels - -(0.11.12) 2016-07-06: - - added support for roundtrip of single/double quoted scalars using: - ruamel.yaml.round_trip_load(stream, preserve_quotes=True) - -(0.11.10) 2016-05-02: - -- added .insert(pos, key, value, comment=None) to CommentedMap - -(0.11.10) 2016-04-19: +[0.15.42, 2018-07-01]: +- fix regression showing only on narrow Python 2.7 (py27mu) builds (with help from + `Marcel Bargull `__ and `Colm O'Connor <>`__). +- run pre-commit `tox` on Python 2.7 wide and narrow, as well as 3.4/3.5/3.6/3.7/pypy + +[0.15.41, 2018-06-27]: +- add detection of C-compile failure (investigation prompted by `StackOverlow `__ + by `Emmanuel Blot `__), which + was removed while no longer dependent on `libyaml`, C-extensions compilation still + needs a compiler though. + +[0.15.40, 2018-06-18]: +- added links to landing places as suggested in issue 190 by `KostisA `__ +- |- + fixes issue #201: decoding unicode escaped tags on Python2, reported + by `Dan Abolafia `__ + +[0.15.39, 2018-06-16]: +- merge PR27 improving package startup time (and loading when regexp not actually + used), provided by `Marcel Bargull `__ + +[0.15.38, 2018-06-13]: +- fix for losing precision when roundtripping floats by `Rolf Wojtech `__ +- fix for hardcoded dir separator not working for Windows by `Nuno André `__ +- typo fix by `Andrey Somov `__ + +[0.15.37, 2018-03-21]: +- again trying to create installable files for 187 + +[0.15.36, 2018-02-07]: +- fix issue 187, incompatibility of C extension with 3.7 (reported by Daniel Blanchard) + +[0.15.35, 2017-12-03]: +- allow `None` as stream when specifying `transform` parameters to `YAML.dump()`. + This is useful if the transforming function doesn't return a meaningful value (inspired + by `StackOverflow `__ by `rsaw `__). + +[0.15.34, 2017-09-17]: +- fix for issue 157: CDumper not dumping floats (reported by Jan Smitka) + +[0.15.33, 2017-08-31]: +- support for "undefined" round-tripping tagged scalar objects (in addition to tagged + mapping object). Inspired by a use case presented by Matthew Patton on `StackOverflow + `__. +- |- + fix issue 148: replace cryptic error message when using `!!timestamp` with an + incorrectly formatted or non-scalar. Reported by FichteFoll. + +[0.15.32, 2017-08-21]: +- |- + allow setting `yaml.default_flow_style = None` (default: `False`) for for `typ='rt'`. +- fix for issue 149: multiplications on `ScalarFloat` now return `float` + +[0.15.31, 2017-08-15]: +- fix Comment dumping + +[0.15.30, 2017-08-14]: +- |- + fix for issue with "compact JSON" not parsing: `{"in":{},"out":{}}` + (reported on `StackOverflow `_ by + `mjalkio `_ + +[0.15.29, 2017-08-14]: +- |- + fix issue #51: different indents for mappings and sequences (reported by Alex Harvey) +- fix for flow sequence/mapping as element/value of block sequence with sequence-indent + minus dash-offset not equal two. + +[0.15.28, 2017-08-13]: +- |- + fix issue #61: merge of merge cannot be __repr__-ed (reported by Tal Liron) + +[0.15.27, 2017-08-13]: +- fix issue 62, YAML 1.2 allows `?` and `:` in plain scalars if non-ambigious (reported + by nowox) +- fix lists within lists which would make comments disappear + +[0.15.26, 2017-08-10]: +- fix for disappearing comment after empty flow sequence (reported by oit-tzhimmash) + +[0.15.25, 2017-08-09]: +- fix for problem with dumping (unloaded) floats (reported by eyenseo) + +[0.15.24, 2017-08-09]: +- added ScalarFloat which supports roundtripping of 23.1, 23.100, 42.00E+56, 0.0, + -0.0 etc. while keeping the format. Underscores in mantissas are not preserved/supported + (yet, is anybody using that?). +- (finally) fixed longstanding issue 23 (reported by `Antony Sottile `_), + now handling comment between block mapping key and value correctly +- warn on YAML 1.1 float input that is incorrect (triggered by invalid YAML provided + by Cecil Curry) +- |- + allow setting of boolean representation (`false`, `true`) by using: + `yaml.boolean_representation = [u'False', u'True']` + +[0.15.23, 2017-08-01]: +- fix for round_tripping integers on 2.7.X > sys.maxint (reported by ccatterina) + +[0.15.22, 2017-07-28]: +- fix for round_tripping singe excl. mark tags doubling (reported and fix by Jan Brezina) + +[0.15.21, 2017-07-25]: +- fix for writing unicode in new API, https://stackoverflow.com/a/45281922/1307905 + +[0.15.20, 2017-07-23]: +- wheels for windows including C extensions + +[0.15.19, 2017-07-13]: +- added object constructor for rt, decorator `yaml_object` to replace YAMLObject. +- fix for problem using load_all with Path() instance +- fix for load_all in combination with zero indent block style literal (`pure=True` + only!) + +[0.15.18, 2017-07-04]: +- missing `pure` attribute on `YAML` useful for implementing `!include` tag constructor + for `including YAML files in a YAML file `_ +- some documentation improvements +- trigger of doc build on new revision + +[0.15.17, 2017-07-03]: +- support for Unicode supplementary Plane **output** with allow_unicode (input was + already supported, triggered by `this `_ + Stack Overflow Q&A) + +[0.15.16, 2017-07-01]: +- minor typing issues (reported and fix provided by `Manvendra Singh `_) +- small doc improvements + +[0.15.15, 2017-06-27]: +- fix for issue 135, typ='safe' not dumping in Python 2.7 (reported by Andrzej Ostrowski + `_) + +[0.15.14, 2017-06-25]: +- setup.py: change ModuleNotFoundError to ImportError (reported and fix by Asley Drake) + +[0.15.13, 2017-06-24]: +- suppress duplicate key warning on mappings with merge keys (reported by Cameron + Sweeney) + +[0.15.12, 2017-06-24]: +- remove fatal dependency of setup.py on wheel package (reported by Cameron Sweeney) + +[0.15.11, 2017-06-24]: +- fix for issue 130, regression in nested merge keys (reported by `David Fee `_) + +[0.15.10, 2017-06-23]: +- top level PreservedScalarString not indented if not explicitly asked to +- remove Makefile (not very useful anyway) +- some mypy additions + +[0.15.9, 2017-06-16]: +- |- + fix for issue 127: tagged scalars were always quoted and seperated + by a newline when in a block sequence (reported and largely fixed by + `Tommy Wang `_) + +[0.15.8, 2017-06-15]: +- allow plug-in install via `install ruamel.yaml[jinja2]` + +[0.15.7, 2017-06-14]: +- add plug-in mechanism for load/dump pre resp. post-processing + +[0.15.6, 2017-06-10]: +- a set() with duplicate elements now throws error in rt loading +- support for toplevel column zero literal/folded scalar in explicit documents + +[0.15.5, 2017-06-08]: +- repeat `load()` on a single `YAML()` instance would fail. + +[0.15.4, 2017-06-08]: +- |- + `transform` parameter on dump that expects a function taking a + string and returning a string. This allows transformation of the output + before it is written to stream. +- some updates to the docs + +[0.15.3, 2017-06-07]: +- No longer try to compile C extensions on Windows. Compilation can be forced by setting + the environment variable `RUAMEL_FORCE_EXT_BUILD` to some value before starting + the `pip install`. + +[0.15.2, 2017-06-07]: +- update to conform to mypy 0.511:mypy --strict + +[0.15.1, 2017-06-07]: +- Any `duplicate keys `_ + in mappings generate an error (in the old API this change generates a warning until + 0.16) +- dependecy on ruamel.ordereddict for 2.7 now via extras_require + +[0.15.0, 2017-06-04]: +- it is now allowed to pass in a `pathlib.Path` as "stream" parameter to all load/dump + functions +- passing in a non-supported object (e.g. a string) as "stream" will result in a much + more meaningful YAMLStreamError. +- assigning a normal string value to an existing CommentedMap key or CommentedSeq + element will result in a value cast to the previous value's type if possible. + +[0.14.12, 2017-05-14]: +- fix for issue 119, deepcopy not returning subclasses (reported and PR by Constantine + Evans ) + +[0.14.11, 2017-05-01]: +- fix for issue 103 allowing implicit documents after document end marker line (`...`) + in YAML 1.2 + +[0.14.10, 2017-04-26]: +- fix problem with emitting using cyaml + +[0.14.9, 2017-04-22]: +- remove dependency on `typing` while still supporting `mypy` (http://stackoverflow.com/a/43516781/1307905) +- fix unclarity in doc that stated 2.6 is supported (reported by feetdust) + +[0.14.8, 2017-04-19]: +- fix Text not available on 3.5.0 and 3.5.1, now proactively setting version guards + on all files (reported by `João Paulo Magalhães `_) + +[0.14.7, 2017-04-18]: +- round trip of integers (decimal, octal, hex, binary) now preserve leading zero(s) + padding and underscores. Underscores are presumed to be at regular distances (i.e. + `0o12_345_67` dumps back as `0o1_23_45_67` as the space from the last digit to the + underscore before that is the determining factor). + +[0.14.6, 2017-04-14]: +- binary, octal and hex integers are now preserved by default. This was a known deficiency. + Working on this was prompted by the issue report (112) from devnoname120, as well + as the additional experience with `.replace()` on `scalarstring` classes. +- fix issues 114 cannot install on Buildozer (reported by mixmastamyk). Setting env. + var `RUAMEL_NO_PIP_INSTALL_CHECK` will suppress `pip`-check. + +[0.14.5, 2017-04-04]: +- fix issue 109 None not dumping correctly at top level (reported by Andrea Censi) +- fix issue 110 .replace on Preserved/DoubleQuoted/SingleQuoted ScalarString would + give back "normal" string (reported by sandres23) + +[0.14.4, 2017-03-31]: +- fix readme + +[0.14.3, 2017-03-31]: +- fix for 0o52 not being a string in YAML 1.1 (reported on `StackOverflow Q&A 43138503>`_ + by `Frank D `_ + +[0.14.2, 2017-03-23]: +- fix for old default pip on Ubuntu 14.04 (reported by Sébastien Maccagnoni-Munch) + +[0.14.1, 2017-03-22]: +- fix Text not available on 3.5.0 and 3.5.1 (reported by Charles Bouchard-Légaré) + +[0.14.0, 2017-03-21]: +- updates for mypy --strict +- preparation for moving away from inheritance in Loader and Dumper, calls from e.g. + the Representer to the Serializer.serialize() are now done via the attribute .serializer.serialize(). + Usage of .serialize() outside of Serializer will be deprecated soon +- some extra tests on main.py functions + +[0.13.14, 2017-02-12]: +- fix for issue 97, clipped block scalar followed by empty lines and comment would + result in two CommentTokens of which the first was dropped. (reported by Colm O'Connor) + +[0.13.13, 2017-01-28]: +- fix for issue 96, prevent insertion of extra empty line if indented mapping entries + are separated by an empty line (reported by Derrick Sawyer) + +[0.13.11, 2017-01-23]: +- allow ':' in flow style scalars if not followed by space. Also don't quote such + scalar as this is no longer necessary. +- add python 3.6 manylinux wheel to PyPI + +[0.13.10, 2017-01-22]: +- fix for issue 93, insert spurious blank line before single line comment between + indented sequence elements (reported by Alex) + +[0.13.9, 2017-01-18]: +- fix for issue 92, wrong import name reported by the-corinthian + +[0.13.8, 2017-01-18]: +- fix for issue 91, when a compiler is unavailable reported by Maximilian Hils +- fix for deepcopy issue with TimeStamps not preserving 'T', reported on `StackOverflow + Q&A `_ by `Quuxplusone `_ + +[0.13.7, 2016-12-27]: +- fix for issue 85, constructor.py importing unicode_literals caused mypy to fail + on 2.7 (reported by Peter Amstutz) + +[0.13.6, 2016-12-27]: +- fix for issue 83, collections.OrderedDict not representable by SafeRepresenter (reported + by Frazer McLean) + +[0.13.5, 2016-12-25]: +- fix for issue 84, deepcopy not properly working (reported by Peter Amstutz) + +[0.13.4, 2016-12-05]: +- another fix for issue 82, change to non-global resolver data broke implicit type + specification + +[0.13.3, 2016-12-05]: +- fix for issue 82, deepcopy not working (reported by code monk) + +[0.13.2, 2016-11-28]: +- fix for comments after empty (null) values (reported by dsw2127 and cokelaer) + +[0.13.1, 2016-11-22]: +- optimisations on memory usage when loading YAML from large files (py3 -50%, py2 + -85%) + +[0.13.0, 2016-11-20]: +- if `load()` or `load_all()` is called with only a single argument (stream or string) + a UnsafeLoaderWarning will be issued once. If appropriate you can surpress this + warning by filtering it. Explicitly supplying the `Loader=ruamel.yaml.Loader` argument, + will also prevent it from being issued. You should however consider using `safe_load()`, + `safe_load_all()` if your YAML input does not use tags. +- allow adding comments before and after keys (based on `StackOveflow Q&A `_ by + `msinn `_) + +[0.12.18, 2016-11-16]: +- another fix for numpy (re-reported independently by PaulG & Nathanial Burdic) + +[0.12.17, 2016-11-15]: +- only the RoundTripLoader included the Resolver that supports YAML 1.2 now all loaders + do (reported by mixmastamyk) + +[0.12.16, 2016-11-13]: +- allow dot char (and many others) in anchor name Fix issue 72 (reported by Shalon + Wood) +- |- + Slightly smarter behaviour dumping strings when no style is + specified. Single string scalars that start with single quotes + or have newlines now are dumped double quoted "'abc\nklm'" instead of + + '''abc + + klm''' + +[0.12.14, 2016-09-21]: +- preserve round-trip sequences that are mapping keys (prompted by stackoverflow question + 39595807 from Nowox) + +[0.12.13, 2016-09-15]: +- |- + Fix for issue #60 representation of CommentedMap with merge + keys incorrect (reported by Tal Liron) + +[0.12.11, 2016-09-06]: +- Fix issue 58 endless loop in scanning tokens (reported by Christopher Lambert) + +[0.12.10, 2016-09-05]: +- Make previous fix depend on unicode char width (32 bit unicode support is a problem + on MacOS reported by David Tagatac) + +[0.12.8, 2016-09-05]: +- To be ignored Unicode characters were not properly regex matched (no specific tests, + PR by Haraguroicha Hsu) + +[0.12.7, 2016-09-03]: +- fixing issue 54 empty lines with spaces (reported by Alex Harvey) + +[0.12.6, 2016-09-03]: +- fixing issue 46 empty lines between top-level keys were gobbled (but not between + sequence elements, nor between keys in netsted mappings (reported by Alex Harvey) + +[0.12.5, 2016-08-20]: +- |- + fixing issue 45 preserving datetime formatting (submitted by altuin) + Several formatting parameters are preserved with some normalisation: +- preserve 'T', 't' is replaced by 'T', multiple spaces between date and time reduced + to one. +- optional space before timezone is removed +- still using microseconds, but now rounded (.1234567 -> .123457) +- Z/-5/+01:00 preserved + +[0.12.4, 2016-08-19]: +- |- + Fix for issue 44: missing preserve_quotes keyword argument (reported by M. Crusoe) + +[0.12.3, 2016-08-17]: +- correct 'in' operation for merged CommentedMaps in round-trip mode (implementation + inspired by J.Ngo, but original not working for merges) +- iteration over round-trip loaded mappings, that contain merges. Also keys(), items(), + values() (Py3/Py2) and iterkeys(), iteritems(), itervalues(), viewkeys(), viewitems(), + viewvalues() (Py2) +- |- + reuse of anchor name now generates warning, not an error. Round-tripping such + anchors works correctly. This inherited PyYAML issue was brought to attention + by G. Coddut (and was long standing https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=515634) + suppressing the warning: + ``` + import warnings + from ruamel.yaml.error import ReusedAnchorWarning + warnings.simplefilter("ignore", ReusedAnchorWarning) + ``` + +[0.12.2, 2016-08-16]: +- minor improvements based on feedback from M. Crusoe https://bitbucket.org/ruamel/yaml/issues/42/ + +[0.12.0, 2016-08-16]: +- drop support for Python 2.6 +- include initial Type information (inspired by M. Crusoe) + +[0.11.15, 2016-08-07]: +- Change to prevent FutureWarning in NumPy, as reported by tgehring ("comparison to + None will result in an elementwise object comparison in the future") + +[0.11.14, 2016-07-06]: +- fix preserve_quotes missing on original Loaders (as reported by Leynos, bitbucket + issue 38) + +[0.11.13, 2016-07-06]: +- documentation only, automated linux wheels + +[0.11.12, 2016-07-06]: +- |- + added support for roundtrip of single/double quoted scalars using: + ruamel.yaml.round_trip_load(stream, preserve_quotes=True) + +[0.11.10, 2016-05-02]: +- added `.insert(pos, key, value, comment=None)` to CommentedMap + +[0.11.10, 2016-04-19]: - indent=2, block_seq_indent=2 works as expected -(0.11.0) 2016-02-18: - - RoundTripLoader loads 1.2 by default (no sexagesimals, 012 octals nor - yes/no/on/off booleans +[0.11.0, 2016-02-18]: +- RoundTripLoader loads 1.2 by default (no sexagesimals, 012 octals nor yes/no/on/off + booleans -(0.10.11) 2015-09-17: +[0.10.11, 2015-09-17]: - Fix issue 13: dependency on libyaml to be installed for yaml.h -(0.10.10) 2015-09-15: +[0.10.10, 2015-09-15]: - Python 3.5 tested with tox - pypy full test (old PyYAML tests failed on too many open file handles) -(0.10.6-0.10.9) 2015-09-14: +[0.10.6-0.10.9, 2015-09-14]: - Fix for issue 9 - Fix for issue 11: double dump losing comments - Include libyaml code - move code from 'py' subdir for proper namespace packaging. -(0.10.5) 2015-08-25: +[0.10.5, 2015-08-25]: - preservation of newlines after block scalars. Contributed by Sam Thursfield. -(0.10) 2015-06-22: +[0.10, 2015-06-22]: - preservation of hand crafted anchor names ( not of the form "idNNN") -- preservation of map merges ( <<< ) +- preservation of map merges ( `<<` ) -(0.9) 2015-04-18: -- collections read in by the RoundTripLoader now have a ``lc`` property - that can be quired for line and column ( ``lc.line`` resp. ``lc.col``) +[0.9, 2015-04-18]: +- collections read in by the RoundTripLoader now have a `lc` property that can be + quired for line and column ( `lc.line` resp. `lc.col`) -(0.8) 2015-04-15: +[0.8, 2015-04-15]: - bug fix for non-roundtrip save of ordereddict - adding/replacing end of line comments on block style mappings/sequences -(0.7.2) 2015-03-29: +[0.7.2, 2015-03-29]: - support for end-of-line comments on flow style sequences and mappings -(0.7.1) 2015-03-27: +[0.7.1, 2015-03-27]: - RoundTrip capability of flow style sequences ( 'a: b, c, d' ) -(0.7) 2015-03-26: -- tests (currently failing) for inline sequece and non-standard spacing between - block sequence dash and scalar (Anthony Sottile) -- initial possibility (on list, i.e. CommentedSeq) to set the flow format - explicitly +[0.7, 2015-03-26]: +- tests (currently failing) for inline sequece and non-standard spacing between block + sequence dash and scalar (Anthony Sottile) +- initial possibility (on list, i.e. CommentedSeq) to set the flow format explicitly - RoundTrip capability of flow style sequences ( 'a: b, c, d' ) -(0.6.1) 2015-03-15: -- setup.py changed so ruamel.ordereddict no longer is a dependency - if not on CPython 2.x (used to test only for 2.x, which breaks pypy 2.5.0 - reported by Anthony Sottile) +[0.6.1, 2015-03-15]: +- setup.py changed so ruamel.ordereddict no longer is a dependency if not on CPython + 2.x (used to test only for 2.x, which breaks pypy 2.5.0 reported by Anthony Sottile) -(0.6) 2015-03-11: +[0.6, 2015-03-11]: - basic support for scalars with preserved newlines - html option for yaml command - check if yaml C library is available before trying to compile C extension - include unreleased change in PyYAML dd 20141128 -(0.5) 2015-01-14: +[0.5, 2015-01-14]: - move configobj -> YAML generator to own module -- added dependency on ruamel.base (based on feedback from Sess - +- added dependency on ruamel.base (based on feedback from Sess -(0.4) 20141125: +[0.4, 2014-11-25]: - move comment classes in own module comments - fix omap pre comment - make !!omap and !!set take parameters. There are still some restrictions: - no comments before the !!tag - extra tests -(0.3) 20141124: +[0.3, 2014-11-24]: - fix value comment occuring as on previous line (looking like eol comment) - INI conversion in yaml + tests - (hidden) test in yaml for debugging with auto command - fix for missing comment in middel of simple map + test -(0.2) 20141123: +[0.2, 2014-11-23]: - add ext/_yaml.c etc to the source tree - tests for yaml to work on 2.6/3.3/3.4 - change install so that you can include ruamel.yaml instead of ruamel.yaml.py - add "yaml" utility with initial subcommands (test rt, from json) -(0.1) 20141122: +[0.1, 2014-11-22]: - merge py2 and py3 code bases -- remove support for 2.5/3.0/3.1/3.2 (this merge relies on u"" as - available in 3.3 and . imports not available in 2.5) +- remove support for 2.5/3.0/3.1/3.2 (this merge relies on u"" as available in 3.3 + and . imports not available in 2.5) - tox.ini for 2.7/3.4/2.6/3.3 - remove lib3/ and tests/lib3 directories and content - commit @@ -1177,19 +1195,20 @@ - DATA=changed to be relative to __file__ of code - DATA using os.sep - remove os.path from imports as os is already imported -- have test_yaml.py exit with value 0 on success, 1 on failures, 2 on - error -- added support for octal integers starting with '0o' - keep support for 01234 as well as 0o1234 +- have test_yaml.py exit with value 0 on success, 1 on failures, 2 on error +- added support for octal integers starting with '0o' keep support for 01234 as well + as 0o1234 - commit -- added test_roundtrip_data: - requirest a .data file and .roundtrip (empty), yaml_load .data +- |- + added test_roundtrip_data: + requires a .data file and .roundtrip (empty), yaml_load .data and compare dump against original. -- fix grammar as per David Pursehouse: +- |- + fix grammar as per David Pursehouse: https://bitbucket.org/xi/pyyaml/pull-request/5/fix-grammar-in-error-messages/diff -- http://www.json.org/ extra escaped char \/ - add .skip-ext as libyaml is not updated -- David Fraser: Extract a method to represent keys in mappings, so that +- http://www.json.org/ extra escaped char `\/` add .skip-ext as libyaml is not updated +- |- + David Fraser: Extract a method to represent keys in mappings, so that a subclass can choose not to quote them, used in repesent_mapping https://bitbucket.org/davidfraser/pyyaml/ - add CommentToken and percolate through parser and composer and constructor diff --git a/README.md b/README.md new file mode 100644 index 0000000..bf3d8cc --- /dev/null +++ b/README.md @@ -0,0 +1,396 @@ +# ruamel.yaml + +`ruamel.yaml` is a YAML 1.2 loader/dumper package for Python. + + + + + + + + + + + + + + + + +
version0.18.5
updated2023-11-03
documentationhttps://yaml.readthedocs.io
repositoryhttps://sourceforge.net/projects/ruamel-yaml
pypihttps://pypi.org/project/ruamel.yaml
+ +As announced, in 0.18.0, the old PyYAML functions have been deprecated. +(`scan`, `parse`, `compose`, `load`, `emit`, `serialize`, `dump` and their variants +(`_all`, `safe_`, `round_trip_`, etc)). If you only read this after your program has +stopped working: I am sorry to hear that, but that also means you, or the person +developing your program, has not tested with warnings on (which is the recommendation +in PEP 565, and e.g. defaultin when using `pytest`). If you have troubles, explicitly use +``` +pip install "ruamel.yaml<0.18.0" +``` +or put something to that effects in your requirments, to give yourself +some time to solve the issue. + +There will be at least one more potentially breaking change in the 0.18 series: `YAML(typ='unsafe')` +now has a pending deprecation warning and is going to be deprecated, probably before the end of 2023. +If you only use it to dump, please use the new `YAML(typ='full')`, the result of that can be *safely* +loaded with a default instance `YAML()`, as that will get you inspectable, tagged, scalars, instead of +executed Python functions/classes. (You should probably add constructors for what you actually need, +but I do consider adding a `ruamel.yaml.unsafe` package that will re-add the `typ='unsafe'` option. +*Please adjust/pin your dependencies accordingly if necessary.* + + +There seems to be a CVE on `ruamel.yaml`, stating that the `load()` function could be abused +because of unchecked input. `load()` was never the default function (that was `round_trip_load()` +before the new API came into existence`. So the creator of that CVE was ill informed and +probably lazily assumed that since `ruamel.yaml` is a derivative of PyYAML (for which +a similar CVE exists), the same problem would still exist, without checking. +So the CVE was always inappriate, now just more so, as the call +to the function `load()` with any input will terminate your program with an error message. If you +(have to) care about such things as this CVE, my recommendation is to stop using Python +completely, as `pickle.load()` can be abused in the same way as `load()` (and like unlike `load()` +is only documented to be unsafe, without development-time warning. + +Version 0.17.21 was the last one tested to be working on Python 3.5 and 3.6
+The 0.16.13 release was the last that was tested to be working on Python 2.7. + + +There are two extra plug-in packages +(`ruamel.yaml.bytes` and `ruamel.yaml.string`) +for those not wanting to do the streaming to a +`io.BytesIO/StringIO` buffer themselves. + +If your package uses `ruamel.yaml` and is not listed on PyPI, drop me an +email, preferably with some information on how you use the package (or a +link to the repository) and I'll keep you informed when the status of +the API is stable enough to make the transition. + +
+    Overview
+
+    Installing
+      Optional requirements
+
+    Basic Usage
+      Load and dump  
+      More examples
+
+    Working with Python classes
+      Dumping Python classes
+      Dataclass
+
+    Details
+      Indentation of block sequences
+        Inconsistently indented YAML
+        Indenting using `typ="safe"`
+      Positioning ':' in top level mappings, prefixing ':'
+        Document version support
+        Round trip including comments
+    Config file formats
+    Extending
+    Smartening
+
+    Examples
+      Output of `dump()` as a string
+
+    Departure from previous API
+      Loading
+        Duplicate keys
+      Dumping a multi-document YAML stream
+      Dumping
+        Controls
+      Transparent usage of new and old API
+      Reason for API change
+
+    Differences with PyYAML
+      Defaulting to YAML 1.2 support
+      PY2/PY3 reintegration
+      Fixes
+      Testing
+      API
+
+    Contributing
+      Documentation
+      Code
+        Flake
+        Tox/pytest
+        Typing/mypy
+      Generated files
+      Vulnerabilities
+
+ + +[![image](https://readthedocs.org/projects/yaml/badge/?version=latest)](https://yaml.readthedocs.org/en/latest?badge=latest)[![image](https://bestpractices.coreinfrastructure.org/projects/1128/badge)](https://bestpractices.coreinfrastructure.org/projects/1128) +[![image](https://sourceforge.net/p/ruamel-yaml/code/ci/default/tree/_doc/_static/license.svg?format=raw)](https://opensource.org/licenses/MIT) +[![image](https://sourceforge.net/p/ruamel-yaml/code/ci/default/tree/_doc/_static/pypi.svg?format=raw)](https://pypi.org/project/ruamel.yaml/) +[![image](https://sourceforge.net/p/oitnb/code/ci/default/tree/_doc/_static/oitnb.svg?format=raw)](https://pypi.org/project/oitnb/) +[![image](http://www.mypy-lang.org/static/mypy_badge.svg)](http://mypy-lang.org/) + +# ChangeLog + +0.18.5 (2023-11-03): + +- there is some indication that dependent packages have been pinned to use specific (tested) and just install the latest even in Python versions that have end-of-life + +0.18.4 (2023-11-01): + +- YAML() instance has a `doc_infos` attribute which is a cumulative list of DocInfo instances (one for `load()`, one per document for `load_all()`). DocInfo instances contain version information (requested, directive) and tag directive information +- fix issue that the YAML instance tags attribute was not reset between documents, resulting in mixing of tag directives of multiple documents. Now only provides tag directive information on latest document after loading. This means tags for dumping must be set **again** after a document is loaded with the same instance. (because of this tags will be removed in a favour of a different mechanism in the future) +- fix issue with multiple document intermixing YAML 1.2 and YAML 1.1, the VersionedResolver now resets +- fix issue with disappearing comment when next token was Tag (still can't have both a comment before a tag and after a tag, before node) + +0.18.3 (2023-10-29): + +- fix issue with spurious newline on first item after comment + nested block sequence +- additional links in the metadata on PyPI (Reported, with pointers how to fix, by [Sorin](https://sourceforge.net/u/ssbarnea/profile/)). + +0.18.2 (2023-10-24): + +- calling the deprecated functions now raises an `AttributeError` with the, somewhat more informative, orginal warning message. Instead of calling `sys.exit(1)` + +0.18.1 (2023-10-24): + +- calling the deprecated functions now always displays the warning message. (reported by [Trend Lloyd](https://sourceforge.net/u/lathiat2/profile/)) + +0.18.0 (2023-10-23): + +- the **functions** `scan`, `parse`, `compose`, `load`, `emit`, `serialize`, `dump` and their variants (`_all`, `safe_`, `round_trip_`, etc) have been deprecated (the same named **methods** on `YAML()` instances are, of course, still there. +- `YAML(typ='unsafe')` now issues a `PendingDeprecationWarning`. This will become deprecated in the 0.18 series +(probably before the end of 2023). +You can use `YAML(typ='full')` to dump unregistered Python classes/functions. +For loading you'll have to register your classes/functions +if you want the old, unsafe, functionality. You can still load any tag, like `!!python/name:posix.system', **safely** +with the (default) round-trip parser. +- fix for `bytes-like object is required not 'str' while dumping binary streams`. This was reported, analysed and a fix provided by [Vit Zikmund](https://sourceforge.net/u/tlwhitec/profile/) + +0.17.40 (2023-10-20): + +- flow style sets are now preserved ( `!!set {a, b, c} )`. Any values specified when loading are dropped, including `!!null ""`. +- potential workaround for issue 484: the long_description_content_type including the variant specification `CommonMark` +can result in problems on Azure. If you can install from `.tar.gz` using +`RUAMEL_NO_LONG_DESCRIPTION=1 pip install ruamel.yaml --no-binary :all:` then the long description, and its +offending type, are nog included (in the METADATA). +(Reported by [Coury Ditch](https://sourceforge.net/u/cmditch/profile/)) +- links in documentation update (reported by [David Hoese](https://sourceforge.net/u/daveydave400/profile/)) +- Added some `__repr__` for internally used classes + +0.17.39 (2023-10-19): + +- update README generation, no code changes + +0.17.36 (2023-10-19): + +- fixed issue 480, dumping of a loaded empty flow-style mapping with comment failed (Reported by [Stéphane Brunner](https://sourceforge.net/u/stbrunner/profile/)) +- fixed issue 482, caused by DEFAULT_MAPPING_TAG having changes to being a `Tag()` instance, not a string (reported by [yan12125](https://sourceforge.net/u/yan12125/profile/)) +- updated documentation to use mkdocs + +0.17.35 (2023-10-04): + +- support for loading dataclasses with `InitVar` variables (some special coding was necessary to get the, unexecpected, default value in the corresponding instance attribute ( example of usage in [this question](https://stackoverflow.com/q/77228378/1307905)) + +0.17.34 (2023-10-03): + +- Python 3.12 also loads C version when using `typ='safe'` +- initial support for loading invoking +`__post_init__()` on dataclasses that have that +method after loading a registered dataclass. +(Originally +[asked](https://stackoverflow.com/q/51529458/1307905) on +Stackoverflow by +[nyanpasu64](https://stackoverflow.com/users/2683842/nyanpasu64) +and as +[ticket](https://sourceforge.net/p/ruamel-yaml/tickets/355/) by +[Patrick Lehmann](https://sourceforge.net/u/paebbels/profile/)) + +``` +@yaml.register_class +@dataclass +class ... +``` + +0.17.33 (2023-09-28): + +- added `flow_seq_start`, `flow_seq_end`, `flow_seq_separator`, `flow_map_start`, `flow_map_end`, `flow_map_separator` **class** attributes to the `Emitter` class so flow style output can more easily be influenced (based on [this answer](https://stackoverflow.com/a/76547814/1307905) on a StackOverflow question by [Huw Walters](https://stackoverflow.com/users/291033/huw-walters)). + +0.17.32 (2023-06-17): + +- fix issue with scanner getting stuck in infinite loop + +0.17.31 (2023-05-31): + +- added tag.setter on `ScalarEvent` and on `Node`, that takes either a `Tag` instance, or a str (reported by [Sorin Sbarnea](https://sourceforge.net/u/ssbarnea/profile/)) + +0.17.30 (2023-05-30): + +- fix issue 467, caused by Tag instances not being hashable (reported by [Douglas Raillard](https://bitbucket.org/%7Bcf052d92-a278-4339-9aa8-de41923bb556%7D/)) + +0.17.29 (2023-05-30): + +- changed the internals of the tag property from a string to a class which allows for preservation of the original handle and suffix. This should result in better results using documents with %TAG directives, as well as preserving URI escapes in tag suffixes. + +0.17.28 (2023-05-26): + +- fix for issue 464: documents ending with document end marker +without final newline fail to load (reported by [Mariusz +Rusiniak](https://sourceforge.net/u/r2dan/profile/)) + +0.17.27 (2023-05-25): + +- fix issue with inline mappings as value for merge keys (reported by Sirish on [StackOverflow](https://stackoverflow.com/q/76331049/1307905)) +- fix for 468, error inserting after accessing merge attribute on `CommentedMap` (reported by [Bastien gerard](https://sourceforge.net/u/bagerard/)) +- fix for issue 461 pop + insert on same `CommentedMap` key throwing error (reported by [John Thorvald Wodder II](https://sourceforge.net/u/jwodder/profile/)) + +0.17.26 (2023-05-09): + +- fix for error on edge cage for issue 459 + +0.17.25 (2023-05-09): + +- fix for regression while dumping wrapped strings with too many backslashes removed (issue 459, reported by [Lele Gaifax](https://sourceforge.net/u/lele/profile/)) + +0.17.24 (2023-05-06): + +- rewrite of `CommentedMap.insert()`. If you have a merge key in the YAML document for the mapping you insert to, the position value should be the one as you look at the YAML input. This fixes issue 453 where other keys of a merged in mapping would show up after an insert (reported by [Alex Miller](https://sourceforge.net/u/millerdevel/profile/)). It also fixes a call to `.insert()` resulting into the merge key to move to be the first key if it wasn't already and it is also now possible to insert a key before a merge key (even if the fist key in the mapping). +- fix (in the pure Python implementation including default) for issue 447. (reported by [Jack Cherng](https://sourceforge.net/u/jfcherng/profile/), also brought up by brent on [StackOverflow](https://stackoverflow.com/q/40072485/1307905)) + +0.17.23 (2023-05-05): + +- fix 458, error on plain scalars starting with word longer than width. (reported by [Kyle Larose](https://sourceforge.net/u/klarose/profile/)) +- fix for `.update()` no longer correctly handling keyword arguments (reported by John Lin on [StackOverflow]( https://stackoverflow.com/q/76089100/1307905)) +- fix issue 454: high Unicode (emojis) in quoted strings always +escaped (reported by [Michal +Čihař](https://sourceforge.net/u/nijel/profile/) based on a +question on StackOverflow). +- fix issue with emitter conservatively inserting extra backslashes in wrapped quoted strings (reported by thebenman on [StackOverflow](https://stackoverflow.com/q/75631454/1307905)) + +0.17.22 (2023-05-02): + +- fix issue 449 where the second exclamation marks got URL encoded (reported and fixing PR provided by [John Stark](https://sourceforge.net/u/jods/profile/)) +- fix issue with indent != 2 and literal scalars with empty first line (reported by wrdis on [StackOverflow](https://stackoverflow.com/q/75584262/1307905)) +- updated `__repr__` of CommentedMap, now that Python's dict is ordered -> no more `ordereddict(list-of-tuples)` +- merge MR 4, handling OctalInt in YAML 1.1 (provided by [Jacob Floyd](https://sourceforge.net/u/cognifloyd/profile/)) +- fix loading of `!!float 42` (reported by Eric on [Stack overflow](https://stackoverflow.com/a/71555107/1307905)) +- line numbers are now set on `CommentedKeySeq` and `CommentedKeyMap` (which are created if you have a sequence resp. mapping as the key in a mapping) +- plain scalars: put single words longer than width on a line of +their own, instead of after the previous line (issue 427, reported +by [Antoine +Cotten](https://sourceforge.net/u/antoineco/profile/)). Caveat: +this currently results in a space ending the previous line. +- fix for folded scalar part of 421: comments after ">" on first +line of folded scalars are now preserved (as were those in the +same position on literal scalars). Issue reported by Jacob Floyd. +- added stacklevel to warnings +- typing changed from Py2 compatible comments to Py3, removed various Py2-isms + +0.17.21 (2022-02-12): + +- fix bug in calling `.compose()` method with `pathlib.Path` instance. + +0.17.20 (2022-01-03): + +- fix error in microseconds while rounding datetime fractions >= 9999995 (reported by [Luis Ferreira](https://sourceforge.net/u/ljmf00/)) + +0.17.19 (2021-12-26): + +- fix mypy problems (reported by [Arun](https://sourceforge.net/u/arunppsg/profile/)) + +0.17.18 (2021-12-24): + +- copy-paste error in folded scalar comment attachment (reported by [Stephan Geulette](https://sourceforge.net/u/sgeulette/profile/)) +- fix 411, indent error comment between key empty seq value (reported by [Guillermo Julián](https://sourceforge.net/u/gjulianm/profile/)) + +0.17.17 (2021-10-31): + +- extract timestamp matching/creation to util + +0.17.16 (2021-08-28): + +- 398 also handle issue 397 when comment is newline + +0.17.15 (2021-08-28): + +- fix issue 397, insert comment before key when a comment between key and value exists (reported by [Bastien gerard](https://sourceforge.net/u/bagerard/)) + +0.17.14 (2021-08-25): + +- fix issue 396, inserting key/val in merged-in dictionary (reported by [Bastien gerard](https://sourceforge.net/u/bagerard/)) + +0.17.13 (2021-08-21): + +- minor fix in attr handling + +0.17.12 (2021-08-21): + +- fix issue with anchor on registered class not preserved and those classes using package attrs with `@attr.s()` (both reported by [ssph](https://sourceforge.net/u/sph/)) + +0.17.11 (2021-08-19): + +- fix error baseclass for `DuplicateKeyError` (reported by [Łukasz Rogalski](https://sourceforge.net/u/lrogalski/)) +- fix typo in reader error message, causing `KeyError` during reader error (reported by [MTU](https://sourceforge.net/u/mtu/)) + +0.17.10 (2021-06-24): + +- fix issue 388, token with old comment structure != two elements (reported by [Dimitrios Bariamis](https://sourceforge.net/u/dbdbc/)) + +0.17.9 (2021-06-10): + +- fix issue with updating CommentedMap (reported by sri on [StackOverflow](https://stackoverflow.com/q/67911659/1307905)) + +0.17.8 (2021-06-09): + +- fix for issue 387 where templated anchors on tagged object did get set resulting in potential id reuse. (reported by [Artem Ploujnikov](https://sourceforge.net/u/flexthink/)) + +0.17.7 (2021-05-31): + +- issue 385 also affected other deprecated loaders (reported via email by Oren Watson) + +0.17.6 (2021-05-31): + +- merged type annotations update provided by [Jochen Sprickerhof](https://sourceforge.net/u/jspricke/) +- fix for issue 385: deprecated round_trip_loader function not +working (reported by [Mike +Gouline](https://sourceforge.net/u/gouline/)) +- wasted a few hours getting rid of mypy warnings/errors + +0.17.5 (2021-05-30): + +- fix for issue 384 `!!set` with aliased entry resulting in broken YAML on rt reported by [William Kimball](https://sourceforge.net/u/william303/)) + +0.17.4 (2021-04-07): + +- prevent (empty) comments from throwing assertion error (issue 351 reported by [William Kimball](https://sourceforge.net/u/william303/)) comments (or empty line) will be dropped + +0.17.3 (2021-04-07): + +- fix for issue 382 caused by an error in a format string (reported by [William Kimball](https://sourceforge.net/u/william303/)) +- allow expansion of aliases by setting `yaml.composer.return_alias = lambda s: copy.deepcopy(s)` +(as per [Stackoverflow answer](https://stackoverflow.com/a/66983530/1307905)) + +0.17.2 (2021-03-29): + +- change -py2.py3-none-any.whl to -py3-none-any.whl, and remove 0.17.1 + +0.17.1 (2021-03-29): + +- added 'Programming Language :: Python :: 3 :: Only', and +removing 0.17.0 from PyPI (reported by [Alasdair +Nicol](https://sourceforge.net/u/alasdairnicol/)) + +0.17.0 (2021-03-26): + +- removed because of incomplete classifiers +- this release no longer supports Python 2.7, most if not all Python 2 specific code is removed. The 0.17.x series is the last to support Python 3.5 (this also allowed for removal of the dependency on `ruamel.std.pathlib`) +- remove Python2 specific code branches and adaptations (u-strings) +- prepare % code for f-strings using `_F` +- allow PyOxidisation ([issue 324](https://sourceforge.net/p/ruamel-yaml/tickets/324/) resp. [issue 171](https://github.com/indygreg/PyOxidizer/issues/171)) +- replaced Python 2 compatible enforcement of keyword arguments with '*' +- the old top level *functions* `load`, `safe_load`, `round_trip_load`, `dump`, `safe_dump`, `round_trip_dump`, `scan`, `parse`, `compose`, `emit`, `serialize` as well as their `_all` variants for multi-document streams, now issue a `PendingDeprecationning` (e.g. when run from pytest, but also Python is started with `-Wd`). Use the methods on `YAML()`, which have been extended. +- fix for issue 376: indentation changes could put literal/folded +scalar to start before the `#` column of a following comment. +Effectively making the comment part of the scalar in the output. +(reported by [Bence Nagy](https://sourceforge.net/u/underyx/)) + +------------------------------------------------------------------------ + +For older changes see the file +[CHANGES](https://sourceforge.net/p/ruamel-yaml/code/ci/default/tree/CHANGES) diff --git a/README.rst b/README.rst deleted file mode 100644 index 9ad161b..0000000 --- a/README.rst +++ /dev/null @@ -1,363 +0,0 @@ - -ruamel.yaml -=========== - -``ruamel.yaml`` is a YAML 1.2 loader/dumper package for Python. - -:version: 0.17.35 -:updated: 2023-10-04 -:documentation: http://yaml.readthedocs.io -:repository: https://sourceforge.net/projects/ruamel-yaml/ -:pypi: https://pypi.org/project/ruamel.yaml/ - -*Starting with 0.17.22 only Python 3.7+ is supported. -The 0.17 series is also the last to support old PyYAML functions, replace it by -creating a `YAML()` instance and use its `.load()` and `.dump()` methods.* -New(er) functionality is usually only available via the new API. - -The 0.17.21 was the last one tested to be working on Python 3.5 and 3.6 (the -latter was not tested, because -tox/virtualenv stopped supporting that EOL version). -The 0.16.13 release was the last that was tested to be working on Python 2.7. - -*Please adjust/pin your dependencies accordingly if necessary. (`ruamel.yaml<0.18`)* - -There are now two extra plug-in packages (`ruamel.yaml.bytes` and `ruamel.yaml.string`) -for those not wanting to do the streaming to a `io.BytesIO/StringIO` buffer themselves. - -If your package uses ``ruamel.yaml`` and is not listed on PyPI, drop -me an email, preferably with some information on how you use the -package (or a link to the repository) and I'll keep you informed -when the status of the API is stable enough to make the transition. - -* `Overview `_ -* `Installing `_ -* `Basic Usage `_ -* `Details `_ -* `Examples `_ -* `API `_ -* `Differences with PyYAML `_ - -.. image:: https://readthedocs.org/projects/yaml/badge/?version=stable - :target: https://yaml.readthedocs.org/en/stable - -.. image:: https://bestpractices.coreinfrastructure.org/projects/1128/badge - :target: https://bestpractices.coreinfrastructure.org/projects/1128 - -.. image:: https://sourceforge.net/p/ruamel-yaml/code/ci/default/tree/_doc/_static/license.svg?format=raw - :target: https://opensource.org/licenses/MIT - -.. image:: https://sourceforge.net/p/ruamel-yaml/code/ci/default/tree/_doc/_static/pypi.svg?format=raw - :target: https://pypi.org/project/ruamel.yaml/ - -.. image:: https://sourceforge.net/p/oitnb/code/ci/default/tree/_doc/_static/oitnb.svg?format=raw - :target: https://pypi.org/project/oitnb/ - -.. image:: http://www.mypy-lang.org/static/mypy_badge.svg - :target: http://mypy-lang.org/ - -ChangeLog -========= - -.. should insert NEXT: at the beginning of line for next key (with empty line) - -0.17.35 (2023-10-04): - - support for loading dataclasses with ``InitVar`` variables (some - special coding was necessary to get the, unexecpected, default value - in the corresponding instance attribute ( example of usage in - `this question `__ ) - -0.17.34 (2023-10-03): - - Python 3.12 also loads C version when using ``typ='safe'`` - - initial support for loading invoking `__post_init__()` on dataclasses that have that method - after loading a registered dataclass (`@yaml.register_class\n@dataclass\nclass ...`). - (Originally `asked `__ on Stackoverflow by - `nyanpasu64 `__ and as - `ticket `__ - by `Patrick Lehmann `__ - -0.17.33 (2023-09-28): - - added `flow_seq_start`, `flow_seq_end`, `flow_seq_separator`, `flow_map_start`, `flow_map_end`, - `flow_map_separator` **class** attributes to the `Emitter` class so flow style output - can more easily be influenced (based on `this answer `__ - on a StackOverflow question by `Huw Walters `__). - -0.17.32 (2023-06-17): - - fix issue with scanner getting stuck in infinite loop - -0.17.31 (2023-05-31): - - added tag.setter on `ScalarEvent` and on `Node`, that takes either - a `Tag` instance, or a str - (reported by `Sorin Sbarnea `__) - -0.17.30 (2023-05-30): - - fix issue 467, caused by Tag instances not being hashable (reported by - `Douglas Raillard - `__) - -0.17.29 (2023-05-30): - - changed the internals of the tag property from a string to a class which allows - for preservation of the original handle and suffix. This should - result in better results using documents with %TAG directives, as well - as preserving URI escapes in tag suffixes. - -0.17.28 (2023-05-26): - - fix for issue 464: documents ending with document end marker without final newline - fail to load (reported by `Mariusz Rusiniak `__) - -0.17.27 (2023-05-25): - - fix issue with inline mappings as value for merge keys - (reported by Sirish on `StackOverflow `__) - - fix for 468, error inserting after accessing merge attribute on ``CommentedMap`` - (reported by `Bastien gerard `__) - - fix for issue 461 pop + insert on same `CommentedMap` key throwing error - (reported by `John Thorvald Wodder II `__) - -0.17.26 (2023-05-09): - - fix for error on edge cage for issue 459 - -0.17.25 (2023-05-09): - - fix for regression while dumping wrapped strings with too many backslashes removed - (issue 459, reported by `Lele Gaifax `__) - -0.17.24 (2023-05-06): - - rewrite of ``CommentedMap.insert()``. If you have a merge key in - the YAML document for the mapping you insert to, the position value should - be the one as you look at the YAML input. - This fixes issue 453 where other - keys of a merged in mapping would show up after an insert (reported by - `Alex Miller `__). It - also fixes a call to `.insert()` resulting into the merge key to move - to be the first key if it wasn't already and it is also now possible - to insert a key before a merge key (even if the fist key in the mapping). - - fix (in the pure Python implementation including default) for issue 447. - (reported by `Jack Cherng `__, - also brought up by brent on - `StackOverflow `__) - -0.17.23 (2023-05-05): - - fix 458, error on plain scalars starting with word longer than width. - (reported by `Kyle Larose `__) - - fix for ``.update()`` no longer correctly handling keyword arguments - (reported by John Lin on `__) - - fix issue 454: high Unicode (emojis) in quoted strings always - escaped (reported by `Michal Čihař `__ - based on a question on StackOverflow). - - fix issue with emitter conservatively inserting extra backslashes in wrapped - quoted strings (reported by thebenman on `StackOverflow - `__) - -0.17.22 (2023-05-02): - - - fix issue 449 where the second exclamation marks got URL encoded (reported - and fixing PR provided by `John Stark `__) - - fix issue with indent != 2 and literal scalars with empty first line - (reported by wrdis on `StackOverflow `__) - - updated __repr__ of CommentedMap, now that Python's dict is ordered -> no more - ordereddict(list-of-tuples) - - merge MR 4, handling OctalInt in YAML 1.1 - (provided by `Jacob Floyd `_) - - fix loading of `!!float 42` (reported by Eric on - `Stack overflow `_) - - line numbers are now set on `CommentedKeySeq` and `CommentedKeyMap` (which - are created if you have a sequence resp. mapping as the key in a mapping) - - plain scalars: put single words longer than width on a line of their own, instead - of after the previous line (issue 427, reported by `Antoine Cotten - `_). Caveat: this currently results in a - space ending the previous line. - - fix for folded scalar part of 421: comments after ">" on first line of folded - scalars are now preserved (as were those in the same position on literal scalars). - Issue reported by Jacob Floyd. - - added stacklevel to warnings - - typing changed from Py2 compatible comments to Py3, removed various Py2-isms - -0.17.21 (2022-02-12): - - fix bug in calling `.compose()` method with `pathlib.Path` instance. - -0.17.20 (2022-01-03): - - fix error in microseconds while rounding datetime fractions >= 9999995 - (reported by `Luis Ferreira `__) - -0.17.19 (2021-12-26): - - fix mypy problems (reported by `Arun `__) - -0.17.18 (2021-12-24): - - copy-paste error in folded scalar comment attachment (reported by `Stephan Geulette - `__) - - fix 411, indent error comment between key empty seq value (reported by `Guillermo Julián - `__) - -0.17.17 (2021-10-31): - - extract timestamp matching/creation to util - -0.17.16 (2021-08-28): - - 398 also handle issue 397 when comment is newline - -0.17.15 (2021-08-28): - - fix issue 397, insert comment before key when a comment between key and value exists - (reported by `Bastien gerard `__) - -0.17.14 (2021-08-25): - - fix issue 396, inserting key/val in merged-in dictionary (reported by `Bastien gerard - `__) - -0.17.13 (2021-08-21): - - minor fix in attr handling - -0.17.12 (2021-08-21): - - fix issue with anchor on registered class not preserved and those classes using package - attrs with `@attr.s()` (both reported by `ssph `__) - -0.17.11 (2021-08-19): - - fix error baseclass for ``DuplicateKeyError`` (reported by `Łukasz Rogalski - `__) - - fix typo in reader error message, causing `KeyError` during reader error - (reported by `MTU `__) - -0.17.10 (2021-06-24): - - fix issue 388, token with old comment structure != two elements - (reported by `Dimitrios Bariamis `__) - -0.17.9 (2021-06-10): - - fix issue with updating CommentedMap (reported by sri on - `StackOverflow `__) - -0.17.8 (2021-06-09): - - fix for issue 387 where templated anchors on tagged object did get set - resulting in potential id reuse. (reported by `Artem Ploujnikov - `__) - -0.17.7 (2021-05-31): - - issue 385 also affected other deprecated loaders (reported via email - by Oren Watson) - -0.17.6 (2021-05-31): - - merged type annotations update provided by - `Jochen Sprickerhof `__ - - fix for issue 385: deprecated round_trip_loader function not working - (reported by `Mike Gouline `__) - - wasted a few hours getting rid of mypy warnings/errors - -0.17.5 (2021-05-30): - - fix for issue 384 !!set with aliased entry resulting in broken YAML on rt - reported by `William Kimball `__) - -0.17.4 (2021-04-07): - - prevent (empty) comments from throwing assertion error (issue 351 - reported by `William Kimball `__) - comments (or empty line) will be dropped - -0.17.3 (2021-04-07): - - fix for issue 382 caused by an error in a format string (reported by - `William Kimball `__) - - allow expansion of aliases by setting ``yaml.composer.return_alias = lambda s: copy.deepcopy(s)`` - (as per `Stackoverflow answer `__) - -0.17.2 (2021-03-29): - - change -py2.py3-none-any.whl to -py3-none-any.whl, and remove 0.17.1 - -0.17.1 (2021-03-29): - - added 'Programming Language :: Python :: 3 :: Only', and removing - 0.17.0 from PyPI (reported by `Alasdair Nicol `__) - -0.17.0 (2021-03-26): - - removed because of incomplete classifiers - - this release no longer supports Python 2.7, most if not all Python 2 - specific code is removed. The 0.17.x series is the last to support Python 3.5 - (this also allowed for removal of the dependency on ``ruamel.std.pathlib``) - - remove Python2 specific code branches and adaptations (u-strings) - - prepare % code for f-strings using ``_F`` - - allow PyOxidisation (`issue 324 `__ - resp. `issue 171 `__) - - replaced Python 2 compatible enforcement of keyword arguments with '*' - - the old top level *functions* ``load``, ``safe_load``, ``round_trip_load``, - ``dump``, ``safe_dump``, ``round_trip_dump``, ``scan``, ``parse``, - ``compose``, ``emit``, ``serialize`` as well as their ``_all`` variants for - multi-document streams, now issue a ``PendingDeprecationning`` (e.g. when run - from pytest, but also Python is started with ``-Wd``). Use the methods on - ``YAML()``, which have been extended. - - fix for issue 376: indentation changes could put literal/folded scalar to start - before the ``#`` column of a following comment. Effectively making the comment - part of the scalar in the output. (reported by - `Bence Nagy `__) - - -0.16.13 (2021-03-05): - - fix for issue 359: could not update() CommentedMap with keyword arguments - (reported by `Steve Franchak `__) - - fix for issue 365: unable to dump mutated TimeStamp objects - (reported by Anton Akmerov `__) - - fix for issue 371: unable to addd comment without starting space - (reported by 'Mark Grandi `__) - - fix for issue 373: recursive call to walk_tree not preserving all params - (reported by `eulores `__) - - a None value in a flow-style sequence is now dumped as `null` instead - of `!!null ''` (reported by mcarans on - `StackOverflow `__) - -0.16.12 (2020-09-04): - - update links in doc - -0.16.11 (2020-09-03): - - workaround issue with setuptools 0.50 and importing pip ( fix by jaraco - https://github.com/pypa/setuptools/issues/2355#issuecomment-685159580 ) - -0.16.10 (2020-02-12): - - (auto) updated image references in README to sourceforge - -0.16.9 (2020-02-11): - - update CHANGES - -0.16.8 (2020-02-11): - - update requirements so that ruamel.yaml.clib is installed for 3.8, - as it has become available (via manylinux builds) - -0.16.7 (2020-01-30): - - fix typchecking issue on TaggedScalar (reported by Jens Nielsen) - - fix error in dumping literal scalar in sequence with comments before element - (reported by `EJ Etherington `__) - -0.16.6 (2020-01-20): - - fix empty string mapping key roundtripping with preservation of quotes as `? ''` - (reported via email by Tomer Aharoni). - - fix incorrect state setting in class constructor (reported by `Douglas Raillard - `__) - - adjust deprecation warning test for Hashable, as that no longer warns (reported - by `Jason Montleon `__) - -0.16.5 (2019-08-18): - - allow for ``YAML(typ=['unsafe', 'pytypes'])`` - -0.16.4 (2019-08-16): - - fix output of TAG directives with # (reported by `Thomas Smith - `__) - - -0.16.3 (2019-08-15): - - split construct_object - - change stuff back to keep mypy happy - - move setting of version based on YAML directive to scanner, allowing to - check for file version during TAG directive scanning - -0.16.2 (2019-08-15): - - preserve YAML and TAG directives on roundtrip, correctly output # - in URL for YAML 1.2 (both reported by `Thomas Smith - `__) - -0.16.1 (2019-08-08): - - Force the use of new version of ruamel.yaml.clib (reported by `Alex Joz - `__) - - Allow '#' in tag URI as these are allowed in YAML 1.2 (reported by - `Thomas Smith - `__) - -0.16.0 (2019-07-25): - - split of C source that generates .so file to ruamel.yaml.clib - - duplicate keys are now an error when working with the old API as well - - ----- - -For older changes see the file -`CHANGES `_ diff --git a/__init__.py b/__init__.py index b96961d..f8cfa43 100644 --- a/__init__.py +++ b/__init__.py @@ -5,9 +5,9 @@ _package_data = dict( full_package_name='ruamel.yaml', - version_info=(0, 17, 35), - __version__='0.17.35', - version_timestamp='2023-10-04 11:45:09', + version_info=(0, 18, 5), + __version__='0.18.5', + version_timestamp='2023-11-03 08:54:26', author='Anthon van der Neut', author_email='a.van.der.neut@ruamel.eu', description='ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order', # NOQA @@ -16,7 +16,7 @@ extras_require={ ':platform_python_implementation=="CPython" and python_version<"3.13"': ['ruamel.yaml.clib>=0.2.7'], # NOQA 'jinja2': ['ruamel.yaml.jinja2>=0.2'], - 'docs': ['ryd'], + 'docs': ['ryd', 'mercurial>5.7'], }, classifiers=[ 'Programming Language :: Python :: 3 :: Only', @@ -25,6 +25,7 @@ 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: Implementation :: CPython', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Text Processing :: Markup', @@ -38,8 +39,7 @@ fl8excl='_test/lib,branch_default', ), # universal=True, - python_requires='>=3', - rtfd='yaml', + python_requires='>=3.7', ) # type: Dict[Any, Any] diff --git a/_doc/README.ryd b/_doc/README.ryd new file mode 100644 index 0000000..f728607 --- /dev/null +++ b/_doc/README.ryd @@ -0,0 +1,120 @@ +version: 0.2 +text: md +pdf: false +order: +- overview.ryd +- install.ryd +- basicuse.ryd +- dumpcls.ryd +- detail.ryd +- example.ryd +- api.ryd +- pyyaml.ryd +- contributing.ryd +toc: False # don't index this file or put in mkdocs.nav +mkdocs: + site_name: yaml + docs_dir: _doc + site_author: Anthon van der Neut + + nav: + - overview.md + - install.md + - basicuse.md + - dumpcls.md + - detail.md + - example.md + - api.md + - pyyaml.md + - contributing.md + + theme: + name: readthedocs + + exclude_docs: | + *.ryd + *.rst + + markdown_extensions: + - toc: + permalink: true +--- | +# ruamel.yaml + +`ruamel.yaml` is a YAML 1.2 loader/dumper package for Python. + +--- !table +version: !Env version +updated: !Env date +documentation: https://yaml.readthedocs.io +repository: https://sourceforge.net/projects/ruamel-yaml +pypi: https://pypi.org/project/ruamel.yaml +--- | + +As announced, in 0.18.0, the old PyYAML functions have been deprecated. +(`scan`, `parse`, `compose`, `load`, `emit`, `serialize`, `dump` and their variants +(`_all`, `safe_`, `round_trip_`, etc)). If you only read this after your program has +stopped working: I am sorry to hear that, but that also means you, or the person +developing your program, has not tested with warnings on (which is the recommendation +in PEP 565, and e.g. defaultin when using `pytest`). If you have troubles, explicitly use +``` +pip install "ruamel.yaml<0.18.0" +``` +or put something to that effects in your requirments, to give yourself +some time to solve the issue. + +There will be at least one more potentially breaking change in the 0.18 series: `YAML(typ='unsafe')` +now has a pending deprecation warning and is going to be deprecated, probably before the end of 2023. +If you only use it to dump, please use the new `YAML(typ='full')`, the result of that can be *safely* +loaded with a default instance `YAML()`, as that will get you inspectable, tagged, scalars, instead of +executed Python functions/classes. (You should probably add constructors for what you actually need, +but I do consider adding a `ruamel.yaml.unsafe` package that will re-add the `typ='unsafe'` option. +*Please adjust/pin your dependencies accordingly if necessary.* + + +There seems to be a CVE on `ruamel.yaml`, stating that the `load()` function could be abused +because of unchecked input. `load()` was never the default function (that was `round_trip_load()` +before the new API came into existence`. So the creator of that CVE was ill informed and +probably lazily assumed that since `ruamel.yaml` is a derivative of PyYAML (for which +a similar CVE exists), the same problem would still exist, without checking. +So the CVE was always inappriate, now just more so, as the call +to the function `load()` with any input will terminate your program with an error message. If you +(have to) care about such things as this CVE, my recommendation is to stop using Python +completely, as `pickle.load()` can be abused in the same way as `load()` (and like unlike `load()` +is only documented to be unsafe, without development-time warning. + +Version 0.17.21 was the last one tested to be working on Python 3.5 and 3.6
+The 0.16.13 release was the last that was tested to be working on Python 2.7. + + +There are two extra plug-in packages +(`ruamel.yaml.bytes` and `ruamel.yaml.string`) +for those not wanting to do the streaming to a +`io.BytesIO/StringIO` buffer themselves. + +If your package uses `ruamel.yaml` and is not listed on PyPI, drop me an +email, preferably with some information on how you use the package (or a +link to the repository) and I'll keep you informed when the status of +the API is stable enough to make the transition. + +--- !toc +level: 3 +# prefix: http://yaml.readthedocs.io/en/latest/ +--- | + +[![image](https://readthedocs.org/projects/yaml/badge/?version=latest)](https://yaml.readthedocs.org/en/latest?badge=latest)[![image](https://bestpractices.coreinfrastructure.org/projects/1128/badge)](https://bestpractices.coreinfrastructure.org/projects/1128) +[![image](https://sourceforge.net/p/ruamel-yaml/code/ci/default/tree/_doc/_static/license.svg?format=raw)](https://opensource.org/licenses/MIT) +[![image](https://sourceforge.net/p/ruamel-yaml/code/ci/default/tree/_doc/_static/pypi.svg?format=raw)](https://pypi.org/project/ruamel.yaml/) +[![image](https://sourceforge.net/p/oitnb/code/ci/default/tree/_doc/_static/oitnb.svg?format=raw)](https://pypi.org/project/oitnb/) +[![image](http://www.mypy-lang.org/static/mypy_badge.svg)](http://mypy-lang.org/) + +# ChangeLog + +--- !changelog +CHANGES +--- | + +------------------------------------------------------------------------ + +For older changes see the file +[CHANGES](https://sourceforge.net/p/ruamel-yaml/code/ci/default/tree/CHANGES) diff --git a/_doc/_static/pypi.svg b/_doc/_static/pypi.svg index 6703d59..868101a 100644 --- a/_doc/_static/pypi.svg +++ b/_doc/_static/pypi.svg @@ -1 +1 @@ - pypipypi0.17.350.17.35 + pypipypi0.18.50.18.5 diff --git a/_doc/api.ryd b/_doc/api.ryd index 8bdf9a4..c0e1a7d 100644 --- a/_doc/api.ryd +++ b/_doc/api.ryd @@ -1,7 +1,6 @@ version: 0.2 -text: rst -fix_inline_single_backquotes: true -pdf: true +text: md +pdf: false --- !python-pre | import sys from io import StringIO @@ -13,51 +12,47 @@ istream = stream = doc = "a: 1" data = dict(a=1) from pathlib import Path # or: from ruamel.std.pathlib import Path --- | -+++++++++++++++++++++++++++ -Departure from previous API -+++++++++++++++++++++++++++ +# Departure from previous API -With version 0.15.0 ``ruamel.yaml`` starts to depart from the previous (PyYAML) way -of loading and dumping. During a transition period the original -``load()`` and ``dump()`` in its various formats will still be supported, -but this is not guaranteed to be so with the transition to 1.0. +With version 0.15.0 `ruamel.yaml` starts to depart from the previous +(PyYAML) way of loading and dumping. During a transition period the +original `load()` and `dump()` in its various formats will still be +supported, but this is not guaranteed to be so with the transition to +1.0. At the latest with 1.0, but possible earlier transition error and warning messages will be issued, so any packages depending on ruamel.yaml should pin the version with which they are testing. - -Up to 0.15.0, the loaders (``load()``, ``safe_load()``, -``round_trip_load()``, ``load_all``, etc.) took, apart from the input -stream, a ``version`` argument to allow downgrading to YAML 1.1, -sometimes needed for +Up to 0.15.0, the loaders (`load()`, `safe_load()`, `round_trip_load()`, +`load_all`, etc.) took, apart from the input stream, a `version` +argument to allow downgrading to YAML 1.1, sometimes needed for documents without directive. When round-tripping, there was an option to preserve quotes. -Up to 0.15.0, the dumpers (``dump()``, ``safe_dump``, -``round_trip_dump()``, ``dump_all()``, etc.) had a plethora of -arguments, some inherited from ``PyYAML``, some added in -``ruamel.yaml``. The only required argument is the ``data`` to be -dumped. If the stream argument is not provided to the dumper, then a -string representation is build up in memory and returned to the -caller. +Up to 0.15.0, the dumpers (`dump()`, `safe_dump`, `round_trip_dump()`, +`dump_all()`, etc.) had a plethora of arguments, some inherited from +`PyYAML`, some added in `ruamel.yaml`. The only required argument is the +`data` to be dumped. If the stream argument is not provided to the +dumper, then a string representation is build up in memory and returned +to the caller. -Starting with 0.15.0 ``load()`` and ``dump()`` are methods on a -``YAML`` instance and only take the stream, -resp. the data and stream argument. All other parameters are set on the instance -of ``YAML`` before calling ``load()`` or ``dump()`` +Starting with 0.15.0 `load()` and `dump()` are methods on a `YAML` +instance and only take the stream, resp. the data and stream argument. +All other parameters are set on the instance of `YAML` before calling +`load()` or `dump()` Before 0.15.0 you could do: -.. code:: python - - from pathlib import Path - from ruamel import yaml +``` python +from pathlib import Path +from ruamel import yaml - data = yaml.safe_load("abc: 1") - out = Path('/tmp/out.yaml') - with out.open('w') as fp: - yaml.safe_dump(data, fp, default_flow_style=False) +data = yaml.safe_load("abc: 1") +out = Path('/tmp/out.yaml') +with out.open('w') as fp: + yaml.safe_dump(data, fp, default_flow_style=False) +``` after: --- !python | @@ -70,51 +65,48 @@ data = yaml.load("abc: 1") out = Path('/tmp/out.yaml') yaml.dump(data, out) --- | -If you previously used a keyword argument ``explicit_start=True`` you -now do ``yaml.explicit_start = True`` before calling ``dump()``. The -``Loader`` and ``Dumper`` keyword arguments are not supported that -way. You can provide the ``typ`` keyword to ``rt`` (default), -``safe``, ``unsafe`` or ``base`` (for round-trip load/dump, safe_load/dump, -load/dump resp. using the BaseLoader / BaseDumper. More fine-control -is possible by setting the attributes ``.Parser``, ``.Constructor``, -``.Emitter``, etc., to the class of the type to create for that stage -(typically a subclass of an existing class implementing that). - -The default loader (``typ='rt'``) is a direct derivative of the safe loader, without the -methods to construct arbitrary Python objects that make the ``unsafe`` loader -unsafe, but with the changes needed for round-trip preservation of comments, -etc.. For trusted Python classes a constructor can of course be added to the round-trip -or safe-loader, but this has to be done explicitly (``add_constructor``). - -All data is dumped (not just for round-trip-mode) with ``.allow_unicode -= True`` - -You can of course have multiple YAML instances active at the same -time, with different load and/or dump behaviour. +If you previously used a keyword argument `explicit_start=True` you now +do `yaml.explicit_start = True` before calling `dump()`. The `Loader` +and `Dumper` keyword arguments are not supported that way. You can +provide the `typ` keyword to `rt` (default), `safe`, `unsafe` or `base` +(for round-trip load/dump, safe_load/dump, load/dump resp. using the +BaseLoader / BaseDumper. More fine-control is possible by setting the +attributes `.Parser`, `.Constructor`, `.Emitter`, etc., to the class of +the type to create for that stage (typically a subclass of an existing +class implementing that). + +The default loader (`typ='rt'`) is a direct derivative of the safe +loader, without the methods to construct arbitrary Python objects that +make the `unsafe` loader unsafe, but with the changes needed for +round-trip preservation of comments, etc.. For trusted Python classes a +constructor can of course be added to the round-trip or safe-loader, but +this has to be done explicitly (`add_constructor`). + +All data is dumped (not just for round-trip-mode) with +`.allow_unicode = True` + +You can of course have multiple YAML instances active at the same time, +with different load and/or dump behaviour. Initially only the typical operations are supported, but in principle -all functionality of the old interface will be available via -``YAML`` instances (if you are using something that isn't let me know). +all functionality of the old interface will be available via `YAML` +instances (if you are using something that isn\'t let me know). If a parse or dump fails, and throws and exception, the state of the -``YAML()`` instance is not guaranteed to be able to handle further -processing. You should, at that point to recreate the YAML instance before -proceeding. - +`YAML()` instance is not guaranteed to be able to handle further +processing. You should, at that point to recreate the YAML instance +before proceeding. -Loading -+++++++ +## Loading -Duplicate keys -^^^^^^^^^^^^^^ +### Duplicate keys In JSON mapping keys should be unique, in YAML they must be unique. PyYAML never enforced this although the YAML 1.1 specification already required this. -In the new API (starting 0.15.1) duplicate keys in mappings are no longer allowed by -default. To allow duplicate keys in mappings: - +In the new API (starting 0.15.1) duplicate keys in mappings are no +longer allowed by default. To allow duplicate keys in mappings: --- !python | yaml = ruamel.yaml.YAML() yaml.allow_duplicate_keys = True @@ -123,32 +115,29 @@ yaml.load(stream) In the old API this is a warning starting with 0.15.2 and an error in 0.16.0. -When a duplicate key is found it and its value are discarded, as should be done -according to the `YAML 1.1 specification `__. - -Dumping a multi-documents YAML stream -+++++++++++++++++++++++++++++++++++++ +When a duplicate key is found it and its value are discarded, as should +be done according to the [YAML 1.1 +specification](http://yaml.org/spec/1.1/#id932806). -The "normal" ``dump_all`` expected as first element a list of documents, or -something else the internals of the method can iterate over. To read -and write a multi-document you would either make a ``list``:: +## Dumping a multi-document YAML stream +The \"normal\" `dump_all` expected as first element a list of documents, +or something else the internals of the method can iterate over. To read +and write a multi-document you would either make a `list`: --- !code | yaml = YAML() data = list(yaml.load_all(in_path)) # do something on data[0], data[1], etc. yaml.dump_all(data, out_path) --- | +or create some function/object that would yield the `data` values. -or create some function/object that would yield the ``data`` values. - -What you now can do is create ``YAML()`` as an context manager. This -works for output (dumping) only, requires you to specify the output -(file, buffer, ``Path``) at creation time, and doesn't support -``transform`` (yet). - -:: +What you now can do is create `YAML()` as an context manager. This works +for output (dumping) only, requires you to specify the output (file, +buffer, `Path`) at creation time, and doesn\'t support `transform` +(yet). +: --- !code | with YAML(output=sys.stdout) as yaml: yaml.explicit_start = True @@ -156,16 +145,14 @@ works for output (dumping) only, requires you to specify the output # do something on data yaml.dump(data) --- | - -Within the context manager, you cannot use the ``dump()`` with a -second (stream) argument, nor can you use ``dump_all()``. The -``dump()`` within the context of the ``YAML()`` automatically creates -multi-document if called more than once. +Within the context manager, you cannot use the `dump()` with a second +(stream) argument, nor can you use `dump_all()`. The `dump()` within the +context of the `YAML()` automatically creates multi-document if called +more than once. To combine multiple YAML documents from multiple files: -:: - +: --- !code | list_of_filenames = ['x.yaml', 'y.yaml', ] with YAML(output=sys.stdout) as yaml: @@ -174,46 +161,44 @@ To combine multiple YAML documents from multiple files: with open(path) as fp: yaml.dump(yaml.load(fp)) --- | - The output will be a valid, uniformly indented YAML file. Doing -``cat {x,y}.yaml`` might result in a single document if there is not -document start marker at the beginning of ``y.yaml`` - +`cat {x,y}.yaml` might result in a single document if there is not +document start marker at the beginning of `y.yaml` +## Dumping +### Controls -Dumping -+++++++ +On your `YAML()` instance you can set attributes e.g with: -Controls -^^^^^^^^ + yaml = YAML(typ='safe', pure=True) + yaml.allow_unicode = False -On your ``YAML()`` instance you can set attributes e.g with:: +available attributes include: - yaml = YAML(typ='safe', pure=True) - yaml.allow_unicode = False +`unicode_supplementary` -available attributes include: +: Defaults to `True` if Python\'s Unicode size is larger than 2 bytes. + Set to `False` to enforce output of the form `\U0001f601` (ignored + if `allow_unicode` is `False`) -``unicode_supplementary`` - Defaults to ``True`` if Python's Unicode size is larger than 2 bytes. Set to ``False`` to - enforce output of the form ``\U0001f601`` (ignored if ``allow_unicode`` is ``False``) +## Transparent usage of new and old API -Transparent usage of new and old API -++++++++++++++++++++++++++++++++++++ +With 0.18 the entry functions for the old API has been removed, so the +following now only makes sense if you use the old API on a pinned +old version or `ruamel.yaml`. -If you have multiple packages depending on ``ruamel.yaml``, or install +If you have multiple packages depending on `ruamel.yaml`, or install your utility together with other packages not under your control, then -fixing your ``install_requires`` might not be so easy. +fixing your `install_requires` might not be so easy. -Depending on your usage you might be able to "version" your usage to +Depending on your usage you might be able to \"version\" your usage to be compatible with both the old and the new. The following are some -examples all assuming ``from ruamel import yaml`` somewhere at the top -of your file and some ``istream`` and ``ostream`` apropriately opened -for reading resp. writing. +examples all assuming `from ruamel import yaml` somewhere at the top of +your file and some `istream` and `ostream` apropriately opened for +reading resp. writing. - -Loading and dumping using the ``SafeLoader``:: +Loading and dumping using the `SafeLoader`: if ruamel.yaml.version_info < (0, 15): data = yaml.safe_load(istream) @@ -223,9 +208,8 @@ Loading and dumping using the ``SafeLoader``:: data = yml.load(istream) yml.dump(data, ostream) -Loading with the ``CSafeLoader``, dumping with -``RoundTripLoader``. You need two ``YAML`` instances, but each of them -can be re-used: +Loading with the `CSafeLoader`, dumping with `RoundTripLoader`. You need +two `YAML` instances, but each of them can be re-used: --- !python | if ruamel.yaml.version_info < (0, 15): data = yaml.load(istream, Loader=yaml.CSafeLoader) @@ -238,9 +222,8 @@ else: ymlo.explicit_start = True ymlo.dump(data, ostream) --- | -Loading and dumping from ``pathlib.Path`` instances using the -round-trip-loader:: - +Loading and dumping from `pathlib.Path` instances using the +round-trip-loader: --- !code | # in myyaml.py if ruamel.yaml.version_info < (0, 15): @@ -272,57 +255,54 @@ else: data = yml.load(inf) yml.dump(data, outf) --- | -+++++++++++++++++++++ -Reason for API change -+++++++++++++++++++++ +## Reason for API change -``ruamel.yaml`` inherited the way of doing things from ``PyYAML``. In -particular when calling the function ``load()`` or ``dump()`` -temporary instances of ``Loader()`` resp. ``Dumper()`` were -created that were discarded on termination of the function. +`ruamel.yaml` inherited the way of doing things from `PyYAML`. In +particular when calling the function `load()` or `dump()` temporary +instances of `Loader()` resp. `Dumper()` were created that were +discarded on termination of the function. This way of doing things leads to several problems: -- it is virtually impossible to return information to the caller apart from the - constructed data structure. E.g. if you would get a YAML document - version number from a directive, there is no way to let the caller - know apart from handing back special data structures. The same - problem exists when trying to do on the fly - analysis of a document for indentation width. - -- these instances were composites of the various load/dump steps and - if you wanted to enhance one of the steps, you needed e.g. subclass - the emitter and make a new composite (dumper) as well, providing all - of the parameters (i.e. copy paste) - - Alternatives, like making a class that returned a ``Dumper`` when - called and sets attributes before doing so, is cumbersome for - day-to-day use. - -- many routines (like ``add_representer()``) have a direct global - impact on all of the following calls to ``dump()`` and those are - difficult if not impossible to turn back. This forces the need to - subclass ``Loaders`` and ``Dumpers``, a long time problem in PyYAML - as some attributes were not ``deep_copied`` although a bug-report - (and fix) had been available a long time. - -- If you want to set an attribute, e.g. to control whether literal - block style scalars are allowed to have trailing spaces on a line - instead of being dumped as double quoted scalars, you have to change - the ``dump()`` family of routines, all of the ``Dumpers()`` as well - as the actual functionality change in ``emitter.Emitter()``. The - functionality change takes changing 4 (four!) lines in one file, and being able - to enable that another 50+ line changes (non-contiguous) in 3 more files resulting - in diff that is far over 200 lines long. - -- replacing libyaml with something that doesn't both support ``0o52`` - and ``052`` for the integer ``42`` (instead of ``52`` as per YAML 1.2) - is difficult - - -With ``ruamel.yaml>=0.15.0`` the various steps "know" about the -``YAML`` instance and can pick up setting, as well as report back -information via that instance. Representers, etc., are added to a -reusable instance and different YAML instances can co-exists. +- it is virtually impossible to return information to the caller apart + from the constructed data structure. E.g. if you would get a YAML + document version number from a directive, there is no way to let the + caller know apart from handing back special data structures. The + same problem exists when trying to do on the fly analysis of a + document for indentation width. + +- these instances were composites of the various load/dump steps and + if you wanted to enhance one of the steps, you needed e.g. subclass + the emitter and make a new composite (dumper) as well, providing all + of the parameters (i.e. copy paste) + + Alternatives, like making a class that returned a `Dumper` when + called and sets attributes before doing so, is cumbersome for + day-to-day use. + +- many routines (like `add_representer()`) have a direct global impact + on all of the following calls to `dump()` and those are difficult if + not impossible to turn back. This forces the need to subclass + `Loaders` and `Dumpers`, a long time problem in PyYAML as some + attributes were not `deep_copied` although a bug-report (and fix) + had been available a long time. + +- If you want to set an attribute, e.g. to control whether literal + block style scalars are allowed to have trailing spaces on a line + instead of being dumped as double quoted scalars, you have to change + the `dump()` family of routines, all of the `Dumpers()` as well as + the actual functionality change in `emitter.Emitter()`. The + functionality change takes changing 4 (four!) lines in one file, and + being able to enable that another 50+ line changes (non-contiguous) + in 3 more files resulting in diff that is far over 200 lines long. + +- replacing libyaml with something that doesn\'t both support `0o52` + and `052` for the integer `42` (instead of `52` as per YAML 1.2) is + difficult + +With `ruamel.yaml>=0.15.0` the various steps \"know\" about the `YAML` +instance and can pick up setting, as well as report back information via +that instance. Representers, etc., are added to a reusable instance and +different YAML instances can co-exists. This change eases development and helps prevent regressions. diff --git a/_doc/basicuse.ryd b/_doc/basicuse.ryd index 35e7c38..cce50d8 100644 --- a/_doc/basicuse.ryd +++ b/_doc/basicuse.ryd @@ -1,7 +1,6 @@ version: 0.2 -text: rst -fix_inline_single_backquotes: true -pdf: true +text: md +pdf: false --- !python-pre | import sys from io import StringIO @@ -11,9 +10,8 @@ s = StringIO() doc = "a: 1" data = dict(a=1) --- | -*********** -Basic Usage -*********** +# Basic Usage +## Load and dump You load a YAML document using: --- !python | @@ -23,14 +21,15 @@ yaml=YAML(typ='safe') # default, if not specfied, is 'rt' (round-trip) yaml.load(doc) --- | -in this ``doc`` can be a file pointer (i.e. an object that has the -``.read()`` method, a string or a ``pathlib.Path()``. ``typ='safe'`` -accomplishes the same as what ``safe_load()`` did before: loading of a -document without resolving unknown tags. Provide ``pure=True`` to -enforce using the pure Python implementation, otherwise the faster C libraries will be used -when possible/available but these behave slightly different (and sometimes more like a YAML 1.1 loader). +in this `doc` can be a file pointer (i.e. an object that has the +`.read()` method, a string or a `pathlib.Path()`. `typ='safe'` +accomplishes the same as what `safe_load()` did before: loading of a +document without resolving unknown tags. Provide `pure=True` to enforce +using the pure Python implementation, otherwise the faster C libraries +will be used when possible/available but these behave slightly different +(and sometimes more like a YAML 1.1 loader). -Dumping works in the same way:: +Dumping works in the same way: --- !code | from ruamel.yaml import YAML @@ -38,13 +37,12 @@ yaml=YAML() yaml.default_flow_style = False yaml.dump({'a': [1, 2]}, s) --- | -in this ``s`` can be a file pointer (i.e. an object that has the -``.write()`` method, or a ``pathlib.Path()``. If you want to display -your output, just stream to ``sys.stdout``. - -If you need to transform a string representation of the output provide -a function that takes a string as input and returns one: +in this `s` can be a file pointer (i.e. an object that has the +`.write()` method, or a `pathlib.Path()`. If you want to display your +output, just stream to `sys.stdout`. +If you need to transform a string representation of the output provide a +function that takes a string as input and returns one: --- !python | def tr(s): return s.replace('\n', '<\n') # such output is not valid YAML! @@ -52,12 +50,11 @@ def tr(s): yaml.dump(data, sys.stdout, transform=tr) --- | -More examples -============= +## More examples Using the C based SafeLoader (at this time is inherited from -libyaml/PyYAML and e.g. loads ``0o52`` as well as ``052`` load as integer ``42``): - +libyaml/PyYAML and e.g. loads `0o52` as well as `052` as integer +`42`): --- !python | from ruamel.yaml import YAML @@ -65,9 +62,16 @@ libyaml/PyYAML and e.g. loads ``0o52`` as well as ``052`` load as integer ``42`` yaml.load("""a:\n b: 2\n c: 3\n""") --- | -Using the Python based SafeLoader (YAML 1.2 support, ``052`` loads as ``52``): +Using the Python based SafeLoader (YAML 1.2 support, `052` loads as +`52`): --- !python | from ruamel.yaml import YAML yaml=YAML(typ="safe", pure=True) yaml.load("""a:\n b: 2\n c: 3\n""") + +--- | + +Restrictions when using the C based SafeLoader/SafeDumper: + +- yaml.indent will set the same value for mappings and sequences. (Issue 471) diff --git a/_doc/conf.py b/_doc/conf.py index 1c4a02d..3b4f6c8 100644 --- a/_doc/conf.py +++ b/_doc/conf.py @@ -85,6 +85,7 @@ class ryd2rst: except Exception as e: print('ryd exception', e) + raise # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/_doc/contributing.ryd b/_doc/contributing.ryd index 8c76325..24e351b 100644 --- a/_doc/contributing.ryd +++ b/_doc/contributing.ryd @@ -1,134 +1,139 @@ version: 0.2 -text: rst -fix_inline_single_backquotes: true -pdf: true +text: md +pdf: false --- | -************ -Contributing -************ +# Contributing -Any contribution to ``ruamel.yaml`` is welcome, be it in the form of an -email, a question on stackoverflow (I'll get notified of that when you tag it -with ``ruamel.yaml``), an issue or pull-request (PR) on sourceforge. +Any contribution to `ruamel.yaml` is welcome, be it in the form of an +email, a question on stackoverflow (I\'ll get notified of that when you +tag it with `ruamel.yaml`), an issue or pull-request (PR) on +sourceforge. -Contributing via stackoverflow is, for most, easy to do. When I answer your -question there and the answer warrants an extension to the documentation or -code, I will include it in a documentation update and/or future (normally the -next) release of ``ruamel.yaml``. +Contributing via stackoverflow is, for most, easy to do. When I answer +your question there and the answer warrants an extension to the +documentation or code, I will include it in a documentation update +and/or future (normally the next) release of `ruamel.yaml`. -Please don't post support questions as an issue on sourceforge. +Please don\'t post support questions as an issue on sourceforge. -Documentation -============= +## Documentation -The documentation for ``ruamel.yaml`` is in YAML, more specifically in `ryd -`_ ( /rɑɪt/, pronounced like the verb “write” -). This is reStructuredText mixed with Python, each in separate YAML documents -within a single file. If you know a bit of YAML, Python and reStructuredText it -will be clear how that works. +The documentation for `ruamel.yaml` is in YAML, more specifically in +[ryd](https://pypi.python.org/pypi/ryd) ( /rɑɪt/, pronounced like the +verb "write" ). This is Markdown (previously reStructuredText) +mixed with Python, each in +separate YAML documents within a single file. If you know a bit of YAML, +Python and Markdown, it will be clear how that works. If you want to contribute to the documentation, you can send me a clear -description of the needed changes, e.g. as a unified diff. If the changes -encompass multiple documents in a ``.ryd`` file, it is best to install ``ryd`` -(use a virtualenv!), clone the ``ruamel.yaml`` repository on sourceforge, edit -documentation, run ``ryd``:: +description of the needed changes, e.g. as a unified diff. If the +changes encompass multiple documents in a `.ryd` file, it is best to +install `ryd` (use a virtualenv!), clone the `ruamel.yaml` repository on +sourceforge, edit documentation, run `ryd`: - ryd --pdf '**/*.ryd' + ryd --pdf '**/*.ryd' -(quoting might not be necessary depending on your shell), and once the PDF(s) -look acceptable, submit a pull-request. +(quoting might not be necessary depending on your shell), and once the +PDF(s) look acceptable, submit a pull-request. -``ryd`` will check your file for single backquotes (my most common mistake going -back and forth between reStructuredText and other mark up). +`ryd` will check your file for single backquotes (my most common mistake +going back and forth between reStructuredText and other mark up). -If you contribute example programs, note that ``ryd`` will automatically run your -program (so it should be correct) and can include the output of the program in -the resulting ``.rst`` (and PDF) file. +If you contribute example programs, note that `ryd` will automatically +run your program (so it should be correct) and can include the output of +the program in the resulting `.rst` (and PDF) file. -Code -==== +## Code -Code changes are welcome as well, but anything beyond a minor change should be -tested (``tox``/``pytest``), checked for typing conformance (``mypy``) and pass -pep8 conformance (``flake8``). +Code changes are welcome as well, but anything beyond a minor change +should be tested (`tox`/`pytest`), checked for typing conformance +(`mypy`) and pass pep8 conformance (`flake8`). -In my experience it is best to use two ``virtualenv`` environments, one with the -latest Python from the 2.7 series, the other with 3.5 or 3.6. In the -site-packages directory of each virtualenv make a soft link to the ruamel -directory of your (cloned and checked out) copy of the repository. Do not under -any circumstances run ``pip install -e .`` or ``python setup.py -e .`` it will -not work (at least not until these commands are fixed to support packages with -namespaces). +In my experience it is best to use two `virtualenv` environments, one +with the latest Python version currently supported, the other with +the oldest supported version. +In the site-packages directory of each virtualenv make a soft link to +the ruamel directory of your (cloned and checked out) copy of the +repository. Do not under any circumstances run `pip install -e .` or +`python setup.py -e .` it will not work (at least not until these +commands are fixed to support packages with namespaces). -You can install ``tox``, ``pytest``, ``mypy`` and ``flake8`` in the Python3 -``virtualenv``, or in a ``virtualenv`` of their own. If all of these commands -pass without warning/error, you can create your pull-request. +You can install `tox`, `pytest`, `mypy` and `flake8` in the Python3 +`virtualenv`, or in a `virtualenv` of their own. If all of these +commands pass without warning/error, you can create your pull-request. -Flake -+++++ +### Flake -My ``~/.config/flake8`` file:: +My `~/.config/flake8` file: - [flake8] - show-source = True - max-line-length = 95 - ignore = F405 + [flake8] + show-source = True + max-line-length = 95 + ignore = F405 -The suppress of F405 is necessary to allow ``from xxx import *``, which I have -not removed in all places (yet). +The suppress of F405 is necessary to allow `from xxx import *`, which I +have not removed in all places (yet). -First make sure your checked out source passes ``flake8`` without test (it should). -Then make your changes pass without any warnings/errors. +First make sure your checked out source passes `flake8` without test (it +should). Then make your changes pass without any warnings/errors. -Tox/pytest -++++++++++ +### Tox/pytest -Whether you add something or fix some bug with your code changes, first add one -or more tests that fail in the unmodified source when running ``tox``. Once that -is in place add your code, which should have as a result that your added test(s) -no longer fail, and neither should any other existing tests. +Whether you add something or fix some bug with your code changes, first +add one or more tests that fail in the unmodified source when running +`tox`. Once that is in place add your code, which should have as a +result that your added test(s) no longer fail, and neither should any +other existing tests. -Typing/mypy -+++++++++++ +### Typing/mypy -If you add methods or functions to ``ruamel.yaml``, you will need to add Python -2.7 compatible typing information in order for ``mypy`` to pass without error. +If you add methods or functions to `ruamel.yaml`, you will need to add +Python 2.7 compatible typing information in order for `mypy` to pass +without error. -I run ``mypy`` from the directory where the (link to) ruamel directory is -using:: +I run `mypy` from the directory where the (link to) ruamel directory is +using: mypy --py2 --strict --follow-imports silent ruamel/yaml/*.py This should give no errors or warnings - -Generated files -=============== - -I use a minimal environment when developing, void of most artifacts needed for -packaging, testing etc. These artifact files are *generated*, just before committing to -sourceforge and pushing to PyPI, with nuances coming from the ``_package_data`` -information in ``__init__.py``. Included changes in these files will -automatically be reverted, even assuming your PR is accepted as is. - -Consider the following files **read-only** (if you think changes need to be made -to these, contact me):: - - setup.py - tox.ini - LICENSE - _ryd/conf.py - -ryd/Makefile - - -Vulnerabilities -=============== - -If you find a vulnerability in ``ruamel.yaml`` (e.g. that would show the ``safe`` -and ``rt`` loader are not safe due to a bug in the software)), please contact me -directly via email, or by leaving a comment on StackOverflow (below any of my -posts), without going into the details about the vulnerability. After contact is -estabilished I will work to eliminate the vulnerability in a timely fashion. -After the vulnerability is removed, and affected parties haven been notified to -allow them to update versions, the vulnerability will be published, and your role -in finding/resolving this properly attributed. +## Generated files + +I use a minimal environment when developing, void of most artifacts +needed for packaging, testing etc. These artifact files are *generated*, +just before committing to sourceforge and pushing to PyPI, with nuances +coming from the `_package_data` information in `__init__.py`. Included +changes in these files will automatically be reverted, even assuming +your PR is accepted as is. + +Consider the following files **read-only** (if you think changes need to +be made to these, contact me): + + setup.py + tox.ini + LICENSE + _ryd/conf.py + -ryd/Makefile + +## Vulnerabilities + +If you find a vulnerability in `ruamel.yaml` (e.g. that would show the +`safe` and `rt` loader are not safe due to a bug in the software)), +please contact me directly via email, or by leaving a comment on +StackOverflow (below any of my posts), without going into the details +about the vulnerability. After contact is estabilished I will work to +eliminate the vulnerability in a timely fashion. After the vulnerability +is removed, and affected parties haven been notified to allow them to +update versions, the vulnerability will be published, and your role in +finding/resolving this properly attributed. + +Please note that there is a CVE out there against `ruamel.yaml`, that states +that the input of the function `load()` is not checked. As the +use of `ruamel.yaml.load()` was never the default, was documented to potentially +cause problems when specific parameters were provided, and issued a +warning, this was always an inappropriate statement. +(To compare: no such CVE was given for the use of the Python standard library +function `pickle.load`, which only documents which is default function +to use and only documented to potentially dangerious). The whole CVE is moot, +with the removal of the `load()` function 0.18. diff --git a/_doc/detail.ryd b/_doc/detail.ryd index b25c939..26ce7f0 100644 --- a/_doc/detail.ryd +++ b/_doc/detail.ryd @@ -1,165 +1,168 @@ version: 0.2 -text: rst -fix_inline_single_backquotes: true +text: md +pdf: false --- | -******* -Details -******* - - - -- support for simple lists as mapping keys by transforming these to tuples -- ``!!omap`` generates ordereddict (C) on Python 2, collections.OrderedDict - on Python 3, and ``!!omap`` is generated for these types. -- Tests whether the C yaml library is installed as well as the header - files. That library doesn't generate CommentTokens, so it cannot be used to - do round trip editing on comments. It can be used to speed up normal - processing (so you don't need to install ``ruamel.yaml`` and ``PyYaml``). - See the section *Optional requirements*. -- Basic support for multiline strings with preserved newlines and - chomping ( '``|``', '``|+``', '``|-``' ). As this subclasses the string type - the information is lost on reassignment. (This might be changed - in the future so that the preservation/folding/chomping is part of the - parent container, like comments). -- anchors names that are hand-crafted (not of the form``idNNN``) are preserved -- `merges `_ in dictionaries are preserved -- adding/replacing comments on block-style sequences and mappings - with smart column positioning -- collection objects (when read in via RoundTripParser) have an ``lc`` - property that contains line and column info ``lc.line`` and ``lc.col``. - Individual positions for mappings and sequences can also be retrieved - (``lc.key('a')``, ``lc.value('a')`` resp. ``lc.item(3)``) -- preservation of whitelines after block scalars. Contributed by Sam Thursfield. - -*In the following examples it is assumed you have done something like:*:: - - from ruamel.yaml import YAML - yaml = YAML() +# Details + +- support for simple lists as mapping keys by transforming these to + tuples +- `!!omap` generates ordereddict (C) on Python 2, + collections.OrderedDict on Python 3, and `!!omap` is generated for + these types. +- Tests whether the C yaml library is installed as well as the header + files. That library doesn\'t generate CommentTokens, so it cannot be + used to do round trip editing on comments. It can be used to speed + up normal processing (so you don\'t need to install `ruamel.yaml` + and `PyYaml`). See the section *Optional requirements*. +- Basic support for multiline strings with preserved newlines and + chomping ( \'`|`\', \'`|+`\', \'`|-`\' ). As this subclasses the + string type the information is lost on reassignment. (This might be + changed in the future so that the preservation/folding/chomping is + part of the parent container, like comments). +- anchors names that are hand-crafted (not of the form`idNNN`) are + preserved +- [merges](http://yaml.org/type/merge.html) in dictionaries are + preserved +- adding/replacing comments on block-style sequences and mappings with + smart column positioning +- collection objects (when read in via RoundTripParser) have an `lc` + property that contains line and column info `lc.line` and `lc.col`. + Individual positions for mappings and sequences can also be + retrieved (`lc.key('a')`, `lc.value('a')` resp. `lc.item(3)`) +- preservation of whitelines after block scalars. Contributed by Sam + Thursfield. + +*In the following examples it is assumed you have done something like:*: + + from ruamel.yaml import YAML + yaml = YAML() *if not explicitly specified.* -Indentation of block sequences -============================== +## Indentation of block sequences -Although ruamel.yaml doesn't preserve individual indentations of block sequence -items, it does properly dump:: +Although ruamel.yaml doesn\'t preserve individual indentations of block +sequence items, it does properly dump: - x: - - b: 1 - - 2 + x: + - b: 1 + - 2 -back to:: +back to: - x: - - b: 1 - - 2 + x: + - b: 1 + - 2 -if you specify ``yaml.indent(sequence=4)`` (indentation is counted to the +if you specify `yaml.indent(sequence=4)` (indentation is counted to the beginning of the sequence element). PyYAML (and older versions of ruamel.yaml) gives you non-indented -scalars (when specifying default_flow_style=False):: +scalars (when specifying default_flow_style=False): - x: - - b: 1 - - 2 + x: + - b: 1 + - 2 -You can use ``mapping=4`` to also have the mappings values indented. -The dump also observes an additional ``offset=2`` setting that -can be used to push the dash inwards, *within the space defined by* ``sequence``. +You can use `mapping=4` to also have the mappings values indented. The +dump also observes an additional `offset=2` setting that can be used to +push the dash inwards, *within the space defined by* `sequence`. -The above example with the often seen ``yaml.indent(mapping=2, sequence=4, offset=2)`` -indentation:: +The above example with the often seen +`yaml.indent(mapping=2, sequence=4, offset=2)` indentation: - x: - y: - - b: 1 - - 2 + x: + y: + - b: 1 + - 2 -The defaults are as if you specified ``yaml.indent(mapping=2, sequence=2, offset=0)``. +The defaults are as if you specified +`yaml.indent(mapping=2, sequence=2, offset=0)`. -If the ``offset`` equals ``sequence``, there is not enough -room for the dash and the space that has to follow it. In that case the -element itself would normally be pushed to the next line (and older versions -of ruamel.yaml did so). But this is -prevented from happening. However the ``indent`` level is what is used -for calculating the cumulative indent for deeper levels and specifying -``sequence=3`` resp. ``offset=2``, might give correct, but counter -intuitive results. +If the `offset` equals `sequence`, there is not enough room for the dash +and the space that has to follow it. In that case the element itself +would normally be pushed to the next line (and older versions of +`ruamel.yaml` did so). But this is prevented from happening. However the +`indent` level is what is used for calculating the cumulative indent for +deeper levels and specifying `sequence=3` resp. `offset=2`, might give +correct, but counter-intuitive results. -**It is best to always have** ``sequence >= offset + 2`` -**but this is not enforced**. Depending on your structure, not following -this advice **might lead to invalid output**. +**It is best to always have** `sequence >= offset + 2` **but this is not +enforced**. Depending on your structure, not following this advice +**might lead to invalid output**. -Inconsistently indented YAML -++++++++++++++++++++++++++++ +### Inconsistently indented YAML -If your input is inconsistently indented, such indentation cannot be preserved. -The first round-trip will make it consistent/normalize it. Here are some -inconsistently indented YAML examples. +If your input is inconsistently indented, such indentation cannot be +preserved. The first round-trip will make it consistent/normalize it. +Here are some inconsistently indented YAML examples. -``b`` indented 3, ``c`` indented 4 positions:: +`b` indented 3, `c` indented 4 positions: - a: - b: - c: 1 + a: + b: + c: 1 + +Top level sequence is indented 2 without offset, the other sequence 4 +(with offset 2): -Top level sequence is indented 2 without offset, the other sequence 4 (with offset 2):: + - key: + - foo + - bar - - key: - - foo - - bar +### Indenting using `typ="safe"` +The C based emitter doesn't have the fine control, distinguishing between +block mappings and sequences. Do only use the `pure` Python versions +of the dumper if you want to have that sort of control. -Positioning ':' in top level mappings, prefixing ':' -==================================================== +## Positioning ':' in top level mappings, prefixing ':' -If you want your toplevel mappings to look like:: +If you want your toplevel mappings to look like: - library version: 1 - comment : | - this is just a first try + library version: 1 + comment : | + this is just a first try -then set ``yaml.top_level_colon_align = True`` -(and ``yaml.indent = 4``). ``True`` causes calculation based on the longest key, -but you can also explicitly set a number. +then set `yaml.top_level_colon_align = True` (and `yaml.indent = 4`). +`True` causes calculation based on the longest key, but you can also +explicitly set a number. If you want an extra space between a mapping key and the colon specify -``yaml.prefix_colon = ' '``:: +`yaml.prefix_colon = ' '`: - - https://myurl/abc.tar.xz : 23445 - # ^ extra space here - - https://myurl/def.tar.xz : 944 + - https://myurl/abc.tar.xz : 23445 + # ^ extra space here + - https://myurl/def.tar.xz : 944 -If you combine ``prefix_colon`` with ``top_level_colon_align``, the -top level mapping doesn't get the extra prefix. If you want that -anyway, specify ``yaml.top_level_colon_align = 12`` where ``12`` has to be an +If you combine `prefix_colon` with `top_level_colon_align`, the top +level mapping doesn\'t get the extra prefix. If you want that anyway, +specify `yaml.top_level_colon_align = 12` where `12` has to be an integer that is one more than length of the widest key. +### Document version support -Document version support -++++++++++++++++++++++++ - -In YAML a document version can be explicitly set by using:: +In YAML a document version can be explicitly set by using: - %YAML 1.x + %YAML 1.x -before the document start (at the top or before a -``---``). For ``ruamel.yaml`` x has to be 1 or 2. If no explicit -version is set `version 1.2 `_ -is assumed (which has been released in 2009). +before the document start (at the top or before a `---`). For +`ruamel.yaml` x has to be 1 or 2. If no explicit version is set [version +1.2](http://www.yaml.org/spec/1.2/spec.html) is assumed (which has been +released in 2009). The 1.2 version does **not** support: -- sexagesimals like ``12:34:56`` -- octals that start with 0 only: like ``012`` for number 10 (``0o12`` **is** - supported by YAML 1.2) -- Unquoted Yes and On as alternatives for True and No and Off for False. +- sexagesimals like `12:34:56` +- octals that start with 0 only: like `012` for number 10 (`0o12` + **is** supported by YAML 1.2) +- Unquoted Yes and On as alternatives for True and No and Off for + False. If you cannot change your YAML files and you need them to load as 1.1 -you can load with ``yaml.version = (1, 1)``, -or the equivalent (version can be a tuple, list or string) ``yaml.version = "1.1"`` +you can load with `yaml.version = (1, 1)`, or the equivalent (version +can be a tuple, list or string) `yaml.version = "1.1"` *If you cannot change your code, stick with ruamel.yaml==0.10.23 and let me know if it would help to be able to set an environment variable.* @@ -167,15 +170,13 @@ me know if it would help to be able to set an environment variable.* This does not affect dump as ruamel.yaml never emitted sexagesimals, nor octal numbers, and emitted booleans always as true resp. false -Round trip including comments -+++++++++++++++++++++++++++++ +### Round trip including comments The major motivation for this fork is the round-trip capability for comments. The integration of the sources was just an initial step to make this easier. -adding/replacing comments -^^^^^^^^^^^^^^^^^^^^^^^^^ +#### adding/replacing comments Starting with version 0.8, you can add/replace comments on block style collections (mappings/sequences resuting in Python dict/list). The basic @@ -223,65 +224,63 @@ Resulting in:: f: 6 # comment 3 --- | -If the comment doesn't start with '#', this will be added. The key is -the element index for list, the actual key for dictionaries. As can be seen -from the example, the column to choose for a comment is derived -from the previous, next or preceding comment column (picking the first one -found). +If the comment doesn\'t start with \'#\', this will be added. The key is +the element index for list, the actual key for dictionaries. As can be +seen from the example, the column to choose for a comment is derived +from the previous, next or preceding comment column (picking the first +one found). Make sure that the added comment is correct, in the sense that when it contains newlines, the following is either an empty line or a line with only spaces, or the first non-space is a `#`. -Config file formats -+++++++++++++++++++ +# Config file formats -There are only a few configuration file formats that are easily -readable and editable: JSON, INI/ConfigParser, YAML (XML is to cluttered -to be called easily readable). +There are only a few configuration file formats that are easily readable +and editable: JSON, INI/ConfigParser, YAML (XML is to cluttered to be +called easily readable). -Unfortunately `JSON `_ doesn't support comments, +Unfortunately [JSON](http://www.json.org/) doesn\'t support comments, and although there are some solutions with pre-processed filtering of comments, there are no libraries that support round trip updating of such commented files. -INI files support comments, and the excellent `ConfigObj -`_ library by Foord -and Larosa even supports round trip editing with comment preservation, -nesting of sections and limited lists (within a value). Retrieval of -particular value format is explicit (and extensible). +INI files support comments, and the excellent +[ConfigObj](http://www.voidspace.org.uk/python/configobj.html) library +by Foord and Larosa even supports round trip editing with comment +preservation, nesting of sections and limited lists (within a value). +Retrieval of particular value format is explicit (and extensible). YAML has basic mapping and sequence structures as well as support for -ordered mappings and sets. It supports scalars various types -including dates and datetimes (missing in JSON). -YAML has comments, but these are normally thrown away. +ordered mappings and sets. It supports scalars various types including +dates and datetimes (missing in JSON). YAML has comments, but these are +normally thrown away. -Block structured YAML is a clean and very human readable -format. By extending the Python YAML parser to support round trip -preservation of comments, it makes YAML a very good choice for -configuration files that are human readable and editable while at -the same time interpretable and modifiable by a program. +Block structured YAML is a clean and very human readable format. By +extending the Python YAML parser to support round trip preservation of +comments, it makes YAML a very good choice for configuration files that +are human readable and editable while at the same time interpretable and +modifiable by a program. -Extending -+++++++++ +# Extending There are normally six files involved when extending the roundtrip -capabilities: the reader, parser, composer and constructor to go from YAML to -Python and the resolver, representer, serializer and emitter to go the other -way. +capabilities: the reader, parser, composer and constructor to go from +YAML to Python and the resolver, representer, serializer and emitter to +go the other way. Extending involves keeping extra data around for the next process step, -eventuallly resulting in a different Python object (subclass or alternative), -that should behave like the original, but on the way from Python to YAML -generates the original (or at least something much closer). +eventuallly resulting in a different Python object (subclass or +alternative), that should behave like the original, but on the way from +Python to YAML generates the original (or at least something much +closer). -Smartening -++++++++++ +# Smartening -When you use round-tripping, then the complex data you get are -already subclasses of the built-in types. So you can patch -in extra methods or override existing ones. Some methods are already -included and you can do:: +When you use round-tripping, then the complex data you get are already +subclasses of the built-in types. So you can patch in extra methods or +override existing ones. Some methods are already included and you can +do: yaml_str = """\ a: diff --git a/_doc/dumpcls.ryd b/_doc/dumpcls.ryd index 8e9ac6e..048cdeb 100644 --- a/_doc/dumpcls.ryd +++ b/_doc/dumpcls.ryd @@ -1,30 +1,29 @@ version: 0.2 -text: rst -fix_inline_single_backquotes: true -pdf: true +text: md +pdf: false # code_directory: ../_example --- | +# Working with Python classes + +## Dumping Python classes -********************** -Dumping Python classes -********************** +Only `yaml = YAML(typ='unsafe')` loads and dumps Python objects +out-of-the-box. And since it loads **any** Python object, this can be +unsafe, so don't use it. -Only ``yaml = YAML(typ='unsafe')`` loads and dumps Python objects out-of-the-box. And -since it loads **any** Python object, this can be unsafe. - -If you have instances of some class(es) that you want to dump or load, it is -easy to allow the YAML instance to do that explicitly. You can either register the -class with the ``YAML`` instance or decorate the class. - -Registering is done with ``YAML.register_class()``: +If you have instances of some class(es) that you want to dump or load, +it is easy to allow the YAML instance to do that explicitly. You can +either register the class with the `YAML` instance or decorate the +class. +Registering is done with `YAML.register_class()`: --- !python | import sys import ruamel.yaml -class User(object): +class User: def __init__(self, name, age): self.name = name self.age = age @@ -36,12 +35,11 @@ yaml.dump([User('Anthon', 18)], sys.stdout) --- !stdout | which gives as output:: --- | -The tag ``!User`` originates from the name of the class. - -You can specify a different tag by adding the attribute ``yaml_tag``, and -explicitly specify dump and/or load *classmethods* which have to be called -``to_yaml`` resp. ``from_yaml``: +The tag `!User` originates from the name of the class. +You can specify a different tag by adding the attribute `yaml_tag`, and +explicitly specify dump and/or load *classmethods* which have to be +named `to_yaml` resp. `from_yaml`: --- !python | import sys import ruamel.yaml @@ -71,10 +69,8 @@ yaml.dump([User('Anthon', 18)], sys.stdout) which gives as output:: --- | - -When using the decorator, which takes the ``YAML()`` instance as a parameter, -the ``yaml = YAML()`` line needs to be moved up in the file: - +When using the decorator, which takes the `YAML()` instance as a +parameter, the `yaml = YAML()` line needs to be moved up in the file: --- !python | import sys from ruamel.yaml import YAML, yaml_object @@ -103,5 +99,217 @@ class User: yaml.dump([User('Anthon', 18)], sys.stdout) --- | -The ``yaml_tag``, ``from_yaml`` and ``to_yaml`` work in the same way as when using -``.register_class()``. +The `yaml_tag`, `from_yaml` and `to_yaml` work in the same way as when +using `.register_class()`. + +Alternatively you can use the `register_class()` method as decorator, +This also requires you have the yaml instance available: +--- !python | +import sys +import ruamel.yaml + +yaml = ruamel.yaml.YAML() + +@yaml.register_class +class User: + yaml_tag = u'!user' + + def __init__(self, name, age): + self.name = name + self.age = age + + @classmethod + def to_yaml(cls, representer, node): + return representer.represent_scalar(cls.yaml_tag, + u'{.name}-{.age}'.format(node, node)) + + @classmethod + def from_yaml(cls, constructor, node): + return cls(*node.value.split('-')) + + +yaml.dump([User('Anthon', 18)], sys.stdout) + +--- !stdout | + +This also gives: + +--- | + +If your class is dumped as a YAML mapping or sequence, there might be an (indirect) +reference to the object itself in one or more of the mapping keys (in YAML these +don't have to be simple scalars), mapping values or sequence entries. + +That means that re-creating an object in `to_yaml` cannot generally just create +a `dict`/`list` from the `node` parameter and then create and return a complete +object. The solution for this is to create an empty object and yield that +and then fill in the content data afterwards. That way, if there is a self +reference, and the same node is encountered *while creating the content for the +object*, there is an `id` (from the yielded object) created for that node which +can be assigned. + +--- !python | + +from pathlib import Path +import ruamel.yaml + +class Person: + def __init__(self, name, siblings=None): + self.name = name + self.siblings = [] if siblings is None else siblings + +arya = Person('Arya') +sansa = Person('Sansa') +arya.siblings.append(sansa) # there are better ways to represent this +sansa.siblings.append(arya) + +yaml = ruamel.yaml.YAML() +yaml.register_class(Person) + +path = Path('/tmp/arya.yaml') +yaml.dump(arya, path) +print(path.read_text()) + +--- !stdout | + +dumping as: + +--- | + +And you can load the output: + +--- !python | + +from pathlib import Path +import ruamel.yaml + +class Person: + def __init__(self, name, siblings=None): + self.name = name + self.siblings = [] if siblings is None else siblings + + def __repr__(self): + return f'Person(name: {self.name}, siblings: {self.siblings})' + +path = Path('/tmp/arya.yaml') +yaml = ruamel.yaml.YAML() +yaml.register_class(Person) +data = yaml.load(path) + +print(data) + +--- !stdout | + +giving: +--- | + +But if you provide a (to) simple loader: + +--- !python | + +from pathlib import Path +import ruamel.yaml + +class Person: + def __init__(self, name, siblings=None): + self.name = name + self.siblings = [] if siblings is None else siblings + + def __repr__(self): + return f'Person(name: {self.name}, siblings: {self.siblings})' + + @classmethod + def from_yaml(cls, constructor, node): + data = ruamel.yaml.CommentedMap() + constructor.construct_mapping(node, maptyp=data, deep=True) + return cls(**data) + + +path = Path('/tmp/arya.yaml') +yaml = ruamel.yaml.YAML() +yaml.register_class(Person) +data = yaml.load(path) +print(data) + +--- !stdout | + +giving: + +--- | +As you can see, Sansa has no normal siblings after this load. + +What you need to do is yield the empty Person instance and fill it in +afterwards: + +--- !python | + +from pathlib import Path +import ruamel.yaml + +class Person: + def __init__(self, name, siblings=None): + self.name = name + self.siblings = [] if siblings is None else siblings + + def __repr__(self): + return f'Person(name: {self.name}, siblings: {self.siblings})' + + @classmethod + def from_yaml(cls, constructor, node): + person = Person(name='') + yield person + data = ruamel.yaml.CommentedMap() + constructor.construct_mapping(node, maptyp=data, deep=True) + for k, v in data.items(): + setattr(person, k, v) + + +path = Path('/tmp/arya.yaml') +yaml = ruamel.yaml.YAML() +yaml.register_class(Person) +data = yaml.load(path) +print(data) + +--- !stdout | + +giving: + +--- | + +## Dataclass + +Although you could always register dataclasses, in 0.17.34 support was added to +call `__post_init__()` on these classes, if available. + + +--- !python | + +from typing import ClassVar +from dataclasses import dataclass +import ruamel.yaml + +@dataclass +class DC: + yaml_tag: ClassVar = '!dc_example' # if you don't want !DC as tag + abc: int + klm: int + xyz: int = 0 + + def __post_init__(self) -> None: + self.xyz = self.abc + self.klm + +yaml = ruamel.yaml.YAML() +yaml.register_class(DC) +dc = DC(abc=5, klm=42) +assert dc.xyz == 47 + +yaml_str = """\ +!dc_example +abc: 13 +klm: 37 +""" +dc2 = yaml.load(yaml_str) +print(f'{dc2.xyz=}') + +--- !stdout | +printing: diff --git a/_doc/example.ryd b/_doc/example.ryd index c38ead0..4b431cd 100644 --- a/_doc/example.ryd +++ b/_doc/example.ryd @@ -1,14 +1,11 @@ version: 0.2 -text: rst -fix_inline_single_backquotes: true -pdf: true +text: md +pdf: false --- | -******** -Examples -******** +# Examples -Basic round trip of parsing YAML to Python objects, modifying -and generating YAML: +Basic round trip of parsing YAML to Python objects, modifying and +generating YAML: --- !python | import sys from ruamel.yaml import YAML @@ -30,11 +27,11 @@ and generating YAML: --- !stdout | Resulting in:: --- | ----- +------------------------------------------------------------------------ -YAML handcrafted anchors and references as well as key merging -are preserved. The merged keys can transparently be accessed -using ``[]`` and ``.get()``: +YAML handcrafted anchors and references as well as key merging are +preserved. The merged keys can transparently be accessed using `[]` and +`.get()`: --- !python | from ruamel.yaml import YAML @@ -66,9 +63,9 @@ using ``[]`` and ``.get()``: data = yaml.load(inp) assert data[7]['y'] == 2 --- | - -The ``CommentedMap``, which is the ``dict`` like construct one gets when round-trip loading, -supports insertion of a key into a particular position, while optionally adding a comment: +The `CommentedMap`, which is the `dict` like construct one gets when +round-trip loading, supports insertion of a key into a particular +position, while optionally adding a comment: --- !python | import sys from ruamel.yaml import YAML @@ -87,21 +84,21 @@ supports insertion of a key into a particular position, while optionally adding --- !stdout | gives:: --- | -Please note that the comment is aligned with that of its neighbour (if available). +Please note that the comment is aligned with that of its neighbour (if +available). -The above was inspired by a `question `_ -posted by *demux* on StackOverflow. +The above was inspired by a +[question](http://stackoverflow.com/a/36970608/1307905) posted by +*demux* on StackOverflow. ----- +------------------------------------------------------------------------ -By default ``ruamel.yaml`` indents with two positions in block style, for +By default `ruamel.yaml` indents with two positions in block style, for both mappings and sequences. For sequences the indent is counted to the beginning of the scalar, with the dash taking the first position of the -indented "space". - -You can change this default indentation by e.g. using ``yaml.indent()``: - +indented \"space\". +You can change this default indentation by e.g. using `yaml.indent()`: --- !python | import sys @@ -123,16 +120,14 @@ giving:: --- | - If a block sequence or block mapping is the element of a sequence, the -are, by default, displayed `compact -`__ notation. This means -that the dash of the "parent" sequence is on the same line as the -first element resp. first key/value pair of the child collection. +are, by default, displayed +[compact](http://yaml.org/spec/1.2/spec.html#id2797686) notation. This +means that the dash of the \"parent\" sequence is on the same line as +the first element resp. first key/value pair of the child collection. If you want either or both of these (sequence within sequence, mapping -within sequence) to begin on the next line use ``yaml.compact()``: - +within sequence) to begin on the next line use `yaml.compact()`: --- !python | import sys @@ -152,13 +147,11 @@ yaml.dump(d, sys.stdout) giving:: ---- | - ------- - -The following program uses three dumps on the same data, resulting in a stream with -three documents: +--- | +------------------------------------------------------------------------ +The following program uses three dumps on the same data, resulting in a +stream with three documents: --- !python | import sys from ruamel.yaml import YAML @@ -201,40 +194,39 @@ yaml.dump(data, sys.stdout, transform=sequence_indent_four) --- !stdout | gives as output:: ---- | - -The transform example, in the last document, was inspired by a -`question posted by *nowox* -`_ on StackOverflow. +--- | +The transform example, in the last document, was inspired by a [question +posted by \*nowox\*](https://stackoverflow.com/q/44388701/1307905) on +StackOverflow. ------ +------------------------------------------------------------------------ -Output of ``dump()`` as a string -++++++++++++++++++++++++++++++++ +## Output of `dump()` as a string -The single most abused "feature" of the old API is not providing the (second) -stream parameter to one of the ``dump()`` variants, in order to get a monolithic string -representation of the stream back. +The single most abused "feature" of the old API is not providing the +(second) stream parameter to one of the `dump()` variants, in order to +get a monolithic string representation of the stream back. -Apart from being memory inefficient and slow, quite often people using this did not -realise that ``print(round_trip_dump(dict(a=1, b=2)))`` gets you an extra, -empty, line after ``b: 2``. +Apart from being memory inefficient and slow, quite often people using +this did not realise that `print(round_trip_dump(dict(a=1, b=2)))` gets +you an extra, empty, line after `b: 2`. The real question is why this functionality, which is seldom really -necessary, is available in the old API (and in PyYAML) in the first place. One -explanation you get by looking at what someone would need to do to make this -available if it weren't there already. Apart from subclassing the ``Serializer`` -and providing a new ``dump`` method, which would ten or so lines, another -**hundred** lines, essentially the whole ``dumper.py`` file, would need to be -copied and to make use of this serializer. - -The fact is that one should normally be doing ``round_trip_dump(dict(a=1, b=2)), -sys.stdout)`` and do away with 90% of the cases for returning the string, and -that all post-processing YAML, before writing to stream, can be handled by using -the ``transform=`` parameter of dump, being able to handle most of the rest. But -it is also much easier in the new API to provide that YAML output as a string if +necessary, is available in the old API (and in PyYAML) in the first +place. One explanation you get by looking at what someone would need to +do to make this available if it weren\'t there already. Apart from +subclassing the `Serializer` and providing a new `dump` method, which +would ten or so lines, another **hundred** lines, essentially the whole +`dumper.py` file, would need to be copied and to make use of this +serializer. + +The fact is that one should normally be doing +`round_trip_dump(dict(a=1, b=2)), sys.stdout)` and do away with 90% of +the cases for returning the string, and that all post-processing YAML, +before writing to stream, can be handled by using the `transform=` +parameter of dump, being able to handle most of the rest. But it is also +much easier in the new API to provide that YAML output as a string if you really need to have it (or think you do): - --- !python | import sys from ruamel.yaml import YAML @@ -252,11 +244,12 @@ class MyYAML(YAML): yaml = MyYAML() # or typ='safe'/'unsafe' etc --- | -with about one tenth of the lines needed for the old interface, you can once more do:: +with about one tenth of the lines needed for the old interface, you can +once more do: --- !code | print(yaml.dump(dict(a=1, b=2))) --- | -instead of:: +instead of: --- !code | yaml.dump((dict(a=1, b=2)), sys.stdout) print() # or sys.stdout.write('\n') diff --git a/_doc/index.ryd b/_doc/index.ryd deleted file mode 100644 index 9333020..0000000 --- a/_doc/index.ryd +++ /dev/null @@ -1,56 +0,0 @@ -version: 0.2 -text: rst -fix_inline_single_backquotes: true -pdf: false ---- !comment | -Sections, subsections, etc. in .ryd files - # with overline, for parts - * with overline, for chapters - =, for sections - +, for subsections - ^, for subsubsections - ", for paragraphs - - don't use - or . as --- or ... interfere with ryd ---- | - -*********** -ruamel.yaml -*********** - -`SoureForge `_ | -`PyPI `_ - - -Contents: - -.. toctree:: - :maxdepth: 2 - - overview - install - basicuse - dumpcls - detail - example - api - pyyaml - contributing - -.. image:: https://readthedocs.org/projects/yaml/badge/?version=stable - :target: https://yaml.readthedocs.org/en/stable - -.. image:: https://bestpractices.coreinfrastructure.org/projects/1128/badge - :target: https://bestpractices.coreinfrastructure.org/projects/1128 - -.. image:: https://sourceforge.net/p/ruamel-yaml/code/ci/default/tree/_doc/_static/license.svg?format=raw - :target: https://opensource.org/licenses/MIT - -.. image:: https://sourceforge.net/p/ruamel-yaml/code/ci/default/tree/_doc/_static/pypi.svg?format=raw - :target: https://pypi.org/project/ruamel.yaml/ - -.. image:: https://sourceforge.net/p/oitnb/code/ci/default/tree/_doc/_static/oitnb.svg?format=raw - :target: https://pypi.org/project/oitnb/ - -.. image:: http://www.mypy-lang.org/static/mypy_badge.svg - :target: http://mypy-lang.org/ diff --git a/_doc/install.ryd b/_doc/install.ryd index 2d54849..9edfc70 100644 --- a/_doc/install.ryd +++ b/_doc/install.ryd @@ -1,54 +1,47 @@ version: 0.2 -text: rst -fix_inline_single_backquotes: true -# pdf: true +text: md +pdf: false --- | -********** -Installing -********** +# Installing -Make sure you have a recent version of ``pip`` and ``setuptools`` -installed. The later needs environment marker support -(``setuptools>=20.6.8``) and that is e.g. bundled with Python 3.4.6 but -not with 3.4.4. It is probably best to do:: +Make sure you have a recent version of `pip` and `setuptools` installed. +The later needs environment marker support (`setuptools>=20.6.8`) and +that is e.g. bundled with Python 3.4.6 but not with 3.4.4. It is +probably best to do: pip install -U pip setuptools wheel -in your environment (``virtualenv``, (Docker) container, etc) before -installing ``ruamel.yaml``. +in your environment (`virtualenv`, (Docker) container, etc) before +installing `ruamel.yaml`. -``ruamel.yaml`` itself should be installed from PyPI_ using:: +`ruamel.yaml` itself should be installed from [PyPI]() using: pip install ruamel.yaml If you want to process jinja2/YAML templates (which are not valid YAML -with the default jinja2 markers), do ``pip install -ruamel.yaml[jinja2]`` (you might need to quote the last argument -because of the ``[]``) +with the default jinja2 markers), do `pip install ruamel.yaml[jinja2]` +(you might need to quote the last argument because of the `[]`) +There also is a commandline utility `yaml` available after installing: -There also is a commandline utility ``yaml`` available after installing:: - - pip install ruamel.yaml.cmd + pip install ruamel.yaml.cmd that allows for round-trip testing/re-indenting and conversion of YAML files (JSON,INI,HTML tables) -Optional requirements -+++++++++++++++++++++ +## Optional requirements If you have the the header files for your Python executables installed then you can use the (non-roundtrip), but faster, C loader and emitter. -On Debian systems you should use:: +On Debian systems you should use: sudo apt-get install python3-dev -you can leave out ``python3-dev`` if you don't use python3 - -For CentOS (7) based systems you should do:: +you can leave out `python3-dev` if you don\'t use python3 - sudo yum install python-devel +For CentOS (7) based systems you should do: + sudo yum install python-devel --- !inc-raw | links.rydinc diff --git a/_doc/overview.ryd b/_doc/overview.ryd index 43be596..b10dc78 100644 --- a/_doc/overview.ryd +++ b/_doc/overview.ryd @@ -1,51 +1,47 @@ version: 0.2 -text: rst -fix_inline_single_backquotes: true +text: md +pdf: false --- | -******** -Overview -******** - -``ruamel.yaml`` is a YAML 1.2 loader/dumper package for Python. It is a -derivative of Kirill Simonov's `PyYAML 3.11 -`_. - -``ruamel.yaml`` supports `YAML 1.2`_ and has round-trip loaders and dumpers. -A round-trip is a YAML load-modify-save sequence and ruamel.yaml tries to -preserve, among others: - -- comments -- block style and key ordering are kept, so you can diff the round-tripped - source -- flow style sequences ( 'a: b, c, d') (based on request and test by - Anthony Sottile) -- anchor names that are hand-crafted (i.e. not of the form``idNNN``) -- `merges `_ in dictionaries are preserved - -This preservation is normally not broken unless you severely alter -the structure of a component (delete a key in a dict, remove list entries). +# Overview + +`ruamel.yaml` is a YAML 1.2 loader/dumper package for Python. It is a +derivative of Kirill Simonov\'s [PyYAML +3.11](https://bitbucket.org/xi/pyyaml). + +`ruamel.yaml` supports [YAML 1.2]() and has round-trip loaders and +dumpers. A round-trip is a YAML load-modify-save sequence and +ruamel.yaml tries to preserve, among others: + +- comments +- block style and key ordering are kept, so you can diff the + round-tripped source +- flow style sequences ( \'a: b, c, d\') (based on request and test by + Anthony Sottile) +- anchor names that are hand-crafted (i.e. not of the form`idNNN`) +- [merges](http://yaml.org/type/merge.html) in dictionaries are + preserved + +This preservation is normally not broken unless you severely alter the +structure of a component (delete a key in a dict, remove list entries). Reassigning values or replacing list items, etc., is fine. -For the specific 1.2 differences see :ref:`yaml-1-2-support` +For the specific 1.2 differences see +`yaml-1-2-support`{.interpreted-text role="ref"} -Although individual indentation of lines is not preserved, you can specify -separate indentation levels for mappings and sequences (counting for sequences -does **not** include the dash for a sequence element) and specific offset of -block sequence dashes within that indentation. +Although individual indentation of lines is not preserved, you can +specify separate indentation levels for mappings and sequences (counting +for sequences does **not** include the dash for a sequence element) and +specific offset of block sequence dashes within that indentation. - -Although ``ruamel.yaml`` still allows most of the PyYAML way of doing +Although `ruamel.yaml` still allows most of the PyYAML way of doing things, adding features required a different API then the transient -nature of PyYAML's ``Loader`` and ``Dumper``. Starting with -``ruamel.yaml`` version 0.15.0 this new API gets introduced. Old ways -that get in the way will be removed, after first generating warnings -on use, then generating an error. In general a warning in version 0.N.x will become an -error in 0.N+1.0 - - -Many of the bugs filed against PyYAML, but that were never -acted upon, have been fixed in ``ruamel.yaml`` - - +nature of PyYAML\'s `Loader` and `Dumper`. Starting with `ruamel.yaml` +version 0.15.0 this new API gets introduced. Old ways that get in the +way will be removed, after first generating warnings on use, then +generating an error. In general a warning in version 0.N.x will become +an error in 0.N+1.0 + +Many of the bugs filed against PyYAML, but that were never acted upon, +have been fixed in `ruamel.yaml` --- !inc-raw | links.rydinc diff --git a/_doc/pyyaml.ryd b/_doc/pyyaml.ryd index 56ee391..f670237 100644 --- a/_doc/pyyaml.ryd +++ b/_doc/pyyaml.ryd @@ -1,84 +1,72 @@ version: 0.2 -text: rst -fix_inline_single_backquotes: true -pdf: true +text: md +pdf: false --- | -*********************** -Differences with PyYAML -*********************** +# Differences with PyYAML -.. parsed-literal:: +::: parsed-literal - *If I have seen further, it is by standing on the shoulders of giants*. - Isaac Newton (1676) +*If I have seen further, it is by standing on the shoulders of giants*. +: Isaac Newton (1676) +::: - -``ruamel.yaml`` is a derivative of Kirill Simonov's `PyYAML 3.11 -`_ and would not exist without that +`ruamel.yaml` is a derivative of Kirill Simonov\'s [PyYAML +3.11](https://bitbucket.org/xi/pyyaml) and would not exist without that excellent base to start from. The following a summary of the major differences with PyYAML 3.11 -.. _yaml-1-2-support: - -Defaulting to YAML 1.2 support -++++++++++++++++++++++++++++++ - -PyYAML supports the `YAML 1.1`_ standard, ``ruamel.yaml`` supports -`YAML 1.2`_ as released in 2009. +## Defaulting to YAML 1.2 support -- YAML 1.2 dropped support for several features unquoted ``Yes``, - ``No``, ``On``, ``Off`` -- YAML 1.2 no longer accepts strings that start with a ``0`` and solely - consist of number characters as octal, you need to specify such strings with - ``0o[0-7]+`` (zero + lower-case o for octal + one or more octal characters). -- YAML 1.2 no longer supports `sexagesimals - `_, so the string scalar - ``12:34:56`` doesn't need quoting. -- ``\/`` escape for JSON compatibility -- correct parsing of floating point scalars with exponentials +PyYAML supports the [YAML 1.1]() standard, `ruamel.yaml` supports [YAML +1.2]() as released in 2009. -unless the YAML document is loaded with an explicit ``version==1.1`` or -the document starts with:: +- YAML 1.2 dropped support for several features unquoted `Yes`, `No`, + `On`, `Off` +- YAML 1.2 no longer accepts strings that start with a `0` and solely + consist of number characters as octal, you need to specify such + strings with `0o[0-7]+` (zero + lower-case o for octal + one or more + octal characters). +- YAML 1.2 no longer supports + [sexagesimals](https://en.wikipedia.org/wiki/Sexagesimal), so the + string scalar `12:34:56` doesn\'t need quoting. +- `\/` escape for JSON compatibility +- correct parsing of floating point scalars with exponentials - % YAML 1.1 +unless the YAML document is loaded with an explicit `version==1.1` or +the document starts with: -, ``ruamel.yaml`` will load the document as version 1.2. + % YAML 1.1 +, `ruamel.yaml` will load the document as version 1.2. -PY2/PY3 reintegration -+++++++++++++++++++++ +## PY2/PY3 reintegration -``ruamel.yaml`` re-integrates the Python 2 and 3 sources, running on -Python 2.7 (CPython, PyPy), 3.3, 3.4, 3.5 and 3.6 (support for 2.6 has been -dropped mid 2016). It is more easy to extend and maintain as only a +`ruamel.yaml` re-integrates the Python 2 and 3 sources, running on +Python 2.7 (CPython, PyPy), 3.3, 3.4, 3.5 and 3.6 (support for 2.6 has +been dropped mid 2016). It is more easy to extend and maintain as only a miniscule part of the code is Python version specific. -Fixes -+++++ +## Fixes -- ``ruamel.yaml`` follows the ``indent`` keyword argument on scalars - when dumping. -- ``ruamel.yaml`` allows ``:`` in plain scalars, as long as these are not - followed by a space (as per the specification) +- `ruamel.yaml` follows the `indent` keyword argument on scalars when + dumping. +- `ruamel.yaml` allows `:` in plain scalars, as long as these are not + followed by a space (as per the specification) +## Testing -Testing -+++++++ +`ruamel.yaml` is tested using [tox]() and [py.test](). In addition to +new tests, the original PyYAML test framework is called from within +`tox` runs. -``ruamel.yaml`` is tested using `tox`_ and `py.test`_. In addition to -new tests, the original PyYAML -test framework is called from within ``tox`` runs. +Before versions are pushed to PyPI, `tox` is invoked, and has to pass, +on all supported Python versions, on PyPI as well as flake8/pep8 -Before versions are pushed to PyPI, ``tox`` is invoked, and has to pass, on all -supported Python versions, on PyPI as well as flake8/pep8 +## API -API -+++ - -Starting with 0.15 the API for using ``ruamel.yaml`` has diverged allowing +Starting with 0.15 the API for using `ruamel.yaml` has diverged allowing easier addition of new features. - --- !inc-raw - links.rydinc diff --git a/_test/test_add_xxx.py b/_test/test_add_xxx.py index 0ff8c26..22d652a 100644 --- a/_test/test_add_xxx.py +++ b/_test/test_add_xxx.py @@ -29,7 +29,8 @@ def dice_representer(dumper: Any, data: Any) -> Any: def test_dice_constructor() -> None: import ruamel.yaml # NOQA - yaml = ruamel.yaml.YAML(typ='unsafe', pure=True) + with pytest.warns(PendingDeprecationWarning): + yaml = ruamel.yaml.YAML(typ='unsafe', pure=True) ruamel.yaml.add_constructor('!dice', dice_constructor) data = yaml.load('initial hit points: !dice 8d4') assert str(data) == "{'initial hit points': Dice(8,4)}" @@ -38,7 +39,8 @@ def test_dice_constructor() -> None: def test_dice_constructor_with_loader() -> None: import ruamel.yaml # NOQA - yaml = ruamel.yaml.YAML(typ='unsafe', pure=True) + with pytest.warns(PendingDeprecationWarning): + yaml = ruamel.yaml.YAML(typ='unsafe', pure=True) ruamel.yaml.add_constructor('!dice', dice_constructor, Loader=ruamel.yaml.Loader) data = yaml.load('initial hit points: !dice 8d4') assert str(data) == "{'initial hit points': Dice(8,4)}" @@ -47,7 +49,8 @@ def test_dice_constructor_with_loader() -> None: def test_dice_representer() -> None: import ruamel.yaml # NOQA - yaml = ruamel.yaml.YAML(typ='unsafe', pure=True) + with pytest.warns(PendingDeprecationWarning): + yaml = ruamel.yaml.YAML(typ='unsafe', pure=True) yaml.default_flow_style = False ruamel.yaml.add_representer(Dice, dice_representer) # ruamel.yaml 0.15.8+ no longer forces quotes tagged scalars @@ -59,7 +62,8 @@ def test_dice_representer() -> None: def test_dice_implicit_resolver() -> None: import ruamel.yaml # NOQA - yaml = ruamel.yaml.YAML(typ='unsafe', pure=True) + with pytest.warns(PendingDeprecationWarning): + yaml = ruamel.yaml.YAML(typ='unsafe', pure=True) yaml.default_flow_style = False pattern = re.compile(r'^\d+d\d+$') ruamel.yaml.add_implicit_resolver('!dice', pattern) @@ -106,7 +110,8 @@ def to_yaml(cls, dumper: Any, data: Any) -> Any: def test_yaml_obj() -> None: import ruamel.yaml # NOQA - yaml = ruamel.yaml.YAML(typ='unsafe', pure=True) + with pytest.warns(PendingDeprecationWarning): + yaml = ruamel.yaml.YAML(typ='unsafe', pure=True) ruamel.yaml.add_representer(Obj1, YAMLObj1.to_yaml) ruamel.yaml.add_multi_constructor(YAMLObj1.yaml_tag, YAMLObj1.from_yaml) x = yaml.load('!obj:x.2\na: 1') @@ -119,7 +124,8 @@ def test_yaml_obj() -> None: def test_yaml_obj_with_loader_and_dumper() -> None: import ruamel.yaml # NOQA - yaml = ruamel.yaml.YAML(typ='unsafe', pure=True) + with pytest.warns(PendingDeprecationWarning): + yaml = ruamel.yaml.YAML(typ='unsafe', pure=True) ruamel.yaml.add_representer(Obj1, YAMLObj1.to_yaml, Dumper=ruamel.yaml.Dumper) ruamel.yaml.add_multi_constructor( YAMLObj1.yaml_tag, YAMLObj1.from_yaml, Loader=ruamel.yaml.Loader, diff --git a/_test/test_class_register.py b/_test/test_class_register.py index 18d2254..b15ef77 100644 --- a/_test/test_class_register.py +++ b/_test/test_class_register.py @@ -4,6 +4,7 @@ testing of YAML.register_class and @yaml_object """ +import pytest # type: ignore # NOQA from typing import Any from ruamel.yaml.comments import TaggedScalar, CommentedMap # NOQA @@ -56,7 +57,8 @@ def test_register_0_safe(self) -> None: def test_register_0_unsafe(self) -> None: # default_flow_style = None - yaml = YAML(typ='unsafe') + with pytest.warns(PendingDeprecationWarning): + yaml = YAML(typ='unsafe') yaml.register_class(User0) ys = """ - !User0 {age: 18, name: Anthon} @@ -83,7 +85,8 @@ def test_register_1_safe(self) -> None: yaml.dump(d, compare=ys) def test_register_1_unsafe(self) -> None: - yaml = YAML(typ='unsafe') + with pytest.warns(PendingDeprecationWarning): + yaml = YAML(typ='unsafe') yaml.register_class(User1) ys = """ [!user Anthon-18] diff --git a/_test/test_deprecation.py b/_test/test_deprecation.py index 390c26c..ea86f5f 100644 --- a/_test/test_deprecation.py +++ b/_test/test_deprecation.py @@ -3,9 +3,127 @@ import sys import pytest # type:ignore # NOQA +last_to_warn = (0, 17, 40) + @pytest.mark.skipif(sys.version_info < (3, 7) or sys.version_info >= (3, 9), # type: ignore reason='collections not available?') def test_collections_deprecation() -> None: with pytest.warns(DeprecationWarning): from collections import Hashable # type: ignore # NOQA + + +class TestFunctionDeprecation: + def test_deprecation_scan(self) -> None: + import ruamel.yaml + + if ruamel.yaml.version_info <= last_to_warn: + with pytest.warns(PendingDeprecationWarning): + data = ruamel.yaml.load('a: 42') # NOQA + else: + with pytest.raises(AttributeError): + data = ruamel.yaml.load('a: 42') # NOQA + + def test_deprecation_parse(self) -> None: + import ruamel.yaml + + if ruamel.yaml.version_info <= last_to_warn: + data = ruamel.yaml.parse('a: 42') # NOQA + else: + with pytest.raises(AttributeError): + data = ruamel.yaml.parse('a: 42') # NOQA + + def test_deprecation_compose(self) -> None: + import ruamel.yaml + + if ruamel.yaml.version_info <= last_to_warn: + with pytest.warns(PendingDeprecationWarning): + data = ruamel.yaml.compose('a: 42') # NOQA + else: + with pytest.raises(AttributeError): + data = ruamel.yaml.parse('a: 42') # NOQA + + def test_deprecation_compose_all(self) -> None: + import ruamel.yaml + + if ruamel.yaml.version_info <= last_to_warn: + data = ruamel.yaml.compose_all('a: 42') # NOQA + else: + with pytest.raises(AttributeError): + data = ruamel.yaml.parse('a: 42') # NOQA + + def test_deprecation_load(self) -> None: + import ruamel.yaml + + if ruamel.yaml.version_info <= last_to_warn: + with pytest.warns(PendingDeprecationWarning): + data = ruamel.yaml.load('a: 42') # NOQA + else: + with pytest.raises(AttributeError): + data = ruamel.yaml.parse('a: 42') # NOQA + + def test_deprecation_load_all(self) -> None: + import ruamel.yaml + + if ruamel.yaml.version_info <= last_to_warn: + data = ruamel.yaml.load_all('a: 42') # NOQA + else: + with pytest.raises(AttributeError): + data = ruamel.yaml.parse('a: 42') # NOQA + + def test_deprecation_safe_load(self) -> None: + import ruamel.yaml + + if ruamel.yaml.version_info <= last_to_warn: + with pytest.warns(PendingDeprecationWarning): + data = ruamel.yaml.safe_load('a: 42') # NOQA + else: + with pytest.raises(AttributeError): + data = ruamel.yaml.parse('a: 42') # NOQA + + def test_deprecation_round_trip_load(self) -> None: + import ruamel.yaml + + if ruamel.yaml.version_info <= last_to_warn: + with pytest.warns(PendingDeprecationWarning): + data = ruamel.yaml.round_trip_load('a: 42') # NOQA + else: + with pytest.raises(AttributeError): + data = ruamel.yaml.parse('a: 42') # NOQA + + +class TestYamlTyp: + def test_unsafe_deprecation(self) -> None: + import ruamel.yaml + + if ruamel.yaml.version_info < (0, 18, 0): + yaml = ruamel.yaml.YAML(typ='unsafe') + else: + with pytest.warns(PendingDeprecationWarning): + # with pytest.raises(SystemExit): + yaml = ruamel.yaml.YAML(typ='unsafe') # NOQA + + def test_full_load_error(self) -> None: + import ruamel.yaml + + yaml = ruamel.yaml.YAML(typ='full', pure=True) + with pytest.raises(ruamel.yaml.error.YAMLError): + yaml.load('a: b') + yaml = ruamel.yaml.YAML(typ='full') # C scanner/loader + with pytest.raises(ruamel.yaml.error.YAMLError): + yaml.load('a: b') + + def test_full_rt(self) -> None: + import os + import io + import ruamel.yaml + + yaml = ruamel.yaml.YAML(typ='full', pure=True) + buf = io.BytesIO() + yaml.dump([{'fun': os.system}], buf) + print(buf.getvalue()) + yaml = ruamel.yaml.YAML() + data = yaml.load(buf.getvalue()) + print(data) + ts = data[0]['fun'] + assert 'posix.system' in str(ts.tag) diff --git a/_test/test_docinfo.py b/_test/test_docinfo.py new file mode 100644 index 0000000..f05ee26 --- /dev/null +++ b/_test/test_docinfo.py @@ -0,0 +1,44 @@ + +import pytest # type: ignore # NOQA +from ruamel.yaml.docinfo import Version, version, Tag, DocInfo # NOQA + + +class TestVersion: + def test_create_from_integers(self) -> None: + v = Version(1, 2) + assert v.major == 1 + assert v.minor == 2 + + def test_create_using_generator(self) -> None: + v = version(1, 2) + assert isinstance(v, Version) + assert v.major == 1 + assert v.minor == 2 + + def test_create_from_string_using_generator(self) -> None: + v = version('1.2') + assert isinstance(v, Version) + assert v.major == 1 + assert v.minor == 2 + + def test_create_from_string_extra_param(self) -> None: + with pytest.raises(AssertionError): + _ = version('1.2', 3) + + def test_create_from_single_integer(self) -> None: + with pytest.raises(AssertionError): + _ = version(1) + with pytest.raises(TypeError): + _ = Version(1) # type: ignore + + +class TestDocInfo: + def test_empty(self) -> None: + di = DocInfo() + assert di.requested_version is None + assert di.doc_version is None + assert di.tags == [] + + def test_versions(self) -> None: + di = DocInfo(version('1.2'), version('1.1')) + assert di.requested_version > di.doc_version # type: ignore diff --git a/_test/test_issues.py b/_test/test_issues.py index d6376c2..554c7d2 100644 --- a/_test/test_issues.py +++ b/_test/test_issues.py @@ -942,13 +942,13 @@ def test_issue_445(self) -> None: from ruamel.yaml.compat import StringIO yaml = YAML() - yaml.version = '1.1' + yaml.version = '1.1' # type: ignore data = yaml.load('quote: I have seen things') buf = StringIO() yaml.dump(data, buf) assert buf.getvalue() == '%YAML 1.1\n---\nquote: I have seen things\n' yaml = YAML() - yaml.version = [1, 1] + yaml.version = [1, 1] # type: ignore data = yaml.load('quote: I have seen things') buf = StringIO() yaml.dump(data, buf) @@ -1140,10 +1140,63 @@ def test_issue_464(self) -> None: yaml.load('---\na: True\n...') def test_issue_467(self) -> None: + # cannot change the default constructor, following test will fail import ruamel.yaml yaml = ruamel.yaml.YAML() - yaml.constructor.add_constructor(yaml.resolver.DEFAULT_MAPPING_TAG, lambda x, y: None) + old_constructor = yaml.constructor.add_constructor( + yaml.resolver.DEFAULT_MAPPING_TAG, + lambda x, y: None, + ) + # this should be solved by the copy to the Constructor instance + if old_constructor is not None: + yaml.constructor.add_constructor( + yaml.resolver.DEFAULT_MAPPING_TAG, + old_constructor, + ) + + yaml = ruamel.yaml.YAML() + # for k, v in yaml.constructor.yaml_constructors.items(): + # print(k, v) + assert yaml.load('a: b') is not None + + def test_issue_480(self) -> None: + import sys + import ruamel.yaml + + yaml = ruamel.yaml.YAML() + data = yaml.load( + dedent(""" + # hi + {} + """), + ) + yaml.dump(data, sys.stdout) + + def test_issue_482(self) -> None: + import ruamel.yaml + from collections import OrderedDict + + def _ordered_constructor(loader: Any, node: Any) -> Any: + loader.flatten_mapping(node) + return OrderedDict(loader.construct_pairs(node)) + + content = 'foo: bar' + + yaml = ruamel.yaml.YAML(typ='safe', pure=True) + old_constructor = yaml.constructor.add_constructor( + yaml.Resolver.DEFAULT_MAPPING_TAG, + _ordered_constructor, + ) + + data = yaml.load(content) + print('data', data, type(data)) + assert isinstance(data, OrderedDict) + if old_constructor is not None: + yaml.constructor.add_constructor( + yaml.resolver.DEFAULT_MAPPING_TAG, + old_constructor, + ) # @pytest.mark.xfail(strict=True, reason='bla bla', raises=AssertionError) # def test_issue_ xxx(self) -> None: diff --git a/_test/test_yamlfile.py b/_test/test_yamlfile.py index ffee9f2..2fc8d7f 100644 --- a/_test/test_yamlfile.py +++ b/_test/test_yamlfile.py @@ -92,7 +92,8 @@ def test_set_out(self) -> None: x = set(['a', 'b', 'c']) # NOQA # cannot use round_trip_dump, it doesn't show null in block style buf = io.StringIO() - yaml = ruamel.yaml.YAML(typ='unsafe', pure=True) + with pytest.warns(PendingDeprecationWarning): + yaml = ruamel.yaml.YAML(typ='unsafe', pure=True) yaml.default_flow_style = False yaml.dump(x, buf) assert buf.getvalue() == dedent(""" @@ -112,6 +113,12 @@ def test_set_compact(self) -> None: ? c """) + def test_set_compact_flow(self) -> None: + # this format is read and also should be written by default + round_trip(""" + !!set {a, b, c} + """) + def test_blank_line_after_comment(self) -> None: round_trip(""" # Comment with spaces after it. diff --git a/_test/test_yamlobject.py b/_test/test_yamlobject.py index 7f7b14d..b5dd154 100644 --- a/_test/test_yamlobject.py +++ b/_test/test_yamlobject.py @@ -81,7 +81,8 @@ def test_qualified_name01(tmpdir: Any) -> None: import ruamel.yaml.comments from ruamel.yaml.compat import StringIO - yaml = YAML(typ='unsafe', pure=True) + with pytest.warns(PendingDeprecationWarning): + yaml = YAML(typ='unsafe', pure=True) yaml.explicit_end = True buf = StringIO() yaml.dump(ruamel.yaml.comments.CommentedBase.yaml_anchor, buf) diff --git a/comments.py b/comments.py index 4aea3c7..843b329 100644 --- a/comments.py +++ b/comments.py @@ -24,6 +24,7 @@ __all__ = ['CommentedSeq', 'CommentedKeySeq', 'CommentedMap', 'CommentedOrderedMap', 'CommentedSet', 'comment_attrib', 'merge_attrib', + 'TaggedScalar', 'C_POST', 'C_PRE', 'C_SPLIT_ON_FIRST_BLANK', 'C_BLANK_LINE_PRESERVE_SPACE', ] # fmt: on @@ -220,6 +221,9 @@ def flow_style(self, default: Optional[Any] = None) -> Any: return default return self._flow_style + def __repr__(self) -> str: + return f'Format({self._flow_style})' + class LineCol: """ @@ -432,7 +436,11 @@ def tag(self) -> Any: def yaml_set_ctag(self, value: Tag) -> None: setattr(self, Tag.attrib, value) - def copy_attributes(self, t: Any, memo: Any = None) -> None: + def copy_attributes(self, t: Any, memo: Any = None) -> Any: + """ + copies the YAML related attributes, not e.g. .values + returns target + """ # fmt: off for a in [Comment.attrib, Format.attrib, LineCol.attrib, Anchor.attrib, Tag.attrib, merge_attrib]: @@ -441,6 +449,7 @@ def copy_attributes(self, t: Any, memo: Any = None) -> None: setattr(t, a, copy.deepcopy(getattr(self, a, memo))) else: setattr(t, a, getattr(self, a)) + return t # fmt: on def _yaml_add_eol_comment(self, comment: Any, key: Any) -> None: @@ -1141,6 +1150,9 @@ def count(self, s: str, start: Optional[int] = None, end: Optional[int] = None) def __getitem__(self, pos: int) -> Any: return self.value[pos] + def __repr__(self) -> str: + return f'TaggedScalar(value={self.value!r}, style={self.style!r}, tag={self.tag!r})' + def dump_comments(d: Any, name: str = "", sep: str = '.', out: Any = sys.stdout) -> None: """ diff --git a/compat.py b/compat.py index c427246..9786fae 100644 --- a/compat.py +++ b/compat.py @@ -1,5 +1,7 @@ # coding: utf-8 +from __future__ import annotations + # partially from package six by Benjamin Peterson import sys @@ -19,7 +21,6 @@ SupportsIndex = int # type: ignore # fmt: on - _DEFAULT_YAML_VERSION = (1, 2) try: @@ -50,12 +51,11 @@ def insert(self, pos: int, key: Any, value: Any) -> None: StringIO = io.StringIO BytesIO = io.BytesIO -# StreamType = Union[BinaryIO, IO[str], IO[unicode], StringIO] -# StreamType = Union[BinaryIO, IO[str], StringIO] # type: ignore StreamType = Any -StreamTextType = StreamType # Union[Text, StreamType] -VersionType = Union[List[int], str, Tuple[int, int]] +StreamTextType = StreamType +from ruamel.yaml.docinfo import Version # NOQA +VersionType = Union[str , Tuple[int, int] , List[int] , Version , None] builtins_module = 'builtins' @@ -97,17 +97,17 @@ def dump(self) -> None: # used from yaml util when testing def dbg(val: Any = None) -> Any: - global _debug - if _debug is None: + debug = _debug + if debug is None: # set to true or false _debugx = os.environ.get('YAMLDEBUG') if _debugx is None: - _debug = 0 + debug = 0 else: - _debug = int(_debugx) + debug = int(_debugx) if val is None: - return _debug - return _debug & val + return debug + return debug & val class Nprint: diff --git a/constructor.py b/constructor.py index 6f65b0b..e4f6f16 100644 --- a/constructor.py +++ b/constructor.py @@ -17,6 +17,7 @@ nprint, nprintf, version_tnf) from ruamel.yaml.compat import ordereddict +from ruamel.yaml.tag import Tag from ruamel.yaml.comments import * # NOQA from ruamel.yaml.comments import (CommentedMap, CommentedOrderedMap, CommentedSet, CommentedKeySeq, CommentedSeq, TaggedScalar, @@ -310,11 +311,17 @@ def construct_pairs(self, node: Any, deep: bool = False) -> Any: pairs.append((key, value)) return pairs + # ToDo: putting stuff on the class makes it global, consider making this to work on an + # instance variable once function load is dropped. @classmethod - def add_constructor(cls, tag: Any, constructor: Any) -> None: + def add_constructor(cls, tag: Any, constructor: Any) -> Any: + if isinstance(tag, Tag): + tag = str(tag) if 'yaml_constructors' not in cls.__dict__: cls.yaml_constructors = cls.yaml_constructors.copy() + ret_val = cls.yaml_constructors.get(tag, None) cls.yaml_constructors[tag] = constructor + return ret_val @classmethod def add_multi_constructor(cls, tag_prefix: Any, multi_constructor: Any) -> None: @@ -1581,6 +1588,10 @@ def construct_yaml_omap(self, node: Any) -> Iterator[CommentedOrderedMap]: def construct_yaml_set(self, node: Any) -> Iterator[CommentedSet]: data = CommentedSet() data._yaml_set_line_col(node.start_mark.line, node.start_mark.column) + if node.flow_style is True: + data.fa.set_flow_style() + elif node.flow_style is False: + data.fa.set_block_style() yield data self.construct_setting(node, data) diff --git a/docinfo.py b/docinfo.py new file mode 100644 index 0000000..aec6ea7 --- /dev/null +++ b/docinfo.py @@ -0,0 +1,67 @@ + +from __future__ import annotations + +""" +DocInfo + +Although it was possible to read tag directives before this, all handle/prefix +pairs for all documents in all streams were stored in one dictionary per +YAML instance, making it impossible to distinguish where such a pair came +from without sublassing the scanner. + +ToDo: +DocInfo can be used by a yaml dumper to dump a class +- if connected to the root of a data structure +- if provided to the dumper? +""" + +from typing import Optional, Tuple +from dataclasses import dataclass, field, MISSING # NOQA + + +@dataclass(order=True, frozen=True) +class Version: + major: int + minor: int + + # def __repr__(self): + # return f'Version("{self.major}.{self.minor}")' + + +def version( + major: int | str | Tuple[int, int] | None, + minor: Optional[int] = None, +) -> Optional[Version]: + if major is None: + assert minor is None + return None + if isinstance(major, str): + assert minor is None + parts = major.split('.') + assert len(parts) == 2 + return Version(int(parts[0]), int(parts[1])) + elif isinstance(major, tuple): + assert minor is None + assert len(major) == 2 + major, minor = major + assert minor is not None + return Version(major, minor) + + +@dataclass(frozen=True) +class Tag: + handle: str + prefix: str + + +@dataclass +class DocInfo: + """ + Store document information, can be used for analysis of a loaded YAML document + requested_version: if explicitly set before load + doc_version: from %YAML directive + tags: from %TAG directives in scanned order + """ + requested_version: Optional[Version] = None + doc_version: Optional[Version] = None + tags: list[Tag] = field(default_factory=list) diff --git a/emitter.py b/emitter.py index d3eb0bb..1d58be2 100644 --- a/emitter.py +++ b/emitter.py @@ -48,6 +48,9 @@ def __init__( self.allow_double_quoted = allow_double_quoted self.allow_block = allow_block + def __repr__(self) -> str: + return f'scalar={self.scalar!r}, empty={self.empty}, multiline={self.multiline}, allow_flow_plain={self.allow_flow_plain}, allow_block_plain={self.allow_block_plain}, allow_single_quoted={self.allow_single_quoted}, allow_double_quoted={self.allow_double_quoted}, allow_block={self.allow_block}' # NOQA + class Indents: # replacement for the list based stack of None/int @@ -60,6 +63,14 @@ def append(self, val: Any, seq: Any) -> None: def pop(self) -> Any: return self.values.pop()[0] + def seq_seq(self) -> bool: + try: + if self.values[-2][1] and self.values[-1][1]: + return True + except IndexError: + pass + return False + def last_seq(self) -> bool: # return the seq(uence) value for the element added before the last one # in increase_indent() @@ -416,7 +427,6 @@ def expect_node( # nprint('@', self.indention, self.no_newline, self.column) self.expect_scalar() elif isinstance(self.event, SequenceStartEvent): - # nprint('@', self.indention, self.no_newline, self.column) i2, n2 = self.indention, self.no_newline # NOQA if self.event.comment: if self.event.flow_style is False: @@ -442,12 +452,16 @@ def expect_node( self.expect_flow_sequence(force_flow_indent) else: self.expect_block_sequence() + if self.indents.seq_seq(): + # - - + self.indention = True + self.no_newline = False elif isinstance(self.event, MappingStartEvent): if self.event.flow_style is False and self.event.comment: self.write_post_comment(self.event) if self.event.comment and self.event.comment[1]: self.write_pre_comment(self.event) - if self.event.flow_style: + if self.event.flow_style and self.indents.values: force_flow_indent = not self.indents.values[-1][1] if ( self.flow_level @@ -513,6 +527,9 @@ def expect_flow_sequence_item(self) -> None: popped = self.flow_context.pop() assert popped == '[' if self.canonical: + # ToDo: so-39595807, maybe add a space to the flow_seq_separator + # and strip the last space, if space then indent, else do not + # not sure that [1,2,3] is a valid YAML seq self.write_indicator(self.flow_seq_separator, False) self.write_indent() self.write_indicator(self.flow_seq_end, False) @@ -609,7 +626,8 @@ def expect_flow_mapping_key(self) -> None: self.expect_node(mapping=True) def expect_flow_mapping_simple_value(self) -> None: - self.write_indicator(self.prefixed_colon, False) + if getattr(self.event, 'style', '?') != '-': # suppress for flow style sets + self.write_indicator(self.prefixed_colon, False) self.states.append(self.expect_flow_mapping_key) self.expect_node(mapping=True) @@ -838,7 +856,7 @@ def choose_scalar_style(self) -> Any: self.analysis = self.analyze_scalar(self.event.value) if self.event.style == '"' or self.canonical: return '"' - if (not self.event.style or self.event.style == '?') and ( + if (not self.event.style or self.event.style == '?' or self.event.style == '-') and ( self.event.implicit[0] or not self.event.implicit[2] ): if not ( @@ -849,6 +867,8 @@ def choose_scalar_style(self) -> Any: or (not self.flow_level and self.analysis.allow_block_plain) ): return "" + if self.event.style == '-': + return "" self.analysis.allow_block = True if self.event.style and self.event.style in '|>': if ( @@ -886,7 +906,7 @@ def process_scalar(self) -> None: elif self.style == '>': try: cmx = self.event.comment[1][0] - except (IndexError, TypeError): + except (IndexError, TypeError) as e: # NOQA cmx = "" self.write_folded(self.analysis.scalar, cmx) if ( @@ -1709,6 +1729,8 @@ def write_comment(self, comment: Any, pre: bool = False) -> None: self.write_line_break() def write_pre_comment(self, event: Any) -> bool: + if event.comment is None: + return False comments = event.comment[1] if comments is None: return False @@ -1740,7 +1762,6 @@ def prepare_tag(self, ctag: Any) -> Any: if not ctag: raise EmitterError('tag must not be empty') tag = str(ctag) - # print('handling', repr(tag)) if tag == '!' or tag == '!!': return tag handle = ctag.handle diff --git a/main.py b/main.py index 92ec817..b80c1f5 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,7 @@ # coding: utf-8 +from __future__ import annotations + import sys import os import warnings @@ -32,8 +34,9 @@ ) from ruamel.yaml.loader import Loader as UnsafeLoader # NOQA from ruamel.yaml.comments import CommentedMap, CommentedSeq, C_PRE +from ruamel.yaml.docinfo import DocInfo, version, Version -from typing import List, Set, Dict, Union, Any, Callable, Optional, Text, Type # NOQA +from typing import List, Set, Dict, Tuple, Union, Any, Callable, Optional, Text, Type # NOQA from types import TracebackType from ruamel.yaml.compat import StreamType, StreamTextType, VersionType # NOQA from pathlib import Path # NOQA @@ -62,7 +65,9 @@ def __init__( """ typ: 'rt'/None -> RoundTripLoader/RoundTripDumper, (default) 'safe' -> SafeLoader/SafeDumper, - 'unsafe' -> normal/unsafe Loader/Dumper + 'unsafe' -> normal/unsafe Loader/Dumper (pending deprecation) + 'full' -> full Dumper only, including python built-ins that are + potentially unsafe to load 'base' -> baseloader pure: if True only use Python modules input/output: needed to work as context manager @@ -108,6 +113,11 @@ def __init__( self.Composer = ruamel.yaml.composer.Composer self.Constructor = ruamel.yaml.constructor.BaseConstructor elif 'unsafe' in self.typ: + warnings.warn( + "\nyou should no longer specify 'unsafe'.\nFor **dumping only** use yaml=YAML(typ='full')\n", # NOQA + PendingDeprecationWarning, + stacklevel=2, + ) self.Emitter = ( ruamel.yaml.emitter.Emitter if pure or CEmitter is None else CEmitter ) @@ -115,6 +125,14 @@ def __init__( self.Parser = ruamel.yaml.parser.Parser if pure or CParser is None else CParser self.Composer = ruamel.yaml.composer.Composer self.Constructor = ruamel.yaml.constructor.Constructor + elif 'full' in self.typ: + self.Emitter = ( + ruamel.yaml.emitter.Emitter if pure or CEmitter is None else CEmitter + ) + self.Representer = ruamel.yaml.representer.Representer + self.Parser = ruamel.yaml.parser.Parser if pure or CParser is None else CParser + # self.Composer = ruamel.yaml.composer.Composer + # self.Constructor = ruamel.yaml.constructor.Constructor elif 'rtsc' in self.typ: self.default_flow_style = False # no optimized rt-dumper yet @@ -163,7 +181,8 @@ def __init__( self.encoding = 'utf-8' self.explicit_start: Union[bool, None] = None self.explicit_end: Union[bool, None] = None - self.tags = None + self._tags = None + self.doc_infos: List[DocInfo] = [] self.default_style = None self.top_level_block_style_scalar_no_indent_error_1_1 = False # directives end indicator with single scalar document @@ -228,17 +247,25 @@ def composer(self) -> Any: def constructor(self) -> Any: attr = '_' + sys._getframe().f_code.co_name if not hasattr(self, attr): - cnst = self.Constructor(preserve_quotes=self.preserve_quotes, loader=self) + if self.Constructor is None: + if 'full' in self.typ: + raise YAMLError( + "\nyou can only use yaml=YAML(typ='full') for dumping\n", # NOQA + ) + cnst = self.Constructor(preserve_quotes=self.preserve_quotes, loader=self) # type: ignore # NOQA cnst.allow_duplicate_keys = self.allow_duplicate_keys setattr(self, attr, cnst) return getattr(self, attr) @property def resolver(self) -> Any: - attr = '_' + sys._getframe().f_code.co_name - if not hasattr(self, attr): - setattr(self, attr, self.Resolver(version=self.version, loader=self)) - return getattr(self, attr) + try: + rslvr = self._resolver # type: ignore + except AttributeError: + rslvr = None + if rslvr is None or rslvr._loader_version != self.version: + rslvr = self._resolver = self.Resolver(version=self.version, loader=self) + return rslvr @property def emitter(self) -> Any: @@ -315,20 +342,19 @@ def scan(self, stream: StreamTextType) -> Any: # pathlib.Path() instance with stream.open('rb') as fp: return self.scan(fp) + self.doc_infos.append(DocInfo(requested_version=version(self.version))) + self.tags = {} _, parser = self.get_constructor_parser(stream) try: while self.scanner.check_token(): yield self.scanner.get_token() finally: parser.dispose() - try: - self._reader.reset_reader() - except AttributeError: - pass - try: - self._scanner.reset_scanner() - except AttributeError: - pass + for comp in ('reader', 'scanner'): + try: + getattr(getattr(self, '_' + comp), f'reset_{comp}')() + except AttributeError: + pass def parse(self, stream: StreamTextType) -> Any: """ @@ -338,20 +364,19 @@ def parse(self, stream: StreamTextType) -> Any: # pathlib.Path() instance with stream.open('rb') as fp: return self.parse(fp) + self.doc_infos.append(DocInfo(requested_version=version(self.version))) + self.tags = {} _, parser = self.get_constructor_parser(stream) try: while parser.check_event(): yield parser.get_event() finally: parser.dispose() - try: - self._reader.reset_reader() - except AttributeError: - pass - try: - self._scanner.reset_scanner() - except AttributeError: - pass + for comp in ('reader', 'scanner'): + try: + getattr(getattr(self, '_' + comp), f'reset_{comp}')() + except AttributeError: + pass def compose(self, stream: Union[Path, StreamTextType]) -> Any: """ @@ -362,39 +387,37 @@ def compose(self, stream: Union[Path, StreamTextType]) -> Any: # pathlib.Path() instance with stream.open('rb') as fp: return self.compose(fp) + self.doc_infos.append(DocInfo(requested_version=version(self.version))) + self.tags = {} constructor, parser = self.get_constructor_parser(stream) try: return constructor.composer.get_single_node() finally: parser.dispose() - try: - self._reader.reset_reader() - except AttributeError: - pass - try: - self._scanner.reset_scanner() - except AttributeError: - pass + for comp in ('reader', 'scanner'): + try: + getattr(getattr(self, '_' + comp), f'reset_{comp}')() + except AttributeError: + pass def compose_all(self, stream: Union[Path, StreamTextType]) -> Any: """ Parse all YAML documents in a stream and produce corresponding representation trees. """ + self.doc_infos.append(DocInfo(requested_version=version(self.version))) + self.tags = {} constructor, parser = self.get_constructor_parser(stream) try: while constructor.composer.check_node(): yield constructor.composer.get_node() finally: parser.dispose() - try: - self._reader.reset_reader() - except AttributeError: - pass - try: - self._scanner.reset_scanner() - except AttributeError: - pass + for comp in ('reader', 'scanner'): + try: + getattr(getattr(self, '_' + comp), f'reset_{comp}')() + except AttributeError: + pass # separate output resolver? @@ -421,19 +444,18 @@ def load(self, stream: Union[Path, StreamTextType]) -> Any: # pathlib.Path() instance with stream.open('rb') as fp: return self.load(fp) + self.doc_infos.append(DocInfo(requested_version=version(self.version))) + self.tags = {} constructor, parser = self.get_constructor_parser(stream) try: return constructor.get_single_data() finally: parser.dispose() - try: - self._reader.reset_reader() - except AttributeError: - pass - try: - self._scanner.reset_scanner() - except AttributeError: - pass + for comp in ('reader', 'scanner'): + try: + getattr(getattr(self, '_' + comp), f'reset_{comp}')() + except AttributeError: + pass def load_all(self, stream: Union[Path, StreamTextType]) -> Any: # *, skip=None): if not hasattr(stream, 'read') and hasattr(stream, 'open'): @@ -446,25 +468,30 @@ def load_all(self, stream: Union[Path, StreamTextType]) -> Any: # *, skip=None) # skip = [] # elif isinstance(skip, int): # skip = [skip] + self.doc_infos.append(DocInfo(requested_version=version(self.version))) + self.tags = {} constructor, parser = self.get_constructor_parser(stream) try: while constructor.check_data(): yield constructor.get_data() + self.doc_infos.append(DocInfo(requested_version=version(self.version))) finally: parser.dispose() - try: - self._reader.reset_reader() - except AttributeError: - pass - try: - self._scanner.reset_scanner() - except AttributeError: - pass + for comp in ('reader', 'scanner'): + try: + getattr(getattr(self, '_' + comp), f'reset_{comp}')() + except AttributeError: + pass def get_constructor_parser(self, stream: StreamTextType) -> Any: """ the old cyaml needs special setup, and therefore the stream """ + if self.Constructor is None: + if 'full' in self.typ: + raise YAMLError( + "\nyou can only use yaml=YAML(typ='full') for dumping\n", # NOQA + ) if self.Parser is not CParser: if self.Reader is None: self.Reader = ruamel.yaml.reader.Reader @@ -705,6 +732,7 @@ def __init__( width=self.width, allow_unicode=self.allow_unicode, line_break=self.line_break, + encoding=self.encoding, explicit_start=self.explicit_start, explicit_end=self.explicit_end, version=self.version, @@ -798,23 +826,35 @@ def _indent(self, mapping: Any = None, sequence: Any = None, offset: Any = None) self.sequence_dash_offset = offset @property - def version(self) -> Optional[Any]: + def version(self) -> Optional[Tuple[int, int]]: return self._version @version.setter - def version(self, val: Optional[VersionType]) -> None: + def version(self, val: VersionType) -> None: if val is None: self._version = val return - if isinstance(val, str): + elif isinstance(val, str): sval = tuple(int(x) for x in val.split('.')) - else: + elif isinstance(val, (list, tuple)): sval = tuple(int(x) for x in val) + elif isinstance(val, Version): + sval = (val.major, val.minor) + else: + raise TypeError(f'unknown version type {type(val)}') assert len(sval) == 2, f'version can only have major.minor, got {val}' assert sval[0] == 1, f'version major part can only be 1, got {val}' assert sval[1] in [1, 2], f'version minor part can only be 2 or 1, got {val}' self._version = sval + @property + def tags(self) -> Any: + return self._tags + + @tags.setter + def tags(self, val: Any) -> None: + self._tags = val + @property def indent(self) -> Any: return self._indent @@ -982,15 +1022,26 @@ def warn_deprecation(fun: Any, method: Any, arg: str = '') -> None: ) -def error_deprecation(fun: Any, method: Any, arg: str = '') -> None: - warnings.warn( - f'\n{fun} has been removed, use\n\n yaml=YAML({arg})\n yaml.{method}(...)\n\ninstead', # NOQA - DeprecationWarning, - stacklevel=3, - ) - sys.exit(1) +def error_deprecation(fun: Any, method: Any, arg: str = '', comment: str = 'instead of') -> None: # NOQA + import inspect + + s = f'\n"{fun}()" has been removed, use\n\n yaml = YAML({arg})\n yaml.{method}(...)\n\n{comment}' # NOQA + try: + info = inspect.getframeinfo(inspect.stack()[2][0]) + context = '' if info.code_context is None else "".join(info.code_context) + s += f' file "{info.filename}", line {info.lineno}\n\n{context}' + except Exception as e: + _ = e + s += '\n' + if sys.version_info < (3, 10): + raise AttributeError(s) + else: + raise AttributeError(s, name=None) +_error_dep_arg = "typ='rt'" +_error_dep_comment = "and register any classes that you use, or check the tag attribute on the loaded data,\ninstead of" # NOQA + ######################################################################################## @@ -998,26 +1049,14 @@ def scan(stream: StreamTextType, Loader: Any = Loader) -> Any: """ Scan a YAML stream and produce scanning tokens. """ - warn_deprecation('scan', 'scan', arg="typ='unsafe', pure=True") - loader = Loader(stream) - try: - while loader.scanner.check_token(): - yield loader.scanner.get_token() - finally: - loader._parser.dispose() + error_deprecation('scan', 'scan', arg=_error_dep_arg, comment=_error_dep_comment) def parse(stream: StreamTextType, Loader: Any = Loader) -> Any: """ Parse a YAML stream and produce parsing events. """ - warn_deprecation('parse', 'parse', arg="typ='unsafe', pure=True") - loader = Loader(stream) - try: - while loader._parser.check_event(): - yield loader._parser.get_event() - finally: - loader._parser.dispose() + error_deprecation('parse', 'parse', arg=_error_dep_arg, comment=_error_dep_comment) def compose(stream: StreamTextType, Loader: Any = Loader) -> Any: @@ -1025,12 +1064,7 @@ def compose(stream: StreamTextType, Loader: Any = Loader) -> Any: Parse the first YAML document in a stream and produce the corresponding representation tree. """ - warn_deprecation('compose', 'compose', arg="typ='unsafe', pure=True") - loader = Loader(stream) - try: - return loader.get_single_node() - finally: - loader.dispose() + error_deprecation('compose', 'compose', arg=_error_dep_arg, comment=_error_dep_comment) def compose_all(stream: StreamTextType, Loader: Any = Loader) -> Any: @@ -1038,13 +1072,7 @@ def compose_all(stream: StreamTextType, Loader: Any = Loader) -> Any: Parse all YAML documents in a stream and produce corresponding representation trees. """ - warn_deprecation('compose', 'compose', arg="typ='unsafe', pure=True") - loader = Loader(stream) - try: - while loader.check_node(): - yield loader._composer.get_node() - finally: - loader._parser.dispose() + error_deprecation('compose', 'compose', arg=_error_dep_arg, comment=_error_dep_comment) def load( @@ -1054,23 +1082,7 @@ def load( Parse the first YAML document in a stream and produce the corresponding Python object. """ - warn_deprecation('load', 'load', arg="typ='unsafe', pure=True") - if Loader is None: - warnings.warn(UnsafeLoaderWarning.text, UnsafeLoaderWarning, stacklevel=2) - Loader = UnsafeLoader - loader = Loader(stream, version, preserve_quotes=preserve_quotes) # type: Any - try: - return loader._constructor.get_single_data() - finally: - loader._parser.dispose() - try: - loader._reader.reset_reader() - except AttributeError: - pass - try: - loader._scanner.reset_scanner() - except AttributeError: - pass + error_deprecation('load', 'load', arg=_error_dep_arg, comment=_error_dep_comment) def load_all( @@ -1081,24 +1093,7 @@ def load_all( Parse all YAML documents in a stream and produce corresponding Python objects. """ - warn_deprecation('load_all', 'load_all', arg="typ='unsafe', pure=True") - if Loader is None: - warnings.warn(UnsafeLoaderWarning.text, UnsafeLoaderWarning, stacklevel=2) - Loader = UnsafeLoader - loader = Loader(stream, version, preserve_quotes=preserve_quotes) # type: Any - try: - while loader._constructor.check_data(): - yield loader._constructor.get_data() - finally: - loader._parser.dispose() - try: - loader._reader.reset_reader() - except AttributeError: - pass - try: - loader._scanner.reset_scanner() - except AttributeError: - pass + error_deprecation('load_all', 'load_all', arg=_error_dep_arg, comment=_error_dep_comment) def safe_load(stream: StreamTextType, version: Optional[VersionType] = None) -> Any: @@ -1107,8 +1102,7 @@ def safe_load(stream: StreamTextType, version: Optional[VersionType] = None) -> and produce the corresponding Python object. Resolve only basic YAML tags. """ - warn_deprecation('safe_load', 'load', arg="typ='safe', pure=True") - return load(stream, SafeLoader, version) + error_deprecation('safe_load', 'load', arg="typ='safe', pure=True") def safe_load_all(stream: StreamTextType, version: Optional[VersionType] = None) -> Any: @@ -1117,8 +1111,7 @@ def safe_load_all(stream: StreamTextType, version: Optional[VersionType] = None) and produce corresponding Python objects. Resolve only basic YAML tags. """ - warn_deprecation('safe_load_all', 'load_all', arg="typ='safe', pure=True") - return load_all(stream, SafeLoader, version) + error_deprecation('safe_load_all', 'load_all', arg="typ='safe', pure=True") def round_trip_load( @@ -1131,8 +1124,7 @@ def round_trip_load( and produce the corresponding Python object. Resolve only basic YAML tags. """ - warn_deprecation('round_trip_load_all', 'load') - return load(stream, RoundTripLoader, version, preserve_quotes=preserve_quotes) + error_deprecation('round_trip_load_all', 'load') def round_trip_load_all( @@ -1145,8 +1137,7 @@ def round_trip_load_all( and produce corresponding Python objects. Resolve only basic YAML tags. """ - warn_deprecation('round_trip_load_all', 'load_all') - return load_all(stream, RoundTripLoader, version, preserve_quotes=preserve_quotes) + error_deprecation('round_trip_load_all', 'load_all') def emit( @@ -1164,30 +1155,7 @@ def emit( Emit YAML parsing events into a stream. If stream is None, return the produced string instead. """ - warn_deprecation('emit', 'emit', arg="typ='safe', pure=True") - getvalue = None - if stream is None: - stream = StringIO() - getvalue = stream.getvalue - dumper = Dumper( - stream, - canonical=canonical, - indent=indent, - width=width, - allow_unicode=allow_unicode, - line_break=line_break, - ) - try: - for event in events: - dumper.emit(event) - finally: - try: - dumper._emitter.dispose() - except AttributeError: - raise - dumper.dispose() # cyaml - if getvalue is not None: - return getvalue() + error_deprecation('emit', 'emit', arg="typ='safe', pure=True") enc = None @@ -1213,40 +1181,7 @@ def serialize_all( Serialize a sequence of representation trees into a YAML stream. If stream is None, return the produced string instead. """ - warn_deprecation('serialize_all', 'serialize_all', arg="typ='safe', pure=True") - getvalue = None - if stream is None: - if encoding is None: - stream = StringIO() - else: - stream = BytesIO() - getvalue = stream.getvalue - dumper = Dumper( - stream, - canonical=canonical, - indent=indent, - width=width, - allow_unicode=allow_unicode, - line_break=line_break, - encoding=encoding, - version=version, - tags=tags, - explicit_start=explicit_start, - explicit_end=explicit_end, - ) - try: - dumper._serializer.open() - for node in nodes: - dumper.serialize(node) - dumper._serializer.close() - finally: - try: - dumper._emitter.dispose() - except AttributeError: - raise - dumper.dispose() # cyaml - if getvalue is not None: - return getvalue() + error_deprecation('serialize_all', 'serialize_all', arg="typ='safe', pure=True") def serialize( @@ -1256,8 +1191,7 @@ def serialize( Serialize a representation tree into a YAML stream. If stream is None, return the produced string instead. """ - warn_deprecation('serialize', 'serialize', arg="typ='safe', pure=True") - return serialize_all([node], stream, Dumper=Dumper, **kwds) + error_deprecation('serialize', 'serialize', arg="typ='safe', pure=True") def dump_all( @@ -1285,52 +1219,7 @@ def dump_all( Serialize a sequence of Python objects into a YAML stream. If stream is None, return the produced string instead. """ - warn_deprecation('dump_all', 'dump_all', arg="typ='unsafe', pure=True") - getvalue = None - if top_level_colon_align is True: - top_level_colon_align = max([len(str(x)) for x in documents[0]]) - if stream is None: - if encoding is None: - stream = StringIO() - else: - stream = BytesIO() - getvalue = stream.getvalue - dumper = Dumper( - stream, - default_style=default_style, - default_flow_style=default_flow_style, - canonical=canonical, - indent=indent, - width=width, - allow_unicode=allow_unicode, - line_break=line_break, - encoding=encoding, - explicit_start=explicit_start, - explicit_end=explicit_end, - version=version, - tags=tags, - block_seq_indent=block_seq_indent, - top_level_colon_align=top_level_colon_align, - prefix_colon=prefix_colon, - ) - try: - dumper._serializer.open() - for data in documents: - try: - dumper._representer.represent(data) - except AttributeError: - # nprint(dir(dumper._representer)) - raise - dumper._serializer.close() - finally: - try: - dumper._emitter.dispose() - except AttributeError: - raise - dumper.dispose() # cyaml - if getvalue is not None: - return getvalue() - return None + error_deprecation('dump_all', 'dump_all', arg="typ='unsafe', pure=True") def dump( @@ -1359,25 +1248,7 @@ def dump( default_style ∈ None, '', '"', "'", '|', '>' """ - warn_deprecation('dump', 'dump', arg="typ='unsafe', pure=True") - return dump_all( - [data], - stream, - Dumper=Dumper, - default_style=default_style, - default_flow_style=default_flow_style, - canonical=canonical, - indent=indent, - width=width, - allow_unicode=allow_unicode, - line_break=line_break, - encoding=encoding, - explicit_start=explicit_start, - explicit_end=explicit_end, - version=version, - tags=tags, - block_seq_indent=block_seq_indent, - ) + error_deprecation('dump', 'dump', arg="typ='unsafe', pure=True") def safe_dump(data: Any, stream: Optional[StreamType] = None, **kwds: Any) -> Any: @@ -1386,8 +1257,7 @@ def safe_dump(data: Any, stream: Optional[StreamType] = None, **kwds: Any) -> An Produce only basic YAML tags. If stream is None, return the produced string instead. """ - warn_deprecation('safe_dump', 'dump', arg="typ='safe', pure=True") - return dump_all([data], stream, Dumper=SafeDumper, **kwds) + error_deprecation('safe_dump', 'dump', arg="typ='safe', pure=True") def round_trip_dump( @@ -1411,27 +1281,7 @@ def round_trip_dump( prefix_colon: Any = None, ) -> Any: allow_unicode = True if allow_unicode is None else allow_unicode - warn_deprecation('round_trip_dump', 'dump') - return dump_all( - [data], - stream, - Dumper=Dumper, - default_style=default_style, - default_flow_style=default_flow_style, - canonical=canonical, - indent=indent, - width=width, - allow_unicode=allow_unicode, - line_break=line_break, - encoding=encoding, - explicit_start=explicit_start, - explicit_end=explicit_end, - version=version, - tags=tags, - block_seq_indent=block_seq_indent, - top_level_colon_align=top_level_colon_align, - prefix_colon=prefix_colon, - ) + error_deprecation('round_trip_dump', 'dump') # Loader/Dumper are no longer composites, to get to the associated diff --git a/nodes.py b/nodes.py index 7ab43e7..1721049 100644 --- a/nodes.py +++ b/nodes.py @@ -78,6 +78,7 @@ class ScalarNode(Node): """ styles: ? -> set() ? key, no value + - -> suppressable null value in set " -> double quoted ' -> single quoted | -> literal style diff --git a/parser.py b/parser.py index 8cb9a37..b031aa6 100644 --- a/parser.py +++ b/parser.py @@ -314,11 +314,14 @@ def process_directives(self) -> Any: else: value = yaml_version, None if self.loader is not None and hasattr(self.loader, 'tags'): + # ToDo: this is used to keep a single loaded file from losing its version + # info, but it affects following versions that have no explicit directive self.loader.version = yaml_version if self.loader.tags is None: self.loader.tags = {} for k in self.tag_handles: self.loader.tags[k] = self.tag_handles[k] + self.loader.doc_infos[-1].tags.append((k, self.tag_handles[k])) for key in self.DEFAULT_TAGS: if key not in self.tag_handles: self.tag_handles[key] = self.DEFAULT_TAGS[key] @@ -383,6 +386,10 @@ def parse_node(self, block: bool = False, indentless_sequence: bool = False) -> ) elif self.scanner.check_token(TagToken): token = self.scanner.get_token() + try: + self.move_token_comment(token) + except NotImplementedError: + pass start_mark = tag_mark = token.start_mark end_mark = token.end_mark # tag = token.value @@ -412,6 +419,9 @@ def parse_node(self, block: bool = False, indentless_sequence: bool = False) -> if pt.comment and pt.comment[0]: comment = [pt.comment[0], []] pt.comment[0] = None + elif pt.comment and pt.comment[0] is None and pt.comment[1]: + comment = [None, pt.comment[1]] + pt.comment[1] = None elif self.loader: if pt.comment: comment = pt.comment @@ -432,7 +442,6 @@ def parse_node(self, block: bool = False, indentless_sequence: bool = False) -> dimplicit = (False, True) else: dimplicit = (False, False) - # nprint('se', token.value, token.comment) event = ScalarEvent( anchor, tag, @@ -821,8 +830,8 @@ def distribute_comment(self, comment: Any, line: Any) -> Any: return None if not comment[0]: return None - if comment[0][0] != line + 1: - nprintf('>>>dcxxx', comment, line) + # if comment[0][0] != line + 1: + # nprintf('>>>dcxxx', comment, line) assert comment[0][0] == line + 1 # if comment[0] - line > 1: # return diff --git a/representer.py b/representer.py index 7c89545..0d1ca12 100644 --- a/representer.py +++ b/representer.py @@ -980,7 +980,8 @@ def represent_set(self, setting: Any) -> MappingNode: if item_comment: assert getattr(node_key, 'comment', None) is None node_key.comment = item_comment[:2] - node_key.style = node_value.style = '?' + node_key.style = '?' + node_value.style = '-' if flow_style else '?' if not (isinstance(node_key, ScalarNode) and not node_key.style): best_style = False if not (isinstance(node_value, ScalarNode) and not node_value.style): diff --git a/resolver.py b/resolver.py index 71ba4c7..aa3ca11 100644 --- a/resolver.py +++ b/resolver.py @@ -330,6 +330,7 @@ def get_loader_version(self, version: Optional[VersionType]) -> Any: if isinstance(version, list): return tuple(version) # assume string + assert isinstance(version, str) return tuple(map(int, version.split('.'))) @property diff --git a/scanner.py b/scanner.py index 11779f4..65d9a77 100644 --- a/scanner.py +++ b/scanner.py @@ -31,10 +31,10 @@ import inspect from ruamel.yaml.error import MarkedYAMLError, CommentMark # NOQA from ruamel.yaml.tokens import * # NOQA +from ruamel.yaml.docinfo import Version, Tag # NOQA from ruamel.yaml.compat import check_anchorname_char, nprint, nprintf # NOQA -from typing import Any, Dict, Optional, List, Union, Text # NOQA -from ruamel.yaml.compat import VersionType # NOQA +from typing import Any, Dict, Optional, List, Union, Text, Tuple # NOQA __all__ = ['Scanner', 'RoundTripScanner', 'ScannerError'] @@ -84,7 +84,6 @@ def __init__(self, loader: Any = None) -> None: self.loader._scanner = self self.reset_scanner() self.first_time = False - self.yaml_version: Any = None @property def flow_level(self) -> int: @@ -142,6 +141,8 @@ def reset_scanner(self) -> None: # A simple key may start with ALIAS, ANCHOR, TAG, SCALAR(flow), # '[', or '{' tokens. self.possible_simple_keys: Dict[Any, Any] = {} + self.yaml_version: Any = None + self.tag_directives: List[Tuple[Any, Any]] = [] @property def reader(self) -> Any: @@ -911,6 +912,7 @@ def scan_yaml_directive_value(self, start_mark: Any) -> Any: self.reader.get_mark(), ) self.yaml_version = (major, minor) + self.loader.doc_infos[-1].doc_version = Version(major, minor) return self.yaml_version def scan_yaml_directive_number(self, start_mark: Any) -> Any: @@ -942,7 +944,9 @@ def scan_tag_directive_value(self, start_mark: Any) -> Any: while srp() == ' ': srf() prefix = self.scan_tag_directive_prefix(start_mark) - return (handle, prefix) + ret_val = (handle, prefix) + self.tag_directives.append(ret_val) + return ret_val def scan_tag_directive_handle(self, start_mark: Any) -> Any: # See the specification for details. diff --git a/setup.py b/setup.py index b60f159..3154575 100644 --- a/setup.py +++ b/setup.py @@ -526,6 +526,24 @@ def url(self): sp = sp.replace(ch, '-') return 'https://sourceforge.net/p/{0}/code/ci/default/tree'.format(sp) + @property + def project_urls(self): + ret_val = {} + sp = self.full_package_name + for ch in '_.': + sp = sp.replace(ch, '-') + base_url = self._pkg_data.get('url', 'https://sourceforge.net/p/{0}'.format(sp)) + if base_url[-1] != '/': + base_url += '/' + ret_val['Home'] = base_url + if 'sourceforge.net' in base_url: + ret_val['Source'] = base_url + 'code/ci/default/tree/' + ret_val['Tracker'] = base_url + 'tickets/' + rtfd = self._pkg_data.get('read_the_docs') + if rtfd: + ret_val['Documentation'] = 'https://{0}.readthedocs.io/'.format(rtfd) + return ret_val + @property def author(self): return self._pkg_data['author'] # no get needs to be there @@ -853,7 +871,8 @@ def main(): version=version_str, packages=nsp.packages, python_requires=nsp.python_requires, - url=nsp.url, + # url=nsp.url, + project_urls=nsp.project_urls, author=nsp.author, author_email=nsp.author_email, cmdclass=cmdclass, @@ -879,12 +898,17 @@ def main(): # return if dump_kw in sys.argv: sys.argv.remove(dump_kw) - try: - with open('README.rst') as fp: - kw['long_description'] = fp.read() - kw['long_description_content_type'] = 'text/x-rst' - except Exception: - pass + if not os.environ.get('RUAMEL_NO_LONG_DESCRIPTION', False): + for readme_file_name, readme_markup_type in [ + ('README.md', 'text/markdown; charset=UTF-8; variant=CommonMark'), + ('README.rst', 'text/x-rst'), + ]: + try: + kw['long_description'] = open(readme_file_name).read() + kw['long_description_content_type'] = readme_markup_type + break + except FileNotFoundError: + pass # if nsp.wheel(kw, setup): # return diff --git a/tox.ini b/tox.ini index 9070ba6..0c4a722 100755 --- a/tox.ini +++ b/tox.ini @@ -6,7 +6,7 @@ envlist = cs,py311,py310,py39,py38,py37,py312 allowlist_externals = /bin/bash install_command = pip install --disable-pip-version-check {opts} {packages} commands = - /bin/bash -c 'pytest _test/test_*.py' + /bin/bash -c 'pytest {posargs} _test/test_*.py' deps = pytest setuptools From 793e1a608d05657cfb9adbd008cf8e4f38e63cfc Mon Sep 17 00:00:00 2001 From: Brad Cowie Date: Thu, 16 Nov 2023 14:24:05 +1300 Subject: [PATCH 2/2] Replace README.rst with README.md. --- debian/python3-ruamel.yaml.docs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/python3-ruamel.yaml.docs b/debian/python3-ruamel.yaml.docs index a1320b1..b43bf86 100644 --- a/debian/python3-ruamel.yaml.docs +++ b/debian/python3-ruamel.yaml.docs @@ -1 +1 @@ -README.rst +README.md