diff --git a/README.md b/README.md index c3f766f..a7d8542 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,9 @@ Binary fields can be converted between CBOR, MessagePack, and YAML. The Local Date type can only be converted to JSON (as a string) and YAML. The Local Time type cannot be converted to any other format. Offset Date-Time and its equivalents can be converted between CBOR, MessagePack, TOML, and YAML. -Keys of any date-time type are converted to string TOML keys. -- Date and time types are converted to JSON strings. +- The date and time types have no JSON counterpart. +They are converted to JSON strings with the `--stringify` option. They cannot be safely roundtripped through JSON. -- A YAML timestamp with only a date becomes a YAML timestamp or a TOML Local Date-Time for the midnight of that date. -This means you cannot roundtrip every YAML document through Remarshal. ## Installation diff --git a/example.cbor b/example.cbor index 34ab20e..c994d26 100644 --- a/example.cbor +++ b/example.cbor @@ -1,2 +1,2 @@ -¦eowner¤cdobÀx1979-05-27T07:32:00+00:00cbiox1GitHub Cofounder & CEO -Likes tater tots and beer.dnamerTom Preston-WernerlorganizationfGitHubetitlelTOML Examplegclients¢ddata‚‚egammaedelta‚ehosts‚ealphaeomegagservers¢dbeta£bdcfeqdc10biph10.0.0.2gcountryf中国ealpha¢bdcfeqdc10biph10.0.0.1hdatabase¤eportsƒAABfserverk192.168.1.1genabledõnconnection_maxˆhproducts‚¢csku,ydnamefHammer£cskuùydnamedNailecolordgray \ No newline at end of file +¦etitlelTOML Exampleeowner¤dnamerTom Preston-WernerlorganizationfGitHubcbiox1GitHub Cofounder & CEO +Likes tater tots and beer.cdobÀt1979-05-27T07:32:00Zhdatabase¤fserverk192.168.1.1eportsƒAABnconnection_maxˆgenabledõgservers¢ealpha¢biph10.0.0.1bdcfeqdc10dbeta£biph10.0.0.2bdcfeqdc10gcountryf中国gclients¢ddata‚‚egammaedelta‚ehosts‚ealphaeomegahproducts‚¢dnamefHammercsku,y£dnamedNailcskuùyecolordgray \ No newline at end of file diff --git a/example.json b/example.json index 37bead3..48b082c 100644 --- a/example.json +++ b/example.json @@ -1,4 +1,32 @@ { + "title": "TOML Example", + "owner": { + "name": "Tom Preston-Werner", + "organization": "GitHub", + "bio": "GitHub Cofounder & CEO\nLikes tater tots and beer.", + "dob": "1979-05-27T07:32:00+00:00" + }, + "database": { + "server": "192.168.1.1", + "ports": [ + 8001, + 8001, + 8002 + ], + "connection_max": 5000, + "enabled": true + }, + "servers": { + "alpha": { + "ip": "10.0.0.1", + "dc": "eqdc10" + }, + "beta": { + "ip": "10.0.0.2", + "dc": "eqdc10", + "country": "中国" + } + }, "clients": { "data": [ [ @@ -15,43 +43,15 @@ "omega" ] }, - "database": { - "connection_max": 5000, - "enabled": true, - "ports": [ - 8001, - 8001, - 8002 - ], - "server": "192.168.1.1" - }, - "owner": { - "bio": "GitHub Cofounder & CEO\nLikes tater tots and beer.", - "dob": "1979-05-27T07:32:00+00:00", - "name": "Tom Preston-Werner", - "organization": "GitHub" - }, "products": [ { "name": "Hammer", "sku": 738594937 }, { - "color": "gray", "name": "Nail", - "sku": 284758393 + "sku": 284758393, + "color": "gray" } - ], - "servers": { - "alpha": { - "dc": "eqdc10", - "ip": "10.0.0.1" - }, - "beta": { - "country": "中国", - "dc": "eqdc10", - "ip": "10.0.0.2" - } - }, - "title": "TOML Example" + ] } diff --git a/example.msgpack b/example.msgpack index 5093dbf..80a7cc7 100644 --- a/example.msgpack +++ b/example.msgpack @@ -1,2 +1,2 @@ -†§clients‚¤data’’¥gamma¥delta’¥hosts’¥alpha¥omega¨database„®connection_max͈§enabledÃ¥ports“ÍAÍAÍB¦server«192.168.1.1¥owner„£bioÙ1GitHub Cofounder & CEO -Likes tater tots and beer.£dobÖÿ®Wp¤name²Tom Preston-Werner¬organization¦GitHub¨products’‚¤name¦Hammer£skuÎ,yƒ¥color¤gray¤name¤Nail£skuÎùy§servers‚¥alpha‚¢dc¦eqdc10¢ip¨10.0.0.1¤betaƒ§country¦ä¸­å›½¢dc¦eqdc10¢ip¨10.0.0.2¥title¬TOML Example \ No newline at end of file +†¥title¬TOML Example¥owner„¤name²Tom Preston-Werner¬organization¦GitHub£bioÙ1GitHub Cofounder & CEO +Likes tater tots and beer.£dobÖÿ®Wp¨database„¦server«192.168.1.1¥ports“ÍAÍAÍB®connection_max͈§enabledçservers‚¥alpha‚¢ip¨10.0.0.1¢dc¦eqdc10¤betaƒ¢ip¨10.0.0.2¢dc¦eqdc10§country¦ä¸­å›½§clients‚¤data’’¥gamma¥delta’¥hosts’¥alpha¥omega¨products’‚¤name¦Hammer£skuÎ,yƒ¤name¤Nail£skuÎùy¥color¤gray \ No newline at end of file diff --git a/example.yaml b/example.yaml index 372f3f4..ca37203 100644 --- a/example.yaml +++ b/example.yaml @@ -1,3 +1,25 @@ +title: TOML Example +owner: + name: Tom Preston-Werner + organization: GitHub + bio: "GitHub Cofounder & CEO\nLikes tater tots and beer." + dob: 1979-05-27 07:32:00+00:00 +database: + server: 192.168.1.1 + ports: + - 8001 + - 8001 + - 8002 + connection_max: 5000 + enabled: true +servers: + alpha: + ip: 10.0.0.1 + dc: eqdc10 + beta: + ip: 10.0.0.2 + dc: eqdc10 + country: 中国 clients: data: - - gamma @@ -7,33 +29,9 @@ clients: hosts: - alpha - omega -database: - connection_max: 5000 - enabled: true - ports: - - 8001 - - 8001 - - 8002 - server: 192.168.1.1 -owner: - bio: 'GitHub Cofounder & CEO - - Likes tater tots and beer.' - dob: 1979-05-27 07:32:00+00:00 - name: Tom Preston-Werner - organization: GitHub products: - name: Hammer sku: 738594937 -- color: gray - name: Nail +- name: Nail sku: 284758393 -servers: - alpha: - dc: eqdc10 - ip: 10.0.0.1 - beta: - country: 中国 - dc: eqdc10 - ip: 10.0.0.2 -title: TOML Example + color: gray diff --git a/poetry.lock b/poetry.lock index d9c50ff..843ee58 100644 --- a/poetry.lock +++ b/poetry.lock @@ -319,79 +319,6 @@ pytest = ">=4.6" [package.extras] testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] -[[package]] -name = "python-dateutil" -version = "2.8.2" -description = "Extensions to the standard Python datetime module" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, -] - -[package.dependencies] -six = ">=1.5" - -[[package]] -name = "pyyaml" -version = "6.0.1" -description = "YAML parser and emitter for Python" -optional = false -python-versions = ">=3.6" -files = [ - {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, - {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, - {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, - {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, - {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, - {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, - {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, - {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, - {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, - {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, - {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, - {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, - {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, - {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, -] - [[package]] name = "rich" version = "13.6.0" @@ -425,6 +352,83 @@ files = [ [package.dependencies] rich = ">=11.0.0" +[[package]] +name = "ruamel-yaml" +version = "0.18.6" +description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruamel.yaml-0.18.6-py3-none-any.whl", hash = "sha256:57b53ba33def16c4f3d807c0ccbc00f8a6081827e81ba2491691b76882d0c636"}, + {file = "ruamel.yaml-0.18.6.tar.gz", hash = "sha256:8b27e6a217e786c6fbe5634d8f3f11bc63e0f80f6a5890f28863d9c45aac311b"}, +] + +[package.dependencies] +"ruamel.yaml.clib" = {version = ">=0.2.7", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.13\""} + +[package.extras] +docs = ["mercurial (>5.7)", "ryd"] +jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] + +[[package]] +name = "ruamel-yaml-clib" +version = "0.2.8" +description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" +optional = false +python-versions = ">=3.6" +files = [ + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win_amd64.whl", hash = "sha256:1758ce7d8e1a29d23de54a16ae867abd370f01b5a69e1a3ba75223eaa3ca1a1b"}, + {file = "ruamel.yaml.clib-0.2.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win32.whl", hash = "sha256:75e1ed13e1f9de23c5607fe6bd1aeaae21e523b32d83bb33918245361e9cc51b"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win_amd64.whl", hash = "sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win32.whl", hash = "sha256:955eae71ac26c1ab35924203fda6220f84dce57d6d7884f189743e2abe3a9fbe"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win_amd64.whl", hash = "sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win32.whl", hash = "sha256:84b554931e932c46f94ab306913ad7e11bba988104c5cff26d90d03f68258cd5"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win_amd64.whl", hash = "sha256:25ac8c08322002b06fa1d49d1646181f0b2c72f5cbc15a85e80b4c30a544bb15"}, + {file = "ruamel.yaml.clib-0.2.8.tar.gz", hash = "sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512"}, +] + [[package]] name = "ruff" version = "0.2.1" @@ -467,17 +471,6 @@ docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] -[[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] - [[package]] name = "tomli" version = "2.0.1" @@ -511,17 +504,6 @@ files = [ {file = "types_python_dateutil-2.8.19.14-py3-none-any.whl", hash = "sha256:f977b8de27787639986b4e28963263fd0e5158942b3ecef91b9335c130cb1ce9"}, ] -[[package]] -name = "types-pyyaml" -version = "6.0.12.12" -description = "Typing stubs for PyYAML" -optional = false -python-versions = "*" -files = [ - {file = "types-PyYAML-6.0.12.12.tar.gz", hash = "sha256:334373d392fde0fdf95af5c3f1661885fa10c52167b14593eb856289e1855062"}, - {file = "types_PyYAML-6.0.12.12-py3-none-any.whl", hash = "sha256:c05bc6c158facb0676674b7f11fe3960db4f389718e19e62bd2b84d6205cfd24"}, -] - [[package]] name = "typing-extensions" version = "4.8.0" @@ -547,4 +529,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "15ea61c91eef0448ba97b66997a2b70b01a36f377ee4ee1487b8aa77100bf583" +content-hash = "787b322a087f4a5faad4df8222ddf783ac54602de5b31732dba568738aa99ed5" diff --git a/pyproject.toml b/pyproject.toml index f86f70d..72db748 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,10 +33,8 @@ include = [ [tool.poetry.dependencies] python = "^3.8" -python-dateutil = "^2.8" - cbor2 = "^5.4" -PyYAML = "^6.0" +"ruamel.yaml" = "^0.18.0" tomli = { version = "^2.0.1", python = "<3.11" } tomlkit = "^0.12.1" u-msgpack-python = "^2.8" @@ -48,7 +46,6 @@ rich-argparse = "^1.4.0" ruff = "0.2.1" tomli = "^2.0.1" types-python-dateutil = "^2.8.19.13" -types-pyyaml = "^6.0.12.10" codespell = {extras = ["toml"], version = "^2.2.5"} pyright = "1.1.350" pytest = "^8" diff --git a/src/remarshal/main.py b/src/remarshal/main.py index 4875afe..f4e8bb7 100755 --- a/src/remarshal/main.py +++ b/src/remarshal/main.py @@ -12,11 +12,14 @@ import re import sys import traceback +from dataclasses import dataclass +from io import StringIO from pathlib import Path from typing import ( TYPE_CHECKING, Any, Callable, + Literal, Mapping, Sequence, Union, @@ -25,7 +28,6 @@ import cbor2 # type: ignore import colorama -import dateutil.parser import tomlkit from rich_argparse import RichHelpFormatter @@ -34,20 +36,30 @@ except ModuleNotFoundError: import tomli as tomllib +import ruamel.yaml +import ruamel.yaml.parser +import ruamel.yaml.representer +import ruamel.yaml.scanner import umsgpack -import yaml -import yaml.parser -import yaml.scanner if TYPE_CHECKING: from rich.style import StyleType + +@dataclass(frozen=True) +class YAMLOptions: + indent: int = 2 + style: Literal["", "'", '"', "|", ">"] | None = None + width: int = 80 + + __all__ = [ "DEFAULT_MAX_VALUES", "FORMATS", "RICH_ARGPARSE_STYLES", "Document", "TooManyValuesError", + "YAMLOptions", "decode", "encode", "identity", @@ -56,6 +68,11 @@ "traverse", ] +CLI_DEFAULTS: dict[str, Any] = { + "json_indent": None, + "sort_keys": False, + "stringify": False, +} DEFAULT_MAX_VALUES = 1000000 FORMATS = ["cbor", "json", "msgpack", "toml", "yaml"] UTF_8 = "utf-8" @@ -72,38 +89,6 @@ } -# === YAML === - - -# An ordered dumper for PyYAML. -class _OrderedDumper(yaml.SafeDumper): - pass - - -def _mapping_representer(dumper: Any, data: Any) -> Any: - return dumper.represent_mapping( - yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, data.items() - ) - - -_OrderedDumper.add_representer(dict, _mapping_representer) - - -# Fix loss of time zone information in PyYAML. -# http://stackoverflow.com/questions/13294186/can-pyyaml-parse-iso8601-dates -class _TimezoneLoader(yaml.SafeLoader): - pass - - -def _timestamp_constructor(loader: Any, node: Any) -> datetime.datetime: - return dateutil.parser.parse(node.value) - - -loaders = [_TimezoneLoader] -for loader in loaders: - loader.add_constructor("tag:yaml.org,2002:timestamp", _timestamp_constructor) - - # === CLI === @@ -124,13 +109,6 @@ def _extension_to_format(path: str) -> str: def _parse_command_line(argv: Sequence[str]) -> argparse.Namespace: # noqa: C901. - defaults: dict[str, Any] = { - "json_indent": None, - "ordered": True, - "stringify": False, - "yaml_options": {}, - } - me = Path(argv[0]).name argv0_from, argv0_to = _argv0_to_format(me) format_from_argv0 = argv0_to != "" @@ -186,7 +164,7 @@ def _parse_command_line(argv: Sequence[str]) -> argparse.Namespace: # noqa: C90 dest="json_indent", metavar="", type=int, - default=defaults["json_indent"], + default=CLI_DEFAULTS["json_indent"], help="JSON indentation", ) parser.add_argument( @@ -260,9 +238,8 @@ def _parse_command_line(argv: Sequence[str]) -> argparse.Namespace: # noqa: C90 parser.add_argument( "-s", "--sort-keys", - dest="ordered", - action="store_false", - help="sort JSON, TOML, YAML keys instead of preserving key order", + action="store_true", + help="sort JSON and TOML keys instead of preserving key order", ) parser.add_argument( @@ -294,13 +271,13 @@ def _parse_command_line(argv: Sequence[str]) -> argparse.Namespace: # noqa: C90 dest="yaml_indent", metavar="", type=int, - default=2, + default=YAMLOptions().indent, help="YAML indentation", ) parser.add_argument( "--yaml-style", dest="yaml_style", - default=None, + default=YAMLOptions().style, help="YAML formatting style", choices=["", "'", '"', "|", ">"], ) @@ -314,7 +291,7 @@ def yaml_width(value: str) -> int: dest="yaml_width", metavar="", type=yaml_width, # Allow "inf". - default=80, + default=YAMLOptions().width, help="YAML line width for long strings", ) @@ -343,16 +320,19 @@ def yaml_width(value: str) -> int: if args.output_format == "": parser.error("Need an explicit output format") - for key, value in defaults.items(): + for key, value in CLI_DEFAULTS.items(): vars(args).setdefault(key, value) - # Wrap the yaml_* option. + # Wrap `yaml_*` options in `YAMLOptions` if they are present. + vars(args)["yaml_options"] = YAMLOptions() + if "yaml_indent" in vars(args): - vars(args)["yaml_options"] = { - "default_style": args.yaml_style, - "indent": args.yaml_indent, - "width": args.yaml_width, - } + vars(args)["yaml_options"] = YAMLOptions( + indent=args.yaml_indent, + style=args.yaml_style, + width=args.yaml_width, + ) + for key in ("yaml_indent", "yaml_style", "yaml_width"): del vars(args)[key] @@ -460,10 +440,11 @@ def _decode_toml(input_data: bytes) -> Document: def _decode_yaml(input_data: bytes) -> Document: try: - loader = _TimezoneLoader - doc = yaml.load(input_data, loader) + yaml = ruamel.yaml.YAML(typ="safe") + doc = yaml.load(input_data) + return cast(Document, doc) - except (yaml.scanner.ScannerError, yaml.parser.ParserError) as e: + except (ruamel.yaml.scanner.ScannerError, ruamel.yaml.parser.ParserError) as e: msg = f"Cannot parse as YAML ({e})" raise ValueError(msg) @@ -511,9 +492,19 @@ def _reject_special_keys(key: Any) -> Any: if isinstance(key, bool): msg = "boolean key" raise TypeError(msg) + + if isinstance(key, datetime.date): + msg = "date key" + raise TypeError(msg) + if isinstance(key, datetime.datetime): msg = "date-time key" raise TypeError(msg) + + if isinstance(key, datetime.time): + msg = "time key" + raise TypeError(msg) + if key is None: msg = "null key" raise TypeError(msg) @@ -550,8 +541,8 @@ def _json_default(obj: Any) -> str: def _encode_json( data: Document, *, - ordered: bool, indent: bool | int | None, + sort_keys: bool, stringify: bool, ) -> str: if indent is True: @@ -571,7 +562,7 @@ def _encode_json( ensure_ascii=False, indent=indent, separators=separators, - sort_keys=not ordered, + sort_keys=sort_keys, ) + "\n" ) @@ -591,7 +582,7 @@ def _encode_msgpack(data: Document) -> bytes: def _encode_toml( data: Mapping[Any, Any], *, - ordered: bool, + sort_keys: bool, stringify: bool, ) -> str: key_callback = _stringify_special_keys if stringify else _reject_special_keys @@ -618,7 +609,7 @@ def stringify_null(x: Any) -> Any: key_callback=key_callback, default_callback=default_callback, ), - sort_keys=not ordered, + sort_keys=sort_keys, ) except AttributeError as e: if str(e) == "'list' object has no attribute 'as_string'": @@ -634,21 +625,23 @@ def stringify_null(x: Any) -> Any: raise ValueError(msg) -def _encode_yaml( - data: Document, *, ordered: bool, yaml_options: Mapping[Any, Any] -) -> str: - dumper = _OrderedDumper if ordered else yaml.SafeDumper +def _encode_yaml(data: Document, *, yaml_options: YAMLOptions) -> str: + yaml = ruamel.yaml.YAML() + yaml.default_flow_style = False + + yaml.default_style = yaml_options.style # type: ignore + yaml.indent = yaml_options.indent + yaml.width = yaml_options.width + try: - return yaml.dump( + out = StringIO() + yaml.dump( data, - None, - dumper, - allow_unicode=True, - default_flow_style=False, - encoding=None, - **yaml_options, + out, ) - except yaml.representer.RepresenterError as e: + + return out.getvalue() + except ruamel.yaml.representer.RepresenterError as e: msg = f"Cannot convert data to YAML ({e})" raise ValueError(msg) @@ -658,15 +651,15 @@ def encode( data: Document, *, json_indent: int | None, - ordered: bool, + sort_keys: bool, stringify: bool, - yaml_options: Mapping[Any, Any], + yaml_options: YAMLOptions, ) -> bytes: if output_format == "json": encoded = _encode_json( data, indent=json_indent, - ordered=ordered, + sort_keys=sort_keys, stringify=stringify, ).encode(UTF_8) elif output_format == "msgpack": @@ -678,11 +671,11 @@ def encode( "be encoded as TOML" ) raise TypeError(msg) - encoded = _encode_toml(data, ordered=ordered, stringify=stringify).encode(UTF_8) - elif output_format == "yaml": - encoded = _encode_yaml(data, ordered=ordered, yaml_options=yaml_options).encode( + encoded = _encode_toml(data, sort_keys=sort_keys, stringify=stringify).encode( UTF_8 ) + elif output_format == "yaml": + encoded = _encode_yaml(data, yaml_options=yaml_options).encode(UTF_8) elif output_format == "cbor": encoded = _encode_cbor(data) else: @@ -703,12 +696,12 @@ def remarshal( *, json_indent: int | None = None, max_values: int = DEFAULT_MAX_VALUES, - ordered: bool = True, + sort_keys: bool = True, stringify: bool = False, transform: Callable[[Document], Document] | None = None, unwrap: str | None = None, wrap: str | None = None, - yaml_options: Mapping[Any, Any] | None = None, + yaml_options: YAMLOptions | None = None, ) -> None: input_file = None output_file = None @@ -746,9 +739,9 @@ def remarshal( output_format, parsed, json_indent=json_indent, - ordered=ordered, + sort_keys=sort_keys, stringify=stringify, - yaml_options={} if yaml_options is None else yaml_options, + yaml_options=YAMLOptions() if yaml_options is None else yaml_options, ) output_file.write(encoded) @@ -770,7 +763,7 @@ def main() -> None: args.output, json_indent=args.json_indent, max_values=args.max_values, - ordered=args.ordered, + sort_keys=args.sort_keys, stringify=args.stringify, unwrap=args.unwrap, wrap=args.wrap, diff --git a/tests/bool-null-key.yaml b/tests/bool-null-key.yaml index 48bb2a9..28dd2ab 100644 --- a/tests/bool-null-key.yaml +++ b/tests/bool-null-key.yaml @@ -1,4 +1,4 @@ -on: foo -off: oof +True: foo +false: oof another: bar NULL: "nothin'" diff --git a/tests/long-line-double-quote.yaml b/tests/long-line-double-quote.yaml index 1e02a51..69f72fd 100644 --- a/tests/long-line-double-quote.yaml +++ b/tests/long-line-double-quote.yaml @@ -1,4 +1,4 @@ "balanceHeld": - "description": "Balance of the account held for transferring to other users (in\ - \ cents) and then a bunch more text after that" + "description": "Balance of the account held for transferring to other users (in + cents) and then a bunch more text after that" "type": "integer" diff --git a/tests/norway.json b/tests/norway.json new file mode 100644 index 0000000..6c789ec --- /dev/null +++ b/tests/norway.json @@ -0,0 +1 @@ +{"booleans":[true,false],"strings":["yes","no","on","off"]} diff --git a/tests/norway.yaml b/tests/norway.yaml new file mode 100644 index 0000000..15b4b73 --- /dev/null +++ b/tests/norway.yaml @@ -0,0 +1,8 @@ +booleans: + - true + - false +strings: + - yes + - no + - on + - off diff --git a/tests/order.yaml b/tests/order.yaml deleted file mode 100644 index 19866a3..0000000 --- a/tests/order.yaml +++ /dev/null @@ -1,3 +0,0 @@ -foo: 1 -bar: 2 -baz: 3 diff --git a/tests/sorted.json b/tests/sorted.json new file mode 100644 index 0000000..562ceba --- /dev/null +++ b/tests/sorted.json @@ -0,0 +1,5 @@ +{ + "bar": 2, + "baz": 3, + "foo": 1 +} diff --git a/tests/sorted.toml b/tests/sorted.toml new file mode 100644 index 0000000..ae3e1e0 --- /dev/null +++ b/tests/sorted.toml @@ -0,0 +1,3 @@ +bar = 2 +baz = 3 +foo = 1 diff --git a/tests/test_remarshal.py b/tests/test_remarshal.py index a20b6e2..31295c1 100755 --- a/tests/test_remarshal.py +++ b/tests/test_remarshal.py @@ -19,7 +19,7 @@ import pytest import remarshal -from remarshal.main import _argv0_to_format, _parse_command_line +from remarshal.main import YAMLOptions, _argv0_to_format, _parse_command_line if TYPE_CHECKING: from collections.abc import Mapping, Sequence @@ -95,12 +95,12 @@ def _convert_and_read( *, output_filename: str, json_indent: int | None = 2, - ordered: bool = False, + sort_keys: bool = False, stringify: bool = False, transform: Callable[[remarshal.Document], remarshal.Document] | None = None, unwrap: str | None = None, wrap: str | None = None, - yaml_options: Mapping[Any, Any] | None = None, + yaml_options: YAMLOptions | None = None, ) -> bytes: remarshal.remarshal( input_format, @@ -108,7 +108,7 @@ def _convert_and_read( data_file_path(input_filename), output_filename, json_indent=json_indent, - ordered=ordered, + sort_keys=sort_keys, stringify=stringify, transform=transform, unwrap=unwrap, @@ -137,7 +137,7 @@ def test_msgpack2msgpack(self, convert_and_read) -> None: "example.msgpack", "msgpack", "msgpack", - ordered=True, + sort_keys=False, ) reference = read_file("example.msgpack") assert output == reference @@ -168,7 +168,6 @@ def patch(x: Any) -> Any: "example.json", "json", "msgpack", - ordered=True, transform=patch, ) reference = read_file("example.msgpack") @@ -185,7 +184,6 @@ def patch(x: Any) -> Any: "example.json", "json", "cbor", - ordered=True, transform=patch, ) @@ -245,7 +243,6 @@ def test_toml2msgpack(self, convert_and_read) -> None: "example.toml", "toml", "msgpack", - transform=lambda col: remarshal.traverse(col, dict_callback=sorted_dict), ) reference = read_file("example.msgpack") assert output == reference @@ -274,7 +271,6 @@ def test_yaml2msgpack(self, convert_and_read) -> None: "example.yaml", "yaml", "msgpack", - ordered=True, ) reference = read_file("example.msgpack") assert output == reference @@ -315,8 +311,6 @@ def test_cbor2msgpack(self, convert_and_read) -> None: "example.cbor", "cbor", "msgpack", - ordered=True, - transform=lambda col: remarshal.traverse(col, dict_callback=sorted_dict), ) reference = read_file("example.msgpack") assert output == reference @@ -377,28 +371,28 @@ def test_yaml_style_default(self, convert_and_read) -> None: def test_yaml_style_single_quote(self, convert_and_read) -> None: output = convert_and_read( - "long-line.json", "json", "yaml", yaml_options={"default_style": "'"} + "long-line.json", "json", "yaml", yaml_options=YAMLOptions(style="'") ) reference = read_file("long-line-single-quote.yaml") assert output == reference def test_yaml_style_double_quote(self, convert_and_read) -> None: output = convert_and_read( - "long-line.json", "json", "yaml", yaml_options={"default_style": '"'} + "long-line.json", "json", "yaml", yaml_options=YAMLOptions(style='"') ) reference = read_file("long-line-double-quote.yaml") assert output == reference def test_yaml_style_pipe(self, convert_and_read) -> None: output = convert_and_read( - "long-line.json", "json", "yaml", yaml_options={"default_style": "|"} + "long-line.json", "json", "yaml", yaml_options=YAMLOptions(style="|") ) reference = read_file("long-line-pipe.yaml") assert output == reference def test_yaml_style_gt(self, convert_and_read) -> None: output = convert_and_read( - "long-line.json", "json", "yaml", yaml_options={"default_style": ">"} + "long-line.json", "json", "yaml", yaml_options=YAMLOptions(style=">") ) reference = read_file("long-line-gt.yaml") assert output == reference @@ -500,10 +494,10 @@ def test_run_short_commands(self) -> None: ) def test_ordered_simple(self, convert_and_read) -> None: - formats = ("json", "toml", "yaml") + formats = ("json", "toml") for from_ in formats: for to in formats: - output = convert_and_read("order." + from_, from_, to, ordered=True) + output = convert_and_read("order." + from_, from_, to) reference = read_file("order." + to) message = "failed for {} to {} ({!r} instead of {!r})".format( @@ -514,10 +508,20 @@ def test_ordered_simple(self, convert_and_read) -> None: ) assert output == reference, message - def test_ordered_yaml2yaml(self, convert_and_read) -> None: - output = convert_and_read("example.yaml", "yaml", "yaml", ordered=True) - reference = read_file("example.yaml") - assert output == reference + def test_sort_keys_simple(self, convert_and_read) -> None: + formats = ("json", "toml") + for from_ in formats: + for to in formats: + output = convert_and_read("sorted." + from_, from_, to, sort_keys=True) + reference = read_file("sorted." + to) + + message = "failed for {} to {} ({!r} instead of {!r})".format( + from_, + to, + output, + reference, + ) + assert output == reference, message def test_yaml2json_bool_null_key(self, convert_and_read) -> None: output = convert_and_read( @@ -525,7 +529,6 @@ def test_yaml2json_bool_null_key(self, convert_and_read) -> None: "yaml", "json", json_indent=0, - ordered=True, stringify=True, ) reference = read_file("bool-null-key.json") @@ -536,7 +539,6 @@ def test_yaml2toml_bool_null_key(self, convert_and_read) -> None: "bool-null-key.yaml", "yaml", "toml", - ordered=True, stringify=True, ) reference = read_file("bool-null-key.toml") @@ -547,7 +549,6 @@ def test_yaml2toml_timestamp_key(self, convert_and_read) -> None: "timestamp-key.yaml", "yaml", "toml", - ordered=True, stringify=True, ) reference = read_file("timestamp-key.toml") @@ -561,21 +562,21 @@ def test_yaml_width_default(self, convert_and_read) -> None: ).decode("utf-8") assert len([char for char in output if char == "\n"]) == 4 - def test_yaml_width_30(self, convert_and_read) -> None: + def test_yaml_width_5(self, convert_and_read) -> None: output = convert_and_read( - "long-line.json", "json", "yaml", yaml_options={"width": 5} - ).decode("utf-8") - assert len([char for char in output if char == "\n"]) == 21 + "long-line.json", "json", "yaml", yaml_options=YAMLOptions(width=5) + ).decode() + assert len([char for char in output if char == "\n"]) == 23 def test_yaml_width_120(self, convert_and_read) -> None: output = convert_and_read( - "long-line.json", "json", "yaml", yaml_options={"width": 120} + "long-line.json", "json", "yaml", yaml_options=YAMLOptions(width=120) ).decode("utf-8") assert len([char for char in output if char == "\n"]) == 3 def test_yaml_ident_5(self, convert_and_read) -> None: output = convert_and_read( - "long-line.json", "json", "yaml", yaml_options={"indent": 5} + "long-line.json", "json", "yaml", yaml_options=YAMLOptions(indent=5) ).decode("utf-8") assert set(re.findall(r"\n +", output)) == {"\n ", "\n "} @@ -616,6 +617,16 @@ def test_yaml_billion_laughs(self, convert_and_read) -> None: with pytest.raises(remarshal.TooManyValuesError): convert_and_read("lol.yml", "yaml", "json") + def test_yaml_norway_problem(self, convert_and_read) -> None: + output = convert_and_read( + "norway.yaml", + "yaml", + "json", + json_indent=None, + ) + reference = read_file("norway.json") + assert output == reference + if __name__ == "__main__": pytest.main() diff --git a/tests/timestamp-key.toml b/tests/timestamp-key.toml index 173481d..df52b79 100644 --- a/tests/timestamp-key.toml +++ b/tests/timestamp-key.toml @@ -1 +1 @@ -"2023-08-09T00:00:00" = true +2023-08-09 = true