From bb40e7e81ef14da866db1ff425c37c66dfdaaf4c Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian <29258240+xiancg@users.noreply.github.com>
Date: Sat, 6 May 2023 22:41:47 -0300
Subject: [PATCH 01/65] Removing 2.7 support and switching everything to new
practices
---
.gitignore | 1 -
MANIFEST.in | 3 +
Pipfile | 11 +-
Pipfile.lock | 814 ++++++++++++++++++++-------------------
README.md | 17 -
README.rst | 26 ++
bin/deploy.bat | 16 +
docs/requirements.txt | 1 -
docs/source/conf.py | 4 +-
docs/source/index.rst | 4 +-
pyproject.toml | 3 +
requirements.txt | 9 -
setup.cfg | 2 +-
setup.py | 37 +-
src/vfxnaming/_vesion.py | 1 +
src/vfxnaming/error.py | 3 -
tox.ini | 21 +-
17 files changed, 501 insertions(+), 472 deletions(-)
create mode 100644 MANIFEST.in
delete mode 100644 README.md
create mode 100644 README.rst
create mode 100644 bin/deploy.bat
delete mode 100644 docs/requirements.txt
create mode 100644 pyproject.toml
delete mode 100644 requirements.txt
create mode 100644 src/vfxnaming/_vesion.py
diff --git a/.gitignore b/.gitignore
index c7a12af..4ad5d0e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -106,7 +106,6 @@ venv.bak/
.pydevproject
.project
*.code-workspace
-CGXLightingTools.env
/cov_html
coverage_cmd.txt
cov_py27_html/
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..3e8c3ef
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,3 @@
+recursive-include src/vfxnaming **
+global-exclude *.py[cod]
+recursive-exclude src/vfxnaming __pycache__
\ No newline at end of file
diff --git a/Pipfile b/Pipfile
index c87cc60..e75e0eb 100644
--- a/Pipfile
+++ b/Pipfile
@@ -8,11 +8,16 @@ pytest = "*"
pytest-cov = "*"
pytest-datafiles = "*"
flake8 = "*"
-vfxnaming = {editable = true,path = "."}
python-coveralls = "*"
sphinx = "*"
sphinx-rtd-theme = "*"
twine = "*"
+build = "*"
+wheel = "*"
+rstcheck = "*"
-[packages]
-six = "*"
+[requires]
+python_version = "3.7"
+
+[pipenv]
+allow_prereleases = true
\ No newline at end of file
diff --git a/Pipfile.lock b/Pipfile.lock
index b8fbd73..ea31088 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,10 +1,12 @@
{
"_meta": {
"hash": {
- "sha256": "373ece6c3510f493f6a1148f6a8e2bf34e34cda78360f7c3797e24d3967e7abf"
+ "sha256": "7f657b1ac9f309c3f0915b3a048ca4c204bd37a0140370f091543a2d7c18be0f"
},
"pipfile-spec": 6,
- "requires": {},
+ "requires": {
+ "python_version": "3.7"
+ },
"sources": [
{
"name": "pypi",
@@ -13,16 +15,7 @@
}
]
},
- "default": {
- "six": {
- "hashes": [
- "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a",
- "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"
- ],
- "index": "pypi",
- "version": "==1.14.0"
- }
- },
+ "default": {},
"develop": {
"alabaster": {
"hashes": [
@@ -32,21 +25,13 @@
"markers": "python_version >= '3.6'",
"version": "==0.7.13"
},
- "attrs": {
- "hashes": [
- "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836",
- "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==22.2.0"
- },
"babel": {
"hashes": [
- "sha256:1ad3eca1c885218f6dce2ab67291178944f810a10a9b5f3cb8382a5a232b64fe",
- "sha256:5ef4b3226b0180dedded4229651c8b0e1a3a6a2837d45a073272f313e4cf97f6"
+ "sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610",
+ "sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455"
],
- "markers": "python_version >= '3.6'",
- "version": "==2.11.0"
+ "markers": "python_version >= '3.7'",
+ "version": "==2.12.1"
},
"bleach": {
"hashes": [
@@ -56,6 +41,14 @@
"markers": "python_version >= '3.7'",
"version": "==6.0.0"
},
+ "build": {
+ "hashes": [
+ "sha256:af266720050a66c893a6096a2f410989eeac74ff9a68ba194b3f6473e8e26171",
+ "sha256:d5b71264afdb5951d6704482aac78de887c80691c52b88a9ad195983ca2c9269"
+ ],
+ "index": "pypi",
+ "version": "==0.10.0"
+ },
"certifi": {
"hashes": [
"sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3",
@@ -64,275 +57,193 @@
"markers": "python_version >= '3.6'",
"version": "==2022.12.7"
},
- "cffi": {
- "hashes": [
- "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5",
- "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef",
- "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104",
- "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426",
- "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405",
- "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375",
- "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a",
- "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e",
- "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc",
- "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf",
- "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185",
- "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497",
- "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3",
- "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35",
- "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c",
- "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83",
- "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21",
- "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca",
- "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984",
- "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac",
- "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd",
- "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee",
- "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a",
- "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2",
- "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192",
- "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7",
- "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585",
- "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f",
- "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e",
- "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27",
- "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b",
- "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e",
- "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e",
- "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d",
- "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c",
- "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415",
- "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82",
- "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02",
- "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314",
- "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325",
- "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c",
- "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3",
- "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914",
- "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045",
- "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d",
- "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9",
- "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5",
- "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2",
- "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c",
- "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3",
- "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2",
- "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8",
- "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d",
- "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d",
- "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9",
- "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162",
- "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76",
- "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4",
- "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e",
- "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9",
- "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6",
- "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b",
- "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01",
- "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"
- ],
- "version": "==1.15.1"
- },
"charset-normalizer": {
"hashes": [
- "sha256:00d3ffdaafe92a5dc603cb9bd5111aaa36dfa187c8285c543be562e61b755f6b",
- "sha256:024e606be3ed92216e2b6952ed859d86b4cfa52cd5bc5f050e7dc28f9b43ec42",
- "sha256:0298eafff88c99982a4cf66ba2efa1128e4ddaca0b05eec4c456bbc7db691d8d",
- "sha256:02a51034802cbf38db3f89c66fb5d2ec57e6fe7ef2f4a44d070a593c3688667b",
- "sha256:083c8d17153ecb403e5e1eb76a7ef4babfc2c48d58899c98fcaa04833e7a2f9a",
- "sha256:0a11e971ed097d24c534c037d298ad32c6ce81a45736d31e0ff0ad37ab437d59",
- "sha256:0bf2dae5291758b6f84cf923bfaa285632816007db0330002fa1de38bfcb7154",
- "sha256:0c0a590235ccd933d9892c627dec5bc7511ce6ad6c1011fdf5b11363022746c1",
- "sha256:0f438ae3532723fb6ead77e7c604be7c8374094ef4ee2c5e03a3a17f1fca256c",
- "sha256:109487860ef6a328f3eec66f2bf78b0b72400280d8f8ea05f69c51644ba6521a",
- "sha256:11b53acf2411c3b09e6af37e4b9005cba376c872503c8f28218c7243582df45d",
- "sha256:12db3b2c533c23ab812c2b25934f60383361f8a376ae272665f8e48b88e8e1c6",
- "sha256:14e76c0f23218b8f46c4d87018ca2e441535aed3632ca134b10239dfb6dadd6b",
- "sha256:16a8663d6e281208d78806dbe14ee9903715361cf81f6d4309944e4d1e59ac5b",
- "sha256:292d5e8ba896bbfd6334b096e34bffb56161c81408d6d036a7dfa6929cff8783",
- "sha256:2c03cc56021a4bd59be889c2b9257dae13bf55041a3372d3295416f86b295fb5",
- "sha256:2e396d70bc4ef5325b72b593a72c8979999aa52fb8bcf03f701c1b03e1166918",
- "sha256:2edb64ee7bf1ed524a1da60cdcd2e1f6e2b4f66ef7c077680739f1641f62f555",
- "sha256:31a9ddf4718d10ae04d9b18801bd776693487cbb57d74cc3458a7673f6f34639",
- "sha256:356541bf4381fa35856dafa6a965916e54bed415ad8a24ee6de6e37deccf2786",
- "sha256:358a7c4cb8ba9b46c453b1dd8d9e431452d5249072e4f56cfda3149f6ab1405e",
- "sha256:37f8febc8ec50c14f3ec9637505f28e58d4f66752207ea177c1d67df25da5aed",
- "sha256:39049da0ffb96c8cbb65cbf5c5f3ca3168990adf3551bd1dee10c48fce8ae820",
- "sha256:39cf9ed17fe3b1bc81f33c9ceb6ce67683ee7526e65fde1447c772afc54a1bb8",
- "sha256:3ae1de54a77dc0d6d5fcf623290af4266412a7c4be0b1ff7444394f03f5c54e3",
- "sha256:3b590df687e3c5ee0deef9fc8c547d81986d9a1b56073d82de008744452d6541",
- "sha256:3e45867f1f2ab0711d60c6c71746ac53537f1684baa699f4f668d4c6f6ce8e14",
- "sha256:3fc1c4a2ffd64890aebdb3f97e1278b0cc72579a08ca4de8cd2c04799a3a22be",
- "sha256:4457ea6774b5611f4bed5eaa5df55f70abde42364d498c5134b7ef4c6958e20e",
- "sha256:44ba614de5361b3e5278e1241fda3dc1838deed864b50a10d7ce92983797fa76",
- "sha256:4a8fcf28c05c1f6d7e177a9a46a1c52798bfe2ad80681d275b10dcf317deaf0b",
- "sha256:4b0d02d7102dd0f997580b51edc4cebcf2ab6397a7edf89f1c73b586c614272c",
- "sha256:502218f52498a36d6bf5ea77081844017bf7982cdbe521ad85e64cabee1b608b",
- "sha256:503e65837c71b875ecdd733877d852adbc465bd82c768a067badd953bf1bc5a3",
- "sha256:5995f0164fa7df59db4746112fec3f49c461dd6b31b841873443bdb077c13cfc",
- "sha256:59e5686dd847347e55dffcc191a96622f016bc0ad89105e24c14e0d6305acbc6",
- "sha256:601f36512f9e28f029d9481bdaf8e89e5148ac5d89cffd3b05cd533eeb423b59",
- "sha256:608862a7bf6957f2333fc54ab4399e405baad0163dc9f8d99cb236816db169d4",
- "sha256:62595ab75873d50d57323a91dd03e6966eb79c41fa834b7a1661ed043b2d404d",
- "sha256:70990b9c51340e4044cfc394a81f614f3f90d41397104d226f21e66de668730d",
- "sha256:71140351489970dfe5e60fc621ada3e0f41104a5eddaca47a7acb3c1b851d6d3",
- "sha256:72966d1b297c741541ca8cf1223ff262a6febe52481af742036a0b296e35fa5a",
- "sha256:74292fc76c905c0ef095fe11e188a32ebd03bc38f3f3e9bcb85e4e6db177b7ea",
- "sha256:761e8904c07ad053d285670f36dd94e1b6ab7f16ce62b9805c475b7aa1cffde6",
- "sha256:772b87914ff1152b92a197ef4ea40efe27a378606c39446ded52c8f80f79702e",
- "sha256:79909e27e8e4fcc9db4addea88aa63f6423ebb171db091fb4373e3312cb6d603",
- "sha256:7e189e2e1d3ed2f4aebabd2d5b0f931e883676e51c7624826e0a4e5fe8a0bf24",
- "sha256:7eb33a30d75562222b64f569c642ff3dc6689e09adda43a082208397f016c39a",
- "sha256:81d6741ab457d14fdedc215516665050f3822d3e56508921cc7239f8c8e66a58",
- "sha256:8499ca8f4502af841f68135133d8258f7b32a53a1d594aa98cc52013fff55678",
- "sha256:84c3990934bae40ea69a82034912ffe5a62c60bbf6ec5bc9691419641d7d5c9a",
- "sha256:87701167f2a5c930b403e9756fab1d31d4d4da52856143b609e30a1ce7160f3c",
- "sha256:88600c72ef7587fe1708fd242b385b6ed4b8904976d5da0893e31df8b3480cb6",
- "sha256:8ac7b6a045b814cf0c47f3623d21ebd88b3e8cf216a14790b455ea7ff0135d18",
- "sha256:8b8af03d2e37866d023ad0ddea594edefc31e827fee64f8de5611a1dbc373174",
- "sha256:8c7fe7afa480e3e82eed58e0ca89f751cd14d767638e2550c77a92a9e749c317",
- "sha256:8eade758719add78ec36dc13201483f8e9b5d940329285edcd5f70c0a9edbd7f",
- "sha256:911d8a40b2bef5b8bbae2e36a0b103f142ac53557ab421dc16ac4aafee6f53dc",
- "sha256:93ad6d87ac18e2a90b0fe89df7c65263b9a99a0eb98f0a3d2e079f12a0735837",
- "sha256:95dea361dd73757c6f1c0a1480ac499952c16ac83f7f5f4f84f0658a01b8ef41",
- "sha256:9ab77acb98eba3fd2a85cd160851816bfce6871d944d885febf012713f06659c",
- "sha256:9cb3032517f1627cc012dbc80a8ec976ae76d93ea2b5feaa9d2a5b8882597579",
- "sha256:9cf4e8ad252f7c38dd1f676b46514f92dc0ebeb0db5552f5f403509705e24753",
- "sha256:9d9153257a3f70d5f69edf2325357251ed20f772b12e593f3b3377b5f78e7ef8",
- "sha256:a152f5f33d64a6be73f1d30c9cc82dfc73cec6477ec268e7c6e4c7d23c2d2291",
- "sha256:a16418ecf1329f71df119e8a65f3aa68004a3f9383821edcb20f0702934d8087",
- "sha256:a60332922359f920193b1d4826953c507a877b523b2395ad7bc716ddd386d866",
- "sha256:a8d0fc946c784ff7f7c3742310cc8a57c5c6dc31631269876a88b809dbeff3d3",
- "sha256:ab5de034a886f616a5668aa5d098af2b5385ed70142090e2a31bcbd0af0fdb3d",
- "sha256:c22d3fe05ce11d3671297dc8973267daa0f938b93ec716e12e0f6dee81591dc1",
- "sha256:c2ac1b08635a8cd4e0cbeaf6f5e922085908d48eb05d44c5ae9eabab148512ca",
- "sha256:c512accbd6ff0270939b9ac214b84fb5ada5f0409c44298361b2f5e13f9aed9e",
- "sha256:c75ffc45f25324e68ab238cb4b5c0a38cd1c3d7f1fb1f72b5541de469e2247db",
- "sha256:c95a03c79bbe30eec3ec2b7f076074f4281526724c8685a42872974ef4d36b72",
- "sha256:cadaeaba78750d58d3cc6ac4d1fd867da6fc73c88156b7a3212a3cd4819d679d",
- "sha256:cd6056167405314a4dc3c173943f11249fa0f1b204f8b51ed4bde1a9cd1834dc",
- "sha256:db72b07027db150f468fbada4d85b3b2729a3db39178abf5c543b784c1254539",
- "sha256:df2c707231459e8a4028eabcd3cfc827befd635b3ef72eada84ab13b52e1574d",
- "sha256:e62164b50f84e20601c1ff8eb55620d2ad25fb81b59e3cd776a1902527a788af",
- "sha256:e696f0dd336161fca9adbb846875d40752e6eba585843c768935ba5c9960722b",
- "sha256:eaa379fcd227ca235d04152ca6704c7cb55564116f8bc52545ff357628e10602",
- "sha256:ebea339af930f8ca5d7a699b921106c6e29c617fe9606fa7baa043c1cdae326f",
- "sha256:f4c39b0e3eac288fedc2b43055cfc2ca7a60362d0e5e87a637beac5d801ef478",
- "sha256:f5057856d21e7586765171eac8b9fc3f7d44ef39425f85dbcccb13b3ebea806c",
- "sha256:f6f45710b4459401609ebebdbcfb34515da4fc2aa886f95107f556ac69a9147e",
- "sha256:f97e83fa6c25693c7a35de154681fcc257c1c41b38beb0304b9c4d2d9e164479",
- "sha256:f9d0c5c045a3ca9bedfc35dca8526798eb91a07aa7a2c0fee134c6c6f321cbd7",
- "sha256:ff6f3db31555657f3163b15a6b7c6938d08df7adbfc9dd13d9d19edad678f1e8"
- ],
- "version": "==3.0.1"
+ "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6",
+ "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1",
+ "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e",
+ "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373",
+ "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62",
+ "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230",
+ "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be",
+ "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c",
+ "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0",
+ "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448",
+ "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f",
+ "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649",
+ "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d",
+ "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0",
+ "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706",
+ "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a",
+ "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59",
+ "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23",
+ "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5",
+ "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb",
+ "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e",
+ "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e",
+ "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c",
+ "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28",
+ "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d",
+ "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41",
+ "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974",
+ "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce",
+ "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f",
+ "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1",
+ "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d",
+ "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8",
+ "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017",
+ "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31",
+ "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7",
+ "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8",
+ "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e",
+ "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14",
+ "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd",
+ "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d",
+ "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795",
+ "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b",
+ "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b",
+ "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b",
+ "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203",
+ "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f",
+ "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19",
+ "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1",
+ "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a",
+ "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac",
+ "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9",
+ "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0",
+ "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137",
+ "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f",
+ "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6",
+ "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5",
+ "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909",
+ "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f",
+ "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0",
+ "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324",
+ "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755",
+ "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb",
+ "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854",
+ "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c",
+ "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60",
+ "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84",
+ "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0",
+ "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b",
+ "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1",
+ "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531",
+ "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1",
+ "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11",
+ "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326",
+ "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df",
+ "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"
+ ],
+ "markers": "python_full_version >= '3.7.0'",
+ "version": "==3.1.0"
+ },
+ "click": {
+ "hashes": [
+ "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e",
+ "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"
+ ],
+ "markers": "python_version >= '3.7'",
+ "version": "==8.1.3"
},
- "coverage": {
+ "colorama": {
"hashes": [
- "sha256:04481245ef966fbd24ae9b9e537ce899ae584d521dfbe78f89cad003c38ca2ab",
- "sha256:0c45948f613d5d18c9ec5eaa203ce06a653334cf1bd47c783a12d0dd4fd9c851",
- "sha256:10188fe543560ec4874f974b5305cd1a8bdcfa885ee00ea3a03733464c4ca265",
- "sha256:218fe982371ac7387304153ecd51205f14e9d731b34fb0568181abaf7b443ba0",
- "sha256:29571503c37f2ef2138a306d23e7270687c0efb9cab4bd8038d609b5c2393a3a",
- "sha256:2a60d6513781e87047c3e630b33b4d1e89f39836dac6e069ffee28c4786715f5",
- "sha256:2bf1d5f2084c3932b56b962a683074a3692bce7cabd3aa023c987a2a8e7612f6",
- "sha256:3164d31078fa9efe406e198aecd2a02d32a62fecbdef74f76dad6a46c7e48311",
- "sha256:32df215215f3af2c1617a55dbdfb403b772d463d54d219985ac7cd3bf124cada",
- "sha256:33d1ae9d4079e05ac4cc1ef9e20c648f5afabf1a92adfaf2ccf509c50b85717f",
- "sha256:33ff26d0f6cc3ca8de13d14fde1ff8efe1456b53e3f0273e63cc8b3c84a063d8",
- "sha256:38da2db80cc505a611938d8624801158e409928b136c8916cd2e203970dde4dc",
- "sha256:3b155caf3760408d1cb903b21e6a97ad4e2bdad43cbc265e3ce0afb8e0057e73",
- "sha256:3b946bbcd5a8231383450b195cfb58cb01cbe7f8949f5758566b881df4b33baf",
- "sha256:3baf5f126f30781b5e93dbefcc8271cb2491647f8283f20ac54d12161dff080e",
- "sha256:4b14d5e09c656de5038a3f9bfe5228f53439282abcab87317c9f7f1acb280352",
- "sha256:51b236e764840a6df0661b67e50697aaa0e7d4124ca95e5058fa3d7cbc240b7c",
- "sha256:63ffd21aa133ff48c4dff7adcc46b7ec8b565491bfc371212122dd999812ea1c",
- "sha256:6a43c7823cd7427b4ed763aa7fb63901ca8288591323b58c9cd6ec31ad910f3c",
- "sha256:755e89e32376c850f826c425ece2c35a4fc266c081490eb0a841e7c1cb0d3bda",
- "sha256:7a726d742816cb3a8973c8c9a97539c734b3a309345236cd533c4883dda05b8d",
- "sha256:7c7c0d0827e853315c9bbd43c1162c006dd808dbbe297db7ae66cd17b07830f0",
- "sha256:7ed681b0f8e8bcbbffa58ba26fcf5dbc8f79e7997595bf071ed5430d8c08d6f3",
- "sha256:7ee5c9bb51695f80878faaa5598040dd6c9e172ddcf490382e8aedb8ec3fec8d",
- "sha256:8361be1c2c073919500b6601220a6f2f98ea0b6d2fec5014c1d9cfa23dd07038",
- "sha256:8ae125d1134bf236acba8b83e74c603d1b30e207266121e76484562bc816344c",
- "sha256:9817733f0d3ea91bea80de0f79ef971ae94f81ca52f9b66500c6a2fea8e4b4f8",
- "sha256:98b85dd86514d889a2e3dd22ab3c18c9d0019e696478391d86708b805f4ea0fa",
- "sha256:9ccb092c9ede70b2517a57382a601619d20981f56f440eae7e4d7eaafd1d1d09",
- "sha256:9d58885215094ab4a86a6aef044e42994a2bd76a446dc59b352622655ba6621b",
- "sha256:b643cb30821e7570c0aaf54feaf0bfb630b79059f85741843e9dc23f33aaca2c",
- "sha256:bc7c85a150501286f8b56bd8ed3aa4093f4b88fb68c0843d21ff9656f0009d6a",
- "sha256:beeb129cacea34490ffd4d6153af70509aa3cda20fdda2ea1a2be870dfec8d52",
- "sha256:c31b75ae466c053a98bf26843563b3b3517b8f37da4d47b1c582fdc703112bc3",
- "sha256:c4e4881fa9e9667afcc742f0c244d9364d197490fbc91d12ac3b5de0bf2df146",
- "sha256:c5b15ed7644ae4bee0ecf74fee95808dcc34ba6ace87e8dfbf5cb0dc20eab45a",
- "sha256:d12d076582507ea460ea2a89a8c85cb558f83406c8a41dd641d7be9a32e1274f",
- "sha256:d248cd4a92065a4d4543b8331660121b31c4148dd00a691bfb7a5cdc7483cfa4",
- "sha256:d47dd659a4ee952e90dc56c97d78132573dc5c7b09d61b416a9deef4ebe01a0c",
- "sha256:d4a5a5879a939cb84959d86869132b00176197ca561c664fc21478c1eee60d75",
- "sha256:da9b41d4539eefd408c46725fb76ecba3a50a3367cafb7dea5f250d0653c1040",
- "sha256:db61a79c07331e88b9a9974815c075fbd812bc9dbc4dc44b366b5368a2936063",
- "sha256:ddb726cb861c3117a553f940372a495fe1078249ff5f8a5478c0576c7be12050",
- "sha256:ded59300d6330be27bc6cf0b74b89ada58069ced87c48eaf9344e5e84b0072f7",
- "sha256:e2617759031dae1bf183c16cef8fcfb3de7617f394c813fa5e8e46e9b82d4222",
- "sha256:e5cdbb5cafcedea04924568d990e20ce7f1945a1dd54b560f879ee2d57226912",
- "sha256:ec8e767f13be637d056f7e07e61d089e555f719b387a7070154ad80a0ff31801",
- "sha256:ef382417db92ba23dfb5864a3fc9be27ea4894e86620d342a116b243ade5d35d",
- "sha256:f2cba5c6db29ce991029b5e4ac51eb36774458f0a3b8d3137241b32d1bb91f06",
- "sha256:f5b4198d85a3755d27e64c52f8c95d6333119e49fd001ae5798dac872c95e0f8",
- "sha256:ffeeb38ee4a80a30a6877c5c4c359e5498eec095878f1581453202bfacc8fbc2"
+ "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44",
+ "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"
],
- "markers": "python_version >= '3.7'",
- "version": "==7.1.0"
- },
- "cryptography": {
- "hashes": [
- "sha256:0f8da300b5c8af9f98111ffd512910bc792b4c77392a9523624680f7956a99d4",
- "sha256:35f7c7d015d474f4011e859e93e789c87d21f6f4880ebdc29896a60403328f1f",
- "sha256:5aa67414fcdfa22cf052e640cb5ddc461924a045cacf325cd164e65312d99502",
- "sha256:5d2d8b87a490bfcd407ed9d49093793d0f75198a35e6eb1a923ce1ee86c62b41",
- "sha256:6687ef6d0a6497e2b58e7c5b852b53f62142cfa7cd1555795758934da363a965",
- "sha256:6f8ba7f0328b79f08bdacc3e4e66fb4d7aab0c3584e0bd41328dce5262e26b2e",
- "sha256:706843b48f9a3f9b9911979761c91541e3d90db1ca905fd63fee540a217698bc",
- "sha256:807ce09d4434881ca3a7594733669bd834f5b2c6d5c7e36f8c00f691887042ad",
- "sha256:83e17b26de248c33f3acffb922748151d71827d6021d98c70e6c1a25ddd78505",
- "sha256:96f1157a7c08b5b189b16b47bc9db2332269d6680a196341bf30046330d15388",
- "sha256:aec5a6c9864be7df2240c382740fcf3b96928c46604eaa7f3091f58b878c0bb6",
- "sha256:b0afd054cd42f3d213bf82c629efb1ee5f22eba35bf0eec88ea9ea7304f511a2",
- "sha256:ced4e447ae29ca194449a3f1ce132ded8fcab06971ef5f618605aacaa612beac",
- "sha256:d1f6198ee6d9148405e49887803907fe8962a23e6c6f83ea7d98f1c0de375695",
- "sha256:e124352fd3db36a9d4a21c1aa27fd5d051e621845cb87fb851c08f4f75ce8be6",
- "sha256:e422abdec8b5fa8462aa016786680720d78bdce7a30c652b7fadf83a4ba35336",
- "sha256:ef8b72fa70b348724ff1218267e7f7375b8de4e8194d1636ee60510aae104cd0",
- "sha256:f0c64d1bd842ca2633e74a1a28033d139368ad959872533b1bab8c80e8240a0c",
- "sha256:f24077a3b5298a5a06a8e0536e3ea9ec60e4c7ac486755e5fb6e6ea9b3500106",
- "sha256:fdd188c8a6ef8769f148f88f859884507b954cc64db6b52f66ef199bb9ad660a",
- "sha256:fe913f20024eb2cb2f323e42a64bdf2911bb9738a15dba7d3cce48151034e3a8"
+ "markers": "os_name == 'nt'",
+ "version": "==0.4.6"
+ },
+ "commonmark": {
+ "hashes": [
+ "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60",
+ "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"
],
- "index": "pypi",
- "version": "==39.0.1"
+ "version": "==0.9.1"
+ },
+ "coverage": {
+ "extras": [
+ "toml"
+ ],
+ "hashes": [
+ "sha256:0342a28617e63ad15d96dca0f7ae9479a37b7d8a295f749c14f3436ea59fdcb3",
+ "sha256:066b44897c493e0dcbc9e6a6d9f8bbb6607ef82367cf6810d387c09f0cd4fe9a",
+ "sha256:10b15394c13544fce02382360cab54e51a9e0fd1bd61ae9ce012c0d1e103c813",
+ "sha256:12580845917b1e59f8a1c2ffa6af6d0908cb39220f3019e36c110c943dc875b0",
+ "sha256:156192e5fd3dbbcb11cd777cc469cf010a294f4c736a2b2c891c77618cb1379a",
+ "sha256:1637253b11a18f453e34013c665d8bf15904c9e3c44fbda34c643fbdc9d452cd",
+ "sha256:292300f76440651529b8ceec283a9370532f4ecba9ad67d120617021bb5ef139",
+ "sha256:30dcaf05adfa69c2a7b9f7dfd9f60bc8e36b282d7ed25c308ef9e114de7fc23b",
+ "sha256:338aa9d9883aaaad53695cb14ccdeb36d4060485bb9388446330bef9c361c252",
+ "sha256:373ea34dca98f2fdb3e5cb33d83b6d801007a8074f992b80311fc589d3e6b790",
+ "sha256:38c0a497a000d50491055805313ed83ddba069353d102ece8aef5d11b5faf045",
+ "sha256:40cc0f91c6cde033da493227797be2826cbf8f388eaa36a0271a97a332bfd7ce",
+ "sha256:4436cc9ba5414c2c998eaedee5343f49c02ca93b21769c5fdfa4f9d799e84200",
+ "sha256:509ecd8334c380000d259dc66feb191dd0a93b21f2453faa75f7f9cdcefc0718",
+ "sha256:5c587f52c81211d4530fa6857884d37f514bcf9453bdeee0ff93eaaf906a5c1b",
+ "sha256:5f3671662dc4b422b15776cdca89c041a6349b4864a43aa2350b6b0b03bbcc7f",
+ "sha256:6599bf92f33ab041e36e06d25890afbdf12078aacfe1f1d08c713906e49a3fe5",
+ "sha256:6e8a95f243d01ba572341c52f89f3acb98a3b6d1d5d830efba86033dd3687ade",
+ "sha256:706ec567267c96717ab9363904d846ec009a48d5f832140b6ad08aad3791b1f5",
+ "sha256:780551e47d62095e088f251f5db428473c26db7829884323e56d9c0c3118791a",
+ "sha256:7ff8f3fb38233035028dbc93715551d81eadc110199e14bbbfa01c5c4a43f8d8",
+ "sha256:828189fcdda99aae0d6bf718ea766b2e715eabc1868670a0a07bf8404bf58c33",
+ "sha256:857abe2fa6a4973f8663e039ead8d22215d31db613ace76e4a98f52ec919068e",
+ "sha256:883123d0bbe1c136f76b56276074b0c79b5817dd4238097ffa64ac67257f4b6c",
+ "sha256:8877d9b437b35a85c18e3c6499b23674684bf690f5d96c1006a1ef61f9fdf0f3",
+ "sha256:8e575a59315a91ccd00c7757127f6b2488c2f914096077c745c2f1ba5b8c0969",
+ "sha256:97072cc90f1009386c8a5b7de9d4fc1a9f91ba5ef2146c55c1f005e7b5c5e068",
+ "sha256:9a22cbb5ede6fade0482111fa7f01115ff04039795d7092ed0db43522431b4f2",
+ "sha256:a063aad9f7b4c9f9da7b2550eae0a582ffc7623dca1c925e50c3fbde7a579771",
+ "sha256:a08c7401d0b24e8c2982f4e307124b671c6736d40d1c39e09d7a8687bddf83ed",
+ "sha256:a0b273fe6dc655b110e8dc89b8ec7f1a778d78c9fd9b4bda7c384c8906072212",
+ "sha256:a2b3b05e22a77bb0ae1a3125126a4e08535961c946b62f30985535ed40e26614",
+ "sha256:a66e055254a26c82aead7ff420d9fa8dc2da10c82679ea850d8feebf11074d88",
+ "sha256:aa387bd7489f3e1787ff82068b295bcaafbf6f79c3dad3cbc82ef88ce3f48ad3",
+ "sha256:ae453f655640157d76209f42c62c64c4d4f2c7f97256d3567e3b439bd5c9b06c",
+ "sha256:b5016e331b75310610c2cf955d9f58a9749943ed5f7b8cfc0bb89c6134ab0a84",
+ "sha256:b9a4ee55174b04f6af539218f9f8083140f61a46eabcaa4234f3c2a452c4ed11",
+ "sha256:bd3b4b8175c1db502adf209d06136c000df4d245105c8839e9d0be71c94aefe1",
+ "sha256:bebea5f5ed41f618797ce3ffb4606c64a5de92e9c3f26d26c2e0aae292f015c1",
+ "sha256:c10fbc8a64aa0f3ed136b0b086b6b577bc64d67d5581acd7cc129af52654384e",
+ "sha256:c2c41c1b1866b670573657d584de413df701f482574bad7e28214a2362cb1fd1",
+ "sha256:cf97ed82ca986e5c637ea286ba2793c85325b30f869bf64d3009ccc1a31ae3fd",
+ "sha256:d1f25ee9de21a39b3a8516f2c5feb8de248f17da7eead089c2e04aa097936b47",
+ "sha256:d2fbc2a127e857d2f8898aaabcc34c37771bf78a4d5e17d3e1f5c30cd0cbc62a",
+ "sha256:dc945064a8783b86fcce9a0a705abd7db2117d95e340df8a4333f00be5efb64c",
+ "sha256:ddc5a54edb653e9e215f75de377354e2455376f416c4378e1d43b08ec50acc31",
+ "sha256:e8834e5f17d89e05697c3c043d3e58a8b19682bf365048837383abfe39adaed5",
+ "sha256:ef9659d1cda9ce9ac9585c045aaa1e59223b143f2407db0eaee0b61a4f266fb6",
+ "sha256:f6f5cab2d7f0c12f8187a376cc6582c477d2df91d63f75341307fcdcb5d60303",
+ "sha256:f81c9b4bd8aa747d417407a7f6f0b1469a43b36a85748145e144ac4e8d303cb5",
+ "sha256:f99ef080288f09ffc687423b8d60978cf3a465d3f404a18d1a05474bd8575a47"
+ ],
+ "markers": "python_version >= '3.7'",
+ "version": "==7.2.5"
},
"docutils": {
"hashes": [
- "sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6",
- "sha256:5e1de4d849fee02c63b040a4a3fd567f4ab104defd8a5511fbbc24a8a017efbc"
+ "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125",
+ "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"
],
- "markers": "python_version >= '3.7'",
- "version": "==0.19"
+ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
+ "version": "==0.17.1"
},
- "entrypoints": {
+ "exceptiongroup": {
"hashes": [
- "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19",
- "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"
+ "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e",
+ "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"
],
- "markers": "python_version >= '2.7'",
- "version": "==0.3"
+ "markers": "python_version < '3.11'",
+ "version": "==1.1.1"
},
"flake8": {
"hashes": [
- "sha256:45681a117ecc81e870cbf1262835ae4af5e7a8b08e40b944a8a6e6b895914cfb",
- "sha256:49356e766643ad15072a789a20915d3c91dc89fd313ccd71802303fd67e4deca"
+ "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db",
+ "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"
],
"index": "pypi",
- "version": "==3.7.9"
+ "version": "==5.0.4"
},
"idna": {
"hashes": [
@@ -352,11 +263,19 @@
},
"importlib-metadata": {
"hashes": [
- "sha256:7efb448ec9a5e313a57655d35aa54cd3e01b7e1fbcf72dce1bf06119420f5bad",
- "sha256:e354bedeb60efa6affdcc8ae121b73544a7aa74156d047311948f6d711cd378d"
+ "sha256:057e92c15bc8d9e8109738a48db0ccb31b4d9d5cfbee5a8670879a30be66304b",
+ "sha256:b7e52a1f8dec14a75ea73e0891f3060099ca1d8e6a462a4dff11c3e119ea1b31"
],
- "markers": "python_version < '3.12'",
- "version": "==6.0.0"
+ "markers": "python_version < '3.8'",
+ "version": "==4.2.0"
+ },
+ "iniconfig": {
+ "hashes": [
+ "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3",
+ "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"
+ ],
+ "markers": "python_version >= '3.7'",
+ "version": "==2.0.0"
},
"jaraco.classes": {
"hashes": [
@@ -366,14 +285,6 @@
"markers": "python_version >= '3.7'",
"version": "==3.2.3"
},
- "jeepney": {
- "hashes": [
- "sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806",
- "sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755"
- ],
- "markers": "sys_platform == 'linux'",
- "version": "==0.8.0"
- },
"jinja2": {
"hashes": [
"sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852",
@@ -384,11 +295,11 @@
},
"keyring": {
"hashes": [
- "sha256:771ed2a91909389ed6148631de678f82ddc73737d85a927f382a8a1b157898cd",
- "sha256:ba2e15a9b35e21908d0aaf4e0a47acc52d6ae33444df0da2b49d41a46ef6d678"
+ "sha256:69732a15cb1433bdfbc3b980a8a36a04878a6cfd7cb99f497b573f31618001c0",
+ "sha256:69b01dd83c42f590250fe7a1f503fc229b14de83857314b1933a3ddbf595c4a5"
],
"markers": "python_version >= '3.7'",
- "version": "==23.13.1"
+ "version": "==23.9.3"
},
"markupsafe": {
"hashes": [
@@ -448,26 +359,27 @@
},
"mccabe": {
"hashes": [
- "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
- "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
+ "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325",
+ "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"
],
- "version": "==0.6.1"
+ "markers": "python_version >= '3.6'",
+ "version": "==0.7.0"
},
"more-itertools": {
"hashes": [
- "sha256:250e83d7e81d0c87ca6bd942e6aeab8cc9daa6096d12c5308f3f92fa5e5c1f41",
- "sha256:5a6257e40878ef0520b1803990e3e22303a41b5714006c32a3fd8304b26ea1ab"
+ "sha256:cabaa341ad0389ea83c17a94566a53ae4c9d07349861ecb14dc6d0345cf9ac5d",
+ "sha256:d2bc7f02446e86a68911e58ded76d6561eea00cddfb2a91e7019bbb586c799f3"
],
"markers": "python_version >= '3.7'",
- "version": "==9.0.0"
+ "version": "==9.1.0"
},
"packaging": {
"hashes": [
- "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2",
- "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"
+ "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61",
+ "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"
],
"markers": "python_version >= '3.7'",
- "version": "==23.0"
+ "version": "==23.1"
},
"pkginfo": {
"hashes": [
@@ -479,74 +391,109 @@
},
"pluggy": {
"hashes": [
- "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
- "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"
+ "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159",
+ "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==0.13.1"
- },
- "py": {
- "hashes": [
- "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719",
- "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
- "version": "==1.11.0"
+ "markers": "python_version >= '3.6'",
+ "version": "==1.0.0"
},
"pycodestyle": {
"hashes": [
- "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56",
- "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"
+ "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785",
+ "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==2.5.0"
- },
- "pycparser": {
- "hashes": [
- "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9",
- "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"
+ "markers": "python_version >= '3.6'",
+ "version": "==2.9.1"
+ },
+ "pydantic": {
+ "hashes": [
+ "sha256:01aea3a42c13f2602b7ecbbea484a98169fb568ebd9e247593ea05f01b884b2e",
+ "sha256:0cd181f1d0b1d00e2b705f1bf1ac7799a2d938cce3376b8007df62b29be3c2c6",
+ "sha256:10a86d8c8db68086f1e30a530f7d5f83eb0685e632e411dbbcf2d5c0150e8dcd",
+ "sha256:193924c563fae6ddcb71d3f06fa153866423ac1b793a47936656e806b64e24ca",
+ "sha256:464855a7ff7f2cc2cf537ecc421291b9132aa9c79aef44e917ad711b4a93163b",
+ "sha256:516f1ed9bc2406a0467dd777afc636c7091d71f214d5e413d64fef45174cfc7a",
+ "sha256:6434b49c0b03a51021ade5c4daa7d70c98f7a79e95b551201fff682fc1661245",
+ "sha256:64d34ab766fa056df49013bb6e79921a0265204c071984e75a09cbceacbbdd5d",
+ "sha256:670bb4683ad1e48b0ecb06f0cfe2178dcf74ff27921cdf1606e527d2617a81ee",
+ "sha256:68792151e174a4aa9e9fc1b4e653e65a354a2fa0fed169f7b3d09902ad2cb6f1",
+ "sha256:701daea9ffe9d26f97b52f1d157e0d4121644f0fcf80b443248434958fd03dc3",
+ "sha256:7d45fc99d64af9aaf7e308054a0067fdcd87ffe974f2442312372dfa66e1001d",
+ "sha256:80b1fab4deb08a8292d15e43a6edccdffa5377a36a4597bb545b93e79c5ff0a5",
+ "sha256:82dffb306dd20bd5268fd6379bc4bfe75242a9c2b79fec58e1041fbbdb1f7914",
+ "sha256:8c7f51861d73e8b9ddcb9916ae7ac39fb52761d9ea0df41128e81e2ba42886cd",
+ "sha256:950ce33857841f9a337ce07ddf46bc84e1c4946d2a3bba18f8280297157a3fd1",
+ "sha256:976cae77ba6a49d80f461fd8bba183ff7ba79f44aa5cfa82f1346b5626542f8e",
+ "sha256:9f6f0fd68d73257ad6685419478c5aece46432f4bdd8d32c7345f1986496171e",
+ "sha256:a7cd2251439988b413cb0a985c4ed82b6c6aac382dbaff53ae03c4b23a70e80a",
+ "sha256:abfb7d4a7cd5cc4e1d1887c43503a7c5dd608eadf8bc615413fc498d3e4645cd",
+ "sha256:ae150a63564929c675d7f2303008d88426a0add46efd76c3fc797cd71cb1b46f",
+ "sha256:b0f85904f73161817b80781cc150f8b906d521fa11e3cdabae19a581c3606209",
+ "sha256:b4a849d10f211389502059c33332e91327bc154acc1845f375a99eca3afa802d",
+ "sha256:c15582f9055fbc1bfe50266a19771bbbef33dd28c45e78afbe1996fd70966c2a",
+ "sha256:c230c0d8a322276d6e7b88c3f7ce885f9ed16e0910354510e0bae84d54991143",
+ "sha256:cc1dde4e50a5fc1336ee0581c1612215bc64ed6d28d2c7c6f25d2fe3e7c3e918",
+ "sha256:cf135c46099ff3f919d2150a948ce94b9ce545598ef2c6c7bf55dca98a304b52",
+ "sha256:cfc83c0678b6ba51b0532bea66860617c4cd4251ecf76e9846fa5a9f3454e97e",
+ "sha256:d2a5ebb48958754d386195fe9e9c5106f11275867051bf017a8059410e9abf1f",
+ "sha256:d71e69699498b020ea198468e2480a2f1e7433e32a3a99760058c6520e2bea7e",
+ "sha256:d75ae19d2a3dbb146b6f324031c24f8a3f52ff5d6a9f22f0683694b3afcb16fb",
+ "sha256:dfe2507b8ef209da71b6fb5f4e597b50c5a34b78d7e857c4f8f3115effaef5fe",
+ "sha256:e0cfe895a504c060e5d36b287ee696e2fdad02d89e0d895f83037245218a87fe",
+ "sha256:e79e999e539872e903767c417c897e729e015872040e56b96e67968c3b918b2d",
+ "sha256:ecbbc51391248116c0a055899e6c3e7ffbb11fb5e2a4cd6f2d0b93272118a209",
+ "sha256:f4a2b50e2b03d5776e7f21af73e2070e1b5c0d0df255a827e7c632962f8315af"
],
- "version": "==2.21"
+ "markers": "python_version >= '3.7'",
+ "version": "==1.10.7"
},
"pyflakes": {
"hashes": [
- "sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0",
- "sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"
+ "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2",
+ "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==2.1.1"
+ "markers": "python_version >= '3.6'",
+ "version": "==2.5.0"
},
"pygments": {
"hashes": [
- "sha256:b3ed06a9e8ac9a9aae5a6f5dbe78a8a58655d17b43b93c078f094ddc476ae297",
- "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717"
+ "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c",
+ "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"
],
- "markers": "python_version >= '3.6'",
- "version": "==2.14.0"
+ "markers": "python_version >= '3.7'",
+ "version": "==2.15.1"
+ },
+ "pyproject-hooks": {
+ "hashes": [
+ "sha256:283c11acd6b928d2f6a7c73fa0d01cb2bdc5f07c57a2eeb6e83d5e56b97976f8",
+ "sha256:f271b298b97f5955d53fb12b72c1fb1948c22c1a6b70b315c54cedaca0264ef5"
+ ],
+ "markers": "python_version >= '3.7'",
+ "version": "==1.0.0"
},
"pytest": {
"hashes": [
- "sha256:0e5b30f5cb04e887b91b1ee519fa3d89049595f428c1db76e73bd7f17b09b172",
- "sha256:84dde37075b8805f3d1f392cc47e38a0e59518fb46a431cfdaf7cf1ce805f970"
+ "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362",
+ "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"
],
"index": "pypi",
- "version": "==5.4.1"
+ "version": "==7.3.1"
},
"pytest-cov": {
"hashes": [
- "sha256:cc6742d8bac45070217169f5f72ceee1e0e55b0221f54bcf24845972d3a47f2b",
- "sha256:cdbdef4f870408ebdbfeb44e63e07eb18bb4619fae852f6e760645fa36172626"
+ "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b",
+ "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"
],
"index": "pypi",
- "version": "==2.8.1"
+ "version": "==4.0.0"
},
"pytest-datafiles": {
"hashes": [
- "sha256:143329cbb1dbbb07af24f88fa4668e2f59ce233696cf12c49fd1c98d1756dbf9",
- "sha256:e349b6ad7bcca111f3677b7201d3ca81f93b5e09dcfae8ee2be2c3cae9f55bc7"
+ "sha256:2176e10d3f6e76f358925a897e21e2bcc5a0170b92fac4e66ed055eaa2ca6a22",
+ "sha256:a70c4c66a36d1cdcfc095607f04eee66eaef3fa64cbb62d60c47ce169901d1d4"
],
"index": "pypi",
- "version": "==2.0"
+ "version": "==3.0.0"
},
"python-coveralls": {
"hashes": [
@@ -558,10 +505,19 @@
},
"pytz": {
"hashes": [
- "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0",
- "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a"
+ "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588",
+ "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"
+ ],
+ "markers": "python_version < '3.9'",
+ "version": "==2023.3"
+ },
+ "pywin32-ctypes": {
+ "hashes": [
+ "sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942",
+ "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"
],
- "version": "==2022.7.1"
+ "markers": "sys_platform == 'win32'",
+ "version": "==0.2.0"
},
"pyyaml": {
"hashes": [
@@ -619,47 +575,74 @@
},
"requests": {
"hashes": [
- "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa",
- "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"
+ "sha256:10e94cc4f3121ee6da529d358cdaeaff2f1c409cd377dbc72b825852f2f7e294",
+ "sha256:239d7d4458afcb28a692cdd298d87542235f4ca8d36d03a15bfc128a6559a2f4"
],
- "markers": "python_version >= '3.7' and python_version < '4'",
- "version": "==2.28.2"
+ "markers": "python_version >= '3.7'",
+ "version": "==2.30.0"
},
"requests-toolbelt": {
"hashes": [
- "sha256:18565aa58116d9951ac39baa288d3adb5b3ff975c4f25eee78555d89e8f247f7",
- "sha256:62e09f7ff5ccbda92772a29f394a49c3ad6cb181d568b1337626b2abb628a63d"
+ "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6",
+ "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==0.10.1"
+ "version": "==1.0.0"
},
- "sanitized-package": {
- "editable": true,
- "path": "."
+ "rfc3986": {
+ "hashes": [
+ "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd",
+ "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c"
+ ],
+ "markers": "python_version >= '3.7'",
+ "version": "==2.0.0"
},
- "secretstorage": {
+ "rich": {
"hashes": [
- "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77",
- "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99"
+ "sha256:a4eb26484f2c82589bd9a17c73d32a010b1e29d89f1604cd9bf3a2097b81bb5e",
+ "sha256:ba3a3775974105c221d31141f2c116f4fd65c5ceb0698657a11e9f295ec93fd0"
],
- "markers": "sys_platform == 'linux'",
- "version": "==3.3.3"
+ "markers": "python_full_version >= '3.6.3' and python_full_version < '4.0.0'",
+ "version": "==12.6.0"
+ },
+ "rstcheck": {
+ "hashes": [
+ "sha256:4aaa46e0debc179f849807c453fa384fd2b75167faf5b1274115730805fab529",
+ "sha256:f9cb07a72ef9a81d1e32187eae29b00a89421ccba1bde0b1652a08ed0923f61b"
+ ],
+ "index": "pypi",
+ "version": "==6.1.2"
+ },
+ "rstcheck-core": {
+ "hashes": [
+ "sha256:add19c9a1b97d9087f4b463b49c12cd8a9c03689a255e99089c70a2692f16369",
+ "sha256:d75d7df8f15b58e8aafe322d6fb6ef1ac8d12bb563089b0696948a00ee7f601a"
+ ],
+ "markers": "python_version >= '3.7' and python_version < '4.0'",
+ "version": "==1.0.3"
},
"setuptools": {
"hashes": [
- "sha256:16ccf598aab3b506593c17378473978908a2734d7336755a8769b480906bec1c",
- "sha256:b440ee5f7e607bb8c9de15259dba2583dd41a38879a7abc1d43a71c59524da48"
+ "sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b",
+ "sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990"
],
"markers": "python_version >= '3.7'",
- "version": "==67.2.0"
+ "version": "==67.7.2"
+ },
+ "shellingham": {
+ "hashes": [
+ "sha256:368bf8c00754fd4f55afb7bbb86e272df77e4dc76ac29dbcbb81a59e9fc15744",
+ "sha256:823bc5fb5c34d60f285b624e7264f4dda254bc803a3774a147bf99c0e3004a28"
+ ],
+ "version": "==1.5.0.post1"
},
"six": {
"hashes": [
- "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a",
- "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"
+ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
+ "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
],
- "index": "pypi",
- "version": "==1.14.0"
+ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
+ "version": "==1.16.0"
},
"snowballstemmer": {
"hashes": [
@@ -670,27 +653,27 @@
},
"sphinx": {
"hashes": [
- "sha256:b4c750d546ab6d7e05bdff6ac24db8ae3e8b8253a3569b754e445110a0a12b66",
- "sha256:fc312670b56cb54920d6cc2ced455a22a547910de10b3142276495ced49231cb"
+ "sha256:0a8836751a68306b3fe97ecbe44db786f8479c3bf4b80e3a7f5c838657b4698c",
+ "sha256:6a11ea5dd0bdb197f9c2abc2e0ce73e01340464feaece525e64036546d24c851"
],
"index": "pypi",
- "version": "==2.4.4"
+ "version": "==4.3.2"
},
"sphinx-rtd-theme": {
"hashes": [
- "sha256:00cf895504a7895ee433807c62094cf1e95f065843bf3acd17037c3e9a2becd4",
- "sha256:728607e34d60456d736cc7991fd236afb828b21b82f956c5ea75f94c8414040a"
+ "sha256:a0d8bd1a2ed52e0b338cbe19c4b2eef3c5e7a048769753dac6a9f059c7b641b8",
+ "sha256:f823f7e71890abe0ac6aaa6013361ea2696fc8d3e1fa798f463e82bdb77eeff2"
],
"index": "pypi",
- "version": "==0.4.3"
+ "version": "==1.2.0"
},
"sphinxcontrib-applehelp": {
"hashes": [
- "sha256:29d341f67fb0f6f586b23ad80e072c8e6ad0b48417db2bde114a4c9746feb228",
- "sha256:828f867945bbe39817c210a1abfd1bc4895c8b73fcaade56d45357a348a07d7e"
+ "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a",
+ "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"
],
- "markers": "python_version >= '3.8'",
- "version": "==1.0.4"
+ "markers": "python_version >= '3.5'",
+ "version": "==1.0.2"
},
"sphinxcontrib-devhelp": {
"hashes": [
@@ -702,11 +685,19 @@
},
"sphinxcontrib-htmlhelp": {
"hashes": [
- "sha256:0cbdd302815330058422b98a113195c9249825d681e18f11e8b1f78a2f11efff",
- "sha256:c38cb46dccf316c79de6e5515e1770414b797162b23cd3d06e67020e1d2a6903"
+ "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07",
+ "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2"
],
- "markers": "python_version >= '3.8'",
- "version": "==2.0.1"
+ "markers": "python_version >= '3.6'",
+ "version": "==2.0.0"
+ },
+ "sphinxcontrib-jquery": {
+ "hashes": [
+ "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a",
+ "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae"
+ ],
+ "markers": "python_version > '3'",
+ "version": "==4.1"
},
"sphinxcontrib-jsmath": {
"hashes": [
@@ -732,40 +723,55 @@
"markers": "python_version >= '3.5'",
"version": "==1.1.5"
},
- "tqdm": {
+ "tomli": {
"hashes": [
- "sha256:5f4f682a004951c1b450bc753c710e9280c5746ce6ffedee253ddbcbf54cf1e4",
- "sha256:6fee160d6ffcd1b1c68c65f14c829c22832bc401726335ce92c52d395944a6a1"
+ "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc",
+ "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==4.64.1"
+ "markers": "python_version < '3.11'",
+ "version": "==2.0.1"
},
"twine": {
"hashes": [
- "sha256:c1af8ca391e43b0a06bbc155f7f67db0bf0d19d284bfc88d1675da497a946124",
- "sha256:d561a5e511f70275e5a485a6275ff61851c16ffcb3a95a602189161112d9f160"
+ "sha256:929bc3c280033347a00f847236564d1c52a3e61b1ac2516c97c48f3ceab756d8",
+ "sha256:9e102ef5fdd5a20661eb88fad46338806c3bd32cf1db729603fe3697b1bc83c8"
],
"index": "pypi",
- "version": "==3.1.1"
+ "version": "==4.0.2"
},
- "urllib3": {
+ "typer": {
+ "extras": [
+ "all"
+ ],
"hashes": [
- "sha256:076907bf8fd355cde77728471316625a4d2f7e713c125f51953bb5b3eecf4f72",
- "sha256:75edcdc2f7d85b137124a6c3c9fc3933cdeaa12ecb9a6a959f22797a0feca7e1"
+ "sha256:b5e704f4e48ec263de1c0b3a2387cd405a13767d2f907f44c1a08cbad96f606d",
+ "sha256:ff797846578a9f2a201b53442aedeb543319466870fbe1c701eab66dd7681165"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
- "version": "==1.26.14"
+ "markers": "python_version >= '3.6'",
+ "version": "==0.7.0"
+ },
+ "types-docutils": {
+ "hashes": [
+ "sha256:1d029567e67c52992fd42aa968778bc10a5e445c8450fc751d672d6f50330a4a",
+ "sha256:556fb7ee19248aa482caa142a830c940b776b0f8c7577a98abe0977574546a1d"
+ ],
+ "version": "==0.19.1.9"
},
- "vfxnaming": {
- "editable": true,
- "path": "."
+ "typing-extensions": {
+ "hashes": [
+ "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb",
+ "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"
+ ],
+ "markers": "python_version < '3.8'",
+ "version": "==4.5.0"
},
- "wcwidth": {
+ "urllib3": {
"hashes": [
- "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e",
- "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"
+ "sha256:61717a1095d7e155cdb737ac7bb2f4324a858a1e2e6466f6d03ff630ca68d3cc",
+ "sha256:d055c2f9d38dc53c808f6fdc8eab7360b6fdbbde02340ed25cfbcd817c62469e"
],
- "version": "==0.2.6"
+ "markers": "python_version >= '3.7'",
+ "version": "==2.0.2"
},
"webencodings": {
"hashes": [
@@ -774,13 +780,21 @@
],
"version": "==0.5.1"
},
+ "wheel": {
+ "hashes": [
+ "sha256:cd1196f3faee2b31968d626e1731c94f99cbdb67cf5a46e4f5656cbee7738873",
+ "sha256:d236b20e7cb522daf2390fa84c55eea81c5c30190f90f29ae2ca1ad8355bf247"
+ ],
+ "index": "pypi",
+ "version": "==0.40.0"
+ },
"zipp": {
"hashes": [
- "sha256:6c4fe274b8f85ec73c37a8e4e3fa00df9fb9335da96fb789e3b96b318e5097b3",
- "sha256:a3cac813d40993596b39ea9e93a18e8a2076d5c378b8bc88ec32ab264e04ad02"
+ "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b",
+ "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"
],
"markers": "python_version >= '3.7'",
- "version": "==3.12.1"
+ "version": "==3.15.0"
}
}
}
diff --git a/README.md b/README.md
deleted file mode 100644
index 98cd607..0000000
--- a/README.md
+++ /dev/null
@@ -1,17 +0,0 @@
-# Naming Conventions Library
-
-[![Build Status](https://travis-ci.org/xiancg/vfxnaming.svg?branch=master)](https://travis-ci.org/xiancg/vfxnaming)
-[![Documentation Status](https://readthedocs.org/projects/naming-conventions/badge/?version=latest)](https://naming-conventions.readthedocs.io/en/latest/?badge=latest)
-[![Coverage Status](https://coveralls.io/repos/github/xiancg/vfxnaming/badge.svg?branch=master)](https://coveralls.io/github/xiancg/vfxnaming?branch=master)
-
-# Installation
-```python
-pip install vfxnaming
-```
-
-# Documentation
-[Naming Conventions Docs](http://naming-conventions.rtfd.io/)
-
-A complete suite of tools to manage naming conventions from one or more "Rule repositories". Structure naming rules with your own custom tokens. Then use the library to solve names following those rules so your naming is consistent, and also to parse metadata from exisiting names (cus a name is basically a collection of metadata, right?)
-
-This is completely based on [Copyright (c) 2017 Cesar Saez](https://www.cesarsaez.me/) work. I highly recommend his [Website-Blog](https://www.cesarsaez.me/) and the video tutorial series on his [YouTube Channel](https://www.youtube.com/channel/UCRjk6bi_1ZQ9sL69agz0xMg) Full credits in the [Naming Conventions Docs](http://naming-conventions.rtfd.io/)
\ No newline at end of file
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..7e4d6c0
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,26 @@
+VFX Naming Conventions Framework
+===================================
+
+.. image:: https://travis-ci.org/xiancg/vfxnaming.svg?branch=master
+ :target: https://travis-ci.org/xiancg/vfxnaming
+.. image:: https://readthedocs.org/projects/naming-conventions/badge/?version=latest
+.. image:: https://coveralls.io/repos/github/xiancg/vfxnaming/badge.svg?branch=master
+ :target: https://coveralls.io/github/xiancg/vfxnaming?branch=master
+
+A complete suite of tools to manage naming conventions from one or more "Rule repositories". Structure naming rules with your own custom tokens. Then use the library to solve names following those rules so your naming is consistent, and also to parse metadata from exisiting names (cus a name is basically a collection of metadata, right?)
+
+Installation
+--------------
+.. code-block:: python
+
+ pip install vfxnaming
+
+Documentation
+---------------
+`VFX Naming Conventions Docs `
+
+Acknowledgements
+------------------
+**vfxnaming** is based on `Copyright (c) 2017 Cesar Saez `_
+work. I highly recommend his `Website-Blog `_ and
+the video tutorial series on his `YouTube Channel `_
diff --git a/bin/deploy.bat b/bin/deploy.bat
new file mode 100644
index 0000000..7bda683
--- /dev/null
+++ b/bin/deploy.bat
@@ -0,0 +1,16 @@
+@echo off
+echo "Make sure you're running this from the project pipenv shell"
+IF EXIST ".\dist\*.whl" (
+ echo "Removing old wheels from dist."
+ del /f /q /s ".\dist\*.whl"
+)
+IF EXIST ".\dist\*.tar.gz" (
+ echo "Removing old source from dist."
+ del /f /q /s ".\dist\*.tar.gz"
+)
+mkdir ".\dist"
+echo "Setting up package wheel"
+python -m build
+echo "Uploading to PyPI"
+twine upload dist/* --verbose
+echo "Done!"
diff --git a/docs/requirements.txt b/docs/requirements.txt
deleted file mode 100644
index ecf975e..0000000
--- a/docs/requirements.txt
+++ /dev/null
@@ -1 +0,0 @@
--e .
\ No newline at end of file
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 673b063..f8ce9f5 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -17,8 +17,8 @@
# -- Project information -----------------------------------------------------
-project = 'VFX Naming'
-copyright = '2019, Cesar Saez, Chris Granados- Xian'
+project = 'VFX Naming Conventions Framework'
+copyright = '2019, Chris Granados- Xian, Cesar Saez'
author = 'Chris Granados- Xian'
# The full version, including alpha/beta/rc tags
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 86ce4f6..01604b5 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -60,10 +60,10 @@ This is going to initalize a log file where everything will be recorded.
from vfxnaming import logger
logger.init_file_logger()
-Credits
+Acknowledgements
--------------------
-**vfxnaming** is completely based on `Copyright (c) 2017 Cesar Saez `_
+**vfxnaming** is based on `Copyright (c) 2017 Cesar Saez `_
work. I highly recommend his `Website-Blog `_ and
the video tutorial series on his `YouTube Channel `_
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..b0471b7
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,3 @@
+[build-system]
+requires = ["setuptools", "wheel"]
+build-backend = "setuptools.build_meta:__legacy__"
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index 66e03ae..0000000
--- a/requirements.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# These requirements were autogenerated by pipenv
-# To regenerate from the project's Pipfile, run:
-#
-# pipenv lock --requirements
-#
-
--i https://pypi.org/simple/
-six==1.14.0
diff --git a/setup.cfg b/setup.cfg
index 224a779..11e9ec4 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,2 +1,2 @@
[metadata]
-description-file = README.md
\ No newline at end of file
+description-file = README.rst
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 6beb76d..53d11e9 100644
--- a/setup.py
+++ b/setup.py
@@ -1,38 +1,47 @@
from setuptools import setup, find_packages
-from os import path
-from io import open
+from pathlib import Path
+import re
-here = path.abspath(path.dirname(__file__))
+PACKAGENAME = 'vfxnaming'
+PACKAGE_NICENAME = 'VFX Naming Conventions Framework'
+
+module_dir = Path(__file__).parents[0]
+version_module = module_dir.joinpath('src', PACKAGENAME, '_version.py')
+
+version_str = "0.0.0"
+with open(version_module) as fp:
+ version_str = re.match(
+ r'.*__version__ = [\',\"](.*?)[\',\"]',
+ fp.read(),
+ re.DOTALL
+ ).group(1)
# Get the long description from the README file
-with open(path.join(here, 'README.md'), encoding='utf-8') as f:
- long_description = f.read()
+with open(module_dir.joinpath('README.rst'), encoding='utf-8') as fp:
+ long_description = fp.read()
-version_str = '1.2.3-beta'
setup(
- name='vfxnaming',
+ name=PACKAGENAME,
version=version_str,
- description='Naming conventions library',
+ description=PACKAGE_NICENAME,
long_description=long_description,
- long_description_content_type='text/markdown',
+ long_description_content_type='text/x-rst',
url='https://github.com/xiancg/vfxnaming',
- download_url='https://github.com/xiancg/vfxnaming/archive/v{}.tar.gz'.format(version_str),
+ download_url=f'https://github.com/xiancg/vfxnaming/archive/v{version_str}.tar.gz',
author='Chris Granados- Xian',
author_email='info@chrisgranados.com',
classifiers=[
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
- 'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.7'
],
package_dir={'': 'src'},
packages=find_packages(where='src'),
- python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4',
- install_requires=['six'],
+ python_requires='>=3.7, <4',
extras_require={
'dev': ['pytest', 'pytest-cov', 'pytest-datafiles', 'python-coveralls', 'flake8'],
'docs': ['sphinx', 'sphinx-rtd-theme']
},
- package_data={'': ['cfg/config.json']}
+ include_package_data=True
)
diff --git a/src/vfxnaming/_vesion.py b/src/vfxnaming/_vesion.py
new file mode 100644
index 0000000..80060c8
--- /dev/null
+++ b/src/vfxnaming/_vesion.py
@@ -0,0 +1 @@
+__version__ = "1.2.3-beta"
diff --git a/src/vfxnaming/error.py b/src/vfxnaming/error.py
index 194a80d..d94a5c3 100644
--- a/src/vfxnaming/error.py
+++ b/src/vfxnaming/error.py
@@ -1,6 +1,3 @@
-# coding=utf-8
-
-
class ParsingError(BaseException):
'''Raise when parsing couldn't be completed'''
diff --git a/tox.ini b/tox.ini
index 72b64fe..02e96f9 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,15 +1,12 @@
[tox]
-envlist = py27, py27ci, py37, py37ci, flake8, docs
+envlist = py37, py37ci, flake8, docs
skipsdist = True
[testenv]
-basepython = py27: python2.7
- py27ci: python2.7
- py37: python3.7
+basepython = py37: python3.7
py37ci: python3.7
flake8: python3.7
docs: python3.7
-deps = six
usedevelop = True
[testenv:docs]
@@ -23,20 +20,6 @@ deps = flake8
{[testenv]deps}
commands=flake8 src/
-[testenv:py27]
-deps = pytest
- pytest-cov
- pytest-datafiles
- {[testenv]deps}
-commands= pytest -c tox.ini --cov-report term-missing --cov-report html:cov_py27_html --cov=vfxnaming tests/
-
-[testenv:py27ci]
-deps = pytest
- pytest-cov
- pytest-datafiles
- {[testenv]deps}
-commands= pytest -c tox.ini --cov-report term-missing --cov=vfxnaming tests/
-
[testenv:py37]
deps = pytest
pytest-cov
From 270e3cfc8f7fa1020a866a41c0f526257c7e3cb7 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sat, 3 Aug 2024 20:26:28 -0300
Subject: [PATCH 02/65] New package setup
---
Pipfile | 4 +-
Pipfile.lock | 1084 +++++++++++++++++++++-----------------
pyproject.toml | 40 +-
ruff.toml | 60 +++
setup.cfg | 2 -
setup.py | 47 --
src/vfxnaming/_vesion.py | 1 -
tox.ini | 27 +-
8 files changed, 715 insertions(+), 550 deletions(-)
create mode 100644 ruff.toml
delete mode 100644 setup.cfg
delete mode 100644 setup.py
delete mode 100644 src/vfxnaming/_vesion.py
diff --git a/Pipfile b/Pipfile
index e75e0eb..c2761b0 100644
--- a/Pipfile
+++ b/Pipfile
@@ -7,7 +7,7 @@ verify_ssl = true
pytest = "*"
pytest-cov = "*"
pytest-datafiles = "*"
-flake8 = "*"
+ruff = "*"
python-coveralls = "*"
sphinx = "*"
sphinx-rtd-theme = "*"
@@ -17,7 +17,7 @@ wheel = "*"
rstcheck = "*"
[requires]
-python_version = "3.7"
+python_version = "3.10"
[pipenv]
allow_prereleases = true
\ No newline at end of file
diff --git a/Pipfile.lock b/Pipfile.lock
index ea31088..ea221b7 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,11 +1,11 @@
{
"_meta": {
"hash": {
- "sha256": "7f657b1ac9f309c3f0915b3a048ca4c204bd37a0140370f091543a2d7c18be0f"
+ "sha256": "501c7b9e27a4ffe2d7eb6efa49188aee0841c2bf426e6d4e147b98a66087d42e"
},
"pipfile-spec": 6,
"requires": {
- "python_version": "3.7"
+ "python_version": "3.10"
},
"sources": [
{
@@ -19,132 +19,156 @@
"develop": {
"alabaster": {
"hashes": [
- "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3",
- "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"
+ "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65",
+ "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92"
],
- "markers": "python_version >= '3.6'",
- "version": "==0.7.13"
+ "markers": "python_version >= '3.9'",
+ "version": "==0.7.16"
+ },
+ "annotated-types": {
+ "hashes": [
+ "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53",
+ "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"
+ ],
+ "markers": "python_version >= '3.8'",
+ "version": "==0.7.0"
},
"babel": {
"hashes": [
- "sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610",
- "sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455"
+ "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb",
+ "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"
],
- "markers": "python_version >= '3.7'",
- "version": "==2.12.1"
+ "markers": "python_version >= '3.8'",
+ "version": "==2.15.0"
},
- "bleach": {
+ "backports.tarfile": {
"hashes": [
- "sha256:1a1a85c1595e07d8db14c5f09f09e6433502c51c595970edc090551f0db99414",
- "sha256:33c16e3353dbd13028ab4799a0f89a83f113405c766e9c122df8a06f5b85b3f4"
+ "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34",
+ "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991"
],
- "markers": "python_version >= '3.7'",
- "version": "==6.0.0"
+ "markers": "python_version < '3.12'",
+ "version": "==1.2.0"
},
"build": {
"hashes": [
- "sha256:af266720050a66c893a6096a2f410989eeac74ff9a68ba194b3f6473e8e26171",
- "sha256:d5b71264afdb5951d6704482aac78de887c80691c52b88a9ad195983ca2c9269"
+ "sha256:526263f4870c26f26c433545579475377b2b7588b6f1eac76a001e873ae3e19d",
+ "sha256:75e10f767a433d9a86e50d83f418e83efc18ede923ee5ff7df93b6cb0306c5d4"
],
"index": "pypi",
- "version": "==0.10.0"
+ "markers": "python_version >= '3.8'",
+ "version": "==1.2.1"
},
"certifi": {
"hashes": [
- "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3",
- "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"
+ "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b",
+ "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"
],
"markers": "python_version >= '3.6'",
- "version": "==2022.12.7"
+ "version": "==2024.7.4"
},
"charset-normalizer": {
"hashes": [
- "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6",
- "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1",
- "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e",
- "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373",
- "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62",
- "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230",
- "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be",
- "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c",
- "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0",
- "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448",
- "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f",
- "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649",
- "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d",
- "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0",
- "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706",
- "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a",
- "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59",
- "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23",
- "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5",
- "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb",
- "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e",
- "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e",
- "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c",
- "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28",
- "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d",
- "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41",
- "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974",
- "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce",
- "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f",
- "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1",
- "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d",
- "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8",
- "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017",
- "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31",
- "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7",
- "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8",
- "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e",
- "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14",
- "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd",
- "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d",
- "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795",
- "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b",
- "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b",
- "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b",
- "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203",
- "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f",
- "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19",
- "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1",
- "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a",
- "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac",
- "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9",
- "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0",
- "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137",
- "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f",
- "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6",
- "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5",
- "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909",
- "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f",
- "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0",
- "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324",
- "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755",
- "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb",
- "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854",
- "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c",
- "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60",
- "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84",
- "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0",
- "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b",
- "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1",
- "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531",
- "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1",
- "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11",
- "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326",
- "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df",
- "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"
+ "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027",
+ "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087",
+ "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786",
+ "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8",
+ "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09",
+ "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185",
+ "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574",
+ "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e",
+ "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519",
+ "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898",
+ "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269",
+ "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3",
+ "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f",
+ "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6",
+ "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8",
+ "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a",
+ "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73",
+ "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc",
+ "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714",
+ "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2",
+ "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc",
+ "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce",
+ "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d",
+ "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e",
+ "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6",
+ "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269",
+ "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96",
+ "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d",
+ "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a",
+ "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4",
+ "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77",
+ "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d",
+ "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0",
+ "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed",
+ "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068",
+ "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac",
+ "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25",
+ "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8",
+ "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab",
+ "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26",
+ "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2",
+ "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db",
+ "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f",
+ "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5",
+ "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99",
+ "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c",
+ "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d",
+ "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811",
+ "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa",
+ "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a",
+ "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03",
+ "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b",
+ "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04",
+ "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c",
+ "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001",
+ "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458",
+ "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389",
+ "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99",
+ "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985",
+ "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537",
+ "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238",
+ "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f",
+ "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d",
+ "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796",
+ "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a",
+ "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143",
+ "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8",
+ "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c",
+ "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5",
+ "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5",
+ "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711",
+ "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4",
+ "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6",
+ "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c",
+ "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7",
+ "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4",
+ "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b",
+ "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae",
+ "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12",
+ "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c",
+ "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae",
+ "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8",
+ "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887",
+ "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b",
+ "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4",
+ "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f",
+ "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5",
+ "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33",
+ "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519",
+ "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"
],
"markers": "python_full_version >= '3.7.0'",
- "version": "==3.1.0"
+ "version": "==3.3.2"
},
"click": {
"hashes": [
- "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e",
- "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"
+ "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28",
+ "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"
],
"markers": "python_version >= '3.7'",
- "version": "==8.1.3"
+ "version": "==8.1.7"
},
"colorama": {
"hashes": [
@@ -154,104 +178,90 @@
"markers": "os_name == 'nt'",
"version": "==0.4.6"
},
- "commonmark": {
- "hashes": [
- "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60",
- "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"
- ],
- "version": "==0.9.1"
- },
"coverage": {
"extras": [
"toml"
],
"hashes": [
- "sha256:0342a28617e63ad15d96dca0f7ae9479a37b7d8a295f749c14f3436ea59fdcb3",
- "sha256:066b44897c493e0dcbc9e6a6d9f8bbb6607ef82367cf6810d387c09f0cd4fe9a",
- "sha256:10b15394c13544fce02382360cab54e51a9e0fd1bd61ae9ce012c0d1e103c813",
- "sha256:12580845917b1e59f8a1c2ffa6af6d0908cb39220f3019e36c110c943dc875b0",
- "sha256:156192e5fd3dbbcb11cd777cc469cf010a294f4c736a2b2c891c77618cb1379a",
- "sha256:1637253b11a18f453e34013c665d8bf15904c9e3c44fbda34c643fbdc9d452cd",
- "sha256:292300f76440651529b8ceec283a9370532f4ecba9ad67d120617021bb5ef139",
- "sha256:30dcaf05adfa69c2a7b9f7dfd9f60bc8e36b282d7ed25c308ef9e114de7fc23b",
- "sha256:338aa9d9883aaaad53695cb14ccdeb36d4060485bb9388446330bef9c361c252",
- "sha256:373ea34dca98f2fdb3e5cb33d83b6d801007a8074f992b80311fc589d3e6b790",
- "sha256:38c0a497a000d50491055805313ed83ddba069353d102ece8aef5d11b5faf045",
- "sha256:40cc0f91c6cde033da493227797be2826cbf8f388eaa36a0271a97a332bfd7ce",
- "sha256:4436cc9ba5414c2c998eaedee5343f49c02ca93b21769c5fdfa4f9d799e84200",
- "sha256:509ecd8334c380000d259dc66feb191dd0a93b21f2453faa75f7f9cdcefc0718",
- "sha256:5c587f52c81211d4530fa6857884d37f514bcf9453bdeee0ff93eaaf906a5c1b",
- "sha256:5f3671662dc4b422b15776cdca89c041a6349b4864a43aa2350b6b0b03bbcc7f",
- "sha256:6599bf92f33ab041e36e06d25890afbdf12078aacfe1f1d08c713906e49a3fe5",
- "sha256:6e8a95f243d01ba572341c52f89f3acb98a3b6d1d5d830efba86033dd3687ade",
- "sha256:706ec567267c96717ab9363904d846ec009a48d5f832140b6ad08aad3791b1f5",
- "sha256:780551e47d62095e088f251f5db428473c26db7829884323e56d9c0c3118791a",
- "sha256:7ff8f3fb38233035028dbc93715551d81eadc110199e14bbbfa01c5c4a43f8d8",
- "sha256:828189fcdda99aae0d6bf718ea766b2e715eabc1868670a0a07bf8404bf58c33",
- "sha256:857abe2fa6a4973f8663e039ead8d22215d31db613ace76e4a98f52ec919068e",
- "sha256:883123d0bbe1c136f76b56276074b0c79b5817dd4238097ffa64ac67257f4b6c",
- "sha256:8877d9b437b35a85c18e3c6499b23674684bf690f5d96c1006a1ef61f9fdf0f3",
- "sha256:8e575a59315a91ccd00c7757127f6b2488c2f914096077c745c2f1ba5b8c0969",
- "sha256:97072cc90f1009386c8a5b7de9d4fc1a9f91ba5ef2146c55c1f005e7b5c5e068",
- "sha256:9a22cbb5ede6fade0482111fa7f01115ff04039795d7092ed0db43522431b4f2",
- "sha256:a063aad9f7b4c9f9da7b2550eae0a582ffc7623dca1c925e50c3fbde7a579771",
- "sha256:a08c7401d0b24e8c2982f4e307124b671c6736d40d1c39e09d7a8687bddf83ed",
- "sha256:a0b273fe6dc655b110e8dc89b8ec7f1a778d78c9fd9b4bda7c384c8906072212",
- "sha256:a2b3b05e22a77bb0ae1a3125126a4e08535961c946b62f30985535ed40e26614",
- "sha256:a66e055254a26c82aead7ff420d9fa8dc2da10c82679ea850d8feebf11074d88",
- "sha256:aa387bd7489f3e1787ff82068b295bcaafbf6f79c3dad3cbc82ef88ce3f48ad3",
- "sha256:ae453f655640157d76209f42c62c64c4d4f2c7f97256d3567e3b439bd5c9b06c",
- "sha256:b5016e331b75310610c2cf955d9f58a9749943ed5f7b8cfc0bb89c6134ab0a84",
- "sha256:b9a4ee55174b04f6af539218f9f8083140f61a46eabcaa4234f3c2a452c4ed11",
- "sha256:bd3b4b8175c1db502adf209d06136c000df4d245105c8839e9d0be71c94aefe1",
- "sha256:bebea5f5ed41f618797ce3ffb4606c64a5de92e9c3f26d26c2e0aae292f015c1",
- "sha256:c10fbc8a64aa0f3ed136b0b086b6b577bc64d67d5581acd7cc129af52654384e",
- "sha256:c2c41c1b1866b670573657d584de413df701f482574bad7e28214a2362cb1fd1",
- "sha256:cf97ed82ca986e5c637ea286ba2793c85325b30f869bf64d3009ccc1a31ae3fd",
- "sha256:d1f25ee9de21a39b3a8516f2c5feb8de248f17da7eead089c2e04aa097936b47",
- "sha256:d2fbc2a127e857d2f8898aaabcc34c37771bf78a4d5e17d3e1f5c30cd0cbc62a",
- "sha256:dc945064a8783b86fcce9a0a705abd7db2117d95e340df8a4333f00be5efb64c",
- "sha256:ddc5a54edb653e9e215f75de377354e2455376f416c4378e1d43b08ec50acc31",
- "sha256:e8834e5f17d89e05697c3c043d3e58a8b19682bf365048837383abfe39adaed5",
- "sha256:ef9659d1cda9ce9ac9585c045aaa1e59223b143f2407db0eaee0b61a4f266fb6",
- "sha256:f6f5cab2d7f0c12f8187a376cc6582c477d2df91d63f75341307fcdcb5d60303",
- "sha256:f81c9b4bd8aa747d417407a7f6f0b1469a43b36a85748145e144ac4e8d303cb5",
- "sha256:f99ef080288f09ffc687423b8d60978cf3a465d3f404a18d1a05474bd8575a47"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==7.2.5"
+ "sha256:0086cd4fc71b7d485ac93ca4239c8f75732c2ae3ba83f6be1c9be59d9e2c6382",
+ "sha256:01c322ef2bbe15057bc4bf132b525b7e3f7206f071799eb8aa6ad1940bcf5fb1",
+ "sha256:03cafe82c1b32b770a29fd6de923625ccac3185a54a5e66606da26d105f37dac",
+ "sha256:044a0985a4f25b335882b0966625270a8d9db3d3409ddc49a4eb00b0ef5e8cee",
+ "sha256:07ed352205574aad067482e53dd606926afebcb5590653121063fbf4e2175166",
+ "sha256:0d1b923fc4a40c5832be4f35a5dab0e5ff89cddf83bb4174499e02ea089daf57",
+ "sha256:0e7b27d04131c46e6894f23a4ae186a6a2207209a05df5b6ad4caee6d54a222c",
+ "sha256:1fad32ee9b27350687035cb5fdf9145bc9cf0a094a9577d43e909948ebcfa27b",
+ "sha256:289cc803fa1dc901f84701ac10c9ee873619320f2f9aff38794db4a4a0268d51",
+ "sha256:3c59105f8d58ce500f348c5b56163a4113a440dad6daa2294b5052a10db866da",
+ "sha256:46c3d091059ad0b9c59d1034de74a7f36dcfa7f6d3bde782c49deb42438f2450",
+ "sha256:482855914928c8175735a2a59c8dc5806cf7d8f032e4820d52e845d1f731dca2",
+ "sha256:49c76cdfa13015c4560702574bad67f0e15ca5a2872c6a125f6327ead2b731dd",
+ "sha256:4b03741e70fb811d1a9a1d75355cf391f274ed85847f4b78e35459899f57af4d",
+ "sha256:4bea27c4269234e06f621f3fac3925f56ff34bc14521484b8f66a580aacc2e7d",
+ "sha256:4d5fae0a22dc86259dee66f2cc6c1d3e490c4a1214d7daa2a93d07491c5c04b6",
+ "sha256:543ef9179bc55edfd895154a51792b01c017c87af0ebaae092720152e19e42ca",
+ "sha256:54dece71673b3187c86226c3ca793c5f891f9fc3d8aa183f2e3653da18566169",
+ "sha256:6379688fb4cfa921ae349c76eb1a9ab26b65f32b03d46bb0eed841fd4cb6afb1",
+ "sha256:65fa405b837060db569a61ec368b74688f429b32fa47a8929a7a2f9b47183713",
+ "sha256:6616d1c9bf1e3faea78711ee42a8b972367d82ceae233ec0ac61cc7fec09fa6b",
+ "sha256:6fe885135c8a479d3e37a7aae61cbd3a0fb2deccb4dda3c25f92a49189f766d6",
+ "sha256:7221f9ac9dad9492cecab6f676b3eaf9185141539d5c9689d13fd6b0d7de840c",
+ "sha256:76d5f82213aa78098b9b964ea89de4617e70e0d43e97900c2778a50856dac605",
+ "sha256:7792f0ab20df8071d669d929c75c97fecfa6bcab82c10ee4adb91c7a54055463",
+ "sha256:831b476d79408ab6ccfadaaf199906c833f02fdb32c9ab907b1d4aa0713cfa3b",
+ "sha256:9146579352d7b5f6412735d0f203bbd8d00113a680b66565e205bc605ef81bc6",
+ "sha256:9cc44bf0315268e253bf563f3560e6c004efe38f76db03a1558274a6e04bf5d5",
+ "sha256:a73d18625f6a8a1cbb11eadc1d03929f9510f4131879288e3f7922097a429f63",
+ "sha256:a8659fd33ee9e6ca03950cfdcdf271d645cf681609153f218826dd9805ab585c",
+ "sha256:a94925102c89247530ae1dab7dc02c690942566f22e189cbd53579b0693c0783",
+ "sha256:ad4567d6c334c46046d1c4c20024de2a1c3abc626817ae21ae3da600f5779b44",
+ "sha256:b2e16f4cd2bc4d88ba30ca2d3bbf2f21f00f382cf4e1ce3b1ddc96c634bc48ca",
+ "sha256:bbdf9a72403110a3bdae77948b8011f644571311c2fb35ee15f0f10a8fc082e8",
+ "sha256:beb08e8508e53a568811016e59f3234d29c2583f6b6e28572f0954a6b4f7e03d",
+ "sha256:c4cbe651f3904e28f3a55d6f371203049034b4ddbce65a54527a3f189ca3b390",
+ "sha256:c7b525ab52ce18c57ae232ba6f7010297a87ced82a2383b1afd238849c1ff933",
+ "sha256:ca5d79cfdae420a1d52bf177de4bc2289c321d6c961ae321503b2ca59c17ae67",
+ "sha256:cdab02a0a941af190df8782aafc591ef3ad08824f97850b015c8c6a8b3877b0b",
+ "sha256:d17c6a415d68cfe1091d3296ba5749d3d8696e42c37fca5d4860c5bf7b729f03",
+ "sha256:d39bd10f0ae453554798b125d2f39884290c480f56e8a02ba7a6ed552005243b",
+ "sha256:d4b3cd1ca7cd73d229487fa5caca9e4bc1f0bca96526b922d61053ea751fe791",
+ "sha256:d50a252b23b9b4dfeefc1f663c568a221092cbaded20a05a11665d0dbec9b8fb",
+ "sha256:da8549d17489cd52f85a9829d0e1d91059359b3c54a26f28bec2c5d369524807",
+ "sha256:dcd070b5b585b50e6617e8972f3fbbee786afca71b1936ac06257f7e178f00f6",
+ "sha256:ddaaa91bfc4477d2871442bbf30a125e8fe6b05da8a0015507bfbf4718228ab2",
+ "sha256:df423f351b162a702c053d5dddc0fc0ef9a9e27ea3f449781ace5f906b664428",
+ "sha256:dff044f661f59dace805eedb4a7404c573b6ff0cdba4a524141bc63d7be5c7fd",
+ "sha256:e7e128f85c0b419907d1f38e616c4f1e9f1d1b37a7949f44df9a73d5da5cd53c",
+ "sha256:ed8d1d1821ba5fc88d4a4f45387b65de52382fa3ef1f0115a4f7a20cdfab0e94",
+ "sha256:f2501d60d7497fd55e391f423f965bbe9e650e9ffc3c627d5f0ac516026000b8",
+ "sha256:f7db0b6ae1f96ae41afe626095149ecd1b212b424626175a6633c2999eaad45b"
+ ],
+ "markers": "python_version >= '3.8'",
+ "version": "==7.6.0"
},
"docutils": {
"hashes": [
- "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125",
- "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"
+ "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6",
+ "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
- "version": "==0.17.1"
+ "markers": "python_version >= '3.7'",
+ "version": "==0.20.1"
},
"exceptiongroup": {
"hashes": [
- "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e",
- "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"
+ "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b",
+ "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"
],
"markers": "python_version < '3.11'",
- "version": "==1.1.1"
- },
- "flake8": {
- "hashes": [
- "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db",
- "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"
- ],
- "index": "pypi",
- "version": "==5.0.4"
+ "version": "==1.2.2"
},
"idna": {
"hashes": [
- "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4",
- "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"
+ "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc",
+ "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"
],
"markers": "python_version >= '3.5'",
- "version": "==3.4"
+ "version": "==3.7"
},
"imagesize": {
"hashes": [
@@ -263,11 +273,11 @@
},
"importlib-metadata": {
"hashes": [
- "sha256:057e92c15bc8d9e8109738a48db0ccb31b4d9d5cfbee5a8670879a30be66304b",
- "sha256:b7e52a1f8dec14a75ea73e0891f3060099ca1d8e6a462a4dff11c3e119ea1b31"
+ "sha256:11901fa0c2f97919b288679932bb64febaeacf289d18ac84dd68cb2e74213369",
+ "sha256:72e8d4399996132204f9a16dcc751af254a48f8d1b20b9ff0f98d4a8f901e73d"
],
- "markers": "python_version < '3.8'",
- "version": "==4.2.0"
+ "markers": "python_version >= '3.8'",
+ "version": "==8.2.0"
},
"iniconfig": {
"hashes": [
@@ -279,213 +289,315 @@
},
"jaraco.classes": {
"hashes": [
- "sha256:2353de3288bc6b82120752201c6b1c1a14b058267fa424ed5ce5984e3b922158",
- "sha256:89559fa5c1d3c34eff6f631ad80bb21f378dbcbb35dd161fd2c6b93f5be2f98a"
+ "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd",
+ "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790"
],
- "markers": "python_version >= '3.7'",
- "version": "==3.2.3"
+ "markers": "python_version >= '3.8'",
+ "version": "==3.4.0"
+ },
+ "jaraco.context": {
+ "hashes": [
+ "sha256:3e16388f7da43d384a1a7cd3452e72e14732ac9fe459678773a3608a812bf266",
+ "sha256:c2f67165ce1f9be20f32f650f25d8edfc1646a8aeee48ae06fb35f90763576d2"
+ ],
+ "markers": "python_version >= '3.8'",
+ "version": "==5.3.0"
+ },
+ "jaraco.functools": {
+ "hashes": [
+ "sha256:3460c74cd0d32bf82b9576bbb3527c4364d5b27a21f5158a62aed6c4b42e23f5",
+ "sha256:c9d16a3ed4ccb5a889ad8e0b7a343401ee5b2a71cee6ed192d3f68bc351e94e3"
+ ],
+ "markers": "python_version >= '3.8'",
+ "version": "==4.0.2"
},
"jinja2": {
"hashes": [
- "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852",
- "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"
+ "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369",
+ "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"
],
"markers": "python_version >= '3.7'",
- "version": "==3.1.2"
+ "version": "==3.1.4"
},
"keyring": {
"hashes": [
- "sha256:69732a15cb1433bdfbc3b980a8a36a04878a6cfd7cb99f497b573f31618001c0",
- "sha256:69b01dd83c42f590250fe7a1f503fc229b14de83857314b1933a3ddbf595c4a5"
+ "sha256:8d85a1ea5d6db8515b59e1c5d1d1678b03cf7fc8b8dcfb1651e8c4a524eb42ef",
+ "sha256:8d963da00ccdf06e356acd9bf3b743208878751032d8599c6cc89eb51310ffae"
],
- "markers": "python_version >= '3.7'",
- "version": "==23.9.3"
+ "markers": "python_version >= '3.8'",
+ "version": "==25.3.0"
+ },
+ "markdown-it-py": {
+ "hashes": [
+ "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1",
+ "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"
+ ],
+ "markers": "python_version >= '3.8'",
+ "version": "==3.0.0"
},
"markupsafe": {
"hashes": [
- "sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed",
- "sha256:085fd3201e7b12809f9e6e9bc1e5c96a368c8523fad5afb02afe3c051ae4afcc",
- "sha256:090376d812fb6ac5f171e5938e82e7f2d7adc2b629101cec0db8b267815c85e2",
- "sha256:0b462104ba25f1ac006fdab8b6a01ebbfbce9ed37fd37fd4acd70c67c973e460",
- "sha256:137678c63c977754abe9086a3ec011e8fd985ab90631145dfb9294ad09c102a7",
- "sha256:1bea30e9bf331f3fef67e0a3877b2288593c98a21ccb2cf29b74c581a4eb3af0",
- "sha256:22152d00bf4a9c7c83960521fc558f55a1adbc0631fbb00a9471e097b19d72e1",
- "sha256:22731d79ed2eb25059ae3df1dfc9cb1546691cc41f4e3130fe6bfbc3ecbbecfa",
- "sha256:2298c859cfc5463f1b64bd55cb3e602528db6fa0f3cfd568d3605c50678f8f03",
- "sha256:28057e985dace2f478e042eaa15606c7efccb700797660629da387eb289b9323",
- "sha256:2e7821bffe00aa6bd07a23913b7f4e01328c3d5cc0b40b36c0bd81d362faeb65",
- "sha256:2ec4f2d48ae59bbb9d1f9d7efb9236ab81429a764dedca114f5fdabbc3788013",
- "sha256:340bea174e9761308703ae988e982005aedf427de816d1afe98147668cc03036",
- "sha256:40627dcf047dadb22cd25ea7ecfe9cbf3bbbad0482ee5920b582f3809c97654f",
- "sha256:40dfd3fefbef579ee058f139733ac336312663c6706d1163b82b3003fb1925c4",
- "sha256:4cf06cdc1dda95223e9d2d3c58d3b178aa5dacb35ee7e3bbac10e4e1faacb419",
- "sha256:50c42830a633fa0cf9e7d27664637532791bfc31c731a87b202d2d8ac40c3ea2",
- "sha256:55f44b440d491028addb3b88f72207d71eeebfb7b5dbf0643f7c023ae1fba619",
- "sha256:608e7073dfa9e38a85d38474c082d4281f4ce276ac0010224eaba11e929dd53a",
- "sha256:63ba06c9941e46fa389d389644e2d8225e0e3e5ebcc4ff1ea8506dce646f8c8a",
- "sha256:65608c35bfb8a76763f37036547f7adfd09270fbdbf96608be2bead319728fcd",
- "sha256:665a36ae6f8f20a4676b53224e33d456a6f5a72657d9c83c2aa00765072f31f7",
- "sha256:6d6607f98fcf17e534162f0709aaad3ab7a96032723d8ac8750ffe17ae5a0666",
- "sha256:7313ce6a199651c4ed9d7e4cfb4aa56fe923b1adf9af3b420ee14e6d9a73df65",
- "sha256:7668b52e102d0ed87cb082380a7e2e1e78737ddecdde129acadb0eccc5423859",
- "sha256:7df70907e00c970c60b9ef2938d894a9381f38e6b9db73c5be35e59d92e06625",
- "sha256:7e007132af78ea9df29495dbf7b5824cb71648d7133cf7848a2a5dd00d36f9ff",
- "sha256:835fb5e38fd89328e9c81067fd642b3593c33e1e17e2fdbf77f5676abb14a156",
- "sha256:8bca7e26c1dd751236cfb0c6c72d4ad61d986e9a41bbf76cb445f69488b2a2bd",
- "sha256:8db032bf0ce9022a8e41a22598eefc802314e81b879ae093f36ce9ddf39ab1ba",
- "sha256:99625a92da8229df6d44335e6fcc558a5037dd0a760e11d84be2260e6f37002f",
- "sha256:9cad97ab29dfc3f0249b483412c85c8ef4766d96cdf9dcf5a1e3caa3f3661cf1",
- "sha256:a4abaec6ca3ad8660690236d11bfe28dfd707778e2442b45addd2f086d6ef094",
- "sha256:a6e40afa7f45939ca356f348c8e23048e02cb109ced1eb8420961b2f40fb373a",
- "sha256:a6f2fcca746e8d5910e18782f976489939d54a91f9411c32051b4aab2bd7c513",
- "sha256:a806db027852538d2ad7555b203300173dd1b77ba116de92da9afbc3a3be3eed",
- "sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d",
- "sha256:b8526c6d437855442cdd3d87eede9c425c4445ea011ca38d937db299382e6fa3",
- "sha256:bb06feb762bade6bf3c8b844462274db0c76acc95c52abe8dbed28ae3d44a147",
- "sha256:c0a33bc9f02c2b17c3ea382f91b4db0e6cde90b63b296422a939886a7a80de1c",
- "sha256:c4a549890a45f57f1ebf99c067a4ad0cb423a05544accaf2b065246827ed9603",
- "sha256:ca244fa73f50a800cf8c3ebf7fd93149ec37f5cb9596aa8873ae2c1d23498601",
- "sha256:cf877ab4ed6e302ec1d04952ca358b381a882fbd9d1b07cccbfd61783561f98a",
- "sha256:d9d971ec1e79906046aa3ca266de79eac42f1dbf3612a05dc9368125952bd1a1",
- "sha256:da25303d91526aac3672ee6d49a2f3db2d9502a4a60b55519feb1a4c7714e07d",
- "sha256:e55e40ff0cc8cc5c07996915ad367fa47da6b3fc091fdadca7f5403239c5fec3",
- "sha256:f03a532d7dee1bed20bc4884194a16160a2de9ffc6354b3878ec9682bb623c54",
- "sha256:f1cd098434e83e656abf198f103a8207a8187c0fc110306691a2e94a78d0abb2",
- "sha256:f2bfb563d0211ce16b63c7cb9395d2c682a23187f54c3d79bfec33e6705473c6",
- "sha256:f8ffb705ffcf5ddd0e80b65ddf7bed7ee4f5a441ea7d3419e861a12eaf41af58"
+ "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf",
+ "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff",
+ "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f",
+ "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3",
+ "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532",
+ "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f",
+ "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617",
+ "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df",
+ "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4",
+ "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906",
+ "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f",
+ "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4",
+ "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8",
+ "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371",
+ "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2",
+ "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465",
+ "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52",
+ "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6",
+ "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169",
+ "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad",
+ "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2",
+ "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0",
+ "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029",
+ "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f",
+ "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a",
+ "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced",
+ "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5",
+ "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c",
+ "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf",
+ "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9",
+ "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb",
+ "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad",
+ "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3",
+ "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1",
+ "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46",
+ "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc",
+ "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a",
+ "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee",
+ "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900",
+ "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5",
+ "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea",
+ "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f",
+ "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5",
+ "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e",
+ "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a",
+ "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f",
+ "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50",
+ "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a",
+ "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b",
+ "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4",
+ "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff",
+ "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2",
+ "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46",
+ "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b",
+ "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf",
+ "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5",
+ "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5",
+ "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab",
+ "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd",
+ "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"
],
"markers": "python_version >= '3.7'",
- "version": "==2.1.2"
+ "version": "==2.1.5"
},
- "mccabe": {
+ "mdurl": {
"hashes": [
- "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325",
- "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"
+ "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8",
+ "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"
],
- "markers": "python_version >= '3.6'",
- "version": "==0.7.0"
+ "markers": "python_version >= '3.7'",
+ "version": "==0.1.2"
},
"more-itertools": {
"hashes": [
- "sha256:cabaa341ad0389ea83c17a94566a53ae4c9d07349861ecb14dc6d0345cf9ac5d",
- "sha256:d2bc7f02446e86a68911e58ded76d6561eea00cddfb2a91e7019bbb586c799f3"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==9.1.0"
+ "sha256:e5d93ef411224fbcef366a6e8ddc4c5781bc6359d43412a65dd5964e46111463",
+ "sha256:ea6a02e24a9161e51faad17a8782b92a0df82c12c1c8886fec7f0c3fa1a1b320"
+ ],
+ "markers": "python_version >= '3.8'",
+ "version": "==10.3.0"
+ },
+ "nh3": {
+ "hashes": [
+ "sha256:0411beb0589eacb6734f28d5497ca2ed379eafab8ad8c84b31bb5c34072b7164",
+ "sha256:14c5a72e9fe82aea5fe3072116ad4661af5cf8e8ff8fc5ad3450f123e4925e86",
+ "sha256:19aaba96e0f795bd0a6c56291495ff59364f4300d4a39b29a0abc9cb3774a84b",
+ "sha256:34c03fa78e328c691f982b7c03d4423bdfd7da69cd707fe572f544cf74ac23ad",
+ "sha256:36c95d4b70530b320b365659bb5034341316e6a9b30f0b25fa9c9eff4c27a204",
+ "sha256:3a157ab149e591bb638a55c8c6bcb8cdb559c8b12c13a8affaba6cedfe51713a",
+ "sha256:42c64511469005058cd17cc1537578eac40ae9f7200bedcfd1fc1a05f4f8c200",
+ "sha256:5f36b271dae35c465ef5e9090e1fdaba4a60a56f0bb0ba03e0932a66f28b9189",
+ "sha256:6955369e4d9f48f41e3f238a9e60f9410645db7e07435e62c6a9ea6135a4907f",
+ "sha256:7b7c2a3c9eb1a827d42539aa64091640bd275b81e097cd1d8d82ef91ffa2e811",
+ "sha256:8ce0f819d2f1933953fca255db2471ad58184a60508f03e6285e5114b6254844",
+ "sha256:94a166927e53972a9698af9542ace4e38b9de50c34352b962f4d9a7d4c927af4",
+ "sha256:a7f1b5b2c15866f2db413a3649a8fe4fd7b428ae58be2c0f6bca5eefd53ca2be",
+ "sha256:c8b3a1cebcba9b3669ed1a84cc65bf005728d2f0bc1ed2a6594a992e817f3a50",
+ "sha256:de3ceed6e661954871d6cd78b410213bdcb136f79aafe22aa7182e028b8c7307",
+ "sha256:f0eca9ca8628dbb4e916ae2491d72957fdd35f7a5d326b7032a345f111ac07fe"
+ ],
+ "version": "==0.2.18"
},
"packaging": {
"hashes": [
- "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61",
- "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"
+ "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002",
+ "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"
],
- "markers": "python_version >= '3.7'",
- "version": "==23.1"
+ "markers": "python_version >= '3.8'",
+ "version": "==24.1"
},
"pkginfo": {
"hashes": [
- "sha256:4b7a555a6d5a22169fcc9cf7bfd78d296b0361adad412a346c1226849af5e546",
- "sha256:8fd5896e8718a4372f0ea9cc9d96f6417c9b986e23a4d116dda26b62cc29d046"
+ "sha256:5df73835398d10db79f8eecd5cd86b1f6d29317589ea70796994d49399af6297",
+ "sha256:889a6da2ed7ffc58ab5b900d888ddce90bce912f2d2de1dc1c26f4cb9fe65097"
],
"markers": "python_version >= '3.6'",
- "version": "==1.9.6"
+ "version": "==1.10.0"
},
"pluggy": {
"hashes": [
- "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159",
- "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"
+ "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1",
+ "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"
],
- "markers": "python_version >= '3.6'",
- "version": "==1.0.0"
- },
- "pycodestyle": {
- "hashes": [
- "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785",
- "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==2.9.1"
+ "markers": "python_version >= '3.8'",
+ "version": "==1.5.0"
},
"pydantic": {
"hashes": [
- "sha256:01aea3a42c13f2602b7ecbbea484a98169fb568ebd9e247593ea05f01b884b2e",
- "sha256:0cd181f1d0b1d00e2b705f1bf1ac7799a2d938cce3376b8007df62b29be3c2c6",
- "sha256:10a86d8c8db68086f1e30a530f7d5f83eb0685e632e411dbbcf2d5c0150e8dcd",
- "sha256:193924c563fae6ddcb71d3f06fa153866423ac1b793a47936656e806b64e24ca",
- "sha256:464855a7ff7f2cc2cf537ecc421291b9132aa9c79aef44e917ad711b4a93163b",
- "sha256:516f1ed9bc2406a0467dd777afc636c7091d71f214d5e413d64fef45174cfc7a",
- "sha256:6434b49c0b03a51021ade5c4daa7d70c98f7a79e95b551201fff682fc1661245",
- "sha256:64d34ab766fa056df49013bb6e79921a0265204c071984e75a09cbceacbbdd5d",
- "sha256:670bb4683ad1e48b0ecb06f0cfe2178dcf74ff27921cdf1606e527d2617a81ee",
- "sha256:68792151e174a4aa9e9fc1b4e653e65a354a2fa0fed169f7b3d09902ad2cb6f1",
- "sha256:701daea9ffe9d26f97b52f1d157e0d4121644f0fcf80b443248434958fd03dc3",
- "sha256:7d45fc99d64af9aaf7e308054a0067fdcd87ffe974f2442312372dfa66e1001d",
- "sha256:80b1fab4deb08a8292d15e43a6edccdffa5377a36a4597bb545b93e79c5ff0a5",
- "sha256:82dffb306dd20bd5268fd6379bc4bfe75242a9c2b79fec58e1041fbbdb1f7914",
- "sha256:8c7f51861d73e8b9ddcb9916ae7ac39fb52761d9ea0df41128e81e2ba42886cd",
- "sha256:950ce33857841f9a337ce07ddf46bc84e1c4946d2a3bba18f8280297157a3fd1",
- "sha256:976cae77ba6a49d80f461fd8bba183ff7ba79f44aa5cfa82f1346b5626542f8e",
- "sha256:9f6f0fd68d73257ad6685419478c5aece46432f4bdd8d32c7345f1986496171e",
- "sha256:a7cd2251439988b413cb0a985c4ed82b6c6aac382dbaff53ae03c4b23a70e80a",
- "sha256:abfb7d4a7cd5cc4e1d1887c43503a7c5dd608eadf8bc615413fc498d3e4645cd",
- "sha256:ae150a63564929c675d7f2303008d88426a0add46efd76c3fc797cd71cb1b46f",
- "sha256:b0f85904f73161817b80781cc150f8b906d521fa11e3cdabae19a581c3606209",
- "sha256:b4a849d10f211389502059c33332e91327bc154acc1845f375a99eca3afa802d",
- "sha256:c15582f9055fbc1bfe50266a19771bbbef33dd28c45e78afbe1996fd70966c2a",
- "sha256:c230c0d8a322276d6e7b88c3f7ce885f9ed16e0910354510e0bae84d54991143",
- "sha256:cc1dde4e50a5fc1336ee0581c1612215bc64ed6d28d2c7c6f25d2fe3e7c3e918",
- "sha256:cf135c46099ff3f919d2150a948ce94b9ce545598ef2c6c7bf55dca98a304b52",
- "sha256:cfc83c0678b6ba51b0532bea66860617c4cd4251ecf76e9846fa5a9f3454e97e",
- "sha256:d2a5ebb48958754d386195fe9e9c5106f11275867051bf017a8059410e9abf1f",
- "sha256:d71e69699498b020ea198468e2480a2f1e7433e32a3a99760058c6520e2bea7e",
- "sha256:d75ae19d2a3dbb146b6f324031c24f8a3f52ff5d6a9f22f0683694b3afcb16fb",
- "sha256:dfe2507b8ef209da71b6fb5f4e597b50c5a34b78d7e857c4f8f3115effaef5fe",
- "sha256:e0cfe895a504c060e5d36b287ee696e2fdad02d89e0d895f83037245218a87fe",
- "sha256:e79e999e539872e903767c417c897e729e015872040e56b96e67968c3b918b2d",
- "sha256:ecbbc51391248116c0a055899e6c3e7ffbb11fb5e2a4cd6f2d0b93272118a209",
- "sha256:f4a2b50e2b03d5776e7f21af73e2070e1b5c0d0df255a827e7c632962f8315af"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==1.10.7"
- },
- "pyflakes": {
- "hashes": [
- "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2",
- "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==2.5.0"
+ "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a",
+ "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8"
+ ],
+ "markers": "python_version >= '3.8'",
+ "version": "==2.8.2"
+ },
+ "pydantic-core": {
+ "hashes": [
+ "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d",
+ "sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f",
+ "sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686",
+ "sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482",
+ "sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006",
+ "sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83",
+ "sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6",
+ "sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88",
+ "sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86",
+ "sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a",
+ "sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6",
+ "sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a",
+ "sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6",
+ "sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6",
+ "sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43",
+ "sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c",
+ "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4",
+ "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e",
+ "sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203",
+ "sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd",
+ "sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1",
+ "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24",
+ "sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc",
+ "sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc",
+ "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3",
+ "sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598",
+ "sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98",
+ "sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331",
+ "sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2",
+ "sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a",
+ "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6",
+ "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688",
+ "sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91",
+ "sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa",
+ "sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b",
+ "sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0",
+ "sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840",
+ "sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c",
+ "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd",
+ "sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3",
+ "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231",
+ "sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1",
+ "sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953",
+ "sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250",
+ "sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a",
+ "sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2",
+ "sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20",
+ "sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434",
+ "sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab",
+ "sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703",
+ "sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a",
+ "sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2",
+ "sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac",
+ "sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611",
+ "sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121",
+ "sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e",
+ "sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b",
+ "sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09",
+ "sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906",
+ "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9",
+ "sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7",
+ "sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b",
+ "sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987",
+ "sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c",
+ "sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b",
+ "sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e",
+ "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237",
+ "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1",
+ "sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19",
+ "sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b",
+ "sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad",
+ "sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0",
+ "sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94",
+ "sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312",
+ "sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f",
+ "sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669",
+ "sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1",
+ "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe",
+ "sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99",
+ "sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a",
+ "sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a",
+ "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52",
+ "sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c",
+ "sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad",
+ "sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1",
+ "sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a",
+ "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f",
+ "sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a",
+ "sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27"
+ ],
+ "markers": "python_version >= '3.8'",
+ "version": "==2.20.1"
},
"pygments": {
"hashes": [
- "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c",
- "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"
+ "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199",
+ "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"
],
- "markers": "python_version >= '3.7'",
- "version": "==2.15.1"
+ "markers": "python_version >= '3.8'",
+ "version": "==2.18.0"
},
"pyproject-hooks": {
"hashes": [
- "sha256:283c11acd6b928d2f6a7c73fa0d01cb2bdc5f07c57a2eeb6e83d5e56b97976f8",
- "sha256:f271b298b97f5955d53fb12b72c1fb1948c22c1a6b70b315c54cedaca0264ef5"
+ "sha256:4b37730834edbd6bd37f26ece6b44802fb1c1ee2ece0e54ddff8bfc06db86965",
+ "sha256:7ceeefe9aec63a1064c18d939bdc3adf2d8aa1988a510afec15151578b232aa2"
],
"markers": "python_version >= '3.7'",
- "version": "==1.0.0"
+ "version": "==1.1.0"
},
"pytest": {
"hashes": [
- "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362",
- "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"
+ "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5",
+ "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"
],
"index": "pypi",
- "version": "==7.3.1"
+ "markers": "python_version >= '3.8'",
+ "version": "==8.3.2"
},
"pytest-cov": {
"hashes": [
- "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b",
- "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"
+ "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652",
+ "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"
],
"index": "pypi",
- "version": "==4.0.0"
+ "markers": "python_version >= '3.8'",
+ "version": "==5.0.0"
},
"pytest-datafiles": {
"hashes": [
@@ -503,83 +615,88 @@
"index": "pypi",
"version": "==2.9.3"
},
- "pytz": {
- "hashes": [
- "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588",
- "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"
- ],
- "markers": "python_version < '3.9'",
- "version": "==2023.3"
- },
"pywin32-ctypes": {
"hashes": [
- "sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942",
- "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"
+ "sha256:3426e063bdd5fd4df74a14fa3cf80a0b42845a87e1d1e81f6549f9daec593a60",
+ "sha256:bf490a1a709baf35d688fe0ecf980ed4de11d2b3e37b51e5442587a75d9957e7"
],
"markers": "sys_platform == 'win32'",
- "version": "==0.2.0"
+ "version": "==0.2.2"
},
"pyyaml": {
"hashes": [
- "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf",
- "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293",
- "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b",
- "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57",
- "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b",
- "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4",
- "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07",
- "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba",
- "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9",
- "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287",
- "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513",
- "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0",
- "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782",
- "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0",
- "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92",
- "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f",
- "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2",
- "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc",
- "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1",
- "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c",
- "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86",
- "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4",
- "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c",
- "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34",
- "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b",
- "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d",
- "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c",
- "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb",
- "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7",
- "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737",
- "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3",
- "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d",
- "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358",
- "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53",
- "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78",
- "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803",
- "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a",
- "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f",
- "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174",
- "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"
+ "sha256:0101357af42f5c9fc7e9acc5c5ab8c3049f50db7425de175b6c7a5959cb6023d",
+ "sha256:0ae563b7e3ed5e918cd0184060e28b48b7e672b975bf7c6f4a892cee9d886ada",
+ "sha256:0fe2c1c5401a3a98f06337fed48f57340cf652a685484834b44f5ceeadb772ba",
+ "sha256:1eb00dd3344da80264261ab126c95481824669ed9e5ecc82fb2d88b1fce668ee",
+ "sha256:2086b30215c433c1e480c08c1db8b43c1edd36c59cf43d36b424e6f35fcaf1ad",
+ "sha256:29b4a67915232f79506211e69943e3102e211c616181ceff0adf34e21b469357",
+ "sha256:2e9bc8a34797f0621f56160b961d47a088644370f79d34bedc934fb89e3f47dd",
+ "sha256:30ec6b9afc17353a9abcff109880edf6e8d5b924eb1eeed7fe9376febc1f9800",
+ "sha256:31573d7e161d2f905311f036b12e65c058389b474dbd35740f4880b91e2ca2be",
+ "sha256:36d7bf63558843ea2a81de9d0c3e9c56c353b1df8e6c1faaec86df5adedf2e02",
+ "sha256:3af6b36bc195d741cd5b511810246cad143b99c953b4591e679e194a820d7b7c",
+ "sha256:414629800a1ddccd7303471650843fc801801cc579a195d2fe617b5b455409e3",
+ "sha256:459113f2b9cd68881201a3bd1a858ece3281dc0e92ece6e917d23b128f0fcb31",
+ "sha256:46e4fae38d00b40a62d32d60f1baa1b9ef33aff28c2aafd96b05d5cc770f1583",
+ "sha256:4bf821ccd51e8d5bc1a4021b8bd85a92b498832ac1cd1a53b399f0eb7c1c4258",
+ "sha256:50bd6560a6df3de59336b9a9086cbdea5aa9eee5361661448ee45c21eeb0da68",
+ "sha256:53056b51f111223e603bed1db5367f54596d44cacfa50f07e082a11929612957",
+ "sha256:53c5f0749a93e3296078262c9acf632de246241ff2f22bbedfe49d4b55e9bbdd",
+ "sha256:54c754cee6937bb9b72d6a16163160dec80b93a43020ac6fc9f13729c030c30b",
+ "sha256:58cc18ccbade0c48fb55102aa971a5b4e571e2b22187d083dda33f8708fa4ee7",
+ "sha256:5921fd128fbf27ab7c7ad1a566d2cd9557b84ade130743a7c110a55e7dec3b3c",
+ "sha256:5c758cc29713c9166750a30156ca3d90ac2515d5dea3c874377ae8829cf03087",
+ "sha256:60bf91e73354c96754220a9c04a9502c2ad063231cd754b59f8e4511157e32e2",
+ "sha256:6f0f728a88c6eb58a3b762726b965bb6acf12d97f8ea2cb4fecf856a727f9bdc",
+ "sha256:6f31c5935310da69ea0efe996a962d488f080312f0eb43beff1717acb5fe9bed",
+ "sha256:728b447d0cedec409ea1a3f0ad1a6cc3cec0a8d086611b45f038a9230a2242f3",
+ "sha256:72ffbc5c0cc71877104387548a450f2b7b7c4926b40dc9443e7598fe92aa13d9",
+ "sha256:73d8b233309ecd45c33c51cd55aa1be1dcab1799a9e54f6c753d8cab054b8c34",
+ "sha256:765029d1cf96e9e761329ee1c20f1ca2de8644e7350a151b198260698b96e30f",
+ "sha256:7ee3d180d886a3bc50f753b76340f1c314f9e8c507f5b107212112214c3a66fd",
+ "sha256:826fb4d5ac2c48b9d6e71423def2669d4646c93b6c13612a71b3ac7bb345304b",
+ "sha256:84c39ceec517cd8f01cb144efb08904a32050be51c55b7a59bc7958c8091568d",
+ "sha256:88bfe675bb19ae12a9c77c52322a28a8e2a8d3d213fbcfcded5c3f5ca3ead352",
+ "sha256:8e0a1ebd5c5842595365bf90db3ef7e9a8d6a79c9aedb1d05b675c81c7267fd3",
+ "sha256:9426067a10b369474396bf57fdf895b899045a25d1848798844693780b147436",
+ "sha256:9c5c0de7ec50d4df88b62f4b019ab7b3bb2883c826a1044268e9afb344c57b17",
+ "sha256:ad0c172fe15beffc32e3a8260f18e6708eb0e15ae82c9b3f80fbe04de0ef5729",
+ "sha256:ad206c7f5f08d393b872d3399f597246fdc6ebebff09c5ae5268ac45aebf4f8d",
+ "sha256:b0a163f4f84d1e0fe6a07ccad3b02e9b243790b8370ff0408ae5932c50c4d96d",
+ "sha256:b0dd9c7497d60126445e79e542ff01351c6b6dc121299d89787f5685b382c626",
+ "sha256:b1de10c488d6f02e498eb6956b89081bea31abf3133223c17749e7137734da75",
+ "sha256:b408f36eeb4e2be6f802f1be82daf1b578f3de5a51917c6e467aedb46187d827",
+ "sha256:bae077a01367e4bf5fddf00fd6c8b743e676385911c7c615e29e1c45ace8813b",
+ "sha256:bc3c3600fec6c2a719106381d6282061d8c108369cdec58b6f280610eba41e09",
+ "sha256:c16522bf91daa4ea9dedc1243b56b5a226357ab98b3133089ca627ef99baae6f",
+ "sha256:ca5136a77e2d64b4cf5106fb940376650ae232c74c09a8ff29dbb1e262495b31",
+ "sha256:d6e0f7ee5f8d851b1d91149a3e5074dbf5aacbb63e4b771fcce16508339a856f",
+ "sha256:e7930a0612e74fcca37019ca851b50d73b5f0c3dab7f3085a7c15d2026118315",
+ "sha256:e8e6dd230a158a836cda3cc521fcbedea16f22b16b8cfa8054d0c6cea5d0a531",
+ "sha256:eee36bf4bc11e39e3f17c171f25cdedff3d7c73b148aedc8820257ce2aa56d3b",
+ "sha256:f07adc282d51aaa528f3141ac1922d16d32fe89413ee59bfb8a73ed689ad3d23",
+ "sha256:f09816c047fdb588dddba53d321f1cb8081e38ad2a40ea6a7560a88b7a2f0ea8",
+ "sha256:fea4c4310061cd70ef73b39801231b9dc3dc638bb8858e38364b144fbd335a1a"
],
"markers": "python_version >= '3.6'",
- "version": "==6.0"
+ "version": "==6.0.2rc1"
},
"readme-renderer": {
"hashes": [
- "sha256:cd653186dfc73055656f090f227f5cb22a046d7f71a841dfa305f55c9a513273",
- "sha256:f67a16caedfa71eef48a31b39708637a6f4664c4394801a7b0d6432d13907343"
+ "sha256:1818dd28140813509eeed8d62687f7cd4f7bad90d4db586001c5dc09d4fde311",
+ "sha256:19db308d86ecd60e5affa3b2a98f017af384678c63c88e5d4556a380e674f3f9"
],
- "markers": "python_version >= '3.7'",
- "version": "==37.3"
+ "markers": "python_version >= '3.8'",
+ "version": "==43.0"
},
"requests": {
"hashes": [
- "sha256:10e94cc4f3121ee6da529d358cdaeaff2f1c409cd377dbc72b825852f2f7e294",
- "sha256:239d7d4458afcb28a692cdd298d87542235f4ca8d36d03a15bfc128a6559a2f4"
+ "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760",
+ "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"
],
- "markers": "python_version >= '3.7'",
- "version": "==2.30.0"
+ "markers": "python_version >= '3.8'",
+ "version": "==2.32.3"
},
"requests-toolbelt": {
"hashes": [
@@ -599,49 +716,68 @@
},
"rich": {
"hashes": [
- "sha256:a4eb26484f2c82589bd9a17c73d32a010b1e29d89f1604cd9bf3a2097b81bb5e",
- "sha256:ba3a3775974105c221d31141f2c116f4fd65c5ceb0698657a11e9f295ec93fd0"
+ "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222",
+ "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"
],
- "markers": "python_full_version >= '3.6.3' and python_full_version < '4.0.0'",
- "version": "==12.6.0"
+ "markers": "python_full_version >= '3.7.0'",
+ "version": "==13.7.1"
},
"rstcheck": {
"hashes": [
- "sha256:4aaa46e0debc179f849807c453fa384fd2b75167faf5b1274115730805fab529",
- "sha256:f9cb07a72ef9a81d1e32187eae29b00a89421ccba1bde0b1652a08ed0923f61b"
+ "sha256:23de2575ba0af1adcddea87a20d69187f0fb9dd8270f59eb98d63461c95375a7",
+ "sha256:384942563dfbfcc85903a587ecf050447217c46b51e266ed3fe51371bc599015"
],
"index": "pypi",
- "version": "==6.1.2"
+ "markers": "python_version >= '3.8'",
+ "version": "==6.2.4"
},
"rstcheck-core": {
"hashes": [
- "sha256:add19c9a1b97d9087f4b463b49c12cd8a9c03689a255e99089c70a2692f16369",
- "sha256:d75d7df8f15b58e8aafe322d6fb6ef1ac8d12bb563089b0696948a00ee7f601a"
- ],
- "markers": "python_version >= '3.7' and python_version < '4.0'",
- "version": "==1.0.3"
- },
- "setuptools": {
- "hashes": [
- "sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b",
- "sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990"
+ "sha256:1c100de418b6c9e14d9cf6558644d0ab103fdc447f891313882d02df3a3c52ba",
+ "sha256:9b330020d912e2864f23f332c1a0569463ca3b06b8fee7b7bdd201b055f7f831"
+ ],
+ "markers": "python_version >= '3.8'",
+ "version": "==1.2.1"
+ },
+ "ruff": {
+ "hashes": [
+ "sha256:07c9e3c2a8e1fe377dd460371c3462671a728c981c3205a5217291422209f642",
+ "sha256:111a99cdb02f69ddb2571e2756e017a1496c2c3a2aeefe7b988ddab38b416d36",
+ "sha256:1f77c1c3aa0669fb230b06fb24ffa3e879391a3ba3f15e3d633a752da5a3e670",
+ "sha256:4d394940f61f7720ad371ddedf14722ee1d6250fd8d020f5ea5a86e7be217daf",
+ "sha256:563a7ae61ad284187d3071d9041c08019975693ff655438d8d4be26e492760bd",
+ "sha256:57c6c0dd997b31b536bff49b9eee5ed3194d60605a4427f735eeb1f9c1b8d264",
+ "sha256:80521b88d26a45e871f31e4b88938fd87db7011bb961d8afd2664982dfc3641a",
+ "sha256:94fe60869bfbf0521e04fd62b74cbca21cbc5beb67cbb75ab33fe8c174f54414",
+ "sha256:a0ef5930799a05522985b9cec8290b185952f3fcd86c1772c3bdbd732667fdcd",
+ "sha256:b652dc14f6ef5d1552821e006f747802cc32d98d5509349e168f6bf0ee9f8f42",
+ "sha256:c476acb43c3c51e3c614a2e878ee1589655fa02dab19fe2db0423a06d6a5b1b6",
+ "sha256:c94e084ba3eaa80c2172918c2ca2eb2230c3f15925f4ed8b6297260c6ef179ad",
+ "sha256:d7fe7dccb1a89dc66785d7aa0ac283b2269712d8ed19c63af908fdccca5ccc1a",
+ "sha256:d9bc8f328a9f1309ae80e4d392836e7dbc77303b38ed4a7112699e63d3b066ab",
+ "sha256:e2ff8003f5252fd68425fd53d27c1f08b201d7ed714bb31a55c9ac1d4c13e2eb",
+ "sha256:e395daba77a79f6dc0d07311f94cc0560375ca20c06f354c7c99af3bf4560c5d",
+ "sha256:e6a584c1de6f8591c2570e171cc7ce482bb983d49c70ddf014393cd39e9dfaed",
+ "sha256:f908148c93c02873210a52cad75a6eda856b2cbb72250370ce3afef6fb99b1ed"
],
+ "index": "pypi",
"markers": "python_version >= '3.7'",
- "version": "==67.7.2"
+ "version": "==0.5.6"
},
"shellingham": {
"hashes": [
- "sha256:368bf8c00754fd4f55afb7bbb86e272df77e4dc76ac29dbcbb81a59e9fc15744",
- "sha256:823bc5fb5c34d60f285b624e7264f4dda254bc803a3774a147bf99c0e3004a28"
+ "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686",
+ "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"
],
- "version": "==1.5.0.post1"
+ "markers": "python_version >= '3.7'",
+ "version": "==1.5.4"
},
"six": {
"hashes": [
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
+ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.16.0"
},
"snowballstemmer": {
@@ -653,50 +789,52 @@
},
"sphinx": {
"hashes": [
- "sha256:0a8836751a68306b3fe97ecbe44db786f8479c3bf4b80e3a7f5c838657b4698c",
- "sha256:6a11ea5dd0bdb197f9c2abc2e0ce73e01340464feaece525e64036546d24c851"
+ "sha256:242f92a7ea7e6c5b406fdc2615413890ba9f699114a9c09192d7dfead2ee9cfe",
+ "sha256:c2419e2135d11f1951cd994d6eb18a1835bd8fdd8429f9ca375dc1f3281bd239"
],
"index": "pypi",
- "version": "==4.3.2"
+ "markers": "python_version >= '3.9'",
+ "version": "==7.4.7"
},
"sphinx-rtd-theme": {
"hashes": [
- "sha256:a0d8bd1a2ed52e0b338cbe19c4b2eef3c5e7a048769753dac6a9f059c7b641b8",
- "sha256:f823f7e71890abe0ac6aaa6013361ea2696fc8d3e1fa798f463e82bdb77eeff2"
+ "sha256:31558d49249a3841f4351f3e23009573435f5d8479411317350f8bc5aeafcebe",
+ "sha256:863b1536bef0eb55992be0d01aa681cd7f45ce4a6277e99e055edb5b34a71d4c"
],
"index": "pypi",
- "version": "==1.2.0"
+ "markers": "python_version >= '3.6'",
+ "version": "==2.1.0rc1"
},
"sphinxcontrib-applehelp": {
"hashes": [
- "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a",
- "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"
+ "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1",
+ "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5"
],
- "markers": "python_version >= '3.5'",
- "version": "==1.0.2"
+ "markers": "python_version >= '3.9'",
+ "version": "==2.0.0"
},
"sphinxcontrib-devhelp": {
"hashes": [
- "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e",
- "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"
+ "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad",
+ "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2"
],
- "markers": "python_version >= '3.5'",
- "version": "==1.0.2"
+ "markers": "python_version >= '3.9'",
+ "version": "==2.0.0"
},
"sphinxcontrib-htmlhelp": {
"hashes": [
- "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07",
- "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2"
+ "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8",
+ "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9"
],
- "markers": "python_version >= '3.6'",
- "version": "==2.0.0"
+ "markers": "python_version >= '3.9'",
+ "version": "==2.1.0"
},
"sphinxcontrib-jquery": {
"hashes": [
"sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a",
"sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae"
],
- "markers": "python_version > '3'",
+ "markers": "python_version >= '2.7'",
"version": "==4.1"
},
"sphinxcontrib-jsmath": {
@@ -709,19 +847,19 @@
},
"sphinxcontrib-qthelp": {
"hashes": [
- "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72",
- "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"
+ "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab",
+ "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb"
],
- "markers": "python_version >= '3.5'",
- "version": "==1.0.3"
+ "markers": "python_version >= '3.9'",
+ "version": "==2.0.0"
},
"sphinxcontrib-serializinghtml": {
"hashes": [
- "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd",
- "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"
+ "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331",
+ "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d"
],
- "markers": "python_version >= '3.5'",
- "version": "==1.1.5"
+ "markers": "python_version >= '3.9'",
+ "version": "==2.0.0"
},
"tomli": {
"hashes": [
@@ -733,68 +871,56 @@
},
"twine": {
"hashes": [
- "sha256:929bc3c280033347a00f847236564d1c52a3e61b1ac2516c97c48f3ceab756d8",
- "sha256:9e102ef5fdd5a20661eb88fad46338806c3bd32cf1db729603fe3697b1bc83c8"
+ "sha256:215dbe7b4b94c2c50a7315c0275d2258399280fbb7d04182c7e55e24b5f93997",
+ "sha256:9aa0825139c02b3434d913545c7b847a21c835e11597f5255842d457da2322db"
],
"index": "pypi",
- "version": "==4.0.2"
+ "markers": "python_version >= '3.8'",
+ "version": "==5.1.1"
},
"typer": {
"extras": [
"all"
],
"hashes": [
- "sha256:b5e704f4e48ec263de1c0b3a2387cd405a13767d2f907f44c1a08cbad96f606d",
- "sha256:ff797846578a9f2a201b53442aedeb543319466870fbe1c701eab66dd7681165"
+ "sha256:070d7ca53f785acbccba8e7d28b08dcd88f79f1fbda035ade0aecec71ca5c914",
+ "sha256:49e73131481d804288ef62598d97a1ceef3058905aa536a1134f90891ba35482"
],
- "markers": "python_version >= '3.6'",
- "version": "==0.7.0"
- },
- "types-docutils": {
- "hashes": [
- "sha256:1d029567e67c52992fd42aa968778bc10a5e445c8450fc751d672d6f50330a4a",
- "sha256:556fb7ee19248aa482caa142a830c940b776b0f8c7577a98abe0977574546a1d"
- ],
- "version": "==0.19.1.9"
+ "markers": "python_version >= '3.7'",
+ "version": "==0.12.3"
},
"typing-extensions": {
"hashes": [
- "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb",
- "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"
+ "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d",
+ "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"
],
- "markers": "python_version < '3.8'",
- "version": "==4.5.0"
+ "markers": "python_version >= '3.8'",
+ "version": "==4.12.2"
},
"urllib3": {
"hashes": [
- "sha256:61717a1095d7e155cdb737ac7bb2f4324a858a1e2e6466f6d03ff630ca68d3cc",
- "sha256:d055c2f9d38dc53c808f6fdc8eab7360b6fdbbde02340ed25cfbcd817c62469e"
+ "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472",
+ "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"
],
- "markers": "python_version >= '3.7'",
- "version": "==2.0.2"
- },
- "webencodings": {
- "hashes": [
- "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78",
- "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"
- ],
- "version": "==0.5.1"
+ "markers": "python_version >= '3.8'",
+ "version": "==2.2.2"
},
"wheel": {
"hashes": [
- "sha256:cd1196f3faee2b31968d626e1731c94f99cbdb67cf5a46e4f5656cbee7738873",
- "sha256:d236b20e7cb522daf2390fa84c55eea81c5c30190f90f29ae2ca1ad8355bf247"
+ "sha256:465ef92c69fa5c5da2d1cf8ac40559a8c940886afcef87dcf14b9470862f1d85",
+ "sha256:55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81"
],
"index": "pypi",
- "version": "==0.40.0"
+ "markers": "python_version >= '3.8'",
+ "version": "==0.43.0"
},
"zipp": {
"hashes": [
- "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b",
- "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"
+ "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19",
+ "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"
],
- "markers": "python_version >= '3.7'",
- "version": "==3.15.0"
+ "markers": "python_version >= '3.8'",
+ "version": "==3.19.2"
}
}
}
diff --git a/pyproject.toml b/pyproject.toml
index b0471b7..cb6a38f 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,3 +1,39 @@
[build-system]
-requires = ["setuptools", "wheel"]
-build-backend = "setuptools.build_meta:__legacy__"
\ No newline at end of file
+requires = ["setuptools>=61.0", "wheel", "twine", "build"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "vfxnaming"
+version="1.2.3-beta"
+authors = [
+ { name="Chris Granados", email="info@chrisgranados.com" },
+]
+description = "VFX Naming Conventions Framework"
+readme = "README.rst"
+requires-python = ">=3.7"
+classifiers = [
+ "Development Status :: 4 - Beta",
+ "Intended Audience :: Developers",
+ "Programming Language :: Python :: 3.7",
+ "License :: OSI Approved :: MIT License",
+ "Operating System :: OS Independent",
+]
+
+keywords = ["vfx", "games", "naming", "convention", "gaming", "tech", "art", "pipeline"]
+
+[tool.setuptools]
+include-package-data = true
+
+[tool.setuptools.packages.find]
+where = ["src"]
+include = ["*"]
+
+[project.optional-dependencies]
+tests = ["pytest", "pytest-cov", "pytest-datafiles", "python-coveralls", "flake8"]
+lint = ["ruff"]
+docs = ["sphinx", "sphinx_rtd_theme"]
+build = ["setuptools", "twine", "wheel", "build"]
+
+[project.urls]
+Repository = "https://github.com/xiancg/vfxnaming"
+Documentation = "https://naming-conventions.readthedocs.io/en/latest/"
\ No newline at end of file
diff --git a/ruff.toml b/ruff.toml
new file mode 100644
index 0000000..b4f4d87
--- /dev/null
+++ b/ruff.toml
@@ -0,0 +1,60 @@
+# Exclude a variety of commonly ignored directories.
+exclude = [
+ ".bzr",
+ ".direnv",
+ ".eggs",
+ ".git",
+ ".git-rewrite",
+ ".hg",
+ ".ipynb_checkpoints",
+ ".mypy_cache",
+ ".nox",
+ ".pants.d",
+ ".pyenv",
+ ".pytest_cache",
+ ".pytype",
+ ".ruff_cache",
+ ".svn",
+ ".tox",
+ ".venv",
+ ".vscode",
+ "__pypackages__",
+ "_build",
+ "buck-out",
+ "build",
+ "dist",
+ "node_modules",
+ "site-packages",
+ "venv",
+]
+
+# Same as Black.
+line-length = 90
+indent-width = 4
+
+target-version = "py310"
+
+[lint]
+# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
+select = ["E4", "E7", "E9", "F"]
+ignore = []
+
+# Allow fix for all enabled rules (when `--fix`) is provided.
+fixable = ["ALL"]
+unfixable = []
+
+# Allow unused variables when underscore-prefixed.
+dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
+
+[format]
+# Like Black, use double quotes for strings.
+quote-style = "double"
+
+# Like Black, indent with spaces, rather than tabs.
+indent-style = "space"
+
+# Like Black, respect magic trailing commas.
+skip-magic-trailing-comma = false
+
+# Like Black, automatically detect the appropriate line ending.
+line-ending = "auto"
\ No newline at end of file
diff --git a/setup.cfg b/setup.cfg
deleted file mode 100644
index 11e9ec4..0000000
--- a/setup.cfg
+++ /dev/null
@@ -1,2 +0,0 @@
-[metadata]
-description-file = README.rst
\ No newline at end of file
diff --git a/setup.py b/setup.py
deleted file mode 100644
index 53d11e9..0000000
--- a/setup.py
+++ /dev/null
@@ -1,47 +0,0 @@
-from setuptools import setup, find_packages
-from pathlib import Path
-import re
-
-PACKAGENAME = 'vfxnaming'
-PACKAGE_NICENAME = 'VFX Naming Conventions Framework'
-
-module_dir = Path(__file__).parents[0]
-version_module = module_dir.joinpath('src', PACKAGENAME, '_version.py')
-
-version_str = "0.0.0"
-with open(version_module) as fp:
- version_str = re.match(
- r'.*__version__ = [\',\"](.*?)[\',\"]',
- fp.read(),
- re.DOTALL
- ).group(1)
-
-# Get the long description from the README file
-with open(module_dir.joinpath('README.rst'), encoding='utf-8') as fp:
- long_description = fp.read()
-
-
-setup(
- name=PACKAGENAME,
- version=version_str,
- description=PACKAGE_NICENAME,
- long_description=long_description,
- long_description_content_type='text/x-rst',
- url='https://github.com/xiancg/vfxnaming',
- download_url=f'https://github.com/xiancg/vfxnaming/archive/v{version_str}.tar.gz',
- author='Chris Granados- Xian',
- author_email='info@chrisgranados.com',
- classifiers=[
- 'Development Status :: 4 - Beta',
- 'Intended Audience :: Developers',
- 'Programming Language :: Python :: 3.7'
- ],
- package_dir={'': 'src'},
- packages=find_packages(where='src'),
- python_requires='>=3.7, <4',
- extras_require={
- 'dev': ['pytest', 'pytest-cov', 'pytest-datafiles', 'python-coveralls', 'flake8'],
- 'docs': ['sphinx', 'sphinx-rtd-theme']
- },
- include_package_data=True
-)
diff --git a/src/vfxnaming/_vesion.py b/src/vfxnaming/_vesion.py
deleted file mode 100644
index 80060c8..0000000
--- a/src/vfxnaming/_vesion.py
+++ /dev/null
@@ -1 +0,0 @@
-__version__ = "1.2.3-beta"
diff --git a/tox.ini b/tox.ini
index 02e96f9..7c0c4f6 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,12 +1,12 @@
[tox]
-envlist = py37, py37ci, flake8, docs
+envlist = py310, py310ci, docs
skipsdist = True
[testenv]
-basepython = py37: python3.7
- py37ci: python3.7
- flake8: python3.7
- docs: python3.7
+basepython = py310: python3.10
+ py310ci: python3.10
+ flake8: python3.10
+ docs: python3.10
usedevelop = True
[testenv:docs]
@@ -15,19 +15,14 @@ deps = sphinx
{[testenv]deps}
commands = ./docs/make.bat html
-[testenv:flake8]
-deps = flake8
- {[testenv]deps}
-commands=flake8 src/
-
-[testenv:py37]
+[testenv:py310]
deps = pytest
pytest-cov
pytest-datafiles
{[testenv]deps}
-commands= pytest -c tox.ini --cov-report term-missing --cov-report html:cov_py37_html --cov=vfxnaming tests/
+commands= pytest -c tox.ini --cov-report term-missing --cov-report html:cov_py310_html --cov=vfxnaming tests/
-[testenv:py37ci]
+[testenv:py310ci]
deps = pytest
pytest-cov
pytest-datafiles
@@ -37,10 +32,8 @@ commands= pytest -c tox.ini --cov-report term-missing --cov=vfxnaming tests/
[pytest]
addopts = --maxfail=10 -rf -s
-markers =
- datafiles: datafiles marker registration to avoid warning
- serial
-junit_family=legacy
+markers = serial
+junit_family = legacy
[flake8]
max-line-length = 110
From f9dc59820c50a83da008d4270bc90a7e5099ba5b Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sat, 3 Aug 2024 20:26:38 -0300
Subject: [PATCH 03/65] Update logger
---
src/vfxnaming/logger.py | 169 ++++++++++++++++++++++++++--------------
1 file changed, 109 insertions(+), 60 deletions(-)
diff --git a/src/vfxnaming/logger.py b/src/vfxnaming/logger.py
index 6548170..ea539ab 100644
--- a/src/vfxnaming/logger.py
+++ b/src/vfxnaming/logger.py
@@ -1,84 +1,133 @@
-# coding=utf-8
-from __future__ import absolute_import, print_function
-
import logging
import sys
-import os
import json
from datetime import date
+from pathlib import Path
-_base_name = "vfxnaming"
-logger = logging.getLogger(name='{}log'.format(_base_name))
+class Logger:
+ LEVEL_DEFAULT = logging.INFO
-def init_logger():
- """Initialize '{}log' logging object and add a STDOUT handler to output to console, terminal, etc.
- """.format(_base_name)
- logger.setLevel(logging.DEBUG)
+ def __init__(self, logger_name, propagate=False):
+ self.name = logger_name
+ self.__logger_obj = None
+ self.propagate = propagate
+ self.file_handler = None
- found_handler = False
- for each in logger.handlers:
- if isinstance(each, logging.StreamHandler):
- found_handler = True
- break
+ @property
+ def logger_obj(self):
+ if not self.__logger_obj:
+ if self.logger_exists(self.name):
+ self.__logger_obj = logging.getLogger(self.name)
+ else:
+ self.__logger_obj = logging.getLogger(self.name)
+ self.__logger_obj.setLevel(self.LEVEL_DEFAULT)
+ self.__logger_obj.propagate = self.propagate
- if not found_handler:
- # Formatter
- formatter = logging.Formatter(
- '[%(asctime)s:%(module)s:%(funcName)s:'
- '%(lineno)s:%(levelname)s] %(message)s'
- )
- # STDOUT stream
- streamHandler = logging.StreamHandler(sys.stdout)
- streamHandler.setLevel(logging.DEBUG)
- streamHandler.setFormatter(formatter)
- logger.addHandler(streamHandler)
+ formatter = logging.Formatter(
+ "[%(asctime)s:%(module)s:%(funcName)s:"
+ "%(lineno)s:%(levelname)s] %(message)s"
+ )
+ stream_handler = logging.StreamHandler(sys.stderr)
+ stream_handler.setFormatter(formatter)
+ self.__logger_obj.addHandler(stream_handler)
-def init_file_logger():
- """Adds file log to '{}log' logging object. Log files will be located at the user OS folder.
+ return self.__logger_obj
- Raises:
- OSError, IOError: Directory for log files couldn't be created.
+ @staticmethod
+ def logger_exists(name):
+ return name in logging.Logger.manager.loggerDict.keys()
- Returns:
- [str]: Log file path
- """.format(_base_name)
+ def set_level(self, level):
+ self.logger_obj.setLevel(level)
- found_handler = False
- for each in logger.handlers:
- if isinstance(each, logging.FileHandler):
- found_handler = True
- break
+ def debug(self, msg, *args, **kwargs):
+ self.logger_obj.debug(msg, *args, **kwargs)
- if not found_handler:
- # Formatter
- formatter = logging.Formatter(
- '[%(asctime)s:%(module)s:%(funcName)s:'
- '%(lineno)s:%(levelname)s] %(message)s'
- )
- # Log file stream
- userPath = os.path.expanduser("~")
- module_dir = os.path.split(__file__)[0]
- config_location = os.path.join(module_dir, "cfg", "config.json")
- config = dict()
- with open(config_location) as fp:
- config = json.load(fp)
- finalDir = os.path.join(userPath, "." + config["logger_dir_name"])
+ def info(self, msg, *args, **kwargs):
+ self.logger_obj.info(msg, *args, **kwargs)
+
+ def warning(self, msg, *args, **kwargs):
+ self.logger_obj.warning(msg, *args, **kwargs)
+
+ def error(self, msg, *args, **kwargs):
+ self.logger_obj.error(msg, *args, **kwargs)
+
+ def critical(self, msg, *args, **kwargs):
+ self.logger_obj.critical(msg, *args, **kwargs)
+
+ def log(self, level, msg, *args, **kwargs):
+ self.logger_obj.log(level, msg, *args, **kwargs)
+
+ def exception(self, msg, *args, **kwargs):
+ self.logger_obj.exception(msg, *args, **kwargs)
+
+ def log_to_file(self, level=logging.DEBUG):
+ log_file_path = self.get_log_file_path()
try:
- if not os.path.exists(finalDir):
- os.mkdir(finalDir)
+ if not log_file_path.parent.exists():
+ log_file_path.parent.mkdir()
except (OSError, IOError) as why:
raise why
+ self.file_handler = logging.FileHandler(log_file_path, mode="a")
+ self.file_handler.setLevel(level)
+
+ formatter = logging.Formatter(
+ "[%(asctime)s:%(module)s:%(funcName)s:"
+ "%(lineno)s:%(levelname)s] %(message)s"
+ )
+
+ self.file_handler.setFormatter(formatter)
+ self.logger_obj.addHandler(self.file_handler)
+
+ def stop_logging_to_file(self):
+ if self.file_handler:
+ self.logger_obj.removeHandler(self.file_handler)
+ self.file_handler.close()
+ self.file_handler = None
+
+ def get_log_file_path(self):
+ user_path = Path("~").expanduser()
+ module_dir = Path(__file__).parents[0]
+ config_location = module_dir.joinpath("cfg", "config.json")
+ config = {}
+ with open(config_location) as fp:
+ config = json.load(fp)
+ final_dir = user_path.joinpath(f".{config.get('cfg_dir_name')}")
today = date.today()
date_string = today.strftime("%d-%m-%Y")
- log_file_path = os.path.join(finalDir, '{}_{}.log'.format(_base_name, date_string))
- fileHandler = logging.FileHandler(log_file_path, mode='a')
- fileHandler.setLevel(logging.DEBUG)
- fileHandler.setFormatter(formatter)
- logger.addHandler(fileHandler)
+ log_file_path = final_dir.joinpath(f"{self.logger_obj.name}_{date_string}.log")
return log_file_path
- return None
+
+
+def init_logger(base_name, log_to_file=False):
+ """
+ Initialize 'base_name' logging object and add a STDOUT handler to output to
+ console, terminal, etc.
+
+ Args:
+ base_name (str): Base name for the logger. Will be used to create the logger name.
+ log_to_file (bool): If True, the logger will log to a file.
+
+ Returns:
+ tuple: Tuple containing: logger, logger_gui (child of logger and used for GUI messages)
+ """
+ logger = Logger(f"{base_name}log")
+ if log_to_file:
+ logger.log_to_file()
+
+ logger_gui = Logger(f"{base_name}log.gui", propagate=True)
+ logger_gui.set_level(logging.INFO)
+
+ return logger, logger_gui
+
+
+logger, logger_gui = init_logger("vfxnaming")
+
+
+if __name__ == "__main__":
+ pass
From 29228adde0a9d95f14c4ffeda79ee11798ce427f Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sat, 3 Aug 2024 20:34:32 -0300
Subject: [PATCH 04/65] Logger update and removed six calls
---
src/vfxnaming/cfg/config.json | 3 +-
src/vfxnaming/naming.py | 7 +-
src/vfxnaming/rules.py | 77 ++++---
src/vfxnaming/serialize.py | 3 -
src/vfxnaming/tokens.py | 45 ++--
tests/naming_test.py | 385 +++++++++++++++++-----------------
tests/rules_test.py | 26 +--
tests/tokens_test.py | 149 +++++++------
8 files changed, 336 insertions(+), 359 deletions(-)
diff --git a/src/vfxnaming/cfg/config.json b/src/vfxnaming/cfg/config.json
index 6ae9227..6df3ad8 100644
--- a/src/vfxnaming/cfg/config.json
+++ b/src/vfxnaming/cfg/config.json
@@ -1,4 +1,3 @@
{
- "logger_dir_name": "CGXTools",
- "local_repo_name": "CGXTools"
+ "cfg_dir_name": "CGXTools"
}
\ No newline at end of file
diff --git a/src/vfxnaming/naming.py b/src/vfxnaming/naming.py
index a6b6643..c6c0723 100644
--- a/src/vfxnaming/naming.py
+++ b/src/vfxnaming/naming.py
@@ -25,7 +25,6 @@
from vfxnaming.logger import logger
from vfxnaming.error import SolvingError
-import six
NAMING_REPO_ENV = "NAMING_REPO"
@@ -169,11 +168,11 @@ def save_session(repo=None):
except (IOError, OSError) as why:
raise why
# save tokens
- for name, token in six.iteritems(tokens.get_tokens()):
+ for name, token in tokens.get_tokens().items():
logger.debug("Saving token: '{}' in {}".format(name, repo))
tokens.save_token(name, repo)
# save rules
- for name, rule in six.iteritems(rules.get_rules()):
+ for name, rule in rules.get_rules().items():
if not isinstance(rule, rules.Rule):
continue
logger.debug("Saving rule: '{}' in {}".format(name, repo))
@@ -223,5 +222,5 @@ def load_session(repo=None):
logger.debug("Loading active rule: {}".format(namingconf))
with open(namingconf) as fp:
config = json.load(fp)
- rules.set_active_rule(config.get('set_active_rule'))
+ rules.set_active_rule(config.get("set_active_rule"))
return True
diff --git a/src/vfxnaming/rules.py b/src/vfxnaming/rules.py
index f9c1bd7..949a528 100644
--- a/src/vfxnaming/rules.py
+++ b/src/vfxnaming/rules.py
@@ -1,6 +1,3 @@
-# coding=utf-8
-from __future__ import absolute_import, print_function
-
import re
import json
import os
@@ -12,7 +9,7 @@
from vfxnaming.logger import logger
from vfxnaming.error import ParsingError, SolvingError
-_rules = {'_active': None}
+_rules = {"_active": None}
class Rule(Serializable):
@@ -32,9 +29,11 @@ class Rule(Serializable):
match the pattern. Defaults to ANCHOR_START.
"""
- __FIELDS_REGEX = re.compile(r'{(.+?)}')
- __PATTERN_SEPARATORS_REGEX = re.compile(r'(}[_\-\.:\|/\\]{|[_\-\.:\|/\\]{|}[_\-\.:\|/\\])')
- __SEPARATORS_REGEX = re.compile(r'[_\-\.:\|/\\]')
+ __FIELDS_REGEX = re.compile(r"{(.+?)}")
+ __PATTERN_SEPARATORS_REGEX = re.compile(
+ r"(}[_\-\.:\|/\\]{|[_\-\.:\|/\\]{|}[_\-\.:\|/\\])"
+ )
+ __SEPARATORS_REGEX = re.compile(r"[_\-\.:\|/\\]")
ANCHOR_START, ANCHOR_END, ANCHOR_BOTH = (1, 2, 3)
def __init__(self, name, pattern, anchor=ANCHOR_START):
@@ -131,7 +130,9 @@ def parse(self, name):
name_parts = sorted(match.groupdict().items())
logger.debug(
"Name parts: {}".format(
- ", ".join(["('{}': '{}')".format(k[:-3], v) for k, v in name_parts])
+ ", ".join(
+ ["('{}': '{}')".format(k[:-3], v) for k, v in name_parts]
+ )
)
)
repeated_fields = dict()
@@ -167,37 +168,37 @@ def __build_regex(self):
# ? Taken from Lucidity by Martin Pengelly-Phillips
# Escape non-placeholder components
expression = re.sub(
- r'(?P{(.+?)(:(\\}|.)+?)?})|(?P.+?)',
+ r"(?P{(.+?)(:(\\}|.)+?)?})|(?P.+?)",
self.__escape,
- self._pattern
+ self._pattern,
)
# Replace placeholders with regex pattern
expression = re.sub(
- r'{(?P.+?)(:(?P(\\}|.)+?))?}',
- functools.partial(
- self.__convert, placeholder_count=defaultdict(int)
- ),
- expression
+ r"{(?P.+?)(:(?P(\\}|.)+?))?}",
+ functools.partial(self.__convert, placeholder_count=defaultdict(int)),
+ expression,
)
if self._anchor is not None:
if bool(self._anchor & self.ANCHOR_START):
- expression = '^{0}'.format(expression)
+ expression = "^{0}".format(expression)
if bool(self._anchor & self.ANCHOR_END):
- expression = '{0}$'.format(expression)
+ expression = "{0}$".format(expression)
# Compile expression
try:
compiled = re.compile(expression)
except re.error as error:
- if any([
- 'bad group name' in str(error),
- 'bad character in group name' in str(error)
- ]):
- raise ValueError('Placeholder name contains invalid characters.')
+ if any(
+ [
+ "bad group name" in str(error),
+ "bad character in group name" in str(error),
+ ]
+ ):
+ raise ValueError("Placeholder name contains invalid characters.")
else:
_, value, traceback = sys.exc_info()
- message = 'Invalid pattern: {0}'.format(value)
+ message = "Invalid pattern: {0}".format(value)
if sys.version_info[0] == 3:
raise ValueError(message).with_traceback(traceback)
elif sys.version_info[0] == 2:
@@ -213,33 +214,31 @@ def __convert(self, match, placeholder_count):
"""
# ? Taken from Lucidity by Martin Pengelly-Phillips
- placeholder_name = match.group('placeholder')
+ placeholder_name = match.group("placeholder")
# The re module does not support duplicate group names. To support
# duplicate placeholder names in templates add a unique count to the
# regular expression group name and strip it later during parse.
placeholder_count[placeholder_name] += 1
- placeholder_name += '{0:03d}'.format(
- placeholder_count[placeholder_name]
- )
+ placeholder_name += "{0:03d}".format(placeholder_count[placeholder_name])
- expression = match.group('expression')
+ expression = match.group("expression")
if expression is None:
- expression = r'[\w_.\-/:]+'
+ expression = r"[\w_.\-/:]+"
# Un-escape potentially escaped characters in expression.
- expression = expression.replace('{', '{').replace('}', '}')
+ expression = expression.replace("{", "{").replace("}", "}")
- return r'(?P<{0}>{1})'.format(placeholder_name, expression)
+ return r"(?P<{0}>{1})".format(placeholder_name, expression)
def __escape(self, match):
"""Escape matched 'other' group value."""
# ? Taken from Lucidity by Martin Pengelly-Phillips
groups = match.groupdict()
- if groups['other'] is not None:
- return re.escape(groups['other'])
+ if groups["other"] is not None:
+ return re.escape(groups["other"])
- return groups['placeholder']
+ return groups["placeholder"]
def __digits_pattern(self):
# * This accounts for those cases where a token is used more than once in a rule
@@ -253,8 +252,8 @@ def __digits_pattern(self):
for match in sorted(indexes, reverse=True):
digits_pattern = "{}{}{}".format(
digits_pattern[:match],
- str(repetetions-i),
- digits_pattern[match:]
+ str(repetetions - i),
+ digits_pattern[match:],
)
i += 1
return digits_pattern
@@ -349,7 +348,7 @@ def reset_rules():
bool: True if clearing was successful.
"""
_rules.clear()
- _rules['_active'] = None
+ _rules["_active"] = None
return True
@@ -360,7 +359,7 @@ def get_active_rule():
Returns:
Rule: Rule object instance for currently active Rule.
"""
- name = _rules.get('_active')
+ name = _rules.get("_active")
return _rules.get(name)
@@ -375,7 +374,7 @@ def set_active_rule(name):
bool: True if successful, False otherwise.
"""
if has_rule(name):
- _rules['_active'] = name
+ _rules["_active"] = name
return True
return False
diff --git a/src/vfxnaming/serialize.py b/src/vfxnaming/serialize.py
index 8eb9671..7f2661b 100644
--- a/src/vfxnaming/serialize.py
+++ b/src/vfxnaming/serialize.py
@@ -1,6 +1,3 @@
-# coding=utf-8
-from __future__ import absolute_import, print_function
-
import copy
diff --git a/src/vfxnaming/tokens.py b/src/vfxnaming/tokens.py
index 918cb14..142b366 100644
--- a/src/vfxnaming/tokens.py
+++ b/src/vfxnaming/tokens.py
@@ -1,6 +1,3 @@
-# coding=utf-8
-from __future__ import absolute_import, print_function
-
import copy
import json
import os
@@ -8,7 +5,6 @@
from vfxnaming.logger import logger
from vfxnaming.error import TokenError
-import six
_tokens = dict()
@@ -133,14 +129,16 @@ def solve(self, name=None):
if self.required and name:
return name
elif self.required and name is None:
- raise TokenError("Token {} is required. name parameter must be passed.".format(self.name))
+ raise TokenError(
+ "Token {} is required. name parameter must be passed.".format(self.name)
+ )
elif not self.required and name:
if name not in self._options.keys():
raise TokenError(
"name '{}' not found in Token '{}'. Options: {}".format(
- name, self.name, ', '.join(self._options.keys())
- )
+ name, self.name, ", ".join(self._options.keys())
)
+ )
return self._options.get(name)
elif not self.required and not name:
return self._options.get(self.default)
@@ -157,11 +155,12 @@ def parse(self, value):
if self.required:
return value
elif not self.required and len(self._options) >= 1:
- for k, v in six.iteritems(self._options):
+ for k, v in self._options.items():
if v == value:
return k
- raise TokenError("Value '{}' not found in Token '{}'. Options: {}".format(
- value, self.name, ', '.join(self._options.values())
+ raise TokenError(
+ "Value '{}' not found in Token '{}'. Options: {}".format(
+ value, self.name, ", ".join(self._options.values())
)
)
@@ -225,7 +224,7 @@ def solve(self, number):
str: The solved string to be used in the name
"""
numberStr = str(number).zfill(self.padding)
- return '{}{}{}'.format(self.prefix, numberStr, self.suffix)
+ return "{}{}{}".format(self.prefix, numberStr, self.suffix)
def parse(self, value):
"""Get metatada (number) for given value in name. e.g.: v0025 will return 25
@@ -282,33 +281,33 @@ def required(self):
@property
def padding(self):
- return self._options.get('padding')
+ return self._options.get("padding")
@padding.setter
def padding(self, p):
if p <= 0:
p = 1
- self._options['padding'] = int(p)
+ self._options["padding"] = int(p)
@property
def prefix(self):
- return self._options.get('prefix')
+ return self._options.get("prefix")
@prefix.setter
def prefix(self, this_prefix):
if isinstance(this_prefix, str) and not this_prefix.isdigit():
- self._options['prefix'] = this_prefix
+ self._options["prefix"] = this_prefix
else:
logger.warning("Given prefix has to be a string: {}".format(this_prefix))
@property
def suffix(self):
- return self._options.get('suffix')
+ return self._options.get("suffix")
@suffix.setter
def suffix(self, this_suffix):
if isinstance(this_suffix, str) and not this_suffix.isdigit():
- self._options['suffix'] = this_suffix
+ self._options["suffix"] = this_suffix
else:
logger.warning("Given suffix has to be a string: {}".format(this_suffix))
@@ -335,18 +334,18 @@ def add_token(name, **kwargs):
Token: The Token object instance created for given name and fields.
"""
token = Token(name)
- for k, v in six.iteritems(kwargs):
+ for k, v in kwargs.items():
if k == "default":
continue
token.add_option(k, v)
if "default" in kwargs.keys():
extract_default = copy.deepcopy(kwargs)
del extract_default["default"]
- if kwargs.get('default') in extract_default.keys():
- token.default = kwargs.get('default')
- elif kwargs.get('default') in extract_default.values():
- for k, v in six.iteritems(extract_default):
- if v == kwargs.get('default'):
+ if kwargs.get("default") in extract_default.keys():
+ token.default = kwargs.get("default")
+ elif kwargs.get("default") in extract_default.values():
+ for k, v in extract_default.items():
+ if v == kwargs.get("default"):
token.default = k
break
else:
diff --git a/tests/naming_test.py b/tests/naming_test.py
index c9022b1..9cd7aa3 100644
--- a/tests/naming_test.py
+++ b/tests/naming_test.py
@@ -1,92 +1,92 @@
-# coding=utf-8
-from __future__ import absolute_import, print_function
-
from vfxnaming import naming as n
import vfxnaming.rules as rules
import vfxnaming.tokens as tokens
-from vfxnaming import logger
from vfxnaming.error import ParsingError, SolvingError, TokenError
import os
import pytest
import tempfile
-# Debug logging
-logger.init_logger()
-# logger.init_file_logger()
-
class Test_Solve:
@pytest.fixture(autouse=True)
def setup(self):
tokens.reset_tokens()
- tokens.add_token('whatAffects')
- tokens.add_token_number('digits')
- tokens.add_token(
- 'category', natural='natural',
- practical='practical', dramatic='dramatic',
- volumetric='volumetric', default='natural'
- )
+ tokens.add_token("whatAffects")
+ tokens.add_token_number("digits")
tokens.add_token(
- 'function', key='key',
- fill='fill', ambient='ambient',
- bounce='bounce', rim='rim',
- custom='custom', kick='kick',
- default='custom'
+ "category",
+ natural="natural",
+ practical="practical",
+ dramatic="dramatic",
+ volumetric="volumetric",
+ default="natural",
)
tokens.add_token(
- 'type', lighting='LGT',
- animation='ANI', default='lighting'
- )
- rules.reset_rules()
- rules.add_rule(
- 'lights',
- '{category}_{function}_{whatAffects}_{digits}_{type}'
+ "function",
+ key="key",
+ fill="fill",
+ ambient="ambient",
+ bounce="bounce",
+ rim="rim",
+ custom="custom",
+ kick="kick",
+ default="custom",
)
+ tokens.add_token("type", lighting="LGT", animation="ANI", default="lighting")
+ rules.reset_rules()
+ rules.add_rule("lights", "{category}_{function}_{whatAffects}_{digits}_{type}")
def test_explicit(self):
- name = 'natural_ambient_chars_001_LGT'
- solved = n.solve(category='natural', function='ambient',
- whatAffects='chars', digits=1, type='lighting')
+ name = "natural_ambient_chars_001_LGT"
+ solved = n.solve(
+ category="natural",
+ function="ambient",
+ whatAffects="chars",
+ digits=1,
+ type="lighting",
+ )
assert solved == name
def test_no_match_for_token(self):
with pytest.raises(TokenError) as exception:
n.solve(
- category='natural', function='sarasa',
- whatAffects='chars', digits=1, type='lighting'
+ category="natural",
+ function="sarasa",
+ whatAffects="chars",
+ digits=1,
+ type="lighting",
)
assert str(exception.value).startswith("name") is True
def test_missing_required_token(self):
with pytest.raises(SolvingError) as exception:
- n.solve(
- category='natural', function='key', digits=1, type='lighting'
- )
+ n.solve(category="natural", function="key", digits=1, type="lighting")
assert str(exception.value).startswith("Token") is True
def test_missing_not_required_token(self):
with pytest.raises(SolvingError) as exception:
- n.solve('chars')
+ n.solve("chars")
assert str(exception.value).startswith("Missing argument for field") is True
def test_defaults(self):
- name = 'natural_custom_chars_001_LGT'
- solved = n.solve(category='natural', whatAffects='chars',
- digits=1, type='lighting')
+ name = "natural_custom_chars_001_LGT"
+ solved = n.solve(
+ category="natural", whatAffects="chars", digits=1, type="lighting"
+ )
assert solved == name
- name = 'natural_custom_chars_001_LGT'
- solved = n.solve(whatAffects='chars', digits=1)
+ name = "natural_custom_chars_001_LGT"
+ solved = n.solve(whatAffects="chars", digits=1)
assert solved == name
def test_implicit(self):
- name = 'natural_custom_chars_001_ANI'
- solved = n.solve('chars', 1, type='animation')
+ name = "natural_custom_chars_001_ANI"
+ solved = n.solve("chars", 1, type="animation")
assert solved == name
- name = 'natural_custom_chars_001_LGT'
- solved = n.solve('chars', 1)
+ name = "natural_custom_chars_001_LGT"
+ solved = n.solve("chars", 1)
assert solved == name
@@ -94,46 +94,44 @@ class Test_Parse:
@pytest.fixture(autouse=True)
def setup(self):
tokens.reset_tokens()
- tokens.add_token('whatAffects')
- tokens.add_token_number('digits')
+ tokens.add_token("whatAffects")
+ tokens.add_token_number("digits")
tokens.add_token(
- 'category', natural='natural',
- practical='practical', dramatic='dramatic',
- volumetric='volumetric', default='natural'
+ "category",
+ natural="natural",
+ practical="practical",
+ dramatic="dramatic",
+ volumetric="volumetric",
+ default="natural",
)
tokens.add_token(
- 'function', key='key',
- fill='fill', ambient='ambient',
- bounce='bounce', rim='rim',
- custom='custom', kick='kick',
- default='custom'
- )
- tokens.add_token(
- 'type', lighting='LGT',
- animation='ANI', default='lighting'
+ "function",
+ key="key",
+ fill="fill",
+ ambient="ambient",
+ bounce="bounce",
+ rim="rim",
+ custom="custom",
+ kick="kick",
+ default="custom",
)
+ tokens.add_token("type", lighting="LGT", animation="ANI", default="lighting")
def test_parsing_with_separators(self):
rules.reset_rules()
- rules.add_rule(
- 'lights',
- '{category}_{function}_{whatAffects}_{digits}_{type}'
- )
- name = 'dramatic_bounce_chars_001_LGT'
+ rules.add_rule("lights", "{category}_{function}_{whatAffects}_{digits}_{type}")
+ name = "dramatic_bounce_chars_001_LGT"
parsed = n.parse(name)
- assert parsed['category'] == 'dramatic'
- assert parsed['function'] == 'bounce'
- assert parsed['whatAffects'] == 'chars'
- assert parsed['digits'] == 1
- assert parsed['type'] == 'lighting'
+ assert parsed["category"] == "dramatic"
+ assert parsed["function"] == "bounce"
+ assert parsed["whatAffects"] == "chars"
+ assert parsed["digits"] == 1
+ assert parsed["type"] == "lighting"
def test_parsing_without_separators(self):
rules.reset_rules()
- rules.add_rule(
- 'lights',
- '{category}{function}{whatAffects}{digits}{type}'
- )
- name = 'dramatic_bounce_chars_001_LGT'
+ rules.add_rule("lights", "{category}{function}{whatAffects}{digits}{type}")
+ name = "dramatic_bounce_chars_001_LGT"
parsed = n.parse(name)
assert parsed is None
@@ -143,28 +141,27 @@ class Test_RuleWithRepetitions:
def setup(self):
tokens.reset_tokens()
rules.reset_rules()
+ tokens.add_token("side", center="C", left="L", right="R", default="center")
tokens.add_token(
- 'side', center='C',
- left='L', right='R',
- default='center'
- )
- tokens.add_token(
- 'region', orbital="ORBI",
- parotidmasseter="PAROT", mental="MENT",
- frontal="FRONT", zygomatic="ZYGO",
- retromandibularfossa="RETMAND"
- )
- rules.add_rule(
- "filename",
- '{side}-{region}_{side}-{region}_{side}-{region}'
+ "region",
+ orbital="ORBI",
+ parotidmasseter="PAROT",
+ mental="MENT",
+ frontal="FRONT",
+ zygomatic="ZYGO",
+ retromandibularfossa="RETMAND",
)
+ rules.add_rule("filename", "{side}-{region}_{side}-{region}_{side}-{region}")
def test_parse_repeated_tokens(self):
name = "C-FRONT_L-ORBI_R-ZYGO"
expected = {
- "side1": "center", "region1": "frontal",
- "side2": "left", "region2": "orbital",
- "side3": "right", "region3": "zygomatic"
+ "side1": "center",
+ "region1": "frontal",
+ "side2": "left",
+ "region2": "orbital",
+ "side3": "right",
+ "region3": "zygomatic",
}
result = n.parse(name)
assert result == expected
@@ -178,9 +175,12 @@ def test_parse_repeated_tokens_missing_some(self):
def test_solve_repeated_tokens(self):
name = "C-MENT_L-PAROT_R-RETMAND"
result = n.solve(
- side1="center", side2="left", side3="right",
- region1="mental", region2="parotidmasseter",
- region3="retromandibularfossa"
+ side1="center",
+ side2="left",
+ side3="right",
+ region1="mental",
+ region2="parotidmasseter",
+ region3="retromandibularfossa",
)
assert result == name
@@ -189,8 +189,9 @@ def test_solve_repeat_one_token(self):
name = "L-MENT_L-PAROT_L-RETMAND"
result = n.solve(
side="left",
- region1="mental", region2="parotidmasseter",
- region3="retromandibularfossa"
+ region1="mental",
+ region2="parotidmasseter",
+ region3="retromandibularfossa",
)
assert result == name
@@ -198,9 +199,10 @@ def test_solve_repeat_one_token(self):
def test_solve_repeated_missing_some(self):
name = "C-FRONT_C-PAROT_R-RETMAND"
result = n.solve(
- side1="center", side3="right",
+ side1="center",
+ side3="right",
region2="parotidmasseter",
- region3="retromandibularfossa"
+ region3="retromandibularfossa",
)
assert result == name
@@ -209,79 +211,71 @@ class Test_Anchoring:
@pytest.fixture(autouse=True)
def setup(self):
tokens.reset_tokens()
- tokens.add_token('awesometoken')
+ tokens.add_token("awesometoken")
def test_solve_anchoring_end(self):
rules.reset_rules()
rules.add_rule(
- 'anchoring',
- 'crazy_hardcoded_value_{awesometoken}',
- rules.Rule.ANCHOR_END
+ "anchoring", "crazy_hardcoded_value_{awesometoken}", rules.Rule.ANCHOR_END
)
- name = 'crazy_hardcoded_value_bye'
- solved = n.solve('bye')
+ name = "crazy_hardcoded_value_bye"
+ solved = n.solve("bye")
assert solved == name
def test_solve_anchoring_both(self):
rules.reset_rules()
rules.add_rule(
- 'anchoring',
- '{awesometoken}_crazy_hardcoded_value_{awesometoken}',
- rules.Rule.ANCHOR_BOTH
+ "anchoring",
+ "{awesometoken}_crazy_hardcoded_value_{awesometoken}",
+ rules.Rule.ANCHOR_BOTH,
)
- name = 'hello_crazy_hardcoded_value_bye'
- solved = n.solve(awesometoken1='hello', awesometoken2='bye')
+ name = "hello_crazy_hardcoded_value_bye"
+ solved = n.solve(awesometoken1="hello", awesometoken2="bye")
assert solved == name
def test_solve_anchoring_start(self):
rules.reset_rules()
rules.add_rule(
- 'anchoring',
- '{awesometoken}_crazy_hardcoded_value',
- rules.Rule.ANCHOR_START
+ "anchoring", "{awesometoken}_crazy_hardcoded_value", rules.Rule.ANCHOR_START
)
- name = 'hello_crazy_hardcoded_value'
- solved = n.solve(awesometoken='hello')
+ name = "hello_crazy_hardcoded_value"
+ solved = n.solve(awesometoken="hello")
assert solved == name
def test_parse_anchoring_end(self):
rules.reset_rules()
rules.add_rule(
- 'anchoring',
- 'crazy_hardcoded_value_{awesometoken}',
- rules.Rule.ANCHOR_END
+ "anchoring", "crazy_hardcoded_value_{awesometoken}", rules.Rule.ANCHOR_END
)
- name = 'crazy_hardcoded_value_bye'
+ name = "crazy_hardcoded_value_bye"
parsed = n.parse(name)
- assert parsed == {'awesometoken': 'bye'}
+ assert parsed == {"awesometoken": "bye"}
def test_parse_anchoring_both(self):
rules.reset_rules()
rules.add_rule(
- 'anchoring',
- '{awesometoken}_crazy_hardcoded_value_{awesometoken}',
- rules.Rule.ANCHOR_BOTH
+ "anchoring",
+ "{awesometoken}_crazy_hardcoded_value_{awesometoken}",
+ rules.Rule.ANCHOR_BOTH,
)
- name = 'hello_crazy_hardcoded_value_bye'
+ name = "hello_crazy_hardcoded_value_bye"
parsed = n.parse(name)
- assert parsed == {'awesometoken1': 'hello', 'awesometoken2': 'bye'}
+ assert parsed == {"awesometoken1": "hello", "awesometoken2": "bye"}
def test_parse_anchoring_start(self):
rules.reset_rules()
rules.add_rule(
- 'anchoring',
- '{awesometoken}_crazy_hardcoded_value',
- rules.Rule.ANCHOR_START
+ "anchoring", "{awesometoken}_crazy_hardcoded_value", rules.Rule.ANCHOR_START
)
- name = 'hello_crazy_hardcoded_value'
+ name = "hello_crazy_hardcoded_value"
parsed = n.parse(name)
- assert parsed == {'awesometoken': 'hello'}
+ assert parsed == {"awesometoken": "hello"}
class Test_Serialization:
@@ -292,110 +286,115 @@ def setup(self):
def test_tokens(self):
token1 = tokens.add_token(
- 'function', key='key',
- fill='fill', ambient='ambient',
- bounce='bounce', rim='rim',
- custom='custom', kick='kick',
- default='custom'
+ "function",
+ key="key",
+ fill="fill",
+ ambient="ambient",
+ bounce="bounce",
+ rim="rim",
+ custom="custom",
+ kick="kick",
+ default="custom",
)
token2 = tokens.Token.from_data(token1.data())
assert token1.data() == token2.data()
def test_rules(self):
rule1 = rules.add_rule(
- 'lights',
- '{category}_{function}_{whatAffects}_{digits}_{type}'
+ "lights", "{category}_{function}_{whatAffects}_{digits}_{type}"
)
rule2 = rules.Rule.from_data(rule1.data())
assert rule1.data() == rule2.data()
def test_validation(self):
token = tokens.add_token(
- 'function', key='key',
- fill='fill', ambient='ambient',
- bounce='bounce', rim='rim',
- custom='custom', kick='kick',
- default='custom'
+ "function",
+ key="key",
+ fill="fill",
+ ambient="ambient",
+ bounce="bounce",
+ rim="rim",
+ custom="custom",
+ kick="kick",
+ default="custom",
)
rule = rules.add_rule(
- 'lights',
- '{category}_{function}_{whatAffects}_{digits}_{type}'
+ "lights", "{category}_{function}_{whatAffects}_{digits}_{type}"
)
- tokens.add_token_number('digits')
+ tokens.add_token_number("digits")
assert rules.Rule.from_data(token.data()) is None
assert tokens.Token.from_data(rule.data()) is None
def test_save_load_rule(self):
- rules.add_rule(
- 'test',
- '{category}_{function}_{whatAffects}_{digits}_{type}'
- )
+ rules.add_rule("test", "{category}_{function}_{whatAffects}_{digits}_{type}")
tempdir = tempfile.mkdtemp()
- rules.save_rule('test', tempdir)
+ rules.save_rule("test", tempdir)
rules.reset_rules()
- file_name = "{}.rule".format('test')
+ file_name = "{}.rule".format("test")
filepath = os.path.join(tempdir, file_name)
rules.load_rule(filepath)
- assert rules.has_rule('test') is True
+ assert rules.has_rule("test") is True
def test_save_load_token(self):
tokens.add_token(
- 'test', key='key',
- fill='fill', ambient='ambient',
- bounce='bounce', rim='rim',
- custom='custom', kick='kick',
- default='custom'
+ "test",
+ key="key",
+ fill="fill",
+ ambient="ambient",
+ bounce="bounce",
+ rim="rim",
+ custom="custom",
+ kick="kick",
+ default="custom",
)
tempdir = tempfile.mkdtemp()
- tokens.save_token('test', tempdir)
+ tokens.save_token("test", tempdir)
tokens.reset_tokens()
- file_name = "{}.token".format('test')
+ file_name = "{}.token".format("test")
filepath = os.path.join(tempdir, file_name)
tokens.load_token(filepath)
- assert tokens.has_token('test') is True
+ assert tokens.has_token("test") is True
def test_save_load_token_number(self):
- tokens.add_token_number('test')
+ tokens.add_token_number("test")
tempdir = tempfile.mkdtemp()
- tokens.save_token('test', tempdir)
+ tokens.save_token("test", tempdir)
tokens.reset_tokens()
- file_name = "{}.token".format('test')
+ file_name = "{}.token".format("test")
filepath = os.path.join(tempdir, file_name)
tokens.load_token(filepath)
- assert tokens.has_token('test') is True
+ assert tokens.has_token("test") is True
def test_save_load_session(self):
- tokens.add_token('whatAffects')
- tokens.add_token_number('digits')
- tokens.add_token(
- 'category', natural='natural',
- practical='practical', dramatic='dramatic',
- volumetric='volumetric', default='natural'
- )
+ tokens.add_token("whatAffects")
+ tokens.add_token_number("digits")
tokens.add_token(
- 'function', key='key',
- fill='fill', ambient='ambient',
- bounce='bounce', rim='rim',
- custom='custom', kick='kick',
- default='custom'
+ "category",
+ natural="natural",
+ practical="practical",
+ dramatic="dramatic",
+ volumetric="volumetric",
+ default="natural",
)
tokens.add_token(
- 'type', lighting='LGT',
- animation='ANI', default='lighting'
- )
- rules.add_rule(
- 'lights',
- '{category}.{function}.{whatAffects}.{digits}.{type}'
- )
- rules.add_rule(
- 'test',
- '{category}_{function}'
+ "function",
+ key="key",
+ fill="fill",
+ ambient="ambient",
+ bounce="bounce",
+ rim="rim",
+ custom="custom",
+ kick="kick",
+ default="custom",
)
- rules.set_active_rule('lights')
+ tokens.add_token("type", lighting="LGT", animation="ANI", default="lighting")
+ rules.add_rule("lights", "{category}.{function}.{whatAffects}.{digits}.{type}")
+ rules.add_rule("test", "{category}_{function}")
+ rules.set_active_rule("lights")
repo = tempfile.mkdtemp()
save_result = n.save_session(repo)
@@ -405,11 +404,11 @@ def test_save_load_session(self):
tokens.reset_tokens()
n.load_session(repo)
- assert tokens.has_token('whatAffects') is True
- assert tokens.has_token('digits') is True
- assert tokens.has_token('category') is True
- assert tokens.has_token('function') is True
- assert tokens.has_token('type') is True
- assert rules.has_rule('lights') is True
- assert rules.has_rule('test') is True
- assert rules.get_active_rule().name == 'lights'
+ assert tokens.has_token("whatAffects") is True
+ assert tokens.has_token("digits") is True
+ assert tokens.has_token("category") is True
+ assert tokens.has_token("function") is True
+ assert tokens.has_token("type") is True
+ assert rules.has_rule("lights") is True
+ assert rules.has_rule("test") is True
+ assert rules.get_active_rule().name == "lights"
diff --git a/tests/rules_test.py b/tests/rules_test.py
index 7594120..6693382 100644
--- a/tests/rules_test.py
+++ b/tests/rules_test.py
@@ -1,15 +1,7 @@
-# coding=utf-8
-from __future__ import absolute_import, print_function
-
import vfxnaming.rules as rules
-from vfxnaming import logger
import pytest
-# Debug logging
-logger.init_logger()
-# logger.init_file_logger()
-
class Test_Rule:
@pytest.fixture(autouse=True)
@@ -18,8 +10,7 @@ def setup(self):
def test_add(self):
result = rules.add_rule(
- 'lights',
- '{category}_{function}_{whatAffects}_{digits}_{type}'
+ "lights", "{category}_{function}_{whatAffects}_{digits}_{type}"
)
assert isinstance(result, rules.Rule) is True
@@ -28,20 +19,17 @@ def test_reset_rules(self):
assert result is True
def test_remove_rule(self):
- rules.add_rule('test', '{category}_{function}_{digits}_{type}')
- result = rules.remove_rule('test')
+ rules.add_rule("test", "{category}_{function}_{digits}_{type}")
+ result = rules.remove_rule("test")
assert result is True
- result = rules.remove_rule('test2')
+ result = rules.remove_rule("test2")
assert result is False
def test_active(self):
# pattern = '{category}_{function}_{digits}_{type}'
- rules.add_rule(
- 'lights',
- '{category}_{function}_{whatAffects}_{digits}_{type}'
- )
- rules.add_rule('test', '{category}_{function}_{digits}_{type}')
- rules.set_active_rule('test')
+ rules.add_rule("lights", "{category}_{function}_{whatAffects}_{digits}_{type}")
+ rules.add_rule("test", "{category}_{function}_{digits}_{type}")
+ rules.set_active_rule("test")
result = rules.get_active_rule()
assert result is not None
diff --git a/tests/tokens_test.py b/tests/tokens_test.py
index 9d4b4ae..b6ed878 100644
--- a/tests/tokens_test.py
+++ b/tests/tokens_test.py
@@ -1,17 +1,9 @@
-# coding=utf-8
-from __future__ import absolute_import, print_function
-
from vfxnaming import naming as n
import vfxnaming.rules as rules
import vfxnaming.tokens as tokens
-from vfxnaming import logger
import pytest
-# Debug logging
-logger.init_logger()
-# logger.init_file_logger()
-
class Test_Token:
@pytest.fixture(autouse=True)
@@ -19,13 +11,16 @@ def setup(self):
tokens.reset_tokens()
def test_add(self):
- result = tokens.add_token('whatAffects')
+ result = tokens.add_token("whatAffects")
assert isinstance(result, tokens.Token) is True
result = tokens.add_token(
- 'category', natural='natural',
- practical='practical', dramatic='dramatic',
- volumetric='volumetric', default='natural'
+ "category",
+ natural="natural",
+ practical="practical",
+ dramatic="dramatic",
+ volumetric="volumetric",
+ default="natural",
)
assert isinstance(result, tokens.Token) is True
@@ -34,11 +29,11 @@ def test_reset_tokens(self):
assert result is True
def test_remove_token(self):
- tokens.add_token('test')
- result = tokens.remove_token('test')
+ tokens.add_token("test")
+ result = tokens.remove_token("test")
assert result is True
- result = tokens.remove_token('test2')
+ result = tokens.remove_token("test2")
assert result is False
@@ -47,9 +42,12 @@ class Test_Token_Options:
def setup(self):
tokens.reset_tokens()
self.light_category = tokens.add_token(
- 'category', natural='natural',
- practical='practical', dramatic='dramatic',
- volumetric='volumetric', default='natural'
+ "category",
+ natural="natural",
+ practical="practical",
+ dramatic="dramatic",
+ volumetric="volumetric",
+ default="natural",
)
def test_add_option(self):
@@ -96,83 +94,82 @@ class Test_TokenNumber:
def setup(self):
rules.reset_rules()
tokens.reset_tokens()
- tokens.add_token('whatAffects')
- tokens.add_token_number('number')
+ tokens.add_token("whatAffects")
+ tokens.add_token_number("number")
tokens.add_token(
- 'category', natural='natural',
- practical='practical', dramatic='dramatic',
- volumetric='volumetric', default='natural'
- )
+ "category",
+ natural="natural",
+ practical="practical",
+ dramatic="dramatic",
+ volumetric="volumetric",
+ default="natural",
+ )
tokens.add_token(
- 'function', key='key',
- fill='fill', ambient='ambient',
- bounce='bounce', rim='rim',
- kick='kick', custom='custom',
- default='custom'
- )
- tokens.add_token('type', lighting='LGT', default='LGT')
- rules.add_rule(
- 'lights',
- '{category}_{function}_{whatAffects}_{number}_{type}'
+ "function",
+ key="key",
+ fill="fill",
+ ambient="ambient",
+ bounce="bounce",
+ rim="rim",
+ kick="kick",
+ custom="custom",
+ default="custom",
)
+ tokens.add_token("type", lighting="LGT", default="LGT")
+ rules.add_rule("lights", "{category}_{function}_{whatAffects}_{number}_{type}")
def test_explicit_solve(self):
- name = 'natural_ambient_chars_024_LGT'
+ name = "natural_ambient_chars_024_LGT"
solved = n.solve(
- category='natural', function='ambient',
- whatAffects='chars', number=24, type='lighting'
- )
+ category="natural",
+ function="ambient",
+ whatAffects="chars",
+ number=24,
+ type="lighting",
+ )
assert solved == name
def test_implicit_solve(self):
- name = 'natural_custom_chars_032_LGT'
- solved = n.solve('chars', 32)
+ name = "natural_custom_chars_032_LGT"
+ solved = n.solve("chars", 32)
assert solved == name
def test_prefix_suffix_padding_solve(self):
- name = 'natural_custom_chars_v0032rt_LGT'
- tokens.remove_token('number')
- tokens.add_token_number(
- 'number', prefix='v', suffix='rt', padding=4
- )
- solved = n.solve('chars', 32)
+ name = "natural_custom_chars_v0032rt_LGT"
+ tokens.remove_token("number")
+ tokens.add_token_number("number", prefix="v", suffix="rt", padding=4)
+ solved = n.solve("chars", 32)
assert solved == name
def test_prefix_suffix_padding_parse(self):
- name = 'natural_custom_chars_v0032rt_LGT'
- tokens.remove_token('number')
- tokens.add_token_number(
- 'number', prefix='v', suffix='rt', padding=4
- )
+ name = "natural_custom_chars_v0032rt_LGT"
+ tokens.remove_token("number")
+ tokens.add_token_number("number", prefix="v", suffix="rt", padding=4)
parsed = n.parse(name)
- assert parsed['category'] == 'natural'
- assert parsed['function'] == 'custom'
- assert parsed['whatAffects'] == 'chars'
- assert parsed['number'] == 32
- assert parsed['type'] == 'lighting'
+ assert parsed["category"] == "natural"
+ assert parsed["function"] == "custom"
+ assert parsed["whatAffects"] == "chars"
+ assert parsed["number"] == 32
+ assert parsed["type"] == "lighting"
def test_prefix_only(self):
- name = 'natural_custom_chars_v0078_LGT'
- tokens.remove_token('number')
- tokens.add_token_number(
- 'number', prefix='v', padding=4
- )
+ name = "natural_custom_chars_v0078_LGT"
+ tokens.remove_token("number")
+ tokens.add_token_number("number", prefix="v", padding=4)
parsed = n.parse(name)
- assert parsed['category'] == 'natural'
- assert parsed['function'] == 'custom'
- assert parsed['whatAffects'] == 'chars'
- assert parsed['number'] == 78
- assert parsed['type'] == 'lighting'
+ assert parsed["category"] == "natural"
+ assert parsed["function"] == "custom"
+ assert parsed["whatAffects"] == "chars"
+ assert parsed["number"] == 78
+ assert parsed["type"] == "lighting"
def test_suffix_only(self):
- name = 'natural_custom_chars_0062rt_LGT'
- tokens.remove_token('number')
- tokens.add_token_number(
- 'number', suffix='rt', padding=4
- )
+ name = "natural_custom_chars_0062rt_LGT"
+ tokens.remove_token("number")
+ tokens.add_token_number("number", suffix="rt", padding=4)
parsed = n.parse(name)
- assert parsed['category'] == 'natural'
- assert parsed['function'] == 'custom'
- assert parsed['whatAffects'] == 'chars'
- assert parsed['number'] == 62
- assert parsed['type'] == 'lighting'
+ assert parsed["category"] == "natural"
+ assert parsed["function"] == "custom"
+ assert parsed["whatAffects"] == "chars"
+ assert parsed["number"] == 62
+ assert parsed["type"] == "lighting"
From 3944c62050c68c489db1475a88210c7f2fc54a82 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sun, 4 Aug 2024 12:39:08 -0300
Subject: [PATCH 05/65] Updating format and removing eval statements
---
src/vfxnaming/naming.py | 24 +++++++++++-----------
src/vfxnaming/rules.py | 44 ++++++++++++++---------------------------
src/vfxnaming/tokens.py | 38 ++++++++++++++++-------------------
tests/naming_test.py | 6 +++---
4 files changed, 47 insertions(+), 65 deletions(-)
diff --git a/src/vfxnaming/naming.py b/src/vfxnaming/naming.py
index c6c0723..cb52e2d 100644
--- a/src/vfxnaming/naming.py
+++ b/src/vfxnaming/naming.py
@@ -88,7 +88,7 @@ def solve(*args, **kwargs):
if each in repeated_fields.keys():
counter = repeated_fields.get(each)
repeated_fields[each] = counter + 1
- fields_with_digits.append("{}{}".format(each, counter))
+ fields_with_digits.append(f"{each}{counter}")
else:
fields_with_digits.append(each)
values = dict()
@@ -122,8 +122,8 @@ def solve(*args, **kwargs):
fields_inc += 1
continue
except IndexError as why:
- raise SolvingError("Missing argument for field '{}'\n{}".format(f, why))
- logger.debug("Solving rule '{}' with values {}".format(rule.name, values))
+ raise SolvingError(f"Missing argument for field '{f}'\n{why}")
+ logger.debug(f"Solving rule '{rule.name}' with values {values}")
return rule.solve(**values)
@@ -145,7 +145,7 @@ def get_repo():
config = json.load(fp)
local_repo = os.path.join(userPath, "." + config["local_repo_name"], "naming_repo")
result = env_repo or local_repo
- logger.debug("Repo found: {}".format(result))
+ logger.debug(f"Repo found: {result}")
return result
@@ -169,19 +169,19 @@ def save_session(repo=None):
raise why
# save tokens
for name, token in tokens.get_tokens().items():
- logger.debug("Saving token: '{}' in {}".format(name, repo))
+ logger.debug(f"Saving token: '{name}' in {repo}")
tokens.save_token(name, repo)
# save rules
for name, rule in rules.get_rules().items():
if not isinstance(rule, rules.Rule):
continue
- logger.debug("Saving rule: '{}' in {}".format(name, repo))
+ logger.debug(f"Saving rule: '{name}' in {repo}")
rules.save_rule(name, repo)
# extra configuration
active = rules.get_active_rule()
config = {"set_active_rule": active.name if active else None}
filepath = os.path.join(repo, "naming.conf")
- logger.debug("Saving active rule: {} in {}".format(active.name, filepath))
+ logger.debug(f"Saving active rule: {active.name} in {filepath}")
with open(filepath, "w") as fp:
json.dump(config, fp, indent=4)
return True
@@ -199,11 +199,11 @@ def load_session(repo=None):
"""
repo = repo or get_repo()
if not os.path.exists(repo):
- logger.warning("Given repo directory does not exist: {}".format(repo))
+ logger.warning(f"Given repo directory does not exist: {repo}")
return False
namingconf = os.path.join(repo, "naming.conf")
if not os.path.exists(namingconf):
- logger.warning("Repo is not valid. naming.conf not found {}".format(namingconf))
+ logger.warning(f"Repo is not valid. naming.conf not found {namingconf}")
return False
rules.reset_rules()
tokens.reset_tokens()
@@ -212,14 +212,14 @@ def load_session(repo=None):
for filename in filenames:
filepath = os.path.join(dirpath, filename)
if filename.endswith(".token"):
- logger.debug("Loading token: {}".format(filepath))
+ logger.debug(f"Loading token: {filepath}")
tokens.load_token(filepath)
elif filename.endswith(".rule"):
- logger.debug("Loading rule: {}".format(filepath))
+ logger.debug(f"Loading rule: {filepath}")
rules.load_rule(filepath)
# extra configuration
if os.path.exists(namingconf):
- logger.debug("Loading active rule: {}".format(namingconf))
+ logger.debug(f"Loading active rule: {namingconf}")
with open(namingconf) as fp:
config = json.load(fp)
rules.set_active_rule(config.get("set_active_rule"))
diff --git a/src/vfxnaming/rules.py b/src/vfxnaming/rules.py
index 949a528..f43ccc9 100644
--- a/src/vfxnaming/rules.py
+++ b/src/vfxnaming/rules.py
@@ -93,9 +93,7 @@ def solve(self, **values):
result = self.__digits_pattern().format(**values)
except KeyError as why:
raise SolvingError(
- "Arguments passed do not match with naming rule fields {}\n{}".format(
- self._pattern, why
- )
+ f"Arguments passed do not match with naming rule fields {self._pattern}\n{why}"
)
return result
@@ -117,9 +115,7 @@ def parse(self, name):
expected_separators = self.__PATTERN_SEPARATORS_REGEX.findall(self._pattern)
if len(expected_separators) <= 0:
logger.warning(
- "No separators used for rule '{}', parsing is not possible.".format(
- self.name
- )
+ f"No separators used for rule '{self.name}', parsing is not possible."
)
return None
name_separators = self.__SEPARATORS_REGEX.findall(name)
@@ -128,22 +124,17 @@ def parse(self, name):
match = self._regex.search(name)
if match:
name_parts = sorted(match.groupdict().items())
- logger.debug(
- "Name parts: {}".format(
- ", ".join(
- ["('{}': '{}')".format(k[:-3], v) for k, v in name_parts]
- )
- )
+ name_parts_str = ", ".join(
+ [f"('{k[:-3]}': '{v}')" for k, v in name_parts]
)
+ logger.debug(f"Name parts: {name_parts_str}")
repeated_fields = dict()
for each in self.fields:
if each not in repeated_fields.keys():
if self.fields.count(each) > 1:
repeated_fields[each] = 1
if repeated_fields:
- logger.debug(
- "Repeated tokens: {}".format(", ".join(repeated_fields.keys()))
- )
+ logger.debug(f"Repeated tokens: {', '.join(repeated_fields.keys())}")
for key, value in name_parts:
# Strip number that was added to make group name unique
@@ -154,14 +145,13 @@ def parse(self, name):
if token_name in repeated_fields.keys():
counter = repeated_fields.get(token_name)
repeated_fields[token_name] = counter + 1
- token_name = "{}{}".format(token_name, counter)
+ token_name = f"{token_name}{counter}"
retval[token_name] = token.parse(value)
return retval
else:
raise ParsingError(
- "Separators count mismatch between given name '{}':'{}' and rule's pattern '{}':'{}'.".format(
- name, len(name_separators), self._pattern, len(expected_separators)
- )
+ f"Separators count mismatch between given name '{name}':'{len(name_separators)}' "
+ f"and rule's pattern '{self._pattern}':'{len(expected_separators)}'."
)
def __build_regex(self):
@@ -181,10 +171,10 @@ def __build_regex(self):
if self._anchor is not None:
if bool(self._anchor & self.ANCHOR_START):
- expression = "^{0}".format(expression)
+ expression = f"^{expression}"
if bool(self._anchor & self.ANCHOR_END):
- expression = "{0}$".format(expression)
+ expression = f"{expression}$"
# Compile expression
try:
compiled = re.compile(expression)
@@ -198,7 +188,7 @@ def __build_regex(self):
raise ValueError("Placeholder name contains invalid characters.")
else:
_, value, traceback = sys.exc_info()
- message = "Invalid pattern: {0}".format(value)
+ message = f"Invalid pattern: {value}"
if sys.version_info[0] == 3:
raise ValueError(message).with_traceback(traceback)
elif sys.version_info[0] == 2:
@@ -250,11 +240,7 @@ def __digits_pattern(self):
if repetetions > 1:
i = 0
for match in sorted(indexes, reverse=True):
- digits_pattern = "{}{}{}".format(
- digits_pattern[:match],
- str(repetetions - i),
- digits_pattern[match:],
- )
+ digits_pattern = f"{digits_pattern[:match]}{str(repetetions - i)}{digits_pattern[match:]}"
i += 1
return digits_pattern
@@ -310,7 +296,7 @@ def add_rule(name, pattern, anchor=Rule.ANCHOR_START):
_rules[name] = rule
if get_active_rule() is None:
set_active_rule(name)
- logger.debug("No active rule found, setting this one as active: {}".format(name))
+ logger.debug(f"No active rule found, setting this one as active: {name}")
return rule
@@ -414,7 +400,7 @@ def save_rule(name, directory):
rule = get_rule(name)
if not rule:
return False
- file_name = "{}.rule".format(name)
+ file_name = f"{name}.rule"
filepath = os.path.join(directory, file_name)
with open(filepath, "w") as fp:
json.dump(rule.data(), fp)
diff --git a/src/vfxnaming/tokens.py b/src/vfxnaming/tokens.py
index 142b366..a5428a3 100644
--- a/src/vfxnaming/tokens.py
+++ b/src/vfxnaming/tokens.py
@@ -40,8 +40,8 @@ def add_option(self, key, value):
self._options[key] = value
return True
logger.debug(
- "Option '{}':'{}' already exists in Token '{}'. "
- "Use update_option() instead.".format(key, self._options.get(key), self.name)
+ f"Option '{key}':'{self._options.get(key)}' already exists in Token '{self.name}'. "
+ "Use update_option() instead."
)
return False
@@ -59,8 +59,8 @@ def update_option(self, key, value):
self._options[key] = value
return True
logger.debug(
- "Option '{}':'{}' doesn't exist in Token '{}'. "
- "Use add_option() instead.".format(key, self._options.get(key), self.name)
+ f"Option '{key}':'{self._options.get(key)}' doesn't exist in Token '{self.name}'. "
+ "Use add_option() instead."
)
return False
@@ -77,9 +77,7 @@ def remove_option(self, key):
del self._options[key]
return True
logger.debug(
- "Option '{}':'{}' doesn't exist in Token '{}'. ".format(
- key, self._options.get(key), self.name
- )
+ f"Option '{key}':'{self._options.get(key)}' doesn't exist in Token '{self.name}'"
)
return False
@@ -130,14 +128,13 @@ def solve(self, name=None):
return name
elif self.required and name is None:
raise TokenError(
- "Token {} is required. name parameter must be passed.".format(self.name)
+ f"Token {self.name} is required. name parameter must be passed."
)
elif not self.required and name:
if name not in self._options.keys():
raise TokenError(
- "name '{}' not found in Token '{}'. Options: {}".format(
- name, self.name, ", ".join(self._options.keys())
- )
+ f"name '{name}' not found in Token '{self.name}'. "
+ f"Options: {', '.join(self._options.keys())}"
)
return self._options.get(name)
elif not self.required and not name:
@@ -159,9 +156,8 @@ def parse(self, value):
if v == value:
return k
raise TokenError(
- "Value '{}' not found in Token '{}'. Options: {}".format(
- value, self.name, ", ".join(self._options.values())
- )
+ f"Value '{value}' not found in Token '{self.name}'. "
+ f"Options: {', '.join(self._options.values())}"
)
@property
@@ -223,8 +219,8 @@ def solve(self, number):
Returns:
str: The solved string to be used in the name
"""
- numberStr = str(number).zfill(self.padding)
- return "{}{}{}".format(self.prefix, numberStr, self.suffix)
+ number_str = str(number).zfill(self.padding)
+ return f"{self.prefix}{number_str}{self.suffix}"
def parse(self, value):
"""Get metatada (number) for given value in name. e.g.: v0025 will return 25
@@ -298,7 +294,7 @@ def prefix(self, this_prefix):
if isinstance(this_prefix, str) and not this_prefix.isdigit():
self._options["prefix"] = this_prefix
else:
- logger.warning("Given prefix has to be a string: {}".format(this_prefix))
+ logger.warning(f"Given prefix has to be a string: {this_prefix}")
@property
def suffix(self):
@@ -309,7 +305,7 @@ def suffix(self, this_suffix):
if isinstance(this_suffix, str) and not this_suffix.isdigit():
self._options["suffix"] = this_suffix
else:
- logger.warning("Given suffix has to be a string: {}".format(this_suffix))
+ logger.warning(f"Given suffix has to be a string: {this_suffix}")
@property
def options(self):
@@ -451,7 +447,7 @@ def save_token(name, directory):
token = get_token(name)
if not token:
return False
- file_name = "{}.token".format(name)
+ file_name = f"{name}.token"
filepath = os.path.join(directory, file_name)
with open(filepath, "w") as fp:
json.dump(token.data(), fp)
@@ -476,7 +472,7 @@ def load_token(filepath):
except Exception:
return False
class_name = data.get("_Serializable_classname")
- logger.debug("Loading token type: {}".format(class_name))
- token = eval("{}.from_data(data)".format(class_name))
+ logger.debug(f"Loading token type: {class_name}")
+ token = Token.from_data(data)
_tokens[token.name] = token
return True
diff --git a/tests/naming_test.py b/tests/naming_test.py
index 9cd7aa3..0512ed0 100644
--- a/tests/naming_test.py
+++ b/tests/naming_test.py
@@ -332,7 +332,7 @@ def test_save_load_rule(self):
rules.save_rule("test", tempdir)
rules.reset_rules()
- file_name = "{}.rule".format("test")
+ file_name = "test.rule"
filepath = os.path.join(tempdir, file_name)
rules.load_rule(filepath)
assert rules.has_rule("test") is True
@@ -353,7 +353,7 @@ def test_save_load_token(self):
tokens.save_token("test", tempdir)
tokens.reset_tokens()
- file_name = "{}.token".format("test")
+ file_name = "test.token"
filepath = os.path.join(tempdir, file_name)
tokens.load_token(filepath)
assert tokens.has_token("test") is True
@@ -364,7 +364,7 @@ def test_save_load_token_number(self):
tokens.save_token("test", tempdir)
tokens.reset_tokens()
- file_name = "{}.token".format("test")
+ file_name = "test.token"
filepath = os.path.join(tempdir, file_name)
tokens.load_token(filepath)
assert tokens.has_token("test") is True
From 0e74614ba8a22ab2965b2597c33aebbdae7a4209 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sun, 4 Aug 2024 13:22:52 -0300
Subject: [PATCH 06/65] Adding pathlib and making sure TokenNumber and Token
are taken in load function
---
src/vfxnaming/cfg/config.json | 3 ++-
src/vfxnaming/naming.py | 36 +++++++++++++++++------------------
src/vfxnaming/rules.py | 11 ++++++-----
src/vfxnaming/tokens.py | 22 +++++++++++++--------
tests/naming_test.py | 22 ++++++++++-----------
5 files changed, 51 insertions(+), 43 deletions(-)
diff --git a/src/vfxnaming/cfg/config.json b/src/vfxnaming/cfg/config.json
index 6df3ad8..a173aaa 100644
--- a/src/vfxnaming/cfg/config.json
+++ b/src/vfxnaming/cfg/config.json
@@ -1,3 +1,4 @@
{
- "cfg_dir_name": "CGXTools"
+ "cfg_dir_name": "CGXTools",
+ "local_repo_name": "CGXTools"
}
\ No newline at end of file
diff --git a/src/vfxnaming/naming.py b/src/vfxnaming/naming.py
index cb52e2d..ea326d5 100644
--- a/src/vfxnaming/naming.py
+++ b/src/vfxnaming/naming.py
@@ -16,12 +16,12 @@
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
-from __future__ import absolute_import, print_function
-
import os
import json
import vfxnaming.rules as rules
import vfxnaming.tokens as tokens
+from pathlib import Path
+
from vfxnaming.logger import logger
from vfxnaming.error import SolvingError
@@ -134,19 +134,19 @@ def get_repo():
Environment varialble name: NAMING_REPO
Returns:
- str: Naming repository location
+ Path: Naming repository location
"""
env_repo = os.environ.get(NAMING_REPO_ENV)
- userPath = os.path.expanduser("~")
- module_dir = os.path.split(__file__)[0]
- config_location = os.path.join(module_dir, "cfg", "config.json")
+ user_path = Path.expanduser("~")
+ module_dir = Path(__file__).parent
+ config_location = module_dir / "cfg/config.json"
config = dict()
with open(config_location) as fp:
config = json.load(fp)
- local_repo = os.path.join(userPath, "." + config["local_repo_name"], "naming_repo")
+ local_repo = user_path / f".{config['local_repo_name']}/naming_repo"
result = env_repo or local_repo
logger.debug(f"Repo found: {result}")
- return result
+ return Path(result)
def save_session(repo=None):
@@ -161,10 +161,10 @@ def save_session(repo=None):
Returns:
bool: True if saving session operation was successful.
"""
- repo = repo or get_repo()
- if not os.path.exists(repo):
+ repo: Path = repo or get_repo()
+ if not repo.exists():
try:
- os.mkdir(repo)
+ repo.mkdir(parents=True)
except (IOError, OSError) as why:
raise why
# save tokens
@@ -180,7 +180,7 @@ def save_session(repo=None):
# extra configuration
active = rules.get_active_rule()
config = {"set_active_rule": active.name if active else None}
- filepath = os.path.join(repo, "naming.conf")
+ filepath = repo / "naming.conf"
logger.debug(f"Saving active rule: {active.name} in {filepath}")
with open(filepath, "w") as fp:
json.dump(config, fp, indent=4)
@@ -197,12 +197,12 @@ def load_session(repo=None):
Returns:
bool: True if loading session operation was successful.
"""
- repo = repo or get_repo()
- if not os.path.exists(repo):
+ repo: Path = repo or get_repo()
+ if not repo.exists():
logger.warning(f"Given repo directory does not exist: {repo}")
return False
- namingconf = os.path.join(repo, "naming.conf")
- if not os.path.exists(namingconf):
+ namingconf = repo / "naming.conf"
+ if not namingconf.exists():
logger.warning(f"Repo is not valid. naming.conf not found {namingconf}")
return False
rules.reset_rules()
@@ -210,7 +210,7 @@ def load_session(repo=None):
# tokens and rules
for dirpath, dirnames, filenames in os.walk(repo):
for filename in filenames:
- filepath = os.path.join(dirpath, filename)
+ filepath = Path(dirpath) / filename
if filename.endswith(".token"):
logger.debug(f"Loading token: {filepath}")
tokens.load_token(filepath)
@@ -218,7 +218,7 @@ def load_session(repo=None):
logger.debug(f"Loading rule: {filepath}")
rules.load_rule(filepath)
# extra configuration
- if os.path.exists(namingconf):
+ if namingconf.exists():
logger.debug(f"Loading active rule: {namingconf}")
with open(namingconf) as fp:
config = json.load(fp)
diff --git a/src/vfxnaming/rules.py b/src/vfxnaming/rules.py
index f43ccc9..43bfa76 100644
--- a/src/vfxnaming/rules.py
+++ b/src/vfxnaming/rules.py
@@ -1,9 +1,10 @@
import re
import json
-import os
import sys
import functools
+from pathlib import Path
from collections import defaultdict
+
from vfxnaming.serialize import Serializable
from vfxnaming.tokens import get_token
from vfxnaming.logger import logger
@@ -386,7 +387,7 @@ def get_rules():
return _rules
-def save_rule(name, directory):
+def save_rule(name, directory: Path):
"""Saves given rule serialized to specified location.
Args:
@@ -401,13 +402,13 @@ def save_rule(name, directory):
if not rule:
return False
file_name = f"{name}.rule"
- filepath = os.path.join(directory, file_name)
+ filepath = directory / file_name
with open(filepath, "w") as fp:
json.dump(rule.data(), fp)
return True
-def load_rule(filepath):
+def load_rule(filepath: Path):
"""Load rule from given location and create Rule object in memory to work with it.
Args:
@@ -416,7 +417,7 @@ def load_rule(filepath):
Returns:
bool: True if successful, False if .rule wasn't found.
"""
- if not os.path.isfile(filepath):
+ if not filepath.is_file():
return False
try:
with open(filepath) as fp:
diff --git a/src/vfxnaming/tokens.py b/src/vfxnaming/tokens.py
index a5428a3..af998de 100644
--- a/src/vfxnaming/tokens.py
+++ b/src/vfxnaming/tokens.py
@@ -1,6 +1,7 @@
import copy
import json
-import os
+from pathlib import Path
+
from vfxnaming.serialize import Serializable
from vfxnaming.logger import logger
from vfxnaming.error import TokenError
@@ -434,7 +435,7 @@ def get_tokens():
return _tokens
-def save_token(name, directory):
+def save_token(name, directory: Path):
"""Saves given token serialized to specified location.
Args:
@@ -448,13 +449,13 @@ def save_token(name, directory):
if not token:
return False
file_name = f"{name}.token"
- filepath = os.path.join(directory, file_name)
+ filepath = directory / file_name
with open(filepath, "w") as fp:
json.dump(token.data(), fp)
return True
-def load_token(filepath):
+def load_token(filepath: Path):
"""Load token from given location and create Token or TokenNumber object in
memory to work with it.
@@ -464,7 +465,7 @@ def load_token(filepath):
Returns:
bool: True if successful, False if .token wasn't found.
"""
- if not os.path.isfile(filepath):
+ if not filepath.is_file():
return False
try:
with open(filepath) as fp:
@@ -473,6 +474,11 @@ def load_token(filepath):
return False
class_name = data.get("_Serializable_classname")
logger.debug(f"Loading token type: {class_name}")
- token = Token.from_data(data)
- _tokens[token.name] = token
- return True
+ token_class = globals().get(class_name)
+ if token_class is None:
+ return False
+ token = getattr(token_class, "from_data")(data)
+ if token:
+ _tokens[token.name] = token
+ return True
+ return False
diff --git a/tests/naming_test.py b/tests/naming_test.py
index 0512ed0..28f9a27 100644
--- a/tests/naming_test.py
+++ b/tests/naming_test.py
@@ -1,12 +1,12 @@
+from pathlib import Path
+import pytest
+import tempfile
+
from vfxnaming import naming as n
import vfxnaming.rules as rules
import vfxnaming.tokens as tokens
from vfxnaming.error import ParsingError, SolvingError, TokenError
-import os
-import pytest
-import tempfile
-
class Test_Solve:
@pytest.fixture(autouse=True)
@@ -328,12 +328,12 @@ def test_validation(self):
def test_save_load_rule(self):
rules.add_rule("test", "{category}_{function}_{whatAffects}_{digits}_{type}")
- tempdir = tempfile.mkdtemp()
+ tempdir = Path(tempfile.mkdtemp())
rules.save_rule("test", tempdir)
rules.reset_rules()
file_name = "test.rule"
- filepath = os.path.join(tempdir, file_name)
+ filepath = tempdir / file_name
rules.load_rule(filepath)
assert rules.has_rule("test") is True
@@ -349,23 +349,23 @@ def test_save_load_token(self):
kick="kick",
default="custom",
)
- tempdir = tempfile.mkdtemp()
+ tempdir = Path(tempfile.mkdtemp())
tokens.save_token("test", tempdir)
tokens.reset_tokens()
file_name = "test.token"
- filepath = os.path.join(tempdir, file_name)
+ filepath = tempdir / file_name
tokens.load_token(filepath)
assert tokens.has_token("test") is True
def test_save_load_token_number(self):
tokens.add_token_number("test")
- tempdir = tempfile.mkdtemp()
+ tempdir = Path(tempfile.mkdtemp())
tokens.save_token("test", tempdir)
tokens.reset_tokens()
file_name = "test.token"
- filepath = os.path.join(tempdir, file_name)
+ filepath = tempdir / file_name
tokens.load_token(filepath)
assert tokens.has_token("test") is True
@@ -396,7 +396,7 @@ def test_save_load_session(self):
rules.add_rule("test", "{category}_{function}")
rules.set_active_rule("lights")
- repo = tempfile.mkdtemp()
+ repo = Path(tempfile.mkdtemp())
save_result = n.save_session(repo)
assert save_result is True
From 721f128a356528a0a3e32aea3016fb2deff717c6 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sun, 4 Aug 2024 13:46:59 -0300
Subject: [PATCH 07/65] Working on typing hints to improve readability
---
src/vfxnaming/logger.py | 33 ++++++++++++++++++---------------
src/vfxnaming/naming.py | 19 ++++++++++---------
src/vfxnaming/rules.py | 29 +++++++++++++----------------
3 files changed, 41 insertions(+), 40 deletions(-)
diff --git a/src/vfxnaming/logger.py b/src/vfxnaming/logger.py
index ea539ab..bc36459 100644
--- a/src/vfxnaming/logger.py
+++ b/src/vfxnaming/logger.py
@@ -3,6 +3,7 @@
import json
from datetime import date
from pathlib import Path
+from typing import AnyStr, Tuple
class Logger:
@@ -15,7 +16,7 @@ def __init__(self, logger_name, propagate=False):
self.file_handler = None
@property
- def logger_obj(self):
+ def logger_obj(self) -> logging.Logger:
if not self.__logger_obj:
if self.logger_exists(self.name):
self.__logger_obj = logging.getLogger(self.name)
@@ -36,35 +37,35 @@ def logger_obj(self):
return self.__logger_obj
@staticmethod
- def logger_exists(name):
+ def logger_exists(name: AnyStr) -> bool:
return name in logging.Logger.manager.loggerDict.keys()
def set_level(self, level):
self.logger_obj.setLevel(level)
- def debug(self, msg, *args, **kwargs):
+ def debug(self, msg: AnyStr, *args, **kwargs):
self.logger_obj.debug(msg, *args, **kwargs)
- def info(self, msg, *args, **kwargs):
+ def info(self, msg: AnyStr, *args, **kwargs):
self.logger_obj.info(msg, *args, **kwargs)
- def warning(self, msg, *args, **kwargs):
+ def warning(self, msg: AnyStr, *args, **kwargs):
self.logger_obj.warning(msg, *args, **kwargs)
- def error(self, msg, *args, **kwargs):
+ def error(self, msg: AnyStr, *args, **kwargs):
self.logger_obj.error(msg, *args, **kwargs)
- def critical(self, msg, *args, **kwargs):
+ def critical(self, msg: AnyStr, *args, **kwargs):
self.logger_obj.critical(msg, *args, **kwargs)
- def log(self, level, msg, *args, **kwargs):
+ def log(self, level, msg: AnyStr, *args, **kwargs):
self.logger_obj.log(level, msg, *args, **kwargs)
- def exception(self, msg, *args, **kwargs):
+ def exception(self, msg: AnyStr, *args, **kwargs):
self.logger_obj.exception(msg, *args, **kwargs)
def log_to_file(self, level=logging.DEBUG):
- log_file_path = self.get_log_file_path()
+ log_file_path: Path = self.get_log_file_path()
try:
if not log_file_path.parent.exists():
@@ -89,22 +90,24 @@ def stop_logging_to_file(self):
self.file_handler.close()
self.file_handler = None
- def get_log_file_path(self):
+ def get_log_file_path(self) -> Path:
user_path = Path("~").expanduser()
module_dir = Path(__file__).parents[0]
- config_location = module_dir.joinpath("cfg", "config.json")
+ config_location = module_dir / "cfg/config.json"
config = {}
with open(config_location) as fp:
config = json.load(fp)
- final_dir = user_path.joinpath(f".{config.get('cfg_dir_name')}")
+ final_dir = user_path / f".{config.get('cfg_dir_name')}"
today = date.today()
date_string = today.strftime("%d-%m-%Y")
- log_file_path = final_dir.joinpath(f"{self.logger_obj.name}_{date_string}.log")
+ log_file_path = final_dir / f"{self.logger_obj.name}_{date_string}.log"
return log_file_path
-def init_logger(base_name, log_to_file=False):
+def init_logger(
+ base_name: AnyStr, log_to_file: bool = False
+) -> Tuple[logging.Logger, logging.Logger]:
"""
Initialize 'base_name' logging object and add a STDOUT handler to output to
console, terminal, etc.
diff --git a/src/vfxnaming/naming.py b/src/vfxnaming/naming.py
index ea326d5..0684000 100644
--- a/src/vfxnaming/naming.py
+++ b/src/vfxnaming/naming.py
@@ -21,6 +21,7 @@
import vfxnaming.rules as rules
import vfxnaming.tokens as tokens
from pathlib import Path
+from typing import AnyStr, Dict, Union
from vfxnaming.logger import logger
from vfxnaming.error import SolvingError
@@ -29,7 +30,7 @@
NAMING_REPO_ENV = "NAMING_REPO"
-def parse(name):
+def parse(name: AnyStr) -> Dict:
"""Get metadata from a name string recognized by the currently active rule.
-For rules with repeated tokens:
@@ -49,7 +50,7 @@ def parse(name):
return rule.parse(name)
-def solve(*args, **kwargs):
+def solve(*args, **kwargs) -> AnyStr:
"""Given arguments are used to build a name following currently active rule.
-For rules with repeated tokens:
@@ -76,7 +77,7 @@ def solve(*args, **kwargs):
Returns:
str: A string with the resulting name.
"""
- rule = rules.get_active_rule()
+ rule: rules.Rule = rules.get_active_rule()
# * This accounts for those cases where a token is used more than once in a rule
repeated_fields = dict()
for each in rule.fields:
@@ -91,7 +92,7 @@ def solve(*args, **kwargs):
fields_with_digits.append(f"{each}{counter}")
else:
fields_with_digits.append(each)
- values = dict()
+ values = {}
i = 0
fields_inc = 0
for f in fields_with_digits:
@@ -127,7 +128,7 @@ def solve(*args, **kwargs):
return rule.solve(**values)
-def get_repo():
+def get_repo() -> Path:
"""Get repository location from either global environment variable or local user,
giving priority to environment variable.
@@ -149,14 +150,14 @@ def get_repo():
return Path(result)
-def save_session(repo=None):
+def save_session(repo: Union[Path, None] = None) -> bool:
"""Save rules, tokens and config files to the repository.
Raises:
IOError, OSError: Repository directory could not be created.
Args:
- repo (str, optional): Absolue path to a repository. Defaults to None.
+ repo (Path, optional): Absolue path to a repository. Defaults to None.
Returns:
bool: True if saving session operation was successful.
@@ -187,12 +188,12 @@ def save_session(repo=None):
return True
-def load_session(repo=None):
+def load_session(repo: Union[Path, None] = None) -> bool:
"""Load rules, tokens and config from a repository, and create
Python objects in memory to work with them.
Args:
- repo (str, optional): Absolute path to a repository. Defaults to None.
+ repo (Path, optional): Absolute path to a repository. Defaults to None.
Returns:
bool: True if loading session operation was successful.
diff --git a/src/vfxnaming/rules.py b/src/vfxnaming/rules.py
index 43bfa76..b1422eb 100644
--- a/src/vfxnaming/rules.py
+++ b/src/vfxnaming/rules.py
@@ -4,6 +4,7 @@
import functools
from pathlib import Path
from collections import defaultdict
+from typing import Dict, AnyStr, Union
from vfxnaming.serialize import Serializable
from vfxnaming.tokens import get_token
@@ -44,7 +45,7 @@ def __init__(self, name, pattern, anchor=ANCHOR_START):
self._anchor = anchor
self._regex = self.__build_regex()
- def data(self):
+ def data(self) -> Dict:
"""Collect all data for this object instance.
Returns:
@@ -59,7 +60,7 @@ def data(self):
return retval
@classmethod
- def from_data(cls, data):
+ def from_data(cls, data) -> "Rule":
"""Create object instance from give data. Used by Rule,
Token, Separator to create object instances from disk saved data.
@@ -79,7 +80,7 @@ def from_data(cls, data):
this = cls(data.get("_name"), data.get("_pattern"), data.get("_anchor"))
return this
- def solve(self, **values):
+ def solve(self, **values) -> AnyStr:
"""Given arguments are used to build a name.
Raises:
@@ -99,7 +100,7 @@ def solve(self, **values):
return result
- def parse(self, name):
+ def parse(self, name: AnyStr) -> Union[Dict, None]:
"""Build and return dictionary with keys as tokens and values as given names.
If your rule uses the same token more than once, the returned dictionary keys
@@ -155,7 +156,7 @@ def parse(self, name):
f"and rule's pattern '{self._pattern}':'{len(expected_separators)}'."
)
- def __build_regex(self):
+ def __build_regex(self) -> re.Pattern:
# ? Taken from Lucidity by Martin Pengelly-Phillips
# Escape non-placeholder components
expression = re.sub(
@@ -190,14 +191,11 @@ def __build_regex(self):
else:
_, value, traceback = sys.exc_info()
message = f"Invalid pattern: {value}"
- if sys.version_info[0] == 3:
- raise ValueError(message).with_traceback(traceback)
- elif sys.version_info[0] == 2:
- raise ValueError(message, traceback)
+ raise ValueError(message).with_traceback(traceback)
return compiled
- def __convert(self, match, placeholder_count):
+ def __convert(self, match: re.Match, placeholder_count: int) -> AnyStr:
"""Return a regular expression to represent *match*.
``placeholder_count`` should be a ``defaultdict(int)`` that will be used to
@@ -222,16 +220,15 @@ def __convert(self, match, placeholder_count):
return r"(?P<{0}>{1})".format(placeholder_name, expression)
- def __escape(self, match):
+ def __escape(self, match: re.Match) -> AnyStr:
"""Escape matched 'other' group value."""
# ? Taken from Lucidity by Martin Pengelly-Phillips
groups = match.groupdict()
- if groups["other"] is not None:
- return re.escape(groups["other"])
+ if groups.get("other"):
+ return re.escape(groups.get("other"))
+ return groups.get("placeholder")
- return groups["placeholder"]
-
- def __digits_pattern(self):
+ def __digits_pattern(self) -> AnyStr:
# * This accounts for those cases where a token is used more than once in a rule
digits_pattern = self._pattern
for each in list(set(self.fields)):
From 1c143f68ec83ee9943375ce0e7ddd75ee8d220a7 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sun, 4 Aug 2024 16:05:35 -0300
Subject: [PATCH 08/65] Typing hints
---
src/vfxnaming/rules.py | 40 ++++++++---------
src/vfxnaming/serialize.py | 5 ++-
src/vfxnaming/tokens.py | 89 ++++++++++++++++++++------------------
3 files changed, 69 insertions(+), 65 deletions(-)
diff --git a/src/vfxnaming/rules.py b/src/vfxnaming/rules.py
index b1422eb..c9af793 100644
--- a/src/vfxnaming/rules.py
+++ b/src/vfxnaming/rules.py
@@ -4,7 +4,7 @@
import functools
from pathlib import Path
from collections import defaultdict
-from typing import Dict, AnyStr, Union
+from typing import Dict, AnyStr, Union, Tuple
from vfxnaming.serialize import Serializable
from vfxnaming.tokens import get_token
@@ -40,10 +40,10 @@ class Rule(Serializable):
def __init__(self, name, pattern, anchor=ANCHOR_START):
super(Rule, self).__init__()
- self._name = name
- self._pattern = pattern
- self._anchor = anchor
- self._regex = self.__build_regex()
+ self._name: str = name
+ self._pattern: str = pattern
+ self._anchor: int = anchor
+ self._regex: re.Pattern = self.__build_regex()
def data(self) -> Dict:
"""Collect all data for this object instance.
@@ -243,11 +243,11 @@ def __digits_pattern(self) -> AnyStr:
return digits_pattern
@property
- def pattern(self):
+ def pattern(self) -> AnyStr:
return self._pattern
@property
- def fields(self):
+ def fields(self) -> Tuple:
"""
Returns:
[tuple]: Tuple of all Tokens found in this Rule's pattern
@@ -255,7 +255,7 @@ def fields(self):
return tuple(self.__FIELDS_REGEX.findall(self._pattern))
@property
- def regex(self):
+ def regex(self) -> re.Pattern:
"""
Returns:
[str]: Regular expression used to parse from this Rule
@@ -263,15 +263,15 @@ def regex(self):
return self._regex
@property
- def name(self):
+ def name(self) -> AnyStr:
return self._name
@name.setter
- def name(self, n):
+ def name(self, n: str):
self._name = n
-def add_rule(name, pattern, anchor=Rule.ANCHOR_START):
+def add_rule(name: str, pattern: str, anchor=Rule.ANCHOR_START) -> Rule:
"""Add rule to current naming session. If no active rule is found, it adds
the created one as active by default.
@@ -298,7 +298,7 @@ def add_rule(name, pattern, anchor=Rule.ANCHOR_START):
return rule
-def remove_rule(name):
+def remove_rule(name: AnyStr) -> bool:
"""Remove Rule from current session.
Args:
@@ -313,7 +313,7 @@ def remove_rule(name):
return False
-def has_rule(name):
+def has_rule(name: AnyStr) -> bool:
"""Test if current session has a rule with given name.
Args:
@@ -325,7 +325,7 @@ def has_rule(name):
return name in _rules.keys()
-def reset_rules():
+def reset_rules() -> bool:
"""Clears all rules created for current session.
Returns:
@@ -336,7 +336,7 @@ def reset_rules():
return True
-def get_active_rule():
+def get_active_rule() -> Rule:
"""Get currently active rule for the session. This is the rule
that will be used to parse and solve from.
@@ -347,7 +347,7 @@ def get_active_rule():
return _rules.get(name)
-def set_active_rule(name):
+def set_active_rule(name: AnyStr) -> bool:
"""Sets given rule as active for the session. This it the rule that's
being used to parse and solve from.
@@ -363,7 +363,7 @@ def set_active_rule(name):
return False
-def get_rule(name):
+def get_rule(name: AnyStr) -> Rule:
"""Gets Rule object with given name.
Args:
@@ -375,7 +375,7 @@ def get_rule(name):
return _rules.get(name)
-def get_rules():
+def get_rules() -> Dict:
"""Get all Rule objects for current session.
Returns:
@@ -384,7 +384,7 @@ def get_rules():
return _rules
-def save_rule(name, directory: Path):
+def save_rule(name: AnyStr, directory: Path) -> bool:
"""Saves given rule serialized to specified location.
Args:
@@ -405,7 +405,7 @@ def save_rule(name, directory: Path):
return True
-def load_rule(filepath: Path):
+def load_rule(filepath: Path) -> bool:
"""Load rule from given location and create Rule object in memory to work with it.
Args:
diff --git a/src/vfxnaming/serialize.py b/src/vfxnaming/serialize.py
index 7f2661b..b1e2ad4 100644
--- a/src/vfxnaming/serialize.py
+++ b/src/vfxnaming/serialize.py
@@ -1,8 +1,9 @@
+from typing import Dict
import copy
class Serializable(object):
- def data(self):
+ def data(self) -> Dict:
"""Collect all data for this object instance.
Returns:
@@ -14,7 +15,7 @@ def data(self):
return retval
@classmethod
- def from_data(cls, data):
+ def from_data(cls, data: Dict) -> "Serializable":
"""Create object instance from give data. Used by Rule,
Token, Separator to create object instances from disk saved data.
diff --git a/src/vfxnaming/tokens.py b/src/vfxnaming/tokens.py
index af998de..af4e414 100644
--- a/src/vfxnaming/tokens.py
+++ b/src/vfxnaming/tokens.py
@@ -1,6 +1,7 @@
import copy
import json
from pathlib import Path
+from typing import AnyStr, Dict, Union
from vfxnaming.serialize import Serializable
from vfxnaming.logger import logger
@@ -11,7 +12,7 @@
class Token(Serializable):
- def __init__(self, name):
+ def __init__(self, name: AnyStr):
"""Tokens are the meaningful parts of a naming rule. A token can be required,
meaning fully typed by the user, or can have a set of default options preconfigured.
If options are present, then one of them is the default one.
@@ -23,11 +24,11 @@ def __init__(self, name):
to invoke the Token object.
"""
super(Token, self).__init__()
- self._name = name
+ self._name: AnyStr = name
self._default = None
- self._options = dict()
+ self._options: Dict = {}
- def add_option(self, key, value):
+ def add_option(self, key: AnyStr, value: AnyStr) -> bool:
"""Add an option pair to this Token.
Args:
@@ -46,7 +47,7 @@ def add_option(self, key, value):
)
return False
- def update_option(self, key, value):
+ def update_option(self, key: AnyStr, value: AnyStr) -> bool:
"""Update an option pair on this Token.
Args:
@@ -65,7 +66,7 @@ def update_option(self, key, value):
)
return False
- def remove_option(self, key):
+ def remove_option(self, key: AnyStr) -> bool:
"""Remove an option on this Token.
Args:
@@ -82,7 +83,7 @@ def remove_option(self, key):
)
return False
- def has_option_fullname(self, key):
+ def has_option_fullname(self, key: AnyStr) -> bool:
"""Looks for given option full name in the options.
Args:
@@ -95,7 +96,7 @@ def has_option_fullname(self, key):
return True
return False
- def has_option_abbreviation(self, value):
+ def has_option_abbreviation(self, value: AnyStr) -> bool:
"""Looks for given option abbreviation in the options.
Args:
@@ -108,7 +109,7 @@ def has_option_abbreviation(self, value):
return True
return False
- def solve(self, name=None):
+ def solve(self, name: Union[AnyStr, None] = None) -> AnyStr:
"""Solve for abbreviation given a certain name. e.g.: center could return C
Args:
@@ -141,7 +142,7 @@ def solve(self, name=None):
elif not self.required and not name:
return self._options.get(self.default)
- def parse(self, value):
+ def parse(self, value: AnyStr) -> AnyStr:
"""Get metatada (origin) for given value in name. e.g.: L could return left
Args:
@@ -162,20 +163,20 @@ def parse(self, value):
)
@property
- def required(self):
+ def required(self) -> bool:
return self.default is None
@property
- def name(self):
+ def name(self) -> AnyStr:
return self._name
@name.setter
- def name(self, n):
+ def name(self, n: AnyStr):
self._name = n
@property
- def default(self):
- """If Token has options, one of them will be default. Eitther passed by the user,
+ def default(self) -> AnyStr:
+ """If Token has options, one of them will be default. Either passed by the user,
or simply the first found item in options.
Returns:
@@ -186,16 +187,16 @@ def default(self):
return self._default
@default.setter
- def default(self, d):
+ def default(self, d: AnyStr):
self._default = d
@property
- def options(self):
+ def options(self) -> Dict:
return copy.deepcopy(self._options)
class TokenNumber(Serializable):
- def __init__(self, name):
+ def __init__(self, name: AnyStr):
"""Token for numbers with the ability to handle pure digits and version like strings
(e.g.: v0025) with padding settings.
@@ -206,11 +207,11 @@ def __init__(self, name):
to invoke the Token object.
"""
super(TokenNumber, self).__init__()
- self._name = name
- self._default = 1
- self._options = {"prefix": "", "suffix": "", "padding": 3}
+ self._name: AnyStr = name
+ self._default: int = 1
+ self._options: Dict = {"prefix": "", "suffix": "", "padding": 3}
- def solve(self, number):
+ def solve(self, number: int) -> AnyStr:
"""Solve for number with prefix, suffix and padding parameter found in the instance
options. e.g.: 1 with padding 3, will return 001
@@ -223,7 +224,7 @@ def solve(self, number):
number_str = str(number).zfill(self.padding)
return f"{self.prefix}{number_str}{self.suffix}"
- def parse(self, value):
+ def parse(self, value: AnyStr) -> int:
"""Get metatada (number) for given value in name. e.g.: v0025 will return 25
Args:
@@ -261,59 +262,59 @@ def parse(self, value):
return int(value[prefix_index:-suffix_index])
@property
- def name(self):
+ def name(self) -> AnyStr:
return self._name
@name.setter
- def name(self, n):
+ def name(self, n: AnyStr):
self._name = n
@property
- def default(self):
+ def default(self) -> AnyStr:
return self._default
@property
- def required(self):
+ def required(self) -> bool:
return True
@property
- def padding(self):
+ def padding(self) -> int:
return self._options.get("padding")
@padding.setter
- def padding(self, p):
+ def padding(self, p: int):
if p <= 0:
p = 1
self._options["padding"] = int(p)
@property
- def prefix(self):
+ def prefix(self) -> AnyStr:
return self._options.get("prefix")
@prefix.setter
- def prefix(self, this_prefix):
+ def prefix(self, this_prefix: AnyStr):
if isinstance(this_prefix, str) and not this_prefix.isdigit():
self._options["prefix"] = this_prefix
else:
logger.warning(f"Given prefix has to be a string: {this_prefix}")
@property
- def suffix(self):
+ def suffix(self) -> AnyStr:
return self._options.get("suffix")
@suffix.setter
- def suffix(self, this_suffix):
+ def suffix(self, this_suffix: AnyStr):
if isinstance(this_suffix, str) and not this_suffix.isdigit():
self._options["suffix"] = this_suffix
else:
logger.warning(f"Given suffix has to be a string: {this_suffix}")
@property
- def options(self):
+ def options(self) -> Dict:
return copy.deepcopy(self._options)
-def add_token(name, **kwargs):
+def add_token(name: AnyStr, **kwargs) -> Token:
"""Add token to current naming session. If 'default' keyword argument is found,
set it as default for the token instance.
@@ -351,7 +352,9 @@ def add_token(name, **kwargs):
return token
-def add_token_number(name, prefix=str(), suffix=str(), padding=3):
+def add_token_number(
+ name, prefix: AnyStr = "", suffix: AnyStr = "", padding: int = 3
+) -> TokenNumber:
"""Add token number to current naming session.
Args:
@@ -377,7 +380,7 @@ def add_token_number(name, prefix=str(), suffix=str(), padding=3):
return token
-def remove_token(name):
+def remove_token(name: AnyStr) -> bool:
"""Remove Token or TokenNumber from current session.
Args:
@@ -392,7 +395,7 @@ def remove_token(name):
return False
-def has_token(name):
+def has_token(name: AnyStr) -> bool:
"""Test if current session has a token with given name.
Args:
@@ -404,7 +407,7 @@ def has_token(name):
return name in _tokens.keys()
-def reset_tokens():
+def reset_tokens() -> bool:
"""Clears all rules created for current session.
Returns:
@@ -414,7 +417,7 @@ def reset_tokens():
return True
-def get_token(name):
+def get_token(name: AnyStr) -> Union[Token, TokenNumber, None]:
"""Gets Token or TokenNumber object with given name.
Args:
@@ -426,7 +429,7 @@ def get_token(name):
return _tokens.get(name)
-def get_tokens():
+def get_tokens() -> Dict:
"""Get all Token and TokenNumber objects for current session.
Returns:
@@ -435,7 +438,7 @@ def get_tokens():
return _tokens
-def save_token(name, directory: Path):
+def save_token(name: AnyStr, directory: Path) -> bool:
"""Saves given token serialized to specified location.
Args:
@@ -455,7 +458,7 @@ def save_token(name, directory: Path):
return True
-def load_token(filepath: Path):
+def load_token(filepath: Path) -> bool:
"""Load token from given location and create Token or TokenNumber object in
memory to work with it.
From 78eced5a2be3b153f40a05943b1a2cb23a8c852c Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sun, 4 Aug 2024 16:37:12 -0300
Subject: [PATCH 09/65] Parameterize explicit solve test
---
tests/naming_test.py | 41 +++++++++++++++++++++++++++++++----------
1 file changed, 31 insertions(+), 10 deletions(-)
diff --git a/tests/naming_test.py b/tests/naming_test.py
index 28f9a27..ed45af5 100644
--- a/tests/naming_test.py
+++ b/tests/naming_test.py
@@ -1,6 +1,7 @@
from pathlib import Path
import pytest
import tempfile
+from typing import Dict
from vfxnaming import naming as n
import vfxnaming.rules as rules
@@ -37,16 +38,36 @@ def setup(self):
rules.reset_rules()
rules.add_rule("lights", "{category}_{function}_{whatAffects}_{digits}_{type}")
- def test_explicit(self):
- name = "natural_ambient_chars_001_LGT"
- solved = n.solve(
- category="natural",
- function="ambient",
- whatAffects="chars",
- digits=1,
- type="lighting",
- )
- assert solved == name
+ @pytest.mark.parametrize(
+ "name,solve_data,expected",
+ [
+ (
+ "natural_ambient_chars_001_LGT",
+ {
+ "category": "natural",
+ "function": "ambient",
+ "whatAffects": "chars",
+ "digits": 1,
+ "type": "lighting",
+ },
+ True,
+ ),
+ (
+ "natural_key_env_010_LGT",
+ {
+ "category": "natural",
+ "function": "ambient",
+ "whatAffects": "chars",
+ "digits": 1,
+ "type": "lighting",
+ },
+ False,
+ ),
+ ],
+ )
+ def test_explicit(self, name: str, solve_data: Dict, expected: bool):
+ solved = n.solve(**solve_data)
+ assert (solved == name) is expected
def test_no_match_for_token(self):
with pytest.raises(TokenError) as exception:
From 72316fc84d56d1ea70b9c212cb5117dd0ccdf4c8 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sun, 4 Aug 2024 16:54:14 -0300
Subject: [PATCH 10/65] Parameterize defaults tests
---
tests/naming_test.py | 49 +++++++++++++++++++++++++++++---------------
1 file changed, 32 insertions(+), 17 deletions(-)
diff --git a/tests/naming_test.py b/tests/naming_test.py
index ed45af5..aa0eeb2 100644
--- a/tests/naming_test.py
+++ b/tests/naming_test.py
@@ -70,36 +70,51 @@ def test_explicit(self, name: str, solve_data: Dict, expected: bool):
assert (solved == name) is expected
def test_no_match_for_token(self):
- with pytest.raises(TokenError) as exception:
+ with pytest.raises(TokenError):
n.solve(
category="natural",
- function="sarasa",
+ function="whatever",
whatAffects="chars",
digits=1,
type="lighting",
)
- assert str(exception.value).startswith("name") is True
def test_missing_required_token(self):
- with pytest.raises(SolvingError) as exception:
+ with pytest.raises(SolvingError):
n.solve(category="natural", function="key", digits=1, type="lighting")
- assert str(exception.value).startswith("Token") is True
def test_missing_not_required_token(self):
- with pytest.raises(SolvingError) as exception:
+ with pytest.raises(SolvingError):
n.solve("chars")
- assert str(exception.value).startswith("Missing argument for field") is True
- def test_defaults(self):
- name = "natural_custom_chars_001_LGT"
- solved = n.solve(
- category="natural", whatAffects="chars", digits=1, type="lighting"
- )
- assert solved == name
-
- name = "natural_custom_chars_001_LGT"
- solved = n.solve(whatAffects="chars", digits=1)
- assert solved == name
+ @pytest.mark.parametrize(
+ "name,solve_data,expected",
+ [
+ (
+ "natural_custom_chars_001_LGT",
+ {
+ "category": "natural",
+ "whatAffects": "chars",
+ "digits": 1,
+ "type": "lighting",
+ },
+ True,
+ ),
+ (
+ "natural_custom_chars_001_LGT",
+ {"whatAffects": "chars", "digits": 1},
+ True,
+ ),
+ (
+ "whatever_nondefault_chars_001_LGT",
+ {"whatAffects": "chars", "digits": 1},
+ False,
+ ),
+ ],
+ )
+ def test_defaults(self, name: str, solve_data: Dict, expected: bool):
+ solved = n.solve(**solve_data)
+ assert (solved == name) is expected
def test_implicit(self):
name = "natural_custom_chars_001_ANI"
From 02aebeb78cad74dac2775fa3163f652576896bef Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sun, 4 Aug 2024 17:03:06 -0300
Subject: [PATCH 11/65] Parameterize implicit solving test
---
tests/naming_test.py | 26 ++++++++++++++++++--------
1 file changed, 18 insertions(+), 8 deletions(-)
diff --git a/tests/naming_test.py b/tests/naming_test.py
index aa0eeb2..470f034 100644
--- a/tests/naming_test.py
+++ b/tests/naming_test.py
@@ -1,7 +1,7 @@
from pathlib import Path
import pytest
import tempfile
-from typing import Dict
+from typing import Dict, List
from vfxnaming import naming as n
import vfxnaming.rules as rules
@@ -116,13 +116,23 @@ def test_defaults(self, name: str, solve_data: Dict, expected: bool):
solved = n.solve(**solve_data)
assert (solved == name) is expected
- def test_implicit(self):
- name = "natural_custom_chars_001_ANI"
- solved = n.solve("chars", 1, type="animation")
- assert solved == name
-
- name = "natural_custom_chars_001_LGT"
- solved = n.solve("chars", 1)
+ @pytest.mark.parametrize(
+ "name,solve_args,solve_kwargs",
+ [
+ (
+ "natural_custom_chars_001_ANI",
+ ["chars", 1],
+ {"type": "animation"},
+ ),
+ (
+ "natural_custom_chars_001_LGT",
+ ["chars", 1],
+ {},
+ ),
+ ],
+ )
+ def test_implicit(self, name: str, solve_args: List, solve_kwargs: Dict):
+ solved = n.solve(*solve_args, **solve_kwargs)
assert solved == name
From 4ef373d30da382b7b4557cb0364b5ef55b3fcc00 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sun, 4 Aug 2024 17:15:22 -0300
Subject: [PATCH 12/65] Parameterize parsing tests
---
tests/naming_test.py | 35 ++++++++++++++++++++++++++++-------
1 file changed, 28 insertions(+), 7 deletions(-)
diff --git a/tests/naming_test.py b/tests/naming_test.py
index 470f034..2d769d1 100644
--- a/tests/naming_test.py
+++ b/tests/naming_test.py
@@ -163,16 +163,37 @@ def setup(self):
)
tokens.add_token("type", lighting="LGT", animation="ANI", default="lighting")
- def test_parsing_with_separators(self):
+ @pytest.mark.parametrize(
+ "name,parsed_data",
+ [
+ (
+ "dramatic_bounce_chars_001_LGT",
+ {
+ "category": "dramatic",
+ "function": "bounce",
+ "whatAffects": "chars",
+ "digits": 1,
+ "type": "lighting",
+ },
+ ),
+ (
+ "natural_key_env_012_ANI",
+ {
+ "category": "natural",
+ "function": "key",
+ "whatAffects": "env",
+ "digits": 12,
+ "type": "animation",
+ },
+ ),
+ ],
+ )
+ def test_parsing_with_separators(self, name: str, parsed_data: Dict):
rules.reset_rules()
rules.add_rule("lights", "{category}_{function}_{whatAffects}_{digits}_{type}")
- name = "dramatic_bounce_chars_001_LGT"
parsed = n.parse(name)
- assert parsed["category"] == "dramatic"
- assert parsed["function"] == "bounce"
- assert parsed["whatAffects"] == "chars"
- assert parsed["digits"] == 1
- assert parsed["type"] == "lighting"
+ for key, value in parsed_data.items():
+ assert parsed.get(key) == value
def test_parsing_without_separators(self):
rules.reset_rules()
From ab7ad6d7f0b6a5896e2856c43bf06d80ef8238a1 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sun, 4 Aug 2024 17:26:58 -0300
Subject: [PATCH 13/65] Parameterize repeated tokens
---
tests/naming_test.py | 38 ++++++++++++++++++++++++++++----------
1 file changed, 28 insertions(+), 10 deletions(-)
diff --git a/tests/naming_test.py b/tests/naming_test.py
index 2d769d1..7ba08e6 100644
--- a/tests/naming_test.py
+++ b/tests/naming_test.py
@@ -220,16 +220,34 @@ def setup(self):
)
rules.add_rule("filename", "{side}-{region}_{side}-{region}_{side}-{region}")
- def test_parse_repeated_tokens(self):
- name = "C-FRONT_L-ORBI_R-ZYGO"
- expected = {
- "side1": "center",
- "region1": "frontal",
- "side2": "left",
- "region2": "orbital",
- "side3": "right",
- "region3": "zygomatic",
- }
+ @pytest.mark.parametrize(
+ "name,expected",
+ [
+ (
+ "C-FRONT_L-ORBI_R-ZYGO",
+ {
+ "side1": "center",
+ "region1": "frontal",
+ "side2": "left",
+ "region2": "orbital",
+ "side3": "right",
+ "region3": "zygomatic",
+ },
+ ),
+ (
+ "R-MENT_C-PAROT_L-RETMAND",
+ {
+ "side1": "right",
+ "region1": "mental",
+ "side2": "center",
+ "region2": "parotidmasseter",
+ "side3": "left",
+ "region3": "retromandibularfossa",
+ },
+ ),
+ ],
+ )
+ def test_parse_repeated_tokens(self, name: str, expected: Dict):
result = n.parse(name)
assert result == expected
From c828ed02797fa848f9e2c525024bd5c2f00046da Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sun, 4 Aug 2024 17:48:34 -0300
Subject: [PATCH 14/65] Parameterize repeating tokens
---
tests/naming_test.py | 108 +++++++++++++++++++++++++++++++------------
1 file changed, 78 insertions(+), 30 deletions(-)
diff --git a/tests/naming_test.py b/tests/naming_test.py
index 7ba08e6..072c1fd 100644
--- a/tests/naming_test.py
+++ b/tests/naming_test.py
@@ -253,42 +253,90 @@ def test_parse_repeated_tokens(self, name: str, expected: Dict):
def test_parse_repeated_tokens_missing_some(self):
name = "C-FRONT_-ORBI_R"
- with pytest.raises(ParsingError) as exception:
+ with pytest.raises(ParsingError):
n.parse(name)
- assert str(exception.value).startswith("Separators count mismatch") is True
-
- def test_solve_repeated_tokens(self):
- name = "C-MENT_L-PAROT_R-RETMAND"
- result = n.solve(
- side1="center",
- side2="left",
- side3="right",
- region1="mental",
- region2="parotidmasseter",
- region3="retromandibularfossa",
- )
+ @pytest.mark.parametrize(
+ "name,data",
+ [
+ (
+ "C-MENT_L-PAROT_R-RETMAND",
+ {
+ "side1": "center",
+ "side2": "left",
+ "side3": "right",
+ "region1": "mental",
+ "region2": "parotidmasseter",
+ "region3": "retromandibularfossa",
+ },
+ ),
+ (
+ "C-FRONT_R-ORBI_L-ZYGO",
+ {
+ "side1": "center",
+ "side2": "right",
+ "side3": "left",
+ "region1": "frontal",
+ "region2": "orbital",
+ "region3": "zygomatic",
+ },
+ ),
+ ],
+ )
+ def test_solve_repeated_tokens(self, name: str, data: Dict):
+ result = n.solve(**data)
assert result == name
- def test_solve_repeat_one_token(self):
- name = "L-MENT_L-PAROT_L-RETMAND"
- result = n.solve(
- side="left",
- region1="mental",
- region2="parotidmasseter",
- region3="retromandibularfossa",
- )
-
+ @pytest.mark.parametrize(
+ "name,data",
+ [
+ (
+ "L-MENT_L-PAROT_L-RETMAND",
+ {
+ "side": "left",
+ "region1": "mental",
+ "region2": "parotidmasseter",
+ "region3": "retromandibularfossa",
+ },
+ ),
+ (
+ "R-FRONT_R-FRONT_R-FRONT",
+ {
+ "side1": "right",
+ "side2": "right",
+ "side3": "right",
+ "region": "frontal",
+ },
+ ),
+ ],
+ )
+ def test_solve_repeat_one_token(self, name: str, data: Dict):
+ result = n.solve(**data)
assert result == name
- def test_solve_repeated_missing_some(self):
- name = "C-FRONT_C-PAROT_R-RETMAND"
- result = n.solve(
- side1="center",
- side3="right",
- region2="parotidmasseter",
- region3="retromandibularfossa",
- )
+ @pytest.mark.parametrize(
+ "name,data",
+ [
+ (
+ "C-FRONT_C-PAROT_R-RETMAND",
+ {
+ "side3": "right",
+ "region2": "parotidmasseter",
+ "region3": "retromandibularfossa",
+ },
+ ),
+ (
+ "L-FRONT_C-RETMAND_R-FRONT",
+ {
+ "side1": "left",
+ "side3": "right",
+ "region2": "retromandibularfossa",
+ },
+ ),
+ ],
+ )
+ def test_solve_repeated_missing_some(self, name: str, data: Dict):
+ result = n.solve(**data)
assert result == name
From 2a38c9003519053aa38b81b0c0c49798c1a4e234 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sun, 4 Aug 2024 18:36:57 -0300
Subject: [PATCH 15/65] Parameterization of anchor tests
---
tests/naming_test.py | 85 ++++++++++++++++++++++++++++++++++----------
1 file changed, 66 insertions(+), 19 deletions(-)
diff --git a/tests/naming_test.py b/tests/naming_test.py
index 072c1fd..c524f89 100644
--- a/tests/naming_test.py
+++ b/tests/naming_test.py
@@ -346,69 +346,116 @@ def setup(self):
tokens.reset_tokens()
tokens.add_token("awesometoken")
- def test_solve_anchoring_end(self):
+ @pytest.mark.parametrize(
+ "anchor_position,expected",
+ [
+ (rules.Rule.ANCHOR_END, True),
+ (rules.Rule.ANCHOR_BOTH, True),
+ (rules.Rule.ANCHOR_START, True),
+ ],
+ )
+ def test_solve_anchoring_end(self, anchor_position: int, expected: bool):
rules.reset_rules()
rules.add_rule(
- "anchoring", "crazy_hardcoded_value_{awesometoken}", rules.Rule.ANCHOR_END
+ "anchoring", "crazy_hardcoded_value_{awesometoken}", anchor_position
)
-
name = "crazy_hardcoded_value_bye"
solved = n.solve("bye")
- assert solved == name
+ assert (solved == name) is expected
- def test_solve_anchoring_both(self):
+ @pytest.mark.parametrize(
+ "anchor_position,expected",
+ [
+ (rules.Rule.ANCHOR_END, True),
+ (rules.Rule.ANCHOR_BOTH, True),
+ (rules.Rule.ANCHOR_START, True),
+ ],
+ )
+ def test_solve_anchoring_both(self, anchor_position: int, expected: bool):
rules.reset_rules()
rules.add_rule(
"anchoring",
"{awesometoken}_crazy_hardcoded_value_{awesometoken}",
- rules.Rule.ANCHOR_BOTH,
+ anchor_position,
)
name = "hello_crazy_hardcoded_value_bye"
solved = n.solve(awesometoken1="hello", awesometoken2="bye")
- assert solved == name
+ assert (solved == name) is expected
- def test_solve_anchoring_start(self):
+ @pytest.mark.parametrize(
+ "anchor_position,expected",
+ [
+ (rules.Rule.ANCHOR_END, True),
+ (rules.Rule.ANCHOR_BOTH, True),
+ (rules.Rule.ANCHOR_START, True),
+ ],
+ )
+ def test_solve_anchoring_start(self, anchor_position: int, expected: bool):
rules.reset_rules()
rules.add_rule(
- "anchoring", "{awesometoken}_crazy_hardcoded_value", rules.Rule.ANCHOR_START
+ "anchoring", "{awesometoken}_crazy_hardcoded_value", anchor_position
)
name = "hello_crazy_hardcoded_value"
solved = n.solve(awesometoken="hello")
- assert solved == name
+ assert (solved == name) is expected
- def test_parse_anchoring_end(self):
+ @pytest.mark.parametrize(
+ "anchor_position,expected",
+ [
+ (rules.Rule.ANCHOR_END, True),
+ (rules.Rule.ANCHOR_BOTH, True),
+ (rules.Rule.ANCHOR_START, True),
+ ],
+ )
+ def test_parse_anchoring_end(self, anchor_position: int, expected: bool):
rules.reset_rules()
rules.add_rule(
- "anchoring", "crazy_hardcoded_value_{awesometoken}", rules.Rule.ANCHOR_END
+ "anchoring", "crazy_hardcoded_value_{awesometoken}", anchor_position
)
name = "crazy_hardcoded_value_bye"
parsed = n.parse(name)
- assert parsed == {"awesometoken": "bye"}
+ assert (parsed == {"awesometoken": "bye"}) is expected
- def test_parse_anchoring_both(self):
+ @pytest.mark.parametrize(
+ "anchor_position,expected",
+ [
+ (rules.Rule.ANCHOR_END, True),
+ (rules.Rule.ANCHOR_BOTH, True),
+ (rules.Rule.ANCHOR_START, True),
+ ],
+ )
+ def test_parse_anchoring_both(self, anchor_position: int, expected: bool):
rules.reset_rules()
rules.add_rule(
"anchoring",
"{awesometoken}_crazy_hardcoded_value_{awesometoken}",
- rules.Rule.ANCHOR_BOTH,
+ anchor_position,
)
name = "hello_crazy_hardcoded_value_bye"
parsed = n.parse(name)
- assert parsed == {"awesometoken1": "hello", "awesometoken2": "bye"}
+ assert (parsed == {"awesometoken1": "hello", "awesometoken2": "bye"}) is expected
- def test_parse_anchoring_start(self):
+ @pytest.mark.parametrize(
+ "anchor_position,expected",
+ [
+ (rules.Rule.ANCHOR_END, True),
+ (rules.Rule.ANCHOR_BOTH, True),
+ (rules.Rule.ANCHOR_START, True),
+ ],
+ )
+ def test_parse_anchoring_start(self, anchor_position: int, expected: bool):
rules.reset_rules()
rules.add_rule(
- "anchoring", "{awesometoken}_crazy_hardcoded_value", rules.Rule.ANCHOR_START
+ "anchoring", "{awesometoken}_crazy_hardcoded_value", anchor_position
)
name = "hello_crazy_hardcoded_value"
parsed = n.parse(name)
- assert parsed == {"awesometoken": "hello"}
+ assert (parsed == {"awesometoken": "hello"}) is expected
class Test_Serialization:
From ba8372da6b254f3d00a0c2a17186710fed6064e7 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sun, 4 Aug 2024 19:16:08 -0300
Subject: [PATCH 16/65] More parameterization on naming tests
---
tests/naming_test.py | 59 ++++++++++++++++++++++++++++++++------------
1 file changed, 43 insertions(+), 16 deletions(-)
diff --git a/tests/naming_test.py b/tests/naming_test.py
index c524f89..81838bd 100644
--- a/tests/naming_test.py
+++ b/tests/naming_test.py
@@ -464,25 +464,52 @@ def setup(self):
rules.reset_rules()
tokens.reset_tokens()
- def test_tokens(self):
- token1 = tokens.add_token(
- "function",
- key="key",
- fill="fill",
- ambient="ambient",
- bounce="bounce",
- rim="rim",
- custom="custom",
- kick="kick",
- default="custom",
- )
+ @pytest.mark.parametrize(
+ "name,options",
+ [
+ (
+ "function",
+ {
+ "key": "key",
+ "fill": "fill",
+ "ambient": "ambient",
+ "bounce": "bounce",
+ "rim": "rim",
+ "custom": "custom",
+ "kick": "kick",
+ "default": "custom",
+ },
+ ),
+ (
+ "side",
+ {
+ "left": "left",
+ "right": "right",
+ "center": "center",
+ },
+ ),
+ ],
+ )
+ def test_tokens(self, name: str, options: Dict):
+ token1 = tokens.add_token(name, **options)
token2 = tokens.Token.from_data(token1.data())
assert token1.data() == token2.data()
- def test_rules(self):
- rule1 = rules.add_rule(
- "lights", "{category}_{function}_{whatAffects}_{digits}_{type}"
- )
+ @pytest.mark.parametrize(
+ "name,pattern",
+ [
+ (
+ "lights",
+ "{category}_{function}_{whatAffects}_{digits}_{type}",
+ ),
+ (
+ "filename",
+ "{side}-{region}_{side}-{region}_{side}-{region}",
+ ),
+ ],
+ )
+ def test_rules(self, name: str, pattern: str):
+ rule1 = rules.add_rule(name, pattern)
rule2 = rules.Rule.from_data(rule1.data())
assert rule1.data() == rule2.data()
From db14be82b9a254902c19ec320f6b176dfd111d7b Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sun, 4 Aug 2024 19:20:12 -0300
Subject: [PATCH 17/65] Remove comment
---
tests/rules_test.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/tests/rules_test.py b/tests/rules_test.py
index 6693382..8a542e8 100644
--- a/tests/rules_test.py
+++ b/tests/rules_test.py
@@ -27,7 +27,6 @@ def test_remove_rule(self):
assert result is False
def test_active(self):
- # pattern = '{category}_{function}_{digits}_{type}'
rules.add_rule("lights", "{category}_{function}_{whatAffects}_{digits}_{type}")
rules.add_rule("test", "{category}_{function}_{digits}_{type}")
rules.set_active_rule("test")
From f535ba3d969816d64fe5fc10583b2071c96198bb Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sun, 4 Aug 2024 19:26:43 -0300
Subject: [PATCH 18/65] WIP rules tests parameterization
---
tests/rules_test.py | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/tests/rules_test.py b/tests/rules_test.py
index 8a542e8..749f274 100644
--- a/tests/rules_test.py
+++ b/tests/rules_test.py
@@ -8,11 +8,17 @@ class Test_Rule:
def setup(self):
rules.reset_rules()
- def test_add(self):
- result = rules.add_rule(
- "lights", "{category}_{function}_{whatAffects}_{digits}_{type}"
- )
- assert isinstance(result, rules.Rule) is True
+ @pytest.mark.parametrize(
+ "name,pattern,expected",
+ [
+ ("lights", "{category}_{function}_{whatAffects}_{digits}_{type}", True),
+ ("filename", "{side}-{region}_{side}-{region}_{side}-{region}", True),
+ ("nope", "", False), # TODO: Working here, this shouldn't be passing
+ ],
+ )
+ def test_add(self, name: str, pattern: str, expected: bool):
+ result = rules.add_rule(name, pattern)
+ assert isinstance(result, rules.Rule) is expected
def test_reset_rules(self):
result = rules.reset_rules()
From aa898fcbfbd3fe8a08f499ae988d181d371e6df4 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Mon, 5 Aug 2024 20:39:40 -0300
Subject: [PATCH 19/65] Validate basic rule creation parameters
---
src/vfxnaming/rules.py | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/src/vfxnaming/rules.py b/src/vfxnaming/rules.py
index c9af793..e7c4805 100644
--- a/src/vfxnaming/rules.py
+++ b/src/vfxnaming/rules.py
@@ -271,7 +271,7 @@ def name(self, n: str):
self._name = n
-def add_rule(name: str, pattern: str, anchor=Rule.ANCHOR_START) -> Rule:
+def add_rule(name: str, pattern: str, anchor=Rule.ANCHOR_START) -> Union[str, None]:
"""Add rule to current naming session. If no active rule is found, it adds
the created one as active by default.
@@ -288,8 +288,17 @@ def add_rule(name: str, pattern: str, anchor=Rule.ANCHOR_START) -> Rule:
match the pattern. Defaults to ANCHOR_START.
Returns:
- Rule: The Rule object instance created for given name and fields.
+ Rule: The Rule object instance created for given name and fields. None if
"""
+ if pattern == "":
+ logger.error(f"Pattern cannot be empty for rule: {name}")
+ return
+ if name == "":
+ logger.error(f"Name cannot be empty for rule: {pattern}")
+ return
+ if anchor not in [Rule.ANCHOR_START, Rule.ANCHOR_END, Rule.ANCHOR_BOTH]:
+ logger.error(f"Invalid anchor value for rule: {name}")
+ return
rule = Rule(name, pattern, anchor)
_rules[name] = rule
if get_active_rule() is None:
From 638c8956e9a876919149780c9ed81bb0acc33014 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Mon, 5 Aug 2024 20:44:00 -0300
Subject: [PATCH 20/65] Rules tests parametrization
---
src/vfxnaming/rules.py | 2 +-
tests/rules_test.py | 21 +++++++++++++--------
2 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/src/vfxnaming/rules.py b/src/vfxnaming/rules.py
index e7c4805..df6be1c 100644
--- a/src/vfxnaming/rules.py
+++ b/src/vfxnaming/rules.py
@@ -271,7 +271,7 @@ def name(self, n: str):
self._name = n
-def add_rule(name: str, pattern: str, anchor=Rule.ANCHOR_START) -> Union[str, None]:
+def add_rule(name: str, pattern: str, anchor=Rule.ANCHOR_START) -> Union[Rule, None]:
"""Add rule to current naming session. If no active rule is found, it adds
the created one as active by default.
diff --git a/tests/rules_test.py b/tests/rules_test.py
index 749f274..2f712dc 100644
--- a/tests/rules_test.py
+++ b/tests/rules_test.py
@@ -13,7 +13,7 @@ def setup(self):
[
("lights", "{category}_{function}_{whatAffects}_{digits}_{type}", True),
("filename", "{side}-{region}_{side}-{region}_{side}-{region}", True),
- ("nope", "", False), # TODO: Working here, this shouldn't be passing
+ ("nope", "", False),
],
)
def test_add(self, name: str, pattern: str, expected: bool):
@@ -24,17 +24,22 @@ def test_reset_rules(self):
result = rules.reset_rules()
assert result is True
- def test_remove_rule(self):
+ @pytest.mark.parametrize(
+ "name,expected",
+ [
+ ("test", True),
+ ("test2", False),
+ ],
+ )
+ def test_remove_rule(self, name: str, expected: bool):
rules.add_rule("test", "{category}_{function}_{digits}_{type}")
- result = rules.remove_rule("test")
- assert result is True
-
- result = rules.remove_rule("test2")
- assert result is False
+ result = rules.remove_rule(name)
+ assert result is expected
def test_active(self):
rules.add_rule("lights", "{category}_{function}_{whatAffects}_{digits}_{type}")
- rules.add_rule("test", "{category}_{function}_{digits}_{type}")
+ test_rule = rules.add_rule("test", "{category}_{function}_{digits}_{type}")
rules.set_active_rule("test")
result = rules.get_active_rule()
assert result is not None
+ assert result is test_rule
From 584c4568d48dc47a95f11b2a22ea9d230d810aec Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Mon, 5 Aug 2024 21:12:22 -0300
Subject: [PATCH 21/65] Wip token tests parametrization
---
tests/tokens_test.py | 203 ++++++++++++++++++++++++++++---------------
1 file changed, 133 insertions(+), 70 deletions(-)
diff --git a/tests/tokens_test.py b/tests/tokens_test.py
index b6ed878..b448fa3 100644
--- a/tests/tokens_test.py
+++ b/tests/tokens_test.py
@@ -1,3 +1,5 @@
+from typing import List
+
from vfxnaming import naming as n
import vfxnaming.rules as rules
import vfxnaming.tokens as tokens
@@ -10,31 +12,41 @@ class Test_Token:
def setup(self):
tokens.reset_tokens()
- def test_add(self):
- result = tokens.add_token("whatAffects")
- assert isinstance(result, tokens.Token) is True
-
- result = tokens.add_token(
- "category",
- natural="natural",
- practical="practical",
- dramatic="dramatic",
- volumetric="volumetric",
- default="natural",
- )
+ @pytest.mark.parametrize(
+ "name,kwargs",
+ [
+ ("test", {}),
+ (
+ "category",
+ {
+ "natural": "natural",
+ "practical": "practical",
+ "dramatic": "dramatic",
+ "volumetric": "volumetric",
+ "default": "natural",
+ },
+ ),
+ ],
+ )
+ def test_add(self, name: str, kwargs):
+ result = tokens.add_token(name, **kwargs)
assert isinstance(result, tokens.Token) is True
def test_reset_tokens(self):
result = tokens.reset_tokens()
assert result is True
- def test_remove_token(self):
+ @pytest.mark.parametrize(
+ "name,expected",
+ [
+ ("test", True),
+ ("test2", False),
+ ],
+ )
+ def test_remove_token(self, name: str, expected: bool):
tokens.add_token("test")
- result = tokens.remove_token("test")
- assert result is True
-
- result = tokens.remove_token("test2")
- assert result is False
+ result = tokens.remove_token(name)
+ assert result is expected
class Test_Token_Options:
@@ -50,43 +62,60 @@ def setup(self):
default="natural",
)
- def test_add_option(self):
- result = self.light_category.add_option("extra", "extra")
- assert result is True
- assert "extra" in self.light_category.options.keys()
-
- result = self.light_category.add_option("dramatic", "DRA")
- assert result is False
-
- def test_remove_option(self):
- result = self.light_category.remove_option("natural")
- assert result is True
- assert "natural" not in self.light_category.options.keys()
-
- result = self.light_category.remove_option("non_existent")
- assert result is False
-
- def test_update_option(self):
- result = self.light_category.update_option("natural", "unnatural")
- assert result is True
- assert "unnatural" in self.light_category.options.values()
-
- result = self.light_category.update_option("non_existent", "unnatural")
- assert result is False
-
- def test_has_option_fullname(self):
- result = self.light_category.has_option_fullname("dramatic")
- assert result is True
-
- result = self.light_category.has_option_fullname("default")
- assert result is False
-
- def test_has_option_abbreviation(self):
- result = self.light_category.has_option_abbreviation("volumetric")
- assert result is True
-
- result = self.light_category.has_option_abbreviation("VOL")
- assert result is False
+ @pytest.mark.parametrize(
+ "key,abbreviation,expected",
+ [
+ ("extra", "extra", True),
+ ("dramatic", "DRA", False),
+ ],
+ )
+ def test_add_option(self, key: str, abbreviation: str, expected: bool):
+ result = self.light_category.add_option(key, abbreviation)
+ assert result is expected
+
+ @pytest.mark.parametrize(
+ "key,expected",
+ [
+ ("natural", True),
+ ("non_existent", False),
+ ],
+ )
+ def test_remove_option(self, key: str, expected: bool):
+ result = self.light_category.remove_option(key)
+ assert result is expected
+
+ @pytest.mark.parametrize(
+ "old_key,new_key,expected",
+ [
+ ("natural", "unnatural", True),
+ ("non_existent", "unnatural", False),
+ ],
+ )
+ def test_update_option(self, old_key: str, new_key: str, expected: bool):
+ result = self.light_category.update_option(old_key, new_key)
+ assert result is expected
+
+ @pytest.mark.parametrize(
+ "full_name,expected",
+ [
+ ("dramatic", True),
+ ("default", False),
+ ],
+ )
+ def test_has_option_fullname(self, full_name: str, expected: bool):
+ result = self.light_category.has_option_fullname(full_name)
+ assert result is expected
+
+ @pytest.mark.parametrize(
+ "abbreviation,expected",
+ [
+ ("volumetric", True),
+ ("VOL", False),
+ ],
+ )
+ def test_has_option_abbreviation(self, abbreviation: str, expected: bool):
+ result = self.light_category.has_option_abbreviation(abbreviation)
+ assert result is expected
class Test_TokenNumber:
@@ -118,21 +147,55 @@ def setup(self):
tokens.add_token("type", lighting="LGT", default="LGT")
rules.add_rule("lights", "{category}_{function}_{whatAffects}_{number}_{type}")
- def test_explicit_solve(self):
- name = "natural_ambient_chars_024_LGT"
- solved = n.solve(
- category="natural",
- function="ambient",
- whatAffects="chars",
- number=24,
- type="lighting",
- )
- assert solved == name
-
- def test_implicit_solve(self):
- name = "natural_custom_chars_032_LGT"
- solved = n.solve("chars", 32)
- assert solved == name
+ @pytest.mark.parametrize(
+ "name,data,expected",
+ [
+ (
+ "natural_ambient_chars_024_LGT",
+ {
+ "category": "natural",
+ "function": "ambient",
+ "whatAffects": "chars",
+ "number": 24,
+ "type": "lighting",
+ },
+ True,
+ ),
+ (
+ "natural_ambient_chars_3_LGT",
+ {
+ "category": "natural",
+ "function": "ambient",
+ "whatAffects": "chars",
+ "number": 3,
+ "type": "lighting",
+ },
+ False,
+ ),
+ ],
+ )
+ def test_explicit_solve(self, name: str, data: dict, expected: bool):
+ solved = n.solve(**data)
+ assert (solved == name) is expected
+
+ @pytest.mark.parametrize(
+ "name,data,expected",
+ [
+ (
+ "natural_custom_chars_032_LGT",
+ ["chars", 32],
+ True,
+ ),
+ (
+ "natural_custom_chars_3_LGT",
+ ["chars", 3],
+ False,
+ ),
+ ],
+ )
+ def test_implicit_solve(self, name: str, data: List, expected: bool):
+ solved = n.solve(*data)
+ assert (solved == name) is expected
def test_prefix_suffix_padding_solve(self):
name = "natural_custom_chars_v0032rt_LGT"
From 3ded37b4e0bf423404abf2513fec7ab7f66ba624 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Mon, 5 Aug 2024 22:18:16 -0300
Subject: [PATCH 22/65] Tokens tests parametrization finished
---
src/vfxnaming/tokens.py | 9 ++++++++-
tests/tokens_test.py | 32 ++++++++++++++++++++++++--------
2 files changed, 32 insertions(+), 9 deletions(-)
diff --git a/src/vfxnaming/tokens.py b/src/vfxnaming/tokens.py
index af4e414..26d7934 100644
--- a/src/vfxnaming/tokens.py
+++ b/src/vfxnaming/tokens.py
@@ -225,7 +225,7 @@ def solve(self, number: int) -> AnyStr:
return f"{self.prefix}{number_str}{self.suffix}"
def parse(self, value: AnyStr) -> int:
- """Get metatada (number) for given value in name. e.g.: v0025 will return 25
+ """Get metadata (number) for given value in name. e.g.: v0025 will return 25
Args:
value (str): String value taken from a name with digits in it.
@@ -254,6 +254,13 @@ def parse(self, value: AnyStr) -> int:
break
suffix_index += 1
+ if prefix_index != -1 and self.prefix != "":
+ if value[prefix_index : len(self.prefix)] != self.prefix:
+ logger.warning(f"Prefix '{self.prefix}' not found in '{value}'")
+ if suffix_index != -1 and self.suffix != "":
+ if value[-suffix_index:] != self.suffix:
+ logger.warning(f"Suffix '{self.suffix}' not found in '{value}'")
+
if prefix_index == -1 and suffix_index >= 0:
return int(value[:-suffix_index])
elif prefix_index >= 0 and suffix_index == -1:
diff --git a/tests/tokens_test.py b/tests/tokens_test.py
index b448fa3..2520efb 100644
--- a/tests/tokens_test.py
+++ b/tests/tokens_test.py
@@ -197,28 +197,44 @@ def test_implicit_solve(self, name: str, data: List, expected: bool):
solved = n.solve(*data)
assert (solved == name) is expected
- def test_prefix_suffix_padding_solve(self):
- name = "natural_custom_chars_v0032rt_LGT"
+ @pytest.mark.parametrize(
+ "name,prefix,suffix,padding",
+ [
+ ("natural_custom_chars_v0032rt_LGT", "v", "rt", 4),
+ ("natural_custom_chars_ver32X_LGT", "ver", "X", 2),
+ ],
+ )
+ def test_prefix_suffix_padding_solve(
+ self, name: str, prefix: str, suffix: str, padding: int
+ ):
tokens.remove_token("number")
- tokens.add_token_number("number", prefix="v", suffix="rt", padding=4)
+ tokens.add_token_number("number", prefix=prefix, suffix=suffix, padding=padding)
solved = n.solve("chars", 32)
assert solved == name
- def test_prefix_suffix_padding_parse(self):
- name = "natural_custom_chars_v0032rt_LGT"
+ @pytest.mark.parametrize(
+ "name,prefix,suffix,padding,num",
+ [
+ ("natural_custom_chars_v0076rt_LGT", "v", "rt", 4, 76),
+ ("natural_custom_chars_ver1850X_LGT", "ver", "X", 2, 1850),
+ ],
+ )
+ def test_prefix_suffix_padding_parse(
+ self, name: str, prefix: str, suffix: str, padding: int, num: int
+ ):
tokens.remove_token("number")
- tokens.add_token_number("number", prefix="v", suffix="rt", padding=4)
+ tokens.add_token_number("number", prefix=prefix, suffix=suffix, padding=padding)
parsed = n.parse(name)
assert parsed["category"] == "natural"
assert parsed["function"] == "custom"
assert parsed["whatAffects"] == "chars"
- assert parsed["number"] == 32
+ assert parsed["number"] == num
assert parsed["type"] == "lighting"
def test_prefix_only(self):
name = "natural_custom_chars_v0078_LGT"
tokens.remove_token("number")
- tokens.add_token_number("number", prefix="v", padding=4)
+ tokens.add_token_number("number", prefix="W", padding=4)
parsed = n.parse(name)
assert parsed["category"] == "natural"
assert parsed["function"] == "custom"
From 870da79de865dc911d4a245bc4c896d1b09606fe Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Mon, 5 Aug 2024 22:34:31 -0300
Subject: [PATCH 23/65] Update docs
---
docs/source/changelog.rst | 11 ++++++++++
docs/source/conf.py | 46 +++++++++++----------------------------
docs/source/index.rst | 9 ++++----
docs/source/roadmap.rst | 4 +++-
4 files changed, 31 insertions(+), 39 deletions(-)
diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst
index 7332224..e5ba8c5 100644
--- a/docs/source/changelog.rst
+++ b/docs/source/changelog.rst
@@ -1,6 +1,17 @@
Changelog
================================
+1.3.0-beta
+---------------------------------------
+
+**Improvements:**
+ - Tests parametrization
+ - Removed old dependencies
+ - pyproject.toml file added instead of setup.py
+
+**Changes:**
+ -Dropped support for Python 2 and 3.7
+
1.2.4-beta
---------------------------------------
diff --git a/docs/source/conf.py b/docs/source/conf.py
index f8ce9f5..bd042ee 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -12,48 +12,28 @@
#
import os
import sys
-sys.path.insert(0, os.path.abspath('../..'))
+sys.path.insert(0, os.path.abspath("../.."))
-# -- Project information -----------------------------------------------------
-project = 'VFX Naming Conventions Framework'
-copyright = '2019, Chris Granados- Xian, Cesar Saez'
-author = 'Chris Granados- Xian'
+# -- Project information -----------------------------------------------------
-# The full version, including alpha/beta/rc tags
-release = '1.2.3-beta'
+project = "VFX Naming Conventions Framework"
+author = "Chris Granados- Xian"
+# The master toctree document.
+root_doc = "index"
# -- General configuration ---------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
-# Add any Sphinx extension module names here, as strings. They can be
-# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
-# ones.
-extensions = [
- 'sphinx.ext.autodoc',
- 'sphinx.ext.coverage'
-]
-
-master_doc = 'index'
-
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
-
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-# This pattern also affects html_static_path and html_extra_path.
-exclude_patterns = []
+extensions = ["sphinx.ext.autodoc", "sphinx.ext.coverage"]
+templates_path = ["_templates"]
+exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
# -- Options for HTML output -------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
-# The theme to use for HTML and HTML Help pages. See the documentation for
-# a list of builtin themes.
-#
-html_theme = 'sphinx_rtd_theme'
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
+html_theme = "sphinx_rtd_theme"
+html_static_path = ["_static"]
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 01604b5..1bb79cd 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -63,15 +63,12 @@ This is going to initalize a log file where everything will be recorded.
Acknowledgements
--------------------
-**vfxnaming** is based on `Copyright (c) 2017 Cesar Saez `_
-work. I highly recommend his `Website-Blog `_ and
-the video tutorial series on his `YouTube Channel `_
-
-For more information and credits please check :doc:`credits`
+For more information please check :doc:`credits`
.. toctree::
:maxdepth: 3
:caption: Getting Started
+ :hidden:
usage/repositories
usage/solving
@@ -80,6 +77,7 @@ For more information and credits please check :doc:`credits`
.. toctree::
:maxdepth: 3
:caption: API Reference
+ :hidden:
vfxnaming
rules
@@ -89,6 +87,7 @@ For more information and credits please check :doc:`credits`
.. toctree::
:maxdepth: 3
:caption: Changelog, Roadmap and Credits
+ :hidden:
changelog
roadmap
diff --git a/docs/source/roadmap.rst b/docs/source/roadmap.rst
index d8ba3a6..8362ad9 100644
--- a/docs/source/roadmap.rst
+++ b/docs/source/roadmap.rst
@@ -1,4 +1,6 @@
Roadmap
================================
--Implement nested Tokens
\ No newline at end of file
+- Implement referenced Tokens
+
+- GUI for creating and editing VFXNaming repos
\ No newline at end of file
From 7cf4ddffc9d15da27043cabb07080be160e542cc Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Mon, 5 Aug 2024 23:59:29 -0300
Subject: [PATCH 24/65] Fixing outdated tox
---
.readthedocs.yml | 2 +-
Pipfile | 1 +
Pipfile.lock | 145 ++++++++++++++++++++++----------------
pyproject.toml | 8 +--
src/vfxnaming/__init__.py | 29 ++++++--
tests/__init__.py | 0
tox.ini | 14 ++--
7 files changed, 119 insertions(+), 80 deletions(-)
delete mode 100644 tests/__init__.py
diff --git a/.readthedocs.yml b/.readthedocs.yml
index c314f3b..d2bbcdb 100644
--- a/.readthedocs.yml
+++ b/.readthedocs.yml
@@ -10,7 +10,7 @@ formats: all
# Optionally set the version of Python and requirements required to build your docs
python:
- version: 3.7
+ version: 3.10
install:
- requirements: requirements.txt
- requirements: docs/requirements.txt
diff --git a/Pipfile b/Pipfile
index c2761b0..304b0ef 100644
--- a/Pipfile
+++ b/Pipfile
@@ -15,6 +15,7 @@ twine = "*"
build = "*"
wheel = "*"
rstcheck = "*"
+vfxnaming = {editable=true, path="."}
[requires]
python_version = "3.10"
diff --git a/Pipfile.lock b/Pipfile.lock
index ea221b7..ced122b 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
- "sha256": "501c7b9e27a4ffe2d7eb6efa49188aee0841c2bf426e6d4e147b98a66087d42e"
+ "sha256": "f64bd05daff491800ca48a5a3f0a240bf5b405a5f4642b2e10af50314e8fdb61"
},
"pipfile-spec": 6,
"requires": {
@@ -175,7 +175,7 @@
"sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44",
"sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"
],
- "markers": "os_name == 'nt'",
+ "markers": "sys_platform == 'win32'",
"version": "==0.4.6"
},
"coverage": {
@@ -183,61 +183,81 @@
"toml"
],
"hashes": [
- "sha256:0086cd4fc71b7d485ac93ca4239c8f75732c2ae3ba83f6be1c9be59d9e2c6382",
- "sha256:01c322ef2bbe15057bc4bf132b525b7e3f7206f071799eb8aa6ad1940bcf5fb1",
- "sha256:03cafe82c1b32b770a29fd6de923625ccac3185a54a5e66606da26d105f37dac",
- "sha256:044a0985a4f25b335882b0966625270a8d9db3d3409ddc49a4eb00b0ef5e8cee",
- "sha256:07ed352205574aad067482e53dd606926afebcb5590653121063fbf4e2175166",
- "sha256:0d1b923fc4a40c5832be4f35a5dab0e5ff89cddf83bb4174499e02ea089daf57",
- "sha256:0e7b27d04131c46e6894f23a4ae186a6a2207209a05df5b6ad4caee6d54a222c",
- "sha256:1fad32ee9b27350687035cb5fdf9145bc9cf0a094a9577d43e909948ebcfa27b",
- "sha256:289cc803fa1dc901f84701ac10c9ee873619320f2f9aff38794db4a4a0268d51",
- "sha256:3c59105f8d58ce500f348c5b56163a4113a440dad6daa2294b5052a10db866da",
- "sha256:46c3d091059ad0b9c59d1034de74a7f36dcfa7f6d3bde782c49deb42438f2450",
- "sha256:482855914928c8175735a2a59c8dc5806cf7d8f032e4820d52e845d1f731dca2",
- "sha256:49c76cdfa13015c4560702574bad67f0e15ca5a2872c6a125f6327ead2b731dd",
- "sha256:4b03741e70fb811d1a9a1d75355cf391f274ed85847f4b78e35459899f57af4d",
- "sha256:4bea27c4269234e06f621f3fac3925f56ff34bc14521484b8f66a580aacc2e7d",
- "sha256:4d5fae0a22dc86259dee66f2cc6c1d3e490c4a1214d7daa2a93d07491c5c04b6",
- "sha256:543ef9179bc55edfd895154a51792b01c017c87af0ebaae092720152e19e42ca",
- "sha256:54dece71673b3187c86226c3ca793c5f891f9fc3d8aa183f2e3653da18566169",
- "sha256:6379688fb4cfa921ae349c76eb1a9ab26b65f32b03d46bb0eed841fd4cb6afb1",
- "sha256:65fa405b837060db569a61ec368b74688f429b32fa47a8929a7a2f9b47183713",
- "sha256:6616d1c9bf1e3faea78711ee42a8b972367d82ceae233ec0ac61cc7fec09fa6b",
- "sha256:6fe885135c8a479d3e37a7aae61cbd3a0fb2deccb4dda3c25f92a49189f766d6",
- "sha256:7221f9ac9dad9492cecab6f676b3eaf9185141539d5c9689d13fd6b0d7de840c",
- "sha256:76d5f82213aa78098b9b964ea89de4617e70e0d43e97900c2778a50856dac605",
- "sha256:7792f0ab20df8071d669d929c75c97fecfa6bcab82c10ee4adb91c7a54055463",
- "sha256:831b476d79408ab6ccfadaaf199906c833f02fdb32c9ab907b1d4aa0713cfa3b",
- "sha256:9146579352d7b5f6412735d0f203bbd8d00113a680b66565e205bc605ef81bc6",
- "sha256:9cc44bf0315268e253bf563f3560e6c004efe38f76db03a1558274a6e04bf5d5",
- "sha256:a73d18625f6a8a1cbb11eadc1d03929f9510f4131879288e3f7922097a429f63",
- "sha256:a8659fd33ee9e6ca03950cfdcdf271d645cf681609153f218826dd9805ab585c",
- "sha256:a94925102c89247530ae1dab7dc02c690942566f22e189cbd53579b0693c0783",
- "sha256:ad4567d6c334c46046d1c4c20024de2a1c3abc626817ae21ae3da600f5779b44",
- "sha256:b2e16f4cd2bc4d88ba30ca2d3bbf2f21f00f382cf4e1ce3b1ddc96c634bc48ca",
- "sha256:bbdf9a72403110a3bdae77948b8011f644571311c2fb35ee15f0f10a8fc082e8",
- "sha256:beb08e8508e53a568811016e59f3234d29c2583f6b6e28572f0954a6b4f7e03d",
- "sha256:c4cbe651f3904e28f3a55d6f371203049034b4ddbce65a54527a3f189ca3b390",
- "sha256:c7b525ab52ce18c57ae232ba6f7010297a87ced82a2383b1afd238849c1ff933",
- "sha256:ca5d79cfdae420a1d52bf177de4bc2289c321d6c961ae321503b2ca59c17ae67",
- "sha256:cdab02a0a941af190df8782aafc591ef3ad08824f97850b015c8c6a8b3877b0b",
- "sha256:d17c6a415d68cfe1091d3296ba5749d3d8696e42c37fca5d4860c5bf7b729f03",
- "sha256:d39bd10f0ae453554798b125d2f39884290c480f56e8a02ba7a6ed552005243b",
- "sha256:d4b3cd1ca7cd73d229487fa5caca9e4bc1f0bca96526b922d61053ea751fe791",
- "sha256:d50a252b23b9b4dfeefc1f663c568a221092cbaded20a05a11665d0dbec9b8fb",
- "sha256:da8549d17489cd52f85a9829d0e1d91059359b3c54a26f28bec2c5d369524807",
- "sha256:dcd070b5b585b50e6617e8972f3fbbee786afca71b1936ac06257f7e178f00f6",
- "sha256:ddaaa91bfc4477d2871442bbf30a125e8fe6b05da8a0015507bfbf4718228ab2",
- "sha256:df423f351b162a702c053d5dddc0fc0ef9a9e27ea3f449781ace5f906b664428",
- "sha256:dff044f661f59dace805eedb4a7404c573b6ff0cdba4a524141bc63d7be5c7fd",
- "sha256:e7e128f85c0b419907d1f38e616c4f1e9f1d1b37a7949f44df9a73d5da5cd53c",
- "sha256:ed8d1d1821ba5fc88d4a4f45387b65de52382fa3ef1f0115a4f7a20cdfab0e94",
- "sha256:f2501d60d7497fd55e391f423f965bbe9e650e9ffc3c627d5f0ac516026000b8",
- "sha256:f7db0b6ae1f96ae41afe626095149ecd1b212b424626175a6633c2999eaad45b"
+ "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca",
+ "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d",
+ "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6",
+ "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989",
+ "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c",
+ "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b",
+ "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223",
+ "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f",
+ "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56",
+ "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3",
+ "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8",
+ "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb",
+ "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388",
+ "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0",
+ "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a",
+ "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8",
+ "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f",
+ "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a",
+ "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962",
+ "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8",
+ "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391",
+ "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc",
+ "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2",
+ "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155",
+ "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb",
+ "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0",
+ "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c",
+ "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a",
+ "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004",
+ "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060",
+ "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232",
+ "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93",
+ "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129",
+ "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163",
+ "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de",
+ "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6",
+ "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23",
+ "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569",
+ "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d",
+ "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778",
+ "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d",
+ "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36",
+ "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a",
+ "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6",
+ "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34",
+ "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704",
+ "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106",
+ "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9",
+ "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862",
+ "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b",
+ "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255",
+ "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16",
+ "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3",
+ "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133",
+ "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb",
+ "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657",
+ "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d",
+ "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca",
+ "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36",
+ "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c",
+ "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e",
+ "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff",
+ "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7",
+ "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5",
+ "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02",
+ "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c",
+ "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df",
+ "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3",
+ "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a",
+ "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959",
+ "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234",
+ "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc"
],
"markers": "python_version >= '3.8'",
- "version": "==7.6.0"
+ "version": "==7.6.1"
},
"docutils": {
"hashes": [
@@ -777,7 +797,7 @@
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
+ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
"version": "==1.16.0"
},
"snowballstemmer": {
@@ -879,9 +899,6 @@
"version": "==5.1.1"
},
"typer": {
- "extras": [
- "all"
- ],
"hashes": [
"sha256:070d7ca53f785acbccba8e7d28b08dcd88f79f1fbda035ade0aecec71ca5c914",
"sha256:49e73131481d804288ef62598d97a1ceef3058905aa536a1134f90891ba35482"
@@ -905,14 +922,18 @@
"markers": "python_version >= '3.8'",
"version": "==2.2.2"
},
+ "vfxnaming": {
+ "editable": true,
+ "path": "."
+ },
"wheel": {
"hashes": [
- "sha256:465ef92c69fa5c5da2d1cf8ac40559a8c940886afcef87dcf14b9470862f1d85",
- "sha256:55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81"
+ "sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f",
+ "sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49"
],
"index": "pypi",
"markers": "python_version >= '3.8'",
- "version": "==0.43.0"
+ "version": "==0.44.0"
},
"zipp": {
"hashes": [
diff --git a/pyproject.toml b/pyproject.toml
index cb6a38f..dfe8163 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,20 +1,20 @@
[build-system]
-requires = ["setuptools>=61.0", "wheel", "twine", "build"]
+requires = ["setuptools", "wheel", "twine", "build"]
build-backend = "setuptools.build_meta"
[project]
name = "vfxnaming"
-version="1.2.3-beta"
+version = "1.3.0-beta"
authors = [
{ name="Chris Granados", email="info@chrisgranados.com" },
]
description = "VFX Naming Conventions Framework"
readme = "README.rst"
-requires-python = ">=3.7"
+requires-python = ">=3.10"
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
- "Programming Language :: Python :: 3.7",
+ "Programming Language :: Python :: 3.10",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
]
diff --git a/src/vfxnaming/__init__.py b/src/vfxnaming/__init__.py
index 76e2ea3..ead8b4e 100644
--- a/src/vfxnaming/__init__.py
+++ b/src/vfxnaming/__init__.py
@@ -1,11 +1,28 @@
-# coding=utf-8
-
from vfxnaming.naming import parse, solve, get_repo, save_session, load_session # noqa: F401
from vfxnaming.rules import ( # noqa: F401
- add_rule, remove_rule, has_rule, reset_rules, get_active_rule, set_active_rule,
- get_rule, get_rules, save_rule, load_rule, Rule
+ add_rule,
+ remove_rule,
+ has_rule,
+ reset_rules,
+ get_active_rule,
+ set_active_rule,
+ get_rule,
+ get_rules,
+ save_rule,
+ load_rule,
+ Rule,
)
from vfxnaming.tokens import ( # noqa: F401
- add_token, add_token_number, remove_token, has_token, reset_tokens,
- get_token, get_tokens, save_token, load_token
+ add_token,
+ add_token_number,
+ remove_token,
+ has_token,
+ reset_tokens,
+ get_token,
+ get_tokens,
+ save_token,
+ load_token,
+ Token,
+ TokenNumber,
)
+from vfxnaming.error import ParsingError, SolvingError, TokenError # noqa: F401
diff --git a/tests/__init__.py b/tests/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tox.ini b/tox.ini
index 7c0c4f6..fdf50d8 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,33 +1,33 @@
[tox]
envlist = py310, py310ci, docs
-skipsdist = True
+package = vfxnaming
[testenv]
basepython = py310: python3.10
py310ci: python3.10
- flake8: python3.10
docs: python3.10
usedevelop = True
[testenv:docs]
deps = sphinx
sphinx-rtd-theme
- {[testenv]deps}
-commands = ./docs/make.bat html
+commands =
+ sphinx-build -c "{tox_root}{/}docs{/}source" -d "{tox_root}{/}docs{/}build{/}doctrees" "docs{/}source" "{tox_root}{/}docs{/}build{/}html" --color -b html
+ python -c 'docs_url=r"{tox_root}{/}docs{/}build{/}html{/}index.html".replace("\\", "/").replace("//", "/"); print(f"Docs available here file:///{docs_url}")'
[testenv:py310]
deps = pytest
pytest-cov
pytest-datafiles
- {[testenv]deps}
-commands= pytest -c tox.ini --cov-report term-missing --cov-report html:cov_py310_html --cov=vfxnaming tests/
+commands=
+ pip list
+ pytest -c tox.ini --cov-report term-missing --cov-report html:cov_py310_html --cov=vfxnaming tests/
[testenv:py310ci]
deps = pytest
pytest-cov
pytest-datafiles
python-coveralls
- {[testenv]deps}
commands= pytest -c tox.ini --cov-report term-missing --cov=vfxnaming tests/
[pytest]
From ef92972196bc109eb9993203aee69a727e88f629 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Tue, 6 Aug 2024 22:09:51 -0300
Subject: [PATCH 25/65] Remove old travis
---
.travis.yml | 14 --------------
1 file changed, 14 deletions(-)
delete mode 100644 .travis.yml
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 52c2aa7..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-language: python
-python:
- - "3.7"
-install:
- - pip install tox
- - pip install pipenv
- - pipenv install
- - pipenv install --dev
-script:
- - tox -e py27ci
- - tox -e py37ci
- - tox -e flake8
-after_success:
- - coveralls
From cb57fb5654ca7902812a50fdac722a7e516860c2 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Tue, 6 Aug 2024 22:12:29 -0300
Subject: [PATCH 26/65] Setup shell before invoking ruff
---
.github/workflows/ci_vfxnaming.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/workflows/ci_vfxnaming.yml b/.github/workflows/ci_vfxnaming.yml
index 622abe4..d83a9fd 100644
--- a/.github/workflows/ci_vfxnaming.yml
+++ b/.github/workflows/ci_vfxnaming.yml
@@ -23,6 +23,7 @@ jobs:
python -m pip install --upgrade pip
python -m pip install pipenv tox
pipenv sync
+ pipenv shell
- name: Lint with Ruff
run: |
ruff check --output-format=github .
From 490643056b161ddca2f5f80b8be333be4ff562f2 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Tue, 6 Aug 2024 22:18:31 -0300
Subject: [PATCH 27/65] Using pipenv run
---
.github/workflows/ci_vfxnaming.yml | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/.github/workflows/ci_vfxnaming.yml b/.github/workflows/ci_vfxnaming.yml
index d83a9fd..f0f0470 100644
--- a/.github/workflows/ci_vfxnaming.yml
+++ b/.github/workflows/ci_vfxnaming.yml
@@ -22,15 +22,11 @@ jobs:
run: |
python -m pip install --upgrade pip
python -m pip install pipenv tox
- pipenv sync
- pipenv shell
+ pipenv sync --dev
- name: Lint with Ruff
run: |
- ruff check --output-format=github .
+ pipenv run ruff check --output-format=github .
continue-on-error: true
- name: Run tests with tox
run: |
tox -e py310ci
- - name: Test with pytest
- run: |
- pytest
From ebdcf82d8937a81ee46ea02c386541f4d6b6b40c Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Tue, 6 Aug 2024 22:33:05 -0300
Subject: [PATCH 28/65] Badges
---
README.rst | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/README.rst b/README.rst
index 7e4d6c0..0274f4a 100644
--- a/README.rst
+++ b/README.rst
@@ -1,11 +1,9 @@
VFX Naming Conventions Framework
===================================
-.. image:: https://travis-ci.org/xiancg/vfxnaming.svg?branch=master
- :target: https://travis-ci.org/xiancg/vfxnaming
+.. image:: https://github.com/xiancg/vfxnaming/actions/workflows/ci_vfxnaming.yml/badge.svg?event=push&branch=master
.. image:: https://readthedocs.org/projects/naming-conventions/badge/?version=latest
-.. image:: https://coveralls.io/repos/github/xiancg/vfxnaming/badge.svg?branch=master
- :target: https://coveralls.io/github/xiancg/vfxnaming?branch=master
+.. image:: https://img.shields.io/github/license/readthedocs/actions
A complete suite of tools to manage naming conventions from one or more "Rule repositories". Structure naming rules with your own custom tokens. Then use the library to solve names following those rules so your naming is consistent, and also to parse metadata from exisiting names (cus a name is basically a collection of metadata, right?)
From 4bdded28efc577f3e3092b4b9e6a357357589aaa Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Tue, 6 Aug 2024 23:07:29 -0300
Subject: [PATCH 29/65] Fixing docs buils
---
.readthedocs.yml | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/.readthedocs.yml b/.readthedocs.yml
index d2bbcdb..7638a67 100644
--- a/.readthedocs.yml
+++ b/.readthedocs.yml
@@ -1,6 +1,11 @@
# Required
version: 2
+build:
+ os: ubuntu-22.04
+ tools:
+ python: "3.10"
+
# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/source/conf.py
@@ -10,10 +15,6 @@ formats: all
# Optionally set the version of Python and requirements required to build your docs
python:
- version: 3.10
install:
- - requirements: requirements.txt
- - requirements: docs/requirements.txt
- - method: setuptools
+ - method: pip
path: .
- system_packages: true
From 0794381230bc800d2286aaa4705c2ed94c16f996 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Tue, 6 Aug 2024 23:26:23 -0300
Subject: [PATCH 30/65] docs requirements
---
docs/requirements.txt | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 docs/requirements.txt
diff --git a/docs/requirements.txt b/docs/requirements.txt
new file mode 100644
index 0000000..1a3fd8a
--- /dev/null
+++ b/docs/requirements.txt
@@ -0,0 +1,2 @@
+Sphinx==7.4.7
+sphinx-rtd-theme==2.1.0rc1
From 4930a591ab51c10814948dcc52b1250f87ca512a Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Tue, 6 Aug 2024 23:29:08 -0300
Subject: [PATCH 31/65] Update yml with requirements
---
.readthedocs.yml | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/.readthedocs.yml b/.readthedocs.yml
index 7638a67..7aed3ac 100644
--- a/.readthedocs.yml
+++ b/.readthedocs.yml
@@ -16,5 +16,4 @@ formats: all
# Optionally set the version of Python and requirements required to build your docs
python:
install:
- - method: pip
- path: .
+ - requirements: docs/requirements.txt
From 93611b47be2c6ea8d0b5ac1ec394fc6b8c54b4de Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Tue, 6 Aug 2024 23:35:40 -0300
Subject: [PATCH 32/65] Update badges in docs
---
docs/source/index.rst | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 1bb79cd..b47ce9b 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -1,11 +1,9 @@
VFX Naming Conventions Docs
========================================
-.. image:: https://travis-ci.org/xiancg/vfxnaming.svg?branch=master
- :target: https://travis-ci.org/xiancg/vfxnaming
+.. image:: https://github.com/xiancg/vfxnaming/actions/workflows/ci_vfxnaming.yml/badge.svg?event=push&branch=master
.. image:: https://readthedocs.org/projects/naming-conventions/badge/?version=latest
-.. image:: https://coveralls.io/repos/github/xiancg/vfxnaming/badge.svg?branch=master
- :target: https://coveralls.io/github/xiancg/vfxnaming?branch=master
+.. image:: https://img.shields.io/github/license/readthedocs/actions
Installation
------------
From 879181db8f1ee4029b50774068981a25f45f4701 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sat, 10 Aug 2024 13:24:08 -0300
Subject: [PATCH 33/65] Update coverage
---
.github/workflows/ci_vfxnaming.yml | 4 +-
Pipfile | 2 +-
Pipfile.lock | 143 +++++++++--------------------
tox.ini | 2 +-
4 files changed, 47 insertions(+), 104 deletions(-)
diff --git a/.github/workflows/ci_vfxnaming.yml b/.github/workflows/ci_vfxnaming.yml
index f0f0470..334e542 100644
--- a/.github/workflows/ci_vfxnaming.yml
+++ b/.github/workflows/ci_vfxnaming.yml
@@ -1,6 +1,6 @@
name: VFXNaming CI
-on: [push]
+on: [push, pull_request]
jobs:
build:
@@ -30,3 +30,5 @@ jobs:
- name: Run tests with tox
run: |
tox -e py310ci
+ - name: Coveralls
+ uses: coverallsapp/github-action@v2
diff --git a/Pipfile b/Pipfile
index 304b0ef..ea6258a 100644
--- a/Pipfile
+++ b/Pipfile
@@ -8,7 +8,7 @@ pytest = "*"
pytest-cov = "*"
pytest-datafiles = "*"
ruff = "*"
-python-coveralls = "*"
+coveralls = "*"
sphinx = "*"
sphinx-rtd-theme = "*"
twine = "*"
diff --git a/Pipfile.lock b/Pipfile.lock
index ced122b..c110631 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
- "sha256": "f64bd05daff491800ca48a5a3f0a240bf5b405a5f4642b2e10af50314e8fdb61"
+ "sha256": "ceffa7297cb2f08766f07980c534518d805ddf86ff03394db3a45f95f5c32653"
},
"pipfile-spec": 6,
"requires": {
@@ -35,11 +35,11 @@
},
"babel": {
"hashes": [
- "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb",
- "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"
+ "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b",
+ "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"
],
"markers": "python_version >= '3.8'",
- "version": "==2.15.0"
+ "version": "==2.16.0"
},
"backports.tarfile": {
"hashes": [
@@ -259,6 +259,21 @@
"markers": "python_version >= '3.8'",
"version": "==7.6.1"
},
+ "coveralls": {
+ "hashes": [
+ "sha256:7a6b1fa9848332c7b2221afb20f3df90272ac0167060f41b5fe90429b30b1809",
+ "sha256:7b2a0a2bcef94f295e3cf28dcc55ca40b71c77d1c2446b538e85f0f7bc21aa69"
+ ],
+ "index": "pypi",
+ "markers": "python_version < '3.13' and python_version >= '3.8'",
+ "version": "==4.0.1"
+ },
+ "docopt": {
+ "hashes": [
+ "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"
+ ],
+ "version": "==0.6.2"
+ },
"docutils": {
"hashes": [
"sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6",
@@ -431,11 +446,11 @@
},
"more-itertools": {
"hashes": [
- "sha256:e5d93ef411224fbcef366a6e8ddc4c5781bc6359d43412a65dd5964e46111463",
- "sha256:ea6a02e24a9161e51faad17a8782b92a0df82c12c1c8886fec7f0c3fa1a1b320"
+ "sha256:0f7d9f83a0a8dcfa8a2694a770590d98a67ea943e3d9f5298309a484758c4e27",
+ "sha256:fe0e63c4ab068eac62410ab05cccca2dc71ec44ba8ef29916a0090df061cf923"
],
"markers": "python_version >= '3.8'",
- "version": "==10.3.0"
+ "version": "==10.4.0"
},
"nh3": {
"hashes": [
@@ -627,14 +642,6 @@
"index": "pypi",
"version": "==3.0.0"
},
- "python-coveralls": {
- "hashes": [
- "sha256:bfaf7811e7dc5628e83b6b162962a4e2485dbff184b30e49f380374ed1bcee55",
- "sha256:fb0ff49bb1551dac10b06bd55e9790287d898a0f1e2c959802235cae08dd0bff"
- ],
- "index": "pypi",
- "version": "==2.9.3"
- },
"pywin32-ctypes": {
"hashes": [
"sha256:3426e063bdd5fd4df74a14fa3cf80a0b42845a87e1d1e81f6549f9daec593a60",
@@ -643,65 +650,6 @@
"markers": "sys_platform == 'win32'",
"version": "==0.2.2"
},
- "pyyaml": {
- "hashes": [
- "sha256:0101357af42f5c9fc7e9acc5c5ab8c3049f50db7425de175b6c7a5959cb6023d",
- "sha256:0ae563b7e3ed5e918cd0184060e28b48b7e672b975bf7c6f4a892cee9d886ada",
- "sha256:0fe2c1c5401a3a98f06337fed48f57340cf652a685484834b44f5ceeadb772ba",
- "sha256:1eb00dd3344da80264261ab126c95481824669ed9e5ecc82fb2d88b1fce668ee",
- "sha256:2086b30215c433c1e480c08c1db8b43c1edd36c59cf43d36b424e6f35fcaf1ad",
- "sha256:29b4a67915232f79506211e69943e3102e211c616181ceff0adf34e21b469357",
- "sha256:2e9bc8a34797f0621f56160b961d47a088644370f79d34bedc934fb89e3f47dd",
- "sha256:30ec6b9afc17353a9abcff109880edf6e8d5b924eb1eeed7fe9376febc1f9800",
- "sha256:31573d7e161d2f905311f036b12e65c058389b474dbd35740f4880b91e2ca2be",
- "sha256:36d7bf63558843ea2a81de9d0c3e9c56c353b1df8e6c1faaec86df5adedf2e02",
- "sha256:3af6b36bc195d741cd5b511810246cad143b99c953b4591e679e194a820d7b7c",
- "sha256:414629800a1ddccd7303471650843fc801801cc579a195d2fe617b5b455409e3",
- "sha256:459113f2b9cd68881201a3bd1a858ece3281dc0e92ece6e917d23b128f0fcb31",
- "sha256:46e4fae38d00b40a62d32d60f1baa1b9ef33aff28c2aafd96b05d5cc770f1583",
- "sha256:4bf821ccd51e8d5bc1a4021b8bd85a92b498832ac1cd1a53b399f0eb7c1c4258",
- "sha256:50bd6560a6df3de59336b9a9086cbdea5aa9eee5361661448ee45c21eeb0da68",
- "sha256:53056b51f111223e603bed1db5367f54596d44cacfa50f07e082a11929612957",
- "sha256:53c5f0749a93e3296078262c9acf632de246241ff2f22bbedfe49d4b55e9bbdd",
- "sha256:54c754cee6937bb9b72d6a16163160dec80b93a43020ac6fc9f13729c030c30b",
- "sha256:58cc18ccbade0c48fb55102aa971a5b4e571e2b22187d083dda33f8708fa4ee7",
- "sha256:5921fd128fbf27ab7c7ad1a566d2cd9557b84ade130743a7c110a55e7dec3b3c",
- "sha256:5c758cc29713c9166750a30156ca3d90ac2515d5dea3c874377ae8829cf03087",
- "sha256:60bf91e73354c96754220a9c04a9502c2ad063231cd754b59f8e4511157e32e2",
- "sha256:6f0f728a88c6eb58a3b762726b965bb6acf12d97f8ea2cb4fecf856a727f9bdc",
- "sha256:6f31c5935310da69ea0efe996a962d488f080312f0eb43beff1717acb5fe9bed",
- "sha256:728b447d0cedec409ea1a3f0ad1a6cc3cec0a8d086611b45f038a9230a2242f3",
- "sha256:72ffbc5c0cc71877104387548a450f2b7b7c4926b40dc9443e7598fe92aa13d9",
- "sha256:73d8b233309ecd45c33c51cd55aa1be1dcab1799a9e54f6c753d8cab054b8c34",
- "sha256:765029d1cf96e9e761329ee1c20f1ca2de8644e7350a151b198260698b96e30f",
- "sha256:7ee3d180d886a3bc50f753b76340f1c314f9e8c507f5b107212112214c3a66fd",
- "sha256:826fb4d5ac2c48b9d6e71423def2669d4646c93b6c13612a71b3ac7bb345304b",
- "sha256:84c39ceec517cd8f01cb144efb08904a32050be51c55b7a59bc7958c8091568d",
- "sha256:88bfe675bb19ae12a9c77c52322a28a8e2a8d3d213fbcfcded5c3f5ca3ead352",
- "sha256:8e0a1ebd5c5842595365bf90db3ef7e9a8d6a79c9aedb1d05b675c81c7267fd3",
- "sha256:9426067a10b369474396bf57fdf895b899045a25d1848798844693780b147436",
- "sha256:9c5c0de7ec50d4df88b62f4b019ab7b3bb2883c826a1044268e9afb344c57b17",
- "sha256:ad0c172fe15beffc32e3a8260f18e6708eb0e15ae82c9b3f80fbe04de0ef5729",
- "sha256:ad206c7f5f08d393b872d3399f597246fdc6ebebff09c5ae5268ac45aebf4f8d",
- "sha256:b0a163f4f84d1e0fe6a07ccad3b02e9b243790b8370ff0408ae5932c50c4d96d",
- "sha256:b0dd9c7497d60126445e79e542ff01351c6b6dc121299d89787f5685b382c626",
- "sha256:b1de10c488d6f02e498eb6956b89081bea31abf3133223c17749e7137734da75",
- "sha256:b408f36eeb4e2be6f802f1be82daf1b578f3de5a51917c6e467aedb46187d827",
- "sha256:bae077a01367e4bf5fddf00fd6c8b743e676385911c7c615e29e1c45ace8813b",
- "sha256:bc3c3600fec6c2a719106381d6282061d8c108369cdec58b6f280610eba41e09",
- "sha256:c16522bf91daa4ea9dedc1243b56b5a226357ab98b3133089ca627ef99baae6f",
- "sha256:ca5136a77e2d64b4cf5106fb940376650ae232c74c09a8ff29dbb1e262495b31",
- "sha256:d6e0f7ee5f8d851b1d91149a3e5074dbf5aacbb63e4b771fcce16508339a856f",
- "sha256:e7930a0612e74fcca37019ca851b50d73b5f0c3dab7f3085a7c15d2026118315",
- "sha256:e8e6dd230a158a836cda3cc521fcbedea16f22b16b8cfa8054d0c6cea5d0a531",
- "sha256:eee36bf4bc11e39e3f17c171f25cdedff3d7c73b148aedc8820257ce2aa56d3b",
- "sha256:f07adc282d51aaa528f3141ac1922d16d32fe89413ee59bfb8a73ed689ad3d23",
- "sha256:f09816c047fdb588dddba53d321f1cb8081e38ad2a40ea6a7560a88b7a2f0ea8",
- "sha256:fea4c4310061cd70ef73b39801231b9dc3dc638bb8858e38364b144fbd335a1a"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==6.0.2rc1"
- },
"readme-renderer": {
"hashes": [
"sha256:1818dd28140813509eeed8d62687f7cd4f7bad90d4db586001c5dc09d4fde311",
@@ -761,28 +709,28 @@
},
"ruff": {
"hashes": [
- "sha256:07c9e3c2a8e1fe377dd460371c3462671a728c981c3205a5217291422209f642",
- "sha256:111a99cdb02f69ddb2571e2756e017a1496c2c3a2aeefe7b988ddab38b416d36",
- "sha256:1f77c1c3aa0669fb230b06fb24ffa3e879391a3ba3f15e3d633a752da5a3e670",
- "sha256:4d394940f61f7720ad371ddedf14722ee1d6250fd8d020f5ea5a86e7be217daf",
- "sha256:563a7ae61ad284187d3071d9041c08019975693ff655438d8d4be26e492760bd",
- "sha256:57c6c0dd997b31b536bff49b9eee5ed3194d60605a4427f735eeb1f9c1b8d264",
- "sha256:80521b88d26a45e871f31e4b88938fd87db7011bb961d8afd2664982dfc3641a",
- "sha256:94fe60869bfbf0521e04fd62b74cbca21cbc5beb67cbb75ab33fe8c174f54414",
- "sha256:a0ef5930799a05522985b9cec8290b185952f3fcd86c1772c3bdbd732667fdcd",
- "sha256:b652dc14f6ef5d1552821e006f747802cc32d98d5509349e168f6bf0ee9f8f42",
- "sha256:c476acb43c3c51e3c614a2e878ee1589655fa02dab19fe2db0423a06d6a5b1b6",
- "sha256:c94e084ba3eaa80c2172918c2ca2eb2230c3f15925f4ed8b6297260c6ef179ad",
- "sha256:d7fe7dccb1a89dc66785d7aa0ac283b2269712d8ed19c63af908fdccca5ccc1a",
- "sha256:d9bc8f328a9f1309ae80e4d392836e7dbc77303b38ed4a7112699e63d3b066ab",
- "sha256:e2ff8003f5252fd68425fd53d27c1f08b201d7ed714bb31a55c9ac1d4c13e2eb",
- "sha256:e395daba77a79f6dc0d07311f94cc0560375ca20c06f354c7c99af3bf4560c5d",
- "sha256:e6a584c1de6f8591c2570e171cc7ce482bb983d49c70ddf014393cd39e9dfaed",
- "sha256:f908148c93c02873210a52cad75a6eda856b2cbb72250370ce3afef6fb99b1ed"
+ "sha256:00cc8872331055ee017c4f1071a8a31ca0809ccc0657da1d154a1d2abac5c0be",
+ "sha256:083bbcbe6fadb93cd86709037acc510f86eed5a314203079df174c40bbbca6b3",
+ "sha256:2dca26154ff9571995107221d0aeaad0e75a77b5a682d6236cf89a58c70b76f4",
+ "sha256:33d61fc0e902198a3e55719f4be6b375b28f860b09c281e4bdbf783c0566576a",
+ "sha256:4a09ea2c3f7778cc635e7f6edf57d566a8ee8f485f3c4454db7771efb692c499",
+ "sha256:548992d342fc404ee2e15a242cdbea4f8e39a52f2e7752d0e4cbe88d2d2f416a",
+ "sha256:7e31c9bad4ebf8fdb77b59cae75814440731060a09a0e0077d559a556453acbb",
+ "sha256:7f70284e73f36558ef51602254451e50dd6cc479f8b6f8413a95fcb5db4a55fc",
+ "sha256:8d796327eed8e168164346b769dd9a27a70e0298d667b4ecee6877ce8095ec8e",
+ "sha256:8dfc0a458797f5d9fb622dd0efc52d796f23f0a1493a9527f4e49a550ae9a7e5",
+ "sha256:9369c218f789eefbd1b8d82a8cf25017b523ac47d96b2f531eba73770971c9e5",
+ "sha256:9ccd078c66a8e419475174bfe60a69adb36ce04f8d4e91b006f1329d5cd44bcf",
+ "sha256:a01c34400097b06cf8a6e61b35d6d456d5bd1ae6961542de18ec81eaf33b4cb8",
+ "sha256:a36d8dcf55b3a3bc353270d544fb170d75d2dff41eba5df57b4e0b67a95bb64e",
+ "sha256:a78ad870ae3c460394fc95437d43deb5c04b5c29297815a2a1de028903f19692",
+ "sha256:b88ca3db7eb377eb24fb7c82840546fb7acef75af4a74bd36e9ceb37a890257e",
+ "sha256:eaf3d86a1fdac1aec8a3417a63587d93f906c678bb9ed0b796da7b59c1114a1e",
+ "sha256:fcc8054f1a717e2213500edaddcf1dbb0abad40d98e1bd9d0ad364f75c763eea"
],
"index": "pypi",
"markers": "python_version >= '3.7'",
- "version": "==0.5.6"
+ "version": "==0.5.7"
},
"shellingham": {
"hashes": [
@@ -792,14 +740,6 @@
"markers": "python_version >= '3.7'",
"version": "==1.5.4"
},
- "six": {
- "hashes": [
- "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
- "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
- ],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
- "version": "==1.16.0"
- },
"snowballstemmer": {
"hashes": [
"sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1",
@@ -924,6 +864,7 @@
},
"vfxnaming": {
"editable": true,
+ "markers": "python_version >= '3.10'",
"path": "."
},
"wheel": {
diff --git a/tox.ini b/tox.ini
index fdf50d8..dbed848 100644
--- a/tox.ini
+++ b/tox.ini
@@ -27,7 +27,7 @@ commands=
deps = pytest
pytest-cov
pytest-datafiles
- python-coveralls
+ coveralls
commands= pytest -c tox.ini --cov-report term-missing --cov=vfxnaming tests/
[pytest]
From a06c8a47d543156ca9adb20155e163af07e29780 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sat, 10 Aug 2024 13:26:30 -0300
Subject: [PATCH 34/65] Adds coverage badge
---
README.rst | 1 +
docs/source/index.rst | 2 ++
2 files changed, 3 insertions(+)
diff --git a/README.rst b/README.rst
index 0274f4a..16db7e9 100644
--- a/README.rst
+++ b/README.rst
@@ -3,6 +3,7 @@ VFX Naming Conventions Framework
.. image:: https://github.com/xiancg/vfxnaming/actions/workflows/ci_vfxnaming.yml/badge.svg?event=push&branch=master
.. image:: https://readthedocs.org/projects/naming-conventions/badge/?version=latest
+.. image:: https://coveralls.io/repos/github/xiancg/vfxnaming/badge.svg
.. image:: https://img.shields.io/github/license/readthedocs/actions
A complete suite of tools to manage naming conventions from one or more "Rule repositories". Structure naming rules with your own custom tokens. Then use the library to solve names following those rules so your naming is consistent, and also to parse metadata from exisiting names (cus a name is basically a collection of metadata, right?)
diff --git a/docs/source/index.rst b/docs/source/index.rst
index b47ce9b..7814115 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -4,6 +4,8 @@ VFX Naming Conventions Docs
.. image:: https://github.com/xiancg/vfxnaming/actions/workflows/ci_vfxnaming.yml/badge.svg?event=push&branch=master
.. image:: https://readthedocs.org/projects/naming-conventions/badge/?version=latest
.. image:: https://img.shields.io/github/license/readthedocs/actions
+.. image:: https://coveralls.io/repos/github/xiancg/vfxnaming/badge.svg
+
Installation
------------
From 8fce812dfa44b2e83cb0d74e548fd23256f225f1 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sat, 10 Aug 2024 13:37:47 -0300
Subject: [PATCH 35/65] Testing environment
---
.github/workflows/ci_vfxnaming.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.github/workflows/ci_vfxnaming.yml b/.github/workflows/ci_vfxnaming.yml
index 334e542..2297e07 100644
--- a/.github/workflows/ci_vfxnaming.yml
+++ b/.github/workflows/ci_vfxnaming.yml
@@ -6,6 +6,8 @@ jobs:
build:
runs-on: ubuntu-latest
+ environment:
+ name: coverage
strategy:
fail-fast: false
matrix:
From 583e488e5eea63ab084236169a63f4073398d238 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sat, 10 Aug 2024 13:55:54 -0300
Subject: [PATCH 36/65] Add lcov report
---
.github/workflows/ci_vfxnaming.yml | 4 ++++
tox.ini | 2 +-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/ci_vfxnaming.yml b/.github/workflows/ci_vfxnaming.yml
index 2297e07..60a9ce4 100644
--- a/.github/workflows/ci_vfxnaming.yml
+++ b/.github/workflows/ci_vfxnaming.yml
@@ -8,6 +8,7 @@ jobs:
runs-on: ubuntu-latest
environment:
name: coverage
+ github-token: ${{ secrets.GITHUB_TOKEN }}
strategy:
fail-fast: false
matrix:
@@ -34,3 +35,6 @@ jobs:
tox -e py310ci
- name: Coveralls
uses: coverallsapp/github-action@v2
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+
diff --git a/tox.ini b/tox.ini
index dbed848..61a7f07 100644
--- a/tox.ini
+++ b/tox.ini
@@ -28,7 +28,7 @@ deps = pytest
pytest-cov
pytest-datafiles
coveralls
-commands= pytest -c tox.ini --cov-report term-missing --cov=vfxnaming tests/
+commands= pytest -c tox.ini --cov-report lcov --cov=vfxnaming tests/
[pytest]
addopts = --maxfail=10 -rf -s
From 057036f395a6241f42b2b8764777c0d934df5b47 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sat, 10 Aug 2024 13:56:35 -0300
Subject: [PATCH 37/65] wrong token placement
---
.github/workflows/ci_vfxnaming.yml | 1 -
1 file changed, 1 deletion(-)
diff --git a/.github/workflows/ci_vfxnaming.yml b/.github/workflows/ci_vfxnaming.yml
index 60a9ce4..145f01f 100644
--- a/.github/workflows/ci_vfxnaming.yml
+++ b/.github/workflows/ci_vfxnaming.yml
@@ -8,7 +8,6 @@ jobs:
runs-on: ubuntu-latest
environment:
name: coverage
- github-token: ${{ secrets.GITHUB_TOKEN }}
strategy:
fail-fast: false
matrix:
From 50c3fbedddcb6a68e0e207b84c82e7479cba3b10 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sun, 11 Aug 2024 10:52:20 -0300
Subject: [PATCH 38/65] Update get_repo logic and adds validation functions
---
src/vfxnaming/error.py | 10 +++-
src/vfxnaming/naming.py | 124 ++++++++++++++++++++++++++++++++++------
2 files changed, 113 insertions(+), 21 deletions(-)
diff --git a/src/vfxnaming/error.py b/src/vfxnaming/error.py
index d94a5c3..b4942ac 100644
--- a/src/vfxnaming/error.py
+++ b/src/vfxnaming/error.py
@@ -1,10 +1,14 @@
class ParsingError(BaseException):
- '''Raise when parsing couldn't be completed'''
+ """Raise when parsing couldn't be completed"""
class SolvingError(BaseException):
- '''Raise when solving couldn't be completed'''
+ """Raise when solving couldn't be completed"""
class TokenError(BaseException):
- '''Raise when Token errors are detected.'''
+ """Raise when Token errors are detected."""
+
+
+class RepoError(BaseException):
+ """Raise when Repo errors are detected."""
diff --git a/src/vfxnaming/naming.py b/src/vfxnaming/naming.py
index 0684000..8f58406 100644
--- a/src/vfxnaming/naming.py
+++ b/src/vfxnaming/naming.py
@@ -17,6 +17,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import os
+import re
import json
import vfxnaming.rules as rules
import vfxnaming.tokens as tokens
@@ -24,7 +25,7 @@
from typing import AnyStr, Dict, Union
from vfxnaming.logger import logger
-from vfxnaming.error import SolvingError
+from vfxnaming.error import SolvingError, RepoError
NAMING_REPO_ENV = "NAMING_REPO"
@@ -110,7 +111,7 @@ def solve(*args, **kwargs) -> AnyStr:
fields_inc += 1
continue
elif token.required and kwargs.get(f) is None and len(args) == 0:
- raise SolvingError("Token {} is required.")
+ raise SolvingError("Token {} is required but was not passed.")
# Not required and not passed as keyword argument
elif not token.required and kwargs.get(f) is None:
values[f] = token.solve()
@@ -128,26 +129,113 @@ def solve(*args, **kwargs) -> AnyStr:
return rule.solve(**values)
-def get_repo() -> Path:
- """Get repository location from either global environment variable or local user,
- giving priority to environment variable.
+def validate_repo(repo: Path) -> bool:
+ """Valides repo by checking if it contains a naming.conf file.
- Environment varialble name: NAMING_REPO
+ Args:
+ repo (Path): Repo dir
+
+ Returns:
+ bool: True if valid, False otherwise.
+ """
+ config_file = repo / "naming.conf"
+ if not config_file.exists():
+ return False
+ return True
+
+
+def validate_tokens_and_referenced_rules(pattern: str) -> bool:
+ """Validate if the pattern uses tokens and rules that are defined in the current session.
+
+ Args:
+ pattern (str): Naming pattern to validate.
+
+ Returns:
+ bool: True if successful, False otherwise.
+ """
+ valid = True
+
+ regex = re.compile(r"{(?P.+?)(:(?P(\\}|.)+?))?}")
+ matches = regex.finditer(pattern)
+
+ all_rules = list(rules.get_rules().keys())
+ all_tokens = list(tokens.get_tokens().keys())
+
+ rules_used = []
+ tokens_used = []
+ for match in matches:
+ match_text = match.group(1)
+ if match_text.startswith("@"):
+ rules_used.append(match_text.replace("@", ""))
+ else:
+ tokens_used.append(match_text)
+
+ for rule in rules_used:
+ if rule not in all_rules:
+ valid = False
+ break
+
+ for token in tokens_used:
+ if token not in all_tokens:
+ valid = False
+ break
+
+ return valid
+
+
+def get_repo(force_repo: Union[Path, str] = None) -> Path:
+ """Get the path to a folder structures repo.
+
+ Path is looked for in these places and with the given priority:
+
+ 1- ``force_repo`` parameter
+
+ 2- Environment variable: NAMING_REPO
+
+ 3- User config file: C:/Users/xxxxx/.CGXTools/vfxnaming/config.json
+
+ 4- Dev config file: __file__/cfg/config.json
+
+ In both config.json files the key it looks for is 'vfxnaming_repo'
+
+ If a root path is passed as ``force_repo`` parameter, then it'll
+ return the same path but first checks it actually exists.
+
+ Keyword Arguments:
+ ``force_repo`` {Path} -- Use this path instead of looking for
+ pre-configured ones (default: {None})
+
+ Raises:
+ RepoError: Given repo directory does not exist.
+
+ RepoError: Config file for vfxnmaing library couldn't be found.
Returns:
- Path: Naming repository location
+ [Path] -- Root path
"""
- env_repo = os.environ.get(NAMING_REPO_ENV)
- user_path = Path.expanduser("~")
- module_dir = Path(__file__).parent
- config_location = module_dir / "cfg/config.json"
- config = dict()
- with open(config_location) as fp:
- config = json.load(fp)
- local_repo = user_path / f".{config['local_repo_name']}/naming_repo"
- result = env_repo or local_repo
- logger.debug(f"Repo found: {result}")
- return Path(result)
+ # Env level
+ env_root = Path(os.environ.get(NAMING_REPO_ENV))
+
+ # User level
+ user_cfg_path = Path.expanduser("~") / ".CGXTools/vfxnaming/config.json"
+ user_config = {}
+ if user_cfg_path.exists():
+ with open(user_cfg_path) as fp:
+ user_config = json.load(fp)
+ user_root = user_config.get("vfxnaming_repo")
+
+ root = env_root or user_root
+ if force_repo:
+ root = force_repo
+
+ if not validate_repo(root):
+ raise RepoError(f"VFXNaming repo {root} is not valid, missing naming.conf file.")
+
+ if root.exists():
+ logger.debug(f"VFXNaming repo: {root}")
+ return root
+
+ raise RepoError(f"VFXNaming repo directory doesn't exist: {root}")
def save_session(repo: Union[Path, None] = None) -> bool:
From 60dc4ec4be96f4a38913ff45592446b6bb446669 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sun, 11 Aug 2024 11:11:59 -0300
Subject: [PATCH 39/65] Adds tokens and rules validations. Refactor
save_session
---
src/vfxnaming/error.py | 4 ++++
src/vfxnaming/naming.py | 52 +++++++++++++++++++++++++++--------------
src/vfxnaming/rules.py | 27 ++++++++++++++++++++-
src/vfxnaming/tokens.py | 12 ++++++++++
4 files changed, 77 insertions(+), 18 deletions(-)
diff --git a/src/vfxnaming/error.py b/src/vfxnaming/error.py
index b4942ac..12b356b 100644
--- a/src/vfxnaming/error.py
+++ b/src/vfxnaming/error.py
@@ -10,5 +10,9 @@ class TokenError(BaseException):
"""Raise when Token errors are detected."""
+class RuleError(BaseException):
+ """Raise when Rule errors are detected."""
+
+
class RepoError(BaseException):
"""Raise when Repo errors are detected."""
diff --git a/src/vfxnaming/naming.py b/src/vfxnaming/naming.py
index 8f58406..c46baec 100644
--- a/src/vfxnaming/naming.py
+++ b/src/vfxnaming/naming.py
@@ -19,6 +19,8 @@
import os
import re
import json
+import traceback
+import shutil
import vfxnaming.rules as rules
import vfxnaming.tokens as tokens
from pathlib import Path
@@ -138,7 +140,7 @@ def validate_repo(repo: Path) -> bool:
Returns:
bool: True if valid, False otherwise.
"""
- config_file = repo / "naming.conf"
+ config_file = repo / "vfxnaming.conf"
if not config_file.exists():
return False
return True
@@ -238,39 +240,55 @@ def get_repo(force_repo: Union[Path, str] = None) -> Path:
raise RepoError(f"VFXNaming repo directory doesn't exist: {root}")
-def save_session(repo: Union[Path, None] = None) -> bool:
+def save_session(repo: Union[Path, None] = None, override=True):
"""Save rules, tokens and config files to the repository.
Raises:
- IOError, OSError: Repository directory could not be created.
+ RepoError: Repository directory could not be created or is not valid.
+
+ TokenError: Not required tokens must have at least one option (fullname=abbreviation).
+
+ TemplateError: Template patterns are not valid.
Args:
- repo (Path, optional): Absolue path to a repository. Defaults to None.
+ ``repo`` (str, optional): Path to a repository. Defaults to None.
+
+ ``override`` (bool, optional): If True, it'll remove given directory and recreate it.
Returns:
- bool: True if saving session operation was successful.
+ [bool]: True if saving session operation was successful.
"""
- repo: Path = repo or get_repo()
+ # Validations
+ rules.validate_rules()
+ tokens.validate_tokens()
+
+ repo = repo or get_repo()
+ if override:
+ try:
+ shutil.rmtree(repo)
+ except (IOError, OSError) as why:
+ raise RepoError(why, traceback.format_exc())
if not repo.exists():
try:
- repo.mkdir(parents=True)
+ os.mkdir(repo)
except (IOError, OSError) as why:
- raise why
- # save tokens
+ raise RepoError(why, traceback.format_exc())
+
+ # Save tokens
for name, token in tokens.get_tokens().items():
- logger.debug(f"Saving token: '{name}' in {repo}")
+ logger.debug(f"Saving token: {name} in {repo}")
tokens.save_token(name, repo)
- # save rules
- for name, rule in rules.get_rules().items():
- if not isinstance(rule, rules.Rule):
+ # Save rules
+ for name, template in rules.get_rules().items():
+ if not isinstance(template, rules.Rule):
continue
- logger.debug(f"Saving rule: '{name}' in {repo}")
+ logger.debug(f"Saving template: {name} in {repo}")
rules.save_rule(name, repo)
# extra configuration
active = rules.get_active_rule()
- config = {"set_active_rule": active.name if active else None}
- filepath = repo / "naming.conf"
- logger.debug(f"Saving active rule: {active.name} in {filepath}")
+ config = {"set_active_template": active.name if active else None}
+ filepath = os.path.join(repo, "vfxnaming.conf")
+ logger.debug(f"Saving active template: {active.name} in {filepath}")
with open(filepath, "w") as fp:
json.dump(config, fp, indent=4)
return True
diff --git a/src/vfxnaming/rules.py b/src/vfxnaming/rules.py
index df6be1c..213ddb5 100644
--- a/src/vfxnaming/rules.py
+++ b/src/vfxnaming/rules.py
@@ -9,7 +9,7 @@
from vfxnaming.serialize import Serializable
from vfxnaming.tokens import get_token
from vfxnaming.logger import logger
-from vfxnaming.error import ParsingError, SolvingError
+from vfxnaming.error import ParsingError, SolvingError, RuleError
_rules = {"_active": None}
@@ -372,6 +372,31 @@ def set_active_rule(name: AnyStr) -> bool:
return False
+def validate_rule_pattern(name):
+ """Validates rule pattern is not empty.
+
+ Args:
+ name (str): The name of the rule to validate its pattern.
+
+ Returns:
+ bool: True if successful, False otherwise.
+ """
+ if has_rule(name):
+ template_obj = get_rule(name)
+ if len(template_obj.pattern) >= 1:
+ return True
+ return False
+
+
+def validate_rules():
+ not_valid = []
+ for name, template in get_rules().items():
+ if not validate_rule_pattern(name):
+ not_valid.append(name)
+ if len(not_valid) >= 1:
+ raise RuleError(f"Rules {', '.join(not_valid)}: Patterns are not valid.")
+
+
def get_rule(name: AnyStr) -> Rule:
"""Gets Rule object with given name.
diff --git a/src/vfxnaming/tokens.py b/src/vfxnaming/tokens.py
index 26d7934..d7f52b3 100644
--- a/src/vfxnaming/tokens.py
+++ b/src/vfxnaming/tokens.py
@@ -445,6 +445,18 @@ def get_tokens() -> Dict:
return _tokens
+def validate_tokens():
+ not_valid = list()
+ for name, token_obj in get_tokens().items():
+ if not token_obj.required and len(token_obj.options) == 0:
+ not_valid.append(name)
+ if len(not_valid) >= 1:
+ raise TokenError(
+ f"Tokens {', '.join(not_valid)}: Not required tokens must "
+ "have at least one option (fullname=abbreviation)."
+ )
+
+
def save_token(name: AnyStr, directory: Path) -> bool:
"""Saves given token serialized to specified location.
From be5a88cab7579cbc164be7d2fb51eb3e7f481a93 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sun, 11 Aug 2024 11:25:10 -0300
Subject: [PATCH 40/65] Update load function conf naming
---
src/vfxnaming/naming.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/vfxnaming/naming.py b/src/vfxnaming/naming.py
index c46baec..da06800 100644
--- a/src/vfxnaming/naming.py
+++ b/src/vfxnaming/naming.py
@@ -308,9 +308,9 @@ def load_session(repo: Union[Path, None] = None) -> bool:
if not repo.exists():
logger.warning(f"Given repo directory does not exist: {repo}")
return False
- namingconf = repo / "naming.conf"
+ namingconf = repo / "vfxnaming.conf"
if not namingconf.exists():
- logger.warning(f"Repo is not valid. naming.conf not found {namingconf}")
+ logger.warning(f"Repo is not valid. vfxnaming.conf not found {namingconf}")
return False
rules.reset_rules()
tokens.reset_tokens()
From f0c10d6a63507ca7549fcaf682cd97cd6318ca5c Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sun, 11 Aug 2024 11:37:37 -0300
Subject: [PATCH 41/65] Not templates, rules
---
src/vfxnaming/naming.py | 4 ++--
src/vfxnaming/rules.py | 9 ++++++---
2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/src/vfxnaming/naming.py b/src/vfxnaming/naming.py
index da06800..d9f8463 100644
--- a/src/vfxnaming/naming.py
+++ b/src/vfxnaming/naming.py
@@ -286,9 +286,9 @@ def save_session(repo: Union[Path, None] = None, override=True):
rules.save_rule(name, repo)
# extra configuration
active = rules.get_active_rule()
- config = {"set_active_template": active.name if active else None}
+ config = {"set_active_rule": active.name if active else None}
filepath = os.path.join(repo, "vfxnaming.conf")
- logger.debug(f"Saving active template: {active.name} in {filepath}")
+ logger.debug(f"Saving active rule: {active.name} in {filepath}")
with open(filepath, "w") as fp:
json.dump(config, fp, indent=4)
return True
diff --git a/src/vfxnaming/rules.py b/src/vfxnaming/rules.py
index 213ddb5..a9a0681 100644
--- a/src/vfxnaming/rules.py
+++ b/src/vfxnaming/rules.py
@@ -2,6 +2,7 @@
import json
import sys
import functools
+from copy import deepcopy
from pathlib import Path
from collections import defaultdict
from typing import Dict, AnyStr, Union, Tuple
@@ -382,8 +383,8 @@ def validate_rule_pattern(name):
bool: True if successful, False otherwise.
"""
if has_rule(name):
- template_obj = get_rule(name)
- if len(template_obj.pattern) >= 1:
+ rule_obj = get_rule(name)
+ if len(rule_obj.pattern) >= 1:
return True
return False
@@ -415,7 +416,9 @@ def get_rules() -> Dict:
Returns:
dict: {rule_name:Rule}
"""
- return _rules
+ rules_copy = deepcopy(_rules)
+ del rules_copy["_active"]
+ return rules_copy
def save_rule(name: AnyStr, directory: Path) -> bool:
From bb8d379df7fdbcf1824a4de1917f11d73937eb79 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sun, 11 Aug 2024 16:51:06 -0300
Subject: [PATCH 42/65] Limit to pull requests
---
.github/workflows/ci_vfxnaming.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/ci_vfxnaming.yml b/.github/workflows/ci_vfxnaming.yml
index 145f01f..3293308 100644
--- a/.github/workflows/ci_vfxnaming.yml
+++ b/.github/workflows/ci_vfxnaming.yml
@@ -1,6 +1,6 @@
name: VFXNaming CI
-on: [push, pull_request]
+on: [pull_request]
jobs:
build:
From e4aa558c4673ef3696b44dd2e052d9904c54ed34 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sun, 11 Aug 2024 18:59:12 -0300
Subject: [PATCH 43/65] Adding referenced rules
---
src/vfxnaming/rules.py | 142 ++++++++++++++++++++++++++++++++++-------
tests/naming_test.py | 2 +-
2 files changed, 121 insertions(+), 23 deletions(-)
diff --git a/src/vfxnaming/rules.py b/src/vfxnaming/rules.py
index a9a0681..ed4c329 100644
--- a/src/vfxnaming/rules.py
+++ b/src/vfxnaming/rules.py
@@ -1,6 +1,6 @@
import re
import json
-import sys
+import traceback
import functools
from copy import deepcopy
from pathlib import Path
@@ -37,6 +37,8 @@ class Rule(Serializable):
r"(}[_\-\.:\|/\\]{|[_\-\.:\|/\\]{|}[_\-\.:\|/\\])"
)
__SEPARATORS_REGEX = re.compile(r"[_\-\.:\|/\\]")
+ __RULE_REFERENCE_REGEX = re.compile(r'{@(?P.+?)}')
+ __AT_CODE = "_FXW_"
ANCHOR_START, ANCHOR_END, ANCHOR_BOTH = (1, 2, 3)
def __init__(self, name, pattern, anchor=ANCHOR_START):
@@ -123,15 +125,16 @@ def parse(self, name: AnyStr) -> Union[Dict, None]:
return None
name_separators = self.__SEPARATORS_REGEX.findall(name)
if len(expected_separators) <= len(name_separators):
- retval = dict()
- match = self._regex.search(name)
+ parsed = {}
+ regex = self.__build_regex()
+ match = regex.search(name)
if match:
name_parts = sorted(match.groupdict().items())
name_parts_str = ", ".join(
[f"('{k[:-3]}': '{v}')" for k, v in name_parts]
)
logger.debug(f"Name parts: {name_parts_str}")
- repeated_fields = dict()
+ repeated_fields = {}
for each in self.fields:
if each not in repeated_fields.keys():
if self.fields.count(each) > 1:
@@ -149,8 +152,8 @@ def parse(self, name: AnyStr) -> Union[Dict, None]:
counter = repeated_fields.get(token_name)
repeated_fields[token_name] = counter + 1
token_name = f"{token_name}{counter}"
- retval[token_name] = token.parse(value)
- return retval
+ parsed[token_name] = token.parse(value)
+ return parsed
else:
raise ParsingError(
f"Separators count mismatch between given name '{name}':'{len(name_separators)}' "
@@ -163,7 +166,7 @@ def __build_regex(self) -> re.Pattern:
expression = re.sub(
r"(?P{(.+?)(:(\\}|.)+?)?})|(?P.+?)",
self.__escape,
- self._pattern,
+ self.expanded_pattern()
)
# Replace placeholders with regex pattern
expression = re.sub(
@@ -190,9 +193,8 @@ def __build_regex(self) -> re.Pattern:
):
raise ValueError("Placeholder name contains invalid characters.")
else:
- _, value, traceback = sys.exc_info()
- message = f"Invalid pattern: {value}"
- raise ValueError(message).with_traceback(traceback)
+ message = f"Invalid pattern.\n{traceback.format_exc()}"
+ raise ValueError(message)
return compiled
@@ -206,6 +208,12 @@ def __convert(self, match: re.Match, placeholder_count: int) -> AnyStr:
# ? Taken from Lucidity by Martin Pengelly-Phillips
placeholder_name = match.group("placeholder")
+ # Support at symbol (@) as referenced template indicator. Currently,
+ # this symbol not a valid character for a group name in the standard
+ # Python regex library. Rather than rewrite or monkey patch the library
+ # work around the restriction with a unique identifier.
+ placeholder_name = placeholder_name.replace('@', self.__AT_CODE)
+
# The re module does not support duplicate group names. To support
# duplicate placeholder names in templates add a unique count to the
# regular expression group name and strip it later during parse.
@@ -221,6 +229,56 @@ def __convert(self, match: re.Match, placeholder_count: int) -> AnyStr:
return r"(?P<{0}>{1})".format(placeholder_name, expression)
+ def expanded_pattern(self):
+ """Return pattern with all referenced rules expanded recursively.
+
+ Returns:
+ [str]: Pattern with all referenced rules expanded recursively.
+ """
+ # ? Taken from Lucidity by Martin Pengelly-Phillips
+ return self.__RULE_REFERENCE_REGEX.sub(
+ self.__expand_reference, self.pattern
+ )
+
+ def expanded_pattern_validation(self, pattern):
+ """Return pattern with all referenced rules expanded recursively from a given pattern
+
+ Args:
+ ``pattern`` (str): Pattern string.
+ e.g.: "{@rule_base}/{token_1}/{token_2}/inmutable_folder/"
+
+ Returns:
+ [str]: Pattern with all referenced rules expanded recursively.
+ """
+ # ? Taken from Lucidity by Martin Pengelly-Phillips
+ return self.__RULE_REFERENCE_REGEX.sub(
+ self.__expand_reference, pattern
+ )
+
+ def __expand_reference(self, match):
+ """Expand reference represented by *match*.
+
+ Args:
+ match (str): Template name to look for in repo.
+
+ Raises:
+ TemplateError: If pattern contains a reference that cannot be
+ resolved.
+
+ Returns:
+ [str]: Expanded reference pattern
+ """
+ # ? Taken from Lucidity by Martin Pengelly-Phillips
+ reference = match.group('reference')
+
+ rule = get_rule(reference)
+ if rule is None:
+ raise RuleError(
+ 'Failed to find reference {} in current repo.'.format(reference)
+ )
+
+ return rule.expanded_pattern()
+
def __escape(self, match: re.Match) -> AnyStr:
"""Escape matched 'other' group value."""
# ? Taken from Lucidity by Martin Pengelly-Phillips
@@ -229,39 +287,55 @@ def __escape(self, match: re.Match) -> AnyStr:
return re.escape(groups.get("other"))
return groups.get("placeholder")
- def __digits_pattern(self) -> AnyStr:
+ def __digits_pattern(self):
# * This accounts for those cases where a token is used more than once in a rule
- digits_pattern = self._pattern
+ digits_pattern = deepcopy(self.expanded_pattern())
for each in list(set(self.fields)):
- regex_pattern = re.compile(each)
+ # ? This is going to be a bit more difficult to handle when nesting templates
+ # ? due to the . character not being contemplated by the pattern
+ regex_pattern = re.compile("{{{0}}}".format(each))
indexes = [match.end() for match in regex_pattern.finditer(digits_pattern)]
- repetetions = len(indexes)
- if repetetions > 1:
+ repetitions = len(indexes)
+ if repetitions > 1:
i = 0
for match in sorted(indexes, reverse=True):
- digits_pattern = f"{digits_pattern[:match]}{str(repetetions - i)}{digits_pattern[match:]}"
- i += 1
+ digits_pattern = f"{digits_pattern[:match-1]}{str(repetitions-i)}{digits_pattern[match-1:]}" i += 1
+ logger.debug(f"Digits pattern to account for repeated fields: {digits_pattern}")
return digits_pattern
@property
def pattern(self) -> AnyStr:
+ """
+ Returns:
+ [str]: Pattern that this Rule was initialized with.
+ """
return self._pattern
+ @pattern.setter
+ def pattern(self, pattern):
+ """
+ Some times we need to change the pattern dinamically, at runtime.
+ """
+ if pattern == "":
+ logger.error(f"Pattern cannot be empty for rule: {self.name}")
+ return
+ self._pattern = pattern
+
@property
def fields(self) -> Tuple:
"""
Returns:
[tuple]: Tuple of all Tokens found in this Rule's pattern
"""
- return tuple(self.__FIELDS_REGEX.findall(self._pattern))
+ return tuple(self.__FIELDS_REGEX.findall(self.expanded_pattern()))
@property
- def regex(self) -> re.Pattern:
+ def anchor(self):
"""
Returns:
- [str]: Regular expression used to parse from this Rule
+ [int]: Rule.ANCHOR_START, Rule.ANCHOR_END, Rule.ANCHOR_BOTH = (1, 2, 3)
"""
- return self._regex
+ return self._anchor
@property
def name(self) -> AnyStr:
@@ -269,6 +343,8 @@ def name(self) -> AnyStr:
@name.setter
def name(self, n: str):
+ if n == "":
+ logger.error(f"Name cannot be empty for rule: {self._pattern}")
self._name = n
@@ -335,6 +411,28 @@ def has_rule(name: AnyStr) -> bool:
return name in _rules.keys()
+def update_rule_name(old_name, new_name):
+ """Update rule name.
+
+ Args:
+ old_name (str): The current name of the rule to update.
+
+ new_name (str): The new name of the rule to be updated.
+
+ Returns:
+ True if Rule name was updated, False if another rule
+ has that name already or no current rule with old_name was found.
+ """
+ if has_rule(old_name) and not has_rule(new_name):
+ rule_obj = _rules.pop(old_name)
+ rule_obj.name = new_name
+ _rules[new_name] = rule_obj
+ if _rules.get("_active") == old_name:
+ _rules["_active"] == new_name
+ return True
+ return False
+
+
def reset_rules() -> bool:
"""Clears all rules created for current session.
@@ -391,7 +489,7 @@ def validate_rule_pattern(name):
def validate_rules():
not_valid = []
- for name, template in get_rules().items():
+ for name, rule in get_rules().items():
if not validate_rule_pattern(name):
not_valid.append(name)
if len(not_valid) >= 1:
diff --git a/tests/naming_test.py b/tests/naming_test.py
index 81838bd..9f9dcbd 100644
--- a/tests/naming_test.py
+++ b/tests/naming_test.py
@@ -513,7 +513,7 @@ def test_rules(self, name: str, pattern: str):
rule2 = rules.Rule.from_data(rule1.data())
assert rule1.data() == rule2.data()
- def test_validation(self):
+ def test_from_data_validation(self):
token = tokens.add_token(
"function",
key="key",
From 55ad519778212de3a7a4abded47901ddfb725ce7 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Sun, 11 Aug 2024 19:19:05 -0300
Subject: [PATCH 44/65] Working on new referenced functionality an tests
---
src/vfxnaming/rules.py | 23 ++--
src/vfxnaming/tokens.py | 244 ++++++++++++++++++++++++++++++++++++----
2 files changed, 230 insertions(+), 37 deletions(-)
diff --git a/src/vfxnaming/rules.py b/src/vfxnaming/rules.py
index ed4c329..3ceab6b 100644
--- a/src/vfxnaming/rules.py
+++ b/src/vfxnaming/rules.py
@@ -37,7 +37,7 @@ class Rule(Serializable):
r"(}[_\-\.:\|/\\]{|[_\-\.:\|/\\]{|}[_\-\.:\|/\\])"
)
__SEPARATORS_REGEX = re.compile(r"[_\-\.:\|/\\]")
- __RULE_REFERENCE_REGEX = re.compile(r'{@(?P.+?)}')
+ __RULE_REFERENCE_REGEX = re.compile(r"{@(?P.+?)}")
__AT_CODE = "_FXW_"
ANCHOR_START, ANCHOR_END, ANCHOR_BOTH = (1, 2, 3)
@@ -166,7 +166,7 @@ def __build_regex(self) -> re.Pattern:
expression = re.sub(
r"(?P{(.+?)(:(\\}|.)+?)?})|(?P.+?)",
self.__escape,
- self.expanded_pattern()
+ self.expanded_pattern(),
)
# Replace placeholders with regex pattern
expression = re.sub(
@@ -212,7 +212,7 @@ def __convert(self, match: re.Match, placeholder_count: int) -> AnyStr:
# this symbol not a valid character for a group name in the standard
# Python regex library. Rather than rewrite or monkey patch the library
# work around the restriction with a unique identifier.
- placeholder_name = placeholder_name.replace('@', self.__AT_CODE)
+ placeholder_name = placeholder_name.replace("@", self.__AT_CODE)
# The re module does not support duplicate group names. To support
# duplicate placeholder names in templates add a unique count to the
@@ -236,10 +236,8 @@ def expanded_pattern(self):
[str]: Pattern with all referenced rules expanded recursively.
"""
# ? Taken from Lucidity by Martin Pengelly-Phillips
- return self.__RULE_REFERENCE_REGEX.sub(
- self.__expand_reference, self.pattern
- )
-
+ return self.__RULE_REFERENCE_REGEX.sub(self.__expand_reference, self.pattern)
+
def expanded_pattern_validation(self, pattern):
"""Return pattern with all referenced rules expanded recursively from a given pattern
@@ -251,9 +249,7 @@ def expanded_pattern_validation(self, pattern):
[str]: Pattern with all referenced rules expanded recursively.
"""
# ? Taken from Lucidity by Martin Pengelly-Phillips
- return self.__RULE_REFERENCE_REGEX.sub(
- self.__expand_reference, pattern
- )
+ return self.__RULE_REFERENCE_REGEX.sub(self.__expand_reference, pattern)
def __expand_reference(self, match):
"""Expand reference represented by *match*.
@@ -269,12 +265,12 @@ def __expand_reference(self, match):
[str]: Expanded reference pattern
"""
# ? Taken from Lucidity by Martin Pengelly-Phillips
- reference = match.group('reference')
+ reference = match.group("reference")
rule = get_rule(reference)
if rule is None:
raise RuleError(
- 'Failed to find reference {} in current repo.'.format(reference)
+ "Failed to find reference {} in current repo.".format(reference)
)
return rule.expanded_pattern()
@@ -299,7 +295,8 @@ def __digits_pattern(self):
if repetitions > 1:
i = 0
for match in sorted(indexes, reverse=True):
- digits_pattern = f"{digits_pattern[:match-1]}{str(repetitions-i)}{digits_pattern[match-1:]}" i += 1
+ digits_pattern = f"{digits_pattern[:match-1]}{str(repetitions-i)}{digits_pattern[match-1:]}"
+ i += 1
logger.debug(f"Digits pattern to account for repeated fields: {digits_pattern}")
return digits_pattern
diff --git a/src/vfxnaming/tokens.py b/src/vfxnaming/tokens.py
index d7f52b3..b665aac 100644
--- a/src/vfxnaming/tokens.py
+++ b/src/vfxnaming/tokens.py
@@ -28,45 +28,47 @@ def __init__(self, name: AnyStr):
self._default = None
self._options: Dict = {}
- def add_option(self, key: AnyStr, value: AnyStr) -> bool:
+ def add_option(self, fullname: AnyStr, abbreviation: AnyStr) -> bool:
"""Add an option pair to this Token.
Args:
- key (str): Full name of the option
- value (str): Abbreviation to be used when building the name.
+ fullname (str): Full name of the option
+ abbreviation (str): Abbreviation to be used when building the name.
Returns:
[bool]: True if successful. False otherwise.
"""
- if key not in self._options.keys():
- self._options[key] = value
+ if fullname not in self._options.keys():
+ self._options[fullname] = abbreviation
+ if len(self._options) == 1:
+ self._default = fullname
return True
logger.debug(
- f"Option '{key}':'{self._options.get(key)}' already exists in Token '{self.name}'. "
+ f"Option '{fullname}':'{self._options.get(fullname)}' already exists in Token '{self.name}'. "
"Use update_option() instead."
)
return False
- def update_option(self, key: AnyStr, value: AnyStr) -> bool:
+ def update_option(self, fullname: AnyStr, abbreviation: AnyStr) -> bool:
"""Update an option pair on this Token.
Args:
- key (str): Full name of the option
- value (str): Abbreviation to be used when building the name.
+ fullname (str): Full name of the option
+ abbreviation (str): Abbreviation to be used when building the name.
Returns:
[bool]: True if successful. False otherwise.
"""
- if key in self._options.keys():
- self._options[key] = value
+ if fullname in self._options.keys():
+ self._options[fullname] = abbreviation
return True
logger.debug(
- f"Option '{key}':'{self._options.get(key)}' doesn't exist in Token '{self.name}'. "
+ f"Option '{fullname}':'{self._options.get(fullname)}' doesn't exist in Token '{self.name}'. "
"Use add_option() instead."
)
return False
- def remove_option(self, key: AnyStr) -> bool:
+ def remove_option(self, fullname: AnyStr) -> bool:
"""Remove an option on this Token.
Args:
@@ -75,37 +77,42 @@ def remove_option(self, key: AnyStr) -> bool:
Returns:
[bool]: True if successful. False otherwise.
"""
- if key in self._options.keys():
- del self._options[key]
+ if fullname in self._options.keys():
+ del self._options[fullname]
return True
logger.debug(
- f"Option '{key}':'{self._options.get(key)}' doesn't exist in Token '{self.name}'"
+ f"Option '{fullname}':'{self._options.get(fullname)}' doesn't exist in Token '{self.name}'"
)
return False
- def has_option_fullname(self, key: AnyStr) -> bool:
+ def clear_options(self):
+ """Clears all the options for this token."""
+ self._default = None
+ self._options = {}
+
+ def has_option_fullname(self, fullname: AnyStr) -> bool:
"""Looks for given option full name in the options.
Args:
- key (str): Full name of the option
+ fullname (str): Full name of the option
Returns:
[bool]: True if found. False otherwise.
"""
- if key in self._options.keys():
+ if fullname in self._options.keys():
return True
return False
- def has_option_abbreviation(self, value: AnyStr) -> bool:
+ def has_option_abbreviation(self, abbreviation: AnyStr) -> bool:
"""Looks for given option abbreviation in the options.
Args:
- value ([type]): [description]
+ abbreviation ([type]): [description]
Returns:
[type]: [description]
"""
- if value in self._options.values():
+ if abbreviation in self._options.values():
return True
return False
@@ -119,11 +126,14 @@ def solve(self, name: Union[AnyStr, None] = None) -> AnyStr:
Raises:
SolvingError: If Token is required and no value is passed.
+
SolvingError: If given name is not found in options list.
Returns:
str: If Token is required, the same input value is returned
+
str: If Token has options, the abbreviation for given name is returned
+
str: If nothing is passed and Token has options, default option is returned.
"""
if self.required and name:
@@ -164,10 +174,18 @@ def parse(self, value: AnyStr) -> AnyStr:
@property
def required(self) -> bool:
+ """
+ Returns:
+ [bool]: True if Token is required, False otherwise
+ """
return self.default is None
@property
def name(self) -> AnyStr:
+ """
+ Returns:
+ [str]: Name of this Token
+ """
return self._name
@name.setter
@@ -188,10 +206,18 @@ def default(self) -> AnyStr:
@default.setter
def default(self, d: AnyStr):
+ """
+ Args:
+ d (str): Value of the default option to be set
+ """
self._default = d
@property
def options(self) -> Dict:
+ """
+ Returns:
+ [dict]: {"option_full_name":"abbreviation"}
+ """
return copy.deepcopy(self._options)
@@ -270,6 +296,10 @@ def parse(self, value: AnyStr) -> int:
@property
def name(self) -> AnyStr:
+ """
+ Returns:
+ [str]: Name of this Token
+ """
return self._name
@name.setter
@@ -303,7 +333,7 @@ def prefix(self, this_prefix: AnyStr):
if isinstance(this_prefix, str) and not this_prefix.isdigit():
self._options["prefix"] = this_prefix
else:
- logger.warning(f"Given prefix has to be a string: {this_prefix}")
+ logger.warning(f"Prefix must be a string: {this_prefix}")
@property
def suffix(self) -> AnyStr:
@@ -314,7 +344,7 @@ def suffix(self, this_suffix: AnyStr):
if isinstance(this_suffix, str) and not this_suffix.isdigit():
self._options["suffix"] = this_suffix
else:
- logger.warning(f"Given suffix has to be a string: {this_suffix}")
+ logger.warning(f"Suffix must be a string: {this_suffix}")
@property
def options(self) -> Dict:
@@ -414,6 +444,28 @@ def has_token(name: AnyStr) -> bool:
return name in _tokens.keys()
+def update_token_name(old_name, new_name):
+ """Update token name.
+
+ Args:
+ old_name (str): The current name of the token to update.
+
+ new_name (str): The new name of the token to be updated.
+
+ Returns:
+ True if Token name was updated, False if another token
+ has that name already or no current template with old_name was found.
+ """
+ if has_token(old_name) and not has_token(new_name):
+ token_obj = _tokens.pop(old_name)
+ token_obj.name = new_name
+ _tokens[new_name] = token_obj
+ if _tokens.get("_active") == old_name:
+ _tokens["_active"] == new_name
+ return True
+ return False
+
+
def reset_tokens() -> bool:
"""Clears all rules created for current session.
@@ -436,6 +488,150 @@ def get_token(name: AnyStr) -> Union[Token, TokenNumber, None]:
return _tokens.get(name)
+def get_token_options(token_name):
+ """Gets Token options for given token
+
+ Args:
+ ``token_name`` (str): The name of the token to query.
+
+ Returns:
+ [dict]: Token options. None if no token with given name was found,
+ or token has no options.
+ """
+ if has_token(token_name):
+ token_obj = get_token(token_name)
+ return token_obj.options
+ return None
+
+
+def get_token_default_option(token_name):
+ """Gets Token default option for given token
+
+ Args:
+ ``token_name`` (str): The name of the token to query.
+
+ Returns:
+ [dict]: Token default option. None if no token with given name was found,
+ or token has no options.
+ """
+ if has_token(token_name):
+ token_obj = get_token(token_name)
+ option_dict = {token_obj.default: token_obj.options.get(token_obj.default)}
+ return option_dict
+ return None
+
+
+def add_option_to_token(token_name, fullname, abbreviation):
+ """Adds an option pair to this Token.
+
+ Args:
+ ``token_name`` (str): The name of the exisiting token.
+
+ ``fullname`` (str): Full length name of the option.
+
+ ``abbreviation`` (str): Abbreviation to be used when building the path.
+
+ Returns:
+ [bool]: True if successful. False otherwise.
+ """
+ if has_token(token_name):
+ token_obj = get_token(token_name)
+ return token_obj.add_option(fullname, abbreviation)
+ return False
+
+
+def update_option_fullname_from_token(token_name, old_fullname, new_fullname):
+ """Update an option fullname on this Token.
+
+ Args:
+ ``token_name`` (str): The name of the exisiting token.
+
+ ``old_fullname`` (str): Old full length name of the option.
+
+ ``new_fullname`` (str): New full length name of the option.
+
+ ``abbreviation`` (str): Abbreviation to be used when building the path.
+
+ Returns:
+ [bool]: True if successful. False otherwise.
+ """
+ if has_token(token_name):
+ token_obj = get_token(token_name)
+ if token_obj.has_option_fullname(old_fullname):
+ abbreviation = token_obj.options.get(old_fullname)
+ token_obj.remove_option(old_fullname)
+ return token_obj.add_option(new_fullname, abbreviation)
+ return False
+
+
+def update_option_abbreviation_from_token(token_name, fullname, abbreviation):
+ """Update an option abbreviation on this Token.
+
+ Args:
+ ``token_name`` (str): The name of the exisiting token.
+
+ ``fullname`` (str): Full length name of the option.
+
+ ``abbreviation`` (str): Abbreviation to be used when building the path.
+
+ Returns:
+ [bool]: True if successful. False otherwise.
+ """
+ if has_token(token_name):
+ token_obj = get_token(token_name)
+ if token_obj.has_option_fullname(fullname):
+ return token_obj.update_option(fullname, abbreviation)
+ return False
+
+
+def remove_option_from_token(token_name, fullname):
+ """Remove an option on given token.
+
+ Args:
+ ``token_name`` (str): The name of the exisiting token.
+
+ ``fullname`` (str): Full length name of the option
+
+ Returns:
+ [bool]: True if successful. False otherwise.
+ """
+ if has_token(token_name):
+ token_obj = get_token(token_name)
+ if token_obj.has_option_fullname(fullname):
+ return token_obj.remove_option(fullname)
+ return False
+
+
+def has_option_fullname(token_name, fullname):
+ """Looks for given option full name in the given token options.
+
+ Args:
+ ``fullname`` (str): Full name of the option
+
+ Returns:
+ [bool]: True if found. False otherwise.
+ """
+ if has_token(token_name):
+ token_obj = get_token(token_name)
+ return token_obj.has_option_fullname(fullname)
+ return False
+
+
+def has_option_abbreviation(token_name, abbreviation):
+ """Looks for given option abbreviation in the given token options.
+
+ Args:
+ ``abbreviation`` (str): Abbreviation
+
+ Returns:
+ [bool]: True if found. False otherwise.
+ """
+ if has_token(token_name):
+ token_obj = get_token(token_name)
+ return token_obj.has_option_abbreviation(abbreviation)
+ return False
+
+
def get_tokens() -> Dict:
"""Get all Token and TokenNumber objects for current session.
From a243b9df423b883e0383ef3560e3d0cca54ce977 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Mon, 23 Dec 2024 10:28:08 -0300
Subject: [PATCH 45/65] Adds validation function and test
---
Pipfile.lock | 966 ++++++++++++++++++++------------------
src/vfxnaming/__init__.py | 2 +-
src/vfxnaming/naming.py | 13 +
src/vfxnaming/rules.py | 67 +++
tests/naming_test.py | 49 ++
5 files changed, 641 insertions(+), 456 deletions(-)
diff --git a/Pipfile.lock b/Pipfile.lock
index c110631..a918d56 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -19,11 +19,11 @@
"develop": {
"alabaster": {
"hashes": [
- "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65",
- "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92"
+ "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e",
+ "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b"
],
- "markers": "python_version >= '3.9'",
- "version": "==0.7.16"
+ "markers": "python_version >= '3.10'",
+ "version": "==1.0.0"
},
"annotated-types": {
"hashes": [
@@ -51,124 +51,139 @@
},
"build": {
"hashes": [
- "sha256:526263f4870c26f26c433545579475377b2b7588b6f1eac76a001e873ae3e19d",
- "sha256:75e10f767a433d9a86e50d83f418e83efc18ede923ee5ff7df93b6cb0306c5d4"
+ "sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5",
+ "sha256:b36993e92ca9375a219c99e606a122ff365a760a2d4bba0caa09bd5278b608b7"
],
"index": "pypi",
"markers": "python_version >= '3.8'",
- "version": "==1.2.1"
+ "version": "==1.2.2.post1"
},
"certifi": {
"hashes": [
- "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b",
- "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"
+ "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56",
+ "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"
],
"markers": "python_version >= '3.6'",
- "version": "==2024.7.4"
+ "version": "==2024.12.14"
},
"charset-normalizer": {
"hashes": [
- "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027",
- "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087",
- "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786",
- "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8",
- "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09",
- "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185",
- "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574",
- "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e",
- "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519",
- "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898",
- "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269",
- "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3",
- "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f",
- "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6",
- "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8",
- "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a",
- "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73",
- "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc",
- "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714",
- "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2",
- "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc",
- "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce",
- "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d",
- "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e",
- "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6",
- "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269",
- "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96",
- "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d",
- "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a",
- "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4",
- "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77",
- "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d",
- "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0",
- "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed",
- "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068",
- "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac",
- "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25",
- "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8",
- "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab",
- "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26",
- "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2",
- "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db",
- "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f",
- "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5",
- "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99",
- "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c",
- "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d",
- "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811",
- "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa",
- "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a",
- "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03",
- "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b",
- "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04",
- "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c",
- "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001",
- "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458",
- "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389",
- "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99",
- "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985",
- "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537",
- "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238",
- "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f",
- "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d",
- "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796",
- "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a",
- "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143",
- "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8",
- "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c",
- "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5",
- "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5",
- "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711",
- "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4",
- "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6",
- "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c",
- "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7",
- "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4",
- "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b",
- "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae",
- "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12",
- "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c",
- "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae",
- "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8",
- "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887",
- "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b",
- "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4",
- "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f",
- "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5",
- "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33",
- "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519",
- "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"
+ "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621",
+ "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6",
+ "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8",
+ "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912",
+ "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c",
+ "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b",
+ "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d",
+ "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d",
+ "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95",
+ "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e",
+ "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565",
+ "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64",
+ "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab",
+ "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be",
+ "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e",
+ "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907",
+ "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0",
+ "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2",
+ "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62",
+ "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62",
+ "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23",
+ "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc",
+ "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284",
+ "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca",
+ "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455",
+ "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858",
+ "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b",
+ "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594",
+ "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc",
+ "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db",
+ "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b",
+ "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea",
+ "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6",
+ "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920",
+ "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749",
+ "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7",
+ "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd",
+ "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99",
+ "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242",
+ "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee",
+ "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129",
+ "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2",
+ "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51",
+ "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee",
+ "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8",
+ "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b",
+ "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613",
+ "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742",
+ "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe",
+ "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3",
+ "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5",
+ "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631",
+ "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7",
+ "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15",
+ "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c",
+ "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea",
+ "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417",
+ "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250",
+ "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88",
+ "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca",
+ "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa",
+ "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99",
+ "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149",
+ "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41",
+ "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574",
+ "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0",
+ "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f",
+ "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d",
+ "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654",
+ "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3",
+ "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19",
+ "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90",
+ "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578",
+ "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9",
+ "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1",
+ "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51",
+ "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719",
+ "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236",
+ "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a",
+ "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c",
+ "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade",
+ "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944",
+ "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc",
+ "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6",
+ "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6",
+ "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27",
+ "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6",
+ "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2",
+ "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12",
+ "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf",
+ "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114",
+ "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7",
+ "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf",
+ "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d",
+ "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b",
+ "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed",
+ "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03",
+ "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4",
+ "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67",
+ "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365",
+ "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a",
+ "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748",
+ "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b",
+ "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079",
+ "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"
],
"markers": "python_full_version >= '3.7.0'",
- "version": "==3.3.2"
+ "version": "==3.4.0"
},
"click": {
"hashes": [
- "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28",
- "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"
+ "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2",
+ "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"
],
"markers": "python_version >= '3.7'",
- "version": "==8.1.7"
+ "version": "==8.1.8"
},
"colorama": {
"hashes": [
@@ -183,81 +198,71 @@
"toml"
],
"hashes": [
- "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca",
- "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d",
- "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6",
- "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989",
- "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c",
- "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b",
- "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223",
- "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f",
- "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56",
- "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3",
- "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8",
- "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb",
- "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388",
- "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0",
- "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a",
- "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8",
- "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f",
- "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a",
- "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962",
- "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8",
- "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391",
- "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc",
- "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2",
- "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155",
- "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb",
- "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0",
- "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c",
- "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a",
- "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004",
- "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060",
- "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232",
- "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93",
- "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129",
- "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163",
- "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de",
- "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6",
- "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23",
- "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569",
- "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d",
- "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778",
- "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d",
- "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36",
- "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a",
- "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6",
- "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34",
- "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704",
- "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106",
- "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9",
- "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862",
- "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b",
- "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255",
- "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16",
- "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3",
- "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133",
- "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb",
- "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657",
- "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d",
- "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca",
- "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36",
- "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c",
- "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e",
- "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff",
- "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7",
- "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5",
- "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02",
- "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c",
- "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df",
- "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3",
- "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a",
- "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959",
- "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234",
- "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc"
+ "sha256:0824a28ec542a0be22f60c6ac36d679e0e262e5353203bea81d44ee81fe9c6d4",
+ "sha256:085161be5f3b30fd9b3e7b9a8c301f935c8313dcf928a07b116324abea2c1c2c",
+ "sha256:0ae1387db4aecb1f485fb70a6c0148c6cdaebb6038f1d40089b1fc84a5db556f",
+ "sha256:0d59fd927b1f04de57a2ba0137166d31c1a6dd9e764ad4af552912d70428c92b",
+ "sha256:0f957943bc718b87144ecaee70762bc2bc3f1a7a53c7b861103546d3a403f0a6",
+ "sha256:13a9e2d3ee855db3dd6ea1ba5203316a1b1fd8eaeffc37c5b54987e61e4194ae",
+ "sha256:1a330812d9cc7ac2182586f6d41b4d0fadf9be9049f350e0efb275c8ee8eb692",
+ "sha256:22be16571504c9ccea919fcedb459d5ab20d41172056206eb2994e2ff06118a4",
+ "sha256:2d10e07aa2b91835d6abec555ec8b2733347956991901eea6ffac295f83a30e4",
+ "sha256:35371f8438028fdccfaf3570b31d98e8d9eda8bb1d6ab9473f5a390969e98717",
+ "sha256:3c026eb44f744acaa2bda7493dad903aa5bf5fc4f2554293a798d5606710055d",
+ "sha256:41ff7b0da5af71a51b53f501a3bac65fb0ec311ebed1632e58fc6107f03b9198",
+ "sha256:4401ae5fc52ad8d26d2a5d8a7428b0f0c72431683f8e63e42e70606374c311a1",
+ "sha256:44349150f6811b44b25574839b39ae35291f6496eb795b7366fef3bd3cf112d3",
+ "sha256:447af20e25fdbe16f26e84eb714ba21d98868705cb138252d28bc400381f6ffb",
+ "sha256:4a8d8977b0c6ef5aeadcb644da9e69ae0dcfe66ec7f368c89c72e058bd71164d",
+ "sha256:4e12ae8cc979cf83d258acb5e1f1cf2f3f83524d1564a49d20b8bec14b637f08",
+ "sha256:592ac539812e9b46046620341498caf09ca21023c41c893e1eb9dbda00a70cbf",
+ "sha256:5e6b86b5847a016d0fbd31ffe1001b63355ed309651851295315031ea7eb5a9b",
+ "sha256:608a7fd78c67bee8936378299a6cb9f5149bb80238c7a566fc3e6717a4e68710",
+ "sha256:61f70dc68bd36810972e55bbbe83674ea073dd1dcc121040a08cdf3416c5349c",
+ "sha256:65dad5a248823a4996724a88eb51d4b31587aa7aa428562dbe459c684e5787ae",
+ "sha256:777abfab476cf83b5177b84d7486497e034eb9eaea0d746ce0c1268c71652077",
+ "sha256:7e216d8044a356fc0337c7a2a0536d6de07888d7bcda76febcb8adc50bdbbd00",
+ "sha256:85d9636f72e8991a1706b2b55b06c27545448baf9f6dbf51c4004609aacd7dcb",
+ "sha256:899b8cd4781c400454f2f64f7776a5d87bbd7b3e7f7bda0cb18f857bb1334664",
+ "sha256:8a289d23d4c46f1a82d5db4abeb40b9b5be91731ee19a379d15790e53031c014",
+ "sha256:8d2dfa71665a29b153a9681edb1c8d9c1ea50dfc2375fb4dac99ea7e21a0bcd9",
+ "sha256:8e3c3e38930cfb729cb8137d7f055e5a473ddaf1217966aa6238c88bd9fd50e6",
+ "sha256:8f8770dfc6e2c6a2d4569f411015c8d751c980d17a14b0530da2d7f27ffdd88e",
+ "sha256:932fc826442132dde42ee52cf66d941f581c685a6313feebed358411238f60f9",
+ "sha256:96d636c77af18b5cb664ddf12dab9b15a0cfe9c0bde715da38698c8cea748bfa",
+ "sha256:97ddc94d46088304772d21b060041c97fc16bdda13c6c7f9d8fcd8d5ae0d8611",
+ "sha256:98caba4476a6c8d59ec1eb00c7dd862ba9beca34085642d46ed503cc2d440d4b",
+ "sha256:9901d36492009a0a9b94b20e52ebfc8453bf49bb2b27bca2c9706f8b4f5a554a",
+ "sha256:99e266ae0b5d15f1ca8d278a668df6f51cc4b854513daab5cae695ed7b721cf8",
+ "sha256:9c38bf15a40ccf5619fa2fe8f26106c7e8e080d7760aeccb3722664c8656b030",
+ "sha256:a27801adef24cc30871da98a105f77995e13a25a505a0161911f6aafbd66e678",
+ "sha256:abd3e72dd5b97e3af4246cdada7738ef0e608168de952b837b8dd7e90341f015",
+ "sha256:adb697c0bd35100dc690de83154627fbab1f4f3c0386df266dded865fc50a902",
+ "sha256:b12c6b18269ca471eedd41c1b6a1065b2f7827508edb9a7ed5555e9a56dcfc97",
+ "sha256:b9389a429e0e5142e69d5bf4a435dd688c14478a19bb901735cdf75e57b13845",
+ "sha256:ba9e7484d286cd5a43744e5f47b0b3fb457865baf07bafc6bee91896364e1419",
+ "sha256:bb5555cff66c4d3d6213a296b360f9e1a8e323e74e0426b6c10ed7f4d021e464",
+ "sha256:be57b6d56e49c2739cdf776839a92330e933dd5e5d929966fbbd380c77f060be",
+ "sha256:c69e42c892c018cd3c8d90da61d845f50a8243062b19d228189b0224150018a9",
+ "sha256:ccc660a77e1c2bf24ddbce969af9447a9474790160cfb23de6be4fa88e3951c7",
+ "sha256:d5275455b3e4627c8e7154feaf7ee0743c2e7af82f6e3b561967b1cca755a0be",
+ "sha256:d75cded8a3cff93da9edc31446872d2997e327921d8eed86641efafd350e1df1",
+ "sha256:d872ec5aeb086cbea771c573600d47944eea2dcba8be5f3ee649bfe3cb8dc9ba",
+ "sha256:d891c136b5b310d0e702e186d70cd16d1119ea8927347045124cb286b29297e5",
+ "sha256:db1dab894cc139f67822a92910466531de5ea6034ddfd2b11c0d4c6257168073",
+ "sha256:e28bf44afa2b187cc9f41749138a64435bf340adfcacb5b2290c070ce99839d4",
+ "sha256:e5ea1cf0872ee455c03e5674b5bca5e3e68e159379c1af0903e89f5eba9ccc3a",
+ "sha256:e77363e8425325384f9d49272c54045bbed2f478e9dd698dbc65dbc37860eb0a",
+ "sha256:ee5defd1733fd6ec08b168bd4f5387d5b322f45ca9e0e6c817ea6c4cd36313e3",
+ "sha256:f1592791f8204ae9166de22ba7e6705fa4ebd02936c09436a1bb85aabca3e599",
+ "sha256:f2d1ec60d6d256bdf298cb86b78dd715980828f50c46701abc3b0a2b3f8a0dc0",
+ "sha256:f3ca78518bc6bc92828cd11867b121891d75cae4ea9e908d72030609b996db1b",
+ "sha256:f7b15f589593110ae767ce997775d645b47e5cbbf54fd322f8ebea6277466cec",
+ "sha256:fd1213c86e48dfdc5a0cc676551db467495a95a662d2396ecd58e719191446e1",
+ "sha256:ff74026a461eb0660366fb01c650c1d00f833a086b336bdad7ab00cc952072b3"
],
- "markers": "python_version >= '3.8'",
- "version": "==7.6.1"
+ "markers": "python_version >= '3.9'",
+ "version": "==7.6.9"
},
"coveralls": {
"hashes": [
@@ -276,11 +281,11 @@
},
"docutils": {
"hashes": [
- "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6",
- "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b"
+ "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f",
+ "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"
],
- "markers": "python_version >= '3.7'",
- "version": "==0.20.1"
+ "markers": "python_version >= '3.9'",
+ "version": "==0.21.2"
},
"exceptiongroup": {
"hashes": [
@@ -292,11 +297,11 @@
},
"idna": {
"hashes": [
- "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc",
- "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"
+ "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9",
+ "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"
],
- "markers": "python_version >= '3.5'",
- "version": "==3.7"
+ "markers": "python_version >= '3.6'",
+ "version": "==3.10"
},
"imagesize": {
"hashes": [
@@ -308,11 +313,11 @@
},
"importlib-metadata": {
"hashes": [
- "sha256:11901fa0c2f97919b288679932bb64febaeacf289d18ac84dd68cb2e74213369",
- "sha256:72e8d4399996132204f9a16dcc751af254a48f8d1b20b9ff0f98d4a8f901e73d"
+ "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b",
+ "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"
],
- "markers": "python_version >= '3.8'",
- "version": "==8.2.0"
+ "markers": "python_version < '3.12'",
+ "version": "==8.5.0"
},
"iniconfig": {
"hashes": [
@@ -332,35 +337,35 @@
},
"jaraco.context": {
"hashes": [
- "sha256:3e16388f7da43d384a1a7cd3452e72e14732ac9fe459678773a3608a812bf266",
- "sha256:c2f67165ce1f9be20f32f650f25d8edfc1646a8aeee48ae06fb35f90763576d2"
+ "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3",
+ "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4"
],
"markers": "python_version >= '3.8'",
- "version": "==5.3.0"
+ "version": "==6.0.1"
},
"jaraco.functools": {
"hashes": [
- "sha256:3460c74cd0d32bf82b9576bbb3527c4364d5b27a21f5158a62aed6c4b42e23f5",
- "sha256:c9d16a3ed4ccb5a889ad8e0b7a343401ee5b2a71cee6ed192d3f68bc351e94e3"
+ "sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d",
+ "sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649"
],
"markers": "python_version >= '3.8'",
- "version": "==4.0.2"
+ "version": "==4.1.0"
},
"jinja2": {
"hashes": [
- "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369",
- "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"
+ "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb",
+ "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"
],
"markers": "python_version >= '3.7'",
- "version": "==3.1.4"
+ "version": "==3.1.5"
},
"keyring": {
"hashes": [
- "sha256:8d85a1ea5d6db8515b59e1c5d1d1678b03cf7fc8b8dcfb1651e8c4a524eb42ef",
- "sha256:8d963da00ccdf06e356acd9bf3b743208878751032d8599c6cc89eb51310ffae"
+ "sha256:4c753b3ec91717fe713c4edd522d625889d8973a349b0e582622f49766de58e6",
+ "sha256:e67f8ac32b04be4714b42fe84ce7dad9c40985b9ca827c592cc303e7c26d9741"
],
- "markers": "python_version >= '3.8'",
- "version": "==25.3.0"
+ "markers": "platform_machine != 'ppc64le' and platform_machine != 's390x'",
+ "version": "==25.5.0"
},
"markdown-it-py": {
"hashes": [
@@ -372,69 +377,70 @@
},
"markupsafe": {
"hashes": [
- "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf",
- "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff",
- "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f",
- "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3",
- "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532",
- "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f",
- "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617",
- "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df",
- "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4",
- "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906",
- "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f",
- "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4",
- "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8",
- "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371",
- "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2",
- "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465",
- "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52",
- "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6",
- "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169",
- "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad",
- "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2",
- "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0",
- "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029",
- "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f",
- "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a",
- "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced",
- "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5",
- "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c",
- "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf",
- "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9",
- "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb",
- "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad",
- "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3",
- "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1",
- "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46",
- "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc",
- "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a",
- "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee",
- "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900",
- "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5",
- "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea",
- "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f",
- "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5",
- "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e",
- "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a",
- "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f",
- "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50",
- "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a",
- "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b",
- "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4",
- "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff",
- "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2",
- "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46",
- "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b",
- "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf",
- "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5",
- "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5",
- "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab",
- "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd",
- "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"
+ "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4",
+ "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30",
+ "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0",
+ "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9",
+ "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396",
+ "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13",
+ "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028",
+ "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca",
+ "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557",
+ "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832",
+ "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0",
+ "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b",
+ "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579",
+ "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a",
+ "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c",
+ "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff",
+ "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c",
+ "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22",
+ "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094",
+ "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb",
+ "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e",
+ "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5",
+ "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a",
+ "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d",
+ "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a",
+ "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b",
+ "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8",
+ "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225",
+ "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c",
+ "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144",
+ "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f",
+ "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87",
+ "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d",
+ "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93",
+ "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf",
+ "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158",
+ "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84",
+ "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb",
+ "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48",
+ "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171",
+ "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c",
+ "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6",
+ "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd",
+ "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d",
+ "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1",
+ "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d",
+ "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca",
+ "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a",
+ "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29",
+ "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe",
+ "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798",
+ "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c",
+ "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8",
+ "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f",
+ "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f",
+ "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a",
+ "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178",
+ "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0",
+ "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79",
+ "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430",
+ "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"
],
- "markers": "python_version >= '3.7'",
- "version": "==2.1.5"
+ "markers": "python_version >= '3.9'",
+ "version": "==3.0.2"
},
"mdurl": {
"hashes": [
@@ -446,48 +452,57 @@
},
"more-itertools": {
"hashes": [
- "sha256:0f7d9f83a0a8dcfa8a2694a770590d98a67ea943e3d9f5298309a484758c4e27",
- "sha256:fe0e63c4ab068eac62410ab05cccca2dc71ec44ba8ef29916a0090df061cf923"
+ "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef",
+ "sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6"
],
"markers": "python_version >= '3.8'",
- "version": "==10.4.0"
+ "version": "==10.5.0"
},
"nh3": {
"hashes": [
- "sha256:0411beb0589eacb6734f28d5497ca2ed379eafab8ad8c84b31bb5c34072b7164",
- "sha256:14c5a72e9fe82aea5fe3072116ad4661af5cf8e8ff8fc5ad3450f123e4925e86",
- "sha256:19aaba96e0f795bd0a6c56291495ff59364f4300d4a39b29a0abc9cb3774a84b",
- "sha256:34c03fa78e328c691f982b7c03d4423bdfd7da69cd707fe572f544cf74ac23ad",
- "sha256:36c95d4b70530b320b365659bb5034341316e6a9b30f0b25fa9c9eff4c27a204",
- "sha256:3a157ab149e591bb638a55c8c6bcb8cdb559c8b12c13a8affaba6cedfe51713a",
- "sha256:42c64511469005058cd17cc1537578eac40ae9f7200bedcfd1fc1a05f4f8c200",
- "sha256:5f36b271dae35c465ef5e9090e1fdaba4a60a56f0bb0ba03e0932a66f28b9189",
- "sha256:6955369e4d9f48f41e3f238a9e60f9410645db7e07435e62c6a9ea6135a4907f",
- "sha256:7b7c2a3c9eb1a827d42539aa64091640bd275b81e097cd1d8d82ef91ffa2e811",
- "sha256:8ce0f819d2f1933953fca255db2471ad58184a60508f03e6285e5114b6254844",
- "sha256:94a166927e53972a9698af9542ace4e38b9de50c34352b962f4d9a7d4c927af4",
- "sha256:a7f1b5b2c15866f2db413a3649a8fe4fd7b428ae58be2c0f6bca5eefd53ca2be",
- "sha256:c8b3a1cebcba9b3669ed1a84cc65bf005728d2f0bc1ed2a6594a992e817f3a50",
- "sha256:de3ceed6e661954871d6cd78b410213bdcb136f79aafe22aa7182e028b8c7307",
- "sha256:f0eca9ca8628dbb4e916ae2491d72957fdd35f7a5d326b7032a345f111ac07fe"
- ],
- "version": "==0.2.18"
+ "sha256:09f037c02fc2c43b211ff1523de32801dcfb0918648d8e651c36ef890f1731ec",
+ "sha256:0ae9cbd713524cdb81e64663d0d6aae26f678db9f2cd9db0bf162606f1f9f20c",
+ "sha256:10317cd96fe4bbd4eb6b95f3920b71c902157ad44fed103fdcde43e3b8ee8be6",
+ "sha256:181063c581defe683bd4bb78188ac9936d208aebbc74c7f7c16b6a32ae2ebb38",
+ "sha256:1b9a8340a0aab991c68a5ca938d35ef4a8a3f4bf1b455da8855a40bee1fa0ace",
+ "sha256:231addb7643c952cd6d71f1c8702d703f8fe34afcb20becb3efb319a501a12d7",
+ "sha256:3eb04b9c3deb13c3a375ea39fd4a3c00d1f92e8fb2349f25f1e3e4506751774b",
+ "sha256:47b2946c0e13057855209daeffb45dc910bd0c55daf10190bb0b4b60e2999784",
+ "sha256:4fd2e9248725ebcedac3997a8d3da0d90a12a28c9179c6ba51f1658938ac30d0",
+ "sha256:6ed834c68452a600f517dd3e1534dbfaff1f67f98899fecf139a055a25d99150",
+ "sha256:76e2f603b30c02ff6456b233a83fc377dedab6a50947b04e960a6b905637b776",
+ "sha256:813f1c8012dd64c990514b795508abb90789334f76a561fa0fd4ca32d2275330",
+ "sha256:8698db4c04b140800d1a1cd3067fda399e36e1e2b8fc1fe04292a907350a3e9b",
+ "sha256:92f3f1c4f47a2c6f3ca7317b1d5ced05bd29556a75d3a4e2715652ae9d15c05d",
+ "sha256:9705c42d7ff88a0bea546c82d7fe5e59135e3d3f057e485394f491248a1f8ed5",
+ "sha256:ac4d27dc836a476efffc6eb661994426b8b805c951b29c9cf2ff36bc9ad58bc5",
+ "sha256:ce3731c8f217685d33d9268362e5b4f770914e922bba94d368ab244a59a6c397",
+ "sha256:d2a176fd4306b6f0f178a3f67fac91bd97a3a8d8fafb771c9b9ef675ba5c8886",
+ "sha256:da87573f03084edae8eb87cfe811ec338606288f81d333c07d2a9a0b9b976c0b",
+ "sha256:ddefa9fd6794a87e37d05827d299d4b53a3ec6f23258101907b96029bfef138a",
+ "sha256:e1061a4ab6681f6bdf72b110eea0c4e1379d57c9de937db3be4202f7ad6043db",
+ "sha256:e1f7370b4e14cc03f5ae141ef30a1caf81fa5787711f80be9081418dd9eb79d2",
+ "sha256:eb4254b1dac4a1ee49919a5b3f1caf9803ea8dada1816d9e8289e63d3cd0dd9a",
+ "sha256:f7d564871833ddbe54df3aa59053b1110729d3a800cb7628ae8f42adb3d75208"
+ ],
+ "markers": "python_version >= '3.8'",
+ "version": "==0.2.20"
},
"packaging": {
"hashes": [
- "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002",
- "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"
+ "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759",
+ "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"
],
"markers": "python_version >= '3.8'",
- "version": "==24.1"
+ "version": "==24.2"
},
"pkginfo": {
"hashes": [
- "sha256:5df73835398d10db79f8eecd5cd86b1f6d29317589ea70796994d49399af6297",
- "sha256:889a6da2ed7ffc58ab5b900d888ddce90bce912f2d2de1dc1c26f4cb9fe65097"
+ "sha256:8ad91a0445a036782b9366ef8b8c2c50291f83a553478ba8580c73d3215700cf",
+ "sha256:dcd589c9be4da8973eceffa247733c144812759aa67eaf4bbf97016a02f39088"
],
- "markers": "python_version >= '3.6'",
- "version": "==1.10.0"
+ "markers": "python_version >= '3.8'",
+ "version": "==1.12.0"
},
"pluggy": {
"hashes": [
@@ -499,106 +514,117 @@
},
"pydantic": {
"hashes": [
- "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a",
- "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8"
+ "sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d",
+ "sha256:82f12e9723da6de4fe2ba888b5971157b3be7ad914267dea8f05f82b28254f06"
],
"markers": "python_version >= '3.8'",
- "version": "==2.8.2"
+ "version": "==2.10.4"
},
"pydantic-core": {
"hashes": [
- "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d",
- "sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f",
- "sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686",
- "sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482",
- "sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006",
- "sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83",
- "sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6",
- "sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88",
- "sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86",
- "sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a",
- "sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6",
- "sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a",
- "sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6",
- "sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6",
- "sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43",
- "sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c",
- "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4",
- "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e",
- "sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203",
- "sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd",
- "sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1",
- "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24",
- "sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc",
- "sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc",
- "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3",
- "sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598",
- "sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98",
- "sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331",
- "sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2",
- "sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a",
- "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6",
- "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688",
- "sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91",
- "sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa",
- "sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b",
- "sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0",
- "sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840",
- "sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c",
- "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd",
- "sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3",
- "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231",
- "sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1",
- "sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953",
- "sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250",
- "sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a",
- "sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2",
- "sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20",
- "sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434",
- "sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab",
- "sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703",
- "sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a",
- "sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2",
- "sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac",
- "sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611",
- "sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121",
- "sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e",
- "sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b",
- "sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09",
- "sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906",
- "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9",
- "sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7",
- "sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b",
- "sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987",
- "sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c",
- "sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b",
- "sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e",
- "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237",
- "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1",
- "sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19",
- "sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b",
- "sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad",
- "sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0",
- "sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94",
- "sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312",
- "sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f",
- "sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669",
- "sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1",
- "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe",
- "sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99",
- "sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a",
- "sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a",
- "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52",
- "sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c",
- "sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad",
- "sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1",
- "sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a",
- "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f",
- "sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a",
- "sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27"
+ "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278",
+ "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50",
+ "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9",
+ "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f",
+ "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6",
+ "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc",
+ "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54",
+ "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630",
+ "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9",
+ "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236",
+ "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7",
+ "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee",
+ "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b",
+ "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048",
+ "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc",
+ "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130",
+ "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4",
+ "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd",
+ "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4",
+ "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7",
+ "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7",
+ "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4",
+ "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e",
+ "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa",
+ "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6",
+ "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962",
+ "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b",
+ "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f",
+ "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474",
+ "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5",
+ "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459",
+ "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf",
+ "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a",
+ "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c",
+ "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76",
+ "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362",
+ "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4",
+ "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934",
+ "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320",
+ "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118",
+ "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96",
+ "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306",
+ "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046",
+ "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3",
+ "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2",
+ "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af",
+ "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9",
+ "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67",
+ "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a",
+ "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27",
+ "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35",
+ "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b",
+ "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151",
+ "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b",
+ "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154",
+ "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133",
+ "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef",
+ "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145",
+ "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15",
+ "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4",
+ "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc",
+ "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee",
+ "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c",
+ "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0",
+ "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5",
+ "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57",
+ "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b",
+ "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8",
+ "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1",
+ "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da",
+ "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e",
+ "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc",
+ "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993",
+ "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656",
+ "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4",
+ "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c",
+ "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb",
+ "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d",
+ "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9",
+ "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e",
+ "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1",
+ "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc",
+ "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a",
+ "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9",
+ "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506",
+ "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b",
+ "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1",
+ "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d",
+ "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99",
+ "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3",
+ "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31",
+ "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c",
+ "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39",
+ "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a",
+ "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308",
+ "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2",
+ "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228",
+ "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b",
+ "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9",
+ "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad"
],
"markers": "python_version >= '3.8'",
- "version": "==2.20.1"
+ "version": "==2.27.2"
},
"pygments": {
"hashes": [
@@ -610,29 +636,29 @@
},
"pyproject-hooks": {
"hashes": [
- "sha256:4b37730834edbd6bd37f26ece6b44802fb1c1ee2ece0e54ddff8bfc06db86965",
- "sha256:7ceeefe9aec63a1064c18d939bdc3adf2d8aa1988a510afec15151578b232aa2"
+ "sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8",
+ "sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913"
],
"markers": "python_version >= '3.7'",
- "version": "==1.1.0"
+ "version": "==1.2.0"
},
"pytest": {
"hashes": [
- "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5",
- "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"
+ "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6",
+ "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"
],
"index": "pypi",
"markers": "python_version >= '3.8'",
- "version": "==8.3.2"
+ "version": "==8.3.4"
},
"pytest-cov": {
"hashes": [
- "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652",
- "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"
+ "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35",
+ "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0"
],
"index": "pypi",
- "markers": "python_version >= '3.8'",
- "version": "==5.0.0"
+ "markers": "python_version >= '3.9'",
+ "version": "==6.0.0"
},
"pytest-datafiles": {
"hashes": [
@@ -644,19 +670,19 @@
},
"pywin32-ctypes": {
"hashes": [
- "sha256:3426e063bdd5fd4df74a14fa3cf80a0b42845a87e1d1e81f6549f9daec593a60",
- "sha256:bf490a1a709baf35d688fe0ecf980ed4de11d2b3e37b51e5442587a75d9957e7"
+ "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8",
+ "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755"
],
"markers": "sys_platform == 'win32'",
- "version": "==0.2.2"
+ "version": "==0.2.3"
},
"readme-renderer": {
"hashes": [
- "sha256:1818dd28140813509eeed8d62687f7cd4f7bad90d4db586001c5dc09d4fde311",
- "sha256:19db308d86ecd60e5affa3b2a98f017af384678c63c88e5d4556a380e674f3f9"
+ "sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151",
+ "sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1"
],
- "markers": "python_version >= '3.8'",
- "version": "==43.0"
+ "markers": "python_version >= '3.9'",
+ "version": "==44.0"
},
"requests": {
"hashes": [
@@ -684,11 +710,11 @@
},
"rich": {
"hashes": [
- "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222",
- "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"
+ "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098",
+ "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"
],
- "markers": "python_full_version >= '3.7.0'",
- "version": "==13.7.1"
+ "markers": "python_full_version >= '3.8.0'",
+ "version": "==13.9.4"
},
"rstcheck": {
"hashes": [
@@ -709,28 +735,28 @@
},
"ruff": {
"hashes": [
- "sha256:00cc8872331055ee017c4f1071a8a31ca0809ccc0657da1d154a1d2abac5c0be",
- "sha256:083bbcbe6fadb93cd86709037acc510f86eed5a314203079df174c40bbbca6b3",
- "sha256:2dca26154ff9571995107221d0aeaad0e75a77b5a682d6236cf89a58c70b76f4",
- "sha256:33d61fc0e902198a3e55719f4be6b375b28f860b09c281e4bdbf783c0566576a",
- "sha256:4a09ea2c3f7778cc635e7f6edf57d566a8ee8f485f3c4454db7771efb692c499",
- "sha256:548992d342fc404ee2e15a242cdbea4f8e39a52f2e7752d0e4cbe88d2d2f416a",
- "sha256:7e31c9bad4ebf8fdb77b59cae75814440731060a09a0e0077d559a556453acbb",
- "sha256:7f70284e73f36558ef51602254451e50dd6cc479f8b6f8413a95fcb5db4a55fc",
- "sha256:8d796327eed8e168164346b769dd9a27a70e0298d667b4ecee6877ce8095ec8e",
- "sha256:8dfc0a458797f5d9fb622dd0efc52d796f23f0a1493a9527f4e49a550ae9a7e5",
- "sha256:9369c218f789eefbd1b8d82a8cf25017b523ac47d96b2f531eba73770971c9e5",
- "sha256:9ccd078c66a8e419475174bfe60a69adb36ce04f8d4e91b006f1329d5cd44bcf",
- "sha256:a01c34400097b06cf8a6e61b35d6d456d5bd1ae6961542de18ec81eaf33b4cb8",
- "sha256:a36d8dcf55b3a3bc353270d544fb170d75d2dff41eba5df57b4e0b67a95bb64e",
- "sha256:a78ad870ae3c460394fc95437d43deb5c04b5c29297815a2a1de028903f19692",
- "sha256:b88ca3db7eb377eb24fb7c82840546fb7acef75af4a74bd36e9ceb37a890257e",
- "sha256:eaf3d86a1fdac1aec8a3417a63587d93f906c678bb9ed0b796da7b59c1114a1e",
- "sha256:fcc8054f1a717e2213500edaddcf1dbb0abad40d98e1bd9d0ad364f75c763eea"
+ "sha256:0d5f89f254836799af1615798caa5f80b7f935d7a670fad66c5007928e57ace8",
+ "sha256:13e9ec6d6b55f6da412d59953d65d66e760d583dd3c1c72bf1f26435b5bfdbae",
+ "sha256:552fb6d861320958ca5e15f28b20a3d071aa83b93caee33a87b471f99a6c0835",
+ "sha256:58072f0c06080276804c6a4e21a9045a706584a958e644353603d36ca1eb8a60",
+ "sha256:6ddf5d654ac0d44389f6bf05cee4caeefc3132a64b58ea46738111d687352296",
+ "sha256:736272574e97157f7edbbb43b1d046125fce9e7d8d583d5d65d0c9bf2c15addf",
+ "sha256:8ef06f66f4a05c3ddbc9121a8b0cecccd92c5bf3dd43b5472ffe40b8ca10f0f8",
+ "sha256:9183dd615d8df50defa8b1d9a074053891ba39025cf5ae88e8bcb52edcc4bf08",
+ "sha256:97d9aefef725348ad77d6db98b726cfdb075a40b936c7984088804dfd38268a7",
+ "sha256:9f8402b7c4f96463f135e936d9ab77b65711fcd5d72e5d67597b543bbb43cf3f",
+ "sha256:ab78e33325a6f5374e04c2ab924a3367d69a0da36f8c9cb6b894a62017506111",
+ "sha256:bf197b98ed86e417412ee3b6c893f44c8864f816451441483253d5ff22c0e81e",
+ "sha256:c41319b85faa3aadd4d30cb1cffdd9ac6b89704ff79f7664b853785b48eccdf3",
+ "sha256:e248b1f0fa2749edd3350a2a342b67b43a2627434c059a063418e3d375cfe643",
+ "sha256:e4e56b3baa9c23d324ead112a4fdf20db9a3f8f29eeabff1355114dd96014604",
+ "sha256:e5fe710ab6061592521f902fca7ebcb9fabd27bc7c57c764298b1c1f15fff720",
+ "sha256:f21a1143776f8656d7f364bd264a9d60f01b7f52243fbe90e7670c0dfe0cf65d",
+ "sha256:ffb60904651c00a1e0b8df594591770018a0f04587f7deeb3838344fe3adabac"
],
"index": "pypi",
"markers": "python_version >= '3.7'",
- "version": "==0.5.7"
+ "version": "==0.8.4"
},
"shellingham": {
"hashes": [
@@ -749,21 +775,21 @@
},
"sphinx": {
"hashes": [
- "sha256:242f92a7ea7e6c5b406fdc2615413890ba9f699114a9c09192d7dfead2ee9cfe",
- "sha256:c2419e2135d11f1951cd994d6eb18a1835bd8fdd8429f9ca375dc1f3281bd239"
+ "sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2",
+ "sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927"
],
"index": "pypi",
- "markers": "python_version >= '3.9'",
- "version": "==7.4.7"
+ "markers": "python_version >= '3.10'",
+ "version": "==8.1.3"
},
"sphinx-rtd-theme": {
"hashes": [
- "sha256:31558d49249a3841f4351f3e23009573435f5d8479411317350f8bc5aeafcebe",
- "sha256:863b1536bef0eb55992be0d01aa681cd7f45ce4a6277e99e055edb5b34a71d4c"
+ "sha256:422ccc750c3a3a311de4ae327e82affdaf59eb695ba4936538552f3b00f4ee13",
+ "sha256:b7457bc25dda723b20b086a670b9953c859eab60a2a03ee8eb2bb23e176e5f85"
],
"index": "pypi",
- "markers": "python_version >= '3.6'",
- "version": "==2.1.0rc1"
+ "markers": "python_version >= '3.8'",
+ "version": "==3.0.2"
},
"sphinxcontrib-applehelp": {
"hashes": [
@@ -823,44 +849,74 @@
},
"tomli": {
"hashes": [
- "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc",
- "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"
+ "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6",
+ "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd",
+ "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c",
+ "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b",
+ "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8",
+ "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6",
+ "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77",
+ "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff",
+ "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea",
+ "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192",
+ "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249",
+ "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee",
+ "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4",
+ "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98",
+ "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8",
+ "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4",
+ "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281",
+ "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744",
+ "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69",
+ "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13",
+ "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140",
+ "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e",
+ "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e",
+ "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc",
+ "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff",
+ "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec",
+ "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2",
+ "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222",
+ "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106",
+ "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272",
+ "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a",
+ "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"
],
"markers": "python_version < '3.11'",
- "version": "==2.0.1"
+ "version": "==2.2.1"
},
"twine": {
"hashes": [
- "sha256:215dbe7b4b94c2c50a7315c0275d2258399280fbb7d04182c7e55e24b5f93997",
- "sha256:9aa0825139c02b3434d913545c7b847a21c835e11597f5255842d457da2322db"
+ "sha256:36158b09df5406e1c9c1fb8edb24fc2be387709443e7376689b938531582ee27",
+ "sha256:9c6025b203b51521d53e200f4a08b116dee7500a38591668c6a6033117bdc218"
],
"index": "pypi",
"markers": "python_version >= '3.8'",
- "version": "==5.1.1"
+ "version": "==6.0.1"
},
"typer": {
"hashes": [
- "sha256:070d7ca53f785acbccba8e7d28b08dcd88f79f1fbda035ade0aecec71ca5c914",
- "sha256:49e73131481d804288ef62598d97a1ceef3058905aa536a1134f90891ba35482"
+ "sha256:7994fb7b8155b64d3402518560648446072864beefd44aa2dc36972a5972e847",
+ "sha256:a0588c0a7fa68a1978a069818657778f86abe6ff5ea6abf472f940a08bfe4f0a"
],
"markers": "python_version >= '3.7'",
- "version": "==0.12.3"
+ "version": "==0.15.1"
},
"typing-extensions": {
"hashes": [
"sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d",
"sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"
],
- "markers": "python_version >= '3.8'",
+ "markers": "python_version < '3.11'",
"version": "==4.12.2"
},
"urllib3": {
"hashes": [
- "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472",
- "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"
+ "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df",
+ "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"
],
- "markers": "python_version >= '3.8'",
- "version": "==2.2.2"
+ "markers": "python_version >= '3.9'",
+ "version": "==2.3.0"
},
"vfxnaming": {
"editable": true,
@@ -869,20 +925,20 @@
},
"wheel": {
"hashes": [
- "sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f",
- "sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49"
+ "sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729",
+ "sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248"
],
"index": "pypi",
"markers": "python_version >= '3.8'",
- "version": "==0.44.0"
+ "version": "==0.45.1"
},
"zipp": {
"hashes": [
- "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19",
- "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"
+ "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4",
+ "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"
],
- "markers": "python_version >= '3.8'",
- "version": "==3.19.2"
+ "markers": "python_version >= '3.9'",
+ "version": "==3.21.0"
}
}
}
diff --git a/src/vfxnaming/__init__.py b/src/vfxnaming/__init__.py
index ead8b4e..7edef4e 100644
--- a/src/vfxnaming/__init__.py
+++ b/src/vfxnaming/__init__.py
@@ -1,4 +1,4 @@
-from vfxnaming.naming import parse, solve, get_repo, save_session, load_session # noqa: F401
+from vfxnaming.naming import parse, solve, validate, get_repo, save_session, load_session # noqa: F401
from vfxnaming.rules import ( # noqa: F401
add_rule,
remove_rule,
diff --git a/src/vfxnaming/naming.py b/src/vfxnaming/naming.py
index d9f8463..1ac3ada 100644
--- a/src/vfxnaming/naming.py
+++ b/src/vfxnaming/naming.py
@@ -131,6 +131,19 @@ def solve(*args, **kwargs) -> AnyStr:
return rule.solve(**values)
+def validate(name: AnyStr) -> bool:
+ """Validates a name string against the currently active rule.
+
+ Args:
+ name (str): Name string e.g.: C_helmet_001_MSH
+
+ Returns:
+ bool: True if the name is valid, False otherwise.
+ """
+ rule = rules.get_active_rule()
+ return rule.validate(name)
+
+
def validate_repo(repo: Path) -> bool:
"""Valides repo by checking if it contains a naming.conf file.
diff --git a/src/vfxnaming/rules.py b/src/vfxnaming/rules.py
index 3ceab6b..712cec3 100644
--- a/src/vfxnaming/rules.py
+++ b/src/vfxnaming/rules.py
@@ -160,6 +160,73 @@ def parse(self, name: AnyStr) -> Union[Dict, None]:
f"and rule's pattern '{self._pattern}':'{len(expected_separators)}'."
)
+ def validate(self, name: AnyStr) -> bool:
+ """Validate if given name matches the rule pattern.
+
+ Args:
+ name (str): Name string e.g.: C_helmet_001_MSH
+
+ Returns:
+ bool: True if name matches the rule pattern, False otherwise.
+ """
+ expected_separators = self.__PATTERN_SEPARATORS_REGEX.findall(self._pattern)
+ if len(expected_separators) <= 0:
+ logger.warning(
+ f"No separators used for rule '{self.name}', parsing is not possible."
+ )
+ return False
+
+ name_separators = self.__SEPARATORS_REGEX.findall(name)
+ if len(expected_separators) > len(name_separators):
+ logger.warning(
+ f"Separators count mismatch between given name '{name}':'{len(name_separators)}' "
+ f"and rule's pattern '{self._pattern}':'{len(expected_separators)}'."
+ )
+ return False
+
+ regex = self.__build_regex()
+ match = regex.search(name)
+ if not match:
+ logger.warning(f"Name {name} does not match rule pattern '{self._pattern}'")
+ return False
+
+ name_parts = sorted(match.groupdict().items())
+ name_parts_str = ", ".join([f"('{k[:-3]}': '{v}')" for k, v in name_parts])
+ logger.debug(f"Name parts: {name_parts_str}")
+
+ has_tokens_with_options = False
+ for key, value in name_parts:
+ # Strip number that was added to make group name unique
+ token_name = key[:-3]
+ token = get_token(token_name)
+ if not token.required:
+ has_tokens_with_options = True
+ break
+ # If we don't have tokens with options this match is already valid
+ if not has_tokens_with_options:
+ return True
+
+ repeated_fields = {}
+ for each in self.fields:
+ if each not in repeated_fields.keys():
+ if self.fields.count(each) > 1:
+ repeated_fields[each] = 1
+ if repeated_fields:
+ logger.debug(f"Repeated tokens: {', '.join(repeated_fields.keys())}")
+ matching_options = True
+ for key, value in name_parts:
+ # Strip number that was added to make group name unique
+ token_name = key[:-3]
+ token = get_token(token_name)
+ if not token.required:
+ if not (
+ token.has_option_fullname(value)
+ or token.has_option_abbreviation(value)
+ ):
+ logger.debug(f"Token {token_name} has no option {value}")
+ matching_options = False
+ return matching_options
+
def __build_regex(self) -> re.Pattern:
# ? Taken from Lucidity by Martin Pengelly-Phillips
# Escape non-placeholder components
diff --git a/tests/naming_test.py b/tests/naming_test.py
index 9f9dcbd..242b51f 100644
--- a/tests/naming_test.py
+++ b/tests/naming_test.py
@@ -203,6 +203,55 @@ def test_parsing_without_separators(self):
assert parsed is None
+class Test_Validate:
+ @pytest.fixture(autouse=True)
+ def setup(self):
+ tokens.reset_tokens()
+ tokens.add_token("whatAffects")
+ tokens.add_token_number("digits")
+ tokens.add_token(
+ "category",
+ natural="natural",
+ practical="practical",
+ dramatic="dramatic",
+ volumetric="volumetric",
+ default="natural",
+ )
+ tokens.add_token(
+ "function",
+ key="key",
+ fill="fill",
+ ambient="ambient",
+ bounce="bounce",
+ rim="rim",
+ custom="custom",
+ kick="kick",
+ default="custom",
+ )
+ tokens.add_token("type", lighting="LGT", animation="ANI", default="lighting")
+ rules.add_rule("lights", "{category}_{function}_{whatAffects}_{digits}_{type}")
+
+ @pytest.mark.parametrize(
+ "name,expected",
+ [
+ (
+ "dramatic_bounce_chars_001_LGT",
+ True,
+ ),
+ (
+ "dramatic_bounce_chars_001",
+ False,
+ ),
+ (
+ "whatEver_bounce_chars_001_LGT",
+ False,
+ ),
+ ],
+ )
+ def test_valid(self, name: str, expected: bool):
+ assert n.validate(name) is expected
+
+
class Test_RuleWithRepetitions:
@pytest.fixture(autouse=True)
def setup(self):
From 1b31d15544c4d5ebdbacd06f6ed0d9ea677e5909 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Mon, 23 Dec 2024 10:30:15 -0300
Subject: [PATCH 46/65] All tests passing
---
tests/naming_test.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tests/naming_test.py b/tests/naming_test.py
index 242b51f..0405556 100644
--- a/tests/naming_test.py
+++ b/tests/naming_test.py
@@ -367,7 +367,7 @@ def test_solve_repeat_one_token(self, name: str, data: Dict):
"name,data",
[
(
- "C-FRONT_C-PAROT_R-RETMAND",
+ "C-ORBI_C-PAROT_R-RETMAND",
{
"side3": "right",
"region2": "parotidmasseter",
@@ -375,7 +375,7 @@ def test_solve_repeat_one_token(self, name: str, data: Dict):
},
),
(
- "L-FRONT_C-RETMAND_R-FRONT",
+ "L-ORBI_C-RETMAND_R-ORBI",
{
"side1": "left",
"side3": "right",
From aba19d449fab2e5f6260ded72994772598e4f6bf Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Mon, 23 Dec 2024 14:24:16 -0300
Subject: [PATCH 47/65] Validations for token numbers
---
docs/source/changelog.rst | 7 +++++++
docs/source/roadmap.rst | 4 +++-
docs/source/usage/validating.rst | 10 ++++++++++
pyproject.toml | 2 +-
src/vfxnaming/rules.py | 29 ++++++++++++++++++++++++++++-
5 files changed, 49 insertions(+), 3 deletions(-)
create mode 100644 docs/source/usage/validating.rst
diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst
index e5ba8c5..2f78dbe 100644
--- a/docs/source/changelog.rst
+++ b/docs/source/changelog.rst
@@ -1,6 +1,13 @@
Changelog
================================
+1.3.1-beta
+---------------------------------------
+
+**Improvements:**
+ - Adds validate functionality to rules.
+
+
1.3.0-beta
---------------------------------------
diff --git a/docs/source/roadmap.rst b/docs/source/roadmap.rst
index 8362ad9..bf2a420 100644
--- a/docs/source/roadmap.rst
+++ b/docs/source/roadmap.rst
@@ -3,4 +3,6 @@ Roadmap
- Implement referenced Tokens
-- GUI for creating and editing VFXNaming repos
\ No newline at end of file
+- GUI for creating and editing VFXNaming repos
+
+- Improve registry capabilities
\ No newline at end of file
diff --git a/docs/source/usage/validating.rst b/docs/source/usage/validating.rst
new file mode 100644
index 0000000..ad82b07
--- /dev/null
+++ b/docs/source/usage/validating.rst
@@ -0,0 +1,10 @@
+Validating
+=====================
+
+Many times the only thing we need is to know if a name is valid or not for a given rule. Each Rule validates the name according to next criteria:
+
+- The name must have the same number of tokens as the rule.
+- The tokens must be in the same order as the rule.
+- The number of expected separators must match with the rule.
+- If tokens have options, the given name must use one of those options.
+- If token is a number, validates suffix, prefix and padding.
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index dfe8163..fb49129 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "vfxnaming"
-version = "1.3.0-beta"
+version = "1.3.1-beta"
authors = [
{ name="Chris Granados", email="info@chrisgranados.com" },
]
diff --git a/src/vfxnaming/rules.py b/src/vfxnaming/rules.py
index 712cec3..06caad2 100644
--- a/src/vfxnaming/rules.py
+++ b/src/vfxnaming/rules.py
@@ -8,7 +8,7 @@
from typing import Dict, AnyStr, Union, Tuple
from vfxnaming.serialize import Serializable
-from vfxnaming.tokens import get_token
+from vfxnaming.tokens import get_token, TokenNumber
from vfxnaming.logger import logger
from vfxnaming.error import ParsingError, SolvingError, RuleError
@@ -213,6 +213,7 @@ def validate(self, name: AnyStr) -> bool:
repeated_fields[each] = 1
if repeated_fields:
logger.debug(f"Repeated tokens: {', '.join(repeated_fields.keys())}")
+
matching_options = True
for key, value in name_parts:
# Strip number that was added to make group name unique
@@ -225,6 +226,32 @@ def validate(self, name: AnyStr) -> bool:
):
logger.debug(f"Token {token_name} has no option {value}")
matching_options = False
+ if isinstance(token, TokenNumber):
+ if len(token.suffix):
+ if not value.endswith(token.suffix):
+ logger.debug(
+ f"Token {token_name}: {value} must end with {token.suffix}"
+ )
+ matching_options = False
+ if len(token.prefix):
+ if not value.startswith(token.prefix):
+ logger.debug(
+ f"Token {token_name}: {value} must end with {token.prefix}"
+ )
+ matching_options = False
+ digits = value[len(token.prefix) : len(token.suffix) * -1]
+ if not digits.isdigit():
+ logger.debug(
+ f"Token {token_name}: {value} must be digits with "
+ f"prefix '{token.prefix}' and suffix '{token.suffix}'"
+ )
+ matching_options = False
+ if len(digits) != token.padding:
+ logger.debug(
+ f"Token {token_name}: {value} must have {token.padding} digits"
+ )
+ matching_options = False
+
return matching_options
def __build_regex(self) -> re.Pattern:
From 4fd1bd242b00cf5a6bf2ae21e482a6ad94875a99 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Mon, 23 Dec 2024 15:17:20 -0300
Subject: [PATCH 48/65] Padding validation and more docs for it
---
docs/source/index.rst | 1 +
docs/source/usage/validating.rst | 70 +++++++++++++++++++++++++++++++-
src/vfxnaming/rules.py | 22 +++++++---
tests/naming_test.py | 12 ++++++
4 files changed, 97 insertions(+), 8 deletions(-)
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 7814115..84704eb 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -73,6 +73,7 @@ For more information please check :doc:`credits`
usage/repositories
usage/solving
usage/parsing
+ usage/validating
.. toctree::
:maxdepth: 3
diff --git a/docs/source/usage/validating.rst b/docs/source/usage/validating.rst
index ad82b07..28f969d 100644
--- a/docs/source/usage/validating.rst
+++ b/docs/source/usage/validating.rst
@@ -1,10 +1,76 @@
Validating
=====================
-Many times the only thing we need is to know if a name is valid or not for a given rule. Each Rule validates the name according to next criteria:
+.. note::
+ The validating function is vfxnaming.validate(name)
+
+.. warning::
+ The appropiate Rule must be set as active before calling the validate() function. Use vfxnaming.set_active_rule("rule_name")
+
+Many times the only thing we need is to know if a name is valid or not for a given rule. Each Rule validates the name according to the next criteria:
- The name must have the same number of tokens as the rule.
- The tokens must be in the same order as the rule.
- The number of expected separators must match with the rule.
- If tokens have options, the given name must use one of those options.
-- If token is a number, validates suffix, prefix and padding.
\ No newline at end of file
+- If token is a number, validates suffix, prefix and padding.
+
+Let's set these Tokens and Rule.
+
+.. code-block:: python
+
+ import vfxnaming as n
+
+ # CREATE TOKENS
+ n.reset_tokens()
+ n.add_token("whatAffects")
+ n.add_token_number("digits")
+ n.add_token(
+ "category",
+ natural="natural",
+ practical="practical",
+ dramatic="dramatic",
+ volumetric="volumetric",
+ default="natural",
+ )
+ n.add_token(
+ "function",
+ key="key",
+ fill="fill",
+ ambient="ambient",
+ bounce="bounce",
+ rim="rim",
+ custom="custom",
+ kick="kick",
+ default="custom",
+ )
+ n.add_token("type", lighting="LGT", animation="ANI", default="lighting")
+
+ # CREATE RULES
+ n.add_rule("lights", "{category}_{function}_{whatAffects}_{digits}_{type}")
+
+ n.set_active_rule("lights")
+
+And then let's validate these names:
+
+.. code-block:: python
+
+ n.validate("dramatic_bounce_chars_001_LGT")
+ # Result: True
+
+ n.validate("dramatic_bounce_chars_001")
+ # Result: False. Last token is missing.
+
+ n.validate("whatEver_bounce_chars_001_LGT")
+ # Result: False. whatEver is not a valid option for the category token.
+
+ n.validate("dramatic_bounce_chars_01_LGT")
+ # Result: False. Padding on numbers by default is 3, got 2 in these case.
+
+ n.validate("dramatic_bounce_chars_v001_LGT")
+ # Result: False. No prefix are defined by default or by the code above.
+
+ n.validate("dramatic_bounce_chars_1000_LGT")
+ # Result: True. Even though 1000 has 4 digits, we're validating padding, not the number of digits.
+
+
diff --git a/src/vfxnaming/rules.py b/src/vfxnaming/rules.py
index 06caad2..dbed1e2 100644
--- a/src/vfxnaming/rules.py
+++ b/src/vfxnaming/rules.py
@@ -224,32 +224,42 @@ def validate(self, name: AnyStr) -> bool:
token.has_option_fullname(value)
or token.has_option_abbreviation(value)
):
- logger.debug(f"Token {token_name} has no option {value}")
+ logger.warning(f"Token {token_name} has no option {value}")
matching_options = False
if isinstance(token, TokenNumber):
if len(token.suffix):
if not value.endswith(token.suffix):
- logger.debug(
+ logger.warning(
f"Token {token_name}: {value} must end with {token.suffix}"
)
matching_options = False
if len(token.prefix):
if not value.startswith(token.prefix):
- logger.debug(
+ logger.warning(
f"Token {token_name}: {value} must end with {token.prefix}"
)
matching_options = False
digits = value[len(token.prefix) : len(token.suffix) * -1]
+ if not len(token.suffix):
+ digits = value[len(token.prefix) :]
if not digits.isdigit():
- logger.debug(
+ logger.warning(
f"Token {token_name}: {value} must be digits with "
f"prefix '{token.prefix}' and suffix '{token.suffix}'"
)
matching_options = False
- if len(digits) != token.padding:
- logger.debug(
+ continue
+ hash_str = "#" * token.padding
+ limit = int(hash_str.replace("#", "9"))
+ if len(digits) != token.padding and int(digits) <= limit:
+ logger.warning(
f"Token {token_name}: {value} must have {token.padding} digits"
)
+ if int(digits) > limit:
+ logger.debug(
+ f"Token {token_name}: {value} is higher than {limit}. "
+ "Consider increasing padding."
+ )
matching_options = False
return matching_options
diff --git a/tests/naming_test.py b/tests/naming_test.py
index 0405556..cb7d078 100644
--- a/tests/naming_test.py
+++ b/tests/naming_test.py
@@ -246,6 +246,18 @@ def setup(self):
"whatEver_bounce_chars_001_LGT",
False,
),
+ (
+ "dramatic_bounce_chars_01_LGT",
+ False,
+ ),
+ (
+ "dramatic_bounce_chars_v001_LGT",
+ False,
+ ),
+ (
+ "dramatic_bounce_chars_1000_LGT",
+ True,
+ ),
],
)
def test_valid(self, name: str, expected: bool):
From 5f3b5650e417ee039741a51db006549775fa1115 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Mon, 23 Dec 2024 15:18:32 -0300
Subject: [PATCH 49/65] Version up
---
pyproject.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyproject.toml b/pyproject.toml
index fb49129..a04c25a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "vfxnaming"
-version = "1.3.1-beta"
+version = "1.4.0-beta"
authors = [
{ name="Chris Granados", email="info@chrisgranados.com" },
]
From 52126a3483e8a6664aab6ef84eb26bd1bb0f05f7 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Mon, 23 Dec 2024 15:32:39 -0300
Subject: [PATCH 50/65] Version up
---
.github/workflows/ci_vfxnaming.yml | 2 +-
coverage.lcov | 993 +++++++++++++++++++++++++++++
pyproject.toml | 2 +-
3 files changed, 995 insertions(+), 2 deletions(-)
create mode 100644 coverage.lcov
diff --git a/.github/workflows/ci_vfxnaming.yml b/.github/workflows/ci_vfxnaming.yml
index 145f01f..3293308 100644
--- a/.github/workflows/ci_vfxnaming.yml
+++ b/.github/workflows/ci_vfxnaming.yml
@@ -1,6 +1,6 @@
name: VFXNaming CI
-on: [push, pull_request]
+on: [pull_request]
jobs:
build:
diff --git a/coverage.lcov b/coverage.lcov
new file mode 100644
index 0000000..2b50ffe
--- /dev/null
+++ b/coverage.lcov
@@ -0,0 +1,993 @@
+SF:src\vfxnaming\error.py
+DA:1,1
+DA:5,1
+DA:9,1
+DA:13,1
+DA:17,1
+LF:5
+LH:5
+end_of_record
+SF:src\vfxnaming\naming.py
+DA:19,1
+DA:20,1
+DA:21,1
+DA:22,1
+DA:23,1
+DA:24,1
+DA:25,1
+DA:26,1
+DA:27,1
+DA:29,1
+DA:30,1
+DA:33,1
+DA:36,1
+DA:52,1
+DA:53,1
+DA:56,1
+DA:83,1
+DA:85,1
+DA:86,1
+DA:87,1
+DA:88,1
+DA:89,1
+DA:90,1
+DA:91,1
+DA:92,1
+DA:93,1
+DA:94,1
+DA:95,1
+DA:97,1
+DA:98,1
+DA:99,1
+DA:100,1
+DA:101,1
+DA:102,1
+DA:103,1
+DA:105,1
+DA:106,1
+DA:107,1
+DA:108,1
+DA:111,1
+DA:112,1
+DA:113,1
+DA:114,1
+DA:115,1
+DA:116,1
+DA:118,1
+DA:119,1
+DA:120,1
+DA:121,1
+DA:123,1
+DA:124,1
+DA:125,1
+DA:126,1
+DA:127,1
+DA:128,1
+DA:129,1
+DA:130,1
+DA:131,1
+DA:134,1
+DA:143,1
+DA:144,1
+DA:147,1
+DA:156,0
+DA:157,0
+DA:158,0
+DA:159,0
+DA:162,1
+DA:171,0
+DA:173,0
+DA:174,0
+DA:176,0
+DA:177,0
+DA:179,0
+DA:180,0
+DA:181,0
+DA:182,0
+DA:183,0
+DA:184,0
+DA:186,0
+DA:188,0
+DA:189,0
+DA:190,0
+DA:191,0
+DA:193,0
+DA:194,0
+DA:195,0
+DA:196,0
+DA:198,0
+DA:201,1
+DA:232,0
+DA:235,0
+DA:236,0
+DA:237,0
+DA:238,0
+DA:239,0
+DA:240,0
+DA:242,0
+DA:243,0
+DA:244,0
+DA:246,0
+DA:247,0
+DA:249,0
+DA:250,0
+DA:251,0
+DA:253,0
+DA:256,1
+DA:275,1
+DA:276,1
+DA:278,1
+DA:279,1
+DA:280,1
+DA:281,1
+DA:282,0
+DA:283,0
+DA:284,1
+DA:285,1
+DA:286,1
+DA:287,0
+DA:288,0
+DA:291,1
+DA:292,1
+DA:293,1
+DA:295,1
+DA:296,1
+DA:297,0
+DA:298,1
+DA:299,1
+DA:301,1
+DA:302,1
+DA:303,1
+DA:304,1
+DA:305,1
+DA:306,1
+DA:307,1
+DA:310,1
+DA:320,1
+DA:321,1
+DA:322,0
+DA:323,0
+DA:324,1
+DA:325,1
+DA:326,0
+DA:327,0
+DA:328,1
+DA:329,1
+DA:331,1
+DA:332,1
+DA:333,1
+DA:334,1
+DA:335,1
+DA:336,1
+DA:337,1
+DA:338,1
+DA:339,1
+DA:341,1
+DA:342,1
+DA:343,1
+DA:344,1
+DA:345,1
+DA:346,1
+LF:160
+LH:110
+FN:36,53,parse
+FNDA:1,parse
+FN:56,131,solve
+FNDA:1,solve
+FN:134,144,validate
+FNDA:1,validate
+FN:147,159,validate_repo
+FNDA:0,validate_repo
+FN:162,198,validate_tokens_and_referenced_rules
+FNDA:0,validate_tokens_and_referenced_rules
+FN:201,253,get_repo
+FNDA:0,get_repo
+FN:256,307,save_session
+FNDA:1,save_session
+FN:310,346,load_session
+FNDA:1,load_session
+FNF:8
+FNH:5
+end_of_record
+SF:src\vfxnaming\rules.py
+DA:1,1
+DA:2,1
+DA:3,1
+DA:4,1
+DA:5,1
+DA:6,1
+DA:7,1
+DA:8,1
+DA:10,1
+DA:11,1
+DA:12,1
+DA:13,1
+DA:15,1
+DA:18,1
+DA:35,1
+DA:36,1
+DA:39,1
+DA:40,1
+DA:41,1
+DA:42,1
+DA:44,1
+DA:45,1
+DA:46,1
+DA:47,1
+DA:48,1
+DA:49,1
+DA:51,1
+DA:57,1
+DA:58,1
+DA:59,1
+DA:60,1
+DA:61,1
+DA:62,1
+DA:63,1
+DA:65,1
+DA:66,1
+DA:77,1
+DA:78,1
+DA:79,1
+DA:80,1
+DA:81,1
+DA:83,1
+DA:84,1
+DA:86,1
+DA:95,1
+DA:97,1
+DA:98,1
+DA:99,0
+DA:100,0
+DA:104,1
+DA:106,1
+DA:120,1
+DA:121,1
+DA:122,1
+DA:125,1
+DA:126,1
+DA:127,1
+DA:128,1
+DA:129,1
+DA:130,1
+DA:131,1
+DA:132,1
+DA:133,1
+DA:136,1
+DA:137,1
+DA:138,1
+DA:139,1
+DA:140,1
+DA:141,1
+DA:142,1
+DA:143,1
+DA:145,1
+DA:147,1
+DA:148,1
+DA:149,1
+DA:150,0
+DA:151,1
+DA:152,1
+DA:153,1
+DA:154,1
+DA:155,1
+DA:156,1
+DA:158,1
+DA:163,1
+DA:172,1
+DA:173,1
+DA:174,0
+DA:177,0
+DA:179,1
+DA:180,1
+DA:181,1
+DA:185,1
+DA:187,1
+DA:188,1
+DA:189,1
+DA:190,0
+DA:191,0
+DA:193,1
+DA:194,1
+DA:195,1
+DA:197,1
+DA:198,1
+DA:200,1
+DA:201,1
+DA:202,1
+DA:203,1
+DA:204,1
+DA:206,1
+DA:207,0
+DA:209,1
+DA:210,1
+DA:211,1
+DA:212,1
+DA:213,0
+DA:214,1
+DA:215,0
+DA:217,1
+DA:218,1
+DA:220,1
+DA:221,1
+DA:222,1
+DA:223,1
+DA:227,1
+DA:228,1
+DA:229,1
+DA:230,1
+DA:231,0
+DA:232,0
+DA:235,0
+DA:236,1
+DA:237,0
+DA:238,0
+DA:241,0
+DA:242,1
+DA:243,1
+DA:244,1
+DA:245,1
+DA:246,1
+DA:250,1
+DA:251,1
+DA:252,1
+DA:253,1
+DA:254,1
+DA:255,1
+DA:258,1
+DA:259,0
+DA:263,1
+DA:265,1
+DA:267,1
+DA:270,1
+DA:276,1
+DA:282,1
+DA:283,1
+DA:284,1
+DA:286,1
+DA:287,1
+DA:289,1
+DA:290,1
+DA:291,0
+DA:292,0
+DA:298,0
+DA:300,0
+DA:301,0
+DA:303,1
+DA:305,1
+DA:313,1
+DA:319,1
+DA:324,1
+DA:325,1
+DA:327,1
+DA:328,1
+DA:329,1
+DA:332,1
+DA:334,1
+DA:336,1
+DA:343,1
+DA:345,1
+DA:356,0
+DA:358,1
+DA:372,0
+DA:374,0
+DA:375,0
+DA:376,0
+DA:380,0
+DA:382,1
+DA:385,1
+DA:386,1
+DA:387,1
+DA:388,1
+DA:390,1
+DA:392,1
+DA:393,1
+DA:396,1
+DA:397,1
+DA:398,1
+DA:399,1
+DA:400,1
+DA:401,1
+DA:402,1
+DA:403,1
+DA:404,1
+DA:405,1
+DA:407,1
+DA:408,1
+DA:413,1
+DA:415,1
+DA:416,1
+DA:420,0
+DA:421,0
+DA:422,0
+DA:423,0
+DA:425,1
+DA:426,1
+DA:431,1
+DA:433,1
+DA:434,1
+DA:439,0
+DA:441,1
+DA:442,1
+DA:443,1
+DA:445,1
+DA:446,1
+DA:447,0
+DA:448,0
+DA:449,0
+DA:452,1
+DA:471,1
+DA:472,1
+DA:473,1
+DA:474,1
+DA:475,0
+DA:476,0
+DA:477,1
+DA:478,0
+DA:479,0
+DA:480,1
+DA:481,1
+DA:482,1
+DA:483,1
+DA:484,1
+DA:485,1
+DA:488,1
+DA:497,1
+DA:498,1
+DA:499,1
+DA:500,1
+DA:503,1
+DA:512,1
+DA:515,1
+DA:527,0
+DA:528,0
+DA:529,0
+DA:530,0
+DA:531,0
+DA:532,0
+DA:533,0
+DA:534,0
+DA:537,1
+DA:543,1
+DA:544,1
+DA:545,1
+DA:548,1
+DA:555,1
+DA:556,1
+DA:559,1
+DA:569,1
+DA:570,1
+DA:571,1
+DA:572,0
+DA:575,1
+DA:584,1
+DA:585,1
+DA:586,1
+DA:587,1
+DA:588,0
+DA:591,1
+DA:592,1
+DA:593,1
+DA:594,1
+DA:595,0
+DA:596,1
+DA:597,0
+DA:600,1
+DA:609,1
+DA:612,1
+DA:618,1
+DA:619,1
+DA:620,1
+DA:623,1
+DA:634,1
+DA:635,1
+DA:636,0
+DA:637,1
+DA:638,1
+DA:639,1
+DA:640,1
+DA:641,1
+DA:644,1
+DA:653,1
+DA:654,0
+DA:655,1
+DA:656,1
+DA:657,1
+DA:658,0
+DA:659,0
+DA:660,1
+DA:661,1
+DA:662,1
+DA:663,1
+DA:664,0
+LF:310
+LH:253
+FN:44,49,Rule.__init__
+FNDA:1,Rule.__init__
+FN:51,63,Rule.data
+FNDA:1,Rule.data
+FN:66,84,Rule.from_data
+FNDA:1,Rule.from_data
+FN:86,104,Rule.solve
+FNDA:1,Rule.solve
+FN:106,161,Rule.parse
+FNDA:1,Rule.parse
+FN:163,265,Rule.validate
+FNDA:1,Rule.validate
+FN:267,303,Rule.__build_regex
+FNDA:1,Rule.__build_regex
+FN:305,334,Rule.__convert
+FNDA:1,Rule.__convert
+FN:336,343,Rule.expanded_pattern
+FNDA:1,Rule.expanded_pattern
+FN:345,356,Rule.expanded_pattern_validation
+FNDA:0,Rule.expanded_pattern_validation
+FN:358,380,Rule.__expand_reference
+FNDA:0,Rule.__expand_reference
+FN:382,388,Rule.__escape
+FNDA:1,Rule.__escape
+FN:390,405,Rule.__digits_pattern
+FNDA:1,Rule.__digits_pattern
+FN:408,413,Rule.pattern
+FNDA:1,Rule.pattern
+FN:416,423,Rule.pattern
+FNDA:0,Rule.pattern
+FN:426,431,Rule.fields
+FNDA:1,Rule.fields
+FN:434,439,Rule.anchor
+FNDA:0,Rule.anchor
+FN:442,443,Rule.name
+FNDA:1,Rule.name
+FN:446,449,Rule.name
+FNDA:0,Rule.name
+FN:452,485,add_rule
+FNDA:1,add_rule
+FN:488,500,remove_rule
+FNDA:1,remove_rule
+FN:503,512,has_rule
+FNDA:1,has_rule
+FN:515,534,update_rule_name
+FNDA:0,update_rule_name
+FN:537,545,reset_rules
+FNDA:1,reset_rules
+FN:548,556,get_active_rule
+FNDA:1,get_active_rule
+FN:559,572,set_active_rule
+FNDA:1,set_active_rule
+FN:575,588,validate_rule_pattern
+FNDA:1,validate_rule_pattern
+FN:591,597,validate_rules
+FNDA:1,validate_rules
+FN:600,609,get_rule
+FNDA:1,get_rule
+FN:612,620,get_rules
+FNDA:1,get_rules
+FN:623,641,save_rule
+FNDA:1,save_rule
+FN:644,664,load_rule
+FNDA:1,load_rule
+FNF:32
+FNH:26
+end_of_record
+SF:src\vfxnaming\serialize.py
+DA:1,1
+DA:2,1
+DA:5,1
+DA:6,1
+DA:12,1
+DA:13,1
+DA:14,1
+DA:15,1
+DA:17,1
+DA:18,1
+DA:29,1
+DA:30,1
+DA:31,1
+DA:32,1
+DA:33,1
+DA:35,1
+DA:36,1
+DA:37,1
+LF:18
+LH:18
+FN:6,15,Serializable.data
+FNDA:1,Serializable.data
+FN:18,37,Serializable.from_data
+FNDA:1,Serializable.from_data
+FNF:2
+FNH:2
+end_of_record
+SF:src\vfxnaming\tokens.py
+DA:1,1
+DA:2,1
+DA:3,1
+DA:4,1
+DA:6,1
+DA:7,1
+DA:8,1
+DA:11,1
+DA:14,1
+DA:15,1
+DA:26,1
+DA:27,1
+DA:28,1
+DA:29,1
+DA:31,1
+DA:41,1
+DA:42,1
+DA:43,1
+DA:44,1
+DA:45,1
+DA:46,1
+DA:50,1
+DA:52,1
+DA:62,1
+DA:63,1
+DA:64,1
+DA:65,1
+DA:69,1
+DA:71,1
+DA:80,1
+DA:81,1
+DA:82,1
+DA:83,1
+DA:86,1
+DA:88,1
+DA:90,0
+DA:91,0
+DA:93,1
+DA:102,1
+DA:103,1
+DA:104,1
+DA:106,1
+DA:115,1
+DA:116,1
+DA:117,1
+DA:119,1
+DA:139,1
+DA:140,1
+DA:141,1
+DA:142,0
+DA:145,1
+DA:146,1
+DA:147,1
+DA:151,1
+DA:152,1
+DA:153,1
+DA:155,1
+DA:164,1
+DA:165,1
+DA:166,1
+DA:167,1
+DA:168,1
+DA:169,1
+DA:170,0
+DA:175,1
+DA:176,1
+DA:181,1
+DA:183,1
+DA:184,1
+DA:189,1
+DA:191,1
+DA:192,1
+DA:193,0
+DA:195,1
+DA:196,1
+DA:203,1
+DA:204,0
+DA:205,1
+DA:207,1
+DA:208,1
+DA:213,1
+DA:215,1
+DA:216,1
+DA:221,1
+DA:224,1
+DA:225,1
+DA:235,1
+DA:236,1
+DA:237,1
+DA:238,1
+DA:240,1
+DA:250,1
+DA:251,1
+DA:253,1
+DA:262,1
+DA:263,1
+DA:265,1
+DA:266,1
+DA:267,1
+DA:268,1
+DA:269,1
+DA:270,1
+DA:271,1
+DA:272,1
+DA:274,1
+DA:275,1
+DA:276,1
+DA:277,1
+DA:278,1
+DA:279,1
+DA:280,1
+DA:281,1
+DA:283,1
+DA:284,1
+DA:285,1
+DA:286,1
+DA:287,1
+DA:288,0
+DA:290,1
+DA:291,1
+DA:292,1
+DA:293,1
+DA:294,1
+DA:295,1
+DA:297,1
+DA:298,1
+DA:303,1
+DA:305,1
+DA:306,1
+DA:307,0
+DA:309,1
+DA:310,1
+DA:311,0
+DA:313,1
+DA:314,1
+DA:315,1
+DA:317,1
+DA:318,1
+DA:319,1
+DA:321,1
+DA:322,1
+DA:323,1
+DA:324,0
+DA:325,1
+DA:327,1
+DA:328,1
+DA:329,1
+DA:331,1
+DA:332,1
+DA:333,1
+DA:334,1
+DA:336,0
+DA:338,1
+DA:339,1
+DA:340,1
+DA:342,1
+DA:343,1
+DA:344,1
+DA:345,1
+DA:347,0
+DA:349,1
+DA:350,1
+DA:351,0
+DA:354,1
+DA:371,1
+DA:372,1
+DA:373,1
+DA:374,1
+DA:375,1
+DA:376,1
+DA:377,1
+DA:378,1
+DA:379,1
+DA:380,1
+DA:381,1
+DA:382,1
+DA:383,1
+DA:384,1
+DA:385,1
+DA:387,0
+DA:388,1
+DA:389,1
+DA:392,1
+DA:412,1
+DA:413,1
+DA:414,1
+DA:415,1
+DA:416,1
+DA:417,1
+DA:420,1
+DA:429,1
+DA:430,1
+DA:431,1
+DA:432,1
+DA:435,1
+DA:444,1
+DA:447,1
+DA:459,0
+DA:460,0
+DA:461,0
+DA:462,0
+DA:463,0
+DA:464,0
+DA:465,0
+DA:466,0
+DA:469,1
+DA:475,1
+DA:476,1
+DA:479,1
+DA:488,1
+DA:491,1
+DA:501,0
+DA:502,0
+DA:503,0
+DA:504,0
+DA:507,1
+DA:517,0
+DA:518,0
+DA:519,0
+DA:520,0
+DA:521,0
+DA:524,1
+DA:537,0
+DA:538,0
+DA:539,0
+DA:540,0
+DA:543,1
+DA:558,0
+DA:559,0
+DA:560,0
+DA:561,0
+DA:562,0
+DA:563,0
+DA:564,0
+DA:567,1
+DA:580,0
+DA:581,0
+DA:582,0
+DA:583,0
+DA:584,0
+DA:587,1
+DA:598,0
+DA:599,0
+DA:600,0
+DA:601,0
+DA:602,0
+DA:605,1
+DA:614,0
+DA:615,0
+DA:616,0
+DA:617,0
+DA:620,1
+DA:629,0
+DA:630,0
+DA:631,0
+DA:632,0
+DA:635,1
+DA:641,1
+DA:644,1
+DA:645,1
+DA:646,1
+DA:647,1
+DA:648,0
+DA:649,1
+DA:650,0
+DA:656,1
+DA:666,1
+DA:667,1
+DA:668,0
+DA:669,1
+DA:670,1
+DA:671,1
+DA:672,1
+DA:673,1
+DA:676,1
+DA:686,1
+DA:687,0
+DA:688,1
+DA:689,1
+DA:690,1
+DA:691,0
+DA:692,0
+DA:693,1
+DA:694,1
+DA:695,1
+DA:696,1
+DA:697,0
+DA:698,1
+DA:699,1
+DA:700,1
+DA:701,1
+DA:702,0
+LF:292
+LH:224
+FN:15,29,Token.__init__
+FNDA:1,Token.__init__
+FN:31,50,Token.add_option
+FNDA:1,Token.add_option
+FN:52,69,Token.update_option
+FNDA:1,Token.update_option
+FN:71,86,Token.remove_option
+FNDA:1,Token.remove_option
+FN:88,91,Token.clear_options
+FNDA:0,Token.clear_options
+FN:93,104,Token.has_option_fullname
+FNDA:1,Token.has_option_fullname
+FN:106,117,Token.has_option_abbreviation
+FNDA:1,Token.has_option_abbreviation
+FN:119,153,Token.solve
+FNDA:1,Token.solve
+FN:155,173,Token.parse
+FNDA:1,Token.parse
+FN:176,181,Token.required
+FNDA:1,Token.required
+FN:184,189,Token.name
+FNDA:1,Token.name
+FN:192,193,Token.name
+FNDA:0,Token.name
+FN:196,205,Token.default
+FNDA:1,Token.default
+FN:208,213,Token.default
+FNDA:1,Token.default
+FN:216,221,Token.options
+FNDA:1,Token.options
+FN:225,238,TokenNumber.__init__
+FNDA:1,TokenNumber.__init__
+FN:240,251,TokenNumber.solve
+FNDA:1,TokenNumber.solve
+FN:253,295,TokenNumber.parse
+FNDA:1,TokenNumber.parse
+FN:298,303,TokenNumber.name
+FNDA:1,TokenNumber.name
+FN:306,307,TokenNumber.name
+FNDA:0,TokenNumber.name
+FN:310,311,TokenNumber.default
+FNDA:0,TokenNumber.default
+FN:314,315,TokenNumber.required
+FNDA:1,TokenNumber.required
+FN:318,319,TokenNumber.padding
+FNDA:1,TokenNumber.padding
+FN:322,325,TokenNumber.padding
+FNDA:1,TokenNumber.padding
+FN:328,329,TokenNumber.prefix
+FNDA:1,TokenNumber.prefix
+FN:332,336,TokenNumber.prefix
+FNDA:1,TokenNumber.prefix
+FN:339,340,TokenNumber.suffix
+FNDA:1,TokenNumber.suffix
+FN:343,347,TokenNumber.suffix
+FNDA:1,TokenNumber.suffix
+FN:350,351,TokenNumber.options
+FNDA:0,TokenNumber.options
+FN:354,389,add_token
+FNDA:1,add_token
+FN:392,417,add_token_number
+FNDA:1,add_token_number
+FN:420,432,remove_token
+FNDA:1,remove_token
+FN:435,444,has_token
+FNDA:1,has_token
+FN:447,466,update_token_name
+FNDA:0,update_token_name
+FN:469,476,reset_tokens
+FNDA:1,reset_tokens
+FN:479,488,get_token
+FNDA:1,get_token
+FN:491,504,get_token_options
+FNDA:0,get_token_options
+FN:507,521,get_token_default_option
+FNDA:0,get_token_default_option
+FN:524,540,add_option_to_token
+FNDA:0,add_option_to_token
+FN:543,564,update_option_fullname_from_token
+FNDA:0,update_option_fullname_from_token
+FN:567,584,update_option_abbreviation_from_token
+FNDA:0,update_option_abbreviation_from_token
+FN:587,602,remove_option_from_token
+FNDA:0,remove_option_from_token
+FN:605,617,has_option_fullname
+FNDA:0,has_option_fullname
+FN:620,632,has_option_abbreviation
+FNDA:0,has_option_abbreviation
+FN:635,641,get_tokens
+FNDA:1,get_tokens
+FN:644,653,validate_tokens
+FNDA:1,validate_tokens
+FN:656,673,save_token
+FNDA:1,save_token
+FN:676,702,load_token
+FNDA:1,load_token
+FNF:48
+FNH:34
+end_of_record
diff --git a/pyproject.toml b/pyproject.toml
index a04c25a..dc01b5e 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "vfxnaming"
-version = "1.4.0-beta"
+version = "1.4.1-beta"
authors = [
{ name="Chris Granados", email="info@chrisgranados.com" },
]
From 36305df78c8ce0e996dcb29a9c52f6991daa6c24 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Mon, 23 Dec 2024 16:30:45 -0300
Subject: [PATCH 51/65] Ignore flake8 for now
---
src/vfxnaming/rules.py | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/src/vfxnaming/rules.py b/src/vfxnaming/rules.py
index dbed1e2..37b957f 100644
--- a/src/vfxnaming/rules.py
+++ b/src/vfxnaming/rules.py
@@ -160,7 +160,7 @@ def parse(self, name: AnyStr) -> Union[Dict, None]:
f"and rule's pattern '{self._pattern}':'{len(expected_separators)}'."
)
- def validate(self, name: AnyStr) -> bool:
+ def validate(self, name: AnyStr) -> bool: # noqa: C901
"""Validate if given name matches the rule pattern.
Args:
@@ -239,9 +239,9 @@ def validate(self, name: AnyStr) -> bool:
f"Token {token_name}: {value} must end with {token.prefix}"
)
matching_options = False
- digits = value[len(token.prefix) : len(token.suffix) * -1]
+ digits = value[len(token.prefix) : len(token.suffix) * -1] # noqa: E203
if not len(token.suffix):
- digits = value[len(token.prefix) :]
+ digits = value[len(token.prefix) :] # noqa: E203
if not digits.isdigit():
logger.warning(
f"Token {token_name}: {value} must be digits with "
@@ -399,7 +399,11 @@ def __digits_pattern(self):
if repetitions > 1:
i = 0
for match in sorted(indexes, reverse=True):
- digits_pattern = f"{digits_pattern[:match-1]}{str(repetitions-i)}{digits_pattern[match-1:]}"
+ digits_pattern = (
+ f"{digits_pattern[:match-1]}"
+ f"{str(repetitions-i)}"
+ f"{digits_pattern[match-1:]}"
+ )
i += 1
logger.debug(f"Digits pattern to account for repeated fields: {digits_pattern}")
return digits_pattern
From 7d548045d0c9a7157ecb18c83c2c30905ad64cbf Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Mon, 23 Dec 2024 18:34:25 -0300
Subject: [PATCH 52/65] Fix .conf file naming in logs
---
pyproject.toml | 2 +-
src/vfxnaming/naming.py | 6 ++++--
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index dc01b5e..7cf25a2 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "vfxnaming"
-version = "1.4.1-beta"
+version = "1.4.2-beta"
authors = [
{ name="Chris Granados", email="info@chrisgranados.com" },
]
diff --git a/src/vfxnaming/naming.py b/src/vfxnaming/naming.py
index 1ac3ada..1799373 100644
--- a/src/vfxnaming/naming.py
+++ b/src/vfxnaming/naming.py
@@ -145,7 +145,7 @@ def validate(name: AnyStr) -> bool:
def validate_repo(repo: Path) -> bool:
- """Valides repo by checking if it contains a naming.conf file.
+ """Valides repo by checking if it contains a vfxnaming.conf file.
Args:
repo (Path): Repo dir
@@ -244,7 +244,9 @@ def get_repo(force_repo: Union[Path, str] = None) -> Path:
root = force_repo
if not validate_repo(root):
- raise RepoError(f"VFXNaming repo {root} is not valid, missing naming.conf file.")
+ raise RepoError(
+ f"VFXNaming repo {root} is not valid, missing vfxnaming.conf file."
+ )
if root.exists():
logger.debug(f"VFXNaming repo: {root}")
From 6c60b27de333c65dd1855bb7a81d7f4f87d1f4f6 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Mon, 6 Jan 2025 16:51:38 -0300
Subject: [PATCH 53/65] Missing log info in raise statement
---
pyproject.toml | 2 +-
src/vfxnaming/naming.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index 7cf25a2..7adaf19 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "vfxnaming"
-version = "1.4.2-beta"
+version = "1.4.3-beta"
authors = [
{ name="Chris Granados", email="info@chrisgranados.com" },
]
diff --git a/src/vfxnaming/naming.py b/src/vfxnaming/naming.py
index 1799373..378c760 100644
--- a/src/vfxnaming/naming.py
+++ b/src/vfxnaming/naming.py
@@ -113,7 +113,7 @@ def solve(*args, **kwargs) -> AnyStr:
fields_inc += 1
continue
elif token.required and kwargs.get(f) is None and len(args) == 0:
- raise SolvingError("Token {} is required but was not passed.")
+ raise SolvingError(f"Token {token.name} is required but was not passed.")
# Not required and not passed as keyword argument
elif not token.required and kwargs.get(f) is None:
values[f] = token.solve()
From 98f45dcf796f2f9004be3b5420c5a17068a14b32 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Mon, 6 Jan 2025 17:48:04 -0300
Subject: [PATCH 54/65] Let the user know about casing mismatches
---
pyproject.toml | 2 +-
src/vfxnaming/rules.py | 4 ++++
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/pyproject.toml b/pyproject.toml
index 7adaf19..0fd0567 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "vfxnaming"
-version = "1.4.3-beta"
+version = "1.4.4-beta"
authors = [
{ name="Chris Granados", email="info@chrisgranados.com" },
]
diff --git a/src/vfxnaming/rules.py b/src/vfxnaming/rules.py
index 37b957f..5d5ae4e 100644
--- a/src/vfxnaming/rules.py
+++ b/src/vfxnaming/rules.py
@@ -188,6 +188,10 @@ def validate(self, name: AnyStr) -> bool: # noqa: C901
match = regex.search(name)
if not match:
logger.warning(f"Name {name} does not match rule pattern '{self._pattern}'")
+ if regex.search(name.lower()):
+ logger.warning(
+ f"Name {name} has casing mismatches with '{self._pattern}'"
+ )
return False
name_parts = sorted(match.groupdict().items())
From dfb9dda0d0103820ffee2bea16ec0c5e56f09e6c Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Tue, 7 Jan 2025 14:31:37 -0300
Subject: [PATCH 55/65] Improve error info if casing is the problem
---
src/vfxnaming/tokens.py | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/src/vfxnaming/tokens.py b/src/vfxnaming/tokens.py
index b665aac..3fd9369 100644
--- a/src/vfxnaming/tokens.py
+++ b/src/vfxnaming/tokens.py
@@ -144,10 +144,17 @@ def solve(self, name: Union[AnyStr, None] = None) -> AnyStr:
)
elif not self.required and name:
if name not in self._options.keys():
- raise TokenError(
- f"name '{name}' not found in Token '{self.name}'. "
+ lower_match = [k.lower() for k in self._options.keys()]
+ error_msg = (
+ f"Name '{name}' not found in Token '{self.name}'. "
f"Options: {', '.join(self._options.keys())}"
)
+ if name.lower() in lower_match:
+ error_msg = (
+ f"Check casing of '{name}' against token '{self.name}' "
+ f"options: {', '.join(self._options.keys())}"
+ )
+ raise TokenError(error_msg)
return self._options.get(name)
elif not self.required and not name:
return self._options.get(self.default)
From c0049f48dca9565f6d5ea1e1d2dfa44815c8d65e Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Tue, 7 Jan 2025 16:10:21 -0300
Subject: [PATCH 56/65] Implements validation against data passed by the user
---
Pipfile.lock | 410 +++++++++++++++++++---------------------
src/vfxnaming/naming.py | 58 +++++-
src/vfxnaming/rules.py | 47 ++++-
tests/naming_test.py | 82 ++++++++
4 files changed, 365 insertions(+), 232 deletions(-)
diff --git a/Pipfile.lock b/Pipfile.lock
index 1f6d311..2e210ba 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -46,7 +46,7 @@
"sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34",
"sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991"
],
- "markers": "python_version < '3.12'",
+ "markers": "python_version >= '3.8'",
"version": "==1.2.0"
},
"build": {
@@ -68,114 +68,101 @@
},
"charset-normalizer": {
"hashes": [
- "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621",
- "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6",
- "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8",
- "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912",
- "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c",
- "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b",
- "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d",
- "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d",
- "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95",
- "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e",
- "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565",
- "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64",
- "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab",
- "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be",
- "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e",
- "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907",
- "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0",
- "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2",
- "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62",
- "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62",
- "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23",
- "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc",
- "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284",
- "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca",
- "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455",
- "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858",
- "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b",
- "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594",
- "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc",
- "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db",
- "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b",
- "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea",
- "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6",
- "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920",
- "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749",
- "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7",
- "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd",
- "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99",
- "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242",
- "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee",
- "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129",
- "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2",
- "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51",
- "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee",
- "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8",
- "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b",
- "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613",
- "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742",
- "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe",
- "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3",
- "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5",
- "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631",
- "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7",
- "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15",
- "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c",
- "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea",
- "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417",
- "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250",
- "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88",
- "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca",
- "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa",
- "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99",
- "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149",
- "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41",
- "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574",
- "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0",
- "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f",
- "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d",
- "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654",
- "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3",
- "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19",
- "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90",
- "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578",
- "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9",
- "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1",
- "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51",
- "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719",
- "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236",
- "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a",
- "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c",
- "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade",
- "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944",
- "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc",
- "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6",
- "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6",
- "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27",
- "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6",
- "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2",
- "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12",
- "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf",
- "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114",
- "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7",
- "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf",
- "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d",
- "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b",
- "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed",
- "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03",
- "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4",
- "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67",
- "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365",
- "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a",
- "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748",
- "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b",
- "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079",
- "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"
- ],
- "markers": "python_full_version >= '3.7.0'",
- "version": "==3.4.0"
+ "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537",
+ "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa",
+ "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a",
+ "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294",
+ "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b",
+ "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd",
+ "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601",
+ "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd",
+ "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4",
+ "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d",
+ "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2",
+ "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313",
+ "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd",
+ "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa",
+ "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8",
+ "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1",
+ "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2",
+ "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496",
+ "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d",
+ "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b",
+ "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e",
+ "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a",
+ "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4",
+ "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca",
+ "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78",
+ "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408",
+ "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5",
+ "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3",
+ "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f",
+ "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a",
+ "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765",
+ "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6",
+ "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146",
+ "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6",
+ "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9",
+ "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd",
+ "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c",
+ "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f",
+ "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545",
+ "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176",
+ "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770",
+ "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824",
+ "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f",
+ "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf",
+ "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487",
+ "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d",
+ "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd",
+ "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b",
+ "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534",
+ "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f",
+ "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b",
+ "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9",
+ "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd",
+ "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125",
+ "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9",
+ "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de",
+ "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11",
+ "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d",
+ "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35",
+ "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f",
+ "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda",
+ "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7",
+ "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a",
+ "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971",
+ "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8",
+ "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41",
+ "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d",
+ "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f",
+ "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757",
+ "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a",
+ "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886",
+ "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77",
+ "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76",
+ "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247",
+ "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85",
+ "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb",
+ "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7",
+ "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e",
+ "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6",
+ "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037",
+ "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1",
+ "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e",
+ "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807",
+ "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407",
+ "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c",
+ "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12",
+ "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3",
+ "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089",
+ "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd",
+ "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e",
+ "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00",
+ "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"
+ ],
+ "markers": "python_version >= '3.7'",
+ "version": "==3.4.1"
},
"click": {
"hashes": [
@@ -190,7 +177,7 @@
"sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44",
"sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"
],
- "markers": "sys_platform == 'win32'",
+ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'",
"version": "==0.4.6"
},
"coverage": {
@@ -198,86 +185,71 @@
"toml"
],
"hashes": [
- "sha256:0824a28ec542a0be22f60c6ac36d679e0e262e5353203bea81d44ee81fe9c6d4",
- "sha256:085161be5f3b30fd9b3e7b9a8c301f935c8313dcf928a07b116324abea2c1c2c",
- "sha256:0ae1387db4aecb1f485fb70a6c0148c6cdaebb6038f1d40089b1fc84a5db556f",
- "sha256:0d59fd927b1f04de57a2ba0137166d31c1a6dd9e764ad4af552912d70428c92b",
- "sha256:0f957943bc718b87144ecaee70762bc2bc3f1a7a53c7b861103546d3a403f0a6",
- "sha256:13a9e2d3ee855db3dd6ea1ba5203316a1b1fd8eaeffc37c5b54987e61e4194ae",
- "sha256:1a330812d9cc7ac2182586f6d41b4d0fadf9be9049f350e0efb275c8ee8eb692",
- "sha256:22be16571504c9ccea919fcedb459d5ab20d41172056206eb2994e2ff06118a4",
- "sha256:2d10e07aa2b91835d6abec555ec8b2733347956991901eea6ffac295f83a30e4",
- "sha256:35371f8438028fdccfaf3570b31d98e8d9eda8bb1d6ab9473f5a390969e98717",
- "sha256:3c026eb44f744acaa2bda7493dad903aa5bf5fc4f2554293a798d5606710055d",
- "sha256:41ff7b0da5af71a51b53f501a3bac65fb0ec311ebed1632e58fc6107f03b9198",
- "sha256:4401ae5fc52ad8d26d2a5d8a7428b0f0c72431683f8e63e42e70606374c311a1",
- "sha256:44349150f6811b44b25574839b39ae35291f6496eb795b7366fef3bd3cf112d3",
- "sha256:447af20e25fdbe16f26e84eb714ba21d98868705cb138252d28bc400381f6ffb",
- "sha256:4a8d8977b0c6ef5aeadcb644da9e69ae0dcfe66ec7f368c89c72e058bd71164d",
- "sha256:4e12ae8cc979cf83d258acb5e1f1cf2f3f83524d1564a49d20b8bec14b637f08",
- "sha256:592ac539812e9b46046620341498caf09ca21023c41c893e1eb9dbda00a70cbf",
- "sha256:5e6b86b5847a016d0fbd31ffe1001b63355ed309651851295315031ea7eb5a9b",
- "sha256:608a7fd78c67bee8936378299a6cb9f5149bb80238c7a566fc3e6717a4e68710",
- "sha256:61f70dc68bd36810972e55bbbe83674ea073dd1dcc121040a08cdf3416c5349c",
- "sha256:65dad5a248823a4996724a88eb51d4b31587aa7aa428562dbe459c684e5787ae",
- "sha256:777abfab476cf83b5177b84d7486497e034eb9eaea0d746ce0c1268c71652077",
- "sha256:7e216d8044a356fc0337c7a2a0536d6de07888d7bcda76febcb8adc50bdbbd00",
- "sha256:85d9636f72e8991a1706b2b55b06c27545448baf9f6dbf51c4004609aacd7dcb",
- "sha256:899b8cd4781c400454f2f64f7776a5d87bbd7b3e7f7bda0cb18f857bb1334664",
- "sha256:8a289d23d4c46f1a82d5db4abeb40b9b5be91731ee19a379d15790e53031c014",
- "sha256:8d2dfa71665a29b153a9681edb1c8d9c1ea50dfc2375fb4dac99ea7e21a0bcd9",
- "sha256:8e3c3e38930cfb729cb8137d7f055e5a473ddaf1217966aa6238c88bd9fd50e6",
- "sha256:8f8770dfc6e2c6a2d4569f411015c8d751c980d17a14b0530da2d7f27ffdd88e",
- "sha256:932fc826442132dde42ee52cf66d941f581c685a6313feebed358411238f60f9",
- "sha256:96d636c77af18b5cb664ddf12dab9b15a0cfe9c0bde715da38698c8cea748bfa",
- "sha256:97ddc94d46088304772d21b060041c97fc16bdda13c6c7f9d8fcd8d5ae0d8611",
- "sha256:98caba4476a6c8d59ec1eb00c7dd862ba9beca34085642d46ed503cc2d440d4b",
- "sha256:9901d36492009a0a9b94b20e52ebfc8453bf49bb2b27bca2c9706f8b4f5a554a",
- "sha256:99e266ae0b5d15f1ca8d278a668df6f51cc4b854513daab5cae695ed7b721cf8",
- "sha256:9c38bf15a40ccf5619fa2fe8f26106c7e8e080d7760aeccb3722664c8656b030",
- "sha256:a27801adef24cc30871da98a105f77995e13a25a505a0161911f6aafbd66e678",
- "sha256:abd3e72dd5b97e3af4246cdada7738ef0e608168de952b837b8dd7e90341f015",
- "sha256:adb697c0bd35100dc690de83154627fbab1f4f3c0386df266dded865fc50a902",
- "sha256:b12c6b18269ca471eedd41c1b6a1065b2f7827508edb9a7ed5555e9a56dcfc97",
- "sha256:b9389a429e0e5142e69d5bf4a435dd688c14478a19bb901735cdf75e57b13845",
- "sha256:ba9e7484d286cd5a43744e5f47b0b3fb457865baf07bafc6bee91896364e1419",
- "sha256:bb5555cff66c4d3d6213a296b360f9e1a8e323e74e0426b6c10ed7f4d021e464",
- "sha256:be57b6d56e49c2739cdf776839a92330e933dd5e5d929966fbbd380c77f060be",
- "sha256:c69e42c892c018cd3c8d90da61d845f50a8243062b19d228189b0224150018a9",
- "sha256:ccc660a77e1c2bf24ddbce969af9447a9474790160cfb23de6be4fa88e3951c7",
- "sha256:d5275455b3e4627c8e7154feaf7ee0743c2e7af82f6e3b561967b1cca755a0be",
- "sha256:d75cded8a3cff93da9edc31446872d2997e327921d8eed86641efafd350e1df1",
- "sha256:d872ec5aeb086cbea771c573600d47944eea2dcba8be5f3ee649bfe3cb8dc9ba",
- "sha256:d891c136b5b310d0e702e186d70cd16d1119ea8927347045124cb286b29297e5",
- "sha256:db1dab894cc139f67822a92910466531de5ea6034ddfd2b11c0d4c6257168073",
- "sha256:e28bf44afa2b187cc9f41749138a64435bf340adfcacb5b2290c070ce99839d4",
- "sha256:e5ea1cf0872ee455c03e5674b5bca5e3e68e159379c1af0903e89f5eba9ccc3a",
- "sha256:e77363e8425325384f9d49272c54045bbed2f478e9dd698dbc65dbc37860eb0a",
- "sha256:ee5defd1733fd6ec08b168bd4f5387d5b322f45ca9e0e6c817ea6c4cd36313e3",
- "sha256:f1592791f8204ae9166de22ba7e6705fa4ebd02936c09436a1bb85aabca3e599",
- "sha256:f2d1ec60d6d256bdf298cb86b78dd715980828f50c46701abc3b0a2b3f8a0dc0",
- "sha256:f3ca78518bc6bc92828cd11867b121891d75cae4ea9e908d72030609b996db1b",
- "sha256:f7b15f589593110ae767ce997775d645b47e5cbbf54fd322f8ebea6277466cec",
- "sha256:fd1213c86e48dfdc5a0cc676551db467495a95a662d2396ecd58e719191446e1",
- "sha256:ff74026a461eb0660366fb01c650c1d00f833a086b336bdad7ab00cc952072b3"
+ "sha256:05fca8ba6a87aabdd2d30d0b6c838b50510b56cdcfc604d40760dae7153b73d9",
+ "sha256:0aa9692b4fdd83a4647eeb7db46410ea1322b5ed94cd1715ef09d1d5922ba87f",
+ "sha256:0c807ca74d5a5e64427c8805de15b9ca140bba13572d6d74e262f46f50b13273",
+ "sha256:0d7a2bf79378d8fb8afaa994f91bfd8215134f8631d27eba3e0e2c13546ce994",
+ "sha256:0f460286cb94036455e703c66988851d970fdfd8acc2a1122ab7f4f904e4029e",
+ "sha256:204a8238afe787323a8b47d8be4df89772d5c1e4651b9ffa808552bdf20e1d50",
+ "sha256:2396e8116db77789f819d2bc8a7e200232b7a282c66e0ae2d2cd84581a89757e",
+ "sha256:254f1a3b1eef5f7ed23ef265eaa89c65c8c5b6b257327c149db1ca9d4a35f25e",
+ "sha256:26bcf5c4df41cad1b19c84af71c22cbc9ea9a547fc973f1f2cc9a290002c8b3c",
+ "sha256:27c6e64726b307782fa5cbe531e7647aee385a29b2107cd87ba7c0105a5d3853",
+ "sha256:299e91b274c5c9cdb64cbdf1b3e4a8fe538a7a86acdd08fae52301b28ba297f8",
+ "sha256:2bcfa46d7709b5a7ffe089075799b902020b62e7ee56ebaed2f4bdac04c508d8",
+ "sha256:2ccf240eb719789cedbb9fd1338055de2761088202a9a0b73032857e53f612fe",
+ "sha256:32ee6d8491fcfc82652a37109f69dee9a830e9379166cb73c16d8dc5c2915165",
+ "sha256:3f7b444c42bbc533aaae6b5a2166fd1a797cdb5eb58ee51a92bee1eb94a1e1cb",
+ "sha256:457574f4599d2b00f7f637a0700a6422243b3565509457b2dbd3f50703e11f59",
+ "sha256:489a01f94aa581dbd961f306e37d75d4ba16104bbfa2b0edb21d29b73be83609",
+ "sha256:4bcc276261505d82f0ad426870c3b12cb177752834a633e737ec5ee79bbdff18",
+ "sha256:4e0de1e902669dccbf80b0415fb6b43d27edca2fbd48c74da378923b05316098",
+ "sha256:4e4630c26b6084c9b3cb53b15bd488f30ceb50b73c35c5ad7871b869cb7365fd",
+ "sha256:4eea95ef275de7abaef630c9b2c002ffbc01918b726a39f5a4353916ec72d2f3",
+ "sha256:507a20fc863cae1d5720797761b42d2d87a04b3e5aeb682ef3b7332e90598f43",
+ "sha256:54a5f0f43950a36312155dae55c505a76cd7f2b12d26abeebbe7a0b36dbc868d",
+ "sha256:55b201b97286cf61f5e76063f9e2a1d8d2972fc2fcfd2c1272530172fd28c359",
+ "sha256:59af35558ba08b758aec4d56182b222976330ef8d2feacbb93964f576a7e7a90",
+ "sha256:5c912978f7fbf47ef99cec50c4401340436d200d41d714c7a4766f377c5b7b78",
+ "sha256:656c82b8a0ead8bba147de9a89bda95064874c91a3ed43a00e687f23cc19d53a",
+ "sha256:6713ba4b4ebc330f3def51df1d5d38fad60b66720948112f114968feb52d3f99",
+ "sha256:675cefc4c06e3b4c876b85bfb7c59c5e2218167bbd4da5075cbe3b5790a28988",
+ "sha256:6f93531882a5f68c28090f901b1d135de61b56331bba82028489bc51bdd818d2",
+ "sha256:714f942b9c15c3a7a5fe6876ce30af831c2ad4ce902410b7466b662358c852c0",
+ "sha256:79109c70cc0882e4d2d002fe69a24aa504dec0cc17169b3c7f41a1d341a73694",
+ "sha256:7bbd8c8f1b115b892e34ba66a097b915d3871db7ce0e6b9901f462ff3a975377",
+ "sha256:7ed2f37cfce1ce101e6dffdfd1c99e729dd2ffc291d02d3e2d0af8b53d13840d",
+ "sha256:7fb105327c8f8f0682e29843e2ff96af9dcbe5bab8eeb4b398c6a33a16d80a23",
+ "sha256:89d76815a26197c858f53c7f6a656686ec392b25991f9e409bcef020cd532312",
+ "sha256:9a7cfb50515f87f7ed30bc882f68812fd98bc2852957df69f3003d22a2aa0abf",
+ "sha256:9e1747bab246d6ff2c4f28b4d186b205adced9f7bd9dc362051cc37c4a0c7bd6",
+ "sha256:9e80eba8801c386f72e0712a0453431259c45c3249f0009aff537a517b52942b",
+ "sha256:a01ec4af7dfeb96ff0078ad9a48810bb0cc8abcb0115180c6013a6b26237626c",
+ "sha256:a372c89c939d57abe09e08c0578c1d212e7a678135d53aa16eec4430adc5e690",
+ "sha256:a3b204c11e2b2d883946fe1d97f89403aa1811df28ce0447439178cc7463448a",
+ "sha256:a534738b47b0de1995f85f582d983d94031dffb48ab86c95bdf88dc62212142f",
+ "sha256:a5e37dc41d57ceba70956fa2fc5b63c26dba863c946ace9705f8eca99daecdc4",
+ "sha256:aa744da1820678b475e4ba3dfd994c321c5b13381d1041fe9c608620e6676e25",
+ "sha256:ab32947f481f7e8c763fa2c92fd9f44eeb143e7610c4ca9ecd6a36adab4081bd",
+ "sha256:abb02e2f5a3187b2ac4cd46b8ced85a0858230b577ccb2c62c81482ca7d18852",
+ "sha256:b330368cb99ef72fcd2dc3ed260adf67b31499584dc8a20225e85bfe6f6cfed0",
+ "sha256:bc67deb76bc3717f22e765ab3e07ee9c7a5e26b9019ca19a3b063d9f4b874244",
+ "sha256:c0b1818063dc9e9d838c09e3a473c1422f517889436dd980f5d721899e66f315",
+ "sha256:c56e097019e72c373bae32d946ecf9858fda841e48d82df7e81c63ac25554078",
+ "sha256:c7827a5bc7bdb197b9e066cdf650b2887597ad124dd99777332776f7b7c7d0d0",
+ "sha256:ccc2b70a7ed475c68ceb548bf69cec1e27305c1c2606a5eb7c3afff56a1b3b27",
+ "sha256:d37a84878285b903c0fe21ac8794c6dab58150e9359f1aaebbeddd6412d53132",
+ "sha256:e2f0280519e42b0a17550072861e0bc8a80a0870de260f9796157d3fca2733c5",
+ "sha256:e4ae5ac5e0d1e4edfc9b4b57b4cbecd5bc266a6915c500f358817a8496739247",
+ "sha256:e67926f51821b8e9deb6426ff3164870976fe414d033ad90ea75e7ed0c2e5022",
+ "sha256:e78b270eadb5702938c3dbe9367f878249b5ef9a2fcc5360ac7bff694310d17b",
+ "sha256:ea3c8f04b3e4af80e17bab607c386a830ffc2fb88a5484e1df756478cf70d1d3",
+ "sha256:ec22b5e7fe7a0fa8509181c4aac1db48f3dd4d3a566131b313d1efc102892c18",
+ "sha256:f4f620668dbc6f5e909a0946a877310fb3d57aea8198bde792aae369ee1c23b5",
+ "sha256:fd34e7b3405f0cc7ab03d54a334c17a9e802897580d964bd8c2001f4b9fd488f"
],
"markers": "python_version >= '3.9'",
- "version": "==7.6.9"
- },
- "coveralls": {
- "hashes": [
- "sha256:7a6b1fa9848332c7b2221afb20f3df90272ac0167060f41b5fe90429b30b1809",
- "sha256:7b2a0a2bcef94f295e3cf28dcc55ca40b71c77d1c2446b538e85f0f7bc21aa69"
- ],
- "index": "pypi",
- "markers": "python_version < '3.13' and python_version >= '3.8'",
- "version": "==4.0.1"
- },
- "docopt": {
- "hashes": [
- "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"
- ],
- "version": "==0.6.2"
+ "version": "==7.6.10"
},
"coveralls": {
"hashes": [
@@ -307,7 +279,7 @@
"sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b",
"sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"
],
- "markers": "python_version < '3.11'",
+ "markers": "python_version >= '3.7'",
"version": "==1.2.2"
},
"idna": {
@@ -331,7 +303,7 @@
"sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b",
"sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"
],
- "markers": "python_version < '3.12'",
+ "markers": "python_version >= '3.8'",
"version": "==8.5.0"
},
"iniconfig": {
@@ -376,11 +348,11 @@
},
"keyring": {
"hashes": [
- "sha256:4c753b3ec91717fe713c4edd522d625889d8973a349b0e582622f49766de58e6",
- "sha256:e67f8ac32b04be4714b42fe84ce7dad9c40985b9ca827c592cc303e7c26d9741"
+ "sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66",
+ "sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd"
],
- "markers": "platform_machine != 'ppc64le' and platform_machine != 's390x'",
- "version": "==25.5.0"
+ "markers": "python_version >= '3.9'",
+ "version": "==25.6.0"
},
"markdown-it-py": {
"hashes": [
@@ -643,11 +615,11 @@
},
"pygments": {
"hashes": [
- "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199",
- "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"
+ "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f",
+ "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"
],
"markers": "python_version >= '3.8'",
- "version": "==2.18.0"
+ "version": "==2.19.1"
},
"pyproject-hooks": {
"hashes": [
@@ -688,7 +660,7 @@
"sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8",
"sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755"
],
- "markers": "sys_platform == 'win32'",
+ "markers": "python_version >= '3.6'",
"version": "==0.2.3"
},
"readme-renderer": {
@@ -750,28 +722,28 @@
},
"ruff": {
"hashes": [
- "sha256:0d5f89f254836799af1615798caa5f80b7f935d7a670fad66c5007928e57ace8",
- "sha256:13e9ec6d6b55f6da412d59953d65d66e760d583dd3c1c72bf1f26435b5bfdbae",
- "sha256:552fb6d861320958ca5e15f28b20a3d071aa83b93caee33a87b471f99a6c0835",
- "sha256:58072f0c06080276804c6a4e21a9045a706584a958e644353603d36ca1eb8a60",
- "sha256:6ddf5d654ac0d44389f6bf05cee4caeefc3132a64b58ea46738111d687352296",
- "sha256:736272574e97157f7edbbb43b1d046125fce9e7d8d583d5d65d0c9bf2c15addf",
- "sha256:8ef06f66f4a05c3ddbc9121a8b0cecccd92c5bf3dd43b5472ffe40b8ca10f0f8",
- "sha256:9183dd615d8df50defa8b1d9a074053891ba39025cf5ae88e8bcb52edcc4bf08",
- "sha256:97d9aefef725348ad77d6db98b726cfdb075a40b936c7984088804dfd38268a7",
- "sha256:9f8402b7c4f96463f135e936d9ab77b65711fcd5d72e5d67597b543bbb43cf3f",
- "sha256:ab78e33325a6f5374e04c2ab924a3367d69a0da36f8c9cb6b894a62017506111",
- "sha256:bf197b98ed86e417412ee3b6c893f44c8864f816451441483253d5ff22c0e81e",
- "sha256:c41319b85faa3aadd4d30cb1cffdd9ac6b89704ff79f7664b853785b48eccdf3",
- "sha256:e248b1f0fa2749edd3350a2a342b67b43a2627434c059a063418e3d375cfe643",
- "sha256:e4e56b3baa9c23d324ead112a4fdf20db9a3f8f29eeabff1355114dd96014604",
- "sha256:e5fe710ab6061592521f902fca7ebcb9fabd27bc7c57c764298b1c1f15fff720",
- "sha256:f21a1143776f8656d7f364bd264a9d60f01b7f52243fbe90e7670c0dfe0cf65d",
- "sha256:ffb60904651c00a1e0b8df594591770018a0f04587f7deeb3838344fe3adabac"
+ "sha256:0509e8da430228236a18a677fcdb0c1f102dd26d5520f71f79b094963322ed25",
+ "sha256:0c000a471d519b3e6cfc9c6680025d923b4ca140ce3e4612d1a2ef58e11f11fe",
+ "sha256:248b1fb3f739d01d528cc50b35ee9c4812aa58cc5935998e776bf8ed5b251e75",
+ "sha256:45a56f61b24682f6f6709636949ae8cc82ae229d8d773b4c76c09ec83964a95a",
+ "sha256:496dd38a53aa173481a7d8866bcd6451bd934d06976a2505028a50583e001b76",
+ "sha256:52d587092ab8df308635762386f45f4638badb0866355b2b86760f6d3c076188",
+ "sha256:54799ca3d67ae5e0b7a7ac234baa657a9c1784b48ec954a094da7c206e0365b1",
+ "sha256:61323159cf21bc3897674e5adb27cd9e7700bab6b84de40d7be28c3d46dc67cf",
+ "sha256:7ae4478b1471fc0c44ed52a6fb787e641a2ac58b1c1f91763bafbc2faddc5117",
+ "sha256:7d7fc2377a04b6e04ffe588caad613d0c460eb2ecba4c0ccbbfe2bc973cbc162",
+ "sha256:91a7ddb221779871cf226100e677b5ea38c2d54e9e2c8ed847450ebbdf99b32d",
+ "sha256:9257aa841e9e8d9b727423086f0fa9a86b6b420fbf4bf9e1465d1250ce8e4d8d",
+ "sha256:bc3c083c50390cf69e7e1b5a5a7303898966be973664ec0c4a4acea82c1d4315",
+ "sha256:dcad24b81b62650b0eb8814f576fc65cfee8674772a6e24c9b747911801eeaa5",
+ "sha256:defed167955d42c68b407e8f2e6f56ba52520e790aba4ca707a9c88619e580e3",
+ "sha256:e169ea1b9eae61c99b257dc83b9ee6c76f89042752cb2d83486a7d6e48e8f764",
+ "sha256:e88b8f6d901477c41559ba540beeb5a671e14cd29ebd5683903572f4b40a9807",
+ "sha256:f1d70bef3d16fdc897ee290d7d20da3cbe4e26349f62e8a0274e7a3f4ce7a905"
],
"index": "pypi",
"markers": "python_version >= '3.7'",
- "version": "==0.8.4"
+ "version": "==0.8.6"
},
"shellingham": {
"hashes": [
@@ -897,7 +869,7 @@
"sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a",
"sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"
],
- "markers": "python_version < '3.11'",
+ "markers": "python_version >= '3.8'",
"version": "==2.2.1"
},
"twine": {
@@ -922,7 +894,7 @@
"sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d",
"sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"
],
- "markers": "python_version < '3.11'",
+ "markers": "python_version >= '3.8'",
"version": "==4.12.2"
},
"urllib3": {
diff --git a/src/vfxnaming/naming.py b/src/vfxnaming/naming.py
index 378c760..244a665 100644
--- a/src/vfxnaming/naming.py
+++ b/src/vfxnaming/naming.py
@@ -131,17 +131,69 @@ def solve(*args, **kwargs) -> AnyStr:
return rule.solve(**values)
-def validate(name: AnyStr) -> bool:
- """Validates a name string against the currently active rule.
+def validate(name: AnyStr, **kwargs) -> bool:
+ """Validates a name string against the currently active rule and its
+ tokens if passed as keyword arguments.
+
+ -For rules with repeated tokens:
+
+ If your rule uses the same token more than once, pass arguments with the token
+ name and add an incremental digit
+
+ i.e.: side1='C', side2='R'
+
+ If your rule uses the same token more than once, you can also pass a single
+ instance of the argument and it'll be applied to all repetitions.
+
+ i.e.: side='C'
+
+ If your rule uses the same token more than once, you can ignore one of the repetitions,
+ and the solver will use the default value for that token.
+
+ i.e.: side1='C', side4='L'
Args:
name (str): Name string e.g.: C_helmet_001_MSH
+ kwargs (dict): Keyword arguments with token names and values.
+
Returns:
bool: True if the name is valid, False otherwise.
"""
rule = rules.get_active_rule()
- return rule.validate(name)
+ # * This accounts for those cases where a token is used more than once in a rule
+ repeated_fields = dict()
+ for each in rule.fields:
+ if each not in repeated_fields.keys():
+ if rule.fields.count(each) > 1:
+ repeated_fields[each] = 1
+ fields_with_digits = list()
+ for each in rule.fields:
+ if each in repeated_fields.keys():
+ counter = repeated_fields.get(each)
+ repeated_fields[each] = counter + 1
+ fields_with_digits.append(f"{each}{counter}")
+ else:
+ fields_with_digits.append(each)
+ values = {}
+ fields_inc = 0
+ for f in fields_with_digits:
+ token = tokens.get_token(rule.fields[fields_inc])
+ if token:
+ # Explicitly passed as keyword argument
+ if kwargs.get(f) is not None:
+ values[f] = token.solve(kwargs.get(f))
+ fields_inc += 1
+ continue
+ # Explicitly passed as keyword argument without repetitive digits
+ # Use passed argument for all field repetitions
+ elif kwargs.get(rule.fields[fields_inc]) is not None:
+ values[f] = token.solve(kwargs.get(rule.fields[fields_inc]))
+ fields_inc += 1
+ continue
+ fields_inc += 1
+ logger.debug(f"Validating rule '{rule.name}' with values {values}")
+ return rule.validate(name, **values)
def validate_repo(repo: Path) -> bool:
diff --git a/src/vfxnaming/rules.py b/src/vfxnaming/rules.py
index 5d5ae4e..a5c74ff 100644
--- a/src/vfxnaming/rules.py
+++ b/src/vfxnaming/rules.py
@@ -160,7 +160,7 @@ def parse(self, name: AnyStr) -> Union[Dict, None]:
f"and rule's pattern '{self._pattern}':'{len(expected_separators)}'."
)
- def validate(self, name: AnyStr) -> bool: # noqa: C901
+ def validate(self, name: AnyStr, **validate_values) -> bool: # noqa: C901
"""Validate if given name matches the rule pattern.
Args:
@@ -194,7 +194,42 @@ def validate(self, name: AnyStr) -> bool: # noqa: C901
)
return False
- name_parts = sorted(match.groupdict().items())
+ match_dict = match.groupdict()
+ name_parts = sorted(match_dict.items())
+ repeated_fields = {}
+ for each in self.fields:
+ if each not in repeated_fields.keys():
+ if self.fields.count(each) > 1:
+ repeated_fields[each] = 1
+ if repeated_fields:
+ logger.debug(f"Repeated tokens: {', '.join(repeated_fields.keys())}")
+ if len(validate_values):
+ for key, value in name_parts:
+ # Strip number that was added to make group name unique
+ token_name = key[:-3]
+ token = get_token(token_name)
+ if not token:
+ continue
+ if token_name in repeated_fields.keys():
+ counter = repeated_fields.get(token_name)
+ repeated_fields[token_name] = counter + 1
+ token_name = f"{token_name}{counter}"
+
+ if token_name not in validate_values.keys():
+ continue
+
+ given_value = validate_values.get(token_name)
+ if value != given_value:
+ logger.warning(
+ f"Token '{token_name}' value '{value}' does not match '{given_value}'"
+ )
+ if value.lower() == given_value.lower():
+ logger.warning(
+ f"Token '{token_name}' value '{value}' has "
+ f"casing mismatches with '{given_value}'"
+ )
+ return False
+
name_parts_str = ", ".join([f"('{k[:-3]}': '{v}')" for k, v in name_parts])
logger.debug(f"Name parts: {name_parts_str}")
@@ -210,14 +245,6 @@ def validate(self, name: AnyStr) -> bool: # noqa: C901
if not has_tokens_with_options:
return True
- repeated_fields = {}
- for each in self.fields:
- if each not in repeated_fields.keys():
- if self.fields.count(each) > 1:
- repeated_fields[each] = 1
- if repeated_fields:
- logger.debug(f"Repeated tokens: {', '.join(repeated_fields.keys())}")
-
matching_options = True
for key, value in name_parts:
# Strip number that was added to make group name unique
diff --git a/tests/naming_test.py b/tests/naming_test.py
index cb7d078..fee9d4a 100644
--- a/tests/naming_test.py
+++ b/tests/naming_test.py
@@ -263,6 +263,88 @@ def setup(self):
def test_valid(self, name: str, expected: bool):
assert n.validate(name) is expected
+ @pytest.mark.parametrize(
+ "name,validate_values,expected",
+ [
+ (
+ "dramatic_bounce_chars_001_LGT",
+ {"category": "dramatic"},
+ True,
+ ),
+ (
+ "dramatic_bounce_chars_001_LGT",
+ {"whatAffects": "chars"},
+ True,
+ ),
+ (
+ "dramatic_bounce_chars_001_LGT",
+ {"category": "practical"},
+ False,
+ ),
+ (
+ "dramatic_bounce_chars_001_LGT",
+ {"whatAffects": "anything"},
+ False,
+ ),
+ ],
+ )
+ def test_valid_with_tokens(self, name: str, validate_values: dict, expected: bool):
+ assert n.validate(name, **validate_values) is expected
+
+
+class Test_ValidateWithRepetitions:
+ @pytest.fixture(autouse=True)
+ def setup(self):
+ tokens.reset_tokens()
+ rules.reset_rules()
+ tokens.add_token("side", center="C", left="L", right="R", default="center")
+ tokens.add_token(
+ "region",
+ orbital="ORBI",
+ parotidmasseter="PAROT",
+ mental="MENT",
+ frontal="FRONT",
+ zygomatic="ZYGO",
+ retromandibularfossa="RETMAND",
+ )
+ rules.add_rule("filename", "{side}-{region}_{side}-{region}_{side}-{region}")
+
+ @pytest.mark.parametrize(
+ "name,validate_values,expected",
+ [
+ (
+ "C-FRONT_L-ORBI_R-ZYGO",
+ {
+ "side1": "center",
+ "region1": "frontal",
+ "side2": "left",
+ "region2": "orbital",
+ "side3": "right",
+ "region3": "zygomatic",
+ },
+ True,
+ ),
+ (
+ "R-MENT_C-PAROT_L-RETMAND",
+ {
+ "side2": "center",
+ },
+ True,
+ ),
+ (
+ "R-MENT_C-PAROT_L-RETMAND",
+ {
+ "side": "center",
+ },
+ False,
+ ),
+ ],
+ )
+ def test_valid_with_repetitions(
+ self, name: str, validate_values: dict, expected: bool
+ ):
+ assert n.validate(name, **validate_values) is expected
+
class Test_RuleWithRepetitions:
@pytest.fixture(autouse=True)
From e4156afdbd23047cc5b67162fb367df5919adaa9 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Tue, 7 Jan 2025 16:10:52 -0300
Subject: [PATCH 57/65] Version up
---
pyproject.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyproject.toml b/pyproject.toml
index 0fd0567..ca8faf6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "vfxnaming"
-version = "1.4.4-beta"
+version = "1.4.5-beta"
authors = [
{ name="Chris Granados", email="info@chrisgranados.com" },
]
From 64a0c65ddbd44664f9a9423d089ad6cfbf6103d7 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Wed, 8 Jan 2025 10:05:19 -0300
Subject: [PATCH 58/65] Implements fallback value for required tokens
---
src/vfxnaming/naming.py | 9 ++++-
src/vfxnaming/tokens.py | 33 ++++++++++++++++---
tests/tokens_test.py | 73 ++++++++++++++++++++++++++++++++++++++---
3 files changed, 106 insertions(+), 9 deletions(-)
diff --git a/src/vfxnaming/naming.py b/src/vfxnaming/naming.py
index 244a665..c2f3078 100644
--- a/src/vfxnaming/naming.py
+++ b/src/vfxnaming/naming.py
@@ -113,7 +113,14 @@ def solve(*args, **kwargs) -> AnyStr:
fields_inc += 1
continue
elif token.required and kwargs.get(f) is None and len(args) == 0:
- raise SolvingError(f"Token {token.name} is required but was not passed.")
+ if len(token.fallback):
+ values[f] = token.fallback
+ fields_inc += 1
+ continue
+ else:
+ raise SolvingError(
+ f"Token {token.name} is required but was not passed."
+ )
# Not required and not passed as keyword argument
elif not token.required and kwargs.get(f) is None:
values[f] = token.solve()
diff --git a/src/vfxnaming/tokens.py b/src/vfxnaming/tokens.py
index 3fd9369..d1bc6d5 100644
--- a/src/vfxnaming/tokens.py
+++ b/src/vfxnaming/tokens.py
@@ -27,6 +27,7 @@ def __init__(self, name: AnyStr):
self._name: AnyStr = name
self._default = None
self._options: Dict = {}
+ self._fallback = ""
def add_option(self, fullname: AnyStr, abbreviation: AnyStr) -> bool:
"""Add an option pair to this Token.
@@ -138,7 +139,9 @@ def solve(self, name: Union[AnyStr, None] = None) -> AnyStr:
"""
if self.required and name:
return name
- elif self.required and name is None:
+ elif self.required and len(self._fallback):
+ return self._fallback
+ elif self.required and not name:
raise TokenError(
f"Token {self.name} is required. name parameter must be passed."
)
@@ -227,6 +230,19 @@ def options(self) -> Dict:
"""
return copy.deepcopy(self._options)
+ @property
+ def fallback(self) -> AnyStr:
+ return self._fallback
+
+ @fallback.setter
+ def fallback(self, f: AnyStr):
+ if self.required:
+ self._fallback = f
+ else:
+ logger.warning(
+ f"Token '{self.name}' has options, use {self.name}.default instead."
+ )
+
class TokenNumber(Serializable):
def __init__(self, name: AnyStr):
@@ -288,7 +304,7 @@ def parse(self, value: AnyStr) -> int:
suffix_index += 1
if prefix_index != -1 and self.prefix != "":
- if value[prefix_index : len(self.prefix)] != self.prefix:
+ if value[prefix_index : len(self.prefix)] != self.prefix: # noqa: E203
logger.warning(f"Prefix '{self.prefix}' not found in '{value}'")
if suffix_index != -1 and self.suffix != "":
if value[-suffix_index:] != self.suffix:
@@ -358,7 +374,7 @@ def options(self) -> Dict:
return copy.deepcopy(self._options)
-def add_token(name: AnyStr, **kwargs) -> Token:
+def add_token(name: AnyStr, fallback: AnyStr = "", **kwargs) -> Token:
"""Add token to current naming session. If 'default' keyword argument is found,
set it as default for the token instance.
@@ -366,7 +382,10 @@ def add_token(name: AnyStr, **kwargs) -> Token:
name (str): Name that best describes the token, this will be used as a way
to invoke the Token object.
- kwargs: Each argument following the name is treated as an option for the
+ fallback (str, optional): Fallback value to use if token is required. Default is ""
+ and will raise and error, making the token mandatory.
+
+ kwargs: Each argument following fallback is treated as an option for the
new Token.
Raises:
@@ -392,6 +411,12 @@ def add_token(name: AnyStr, **kwargs) -> Token:
break
else:
raise TokenError("Default value must match one of the options passed.")
+ if len(fallback):
+ if isinstance(fallback, str):
+ token.fallback = fallback
+ else:
+ raise TokenError(f"Fallback must be a string. Got {type(fallback)}")
+
_tokens[name] = token
return token
diff --git a/tests/tokens_test.py b/tests/tokens_test.py
index 2520efb..f3e8757 100644
--- a/tests/tokens_test.py
+++ b/tests/tokens_test.py
@@ -13,11 +13,12 @@ def setup(self):
tokens.reset_tokens()
@pytest.mark.parametrize(
- "name,kwargs",
+ "name,fallback,kwargs",
[
- ("test", {}),
+ ("test", "", {}),
(
"category",
+ "",
{
"natural": "natural",
"practical": "practical",
@@ -26,10 +27,11 @@ def setup(self):
"default": "natural",
},
),
+ ("fallbacktest", "imfallback", {}),
],
)
- def test_add(self, name: str, kwargs):
- result = tokens.add_token(name, **kwargs)
+ def test_add(self, name: str, fallback: str, kwargs):
+ result = tokens.add_token(name, fallback, **kwargs)
assert isinstance(result, tokens.Token) is True
def test_reset_tokens(self):
@@ -118,6 +120,69 @@ def test_has_option_abbreviation(self, abbreviation: str, expected: bool):
assert result is expected
+class Test_TokenFallback:
+ @pytest.fixture(autouse=True)
+ def setup(self):
+ rules.reset_rules()
+ tokens.reset_tokens()
+ tokens.add_token("whatAffects", fallback="nothing")
+ tokens.add_token_number("number")
+ tokens.add_token(
+ "category",
+ natural="natural",
+ practical="practical",
+ dramatic="dramatic",
+ volumetric="volumetric",
+ default="natural",
+ )
+ tokens.add_token(
+ "function",
+ key="key",
+ fill="fill",
+ ambient="ambient",
+ bounce="bounce",
+ rim="rim",
+ kick="kick",
+ custom="custom",
+ default="custom",
+ )
+ tokens.add_token("type", lighting="LGT", default="LGT")
+ rules.add_rule("lights", "{category}_{function}_{whatAffects}_{number}_{type}")
+
+ def test_token_has_fallback(self):
+ assert tokens.get_token("whatAffects").fallback == "nothing"
+
+ @pytest.mark.parametrize(
+ "name,data,expected",
+ [
+ (
+ "natural_ambient_chars_024_LGT",
+ {
+ "category": "natural",
+ "function": "ambient",
+ "whatAffects": "chars",
+ "number": 24,
+ "type": "lighting",
+ },
+ True,
+ ),
+ (
+ "natural_ambient_nothing_003_LGT",
+ {
+ "category": "natural",
+ "function": "ambient",
+ "number": 3,
+ "type": "lighting",
+ },
+ True,
+ ),
+ ],
+ )
+ def test_fallback_solve(self, name: str, data: dict, expected: bool):
+ solved = n.solve(**data)
+ assert (name == solved) is expected
+
+
class Test_TokenNumber:
@pytest.fixture(autouse=True)
def setup(self):
From 74c110ae5d1b6c553c9e4fd2b5eab858c7835c86 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Wed, 8 Jan 2025 10:34:21 -0300
Subject: [PATCH 59/65] Make sure we only enforce this on Token and not
TokenNumber
---
src/vfxnaming/naming.py | 5 +++++
src/vfxnaming/rules.py | 2 ++
2 files changed, 7 insertions(+)
diff --git a/src/vfxnaming/naming.py b/src/vfxnaming/naming.py
index c2f3078..fbd5da6 100644
--- a/src/vfxnaming/naming.py
+++ b/src/vfxnaming/naming.py
@@ -198,6 +198,11 @@ def validate(name: AnyStr, **kwargs) -> bool:
values[f] = token.solve(kwargs.get(rule.fields[fields_inc]))
fields_inc += 1
continue
+ elif token.required and isinstance(token, tokens.Token):
+ if len(token.fallback):
+ values[f] = token.fallback
+ fields_inc += 1
+ continue
fields_inc += 1
logger.debug(f"Validating rule '{rule.name}' with values {values}")
return rule.validate(name, **values)
diff --git a/src/vfxnaming/rules.py b/src/vfxnaming/rules.py
index a5c74ff..8aa50d1 100644
--- a/src/vfxnaming/rules.py
+++ b/src/vfxnaming/rules.py
@@ -203,6 +203,8 @@ def validate(self, name: AnyStr, **validate_values) -> bool: # noqa: C901
repeated_fields[each] = 1
if repeated_fields:
logger.debug(f"Repeated tokens: {', '.join(repeated_fields.keys())}")
+
+ # Validate values passed by the user
if len(validate_values):
for key, value in name_parts:
# Strip number that was added to make group name unique
From 6af78cbf3fc985904e278ceb62ce2714a4b1fdf4 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Wed, 8 Jan 2025 10:34:48 -0300
Subject: [PATCH 60/65] Update docs to include new fallback attribute of Token
---
docs/source/changelog.rst | 7 +++++++
docs/source/tokens.rst | 13 +++++++++----
docs/source/usage/repositories.rst | 9 ++++++---
docs/source/usage/solving.rst | 9 ++++++---
docs/source/usage/validating.rst | 5 ++++-
5 files changed, 32 insertions(+), 11 deletions(-)
diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst
index 2f78dbe..2a5a8d8 100644
--- a/docs/source/changelog.rst
+++ b/docs/source/changelog.rst
@@ -1,6 +1,13 @@
Changelog
================================
+1.4.5-beta
+---------------------------------------
+
+**Improvements:**
+ - Adds user values to validate function so names can be validated against expected data.
+ - Adds fallback to required Tokens, useful for when a Token is required but a default value is needed in case the user doesn't provide one.
+
1.3.1-beta
---------------------------------------
diff --git a/docs/source/tokens.rst b/docs/source/tokens.rst
index 564ed08..6bcdf78 100644
--- a/docs/source/tokens.rst
+++ b/docs/source/tokens.rst
@@ -4,20 +4,25 @@ Tokens are the meaningful parts of a template. A token can be required, meaning
If options are present, then one of them is the default one. Each option follows a {full_name:abbreviation} schema, so that names can be short but meaning can be recovered easily. The default option might be passed explicitly by the user by passing a *default* argument (it must match one of the options in the Token). If no default options is explicitly passed, the Token will sort options alphabetically and pick the first one. Please notice if you pass the *default* option explicitly, you can use the abbreviation or the full option name.
+If fallback is defined, it will be used on required tokens if nothing is passed by the user.
+
.. code-block:: python
:linenos:
- n.add_token('whatAffects')
+ n.add_token('whatLights')
+ n.add_token('shadowType', fallback='soft')
n.add_token_number('digits')
n.add_token('category', natural='nat',
practical='pra', dramatic='dra',
volumetric='vol', default='nat')
-In line 1 we're creating a **Required Token**. This means that for solving the user must provide a value. This is a explicit solve.
+In line 1 we're creating a **Required Token**. This means that in order to solve the user must provide a value, else an error will be raised. This is a explicit solve.
+
+In line 2 we're creating a **Required Token** with a fallback. This means that if the user doesn't provide a value, the Token will solve to the fallback value. This is an implicit solve.
-In line 2 we're creating a **Number Token**. This is a special Token really useful for working with version like or counting parts of a name. It's always required.
+In line 3 we're creating a **Number Token**. This is a special Token really useful for working with version like or counting parts of a name. It's always required.
-In line 3 we're creating an **Optional Token**, which means that for solving the user can pass one of the options in the Token or simply ignore passing a value and the Token will solve to it's default option. This is an implicit solve, which helps to greatly reduce the amount of info that needs to be passed to solve for certain cases.
+In line 4 we're creating an **Optional Token**, which means that for solving the user can pass one of the options in the Token or simply ignore passing a value and the Token will solve to it's default option. This is an implicit solve, which helps to greatly reduce the amount of info that needs to be passed to solve for certain cases.
For more information on implicit and explicit solving please check :doc:`usage/solving`
diff --git a/docs/source/usage/repositories.rst b/docs/source/usage/repositories.rst
index 35bc9eb..330ead7 100644
--- a/docs/source/usage/repositories.rst
+++ b/docs/source/usage/repositories.rst
@@ -57,6 +57,7 @@ When saving the session, all Tokens and Rules in memory will be saved to the rep
:linenos:
n.add_token('whatAffects')
+ n.add_token('shadowType', fallback='soft')
n.add_token_number('digits')
n.add_token(
'category',
@@ -64,11 +65,13 @@ When saving the session, all Tokens and Rules in memory will be saved to the rep
volumetric='vol', default='nat'
)
-In line 1 we're creating a **Required Token**. This means that for solving the user has to provide a value. This is a explicit solve.
+In line 1 we're creating a **Required Token**. This means that in order to solve the user must provide a value, else an error will be raised. This is a explicit solve.
-In line 2 we're creating a **Number Token**. This is a special Token really useful for working with version like or counting parts of a name. It's always required.
+In line 2 we're creating a **Required Token** with a fallback. This means that if the user doesn't provide a value, the Token will solve to the fallback value. This is an implicit solve.
-In line 3 we're creating an **Optional Token**, which means that for solving the user can pass one of the options in the Token or simply ignore passing a value and the Token will solve to it's default option. This is an implicit solve, which helps to greatly reduce the amount of info that needs to be passed to solve for certain cases.
+In line 3 we're creating a **Number Token**. This is a special Token really useful for working with version like or counting parts of a name. It's always required.
+
+In line 4 we're creating an **Optional Token**, which means that for solving the user can pass one of the options in the Token or simply ignore passing a value and the Token will solve to it's default option. This is an implicit solve, which helps to greatly reduce the amount of info that needs to be passed to solve for certain cases.
For more information on implicit and explicit solving please check :doc:`solving`
diff --git a/docs/source/usage/solving.rst b/docs/source/usage/solving.rst
index 6110438..afe2398 100644
--- a/docs/source/usage/solving.rst
+++ b/docs/source/usage/solving.rst
@@ -14,6 +14,7 @@ Let's set these Tokens and Rules.
# CREATE TOKENS
n.add_token('whatAffects')
+ n.add_token('shadowType', fallback='soft')
n.add_token_number('digits')
n.add_token(
'category',
@@ -33,7 +34,7 @@ Let's set these Tokens and Rules.
# CREATE RULES
n.add_rule(
'lights',
- '{category}_{function}_{whatAffects}_{digits}_{type}'
+ '{category}_{function}_{whatAffects}_{shadowType}_{digits}_{type}'
)
n.set_active_rule("lights")
@@ -45,6 +46,8 @@ It would not make any sense to make the user pass each and every Token all the t
That's why vfxnaming.solve() accepts both args and kwargs. Not only that, but if given Token is optional and you want to use it's default value, you don't need to pass it at all.
+Even if you make a required tokken, you can still define a fallback value for it.
+
.. code-block:: python
n.solve(
@@ -57,9 +60,9 @@ That's why vfxnaming.solve() accepts both args and kwargs. Not only that, but if
Each of these calls to vfxnaming.solve() will produce the exact same result:
.. note::
- natural_custom_chars_001_LGT
+ natural_custom_chars_soft_001_LGT
-If you don't pass a required Token (either as an argument or keyword argument), such as 'whatAffects' in this example, you'll get a **TokenError**. You'll also get a **TokenError** if you try to parse a value that doesn't match any of the options in the Token.
+If you don't pass a required Token (either as an argument or keyword argument), such as 'whatAffects' in this example, you'll get a **TokenError**, unless it has a fallback value defined. You'll also get a **TokenError** if you try to parse a value that doesn't match any of the options in the Token.
Solving rules with repeated tokens
-----------------------------------------
diff --git a/docs/source/usage/validating.rst b/docs/source/usage/validating.rst
index 28f969d..f4e6ca1 100644
--- a/docs/source/usage/validating.rst
+++ b/docs/source/usage/validating.rst
@@ -23,7 +23,7 @@ Let's set these Tokens and Rule.
# CREATE TOKENS
n.reset_tokens()
- n.add_token("whatAffects")
+ n.add_token("whatAffects", fallback="nothing")
n.add_token_number("digits")
n.add_token(
"category",
@@ -58,6 +58,9 @@ And then let's validate these names:
n.validate("dramatic_bounce_chars_001_LGT")
# Result: True
+ n.validate("dramatic_bounce_nothing_001_LGT")
+ # Result: True
+
n.validate("dramatic_bounce_chars_001")
# Result: False. Last token is missing.
From 9c4c69f3ed06e1b789ae2c1eaf59eba8e5b2975a Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Wed, 8 Jan 2025 10:35:25 -0300
Subject: [PATCH 61/65] Version up
---
pyproject.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyproject.toml b/pyproject.toml
index ca8faf6..f4f1809 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "vfxnaming"
-version = "1.4.5-beta"
+version = "1.5.0-beta"
authors = [
{ name="Chris Granados", email="info@chrisgranados.com" },
]
From bd159e7ebfe8fb247234a01fbe12d09d0ff44278 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Wed, 8 Jan 2025 17:24:33 -0300
Subject: [PATCH 62/65] WIP picking rules
---
src/vfxnaming/naming.py | 46 +++++++++++++++++++++++++++++++++++++-
src/vfxnaming/rules.py | 49 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 94 insertions(+), 1 deletion(-)
diff --git a/src/vfxnaming/naming.py b/src/vfxnaming/naming.py
index fbd5da6..b68699b 100644
--- a/src/vfxnaming/naming.py
+++ b/src/vfxnaming/naming.py
@@ -24,7 +24,7 @@
import vfxnaming.rules as rules
import vfxnaming.tokens as tokens
from pathlib import Path
-from typing import AnyStr, Dict, Union
+from typing import AnyStr, Dict, Union, Iterable
from vfxnaming.logger import logger
from vfxnaming.error import SolvingError, RepoError
@@ -208,6 +208,50 @@ def validate(name: AnyStr, **kwargs) -> bool:
return rule.validate(name, **values)
+def pick_rule(name: str, strict: bool = False, **kwargs) -> Union[rules.Rule, None]:
+ """Given a name and a set of tokens or conditions passed as keyword arguments,
+ activate the rule that best matches the conditions.
+
+ Args:
+ name (str): Name to match against the conditions.
+ strict (bool, optional): _description_. Defaults to False.
+ conditions (Iterable, optional): _description_. Defaults to [].
+ kwards: _description_
+
+ Returns:
+ _type_: _description_
+ """
+ # Validations
+ if not len(kwargs):
+ # TODO: We can implement conditions based on each rule pattern
+ logger.warning(
+ "No conditions passed to pick a rule. All rules will be evaluated."
+ )
+ return None
+
+ # Check user conditions
+ for key, value in kwargs.items():
+ if key not in rules.get_rules().keys():
+ logger.warning(f"Rule {key} not found in current session.")
+ return None
+ if not isinstance(value, (list, tuple)):
+ logger.warning(f"Decision values for rule {key} must be a list or tuple.")
+ return None
+ # Decision making
+ check_function = (
+ (lambda value: all(token in name for token in value))
+ if strict
+ else (lambda value: all(token.lower() in name.lower() for token in value))
+ )
+ for key, value in kwargs.items():
+ if check_function(value):
+ logger.debug(f"Picked and actived rule: {key}")
+ rules.set_active_rule(key)
+ return rules.get_rule(key)
+ logger.debug("Couldn't pick any rule from given conditions.")
+ return None
+
+
def validate_repo(repo: Path) -> bool:
"""Valides repo by checking if it contains a vfxnaming.conf file.
diff --git a/src/vfxnaming/rules.py b/src/vfxnaming/rules.py
index 8aa50d1..ed9d645 100644
--- a/src/vfxnaming/rules.py
+++ b/src/vfxnaming/rules.py
@@ -39,6 +39,7 @@ class Rule(Serializable):
__SEPARATORS_REGEX = re.compile(r"[_\-\.:\|/\\]")
__RULE_REFERENCE_REGEX = re.compile(r"{@(?P.+?)}")
__AT_CODE = "_FXW_"
+ __NON_HARDCODED_REGEX = re.compile(r"[^{}]+(?=\{)|(?<=\})[^{}]+|^[^{]+|[^}]+$")
ANCHOR_START, ANCHOR_END, ANCHOR_BOTH = (1, 2, 3)
def __init__(self, name, pattern, anchor=ANCHOR_START):
@@ -297,6 +298,54 @@ def validate(self, name: AnyStr, **validate_values) -> bool: # noqa: C901
return matching_options
+ def is_solvable(self, name: str, strict: bool = False) -> bool:
+ """Finds a out if a rule can be solved with a given name using:
+ 1. Hardcoded values in the rule pattern. e.g.: thishardcode_{myrule} -> thishardcode_
+ 2. Token options
+ 3. Token fallback
+
+ Returns:
+ bool: True if name is solvable with rule, False otherwise.
+ """
+ # TODO: Update to expanded_pattern() when implementing nested rules
+ # Check hardcoded values first. If these don't match, there's no point in cheking tokens
+ harcoded = self.__NON_HARDCODED_REGEX.findall(self._pattern)
+ check_function = (
+ (lambda harcoded: all(token in name for token in harcoded))
+ if strict
+ else (
+ lambda harcoded: all(token.lower() in name.lower() for token in harcoded)
+ )
+ )
+ if check_function(harcoded):
+ return True
+
+ # Check token options and fallback where applicable
+ conditions = {}
+ for each in self.fields:
+ token = get_token(each)
+ if token is None:
+ continue
+ conditions[each] = {}
+ if isinstance(token, TokenNumber):
+ conditions[each]["_options"] = [token.prefix, token.suffix]
+ else:
+ if token.required and len(token.fallback):
+ conditions[each]["_fallback"] = [token.fallback]
+ else:
+ conditions[each]["_options"] = token.options.values()
+
+ for token, condition in conditions.items():
+ # If a token with options doesn't find a match, there is no point in checking the rest
+ if "_options" in condition:
+ if not any(option in name for option in condition["_options"]):
+ return False
+ elif "_fallback" in condition:
+ if condition["_fallback"] in name:
+ return True
+
+ return False
+
def __build_regex(self) -> re.Pattern:
# ? Taken from Lucidity by Martin Pengelly-Phillips
# Escape non-placeholder components
From f18ec2c6a8fb5ae0253084df822cbffca73f0a0b Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Fri, 10 Jan 2025 11:23:38 -0300
Subject: [PATCH 63/65] WIP validate many rules
---
src/vfxnaming/naming.py | 125 ++++++++++++++--------------------------
src/vfxnaming/rules.py | 65 +++++----------------
2 files changed, 59 insertions(+), 131 deletions(-)
diff --git a/src/vfxnaming/naming.py b/src/vfxnaming/naming.py
index b68699b..b5186b9 100644
--- a/src/vfxnaming/naming.py
+++ b/src/vfxnaming/naming.py
@@ -138,7 +138,7 @@ def solve(*args, **kwargs) -> AnyStr:
return rule.solve(**values)
-def validate(name: AnyStr, **kwargs) -> bool:
+def validate(name: AnyStr, with_rules: Iterable = [], **kwargs) -> bool:
"""Validates a name string against the currently active rule and its
tokens if passed as keyword arguments.
@@ -167,89 +167,50 @@ def validate(name: AnyStr, **kwargs) -> bool:
Returns:
bool: True if the name is valid, False otherwise.
"""
- rule = rules.get_active_rule()
- # * This accounts for those cases where a token is used more than once in a rule
- repeated_fields = dict()
- for each in rule.fields:
- if each not in repeated_fields.keys():
- if rule.fields.count(each) > 1:
- repeated_fields[each] = 1
- fields_with_digits = list()
- for each in rule.fields:
- if each in repeated_fields.keys():
- counter = repeated_fields.get(each)
- repeated_fields[each] = counter + 1
- fields_with_digits.append(f"{each}{counter}")
- else:
- fields_with_digits.append(each)
- values = {}
- fields_inc = 0
- for f in fields_with_digits:
- token = tokens.get_token(rule.fields[fields_inc])
- if token:
- # Explicitly passed as keyword argument
- if kwargs.get(f) is not None:
- values[f] = token.solve(kwargs.get(f))
- fields_inc += 1
- continue
- # Explicitly passed as keyword argument without repetitive digits
- # Use passed argument for all field repetitions
- elif kwargs.get(rule.fields[fields_inc]) is not None:
- values[f] = token.solve(kwargs.get(rule.fields[fields_inc]))
- fields_inc += 1
- continue
- elif token.required and isinstance(token, tokens.Token):
- if len(token.fallback):
- values[f] = token.fallback
+ previously_active_rule = rules.get_active_rule()
+ for rule in with_rules:
+ if not rules.get_rule(rule):
+ raise SolvingError(f"Rule {rule} not found in current session.")
+
+ rules.set_active_rule(rule)
+ # * This accounts for those cases where a token is used more than once in a rule
+ repeated_fields = dict()
+ for each in rule.fields:
+ if each not in repeated_fields.keys():
+ if rule.fields.count(each) > 1:
+ repeated_fields[each] = 1
+ fields_with_digits = list()
+ for each in rule.fields:
+ if each in repeated_fields.keys():
+ counter = repeated_fields.get(each)
+ repeated_fields[each] = counter + 1
+ fields_with_digits.append(f"{each}{counter}")
+ else:
+ fields_with_digits.append(each)
+ values = {}
+ fields_inc = 0
+ for f in fields_with_digits:
+ token = tokens.get_token(rule.fields[fields_inc])
+ if token:
+ # Explicitly passed as keyword argument
+ if kwargs.get(f) is not None:
+ values[f] = token.solve(kwargs.get(f))
fields_inc += 1
continue
- fields_inc += 1
- logger.debug(f"Validating rule '{rule.name}' with values {values}")
- return rule.validate(name, **values)
-
-
-def pick_rule(name: str, strict: bool = False, **kwargs) -> Union[rules.Rule, None]:
- """Given a name and a set of tokens or conditions passed as keyword arguments,
- activate the rule that best matches the conditions.
-
- Args:
- name (str): Name to match against the conditions.
- strict (bool, optional): _description_. Defaults to False.
- conditions (Iterable, optional): _description_. Defaults to [].
- kwards: _description_
-
- Returns:
- _type_: _description_
- """
- # Validations
- if not len(kwargs):
- # TODO: We can implement conditions based on each rule pattern
- logger.warning(
- "No conditions passed to pick a rule. All rules will be evaluated."
- )
- return None
-
- # Check user conditions
- for key, value in kwargs.items():
- if key not in rules.get_rules().keys():
- logger.warning(f"Rule {key} not found in current session.")
- return None
- if not isinstance(value, (list, tuple)):
- logger.warning(f"Decision values for rule {key} must be a list or tuple.")
- return None
- # Decision making
- check_function = (
- (lambda value: all(token in name for token in value))
- if strict
- else (lambda value: all(token.lower() in name.lower() for token in value))
- )
- for key, value in kwargs.items():
- if check_function(value):
- logger.debug(f"Picked and actived rule: {key}")
- rules.set_active_rule(key)
- return rules.get_rule(key)
- logger.debug("Couldn't pick any rule from given conditions.")
- return None
+ # Explicitly passed as keyword argument without repetitive digits
+ # Use passed argument for all field repetitions
+ elif kwargs.get(rule.fields[fields_inc]) is not None:
+ values[f] = token.solve(kwargs.get(rule.fields[fields_inc]))
+ fields_inc += 1
+ continue
+ elif token.required and isinstance(token, tokens.Token):
+ if len(token.fallback):
+ values[f] = token.fallback
+ fields_inc += 1
+ continue
+ fields_inc += 1
+ logger.debug(f"Validating rule '{rule.name}' with values {values}")
+ return rule.validate(name, **values)
def validate_repo(repo: Path) -> bool:
diff --git a/src/vfxnaming/rules.py b/src/vfxnaming/rules.py
index ed9d645..93cd44f 100644
--- a/src/vfxnaming/rules.py
+++ b/src/vfxnaming/rules.py
@@ -161,7 +161,7 @@ def parse(self, name: AnyStr) -> Union[Dict, None]:
f"and rule's pattern '{self._pattern}':'{len(expected_separators)}'."
)
- def validate(self, name: AnyStr, **validate_values) -> bool: # noqa: C901
+ def validate(self, name: AnyStr, strict: bool = False, **validate_values) -> bool: # noqa: C901
"""Validate if given name matches the rule pattern.
Args:
@@ -170,6 +170,21 @@ def validate(self, name: AnyStr, **validate_values) -> bool: # noqa: C901
Returns:
bool: True if name matches the rule pattern, False otherwise.
"""
+ # Check hardcoded values first. If these don't match, there's no point in cheking tokens
+ harcoded = self.__NON_HARDCODED_REGEX.findall(self._pattern)
+ check_function = (
+ (lambda harcoded: all(token in name for token in harcoded))
+ if strict
+ else (
+ lambda harcoded: all(token.lower() in name.lower() for token in harcoded)
+ )
+ )
+ if not check_function(harcoded):
+ logger.warning(
+ f"Name {name} does not match rule pattern constant values '{self._pattern}'"
+ )
+ return False
+
expected_separators = self.__PATTERN_SEPARATORS_REGEX.findall(self._pattern)
if len(expected_separators) <= 0:
logger.warning(
@@ -298,54 +313,6 @@ def validate(self, name: AnyStr, **validate_values) -> bool: # noqa: C901
return matching_options
- def is_solvable(self, name: str, strict: bool = False) -> bool:
- """Finds a out if a rule can be solved with a given name using:
- 1. Hardcoded values in the rule pattern. e.g.: thishardcode_{myrule} -> thishardcode_
- 2. Token options
- 3. Token fallback
-
- Returns:
- bool: True if name is solvable with rule, False otherwise.
- """
- # TODO: Update to expanded_pattern() when implementing nested rules
- # Check hardcoded values first. If these don't match, there's no point in cheking tokens
- harcoded = self.__NON_HARDCODED_REGEX.findall(self._pattern)
- check_function = (
- (lambda harcoded: all(token in name for token in harcoded))
- if strict
- else (
- lambda harcoded: all(token.lower() in name.lower() for token in harcoded)
- )
- )
- if check_function(harcoded):
- return True
-
- # Check token options and fallback where applicable
- conditions = {}
- for each in self.fields:
- token = get_token(each)
- if token is None:
- continue
- conditions[each] = {}
- if isinstance(token, TokenNumber):
- conditions[each]["_options"] = [token.prefix, token.suffix]
- else:
- if token.required and len(token.fallback):
- conditions[each]["_fallback"] = [token.fallback]
- else:
- conditions[each]["_options"] = token.options.values()
-
- for token, condition in conditions.items():
- # If a token with options doesn't find a match, there is no point in checking the rest
- if "_options" in condition:
- if not any(option in name for option in condition["_options"]):
- return False
- elif "_fallback" in condition:
- if condition["_fallback"] in name:
- return True
-
- return False
-
def __build_regex(self) -> re.Pattern:
# ? Taken from Lucidity by Martin Pengelly-Phillips
# Escape non-placeholder components
From 9d0b0fdd368703a4ea74027e4877bc77dab3e5ef Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Fri, 10 Jan 2025 15:17:36 -0300
Subject: [PATCH 64/65] Validate against certain rules. Validation now returns
a list of valid rules or an empty list if none found
---
pyproject.toml | 2 +-
src/vfxnaming/naming.py | 41 ++++++++++++++++++-----
src/vfxnaming/rules.py | 29 ++++------------
tests/naming_test.py | 74 ++++++++++++++++++++++++++++++-----------
4 files changed, 94 insertions(+), 52 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index f4f1809..f82b4ff 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "vfxnaming"
-version = "1.5.0-beta"
+version = "1.5.1-beta"
authors = [
{ name="Chris Granados", email="info@chrisgranados.com" },
]
diff --git a/src/vfxnaming/naming.py b/src/vfxnaming/naming.py
index b5186b9..7b8b6e1 100644
--- a/src/vfxnaming/naming.py
+++ b/src/vfxnaming/naming.py
@@ -138,9 +138,12 @@ def solve(*args, **kwargs) -> AnyStr:
return rule.solve(**values)
-def validate(name: AnyStr, with_rules: Iterable = [], **kwargs) -> bool:
- """Validates a name string against the currently active rule and its
- tokens if passed as keyword arguments.
+def validate( # noqa: C901
+ name: AnyStr, with_rules: Iterable[str] = [], strict: bool = False, **kwargs
+) -> Iterable[rules.Rule]:
+ """Validates a name string against the currently active rule if no rules are passed or
+ against the list of specific rules passed in with_rules.
+ It also validates its tokens if passed as keyword arguments.
-For rules with repeated tokens:
@@ -162,15 +165,23 @@ def validate(name: AnyStr, with_rules: Iterable = [], **kwargs) -> bool:
Args:
name (str): Name string e.g.: C_helmet_001_MSH
+ with_rules (list, optional): List of rule names to validate against. Defaults to [].
+
+ strict (bool, optional): If False, it'll try to accept casing mismatches.
+
kwargs (dict): Keyword arguments with token names and values.
Returns:
- bool: True if the name is valid, False otherwise.
+ list: List of validated rules. Empty list if no rule could be validated.
"""
previously_active_rule = rules.get_active_rule()
- for rule in with_rules:
- if not rules.get_rule(rule):
- raise SolvingError(f"Rule {rule} not found in current session.")
+ if not len(with_rules):
+ with_rules = [previously_active_rule.name]
+ validated: Iterable[rules.Rule] = []
+ for with_rule in with_rules:
+ rule = rules.get_rule(with_rule)
+ if not rule:
+ logger.warning(f"Rule {with_rule} not found.")
rules.set_active_rule(rule)
# * This accounts for those cases where a token is used more than once in a rule
@@ -210,7 +221,21 @@ def validate(name: AnyStr, with_rules: Iterable = [], **kwargs) -> bool:
continue
fields_inc += 1
logger.debug(f"Validating rule '{rule.name}' with values {values}")
- return rule.validate(name, **values)
+ validation = rule.validate(name, strict, **values)
+ if validation:
+ rules.set_active_rule(previously_active_rule)
+ validated.append(rule)
+ rules.set_active_rule(previously_active_rule)
+ if not len(validated):
+ logger.warning(
+ f"Could not validate {name} with any of the given "
+ f"rules {', '.join([rule for rule in with_rules])}."
+ )
+ else:
+ logger.info(
+ f"Name {name} validated with rules: {', '.join([rule.name for rule in validated])}."
+ )
+ return validated
def validate_repo(repo: Path) -> bool:
diff --git a/src/vfxnaming/rules.py b/src/vfxnaming/rules.py
index 93cd44f..9eb5802 100644
--- a/src/vfxnaming/rules.py
+++ b/src/vfxnaming/rules.py
@@ -39,7 +39,6 @@ class Rule(Serializable):
__SEPARATORS_REGEX = re.compile(r"[_\-\.:\|/\\]")
__RULE_REFERENCE_REGEX = re.compile(r"{@(?P.+?)}")
__AT_CODE = "_FXW_"
- __NON_HARDCODED_REGEX = re.compile(r"[^{}]+(?=\{)|(?<=\})[^{}]+|^[^{]+|[^}]+$")
ANCHOR_START, ANCHOR_END, ANCHOR_BOTH = (1, 2, 3)
def __init__(self, name, pattern, anchor=ANCHOR_START):
@@ -170,21 +169,6 @@ def validate(self, name: AnyStr, strict: bool = False, **validate_values) -> boo
Returns:
bool: True if name matches the rule pattern, False otherwise.
"""
- # Check hardcoded values first. If these don't match, there's no point in cheking tokens
- harcoded = self.__NON_HARDCODED_REGEX.findall(self._pattern)
- check_function = (
- (lambda harcoded: all(token in name for token in harcoded))
- if strict
- else (
- lambda harcoded: all(token.lower() in name.lower() for token in harcoded)
- )
- )
- if not check_function(harcoded):
- logger.warning(
- f"Name {name} does not match rule pattern constant values '{self._pattern}'"
- )
- return False
-
expected_separators = self.__PATTERN_SEPARATORS_REGEX.findall(self._pattern)
if len(expected_separators) <= 0:
logger.warning(
@@ -200,14 +184,10 @@ def validate(self, name: AnyStr, strict: bool = False, **validate_values) -> boo
)
return False
- regex = self.__build_regex()
+ regex = self.__build_regex(strict)
match = regex.search(name)
if not match:
logger.warning(f"Name {name} does not match rule pattern '{self._pattern}'")
- if regex.search(name.lower()):
- logger.warning(
- f"Name {name} has casing mismatches with '{self._pattern}'"
- )
return False
match_dict = match.groupdict()
@@ -313,7 +293,7 @@ def validate(self, name: AnyStr, strict: bool = False, **validate_values) -> boo
return matching_options
- def __build_regex(self) -> re.Pattern:
+ def __build_regex(self, strict: bool = False) -> re.Pattern:
# ? Taken from Lucidity by Martin Pengelly-Phillips
# Escape non-placeholder components
expression = re.sub(
@@ -336,7 +316,10 @@ def __build_regex(self) -> re.Pattern:
expression = f"{expression}$"
# Compile expression
try:
- compiled = re.compile(expression)
+ if strict:
+ compiled = re.compile(expression)
+ else:
+ compiled = re.compile(expression, re.IGNORECASE)
except re.error as error:
if any(
[
diff --git a/tests/naming_test.py b/tests/naming_test.py
index fee9d4a..987798d 100644
--- a/tests/naming_test.py
+++ b/tests/naming_test.py
@@ -1,7 +1,8 @@
from pathlib import Path
import pytest
import tempfile
-from typing import Dict, List
+import types
+from typing import Dict, List, Union
from vfxnaming import naming as n
import vfxnaming.rules as rules
@@ -236,32 +237,33 @@ def setup(self):
[
(
"dramatic_bounce_chars_001_LGT",
- True,
+ 1,
),
(
"dramatic_bounce_chars_001",
- False,
+ 0,
),
(
"whatEver_bounce_chars_001_LGT",
- False,
+ 0,
),
(
"dramatic_bounce_chars_01_LGT",
- False,
+ 0,
),
(
"dramatic_bounce_chars_v001_LGT",
- False,
+ 0,
),
(
"dramatic_bounce_chars_1000_LGT",
- True,
+ 1,
),
],
)
- def test_valid(self, name: str, expected: bool):
- assert n.validate(name) is expected
+ def test_valid(self, name: str, expected: int):
+ validated = n.validate(name)
+ assert len(validated) == expected
@pytest.mark.parametrize(
"name,validate_values,expected",
@@ -269,27 +271,58 @@ def test_valid(self, name: str, expected: bool):
(
"dramatic_bounce_chars_001_LGT",
{"category": "dramatic"},
- True,
+ 1,
),
(
"dramatic_bounce_chars_001_LGT",
{"whatAffects": "chars"},
- True,
+ 1,
),
(
"dramatic_bounce_chars_001_LGT",
{"category": "practical"},
- False,
+ 0,
),
(
"dramatic_bounce_chars_001_LGT",
{"whatAffects": "anything"},
- False,
+ 0,
),
],
)
- def test_valid_with_tokens(self, name: str, validate_values: dict, expected: bool):
- assert n.validate(name, **validate_values) is expected
+ def test_valid_with_tokens(self, name: str, validate_values: dict, expected: int):
+ validated = n.validate(name, **validate_values)
+ assert len(validated) == expected
+
+
+class Test_ValidateHarcodedValues:
+ @pytest.fixture(autouse=True)
+ def setup(self):
+ tokens.reset_tokens()
+ rules.reset_rules()
+ tokens.add_token("side", center="C", left="L", right="R", default="center")
+ tokens.add_token(
+ "region",
+ orbital="ORBI",
+ parotidmasseter="PAROT",
+ mental="MENT",
+ frontal="FRONT",
+ zygomatic="ZYGO",
+ retromandibularfossa="RETMAND",
+ )
+ rules.add_rule("filename", "{side}-ALWAYS_{side}-This_{side}-{region}")
+
+ @pytest.mark.parametrize(
+ "name,strict,expected",
+ [
+ ("C-ALWAYS_C-This_C-ORBI", False, 1),
+ ("C-always_C-This_C-ORBI", False, 1),
+ ("C-always_C-this_C-ORBI", True, 0),
+ ],
+ )
+ def test_valid_harcoded(self, name: str, strict: bool, expected: int):
+ validated = n.validate(name, strict=strict)
+ assert len(validated) == expected
class Test_ValidateWithRepetitions:
@@ -322,28 +355,29 @@ def setup(self):
"side3": "right",
"region3": "zygomatic",
},
- True,
+ 1,
),
(
"R-MENT_C-PAROT_L-RETMAND",
{
"side2": "center",
},
- True,
+ 1,
),
(
"R-MENT_C-PAROT_L-RETMAND",
{
"side": "center",
},
- False,
+ 0,
),
],
)
def test_valid_with_repetitions(
- self, name: str, validate_values: dict, expected: bool
+ self, name: str, validate_values: dict, expected: int
):
- assert n.validate(name, **validate_values) is expected
+ validated = n.validate(name, **validate_values)
+ assert len(validated) == expected
class Test_RuleWithRepetitions:
From 82861ddde500ce5d8b66673ce3413cc891f17835 Mon Sep 17 00:00:00 2001
From: Chris Granados- Xian
Date: Fri, 10 Jan 2025 15:22:07 -0300
Subject: [PATCH 65/65] Update docs
---
docs/source/changelog.rst | 7 +++++++
docs/source/usage/validating.rst | 2 ++
2 files changed, 9 insertions(+)
diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst
index 2a5a8d8..aea76b1 100644
--- a/docs/source/changelog.rst
+++ b/docs/source/changelog.rst
@@ -1,6 +1,13 @@
Changelog
================================
+1.5.1-beta
+---------------------------------------
+
+**Improvements:**
+ - Adds strict validation option. If strict is True, the name must match exactly the casing the rule.
+ - If no rule names are passed to with_rules, only the active rule is validated.
+
1.4.5-beta
---------------------------------------
diff --git a/docs/source/usage/validating.rst b/docs/source/usage/validating.rst
index f4e6ca1..3482cfc 100644
--- a/docs/source/usage/validating.rst
+++ b/docs/source/usage/validating.rst
@@ -14,6 +14,8 @@ Many times the only thing we need is to know if a name is valid or not for a giv
- The number of expected separators must match with the rule.
- If tokens have options, the given name must use one of those options.
- If token is a number, validates suffix, prefix and padding.
+- If strict is passed as True to the validate function, the name must match exactly the casing the rule.
+- If no rule names are passed to with_rules, only the active rule is validated.
Let's set these Tokens and Rule.