diff --git a/.circleci/config.yml b/.circleci/config.yml index 512140d..ee1e032 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,7 +8,7 @@ jobs: docker: # specify the version you desire here # use `-browsers` prefix for selenium tests, e.g. `3.6.1-browsers` - - image: circleci/python:3.7.2 + - image: cimg/python:3.11 # Specify service dependencies here if necessary # CircleCI maintains a library of pre-built images @@ -30,7 +30,7 @@ jobs: - run: name: install dependencies command: | - sudo pip install pipenv + pip install pipenv pipenv install --dev - save_cache: diff --git a/.coveragerc b/.coveragerc index ab7f1fa..c009eaa 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,9 +1,9 @@ [run] source = - abe_json - abe_lookup - avs_json - avs_lookup - eas_json - eas_lookup - shared_code + ./ +omit = + .venv/* + tests/* + +[report] +show_missing = true \ No newline at end of file diff --git a/.github/workflows/azure.yml b/.github/workflows/azure.yml index 42ff5bb..288fc12 100644 --- a/.github/workflows/azure.yml +++ b/.github/workflows/azure.yml @@ -14,7 +14,7 @@ env: AZURE_FUNCTIONAPP_NAME: address-microservice # set this to your application's name AZURE_FUNCTIONAPP_SLOT_NAME: staging # This is the slot name to be deployed to AZURE_FUNCTIONAPP_PACKAGE_PATH: '.' # set this to the path to your web app project, defaults to the repository root - PYTHON_VERSION: '3.7' # set this to the python version to use (supports 3.6, 3.7, 3.8) + PYTHON_VERSION: '3.11' # set this to the python version to use (https://learn.microsoft.com/en-us/azure/azure-functions/functions-versions?tabs=isolated-process%2Cv4&pivots=programming-language-python#languages) jobs: build-and-deploy: diff --git a/.pylintrc b/.pylintrc index f39504b..73d3f6a 100644 --- a/.pylintrc +++ b/.pylintrc @@ -60,85 +60,85 @@ confidence= # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use "--disable=all --enable=classes # --disable=W". -disable=print-statement, - parameter-unpacking, - unpacking-in-except, - old-raise-syntax, - backtick, - long-suffix, - old-ne-operator, - old-octal-literal, - import-star-module-level, - non-ascii-bytes-literal, - raw-checker-failed, - bad-inline-option, - locally-disabled, - file-ignored, - suppressed-message, - useless-suppression, - deprecated-pragma, - use-symbolic-message-instead, - apply-builtin, - basestring-builtin, - buffer-builtin, - cmp-builtin, - coerce-builtin, - execfile-builtin, - file-builtin, - long-builtin, - raw_input-builtin, - reduce-builtin, - standarderror-builtin, - unicode-builtin, - xrange-builtin, - coerce-method, - delslice-method, - getslice-method, - setslice-method, - no-absolute-import, - old-division, - dict-iter-method, - dict-view-method, - next-method-called, - metaclass-assignment, - indexing-exception, - raising-string, - reload-builtin, - oct-method, - hex-method, - nonzero-method, - cmp-method, - input-builtin, - round-builtin, - intern-builtin, - unichr-builtin, - map-builtin-not-iterating, - zip-builtin-not-iterating, - range-builtin-not-iterating, - filter-builtin-not-iterating, - using-cmp-argument, - eq-without-hash, - div-method, - idiv-method, - rdiv-method, - exception-message-attribute, - invalid-str-codec, - sys-max-int, - bad-python3-import, - deprecated-string-function, - deprecated-str-translate-call, - deprecated-itertools-function, - deprecated-types-field, - next-method-defined, - dict-items-not-iterating, - dict-keys-not-iterating, - dict-values-not-iterating, - deprecated-operator-function, - deprecated-urllib-function, - xreadlines-attribute, - deprecated-sys-function, - exception-escape, - comprehension-escape +# disable=print-statement, +# parameter-unpacking, +# unpacking-in-except, +# old-raise-syntax, +# backtick, +# long-suffix, +# old-ne-operator, +# old-octal-literal, +# import-star-module-level, +# non-ascii-bytes-literal, +# raw-checker-failed, +# bad-inline-option, +# locally-disabled, +# file-ignored, +# suppressed-message, +# useless-suppression, +# deprecated-pragma, +# use-symbolic-message-instead, +# apply-builtin, +# basestring-builtin, +# buffer-builtin, +# cmp-builtin, +# coerce-builtin, +# execfile-builtin, +# file-builtin, +# long-builtin, +# raw_input-builtin, +# reduce-builtin, +# standarderror-builtin, +# unicode-builtin, +# xrange-builtin, +# coerce-method, +# delslice-method, +# getslice-method, +# setslice-method, +# no-absolute-import, +# old-division, +# dict-iter-method, +# dict-view-method, +# next-method-called, +# metaclass-assignment, +# indexing-exception, +# raising-string, +# reload-builtin, +# oct-method, +# hex-method, +# nonzero-method, +# cmp-method, +# input-builtin, +# round-builtin, +# intern-builtin, +# unichr-builtin, +# map-builtin-not-iterating, +# zip-builtin-not-iterating, +# range-builtin-not-iterating, +# filter-builtin-not-iterating, +# using-cmp-argument, +# eq-without-hash, +# div-method, +# idiv-method, +# rdiv-method, +# exception-message-attribute, +# invalid-str-codec, +# sys-max-int, +# bad-python3-import, +# deprecated-string-function, +# deprecated-str-translate-call, +# deprecated-itertools-function, +# deprecated-types-field, +# next-method-defined, +# dict-items-not-iterating, +# dict-keys-not-iterating, +# dict-values-not-iterating, +# deprecated-operator-function, +# deprecated-urllib-function, +# xreadlines-attribute, +# deprecated-sys-function, +# exception-escape, +# comprehension-escape # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option @@ -333,8 +333,8 @@ max-module-lines=1000 # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. # `trailing-comma` allows a space between comma and closing bracket: (a, ). # `empty-line` allows space-only lines. -no-space-check=trailing-comma, - dict-separator +# no-space-check=trailing-comma, +# dict-separator # Allow the body of a class to be on the same line as the declaration if body # contains single statement. @@ -357,7 +357,7 @@ ignore-docstrings=yes ignore-imports=no # Minimum lines number of a similarity. -min-similarity-lines=4 +min-similarity-lines=15 [BASIC] @@ -564,7 +564,7 @@ max-parents=7 max-public-methods=20 # Maximum number of return / yield for function / method body. -max-returns=6 +max-returns=10 # Maximum number of statements in function / method body. max-statements=50 @@ -577,5 +577,5 @@ min-public-methods=2 # Exceptions that will emit a warning when being caught. Defaults to # "BaseException, Exception". -overgeneral-exceptions=BaseException, - Exception +overgeneral-exceptions=builtins.BaseException, + builtins.Exception diff --git a/Pipfile b/Pipfile index 7daf69f..f4ba1ef 100644 --- a/Pipfile +++ b/Pipfile @@ -16,4 +16,4 @@ requests = "*" pyjsend = "*" [requires] -python_version = "3.7" +python_version = "3.11" diff --git a/Pipfile.lock b/Pipfile.lock index 37a86bf..fa0ac95 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,11 +1,11 @@ { "_meta": { "hash": { - "sha256": "f1d5572e8d285cbac893779587827086de323ac203e26b8de991e6b056f829f6" + "sha256": "ca88727e497e9dcb9fe8211e6c81453f314e580ae32bd3505889a467c047b82b" }, "pipfile-spec": 6, "requires": { - "python_version": "3.7" + "python_version": "3.11" }, "sources": [ { @@ -18,34 +18,125 @@ "default": { "azure-functions": { "hashes": [ - "sha256:51b2949faa11bc2875fdbc0cc073ac9803dd20d0807f46f94e0114924b31d7c1", - "sha256:893f4e696d111162b72e86258b85ca6e444c21b5e3d72048d3689079f107b325" + "sha256:6c45f5e61fe59328c81928a428d43c838e9ead52f1cde1628fcabb372fa10cc8", + "sha256:c359b9dbd2998c84d8595e31a28ffad4e8ca8dcfb4a3798327f776a67f964351" ], "index": "pypi", - "version": "==1.7.2" + "version": "==1.21.3" }, "certifi": { "hashes": [ - "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee", - "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8" + "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", + "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db" ], - "version": "==2021.5.30" + "markers": "python_version >= '3.6'", + "version": "==2024.12.14" }, "charset-normalizer": { "hashes": [ - "sha256:88fce3fa5b1a84fdcb3f603d889f723d1dd89b26059d0123ca435570e848d5e1", - "sha256:c46c3ace2d744cfbdebceaa3c19ae691f53ae621b39fd7570f59d14fb7f2fd12" - ], - "markers": "python_version >= '3'", - "version": "==2.0.3" + "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" }, "idna": { "hashes": [ - "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a", - "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3" + "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", + "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" ], - "markers": "python_version >= '3'", - "version": "==3.2" + "markers": "python_version >= '3.6'", + "version": "==3.10" }, "pyjsend": { "hashes": [ @@ -56,141 +147,239 @@ }, "requests": { "hashes": [ - "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24", - "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7" + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" ], "index": "pypi", - "version": "==2.26.0" + "markers": "python_version >= '3.8'", + "version": "==2.32.3" }, "urllib3": { "hashes": [ - "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4", - "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f" + "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", + "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", - "version": "==1.26.6" + "markers": "python_version >= '3.9'", + "version": "==2.3.0" } }, "develop": { "astroid": { "hashes": [ - "sha256:6021561b2e87ed6b3c93c2682ac50079c65ab08f1e4e0277ba38f97e0e492185", - "sha256:a670dd7af3fe603f51aa7117462588b7c3bdcd58007edfaee752bf82eceecd28" - ], - "markers": "python_version ~= '3.6'", - "version": "==2.6.4" - }, - "attrs": { - "hashes": [ - "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1", - "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==21.2.0" - }, - "backports.entry-points-selectable": { - "hashes": [ - "sha256:988468260ec1c196dab6ae1149260e2f5472c9110334e5d51adcb77867361f6a", - "sha256:a6d9a871cde5e15b4c4a53e3d43ba890cc6861ec1332c9c2428c92f977192acc" + "sha256:187ccc0c248bfbba564826c26f070494f7bc964fd286b6d9fff4420e55de828c", + "sha256:a88c7994f914a4ea8572fac479459f4955eeccc877be3f2d959a33273b0cf40b" ], - "markers": "python_version >= '2.7'", - "version": "==1.1.0" + "markers": "python_full_version >= '3.9.0'", + "version": "==3.3.8" }, "certifi": { "hashes": [ - "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee", - "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8" + "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", + "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db" ], - "version": "==2021.5.30" + "markers": "python_version >= '3.6'", + "version": "==2024.12.14" }, "cfgv": { "hashes": [ - "sha256:9e600479b3b99e8af981ecdfc80a0296104ee610cab48a5ae4ffd0b668650eb1", - "sha256:b449c9c6118fe8cca7fa5e00b9ec60ba08145d281d52164230a69211c5d597a1" + "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", + "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560" ], - "markers": "python_full_version >= '3.6.1'", - "version": "==3.3.0" + "markers": "python_version >= '3.8'", + "version": "==3.4.0" }, "charset-normalizer": { "hashes": [ - "sha256:88fce3fa5b1a84fdcb3f603d889f723d1dd89b26059d0123ca435570e848d5e1", - "sha256:c46c3ace2d744cfbdebceaa3c19ae691f53ae621b39fd7570f59d14fb7f2fd12" - ], - "markers": "python_version >= '3'", - "version": "==2.0.3" + "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" }, "coverage": { - "hashes": [ - "sha256:004d1880bed2d97151facef49f08e255a20ceb6f9432df75f4eef018fdd5a78c", - "sha256:01d84219b5cdbfc8122223b39a954820929497a1cb1422824bb86b07b74594b6", - "sha256:040af6c32813fa3eae5305d53f18875bedd079960822ef8ec067a66dd8afcd45", - "sha256:06191eb60f8d8a5bc046f3799f8a07a2d7aefb9504b0209aff0b47298333302a", - "sha256:13034c4409db851670bc9acd836243aeee299949bd5673e11844befcb0149f03", - "sha256:13c4ee887eca0f4c5a247b75398d4114c37882658300e153113dafb1d76de529", - "sha256:184a47bbe0aa6400ed2d41d8e9ed868b8205046518c52464fde713ea06e3a74a", - "sha256:18ba8bbede96a2c3dde7b868de9dcbd55670690af0988713f0603f037848418a", - "sha256:1aa846f56c3d49205c952d8318e76ccc2ae23303351d9270ab220004c580cfe2", - "sha256:217658ec7187497e3f3ebd901afdca1af062b42cfe3e0dafea4cced3983739f6", - "sha256:24d4a7de75446be83244eabbff746d66b9240ae020ced65d060815fac3423759", - "sha256:2910f4d36a6a9b4214bb7038d537f015346f413a975d57ca6b43bf23d6563b53", - "sha256:2949cad1c5208b8298d5686d5a85b66aae46d73eec2c3e08c817dd3513e5848a", - "sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4", - "sha256:2cafbbb3af0733db200c9b5f798d18953b1a304d3f86a938367de1567f4b5bff", - "sha256:2e0d881ad471768bf6e6c2bf905d183543f10098e3b3640fc029509530091502", - "sha256:30c77c1dc9f253283e34c27935fded5015f7d1abe83bc7821680ac444eaf7793", - "sha256:3487286bc29a5aa4b93a072e9592f22254291ce96a9fbc5251f566b6b7343cdb", - "sha256:372da284cfd642d8e08ef606917846fa2ee350f64994bebfbd3afb0040436905", - "sha256:41179b8a845742d1eb60449bdb2992196e211341818565abded11cfa90efb821", - "sha256:44d654437b8ddd9eee7d1eaee28b7219bec228520ff809af170488fd2fed3e2b", - "sha256:4a7697d8cb0f27399b0e393c0b90f0f1e40c82023ea4d45d22bce7032a5d7b81", - "sha256:51cb9476a3987c8967ebab3f0fe144819781fca264f57f89760037a2ea191cb0", - "sha256:52596d3d0e8bdf3af43db3e9ba8dcdaac724ba7b5ca3f6358529d56f7a166f8b", - "sha256:53194af30d5bad77fcba80e23a1441c71abfb3e01192034f8246e0d8f99528f3", - "sha256:5fec2d43a2cc6965edc0bb9e83e1e4b557f76f843a77a2496cbe719583ce8184", - "sha256:6c90e11318f0d3c436a42409f2749ee1a115cd8b067d7f14c148f1ce5574d701", - "sha256:74d881fc777ebb11c63736622b60cb9e4aee5cace591ce274fb69e582a12a61a", - "sha256:7501140f755b725495941b43347ba8a2777407fc7f250d4f5a7d2a1050ba8e82", - "sha256:796c9c3c79747146ebd278dbe1e5c5c05dd6b10cc3bcb8389dfdf844f3ead638", - "sha256:869a64f53488f40fa5b5b9dcb9e9b2962a66a87dab37790f3fcfb5144b996ef5", - "sha256:8963a499849a1fc54b35b1c9f162f4108017b2e6db2c46c1bed93a72262ed083", - "sha256:8d0a0725ad7c1a0bcd8d1b437e191107d457e2ec1084b9f190630a4fb1af78e6", - "sha256:900fbf7759501bc7807fd6638c947d7a831fc9fdf742dc10f02956ff7220fa90", - "sha256:92b017ce34b68a7d67bd6d117e6d443a9bf63a2ecf8567bb3d8c6c7bc5014465", - "sha256:970284a88b99673ccb2e4e334cfb38a10aab7cd44f7457564d11898a74b62d0a", - "sha256:972c85d205b51e30e59525694670de6a8a89691186012535f9d7dbaa230e42c3", - "sha256:9a1ef3b66e38ef8618ce5fdc7bea3d9f45f3624e2a66295eea5e57966c85909e", - "sha256:af0e781009aaf59e25c5a678122391cb0f345ac0ec272c7961dc5455e1c40066", - "sha256:b6d534e4b2ab35c9f93f46229363e17f63c53ad01330df9f2d6bd1187e5eaacf", - "sha256:b7895207b4c843c76a25ab8c1e866261bcfe27bfaa20c192de5190121770672b", - "sha256:c0891a6a97b09c1f3e073a890514d5012eb256845c451bd48f7968ef939bf4ae", - "sha256:c2723d347ab06e7ddad1a58b2a821218239249a9e4365eaff6649d31180c1669", - "sha256:d1f8bf7b90ba55699b3a5e44930e93ff0189aa27186e96071fac7dd0d06a1873", - "sha256:d1f9ce122f83b2305592c11d64f181b87153fc2c2bbd3bb4a3dde8303cfb1a6b", - "sha256:d314ed732c25d29775e84a960c3c60808b682c08d86602ec2c3008e1202e3bb6", - "sha256:d636598c8305e1f90b439dbf4f66437de4a5e3c31fdf47ad29542478c8508bbb", - "sha256:deee1077aae10d8fa88cb02c845cfba9b62c55e1183f52f6ae6a2df6a2187160", - "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c", - "sha256:f030f8873312a16414c0d8e1a1ddff2d3235655a2174e3648b4fa66b3f2f1079", - "sha256:f0b278ce10936db1a37e6954e15a3730bea96a0997c26d7fee88e6c396c2086d", - "sha256:f11642dddbb0253cc8853254301b51390ba0081750a8ac03f20ea8103f0c56b6" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4.0'", - "version": "==5.5" + "extras": [ + "toml" + ], + "hashes": [ + "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.10" }, "coveralls": { "hashes": [ - "sha256:172fb79c5f61c6ede60554f2cac46deff6d64ee735991fb2124fb414e188bdb4", - "sha256:9b3236e086627340bf2c95f89f757d093cbed43d17179d3f4fb568c347e7d29a" + "sha256:7a6b1fa9848332c7b2221afb20f3df90272ac0167060f41b5fe90429b30b1809", + "sha256:7b2a0a2bcef94f295e3cf28dcc55ca40b71c77d1c2446b538e85f0f7bc21aa69" ], "index": "pypi", - "version": "==3.1.0" + "markers": "python_version < '3.13' and python_version >= '3.8'", + "version": "==4.0.1" + }, + "dill": { + "hashes": [ + "sha256:468dff3b89520b474c0397703366b7b95eebe6303f108adf9b19da1f702be87a", + "sha256:81aa267dddf68cbfe8029c42ca9ec6a4ab3b22371d1c450abc54422577b4512c" + ], + "markers": "python_version >= '3.11'", + "version": "==0.3.9" }, "distlib": { "hashes": [ - "sha256:106fef6dc37dd8c0e2c0a60d3fca3e77460a48907f335fa28420463a6f799736", - "sha256:23e223426b28491b1ced97dc3bbe183027419dfc7982b4fa2f05d5f3ff10711c" + "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", + "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403" ], - "version": "==0.3.2" + "version": "==0.3.9" }, "docopt": { "hashes": [ @@ -200,297 +389,211 @@ }, "filelock": { "hashes": [ - "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59", - "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836" + "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0", + "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435" ], - "version": "==3.0.12" + "markers": "python_version >= '3.8'", + "version": "==3.16.1" }, "identify": { "hashes": [ - "sha256:7abaecbb414e385752e8ce02d8c494f4fbc780c975074b46172598a28f1ab839", - "sha256:a0e700637abcbd1caae58e0463861250095dfe330a8371733a471af706a4a29a" + "sha256:285a7d27e397652e8cafe537a6cc97dd470a970f48fb2e9d979aa38eae5513ac", + "sha256:993b0f01b97e0568c179bb9196391ff391bfb88a99099dbf5ce392b68f42d0af" ], - "markers": "python_full_version >= '3.6.1'", - "version": "==2.2.11" + "markers": "python_version >= '3.9'", + "version": "==2.6.4" }, "idna": { "hashes": [ - "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a", - "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3" - ], - "markers": "python_version >= '3'", - "version": "==3.2" - }, - "importlib-metadata": { - "hashes": [ - "sha256:079ada16b7fc30dfbb5d13399a5113110dab1aa7c2bc62f66af75f0b717c8cac", - "sha256:9f55f560e116f8643ecf2922d9cd3e1c7e8d52e683178fecd9d08f6aa357e11e" + "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", + "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3" ], - "markers": "python_version < '3.8'", - "version": "==4.6.1" + "markers": "python_version >= '3.6'", + "version": "==3.10" }, "iniconfig": { "hashes": [ - "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", - "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32" + "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", + "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" ], - "version": "==1.1.1" + "markers": "python_version >= '3.7'", + "version": "==2.0.0" }, "isort": { "hashes": [ - "sha256:eed17b53c3e7912425579853d078a0832820f023191561fcee9d7cae424e0813", - "sha256:f65ce5bd4cbc6abdfbe29afc2f0245538ab358c14590912df638033f157d555e" - ], - "markers": "python_version < '4.0' and python_full_version >= '3.6.1'", - "version": "==5.9.2" - }, - "lazy-object-proxy": { - "hashes": [ - "sha256:17e0967ba374fc24141738c69736da90e94419338fd4c7c7bef01ee26b339653", - "sha256:1fee665d2638491f4d6e55bd483e15ef21f6c8c2095f235fef72601021e64f61", - "sha256:22ddd618cefe54305df49e4c069fa65715be4ad0e78e8d252a33debf00f6ede2", - "sha256:24a5045889cc2729033b3e604d496c2b6f588c754f7a62027ad4437a7ecc4837", - "sha256:410283732af311b51b837894fa2f24f2c0039aa7f220135192b38fcc42bd43d3", - "sha256:4732c765372bd78a2d6b2150a6e99d00a78ec963375f236979c0626b97ed8e43", - "sha256:489000d368377571c6f982fba6497f2aa13c6d1facc40660963da62f5c379726", - "sha256:4f60460e9f1eb632584c9685bccea152f4ac2130e299784dbaf9fae9f49891b3", - "sha256:5743a5ab42ae40caa8421b320ebf3a998f89c85cdc8376d6b2e00bd12bd1b587", - "sha256:85fb7608121fd5621cc4377a8961d0b32ccf84a7285b4f1d21988b2eae2868e8", - "sha256:9698110e36e2df951c7c36b6729e96429c9c32b3331989ef19976592c5f3c77a", - "sha256:9d397bf41caad3f489e10774667310d73cb9c4258e9aed94b9ec734b34b495fd", - "sha256:b579f8acbf2bdd9ea200b1d5dea36abd93cabf56cf626ab9c744a432e15c815f", - "sha256:b865b01a2e7f96db0c5d12cfea590f98d8c5ba64ad222300d93ce6ff9138bcad", - "sha256:bf34e368e8dd976423396555078def5cfc3039ebc6fc06d1ae2c5a65eebbcde4", - "sha256:c6938967f8528b3668622a9ed3b31d145fab161a32f5891ea7b84f6b790be05b", - "sha256:d1c2676e3d840852a2de7c7d5d76407c772927addff8d742b9808fe0afccebdf", - "sha256:d7124f52f3bd259f510651450e18e0fd081ed82f3c08541dffc7b94b883aa981", - "sha256:d900d949b707778696fdf01036f58c9876a0d8bfe116e8d220cfd4b15f14e741", - "sha256:ebfd274dcd5133e0afae738e6d9da4323c3eb021b3e13052d8cbd0e457b1256e", - "sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93", - "sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.6.0" + "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109", + "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6" + ], + "markers": "python_full_version >= '3.8.0'", + "version": "==5.13.2" }, "mccabe": { "hashes": [ - "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", - "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", + "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e" ], - "version": "==0.6.1" + "markers": "python_version >= '3.6'", + "version": "==0.7.0" }, "nodeenv": { "hashes": [ - "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b", - "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7" + "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", + "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9" ], - "version": "==1.6.0" + "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": "==1.9.1" }, "packaging": { "hashes": [ - "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7", - "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14" + "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", + "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" ], - "markers": "python_version >= '3.6'", - "version": "==21.0" + "markers": "python_version >= '3.8'", + "version": "==24.2" }, "platformdirs": { "hashes": [ - "sha256:0b9547541f599d3d242078ae60b927b3e453f0ad52f58b4d4bc3be86aed3ec41", - "sha256:3b00d081227d9037bbbca521a5787796b5ef5000faea1e43fd76f1d44b06fcfa" + "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", + "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==2.0.2" + "markers": "python_version >= '3.8'", + "version": "==4.3.6" }, "pluggy": { "hashes": [ - "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", - "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" + "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", + "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.13.1" + "markers": "python_version >= '3.8'", + "version": "==1.5.0" }, "pre-commit": { "hashes": [ - "sha256:764972c60693dc668ba8e86eb29654ec3144501310f7198742a767bec385a378", - "sha256:b679d0fddd5b9d6d98783ae5f10fd0c4c59954f375b70a58cbe1ce9bcf9809a4" + "sha256:80905ac375958c0444c65e9cebebd948b3cdb518f335a091a670a89d652139d2", + "sha256:efde913840816312445dc98787724647c65473daefe420785f885e8ed9a06878" ], "index": "pypi", - "version": "==2.13.0" - }, - "py": { - "hashes": [ - "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3", - "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.10.0" + "markers": "python_version >= '3.9'", + "version": "==4.0.1" }, "pylint": { "hashes": [ - "sha256:23a1dc8b30459d78e9ff25942c61bb936108ccbe29dd9e71c01dc8274961709a", - "sha256:5d46330e6b8886c31b5e3aba5ff48c10f4aa5e76cbf9002c6544306221e63fbc" + "sha256:07c607523b17e6d16e2ae0d7ef59602e332caa762af64203c24b41c27139f36a", + "sha256:26e271a2bc8bce0fc23833805a9076dd9b4d5194e2a02164942cb3cdc37b4183" ], "index": "pypi", - "version": "==2.9.3" - }, - "pyparsing": { - "hashes": [ - "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", - "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" - ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.4.7" + "markers": "python_full_version >= '3.9.0'", + "version": "==3.3.3" }, "pytest": { "hashes": [ - "sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b", - "sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890" + "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", + "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761" ], "index": "pypi", - "version": "==6.2.4" + "markers": "python_version >= '3.8'", + "version": "==8.3.4" }, "pytest-cov": { "hashes": [ - "sha256:261bb9e47e65bd099c89c3edf92972865210c36813f80ede5277dceb77a4a62a", - "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7" + "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", + "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0" ], "index": "pypi", - "version": "==2.12.1" + "markers": "python_version >= '3.9'", + "version": "==6.0.0" }, "pyyaml": { "hashes": [ - "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf", - "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696", - "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393", - "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77", - "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922", - "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5", - "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8", - "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10", - "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc", - "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018", - "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e", - "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253", - "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347", - "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183", - "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541", - "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb", - "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185", - "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc", - "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db", - "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa", - "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46", - "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122", - "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b", - "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63", - "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df", - "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc", - "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247", - "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6", - "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==5.4.1" + "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", + "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", + "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", + "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", + "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", + "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", + "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", + "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", + "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", + "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", + "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", + "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", + "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", + "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", + "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", + "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", + "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", + "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", + "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", + "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", + "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", + "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", + "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", + "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", + "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", + "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", + "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", + "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", + "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", + "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", + "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", + "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", + "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", + "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", + "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", + "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", + "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", + "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", + "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", + "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", + "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", + "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", + "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", + "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", + "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", + "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", + "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", + "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", + "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", + "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", + "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", + "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", + "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" + ], + "markers": "python_version >= '3.8'", + "version": "==6.0.2" }, "requests": { "hashes": [ - "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24", - "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7" + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" ], "index": "pypi", - "version": "==2.26.0" - }, - "six": { - "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.16.0" - }, - "toml": { - "hashes": [ - "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", - "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" - ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.10.2" - }, - "typed-ast": { - "hashes": [ - "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace", - "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff", - "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266", - "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528", - "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6", - "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808", - "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4", - "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363", - "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341", - "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04", - "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41", - "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e", - "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3", - "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899", - "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805", - "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c", - "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c", - "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39", - "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a", - "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3", - "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7", - "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f", - "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075", - "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0", - "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40", - "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428", - "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927", - "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3", - "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f", - "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65" - ], - "markers": "python_version < '3.8' and implementation_name == 'cpython'", - "version": "==1.4.3" - }, - "typing-extensions": { - "hashes": [ - "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497", - "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342", - "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84" - ], - "markers": "python_version < '3.8'", - "version": "==3.10.0.0" + "markers": "python_version >= '3.8'", + "version": "==2.32.3" }, - "urllib3": { + "tomlkit": { "hashes": [ - "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4", - "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f" + "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde", + "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", - "version": "==1.26.6" + "markers": "python_version >= '3.8'", + "version": "==0.13.2" }, - "virtualenv": { - "hashes": [ - "sha256:51df5d8a2fad5d1b13e088ff38a433475768ff61f202356bb9812c454c20ae45", - "sha256:e4fc84337dce37ba34ef520bf2d4392b392999dbe47df992870dc23230f6b758" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==20.6.0" - }, - "wrapt": { + "urllib3": { "hashes": [ - "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7" + "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", + "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d" ], - "version": "==1.12.1" + "markers": "python_version >= '3.9'", + "version": "==2.3.0" }, - "zipp": { + "virtualenv": { "hashes": [ - "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3", - "sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4" + "sha256:23eae1b4516ecd610481eda647f3a7c09aea295055337331bb4e6892ecce47b0", + "sha256:2c9c3262bb8e7b87ea801d715fae4495e6032450c71d2309be9550e7364049aa" ], - "markers": "python_version >= '3.6'", - "version": "==3.5.0" + "markers": "python_version >= '3.8'", + "version": "==20.28.0" } } } diff --git a/README.md b/README.md index 3bc66f8..f7f0c41 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,19 @@ Example query `property_street_number`, `property_street_number_sfx`, `property_ $ curl https:///api/abe/json?$select=property_street_number,property_street_number_sfx,property_street_name,property_street_sfx,property_unit,block,lot&$where=block%20=%270834%27%20AND%20lot=%27144%27 ``` +## `api/status/http` + +Query http status of the serverless function. + +### Query + +Example + +```sh +curl https:///api/status/http + +{"status": "success", "data": {"message": "200 OK"}} +``` ## Deployment notes #### :warning: [Linux Consumption] Successful slot swaps automatically reverted after a few minutes :warning: @@ -80,11 +93,11 @@ Currently Azure Python Functions [does not support pipenv](https://github.com/Az sample usage: production ``` -$ pipenv lock --requirements > requirements.txt +$ pipenv requirements > requirements.txt ``` development ``` -pipenv lock --requirements --dev > requirements-dev.txt +pipenv requirements --dev > requirements-dev.txt ``` #### azure-functions-worker diff --git a/eas_json/__init__.py b/eas_json/__init__.py index a35cdbb..2062ae5 100644 --- a/eas_json/__init__.py +++ b/eas_json/__init__.py @@ -1,4 +1,5 @@ """ eas/json init file """ + import os import json import logging @@ -7,25 +8,25 @@ import azure.functions as func from shared_code.common import func_json_response + def main(req: func.HttpRequest) -> func.HttpResponse: - """ main function for eas/json """ - logging.info('EAS JSON processed a request.') + """main function for eas/json""" + logging.info("EAS JSON processed a request.") try: response = requests.get( - os.getenv('EAS_API_URL'), + os.getenv("EAS_API_URL"), params=req.params, - headers={'X-App-Token': os.getenv('ADDRESS_SVC_APP_TOKEN')} + headers={"X-App-Token": os.getenv("ADDRESS_SVC_APP_TOKEN")}, + timeout=600, ) - headers = { - "Access-Control-Allow-Origin": "*" - } + headers = {"Access-Control-Allow-Origin": "*"} return func_json_response(response, headers) - #pylint: disable=broad-except + # pylint: disable=broad-except except Exception as err: logging.error("EAS JSON error occurred: %s", err) - msg_error = "This endpoint encountered an error. {}".format(err) + msg_error = f"This endpoint encountered an error. {err}" func_response = json.dumps(jsend.error(msg_error)) return func.HttpResponse(func_response, status_code=500) diff --git a/eas_lookup/__init__.py b/eas_lookup/__init__.py index 7db12bb..cabd15f 100644 --- a/eas_lookup/__init__.py +++ b/eas_lookup/__init__.py @@ -1,4 +1,5 @@ """ eas/lookup init file """ + import os import json import logging @@ -6,34 +7,39 @@ import azure.functions as func from shared_code.common import func_json_response + def main(req: func.HttpRequest) -> func.HttpResponse: - """ main function for eas/lookup """ + """main function for eas/lookup""" - logging.info('EAS Lookup processed a request.') + logging.info("EAS Lookup processed a request.") try: - params = req.params.copy() - if 'search' in params: - params['$where'] = \ - "address like upper('{}%') AND parcel_number IS NOT NULL"\ - .format(params['search']) - del params['search'] + params = req.params.copy() + if "search" in params: + search_param = params["search"] + params["$where"] = ( + f"address like upper('{search_param}%') AND parcel_number IS NOT NULL" + ) + del params["search"] response = requests.get( - os.getenv('EAS_API_URL'), + os.getenv("EAS_API_URL"), params=params, - headers={'X-App-Token': os.getenv('ADDRESS_SVC_APP_TOKEN')} + headers={"X-App-Token": os.getenv("ADDRESS_SVC_APP_TOKEN")}, + timeout=600, ) + cache_max_age = os.getenv("ADDRESS_SVC_CACHE_MAX_AGE") headers = { - "Cache-Control": "s-maxage=1, stale-while-revalidate, max-age={}"\ - .format(os.getenv('ADDRESS_SVC_CACHE_MAX_AGE')), - "Access-Control-Allow-Origin": "*" + "Cache-Control": f"s-maxage=1, stale-while-revalidate, max-age={cache_max_age}", + "Access-Control-Allow-Origin": "*", } return func_json_response(response, headers) - #pylint: disable=broad-except + # pylint: disable=broad-except except Exception as err: logging.error("EAS Lookup error occurred: %s", err) - return func.HttpResponse(f"This endpoint encountered an error. {err}", status_code=500) + return func.HttpResponse( + f"This endpoint encountered an error. {err}", status_code=500 + ) diff --git a/host.json b/host.json index 3f33af1..ff66645 100644 --- a/host.json +++ b/host.json @@ -9,7 +9,7 @@ } }, "extensionBundle": { - "id": "Microsoft.Azure.Functions.ExtensionBundle", - "version": "[2.*, 3.0.0)" + "id": "Microsoft.Azure.Functions.ExtensionBundle", + "version": "[4.0.0, 5.0.0)" } } diff --git a/requirements-dev.txt b/requirements-dev.txt index 9723b56..a69cb17 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,50 +1,31 @@ -# -# These requirements were autogenerated by pipenv -# To regenerate from the project's Pipfile, run: -# -# pipenv lock --requirements --dev -# - -# Note: in pipenv 2020.x, "--dev" changed to emit both default and development -# requirements. To emit only development requirements, pass "--dev-only". - -i https://pypi.org/simple -astroid==2.6.2; python_version ~= '3.6' -attrs==21.2.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' -azure-functions==1.7.2 -backports.entry-points-selectable==1.1.0; python_version >= '2.7' -certifi==2021.5.30 -cfgv==3.3.0; python_full_version >= '3.6.1' -charset-normalizer==2.0.1; python_version >= '3' -coverage==5.5; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4' -coveralls==3.1.0 -distlib==0.3.2 +astroid==3.3.8; python_full_version >= '3.9.0' +certifi==2024.12.14; python_version >= '3.6' +cfgv==3.4.0; python_version >= '3.8' +charset-normalizer==3.4.1; python_version >= '3.7' +coverage[toml]==7.6.10; python_version >= '3.9' +coveralls==4.0.1; python_version < '3.13' and python_version >= '3.8' +dill==0.3.9; python_version >= '3.11' +distlib==0.3.9 docopt==0.6.2 -filelock==3.0.12 -identify==2.2.11; python_full_version >= '3.6.1' -idna==3.2; python_version >= '3' -importlib-metadata==4.6.1; python_version < '3.8' -iniconfig==1.1.1 -isort==5.9.2; python_version < '4' and python_full_version >= '3.6.1' -lazy-object-proxy==1.6.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' -mccabe==0.6.1 -nodeenv==1.6.0 -packaging==21.0; python_version >= '3.6' -platformdirs==2.0.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' -pluggy==0.13.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -pre-commit==2.13.0 -py==1.10.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -pylint==2.9.3 -pyparsing==2.4.7; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3' -pytest-cov==2.12.1 -pytest==6.2.4 -pyyaml==5.4.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' -requests==2.26.0 -six==1.16.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' -toml==0.10.2; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3' -typed-ast==1.4.3; python_version < '3.8' and implementation_name == 'cpython' -typing-extensions==3.10.0.0; python_version < '3.8' -urllib3==1.26.6; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4' -virtualenv==20.6.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' -wrapt==1.12.1 -zipp==3.5.0; python_version >= '3.6' +filelock==3.16.1; python_version >= '3.8' +identify==2.6.4; python_version >= '3.9' +idna==3.10; python_version >= '3.6' +iniconfig==2.0.0; python_version >= '3.7' +isort==5.13.2; python_full_version >= '3.8.0' +mccabe==0.7.0; python_version >= '3.6' +nodeenv==1.9.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6' +packaging==24.2; python_version >= '3.8' +platformdirs==4.3.6; python_version >= '3.8' +pluggy==1.5.0; python_version >= '3.8' +pre-commit==4.0.1; python_version >= '3.9' +pylint==3.3.3; python_full_version >= '3.9.0' +pytest==8.3.4; python_version >= '3.8' +pytest-cov==6.0.0; python_version >= '3.9' +pyyaml==6.0.2; python_version >= '3.8' +requests==2.32.3; python_version >= '3.8' +tomlkit==0.13.2; python_version >= '3.8' +urllib3==2.3.0; python_version >= '3.9' +virtualenv==20.28.0; python_version >= '3.8' +azure-functions==1.21.3 +pyjsend==0.2.2 diff --git a/requirements.txt b/requirements.txt index 98e3047..0e107eb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,15 +1,8 @@ -# -# These requirements were autogenerated by pipenv -# To regenerate from the project's Pipfile, run: -# -# pipenv lock --requirements -# - -i https://pypi.org/simple -azure-functions==1.7.2 -certifi==2021.5.30 -charset-normalizer==2.0.3; python_version >= '3' -idna==3.2; python_version >= '3' +azure-functions==1.21.3 +certifi==2024.12.14; python_version >= '3.6' +charset-normalizer==3.4.1; python_version >= '3.7' +idna==3.10; python_version >= '3.6' pyjsend==0.2.2 -requests==2.26.0 -urllib3==1.26.6; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4' +requests==2.32.3; python_version >= '3.8' +urllib3==2.3.0; python_version >= '3.9' diff --git a/shared_code/common.py b/shared_code/common.py index 6de0096..dcc0018 100644 --- a/shared_code/common.py +++ b/shared_code/common.py @@ -1,4 +1,5 @@ """ Common shared functions """ + import os import re import json @@ -6,117 +7,150 @@ import requests import azure.functions as func -def func_json_response(response, headers=None): - """ json func_json_response """ + +def func_json_response(response, headers=None, json_root="items"): + """json func_json_response""" json_data = json.loads(response.text) + func_status_code = response.status_code if response.status_code == 200: - func_response = json.dumps(jsend.success({"items": json_data})) + func_response = {json_root: json_data} else: - func_response = json.dumps(json_data) + func_response = json_data - func_status_code = response.status_code + return func_jsend_response( + func_response, headers=headers, status_code=func_status_code + ) + + +def func_jsend_response(data, headers=None, status_code=200): + """func_jsend_success_response""" + if 200 <= status_code < 500: + # check if data is JSON, else wrap in "message" + try: + # jsend: data must be the dict type + if not isinstance(data, dict): + data = json.loads(data) + except (TypeError, ValueError) as _err: + data = {"message": data} + if 200 <= status_code < 300: + func_response = json.dumps(jsend.success(data)) + else: + func_response = json.dumps(jsend.fail(data)) + else: + func_response = json.dumps(jsend.error(data)) return func.HttpResponse( func_response, - status_code=func_status_code, + status_code=status_code, mimetype="application/json", - headers=headers + headers=headers, ) + def abe_to_eas_fields_query(query_string): - """ replace abe fields with EAS fields in query string""" - #pylint: disable=line-too-long + """replace abe fields with EAS fields in query string""" + # pylint: disable=line-too-long address_field = "trim(property_street_number || greatest(property_street_number_sfx, '') || ' ' || property_street_name || ' ' || property_street_sfx || ' ' || greatest(property_unit, '') || greatest(property_unit_sfx, '')) as address" subs = { - "address" : address_field, - "parcel_number" : "block || lot as parcel_number", - "address_number" : "property_street_number as address_number", - "address_number_suffix" : "property_street_number_sfx as address_number_suffix", - "street_name" : "property_street_name as street_name", - "street_type" : "property_street_sfx as street_type", - "unit_number" : "greatest(property_unit, '') || greatest(property_unit_sfx, '') as unit_number", - "zip_code" : "'' as zip_code" - + "address": address_field, + "parcel_number": "block || lot as parcel_number", + "address_number": "property_street_number as address_number", + "address_number_suffix": "property_street_number_sfx as address_number_suffix", + "street_name": "property_street_name as street_name", + "street_type": "property_street_sfx as street_type", + "unit_number": "greatest(property_unit, '') || greatest(property_unit_sfx, '') as unit_number", + "zip_code": "'' as zip_code", } for old, new in subs.items(): - query_string = re.sub(r"\b%s\b" % old,new,query_string) + # pylint: disable=consider-using-f-string + query_string = re.sub(r"\b%s\b" % old, new, query_string) return query_string + def avs_to_eas_fields_query(query_string): - """ replace abe fields with AVS fields in query string""" - #pylint: disable=line-too-long + """replace abe fields with AVS fields in query string""" + # pylint: disable=line-too-long address_field = "trim(street_number || greatest(street_number_sfx, '') || ' ' || avs_street_name || ' ' || avs_street_sfx || ' ' || greatest(unit, '')) as address" subs = { - "address" : address_field, - "parcel_number" : "block || lot as parcel_number", - "address_number" : "street_number as address_number", + "address": address_field, + "parcel_number": "block || lot as parcel_number", + "address_number": "street_number as address_number", "address_number_suffix": "street_number_sfx as address_number_suffix", - "street_name" : "avs_street_name as street_name", - "street_type" : "avs_street_sfx as street_type", - "unit_number" : "greatest(unit, '') as unit_number" + "street_name": "avs_street_name as street_name", + "street_type": "avs_street_sfx as street_type", + "unit_number": "greatest(unit, '') as unit_number", } for old, new in subs.items(): - query_string = re.sub(r"\b%s\b" % old,new,query_string) + # pylint: disable=consider-using-f-string + query_string = re.sub(r"\b%s\b" % old, new, query_string) return query_string + def error_response(err): - """ return error response""" - msg_error = "This endpoint encountered an error. {}".format(err) + """return error response""" + msg_error = f"This endpoint encountered an error. {err}" func_response = json.dumps(jsend.error(msg_error)) return func.HttpResponse(func_response, status_code=500) + def api_json_request(api_url, field_mapping_function, params): - """ make json api request """ + """make json api request""" if "format" in params: - if params['format'] == "eas": - if "$where" in params and "parcel_number" in params['$where'] \ - and ("$select" not in params or "parcel_number" not in params['$select']): - params['$select'] += ",parcel_number" + if params["format"] == "eas": + if ( + "$where" in params + and "parcel_number" in params["$where"] + and ( + "$select" not in params or "parcel_number" not in params["$select"] + ) + ): + params["$select"] += ",parcel_number" if "$select" in params: - params['$select'] = field_mapping_function(params['$select']) - del params['format'] + params["$select"] = field_mapping_function(params["$select"]) + del params["format"] response = requests.get( api_url, params=params, headers={ - 'Authorization': 'Basic ' + os.getenv('ADDRESS_SVC_AUTH_API_KEY'), - 'X-App-Token': os.getenv('ADDRESS_SVC_APP_TOKEN') - } + "Authorization": "Basic " + os.getenv("ADDRESS_SVC_AUTH_API_KEY"), + "X-App-Token": os.getenv("ADDRESS_SVC_APP_TOKEN"), + }, + timeout=600, ) print(params) - headers = { - "Access-Control-Allow-Origin": "*" - } + headers = {"Access-Control-Allow-Origin": "*"} return func_json_response(response, headers) + def api_lookup_request(api_url, field_mapping_function, params): - """ make search api request """ - if 'search' in params : - params['$where'] = \ - "address like upper('{}%') AND block IS NOT NULL and lot IS NOT NULL"\ - .format(params['search']) - if '$select' in params: - params['$select'] = field_mapping_function(params['$select']) + """make search api request""" + if "search" in params: + search_param = params["search"] + params["$where"] = ( + f"address like upper('{search_param}%') AND block IS NOT NULL and lot IS NOT NULL" + ) + if "$select" in params: + params["$select"] = field_mapping_function(params["$select"]) else: - params['$select'] = field_mapping_function("address") - del params['search'] + params["$select"] = field_mapping_function("address") + del params["search"] response = requests.get( api_url, headers={ - 'Authorization': 'Basic ' + os.getenv('ADDRESS_SVC_AUTH_API_KEY'), - 'X-App-Token': os.getenv('ADDRESS_SVC_APP_TOKEN') + "Authorization": "Basic " + os.getenv("ADDRESS_SVC_AUTH_API_KEY"), + "X-App-Token": os.getenv("ADDRESS_SVC_APP_TOKEN"), }, - params=params + params=params, + timeout=600, ) - + cache_max_age = os.getenv("ADDRESS_SVC_CACHE_MAX_AGE") headers = { - "Cache-Control": "s-maxage=1, stale-while-revalidate, max-age={}"\ - .format(os.getenv('ADDRESS_SVC_CACHE_MAX_AGE')), - "Access-Control-Allow-Origin": "*" + "Cache-Control": f"s-maxage=1, stale-while-revalidate, max-age={cache_max_age}", + "Access-Control-Allow-Origin": "*", } return func_json_response(response, headers) diff --git a/status_http/__init__.py b/status_http/__init__.py new file mode 100644 index 0000000..9cf840c --- /dev/null +++ b/status_http/__init__.py @@ -0,0 +1,36 @@ +""" status/http init file """ + +import os +import json +import logging +import traceback +import requests +import jsend +import azure.functions as func +from requests.models import Response +from shared_code.common import func_jsend_response + + +def main(req: func.HttpRequest) -> func.HttpResponse: + """main function for status/http""" + logging.info("Status processed a request.") + + try: + if req.get_body() and len(req.get_body()): + status_code = 202 + # pylint: disable=protected-access + body = "202 Accepted" + else: + status_code = 200 + # pylint: disable=protected-access + body = "200 OK" + + headers = {"Access-Control-Allow-Origin": "*"} + return func_jsend_response(body, headers, status_code) + + # pylint: disable=broad-except + except Exception as err: + logging.error("Status HTTP error occurred: %s", traceback.format_exc()) + msg_error = f"This endpoint encountered an error. {err}" + func_response = json.dumps(jsend.error(msg_error)) + return func.HttpResponse(func_response, status_code=500) diff --git a/status_http/function.json b/status_http/function.json new file mode 100644 index 0000000..c41baf3 --- /dev/null +++ b/status_http/function.json @@ -0,0 +1,21 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "authLevel": "anonymous", + "type": "httpTrigger", + "direction": "in", + "name": "req", + "route": "status/http", + "methods": [ + "get", + "post" + ] + }, + { + "type": "http", + "direction": "out", + "name": "$return" + } + ] +} diff --git a/tests/test_abe_json.py b/tests/test_abe_json.py index a60ef96..fde426e 100644 --- a/tests/test_abe_json.py +++ b/tests/test_abe_json.py @@ -1,24 +1,25 @@ """ Test for abe/json endpoint """ + import json from unittest.mock import patch import azure.functions as func from abe_json import main + def test_abe_json_function(): - """ test_abe_json_function """ + """test_abe_json_function""" requests_params = [ {}, {"format": "eas", "$select": "address"}, - {"format": "eas", "$select": "address", "$where": "parcel_number IS NOT NULL"}] + {"format": "eas", "$select": "address", "$where": "parcel_number IS NOT NULL"}, + ] for params in requests_params: # Construct a mock HTTP request. req = func.HttpRequest( - method='GET', - body=None, - url='/api/abe/json', - params=params) + method="GET", body=None, url="/api/abe/json", params=params + ) # Call the function. resp = main(req) @@ -29,19 +30,17 @@ def test_abe_json_function(): resp_json = json.loads(resp.get_body()) # Check the output. - assert resp_json['status'] == 'success' - assert len(resp_json['data']['items']) > 0 + assert resp_json["status"] == "success" + assert len(resp_json["data"]["items"]) > 0 + def test_abe_json_function_request_error(): - """ test_abe_json_function_func_error """ + """test_abe_json_function_func_error""" # Construct a mock HTTP request. req = func.HttpRequest( - method='GET', - body=None, - url='/api/abe/json', - params={'hello': 'world'}) - + method="GET", body=None, url="/api/abe/json", params={"hello": "world"} + ) # Call the function. resp = main(req) @@ -49,20 +48,18 @@ def test_abe_json_function_request_error(): resp_json = json.loads(resp.get_body()) print(resp_json) # Check the output. - assert resp_json['error'] + assert resp_json["data"]["error"] + def test_abe_json_function_url_error(): - """ test_abe_json_function_url_error """ + """test_abe_json_function_url_error""" # Construct a mock HTTP request. with patch.dict("os.environ", {"ABE_API_URL": "", "ADDRESS_SVC_APP_TOKEN": ""}): - req = func.HttpRequest( - method='GET', - body=None, - url='/api/abe/json') + req = func.HttpRequest(method="GET", body=None, url="/api/abe/json") # Call the function. resp = main(req) resp_json = json.loads(resp.get_body()) # Check the output. - assert resp_json['status'] == 'error' + assert resp_json["status"] == "error" diff --git a/tests/test_avs_json.py b/tests/test_avs_json.py index 4ef29c7..1c99f24 100644 --- a/tests/test_avs_json.py +++ b/tests/test_avs_json.py @@ -1,24 +1,25 @@ """ Test for avs/json endpoint """ + import json from unittest.mock import patch import azure.functions as func from avs_json import main + def test_avs_json_function(): - """ test_avs_json_function """ + """test_avs_json_function""" requests_params = [ {}, {"format": "eas", "$select": "address"}, - {"format": "eas", "$select": "address", "$where": "parcel_number IS NOT NULL"}] + {"format": "eas", "$select": "address", "$where": "parcel_number IS NOT NULL"}, + ] for params in requests_params: # Construct a mock HTTP request. req = func.HttpRequest( - method='GET', - body=None, - url='/api/avs/json', - params=params) + method="GET", body=None, url="/api/avs/json", params=params + ) # Call the function. resp = main(req) @@ -29,19 +30,17 @@ def test_avs_json_function(): resp_json = json.loads(resp.get_body()) # Check the output. - assert resp_json['status'] == 'success' - assert len(resp_json['data']['items']) > 0 + assert resp_json["status"] == "success" + assert len(resp_json["data"]["items"]) > 0 + def test_avs_json_function_request_error(): - """ test_avs_json_function_func_error """ + """test_avs_json_function_func_error""" # Construct a mock HTTP request. req = func.HttpRequest( - method='GET', - body=None, - url='/api/avs/json', - params={'hello': 'world'}) - + method="GET", body=None, url="/api/avs/json", params={"hello": "world"} + ) # Call the function. resp = main(req) @@ -49,20 +48,18 @@ def test_avs_json_function_request_error(): resp_json = json.loads(resp.get_body()) print(resp_json) # Check the output. - assert resp_json['error'] + assert resp_json["data"]["error"] + def test_avs_json_function_url_error(): - """ test_avs_json_function_url_error """ + """test_avs_json_function_url_error""" # Construct a mock HTTP request. with patch.dict("os.environ", {"AVS_API_URL": "", "ADDRESS_SVC_APP_TOKEN": ""}): - req = func.HttpRequest( - method='GET', - body=None, - url='/api/avs/json') + req = func.HttpRequest(method="GET", body=None, url="/api/avs/json") # Call the function. resp = main(req) resp_json = json.loads(resp.get_body()) # Check the output. - assert resp_json['status'] == 'error' + assert resp_json["status"] == "error" diff --git a/tests/test_common.py b/tests/test_common.py new file mode 100644 index 0000000..6e651cf --- /dev/null +++ b/tests/test_common.py @@ -0,0 +1,18 @@ +# pylint: disable=consider-using-with +""" Test Common functions """ +import json +from unittest import mock + +from shared_code import common + + +def test_func_json_response_error(): + """test func_json_response()""" + + response500 = mock.Mock() + response500.status_code = 500 + response500.text = json.dumps("500 Internal Server Error") + jsend_response = common.func_json_response(response500) + jsend_json = json.loads(jsend_response.get_body()) + assert jsend_response.status_code == 500 + assert jsend_json["status"] == "error" diff --git a/tests/test_eas_json.py b/tests/test_eas_json.py index a21c28c..1efb1fa 100644 --- a/tests/test_eas_json.py +++ b/tests/test_eas_json.py @@ -1,16 +1,15 @@ """ Test for eas/json endpoint """ + import json from unittest.mock import patch import azure.functions as func from eas_json import main + def test_eas_json_function(): - """ test_eas_json_function """ + """test_eas_json_function""" # Construct a mock HTTP request. - req = func.HttpRequest( - method='GET', - body=None, - url='/api/eas/json') + req = func.HttpRequest(method="GET", body=None, url="/api/eas/json") # Call the function. resp = main(req) @@ -20,17 +19,16 @@ def test_eas_json_function(): resp_json = json.loads(resp.get_body()) # Check the output. - assert resp_json['status'] == 'success' - assert len(resp_json['data']['items']) > 0 + assert resp_json["status"] == "success" + assert len(resp_json["data"]["items"]) > 0 + def test_eas_json_function_request_error(): - """ test_eas_json_function_func_error """ + """test_eas_json_function_func_error""" # Construct a mock HTTP request. req = func.HttpRequest( - method='GET', - body=None, - url='/api/eas/json', - params={'hello': 'world'}) + method="GET", body=None, url="/api/eas/json", params={"hello": "world"} + ) # Call the function. resp = main(req) @@ -38,20 +36,18 @@ def test_eas_json_function_request_error(): resp_json = json.loads(resp.get_body()) print(resp_json) # Check the output. - assert resp_json['error'] + assert resp_json["data"]["error"] + def test_eas_json_function_url_error(): - """ test_eas_json_function_url_error """ + """test_eas_json_function_url_error""" # Construct a mock HTTP request. with patch.dict("os.environ", {"EAS_API_URL": "", "ADDRESS_SVC_APP_TOKEN": ""}): - req = func.HttpRequest( - method='GET', - body=None, - url='/api/eas/json') + req = func.HttpRequest(method="GET", body=None, url="/api/eas/json") # Call the function. resp = main(req) resp_json = json.loads(resp.get_body()) # Check the output. - assert resp_json['status'] == 'error' + assert resp_json["status"] == "error" diff --git a/tests/test_status_http.py b/tests/test_status_http.py new file mode 100644 index 0000000..f2c5cbf --- /dev/null +++ b/tests/test_status_http.py @@ -0,0 +1,56 @@ +""" Test for status/http endpoint """ +import json +from unittest.mock import patch +import azure.functions as func +from status_http import main + +def test_status_http_function(): + """ test_status_http_function """ + # Construct a mock HTTP request. + req = func.HttpRequest( + method='GET', + body=None, + url='/api/status/http') + + # Call the function. + resp = main(req) + # print response body + print(resp.get_body()) + # loads response body as json + resp_json = json.loads(resp.get_body()) + + # Check the output. + assert resp_json['status'] == 'success' + + +def test_status_http_function_other(): + """ test_status_http_function_other """ + # Construct a mock HTTP request. + req = func.HttpRequest( + method='POST', + body="TEST", + url='/api/status/http') + + # Call the function. + resp = main(req) + + assert resp.status_code == 202 + +def test_status_http_function_request_error(): + """ test_status_http_function error """ + + with patch('status_http.func_jsend_response') as mock: + mock.side_effect = ValueError('ERROR_TEST') + # Construct a mock HTTP request. + req = func.HttpRequest( + method='GET', + body=None, + url='/api/status/http') + + # Call the function. + resp = main(req) + + resp_json = json.loads(resp.get_body()) + print(resp_json) + # Check the output. + assert resp_json['status'] == 'error'