From 3f97925a8fdc32858a38f39f59cef00856623275 Mon Sep 17 00:00:00 2001 From: Markus Hauru Date: Wed, 1 Mar 2023 14:51:07 +0000 Subject: [PATCH 01/15] Add WeightedBooleanProvider --- sqlsynthgen/providers.py | 24 +++++++++++++++++++++++- tests/examples/expected_ssg.py | 2 ++ tests/test_providers.py | 19 +++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/sqlsynthgen/providers.py b/sqlsynthgen/providers.py index 374c25e7..4f36478b 100644 --- a/sqlsynthgen/providers.py +++ b/sqlsynthgen/providers.py @@ -1,9 +1,10 @@ """This module contains Mimesis Provider sub-classes.""" import datetime as dt import random -from typing import Any +from typing import Any, Optional from mimesis import Datetime, Text +from mimesis import random as mimesis_random from mimesis.providers.base import BaseDataProvider, BaseProvider from sqlalchemy.sql import func, select @@ -82,3 +83,24 @@ def timespan( start = Datetime().datetime(start=earliest_start_year, end=last_start_year) end = start + delta return start, end, delta + + +class WeightedBooleanProvider(BaseProvider): + """A Mimesis provider for booleans with a given probability for True.""" + + def __init__(self, seed: Optional[int] = None) -> None: + """Initialize a WeightedBooleanProvider. Optionally a seed can be provided.""" + if seed is not None: + self.rand = mimesis_random.Random(seed) + else: + self.rand = mimesis_random.Random() + super().__init__() + + class Meta: + """Meta-class for WeightedBooleanProvider settings.""" + + name = "weighted_boolean_provider" + + def bool(self, probability: float) -> bool: + """Return True with given `probability`, otherwise False.""" + return self.rand.uniform(0, 1) < probability diff --git a/tests/examples/expected_ssg.py b/tests/examples/expected_ssg.py index ac0b02ce..f98be8b8 100644 --- a/tests/examples/expected_ssg.py +++ b/tests/examples/expected_ssg.py @@ -13,6 +13,8 @@ generic.add_provider(TimedeltaProvider) from sqlsynthgen.providers import TimespanProvider generic.add_provider(TimespanProvider) +from sqlsynthgen.providers import WeightedBooleanProvider +generic.add_provider(WeightedBooleanProvider) import tests.examples.example_orm import custom_generators diff --git a/tests/test_providers.py b/tests/test_providers.py index b00aec03..ea6a50a9 100644 --- a/tests/test_providers.py +++ b/tests/test_providers.py @@ -92,3 +92,22 @@ def test_timespan(self) -> None: assert earliest_start_year <= start.year <= last_start_year assert min_dt <= delta <= max_dt assert end - start == delta + + +class TestWeightedBooleanProvider(TestCase): + """Tests for WeightedBooleanProvider.""" + + def test_bool(self) -> None: + """Test the bool method""" + assert not providers.WeightedBooleanProvider().bool(0.0) + assert providers.WeightedBooleanProvider().bool(1.0) + seed = 0 + num_repeats = 10000 + prov = providers.WeightedBooleanProvider(seed) + for probability in (0.1, 0.5, 0.9): + bools = [prov.bool(probability) for _ in range(num_repeats)] + trues = sum(bools) + falses = sum(not x for x in bools) + expected_odds = probability / (1 - probability) + observed_odds = trues / falses + assert abs(observed_odds / expected_odds - 1.0) < 0.1 From 4be5c848849607e3b88541c3f00708d5411d9ba2 Mon Sep 17 00:00:00 2001 From: Markus Hauru Date: Wed, 1 Mar 2023 15:24:23 +0000 Subject: [PATCH 02/15] First version of make-stats --- poetry.lock | 1978 +++++++++++++++----------- pyproject.toml | 6 +- sqlsynthgen/main.py | 30 +- sqlsynthgen/make.py | 57 +- tests/examples/example_stats.yaml | 1 + tests/examples/expected_ssg.py | 5 +- tests/examples/generator_conf.yaml | 20 + tests/examples/src.dump | 1003 +++++++++++++ tests/test_functional.py | 19 +- tests/test_main.py | 31 +- tests/test_make.py | 27 +- tests/workspace/custom_generators.py | 6 + 12 files changed, 2300 insertions(+), 883 deletions(-) create mode 100644 tests/examples/example_stats.yaml diff --git a/poetry.lock b/poetry.lock index 9892ce24..24272038 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,3 +1,5 @@ +# This file is automatically @generated by Poetry and should not be changed by hand. + [[package]] name = "alabaster" version = "0.7.13" @@ -5,6 +7,21 @@ description = "A configurable sidebar-enabled Sphinx theme" category = "main" optional = true python-versions = ">=3.6" +files = [ + {file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"}, + {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, +] + +[[package]] +name = "antlr4-python3-runtime" +version = "4.9.3" +description = "ANTLR 4.9.3 runtime for Python 3.7" +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "antlr4-python3-runtime-4.9.3.tar.gz", hash = "sha256:f224469b4168294902bb1efa80a8bf7855f24c99aef99cbefc1bcd3cce77881b"}, +] [[package]] name = "astroid" @@ -13,25 +30,46 @@ description = "An abstract syntax tree for Python with inference support." category = "dev" optional = false python-versions = ">=3.7.2" +files = [ + {file = "astroid-2.14.2-py3-none-any.whl", hash = "sha256:0e0e3709d64fbffd3037e4ff403580550f14471fd3eaae9fa11cc9a5c7901153"}, + {file = "astroid-2.14.2.tar.gz", hash = "sha256:a3cf9f02c53dd259144a7e8f3ccd75d67c9a8c716ef183e0c1f291bc5d7bb3cf"}, +] [package.dependencies] lazy-object-proxy = ">=1.4.0" typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} -wrapt = [ - {version = ">=1.11,<2", markers = "python_version < \"3.11\""}, - {version = ">=1.14,<2", markers = "python_version >= \"3.11\""}, +wrapt = {version = ">=1.11,<2", markers = "python_version < \"3.11\""} + +[[package]] +name = "attrs" +version = "22.2.0" +description = "Classes Without Boilerplate" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"}, + {file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"}, ] +[package.extras] +cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"] +dev = ["attrs[docs,tests]"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"] +tests = ["attrs[tests-no-zope]", "zope.interface"] +tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"] + [[package]] name = "babel" -version = "2.11.0" +version = "2.12.1" description = "Internationalization utilities" category = "main" optional = true -python-versions = ">=3.6" - -[package.dependencies] -pytz = ">=2015.7" +python-versions = ">=3.7" +files = [ + {file = "Babel-2.12.1-py3-none-any.whl", hash = "sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610"}, + {file = "Babel-2.12.1.tar.gz", hash = "sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455"}, +] [[package]] name = "black" @@ -40,6 +78,20 @@ description = "The uncompromising code formatter." category = "dev" optional = false python-versions = ">=3.7" +files = [ + {file = "black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"}, + {file = "black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351"}, + {file = "black-22.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f"}, + {file = "black-22.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4"}, + {file = "black-22.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2"}, + {file = "black-22.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350"}, + {file = "black-22.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d"}, + {file = "black-22.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc"}, + {file = "black-22.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320"}, + {file = "black-22.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148"}, + {file = "black-22.12.0-py3-none-any.whl", hash = "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf"}, + {file = "black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f"}, +] [package.dependencies] click = ">=8.0.0" @@ -62,6 +114,10 @@ description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = true python-versions = ">=3.6" +files = [ + {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, + {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, +] [[package]] name = "charset-normalizer" @@ -70,6 +126,96 @@ description = "The Real First Universal Charset Detector. Open, modern and activ category = "main" optional = true python-versions = "*" +files = [ + {file = "charset-normalizer-3.0.1.tar.gz", hash = "sha256:ebea339af930f8ca5d7a699b921106c6e29c617fe9606fa7baa043c1cdae326f"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88600c72ef7587fe1708fd242b385b6ed4b8904976d5da0893e31df8b3480cb6"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c75ffc45f25324e68ab238cb4b5c0a38cd1c3d7f1fb1f72b5541de469e2247db"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db72b07027db150f468fbada4d85b3b2729a3db39178abf5c543b784c1254539"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62595ab75873d50d57323a91dd03e6966eb79c41fa834b7a1661ed043b2d404d"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ff6f3db31555657f3163b15a6b7c6938d08df7adbfc9dd13d9d19edad678f1e8"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:772b87914ff1152b92a197ef4ea40efe27a378606c39446ded52c8f80f79702e"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70990b9c51340e4044cfc394a81f614f3f90d41397104d226f21e66de668730d"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:292d5e8ba896bbfd6334b096e34bffb56161c81408d6d036a7dfa6929cff8783"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2edb64ee7bf1ed524a1da60cdcd2e1f6e2b4f66ef7c077680739f1641f62f555"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:31a9ddf4718d10ae04d9b18801bd776693487cbb57d74cc3458a7673f6f34639"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:44ba614de5361b3e5278e1241fda3dc1838deed864b50a10d7ce92983797fa76"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:12db3b2c533c23ab812c2b25934f60383361f8a376ae272665f8e48b88e8e1c6"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c512accbd6ff0270939b9ac214b84fb5ada5f0409c44298361b2f5e13f9aed9e"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-win32.whl", hash = "sha256:502218f52498a36d6bf5ea77081844017bf7982cdbe521ad85e64cabee1b608b"}, + {file = "charset_normalizer-3.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:601f36512f9e28f029d9481bdaf8e89e5148ac5d89cffd3b05cd533eeb423b59"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0298eafff88c99982a4cf66ba2efa1128e4ddaca0b05eec4c456bbc7db691d8d"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a8d0fc946c784ff7f7c3742310cc8a57c5c6dc31631269876a88b809dbeff3d3"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:87701167f2a5c930b403e9756fab1d31d4d4da52856143b609e30a1ce7160f3c"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14e76c0f23218b8f46c4d87018ca2e441535aed3632ca134b10239dfb6dadd6b"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c0a590235ccd933d9892c627dec5bc7511ce6ad6c1011fdf5b11363022746c1"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c7fe7afa480e3e82eed58e0ca89f751cd14d767638e2550c77a92a9e749c317"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79909e27e8e4fcc9db4addea88aa63f6423ebb171db091fb4373e3312cb6d603"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ac7b6a045b814cf0c47f3623d21ebd88b3e8cf216a14790b455ea7ff0135d18"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:72966d1b297c741541ca8cf1223ff262a6febe52481af742036a0b296e35fa5a"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f9d0c5c045a3ca9bedfc35dca8526798eb91a07aa7a2c0fee134c6c6f321cbd7"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5995f0164fa7df59db4746112fec3f49c461dd6b31b841873443bdb077c13cfc"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4a8fcf28c05c1f6d7e177a9a46a1c52798bfe2ad80681d275b10dcf317deaf0b"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:761e8904c07ad053d285670f36dd94e1b6ab7f16ce62b9805c475b7aa1cffde6"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-win32.whl", hash = "sha256:71140351489970dfe5e60fc621ada3e0f41104a5eddaca47a7acb3c1b851d6d3"}, + {file = "charset_normalizer-3.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:9ab77acb98eba3fd2a85cd160851816bfce6871d944d885febf012713f06659c"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:84c3990934bae40ea69a82034912ffe5a62c60bbf6ec5bc9691419641d7d5c9a"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74292fc76c905c0ef095fe11e188a32ebd03bc38f3f3e9bcb85e4e6db177b7ea"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c95a03c79bbe30eec3ec2b7f076074f4281526724c8685a42872974ef4d36b72"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c39b0e3eac288fedc2b43055cfc2ca7a60362d0e5e87a637beac5d801ef478"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df2c707231459e8a4028eabcd3cfc827befd635b3ef72eada84ab13b52e1574d"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93ad6d87ac18e2a90b0fe89df7c65263b9a99a0eb98f0a3d2e079f12a0735837"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:59e5686dd847347e55dffcc191a96622f016bc0ad89105e24c14e0d6305acbc6"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:cd6056167405314a4dc3c173943f11249fa0f1b204f8b51ed4bde1a9cd1834dc"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:083c8d17153ecb403e5e1eb76a7ef4babfc2c48d58899c98fcaa04833e7a2f9a"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:f5057856d21e7586765171eac8b9fc3f7d44ef39425f85dbcccb13b3ebea806c"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:7eb33a30d75562222b64f569c642ff3dc6689e09adda43a082208397f016c39a"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-win32.whl", hash = "sha256:95dea361dd73757c6f1c0a1480ac499952c16ac83f7f5f4f84f0658a01b8ef41"}, + {file = "charset_normalizer-3.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:eaa379fcd227ca235d04152ca6704c7cb55564116f8bc52545ff357628e10602"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3e45867f1f2ab0711d60c6c71746ac53537f1684baa699f4f668d4c6f6ce8e14"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cadaeaba78750d58d3cc6ac4d1fd867da6fc73c88156b7a3212a3cd4819d679d"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:911d8a40b2bef5b8bbae2e36a0b103f142ac53557ab421dc16ac4aafee6f53dc"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:503e65837c71b875ecdd733877d852adbc465bd82c768a067badd953bf1bc5a3"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a60332922359f920193b1d4826953c507a877b523b2395ad7bc716ddd386d866"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16a8663d6e281208d78806dbe14ee9903715361cf81f6d4309944e4d1e59ac5b"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a16418ecf1329f71df119e8a65f3aa68004a3f9383821edcb20f0702934d8087"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9d9153257a3f70d5f69edf2325357251ed20f772b12e593f3b3377b5f78e7ef8"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:02a51034802cbf38db3f89c66fb5d2ec57e6fe7ef2f4a44d070a593c3688667b"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:2e396d70bc4ef5325b72b593a72c8979999aa52fb8bcf03f701c1b03e1166918"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:11b53acf2411c3b09e6af37e4b9005cba376c872503c8f28218c7243582df45d"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-win32.whl", hash = "sha256:0bf2dae5291758b6f84cf923bfaa285632816007db0330002fa1de38bfcb7154"}, + {file = "charset_normalizer-3.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:2c03cc56021a4bd59be889c2b9257dae13bf55041a3372d3295416f86b295fb5"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:024e606be3ed92216e2b6952ed859d86b4cfa52cd5bc5f050e7dc28f9b43ec42"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4b0d02d7102dd0f997580b51edc4cebcf2ab6397a7edf89f1c73b586c614272c"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:358a7c4cb8ba9b46c453b1dd8d9e431452d5249072e4f56cfda3149f6ab1405e"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81d6741ab457d14fdedc215516665050f3822d3e56508921cc7239f8c8e66a58"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8b8af03d2e37866d023ad0ddea594edefc31e827fee64f8de5611a1dbc373174"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9cf4e8ad252f7c38dd1f676b46514f92dc0ebeb0db5552f5f403509705e24753"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e696f0dd336161fca9adbb846875d40752e6eba585843c768935ba5c9960722b"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c22d3fe05ce11d3671297dc8973267daa0f938b93ec716e12e0f6dee81591dc1"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:109487860ef6a328f3eec66f2bf78b0b72400280d8f8ea05f69c51644ba6521a"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:37f8febc8ec50c14f3ec9637505f28e58d4f66752207ea177c1d67df25da5aed"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:f97e83fa6c25693c7a35de154681fcc257c1c41b38beb0304b9c4d2d9e164479"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a152f5f33d64a6be73f1d30c9cc82dfc73cec6477ec268e7c6e4c7d23c2d2291"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:39049da0ffb96c8cbb65cbf5c5f3ca3168990adf3551bd1dee10c48fce8ae820"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-win32.whl", hash = "sha256:4457ea6774b5611f4bed5eaa5df55f70abde42364d498c5134b7ef4c6958e20e"}, + {file = "charset_normalizer-3.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:e62164b50f84e20601c1ff8eb55620d2ad25fb81b59e3cd776a1902527a788af"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8eade758719add78ec36dc13201483f8e9b5d940329285edcd5f70c0a9edbd7f"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8499ca8f4502af841f68135133d8258f7b32a53a1d594aa98cc52013fff55678"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3fc1c4a2ffd64890aebdb3f97e1278b0cc72579a08ca4de8cd2c04799a3a22be"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00d3ffdaafe92a5dc603cb9bd5111aaa36dfa187c8285c543be562e61b755f6b"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2ac1b08635a8cd4e0cbeaf6f5e922085908d48eb05d44c5ae9eabab148512ca"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6f45710b4459401609ebebdbcfb34515da4fc2aa886f95107f556ac69a9147e"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ae1de54a77dc0d6d5fcf623290af4266412a7c4be0b1ff7444394f03f5c54e3"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b590df687e3c5ee0deef9fc8c547d81986d9a1b56073d82de008744452d6541"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab5de034a886f616a5668aa5d098af2b5385ed70142090e2a31bcbd0af0fdb3d"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9cb3032517f1627cc012dbc80a8ec976ae76d93ea2b5feaa9d2a5b8882597579"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:608862a7bf6957f2333fc54ab4399e405baad0163dc9f8d99cb236816db169d4"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0f438ae3532723fb6ead77e7c604be7c8374094ef4ee2c5e03a3a17f1fca256c"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:356541bf4381fa35856dafa6a965916e54bed415ad8a24ee6de6e37deccf2786"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-win32.whl", hash = "sha256:39cf9ed17fe3b1bc81f33c9ceb6ce67683ee7526e65fde1447c772afc54a1bb8"}, + {file = "charset_normalizer-3.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:0a11e971ed097d24c534c037d298ad32c6ce81a45736d31e0ff0ad37ab437d59"}, + {file = "charset_normalizer-3.0.1-py3-none-any.whl", hash = "sha256:7e189e2e1d3ed2f4aebabd2d5b0f931e883676e51c7624826e0a4e5fe8a0bf24"}, +] [[package]] name = "click" @@ -78,6 +224,10 @@ description = "Composable command line interface toolkit" category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, + {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, +] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} @@ -89,6 +239,10 @@ description = "Cross-platform colored terminal text." category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] [[package]] name = "dill" @@ -97,6 +251,10 @@ description = "serialize all of python" category = "dev" optional = false python-versions = ">=3.7" +files = [ + {file = "dill-0.3.6-py3-none-any.whl", hash = "sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0"}, + {file = "dill-0.3.6.tar.gz", hash = "sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373"}, +] [package.extras] graph = ["objgraph (>=1.7.2)"] @@ -108,6 +266,42 @@ description = "Docutils -- Python Documentation Utilities" category = "main" optional = true python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "docutils-0.18.1-py2.py3-none-any.whl", hash = "sha256:23010f129180089fbcd3bc08cfefccb3b890b0050e1ca00c867036e9d161b98c"}, + {file = "docutils-0.18.1.tar.gz", hash = "sha256:679987caf361a7539d76e584cbeddc311e3aee937877c87346f31debc63e9d06"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.1.0" +description = "Backport of PEP 654 (exception groups)" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.1.0-py3-none-any.whl", hash = "sha256:327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e"}, + {file = "exceptiongroup-1.1.0.tar.gz", hash = "sha256:bcb67d800a4497e1b404c2dd44fca47d3b7a5e5433dbab67f96c1a685cdfdf23"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "graphviz" +version = "0.17" +description = "Simple Python interface for Graphviz" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "graphviz-0.17-py3-none-any.whl", hash = "sha256:5dadec94046d82adaae6019311a30e0487536d9d5a60d85451f0ba32f9fc6559"}, + {file = "graphviz-0.17.zip", hash = "sha256:ef6e2c5deb9cdcc0c7eece1d89625fd07b0f2208ea2bcb483520907ddf8b4e12"}, +] + +[package.extras] +dev = ["flake8", "pep8-naming", "tox (>=3)", "twine", "wheel"] +docs = ["sphinx (>=1.8)", "sphinx-autodoc-typehints", "sphinx-rtd-theme"] +test = ["mock (>=3)", "pytest (>=5.2)", "pytest-cov", "pytest-mock (>=2)"] [[package]] name = "greenlet" @@ -116,6 +310,68 @@ description = "Lightweight in-process concurrent programming" category = "main" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" +files = [ + {file = "greenlet-2.0.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:bdfea8c661e80d3c1c99ad7c3ff74e6e87184895bbaca6ee8cc61209f8b9b85d"}, + {file = "greenlet-2.0.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:9d14b83fab60d5e8abe587d51c75b252bcc21683f24699ada8fb275d7712f5a9"}, + {file = "greenlet-2.0.2-cp27-cp27m-win32.whl", hash = "sha256:6c3acb79b0bfd4fe733dff8bc62695283b57949ebcca05ae5c129eb606ff2d74"}, + {file = "greenlet-2.0.2-cp27-cp27m-win_amd64.whl", hash = "sha256:283737e0da3f08bd637b5ad058507e578dd462db259f7f6e4c5c365ba4ee9343"}, + {file = "greenlet-2.0.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d27ec7509b9c18b6d73f2f5ede2622441de812e7b1a80bbd446cb0633bd3d5ae"}, + {file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:30bcf80dda7f15ac77ba5af2b961bdd9dbc77fd4ac6105cee85b0d0a5fcf74df"}, + {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26fbfce90728d82bc9e6c38ea4d038cba20b7faf8a0ca53a9c07b67318d46088"}, + {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9190f09060ea4debddd24665d6804b995a9c122ef5917ab26e1566dcc712ceeb"}, + {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d75209eed723105f9596807495d58d10b3470fa6732dd6756595e89925ce2470"}, + {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a51c9751078733d88e013587b108f1b7a1fb106d402fb390740f002b6f6551a"}, + {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:76ae285c8104046b3a7f06b42f29c7b73f77683df18c49ab5af7983994c2dd91"}, + {file = "greenlet-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:2d4686f195e32d36b4d7cf2d166857dbd0ee9f3d20ae349b6bf8afc8485b3645"}, + {file = "greenlet-2.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c4302695ad8027363e96311df24ee28978162cdcdd2006476c43970b384a244c"}, + {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c48f54ef8e05f04d6eff74b8233f6063cb1ed960243eacc474ee73a2ea8573ca"}, + {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1846f1b999e78e13837c93c778dcfc3365902cfb8d1bdb7dd73ead37059f0d0"}, + {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a06ad5312349fec0ab944664b01d26f8d1f05009566339ac6f63f56589bc1a2"}, + {file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:eff4eb9b7eb3e4d0cae3d28c283dc16d9bed6b193c2e1ace3ed86ce48ea8df19"}, + {file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5454276c07d27a740c5892f4907c86327b632127dd9abec42ee62e12427ff7e3"}, + {file = "greenlet-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:7cafd1208fdbe93b67c7086876f061f660cfddc44f404279c1585bbf3cdc64c5"}, + {file = "greenlet-2.0.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:910841381caba4f744a44bf81bfd573c94e10b3045ee00de0cbf436fe50673a6"}, + {file = "greenlet-2.0.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:18a7f18b82b52ee85322d7a7874e676f34ab319b9f8cce5de06067384aa8ff43"}, + {file = "greenlet-2.0.2-cp35-cp35m-win32.whl", hash = "sha256:03a8f4f3430c3b3ff8d10a2a86028c660355ab637cee9333d63d66b56f09d52a"}, + {file = "greenlet-2.0.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4b58adb399c4d61d912c4c331984d60eb66565175cdf4a34792cd9600f21b394"}, + {file = "greenlet-2.0.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:703f18f3fda276b9a916f0934d2fb6d989bf0b4fb5a64825260eb9bfd52d78f0"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:32e5b64b148966d9cccc2c8d35a671409e45f195864560829f395a54226408d3"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dd11f291565a81d71dab10b7033395b7a3a5456e637cf997a6f33ebdf06f8db"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0f72c9ddb8cd28532185f54cc1453f2c16fb417a08b53a855c4e6a418edd099"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd021c754b162c0fb55ad5d6b9d960db667faad0fa2ff25bb6e1301b0b6e6a75"}, + {file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:3c9b12575734155d0c09d6c3e10dbd81665d5c18e1a7c6597df72fd05990c8cf"}, + {file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b9ec052b06a0524f0e35bd8790686a1da006bd911dd1ef7d50b77bfbad74e292"}, + {file = "greenlet-2.0.2-cp36-cp36m-win32.whl", hash = "sha256:dbfcfc0218093a19c252ca8eb9aee3d29cfdcb586df21049b9d777fd32c14fd9"}, + {file = "greenlet-2.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:9f35ec95538f50292f6d8f2c9c9f8a3c6540bbfec21c9e5b4b751e0a7c20864f"}, + {file = "greenlet-2.0.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:d5508f0b173e6aa47273bdc0a0b5ba055b59662ba7c7ee5119528f466585526b"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:f82d4d717d8ef19188687aa32b8363e96062911e63ba22a0cff7802a8e58e5f1"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9c59a2120b55788e800d82dfa99b9e156ff8f2227f07c5e3012a45a399620b7"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2780572ec463d44c1d3ae850239508dbeb9fed38e294c68d19a24d925d9223ca"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:937e9020b514ceedb9c830c55d5c9872abc90f4b5862f89c0887033ae33c6f73"}, + {file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:36abbf031e1c0f79dd5d596bfaf8e921c41df2bdf54ee1eed921ce1f52999a86"}, + {file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:18e98fb3de7dba1c0a852731c3070cf022d14f0d68b4c87a19cc1016f3bb8b33"}, + {file = "greenlet-2.0.2-cp37-cp37m-win32.whl", hash = "sha256:3f6ea9bd35eb450837a3d80e77b517ea5bc56b4647f5502cd28de13675ee12f7"}, + {file = "greenlet-2.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:7492e2b7bd7c9b9916388d9df23fa49d9b88ac0640db0a5b4ecc2b653bf451e3"}, + {file = "greenlet-2.0.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b864ba53912b6c3ab6bcb2beb19f19edd01a6bfcbdfe1f37ddd1778abfe75a30"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ba2956617f1c42598a308a84c6cf021a90ff3862eddafd20c3333d50f0edb45b"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3a569657468b6f3fb60587e48356fe512c1754ca05a564f11366ac9e306526"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8eab883b3b2a38cc1e050819ef06a7e6344d4a990d24d45bc6f2cf959045a45b"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acd2162a36d3de67ee896c43effcd5ee3de247eb00354db411feb025aa319857"}, + {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0bf60faf0bc2468089bdc5edd10555bab6e85152191df713e2ab1fcc86382b5a"}, + {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0ef99cdbe2b682b9ccbb964743a6aca37905fda5e0452e5ee239b1654d37f2a"}, + {file = "greenlet-2.0.2-cp38-cp38-win32.whl", hash = "sha256:b80f600eddddce72320dbbc8e3784d16bd3fb7b517e82476d8da921f27d4b249"}, + {file = "greenlet-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:4d2e11331fc0c02b6e84b0d28ece3a36e0548ee1a1ce9ddde03752d9b79bba40"}, + {file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:88d9ab96491d38a5ab7c56dd7a3cc37d83336ecc564e4e8816dbed12e5aaefc8"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:561091a7be172ab497a3527602d467e2b3fbe75f9e783d8b8ce403fa414f71a6"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:971ce5e14dc5e73715755d0ca2975ac88cfdaefcaab078a284fea6cfabf866df"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be4ed120b52ae4d974aa40215fcdfde9194d63541c7ded40ee12eb4dda57b76b"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94c817e84245513926588caf1152e3b559ff794d505555211ca041f032abbb6b"}, + {file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1a819eef4b0e0b96bb0d98d797bef17dc1b4a10e8d7446be32d1da33e095dbb8"}, + {file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7efde645ca1cc441d6dc4b48c0f7101e8d86b54c8530141b09fd31cef5149ec9"}, + {file = "greenlet-2.0.2-cp39-cp39-win32.whl", hash = "sha256:ea9872c80c132f4663822dd2a08d404073a5a9b5ba6155bea72fb2a79d1093b5"}, + {file = "greenlet-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:db1a39669102a1d8d12b57de2bb7e2ec9066a6f2b3da35ae511ff93b01b5d564"}, + {file = "greenlet-2.0.2.tar.gz", hash = "sha256:e7c8dc13af7db097bed64a051d2dd49e9f0af495c26995c00a9ee842690d34c0"}, +] [package.extras] docs = ["Sphinx", "docutils (<0.18)"] @@ -128,6 +384,10 @@ description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = true python-versions = ">=3.5" +files = [ + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, +] [[package]] name = "imagesize" @@ -136,6 +396,10 @@ description = "Getting image size from png/jpeg/jpeg2000/gif file" category = "main" optional = true python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, + {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, +] [[package]] name = "importlib-metadata" @@ -144,6 +408,10 @@ description = "Read metadata from Python packages" category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "importlib_metadata-6.0.0-py3-none-any.whl", hash = "sha256:7efb448ec9a5e313a57655d35aa54cd3e01b7e1fbcf72dce1bf06119420f5bad"}, + {file = "importlib_metadata-6.0.0.tar.gz", hash = "sha256:e354bedeb60efa6affdcc8ae121b73544a7aa74156d047311948f6d711cd378d"}, +] [package.dependencies] zipp = ">=0.5" @@ -160,6 +428,10 @@ description = "Correctly generate plurals, singular nouns, ordinals, indefinite category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "inflect-6.0.2-py3-none-any.whl", hash = "sha256:182741ec7e9e4c8f7f55b01fa6d80bcd3c4a183d349dfa6d9abbff0a1279e98f"}, + {file = "inflect-6.0.2.tar.gz", hash = "sha256:f1a6bcb0105046f89619fde1a7d044c612c614c2d85ef182582d9dc9b86d309a"}, +] [package.dependencies] pydantic = ">=1.9.1" @@ -168,6 +440,18 @@ pydantic = ">=1.9.1" docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] testing = ["flake8 (<5)", "pygments", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + [[package]] name = "isort" version = "5.12.0" @@ -175,6 +459,10 @@ description = "A Python utility / library to sort Python imports." category = "dev" optional = false python-versions = ">=3.8.0" +files = [ + {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, + {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, +] [package.extras] colors = ["colorama (>=0.4.3)"] @@ -189,6 +477,10 @@ description = "A very fast and expressive template engine." category = "main" optional = true python-versions = ">=3.7" +files = [ + {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, + {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, +] [package.dependencies] MarkupSafe = ">=2.0" @@ -203,783 +495,7 @@ description = "A fast and thorough lazy object proxy." category = "dev" optional = false python-versions = ">=3.7" - -[[package]] -name = "markupsafe" -version = "2.1.2" -description = "Safely add untrusted strings to HTML/XML markup." -category = "main" -optional = true -python-versions = ">=3.7" - -[[package]] -name = "mccabe" -version = "0.7.0" -description = "McCabe checker, plugin for flake8" -category = "dev" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "mimesis" -version = "6.1.1" -description = "Mimesis: Fake Data Generator." -category = "main" -optional = false -python-versions = ">=3.8,<4.0" - -[[package]] -name = "mypy" -version = "0.991" -description = "Optional static typing for Python" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -mypy-extensions = ">=0.4.3" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = ">=3.10" - -[package.extras] -dmypy = ["psutil (>=4.0)"] -install-types = ["pip"] -python2 = ["typed-ast (>=1.4.0,<2)"] -reports = ["lxml"] - -[[package]] -name = "mypy-extensions" -version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." -category = "dev" -optional = false -python-versions = ">=3.5" - -[[package]] -name = "packaging" -version = "23.0" -description = "Core utilities for Python packages" -category = "main" -optional = true -python-versions = ">=3.7" - -[[package]] -name = "pathspec" -version = "0.11.0" -description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "platformdirs" -version = "3.0.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.extras] -docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] - -[[package]] -name = "pockets" -version = "0.9.1" -description = "A collection of helpful Python tools!" -category = "main" -optional = true -python-versions = "*" - -[package.dependencies] -six = ">=1.5.2" - -[[package]] -name = "psycopg2-binary" -version = "2.9.5" -description = "psycopg2 - Python-PostgreSQL Database Adapter" -category = "main" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "pydantic" -version = "1.10.5" -description = "Data validation and settings management using python type hints" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -python-dotenv = {version = ">=0.10.4", optional = true, markers = "extra == \"dotenv\""} -typing-extensions = ">=4.2.0" - -[package.extras] -dotenv = ["python-dotenv (>=0.10.4)"] -email = ["email-validator (>=1.0.3)"] - -[[package]] -name = "pydocstyle" -version = "6.3.0" -description = "Python docstring style checker" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -snowballstemmer = ">=2.2.0" - -[package.extras] -toml = ["tomli (>=1.2.3)"] - -[[package]] -name = "pygments" -version = "2.14.0" -description = "Pygments is a syntax highlighting package written in Python." -category = "main" -optional = true -python-versions = ">=3.6" - -[package.extras] -plugins = ["importlib-metadata"] - -[[package]] -name = "pylint" -version = "2.16.2" -description = "python code static checker" -category = "dev" -optional = false -python-versions = ">=3.7.2" - -[package.dependencies] -astroid = ">=2.14.2,<=2.16.0-dev0" -colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -dill = [ - {version = ">=0.2", markers = "python_version < \"3.11\""}, - {version = ">=0.3.6", markers = "python_version >= \"3.11\""}, -] -isort = ">=4.2.5,<6" -mccabe = ">=0.6,<0.8" -platformdirs = ">=2.2.0" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -tomlkit = ">=0.10.1" -typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} - -[package.extras] -spelling = ["pyenchant (>=3.2,<4.0)"] -testutils = ["gitpython (>3)"] - -[[package]] -name = "python-dotenv" -version = "1.0.0" -description = "Read key-value pairs from a .env file and set them as environment variables" -category = "main" -optional = false -python-versions = ">=3.8" - -[package.extras] -cli = ["click (>=5.0)"] - -[[package]] -name = "pytz" -version = "2022.7.1" -description = "World timezone definitions, modern and historical" -category = "main" -optional = true -python-versions = "*" - -[[package]] -name = "pyyaml" -version = "6.0" -description = "YAML parser and emitter for Python" -category = "main" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "requests" -version = "2.28.2" -description = "Python HTTP for Humans." -category = "main" -optional = true -python-versions = ">=3.7, <4" - -[package.dependencies] -certifi = ">=2017.4.17" -charset-normalizer = ">=2,<4" -idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<1.27" - -[package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] - -[[package]] -name = "setuptools" -version = "67.4.0" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "main" -optional = true -python-versions = ">=3.7" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] - -[[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -category = "main" -optional = true -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" - -[[package]] -name = "snowballstemmer" -version = "2.2.0" -description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." -category = "main" -optional = false -python-versions = "*" - -[[package]] -name = "sphinx" -version = "6.1.3" -description = "Python documentation generator" -category = "main" -optional = true -python-versions = ">=3.8" - -[package.dependencies] -alabaster = ">=0.7,<0.8" -babel = ">=2.9" -colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -docutils = ">=0.18,<0.20" -imagesize = ">=1.3" -importlib-metadata = {version = ">=4.8", markers = "python_version < \"3.10\""} -Jinja2 = ">=3.0" -packaging = ">=21.0" -Pygments = ">=2.13" -requests = ">=2.25.0" -snowballstemmer = ">=2.0" -sphinxcontrib-applehelp = "*" -sphinxcontrib-devhelp = "*" -sphinxcontrib-htmlhelp = ">=2.0.0" -sphinxcontrib-jsmath = "*" -sphinxcontrib-qthelp = "*" -sphinxcontrib-serializinghtml = ">=1.1.5" - -[package.extras] -docs = ["sphinxcontrib-websupport"] -lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-simplify", "isort", "mypy (>=0.990)", "ruff", "sphinx-lint", "types-requests"] -test = ["cython", "html5lib", "pytest (>=4.6)"] - -[[package]] -name = "sphinx-rtd-theme" -version = "1.2.0" -description = "Read the Docs theme for Sphinx" -category = "main" -optional = true -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" - -[package.dependencies] -docutils = "<0.19" -sphinx = ">=1.6,<7" -sphinxcontrib-jquery = {version = ">=2.0.0,<3.0.0 || >3.0.0", markers = "python_version > \"3\""} - -[package.extras] -dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client", "wheel"] - -[[package]] -name = "sphinxcontrib-applehelp" -version = "1.0.4" -description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" -category = "main" -optional = true -python-versions = ">=3.8" - -[package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] -test = ["pytest"] - -[[package]] -name = "sphinxcontrib-devhelp" -version = "1.0.2" -description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." -category = "main" -optional = true -python-versions = ">=3.5" - -[package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] -test = ["pytest"] - -[[package]] -name = "sphinxcontrib-htmlhelp" -version = "2.0.1" -description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" -category = "main" -optional = true -python-versions = ">=3.8" - -[package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] -test = ["html5lib", "pytest"] - -[[package]] -name = "sphinxcontrib-jquery" -version = "2.0.0" -description = "Extension to include jQuery on newer Sphinx releases" -category = "main" -optional = true -python-versions = ">=2.7" - -[package.dependencies] -setuptools = "*" - -[[package]] -name = "sphinxcontrib-jsmath" -version = "1.0.1" -description = "A sphinx extension which renders display math in HTML via JavaScript" -category = "main" -optional = true -python-versions = ">=3.5" - -[package.extras] -test = ["flake8", "mypy", "pytest"] - -[[package]] -name = "sphinxcontrib-napoleon" -version = "0.7" -description = "Sphinx \"napoleon\" extension." -category = "main" -optional = true -python-versions = "*" - -[package.dependencies] -pockets = ">=0.3" -six = ">=1.5.2" - -[[package]] -name = "sphinxcontrib-qthelp" -version = "1.0.3" -description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." -category = "main" -optional = true -python-versions = ">=3.5" - -[package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] -test = ["pytest"] - -[[package]] -name = "sphinxcontrib-serializinghtml" -version = "1.1.5" -description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." -category = "main" -optional = true -python-versions = ">=3.5" - -[package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] -test = ["pytest"] - -[[package]] -name = "sqlacodegen" -version = "3.0.0rc1" -description = "Automatic model code generator for SQLAlchemy" -category = "main" -optional = false -python-versions = ">=3.7" -develop = false - -[package.dependencies] -importlib_metadata = {version = "*", markers = "python_version < \"3.10\""} -inflect = ">=4.0.0" -SQLAlchemy = ">=1.4.0" - -[package.extras] -citext = ["sqlalchemy-citext (>=1.7.0)"] -test = ["mysql-connector-python", "psycopg2-binary", "pytest", "pytest-cov"] - -[package.source] -type = "git" -url = "https://github.com/agronholm/sqlacodegen.git" -reference = "3.0.0rc1" -resolved_reference = "c673bb24446c6ed1401a48fe56a663b0a0616cee" - -[[package]] -name = "sqlalchemy" -version = "1.4.46" -description = "Database Abstraction Library" -category = "main" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" - -[package.dependencies] -greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} - -[package.extras] -aiomysql = ["aiomysql", "greenlet (!=0.4.17)"] -aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] -asyncio = ["greenlet (!=0.4.17)"] -asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"] -mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)"] -mssql = ["pyodbc"] -mssql-pymssql = ["pymssql"] -mssql-pyodbc = ["pyodbc"] -mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"] -mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"] -mysql-connector = ["mysql-connector-python"] -oracle = ["cx_oracle (>=7)", "cx_oracle (>=7,<8)"] -postgresql = ["psycopg2 (>=2.7)"] -postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] -postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] -postgresql-psycopg2binary = ["psycopg2-binary"] -postgresql-psycopg2cffi = ["psycopg2cffi"] -pymysql = ["pymysql", "pymysql (<1)"] -sqlcipher = ["sqlcipher3_binary"] - -[[package]] -name = "sqlalchemy-utils" -version = "0.38.3" -description = "Various utility functions for SQLAlchemy." -category = "main" -optional = false -python-versions = "~=3.6" - -[package.dependencies] -SQLAlchemy = ">=1.3" - -[package.extras] -arrow = ["arrow (>=0.3.4)"] -babel = ["Babel (>=1.3)"] -color = ["colour (>=0.0.4)"] -encrypted = ["cryptography (>=0.6)"] -intervals = ["intervals (>=0.7.1)"] -password = ["passlib (>=1.6,<2.0)"] -pendulum = ["pendulum (>=2.0.5)"] -phone = ["phonenumbers (>=5.9.2)"] -test = ["Jinja2 (>=2.3)", "Pygments (>=1.2)", "backports.zoneinfo", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "isort (>=4.2.2)", "pg8000 (>=1.12.4)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (>=2.7.1)", "python-dateutil (>=2.6)", "pytz (>=2014.2)"] -test-all = ["Babel (>=1.3)", "Jinja2 (>=2.3)", "Pygments (>=1.2)", "arrow (>=0.3.4)", "backports.zoneinfo", "colour (>=0.0.4)", "cryptography (>=0.6)", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "furl (>=0.4.1)", "intervals (>=0.7.1)", "isort (>=4.2.2)", "passlib (>=1.6,<2.0)", "pendulum (>=2.0.5)", "pg8000 (>=1.12.4)", "phonenumbers (>=5.9.2)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (>=2.7.1)", "python-dateutil", "python-dateutil (>=2.6)", "pytz (>=2014.2)"] -timezone = ["python-dateutil"] -url = ["furl (>=0.4.1)"] - -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -category = "dev" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "tomlkit" -version = "0.11.6" -description = "Style preserving TOML library" -category = "dev" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "typer" -version = "0.7.0" -description = "Typer, build great CLIs. Easy to code. Based on Python type hints." -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -click = ">=7.1.1,<9.0.0" - -[package.extras] -all = ["colorama (>=0.4.3,<0.5.0)", "rich (>=10.11.0,<13.0.0)", "shellingham (>=1.3.0,<2.0.0)"] -dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "pre-commit (>=2.17.0,<3.0.0)"] -doc = ["cairosvg (>=2.5.2,<3.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pillow (>=9.3.0,<10.0.0)"] -test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "pytest (>=4.4.0,<8.0.0)", "pytest-cov (>=2.10.0,<5.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "pytest-xdist (>=1.32.0,<4.0.0)", "rich (>=10.11.0,<13.0.0)", "shellingham (>=1.3.0,<2.0.0)"] - -[[package]] -name = "types-pyyaml" -version = "6.0.12.8" -description = "Typing stubs for PyYAML" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "typing-extensions" -version = "4.5.0" -description = "Backported and Experimental Type Hints for Python 3.7+" -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "urllib3" -version = "1.26.14" -description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" -optional = true -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" - -[package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] - -[[package]] -name = "wrapt" -version = "1.15.0" -description = "Module for decorators, wrappers and monkey patching." -category = "dev" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" - -[[package]] -name = "zipp" -version = "3.15.0" -description = "Backport of pathlib-compatible object wrapper for zip files" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] - -[extras] -docs = ["sphinx-rtd-theme", "sphinxcontrib-napoleon"] - -[metadata] -lock-version = "1.1" -python-versions = "^3.9" -content-hash = "27def94a02d8ea26e554b0066b704ea7985e42e309ea83656709765e9ccaecdc" - -[metadata.files] -alabaster = [ - {file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"}, - {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, -] -astroid = [ - {file = "astroid-2.14.2-py3-none-any.whl", hash = "sha256:0e0e3709d64fbffd3037e4ff403580550f14471fd3eaae9fa11cc9a5c7901153"}, - {file = "astroid-2.14.2.tar.gz", hash = "sha256:a3cf9f02c53dd259144a7e8f3ccd75d67c9a8c716ef183e0c1f291bc5d7bb3cf"}, -] -babel = [ - {file = "Babel-2.11.0-py3-none-any.whl", hash = "sha256:1ad3eca1c885218f6dce2ab67291178944f810a10a9b5f3cb8382a5a232b64fe"}, - {file = "Babel-2.11.0.tar.gz", hash = "sha256:5ef4b3226b0180dedded4229651c8b0e1a3a6a2837d45a073272f313e4cf97f6"}, -] -black = [ - {file = "black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"}, - {file = "black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351"}, - {file = "black-22.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f"}, - {file = "black-22.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4"}, - {file = "black-22.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2"}, - {file = "black-22.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350"}, - {file = "black-22.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d"}, - {file = "black-22.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc"}, - {file = "black-22.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320"}, - {file = "black-22.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148"}, - {file = "black-22.12.0-py3-none-any.whl", hash = "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf"}, - {file = "black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f"}, -] -certifi = [ - {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, - {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, -] -charset-normalizer = [ - {file = "charset-normalizer-3.0.1.tar.gz", hash = "sha256:ebea339af930f8ca5d7a699b921106c6e29c617fe9606fa7baa043c1cdae326f"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88600c72ef7587fe1708fd242b385b6ed4b8904976d5da0893e31df8b3480cb6"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c75ffc45f25324e68ab238cb4b5c0a38cd1c3d7f1fb1f72b5541de469e2247db"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db72b07027db150f468fbada4d85b3b2729a3db39178abf5c543b784c1254539"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62595ab75873d50d57323a91dd03e6966eb79c41fa834b7a1661ed043b2d404d"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ff6f3db31555657f3163b15a6b7c6938d08df7adbfc9dd13d9d19edad678f1e8"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:772b87914ff1152b92a197ef4ea40efe27a378606c39446ded52c8f80f79702e"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70990b9c51340e4044cfc394a81f614f3f90d41397104d226f21e66de668730d"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:292d5e8ba896bbfd6334b096e34bffb56161c81408d6d036a7dfa6929cff8783"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2edb64ee7bf1ed524a1da60cdcd2e1f6e2b4f66ef7c077680739f1641f62f555"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:31a9ddf4718d10ae04d9b18801bd776693487cbb57d74cc3458a7673f6f34639"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:44ba614de5361b3e5278e1241fda3dc1838deed864b50a10d7ce92983797fa76"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:12db3b2c533c23ab812c2b25934f60383361f8a376ae272665f8e48b88e8e1c6"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c512accbd6ff0270939b9ac214b84fb5ada5f0409c44298361b2f5e13f9aed9e"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-win32.whl", hash = "sha256:502218f52498a36d6bf5ea77081844017bf7982cdbe521ad85e64cabee1b608b"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:601f36512f9e28f029d9481bdaf8e89e5148ac5d89cffd3b05cd533eeb423b59"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0298eafff88c99982a4cf66ba2efa1128e4ddaca0b05eec4c456bbc7db691d8d"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a8d0fc946c784ff7f7c3742310cc8a57c5c6dc31631269876a88b809dbeff3d3"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:87701167f2a5c930b403e9756fab1d31d4d4da52856143b609e30a1ce7160f3c"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14e76c0f23218b8f46c4d87018ca2e441535aed3632ca134b10239dfb6dadd6b"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c0a590235ccd933d9892c627dec5bc7511ce6ad6c1011fdf5b11363022746c1"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c7fe7afa480e3e82eed58e0ca89f751cd14d767638e2550c77a92a9e749c317"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79909e27e8e4fcc9db4addea88aa63f6423ebb171db091fb4373e3312cb6d603"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ac7b6a045b814cf0c47f3623d21ebd88b3e8cf216a14790b455ea7ff0135d18"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:72966d1b297c741541ca8cf1223ff262a6febe52481af742036a0b296e35fa5a"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f9d0c5c045a3ca9bedfc35dca8526798eb91a07aa7a2c0fee134c6c6f321cbd7"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5995f0164fa7df59db4746112fec3f49c461dd6b31b841873443bdb077c13cfc"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4a8fcf28c05c1f6d7e177a9a46a1c52798bfe2ad80681d275b10dcf317deaf0b"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:761e8904c07ad053d285670f36dd94e1b6ab7f16ce62b9805c475b7aa1cffde6"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-win32.whl", hash = "sha256:71140351489970dfe5e60fc621ada3e0f41104a5eddaca47a7acb3c1b851d6d3"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:9ab77acb98eba3fd2a85cd160851816bfce6871d944d885febf012713f06659c"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:84c3990934bae40ea69a82034912ffe5a62c60bbf6ec5bc9691419641d7d5c9a"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74292fc76c905c0ef095fe11e188a32ebd03bc38f3f3e9bcb85e4e6db177b7ea"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c95a03c79bbe30eec3ec2b7f076074f4281526724c8685a42872974ef4d36b72"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c39b0e3eac288fedc2b43055cfc2ca7a60362d0e5e87a637beac5d801ef478"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df2c707231459e8a4028eabcd3cfc827befd635b3ef72eada84ab13b52e1574d"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93ad6d87ac18e2a90b0fe89df7c65263b9a99a0eb98f0a3d2e079f12a0735837"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:59e5686dd847347e55dffcc191a96622f016bc0ad89105e24c14e0d6305acbc6"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:cd6056167405314a4dc3c173943f11249fa0f1b204f8b51ed4bde1a9cd1834dc"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:083c8d17153ecb403e5e1eb76a7ef4babfc2c48d58899c98fcaa04833e7a2f9a"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:f5057856d21e7586765171eac8b9fc3f7d44ef39425f85dbcccb13b3ebea806c"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:7eb33a30d75562222b64f569c642ff3dc6689e09adda43a082208397f016c39a"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-win32.whl", hash = "sha256:95dea361dd73757c6f1c0a1480ac499952c16ac83f7f5f4f84f0658a01b8ef41"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:eaa379fcd227ca235d04152ca6704c7cb55564116f8bc52545ff357628e10602"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3e45867f1f2ab0711d60c6c71746ac53537f1684baa699f4f668d4c6f6ce8e14"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cadaeaba78750d58d3cc6ac4d1fd867da6fc73c88156b7a3212a3cd4819d679d"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:911d8a40b2bef5b8bbae2e36a0b103f142ac53557ab421dc16ac4aafee6f53dc"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:503e65837c71b875ecdd733877d852adbc465bd82c768a067badd953bf1bc5a3"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a60332922359f920193b1d4826953c507a877b523b2395ad7bc716ddd386d866"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16a8663d6e281208d78806dbe14ee9903715361cf81f6d4309944e4d1e59ac5b"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a16418ecf1329f71df119e8a65f3aa68004a3f9383821edcb20f0702934d8087"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9d9153257a3f70d5f69edf2325357251ed20f772b12e593f3b3377b5f78e7ef8"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:02a51034802cbf38db3f89c66fb5d2ec57e6fe7ef2f4a44d070a593c3688667b"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:2e396d70bc4ef5325b72b593a72c8979999aa52fb8bcf03f701c1b03e1166918"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:11b53acf2411c3b09e6af37e4b9005cba376c872503c8f28218c7243582df45d"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-win32.whl", hash = "sha256:0bf2dae5291758b6f84cf923bfaa285632816007db0330002fa1de38bfcb7154"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:2c03cc56021a4bd59be889c2b9257dae13bf55041a3372d3295416f86b295fb5"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:024e606be3ed92216e2b6952ed859d86b4cfa52cd5bc5f050e7dc28f9b43ec42"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4b0d02d7102dd0f997580b51edc4cebcf2ab6397a7edf89f1c73b586c614272c"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:358a7c4cb8ba9b46c453b1dd8d9e431452d5249072e4f56cfda3149f6ab1405e"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81d6741ab457d14fdedc215516665050f3822d3e56508921cc7239f8c8e66a58"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8b8af03d2e37866d023ad0ddea594edefc31e827fee64f8de5611a1dbc373174"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9cf4e8ad252f7c38dd1f676b46514f92dc0ebeb0db5552f5f403509705e24753"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e696f0dd336161fca9adbb846875d40752e6eba585843c768935ba5c9960722b"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c22d3fe05ce11d3671297dc8973267daa0f938b93ec716e12e0f6dee81591dc1"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:109487860ef6a328f3eec66f2bf78b0b72400280d8f8ea05f69c51644ba6521a"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:37f8febc8ec50c14f3ec9637505f28e58d4f66752207ea177c1d67df25da5aed"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:f97e83fa6c25693c7a35de154681fcc257c1c41b38beb0304b9c4d2d9e164479"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a152f5f33d64a6be73f1d30c9cc82dfc73cec6477ec268e7c6e4c7d23c2d2291"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:39049da0ffb96c8cbb65cbf5c5f3ca3168990adf3551bd1dee10c48fce8ae820"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-win32.whl", hash = "sha256:4457ea6774b5611f4bed5eaa5df55f70abde42364d498c5134b7ef4c6958e20e"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:e62164b50f84e20601c1ff8eb55620d2ad25fb81b59e3cd776a1902527a788af"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8eade758719add78ec36dc13201483f8e9b5d940329285edcd5f70c0a9edbd7f"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8499ca8f4502af841f68135133d8258f7b32a53a1d594aa98cc52013fff55678"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3fc1c4a2ffd64890aebdb3f97e1278b0cc72579a08ca4de8cd2c04799a3a22be"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00d3ffdaafe92a5dc603cb9bd5111aaa36dfa187c8285c543be562e61b755f6b"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2ac1b08635a8cd4e0cbeaf6f5e922085908d48eb05d44c5ae9eabab148512ca"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6f45710b4459401609ebebdbcfb34515da4fc2aa886f95107f556ac69a9147e"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ae1de54a77dc0d6d5fcf623290af4266412a7c4be0b1ff7444394f03f5c54e3"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b590df687e3c5ee0deef9fc8c547d81986d9a1b56073d82de008744452d6541"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab5de034a886f616a5668aa5d098af2b5385ed70142090e2a31bcbd0af0fdb3d"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9cb3032517f1627cc012dbc80a8ec976ae76d93ea2b5feaa9d2a5b8882597579"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:608862a7bf6957f2333fc54ab4399e405baad0163dc9f8d99cb236816db169d4"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0f438ae3532723fb6ead77e7c604be7c8374094ef4ee2c5e03a3a17f1fca256c"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:356541bf4381fa35856dafa6a965916e54bed415ad8a24ee6de6e37deccf2786"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-win32.whl", hash = "sha256:39cf9ed17fe3b1bc81f33c9ceb6ce67683ee7526e65fde1447c772afc54a1bb8"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:0a11e971ed097d24c534c037d298ad32c6ce81a45736d31e0ff0ad37ab437d59"}, - {file = "charset_normalizer-3.0.1-py3-none-any.whl", hash = "sha256:7e189e2e1d3ed2f4aebabd2d5b0f931e883676e51c7624826e0a4e5fe8a0bf24"}, -] -click = [ - {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, - {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, -] -colorama = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] -dill = [ - {file = "dill-0.3.6-py3-none-any.whl", hash = "sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0"}, - {file = "dill-0.3.6.tar.gz", hash = "sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373"}, -] -docutils = [ - {file = "docutils-0.18.1-py2.py3-none-any.whl", hash = "sha256:23010f129180089fbcd3bc08cfefccb3b890b0050e1ca00c867036e9d161b98c"}, - {file = "docutils-0.18.1.tar.gz", hash = "sha256:679987caf361a7539d76e584cbeddc311e3aee937877c87346f31debc63e9d06"}, -] -greenlet = [ - {file = "greenlet-2.0.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:bdfea8c661e80d3c1c99ad7c3ff74e6e87184895bbaca6ee8cc61209f8b9b85d"}, - {file = "greenlet-2.0.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:9d14b83fab60d5e8abe587d51c75b252bcc21683f24699ada8fb275d7712f5a9"}, - {file = "greenlet-2.0.2-cp27-cp27m-win32.whl", hash = "sha256:6c3acb79b0bfd4fe733dff8bc62695283b57949ebcca05ae5c129eb606ff2d74"}, - {file = "greenlet-2.0.2-cp27-cp27m-win_amd64.whl", hash = "sha256:283737e0da3f08bd637b5ad058507e578dd462db259f7f6e4c5c365ba4ee9343"}, - {file = "greenlet-2.0.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d27ec7509b9c18b6d73f2f5ede2622441de812e7b1a80bbd446cb0633bd3d5ae"}, - {file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:30bcf80dda7f15ac77ba5af2b961bdd9dbc77fd4ac6105cee85b0d0a5fcf74df"}, - {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26fbfce90728d82bc9e6c38ea4d038cba20b7faf8a0ca53a9c07b67318d46088"}, - {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9190f09060ea4debddd24665d6804b995a9c122ef5917ab26e1566dcc712ceeb"}, - {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d75209eed723105f9596807495d58d10b3470fa6732dd6756595e89925ce2470"}, - {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a51c9751078733d88e013587b108f1b7a1fb106d402fb390740f002b6f6551a"}, - {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:76ae285c8104046b3a7f06b42f29c7b73f77683df18c49ab5af7983994c2dd91"}, - {file = "greenlet-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:2d4686f195e32d36b4d7cf2d166857dbd0ee9f3d20ae349b6bf8afc8485b3645"}, - {file = "greenlet-2.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c4302695ad8027363e96311df24ee28978162cdcdd2006476c43970b384a244c"}, - {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c48f54ef8e05f04d6eff74b8233f6063cb1ed960243eacc474ee73a2ea8573ca"}, - {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1846f1b999e78e13837c93c778dcfc3365902cfb8d1bdb7dd73ead37059f0d0"}, - {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a06ad5312349fec0ab944664b01d26f8d1f05009566339ac6f63f56589bc1a2"}, - {file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:eff4eb9b7eb3e4d0cae3d28c283dc16d9bed6b193c2e1ace3ed86ce48ea8df19"}, - {file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5454276c07d27a740c5892f4907c86327b632127dd9abec42ee62e12427ff7e3"}, - {file = "greenlet-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:7cafd1208fdbe93b67c7086876f061f660cfddc44f404279c1585bbf3cdc64c5"}, - {file = "greenlet-2.0.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:910841381caba4f744a44bf81bfd573c94e10b3045ee00de0cbf436fe50673a6"}, - {file = "greenlet-2.0.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:18a7f18b82b52ee85322d7a7874e676f34ab319b9f8cce5de06067384aa8ff43"}, - {file = "greenlet-2.0.2-cp35-cp35m-win32.whl", hash = "sha256:03a8f4f3430c3b3ff8d10a2a86028c660355ab637cee9333d63d66b56f09d52a"}, - {file = "greenlet-2.0.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4b58adb399c4d61d912c4c331984d60eb66565175cdf4a34792cd9600f21b394"}, - {file = "greenlet-2.0.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:703f18f3fda276b9a916f0934d2fb6d989bf0b4fb5a64825260eb9bfd52d78f0"}, - {file = "greenlet-2.0.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:32e5b64b148966d9cccc2c8d35a671409e45f195864560829f395a54226408d3"}, - {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dd11f291565a81d71dab10b7033395b7a3a5456e637cf997a6f33ebdf06f8db"}, - {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0f72c9ddb8cd28532185f54cc1453f2c16fb417a08b53a855c4e6a418edd099"}, - {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd021c754b162c0fb55ad5d6b9d960db667faad0fa2ff25bb6e1301b0b6e6a75"}, - {file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:3c9b12575734155d0c09d6c3e10dbd81665d5c18e1a7c6597df72fd05990c8cf"}, - {file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b9ec052b06a0524f0e35bd8790686a1da006bd911dd1ef7d50b77bfbad74e292"}, - {file = "greenlet-2.0.2-cp36-cp36m-win32.whl", hash = "sha256:dbfcfc0218093a19c252ca8eb9aee3d29cfdcb586df21049b9d777fd32c14fd9"}, - {file = "greenlet-2.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:9f35ec95538f50292f6d8f2c9c9f8a3c6540bbfec21c9e5b4b751e0a7c20864f"}, - {file = "greenlet-2.0.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:d5508f0b173e6aa47273bdc0a0b5ba055b59662ba7c7ee5119528f466585526b"}, - {file = "greenlet-2.0.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:f82d4d717d8ef19188687aa32b8363e96062911e63ba22a0cff7802a8e58e5f1"}, - {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9c59a2120b55788e800d82dfa99b9e156ff8f2227f07c5e3012a45a399620b7"}, - {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2780572ec463d44c1d3ae850239508dbeb9fed38e294c68d19a24d925d9223ca"}, - {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:937e9020b514ceedb9c830c55d5c9872abc90f4b5862f89c0887033ae33c6f73"}, - {file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:36abbf031e1c0f79dd5d596bfaf8e921c41df2bdf54ee1eed921ce1f52999a86"}, - {file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:18e98fb3de7dba1c0a852731c3070cf022d14f0d68b4c87a19cc1016f3bb8b33"}, - {file = "greenlet-2.0.2-cp37-cp37m-win32.whl", hash = "sha256:3f6ea9bd35eb450837a3d80e77b517ea5bc56b4647f5502cd28de13675ee12f7"}, - {file = "greenlet-2.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:7492e2b7bd7c9b9916388d9df23fa49d9b88ac0640db0a5b4ecc2b653bf451e3"}, - {file = "greenlet-2.0.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b864ba53912b6c3ab6bcb2beb19f19edd01a6bfcbdfe1f37ddd1778abfe75a30"}, - {file = "greenlet-2.0.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ba2956617f1c42598a308a84c6cf021a90ff3862eddafd20c3333d50f0edb45b"}, - {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3a569657468b6f3fb60587e48356fe512c1754ca05a564f11366ac9e306526"}, - {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8eab883b3b2a38cc1e050819ef06a7e6344d4a990d24d45bc6f2cf959045a45b"}, - {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acd2162a36d3de67ee896c43effcd5ee3de247eb00354db411feb025aa319857"}, - {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0bf60faf0bc2468089bdc5edd10555bab6e85152191df713e2ab1fcc86382b5a"}, - {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0ef99cdbe2b682b9ccbb964743a6aca37905fda5e0452e5ee239b1654d37f2a"}, - {file = "greenlet-2.0.2-cp38-cp38-win32.whl", hash = "sha256:b80f600eddddce72320dbbc8e3784d16bd3fb7b517e82476d8da921f27d4b249"}, - {file = "greenlet-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:4d2e11331fc0c02b6e84b0d28ece3a36e0548ee1a1ce9ddde03752d9b79bba40"}, - {file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:88d9ab96491d38a5ab7c56dd7a3cc37d83336ecc564e4e8816dbed12e5aaefc8"}, - {file = "greenlet-2.0.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:561091a7be172ab497a3527602d467e2b3fbe75f9e783d8b8ce403fa414f71a6"}, - {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:971ce5e14dc5e73715755d0ca2975ac88cfdaefcaab078a284fea6cfabf866df"}, - {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be4ed120b52ae4d974aa40215fcdfde9194d63541c7ded40ee12eb4dda57b76b"}, - {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94c817e84245513926588caf1152e3b559ff794d505555211ca041f032abbb6b"}, - {file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1a819eef4b0e0b96bb0d98d797bef17dc1b4a10e8d7446be32d1da33e095dbb8"}, - {file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7efde645ca1cc441d6dc4b48c0f7101e8d86b54c8530141b09fd31cef5149ec9"}, - {file = "greenlet-2.0.2-cp39-cp39-win32.whl", hash = "sha256:ea9872c80c132f4663822dd2a08d404073a5a9b5ba6155bea72fb2a79d1093b5"}, - {file = "greenlet-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:db1a39669102a1d8d12b57de2bb7e2ec9066a6f2b3da35ae511ff93b01b5d564"}, - {file = "greenlet-2.0.2.tar.gz", hash = "sha256:e7c8dc13af7db097bed64a051d2dd49e9f0af495c26995c00a9ee842690d34c0"}, -] -idna = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, -] -imagesize = [ - {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, - {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, -] -importlib-metadata = [ - {file = "importlib_metadata-6.0.0-py3-none-any.whl", hash = "sha256:7efb448ec9a5e313a57655d35aa54cd3e01b7e1fbcf72dce1bf06119420f5bad"}, - {file = "importlib_metadata-6.0.0.tar.gz", hash = "sha256:e354bedeb60efa6affdcc8ae121b73544a7aa74156d047311948f6d711cd378d"}, -] -inflect = [ - {file = "inflect-6.0.2-py3-none-any.whl", hash = "sha256:182741ec7e9e4c8f7f55b01fa6d80bcd3c4a183d349dfa6d9abbff0a1279e98f"}, - {file = "inflect-6.0.2.tar.gz", hash = "sha256:f1a6bcb0105046f89619fde1a7d044c612c614c2d85ef182582d9dc9b86d309a"}, -] -isort = [ - {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, - {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, -] -jinja2 = [ - {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, - {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, -] -lazy-object-proxy = [ +files = [ {file = "lazy-object-proxy-1.9.0.tar.gz", hash = "sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae"}, {file = "lazy_object_proxy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7"}, {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4"}, @@ -1017,7 +533,15 @@ lazy-object-proxy = [ {file = "lazy_object_proxy-1.9.0-cp39-cp39-win32.whl", hash = "sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821"}, {file = "lazy_object_proxy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f"}, ] -markupsafe = [ + +[[package]] +name = "markupsafe" +version = "2.1.2" +description = "Safely add untrusted strings to HTML/XML markup." +category = "main" +optional = true +python-versions = ">=3.7" +files = [ {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:665a36ae6f8f20a4676b53224e33d456a6f5a72657d9c83c2aa00765072f31f7"}, {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:340bea174e9761308703ae988e982005aedf427de816d1afe98147668cc03036"}, {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22152d00bf4a9c7c83960521fc558f55a1adbc0631fbb00a9471e097b19d72e1"}, @@ -1069,15 +593,39 @@ markupsafe = [ {file = "MarkupSafe-2.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed"}, {file = "MarkupSafe-2.1.2.tar.gz", hash = "sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d"}, ] -mccabe = [ + +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, ] -mimesis = [ + +[[package]] +name = "mimesis" +version = "6.1.1" +description = "Mimesis: Fake Data Generator." +category = "main" +optional = false +python-versions = ">=3.8,<4.0" +files = [ {file = "mimesis-6.1.1-py3-none-any.whl", hash = "sha256:eabe41d7afa23b01dffb51ebd9e10837df6417fef02fa9841989ca886e479790"}, {file = "mimesis-6.1.1.tar.gz", hash = "sha256:044ac378c61db0e06832ff722548fd6e604881d36bc938002e0bd5b85eeb6a98"}, ] -mypy = [ + +[[package]] +name = "mypy" +version = "0.991" +description = "Optional static typing for Python" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ {file = "mypy-0.991-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7d17e0a9707d0772f4a7b878f04b4fd11f6f5bcb9b3813975a9b13c9332153ab"}, {file = "mypy-0.991-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0714258640194d75677e86c786e80ccf294972cc76885d3ebbb560f11db0003d"}, {file = "mypy-0.991-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c8f3be99e8a8bd403caa8c03be619544bc2c77a7093685dcf308c6b109426c6"}, @@ -1109,27 +657,222 @@ mypy = [ {file = "mypy-0.991-py3-none-any.whl", hash = "sha256:de32edc9b0a7e67c2775e574cb061a537660e51210fbf6006b0b36ea695ae9bb"}, {file = "mypy-0.991.tar.gz", hash = "sha256:3c0165ba8f354a6d9881809ef29f1a9318a236a6d81c690094c5df32107bde06"}, ] -mypy-extensions = [ + +[package.dependencies] +mypy-extensions = ">=0.4.3" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = ">=3.10" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +install-types = ["pip"] +python2 = ["typed-ast (>=1.4.0,<2)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +category = "dev" +optional = false +python-versions = ">=3.5" +files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] -packaging = [ + +[[package]] +name = "numpy" +version = "1.24.2" +description = "Fundamental package for array computing in Python" +category = "main" +optional = false +python-versions = ">=3.8" +files = [ + {file = "numpy-1.24.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eef70b4fc1e872ebddc38cddacc87c19a3709c0e3e5d20bf3954c147b1dd941d"}, + {file = "numpy-1.24.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8d2859428712785e8a8b7d2b3ef0a1d1565892367b32f915c4a4df44d0e64f5"}, + {file = "numpy-1.24.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6524630f71631be2dabe0c541e7675db82651eb998496bbe16bc4f77f0772253"}, + {file = "numpy-1.24.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a51725a815a6188c662fb66fb32077709a9ca38053f0274640293a14fdd22978"}, + {file = "numpy-1.24.2-cp310-cp310-win32.whl", hash = "sha256:2620e8592136e073bd12ee4536149380695fbe9ebeae845b81237f986479ffc9"}, + {file = "numpy-1.24.2-cp310-cp310-win_amd64.whl", hash = "sha256:97cf27e51fa078078c649a51d7ade3c92d9e709ba2bfb97493007103c741f1d0"}, + {file = "numpy-1.24.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7de8fdde0003f4294655aa5d5f0a89c26b9f22c0a58790c38fae1ed392d44a5a"}, + {file = "numpy-1.24.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4173bde9fa2a005c2c6e2ea8ac1618e2ed2c1c6ec8a7657237854d42094123a0"}, + {file = "numpy-1.24.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cecaed30dc14123020f77b03601559fff3e6cd0c048f8b5289f4eeabb0eb281"}, + {file = "numpy-1.24.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a23f8440561a633204a67fb44617ce2a299beecf3295f0d13c495518908e910"}, + {file = "numpy-1.24.2-cp311-cp311-win32.whl", hash = "sha256:e428c4fbfa085f947b536706a2fc349245d7baa8334f0c5723c56a10595f9b95"}, + {file = "numpy-1.24.2-cp311-cp311-win_amd64.whl", hash = "sha256:557d42778a6869c2162deb40ad82612645e21d79e11c1dc62c6e82a2220ffb04"}, + {file = "numpy-1.24.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d0a2db9d20117bf523dde15858398e7c0858aadca7c0f088ac0d6edd360e9ad2"}, + {file = "numpy-1.24.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c72a6b2f4af1adfe193f7beb91ddf708ff867a3f977ef2ec53c0ffb8283ab9f5"}, + {file = "numpy-1.24.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c29e6bd0ec49a44d7690ecb623a8eac5ab8a923bce0bea6293953992edf3a76a"}, + {file = "numpy-1.24.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2eabd64ddb96a1239791da78fa5f4e1693ae2dadc82a76bc76a14cbb2b966e96"}, + {file = "numpy-1.24.2-cp38-cp38-win32.whl", hash = "sha256:e3ab5d32784e843fc0dd3ab6dcafc67ef806e6b6828dc6af2f689be0eb4d781d"}, + {file = "numpy-1.24.2-cp38-cp38-win_amd64.whl", hash = "sha256:76807b4063f0002c8532cfeac47a3068a69561e9c8715efdad3c642eb27c0756"}, + {file = "numpy-1.24.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4199e7cfc307a778f72d293372736223e39ec9ac096ff0a2e64853b866a8e18a"}, + {file = "numpy-1.24.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:adbdce121896fd3a17a77ab0b0b5eedf05a9834a18699db6829a64e1dfccca7f"}, + {file = "numpy-1.24.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:889b2cc88b837d86eda1b17008ebeb679d82875022200c6e8e4ce6cf549b7acb"}, + {file = "numpy-1.24.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f64bb98ac59b3ea3bf74b02f13836eb2e24e48e0ab0145bbda646295769bd780"}, + {file = "numpy-1.24.2-cp39-cp39-win32.whl", hash = "sha256:63e45511ee4d9d976637d11e6c9864eae50e12dc9598f531c035265991910468"}, + {file = "numpy-1.24.2-cp39-cp39-win_amd64.whl", hash = "sha256:a77d3e1163a7770164404607b7ba3967fb49b24782a6ef85d9b5f54126cc39e5"}, + {file = "numpy-1.24.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:92011118955724465fb6853def593cf397b4a1367495e0b59a7e69d40c4eb71d"}, + {file = "numpy-1.24.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9006288bcf4895917d02583cf3411f98631275bc67cce355a7f39f8c14338fa"}, + {file = "numpy-1.24.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:150947adbdfeceec4e5926d956a06865c1c690f2fd902efede4ca6fe2e657c3f"}, + {file = "numpy-1.24.2.tar.gz", hash = "sha256:003a9f530e880cb2cd177cba1af7220b9aa42def9c4afc2a2fc3ee6be7eb2b22"}, +] + +[[package]] +name = "opendp" +version = "0.6.2" +description = "Python bindings for the OpenDP Library" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "opendp-0.6.2-py3-none-any.whl", hash = "sha256:d15e66ef0c0d86b35548bcc176a593bc645f8208ba594ce7c24afa38ba5045aa"}, +] + +[[package]] +name = "packaging" +version = "23.0" +description = "Core utilities for Python packages" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, ] -pathspec = [ + +[[package]] +name = "pandas" +version = "1.5.3" +description = "Powerful data structures for data analysis, time series, and statistics" +category = "main" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3749077d86e3a2f0ed51367f30bf5b82e131cc0f14260c4d3e499186fccc4406"}, + {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:972d8a45395f2a2d26733eb8d0f629b2f90bebe8e8eddbb8829b180c09639572"}, + {file = "pandas-1.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:50869a35cbb0f2e0cd5ec04b191e7b12ed688874bd05dd777c19b28cbea90996"}, + {file = "pandas-1.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3ac844a0fe00bfaeb2c9b51ab1424e5c8744f89860b138434a363b1f620f354"}, + {file = "pandas-1.5.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a0a56cef15fd1586726dace5616db75ebcfec9179a3a55e78f72c5639fa2a23"}, + {file = "pandas-1.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:478ff646ca42b20376e4ed3fa2e8d7341e8a63105586efe54fa2508ee087f328"}, + {file = "pandas-1.5.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6973549c01ca91ec96199e940495219c887ea815b2083722821f1d7abfa2b4dc"}, + {file = "pandas-1.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c39a8da13cede5adcd3be1182883aea1c925476f4e84b2807a46e2775306305d"}, + {file = "pandas-1.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f76d097d12c82a535fda9dfe5e8dd4127952b45fea9b0276cb30cca5ea313fbc"}, + {file = "pandas-1.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e474390e60ed609cec869b0da796ad94f420bb057d86784191eefc62b65819ae"}, + {file = "pandas-1.5.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f2b952406a1588ad4cad5b3f55f520e82e902388a6d5a4a91baa8d38d23c7f6"}, + {file = "pandas-1.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:bc4c368f42b551bf72fac35c5128963a171b40dce866fb066540eeaf46faa003"}, + {file = "pandas-1.5.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:14e45300521902689a81f3f41386dc86f19b8ba8dd5ac5a3c7010ef8d2932813"}, + {file = "pandas-1.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9842b6f4b8479e41968eced654487258ed81df7d1c9b7b870ceea24ed9459b31"}, + {file = "pandas-1.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:26d9c71772c7afb9d5046e6e9cf42d83dd147b5cf5bcb9d97252077118543792"}, + {file = "pandas-1.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fbcb19d6fceb9e946b3e23258757c7b225ba450990d9ed63ccceeb8cae609f7"}, + {file = "pandas-1.5.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:565fa34a5434d38e9d250af3c12ff931abaf88050551d9fbcdfafca50d62babf"}, + {file = "pandas-1.5.3-cp38-cp38-win32.whl", hash = "sha256:87bd9c03da1ac870a6d2c8902a0e1fd4267ca00f13bc494c9e5a9020920e1d51"}, + {file = "pandas-1.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:41179ce559943d83a9b4bbacb736b04c928b095b5f25dd2b7389eda08f46f373"}, + {file = "pandas-1.5.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c74a62747864ed568f5a82a49a23a8d7fe171d0c69038b38cedf0976831296fa"}, + {file = "pandas-1.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c4c00e0b0597c8e4f59e8d461f797e5d70b4d025880516a8261b2817c47759ee"}, + {file = "pandas-1.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a50d9a4336a9621cab7b8eb3fb11adb82de58f9b91d84c2cd526576b881a0c5a"}, + {file = "pandas-1.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd05f7783b3274aa206a1af06f0ceed3f9b412cf665b7247eacd83be41cf7bf0"}, + {file = "pandas-1.5.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f69c4029613de47816b1bb30ff5ac778686688751a5e9c99ad8c7031f6508e5"}, + {file = "pandas-1.5.3-cp39-cp39-win32.whl", hash = "sha256:7cec0bee9f294e5de5bbfc14d0573f65526071029d036b753ee6507d2a21480a"}, + {file = "pandas-1.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:dfd681c5dc216037e0b0a2c821f5ed99ba9f03ebcf119c7dac0e9a7b960b9ec9"}, + {file = "pandas-1.5.3.tar.gz", hash = "sha256:74a3fd7e5a7ec052f183273dc7b0acd3a863edf7520f5d3a1765c04ffdb3b0b1"}, +] + +[package.dependencies] +numpy = [ + {version = ">=1.20.3", markers = "python_version < \"3.10\""}, + {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, +] +python-dateutil = ">=2.8.1" +pytz = ">=2020.1" + +[package.extras] +test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] + +[[package]] +name = "pandasql" +version = "0.7.3" +description = "sqldf for pandas" +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "pandasql-0.7.3.tar.gz", hash = "sha256:1eb248869086435a7d85281ebd9fe525d69d9d954a0dceb854f71a8d0fd8de69"}, +] + +[package.dependencies] +numpy = "*" +pandas = "*" +sqlalchemy = "*" + +[[package]] +name = "pathspec" +version = "0.11.0" +description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ {file = "pathspec-0.11.0-py3-none-any.whl", hash = "sha256:3a66eb970cbac598f9e5ccb5b2cf58930cd8e3ed86d393d541eaf2d8b1705229"}, {file = "pathspec-0.11.0.tar.gz", hash = "sha256:64d338d4e0914e91c1792321e6907b5a593f1ab1851de7fc269557a21b30ebbc"}, ] -platformdirs = [ + +[[package]] +name = "platformdirs" +version = "3.0.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ {file = "platformdirs-3.0.0-py3-none-any.whl", hash = "sha256:b1d5eb14f221506f50d6604a561f4c5786d9e80355219694a1b244bcd96f4567"}, {file = "platformdirs-3.0.0.tar.gz", hash = "sha256:8a1228abb1ef82d788f74139988b137e78692984ec7b08eaa6c65f1723af28f9"}, ] -pockets = [ + +[package.extras] +docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] + +[[package]] +name = "pluggy" +version = "1.0.0" +description = "plugin and hook calling mechanisms for python" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, + {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pockets" +version = "0.9.1" +description = "A collection of helpful Python tools!" +category = "main" +optional = true +python-versions = "*" +files = [ {file = "pockets-0.9.1-py2.py3-none-any.whl", hash = "sha256:68597934193c08a08eb2bf6a1d85593f627c22f9b065cc727a4f03f669d96d86"}, {file = "pockets-0.9.1.tar.gz", hash = "sha256:9320f1a3c6f7a9133fe3b571f283bcf3353cd70249025ae8d618e40e9f7e92b3"}, ] -psycopg2-binary = [ + +[package.dependencies] +six = ">=1.5.2" + +[[package]] +name = "psycopg2-binary" +version = "2.9.5" +description = "psycopg2 - Python-PostgreSQL Database Adapter" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ {file = "psycopg2-binary-2.9.5.tar.gz", hash = "sha256:33e632d0885b95a8b97165899006c40e9ecdc634a529dca7b991eb7de4ece41c"}, {file = "psycopg2_binary-2.9.5-cp310-cp310-macosx_10_15_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:0775d6252ccb22b15da3b5d7adbbf8cfe284916b14b6dc0ff503a23edb01ee85"}, {file = "psycopg2_binary-2.9.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2ec46ed947801652c9643e0b1dc334cfb2781232e375ba97312c2fc256597632"}, @@ -1202,7 +945,15 @@ psycopg2-binary = [ {file = "psycopg2_binary-2.9.5-cp39-cp39-win32.whl", hash = "sha256:937880290775033a743f4836aa253087b85e62784b63fd099ee725d567a48aa1"}, {file = "psycopg2_binary-2.9.5-cp39-cp39-win_amd64.whl", hash = "sha256:484405b883630f3e74ed32041a87456c5e0e63a8e3429aa93e8714c366d62bd1"}, ] -pydantic = [ + +[[package]] +name = "pydantic" +version = "1.10.5" +description = "Data validation and settings management using python type hints" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ {file = "pydantic-1.10.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5920824fe1e21cbb3e38cf0f3dd24857c8959801d1031ce1fac1d50857a03bfb"}, {file = "pydantic-1.10.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3bb99cf9655b377db1a9e47fa4479e3330ea96f4123c6c8200e482704bf1eda2"}, {file = "pydantic-1.10.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2185a3b3d98ab4506a3f6707569802d2d92c3a7ba3a9a35683a7709ea6c2aaa2"}, @@ -1240,126 +991,478 @@ pydantic = [ {file = "pydantic-1.10.5-py3-none-any.whl", hash = "sha256:7c5b94d598c90f2f46b3a983ffb46ab806a67099d118ae0da7ef21a2a4033b28"}, {file = "pydantic-1.10.5.tar.gz", hash = "sha256:9e337ac83686645a46db0e825acceea8e02fca4062483f40e9ae178e8bd1103a"}, ] -pydocstyle = [ + +[package.dependencies] +python-dotenv = {version = ">=0.10.4", optional = true, markers = "extra == \"dotenv\""} +typing-extensions = ">=4.2.0" + +[package.extras] +dotenv = ["python-dotenv (>=0.10.4)"] +email = ["email-validator (>=1.0.3)"] + +[[package]] +name = "pydocstyle" +version = "6.3.0" +description = "Python docstring style checker" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ {file = "pydocstyle-6.3.0-py3-none-any.whl", hash = "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019"}, {file = "pydocstyle-6.3.0.tar.gz", hash = "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1"}, ] -pygments = [ + +[package.dependencies] +snowballstemmer = ">=2.2.0" + +[package.extras] +toml = ["tomli (>=1.2.3)"] + +[[package]] +name = "pygments" +version = "2.14.0" +description = "Pygments is a syntax highlighting package written in Python." +category = "main" +optional = true +python-versions = ">=3.6" +files = [ {file = "Pygments-2.14.0-py3-none-any.whl", hash = "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717"}, {file = "Pygments-2.14.0.tar.gz", hash = "sha256:b3ed06a9e8ac9a9aae5a6f5dbe78a8a58655d17b43b93c078f094ddc476ae297"}, ] -pylint = [ + +[package.extras] +plugins = ["importlib-metadata"] + +[[package]] +name = "pylint" +version = "2.16.2" +description = "python code static checker" +category = "dev" +optional = false +python-versions = ">=3.7.2" +files = [ {file = "pylint-2.16.2-py3-none-any.whl", hash = "sha256:ff22dde9c2128cd257c145cfd51adeff0be7df4d80d669055f24a962b351bbe4"}, {file = "pylint-2.16.2.tar.gz", hash = "sha256:13b2c805a404a9bf57d002cd5f054ca4d40b0b87542bdaba5e05321ae8262c84"}, ] -python-dotenv = [ + +[package.dependencies] +astroid = ">=2.14.2,<=2.16.0-dev0" +colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} +dill = {version = ">=0.2", markers = "python_version < \"3.11\""} +isort = ">=4.2.5,<6" +mccabe = ">=0.6,<0.8" +platformdirs = ">=2.2.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +tomlkit = ">=0.10.1" +typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} + +[package.extras] +spelling = ["pyenchant (>=3.2,<4.0)"] +testutils = ["gitpython (>3)"] + +[[package]] +name = "pytest" +version = "7.2.1" +description = "pytest: simple powerful testing with Python" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.2.1-py3-none-any.whl", hash = "sha256:c7c6ca206e93355074ae32f7403e8ea12163b1163c976fee7d4d84027c162be5"}, + {file = "pytest-7.2.1.tar.gz", hash = "sha256:d45e0952f3727241918b8fd0f376f5ff6b301cc0777c6f9a556935c92d8a7d42"}, +] + +[package.dependencies] +attrs = ">=19.2.0" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "python-dotenv" +version = "1.0.0" +description = "Read key-value pairs from a .env file and set them as environment variables" +category = "main" +optional = false +python-versions = ">=3.8" +files = [ {file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"}, {file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"}, ] -pytz = [ + +[package.extras] +cli = ["click (>=5.0)"] + +[[package]] +name = "pytz" +version = "2022.7.1" +description = "World timezone definitions, modern and historical" +category = "main" +optional = false +python-versions = "*" +files = [ {file = "pytz-2022.7.1-py2.py3-none-any.whl", hash = "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a"}, {file = "pytz-2022.7.1.tar.gz", hash = "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0"}, ] -pyyaml = [ - {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, - {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, - {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, - {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, - {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, - {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, - {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, - {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, - {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, - {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, - {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, - {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, - {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, - {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, - {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, - {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, - {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, - {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, -] -requests = [ + +[[package]] +name = "pyyaml" +version = "5.4.1" +description = "YAML parser and emitter for Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ + {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"}, + {file = "PyYAML-5.4.1-cp27-cp27m-win32.whl", hash = "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393"}, + {file = "PyYAML-5.4.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8"}, + {file = "PyYAML-5.4.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185"}, + {file = "PyYAML-5.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541"}, + {file = "PyYAML-5.4.1-cp36-cp36m-win32.whl", hash = "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5"}, + {file = "PyYAML-5.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df"}, + {file = "PyYAML-5.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"}, + {file = "PyYAML-5.4.1-cp37-cp37m-win32.whl", hash = "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b"}, + {file = "PyYAML-5.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf"}, + {file = "PyYAML-5.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc"}, + {file = "PyYAML-5.4.1-cp38-cp38-win32.whl", hash = "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"}, + {file = "PyYAML-5.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696"}, + {file = "PyYAML-5.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6"}, + {file = "PyYAML-5.4.1-cp39-cp39-win32.whl", hash = "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10"}, + {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, + {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, +] + +[[package]] +name = "requests" +version = "2.28.2" +description = "Python HTTP for Humans." +category = "main" +optional = true +python-versions = ">=3.7, <4" +files = [ {file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"}, {file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"}, ] -setuptools = [ + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<1.27" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "setuptools" +version = "67.4.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +category = "main" +optional = true +python-versions = ">=3.7" +files = [ {file = "setuptools-67.4.0-py3-none-any.whl", hash = "sha256:f106dee1b506dee5102cc3f3e9e68137bbad6d47b616be7991714b0c62204251"}, {file = "setuptools-67.4.0.tar.gz", hash = "sha256:e5fd0a713141a4a105412233c63dc4e17ba0090c8e8334594ac790ec97792330"}, ] -six = [ + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] -snowballstemmer = [ + +[[package]] +name = "smartnoise-sql" +version = "0.2.9.1" +description = "Differentially Private SQL Queries" +category = "main" +optional = false +python-versions = ">=3.7,<3.11" +files = [ + {file = "smartnoise-sql-0.2.9.1.tar.gz", hash = "sha256:e5507b75e9186d914a0b64d8a50c0355e7586263414293cc63160e528d686b6a"}, + {file = "smartnoise_sql-0.2.9.1-py3-none-any.whl", hash = "sha256:4ddc310a9cc13873ac31ca909b1059fd7d504892bdd297ae18609c65764063fc"}, +] + +[package.dependencies] +antlr4-python3-runtime = "4.9.3" +graphviz = ">=0.17,<0.18" +opendp = ">=0.6.0,<0.7.0" +pandasql = ">=0.7.3,<0.8.0" +PyYAML = ">=5.4.1,<6.0.0" +sqlalchemy = ">=1.4.23,<2.0.0" + +[[package]] +name = "snowballstemmer" +version = "2.2.0" +description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." +category = "main" +optional = false +python-versions = "*" +files = [ {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, ] -sphinx = [ + +[[package]] +name = "sphinx" +version = "6.1.3" +description = "Python documentation generator" +category = "main" +optional = true +python-versions = ">=3.8" +files = [ {file = "Sphinx-6.1.3.tar.gz", hash = "sha256:0dac3b698538ffef41716cf97ba26c1c7788dba73ce6f150c1ff5b4720786dd2"}, {file = "sphinx-6.1.3-py3-none-any.whl", hash = "sha256:807d1cb3d6be87eb78a381c3e70ebd8d346b9a25f3753e9947e866b2786865fc"}, ] -sphinx-rtd-theme = [ + +[package.dependencies] +alabaster = ">=0.7,<0.8" +babel = ">=2.9" +colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} +docutils = ">=0.18,<0.20" +imagesize = ">=1.3" +importlib-metadata = {version = ">=4.8", markers = "python_version < \"3.10\""} +Jinja2 = ">=3.0" +packaging = ">=21.0" +Pygments = ">=2.13" +requests = ">=2.25.0" +snowballstemmer = ">=2.0" +sphinxcontrib-applehelp = "*" +sphinxcontrib-devhelp = "*" +sphinxcontrib-htmlhelp = ">=2.0.0" +sphinxcontrib-jsmath = "*" +sphinxcontrib-qthelp = "*" +sphinxcontrib-serializinghtml = ">=1.1.5" + +[package.extras] +docs = ["sphinxcontrib-websupport"] +lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-simplify", "isort", "mypy (>=0.990)", "ruff", "sphinx-lint", "types-requests"] +test = ["cython", "html5lib", "pytest (>=4.6)"] + +[[package]] +name = "sphinx-rtd-theme" +version = "1.2.0" +description = "Read the Docs theme for Sphinx" +category = "main" +optional = true +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +files = [ {file = "sphinx_rtd_theme-1.2.0-py2.py3-none-any.whl", hash = "sha256:f823f7e71890abe0ac6aaa6013361ea2696fc8d3e1fa798f463e82bdb77eeff2"}, {file = "sphinx_rtd_theme-1.2.0.tar.gz", hash = "sha256:a0d8bd1a2ed52e0b338cbe19c4b2eef3c5e7a048769753dac6a9f059c7b641b8"}, ] -sphinxcontrib-applehelp = [ + +[package.dependencies] +docutils = "<0.19" +sphinx = ">=1.6,<7" +sphinxcontrib-jquery = {version = ">=2.0.0,<3.0.0 || >3.0.0", markers = "python_version > \"3\""} + +[package.extras] +dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client", "wheel"] + +[[package]] +name = "sphinxcontrib-applehelp" +version = "1.0.4" +description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" +category = "main" +optional = true +python-versions = ">=3.8" +files = [ {file = "sphinxcontrib-applehelp-1.0.4.tar.gz", hash = "sha256:828f867945bbe39817c210a1abfd1bc4895c8b73fcaade56d45357a348a07d7e"}, {file = "sphinxcontrib_applehelp-1.0.4-py3-none-any.whl", hash = "sha256:29d341f67fb0f6f586b23ad80e072c8e6ad0b48417db2bde114a4c9746feb228"}, ] -sphinxcontrib-devhelp = [ + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "1.0.2" +description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." +category = "main" +optional = true +python-versions = ">=3.5" +files = [ {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"}, {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, ] -sphinxcontrib-htmlhelp = [ + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "2.0.1" +description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" +category = "main" +optional = true +python-versions = ">=3.8" +files = [ {file = "sphinxcontrib-htmlhelp-2.0.1.tar.gz", hash = "sha256:0cbdd302815330058422b98a113195c9249825d681e18f11e8b1f78a2f11efff"}, {file = "sphinxcontrib_htmlhelp-2.0.1-py3-none-any.whl", hash = "sha256:c38cb46dccf316c79de6e5515e1770414b797162b23cd3d06e67020e1d2a6903"}, ] -sphinxcontrib-jquery = [ + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["html5lib", "pytest"] + +[[package]] +name = "sphinxcontrib-jquery" +version = "2.0.0" +description = "Extension to include jQuery on newer Sphinx releases" +category = "main" +optional = true +python-versions = ">=2.7" +files = [ {file = "sphinxcontrib-jquery-2.0.0.tar.gz", hash = "sha256:8fb65f6dba84bf7bcd1aea1f02ab3955ac34611d838bcc95d4983b805b234daa"}, {file = "sphinxcontrib_jquery-2.0.0-py3-none-any.whl", hash = "sha256:ed47fa425c338ffebe3c37e1cdb56e30eb806116b85f01055b158c7057fdb995"}, ] -sphinxcontrib-jsmath = [ + +[package.dependencies] +setuptools = "*" + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +description = "A sphinx extension which renders display math in HTML via JavaScript" +category = "main" +optional = true +python-versions = ">=3.5" +files = [ {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, ] -sphinxcontrib-napoleon = [ + +[package.extras] +test = ["flake8", "mypy", "pytest"] + +[[package]] +name = "sphinxcontrib-napoleon" +version = "0.7" +description = "Sphinx \"napoleon\" extension." +category = "main" +optional = true +python-versions = "*" +files = [ {file = "sphinxcontrib-napoleon-0.7.tar.gz", hash = "sha256:407382beed396e9f2d7f3043fad6afda95719204a1e1a231ac865f40abcbfcf8"}, {file = "sphinxcontrib_napoleon-0.7-py2.py3-none-any.whl", hash = "sha256:711e41a3974bdf110a484aec4c1a556799eb0b3f3b897521a018ad7e2db13fef"}, ] -sphinxcontrib-qthelp = [ + +[package.dependencies] +pockets = ">=0.3" +six = ">=1.5.2" + +[[package]] +name = "sphinxcontrib-qthelp" +version = "1.0.3" +description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." +category = "main" +optional = true +python-versions = ">=3.5" +files = [ {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, ] -sphinxcontrib-serializinghtml = [ + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "1.1.5" +description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." +category = "main" +optional = true +python-versions = ">=3.5" +files = [ {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"}, {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"}, ] -sqlacodegen = [] -sqlalchemy = [ + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "sqlacodegen" +version = "3.0.0rc1" +description = "Automatic model code generator for SQLAlchemy" +category = "main" +optional = false +python-versions = ">=3.7" +files = [] +develop = false + +[package.dependencies] +importlib_metadata = {version = "*", markers = "python_version < \"3.10\""} +inflect = ">=4.0.0" +SQLAlchemy = ">=1.4.0" + +[package.extras] +citext = ["sqlalchemy-citext (>=1.7.0)"] +test = ["mysql-connector-python", "psycopg2-binary", "pytest", "pytest-cov"] + +[package.source] +type = "git" +url = "https://github.com/agronholm/sqlacodegen.git" +reference = "3.0.0rc1" +resolved_reference = "c673bb24446c6ed1401a48fe56a663b0a0616cee" + +[[package]] +name = "sqlalchemy" +version = "1.4.46" +description = "Database Abstraction Library" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +files = [ {file = "SQLAlchemy-1.4.46-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:7001f16a9a8e06488c3c7154827c48455d1c1507d7228d43e781afbc8ceccf6d"}, {file = "SQLAlchemy-1.4.46-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c7a46639ba058d320c9f53a81db38119a74b8a7a1884df44d09fbe807d028aaf"}, {file = "SQLAlchemy-1.4.46-cp27-cp27m-win32.whl", hash = "sha256:c04144a24103135ea0315d459431ac196fe96f55d3213bfd6d39d0247775c854"}, @@ -1402,35 +1505,154 @@ sqlalchemy = [ {file = "SQLAlchemy-1.4.46-cp39-cp39-win_amd64.whl", hash = "sha256:315676344e3558f1f80d02535f410e80ea4e8fddba31ec78fe390eff5fb8f466"}, {file = "SQLAlchemy-1.4.46.tar.gz", hash = "sha256:6913b8247d8a292ef8315162a51931e2b40ce91681f1b6f18f697045200c4a30"}, ] -sqlalchemy-utils = [ + +[package.dependencies] +greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} + +[package.extras] +aiomysql = ["aiomysql", "greenlet (!=0.4.17)"] +aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing-extensions (!=3.10.0.1)"] +asyncio = ["greenlet (!=0.4.17)"] +asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)"] +mssql = ["pyodbc"] +mssql-pymssql = ["pymssql"] +mssql-pyodbc = ["pyodbc"] +mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"] +mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"] +mysql-connector = ["mysql-connector-python"] +oracle = ["cx-oracle (>=7)", "cx-oracle (>=7,<8)"] +postgresql = ["psycopg2 (>=2.7)"] +postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] +postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] +postgresql-psycopg2binary = ["psycopg2-binary"] +postgresql-psycopg2cffi = ["psycopg2cffi"] +pymysql = ["pymysql", "pymysql (<1)"] +sqlcipher = ["sqlcipher3-binary"] + +[[package]] +name = "sqlalchemy-utils" +version = "0.38.3" +description = "Various utility functions for SQLAlchemy." +category = "main" +optional = false +python-versions = "~=3.6" +files = [ {file = "SQLAlchemy-Utils-0.38.3.tar.gz", hash = "sha256:9f9afba607a40455cf703adfa9846584bf26168a0c5a60a70063b70d65051f4d"}, {file = "SQLAlchemy_Utils-0.38.3-py3-none-any.whl", hash = "sha256:5c13b5d08adfaa85f3d4e8ec09a75136216fad41346980d02974a70a77988bf9"}, ] -tomli = [ + +[package.dependencies] +SQLAlchemy = ">=1.3" + +[package.extras] +arrow = ["arrow (>=0.3.4)"] +babel = ["Babel (>=1.3)"] +color = ["colour (>=0.0.4)"] +encrypted = ["cryptography (>=0.6)"] +intervals = ["intervals (>=0.7.1)"] +password = ["passlib (>=1.6,<2.0)"] +pendulum = ["pendulum (>=2.0.5)"] +phone = ["phonenumbers (>=5.9.2)"] +test = ["Jinja2 (>=2.3)", "Pygments (>=1.2)", "backports.zoneinfo", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "isort (>=4.2.2)", "pg8000 (>=1.12.4)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (>=2.7.1)", "python-dateutil (>=2.6)", "pytz (>=2014.2)"] +test-all = ["Babel (>=1.3)", "Jinja2 (>=2.3)", "Pygments (>=1.2)", "arrow (>=0.3.4)", "backports.zoneinfo", "colour (>=0.0.4)", "cryptography (>=0.6)", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "furl (>=0.4.1)", "intervals (>=0.7.1)", "isort (>=4.2.2)", "passlib (>=1.6,<2.0)", "pendulum (>=2.0.5)", "pg8000 (>=1.12.4)", "phonenumbers (>=5.9.2)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (>=2.7.1)", "python-dateutil", "python-dateutil (>=2.6)", "pytz (>=2014.2)"] +timezone = ["python-dateutil"] +url = ["furl (>=0.4.1)"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] -tomlkit = [ + +[[package]] +name = "tomlkit" +version = "0.11.6" +description = "Style preserving TOML library" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ {file = "tomlkit-0.11.6-py3-none-any.whl", hash = "sha256:07de26b0d8cfc18f871aec595fda24d95b08fef89d147caa861939f37230bf4b"}, {file = "tomlkit-0.11.6.tar.gz", hash = "sha256:71b952e5721688937fb02cf9d354dbcf0785066149d2855e44531ebdd2b65d73"}, ] -typer = [ + +[[package]] +name = "typer" +version = "0.7.0" +description = "Typer, build great CLIs. Easy to code. Based on Python type hints." +category = "main" +optional = false +python-versions = ">=3.6" +files = [ {file = "typer-0.7.0-py3-none-any.whl", hash = "sha256:b5e704f4e48ec263de1c0b3a2387cd405a13767d2f907f44c1a08cbad96f606d"}, {file = "typer-0.7.0.tar.gz", hash = "sha256:ff797846578a9f2a201b53442aedeb543319466870fbe1c701eab66dd7681165"}, ] -types-pyyaml = [ + +[package.dependencies] +click = ">=7.1.1,<9.0.0" + +[package.extras] +all = ["colorama (>=0.4.3,<0.5.0)", "rich (>=10.11.0,<13.0.0)", "shellingham (>=1.3.0,<2.0.0)"] +dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "pre-commit (>=2.17.0,<3.0.0)"] +doc = ["cairosvg (>=2.5.2,<3.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pillow (>=9.3.0,<10.0.0)"] +test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "pytest (>=4.4.0,<8.0.0)", "pytest-cov (>=2.10.0,<5.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "pytest-xdist (>=1.32.0,<4.0.0)", "rich (>=10.11.0,<13.0.0)", "shellingham (>=1.3.0,<2.0.0)"] + +[[package]] +name = "types-pyyaml" +version = "6.0.12.8" +description = "Typing stubs for PyYAML" +category = "dev" +optional = false +python-versions = "*" +files = [ {file = "types-PyYAML-6.0.12.8.tar.gz", hash = "sha256:19304869a89d49af00be681e7b267414df213f4eb89634c4495fa62e8f942b9f"}, {file = "types_PyYAML-6.0.12.8-py3-none-any.whl", hash = "sha256:5314a4b2580999b2ea06b2e5f9a7763d860d6e09cdf21c0e9561daa9cbd60178"}, ] -typing-extensions = [ + +[[package]] +name = "typing-extensions" +version = "4.5.0" +description = "Backported and Experimental Type Hints for Python 3.7+" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ {file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"}, {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"}, ] -urllib3 = [ + +[[package]] +name = "urllib3" +version = "1.26.14" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = true +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ {file = "urllib3-1.26.14-py2.py3-none-any.whl", hash = "sha256:75edcdc2f7d85b137124a6c3c9fc3933cdeaa12ecb9a6a959f22797a0feca7e1"}, {file = "urllib3-1.26.14.tar.gz", hash = "sha256:076907bf8fd355cde77728471316625a4d2f7e713c125f51953bb5b3eecf4f72"}, ] -wrapt = [ + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[[package]] +name = "wrapt" +version = "1.15.0" +description = "Module for decorators, wrappers and monkey patching." +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +files = [ {file = "wrapt-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ca1cccf838cd28d5a0883b342474c630ac48cac5df0ee6eacc9c7290f76b11c1"}, {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e826aadda3cae59295b95343db8f3d965fb31059da7de01ee8d1c40a60398b29"}, {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5fc8e02f5984a55d2c653f5fea93531e9836abbd84342c1d1e17abc4a15084c2"}, @@ -1507,7 +1729,27 @@ wrapt = [ {file = "wrapt-1.15.0-py3-none-any.whl", hash = "sha256:64b1df0f83706b4ef4cfb4fb0e4c2669100fd7ecacfb59e091fad300d4e04640"}, {file = "wrapt-1.15.0.tar.gz", hash = "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a"}, ] -zipp = [ + +[[package]] +name = "zipp" +version = "3.15.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, ] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] + +[extras] +docs = ["sphinx-rtd-theme", "sphinxcontrib-napoleon"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.9,<3.11" +content-hash = "a378fa7da462a6a05ecadc2af896393c7b0cd7ff2f3ebe224d660ff3e1e07a8f" diff --git a/pyproject.toml b/pyproject.toml index 8c2e3605..327302f0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,17 +7,18 @@ license = "MIT" readme = "README.md" [tool.poetry.dependencies] -python = "^3.9" +python = "^3.9,<3.11" sqlacodegen = {git = "https://github.com/agronholm/sqlacodegen.git", rev = "3.0.0rc1"} pydantic = {extras = ["dotenv"], version = "^1.10.2"} psycopg2-binary = "^2.9.5" sqlalchemy-utils = "^0.38.3" mimesis = "^6.1.1" typer = "^0.7.0" -pyyaml = "^6.0" +pyyaml = "^5.0" sqlalchemy = "^1.4" sphinx-rtd-theme = {version = "^1.2.0", optional = true} sphinxcontrib-napoleon = {version = "^0.7", optional = true} +smartnoise-sql = "^0.2.9.1" [tool.poetry.group.dev.dependencies] black = "^22.10.0" @@ -26,6 +27,7 @@ pylint = "^2.15.8" mypy = "^0.991" types-pyyaml = "^6.0.12.4" pydocstyle = "^6.3.0" +pytest = "^7.2.0" [tool.poetry.extras] docs = ["sphinx-rtd-theme", "sphinxcontrib-napoleon"] diff --git a/sqlsynthgen/main.py b/sqlsynthgen/main.py index 7aebf3fe..80555e35 100644 --- a/sqlsynthgen/main.py +++ b/sqlsynthgen/main.py @@ -7,12 +7,17 @@ import typer from sqlsynthgen.create import create_db_data, create_db_tables, create_db_vocab -from sqlsynthgen.make import make_generators_from_tables, make_tables_file +from sqlsynthgen.make import ( + make_generators_from_tables, + make_src_stats, + make_tables_file, +) from sqlsynthgen.settings import get_settings from sqlsynthgen.utils import import_file, read_yaml_file ORM_FILENAME: Final[str] = "orm.py" SSG_FILENAME: Final[str] = "ssg.py" +STATS_FILENAME: Final[str] = "src-stats.yaml" app = typer.Typer() @@ -92,7 +97,8 @@ def create_tables(orm_file: str = typer.Option(ORM_FILENAME)) -> None: def make_generators( orm_file: str = typer.Option(ORM_FILENAME), ssg_file: str = typer.Option(SSG_FILENAME), - config_file: Optional[str] = typer.Argument(None), + config_file: Optional[str] = typer.Option(None), + stats_file: Optional[str] = typer.Option(None), ) -> None: """Make a SQLSynthGen file of generator classes. @@ -115,11 +121,29 @@ def make_generators( orm_module = import_file(orm_file) generator_config = read_yaml_file(config_file) if config_file is not None else {} - result = make_generators_from_tables(orm_module, generator_config) + result = make_generators_from_tables(orm_module, generator_config, stats_file) ssg_file_path.write_text(result, encoding="utf-8") +@app.command() +def make_stats( + config_file: str = typer.Option(None), + stats_file: str = typer.Option(STATS_FILENAME), +) -> None: + """Compute summary statistics from the source database, write them to a YAML file. + + Example: + $ sqlsynthgen make_stats --config-file=generator_conf.yaml + """ + settings = get_settings() + generator_config = read_yaml_file(config_file) if config_file is not None else {} + src_dsn = settings.src_postgres_dsn + if src_dsn is None: + raise ValueError("Missing source database connection details.") + make_src_stats(src_dsn, generator_config, stats_file) + + @app.command() def make_tables( orm_file: str = typer.Option(ORM_FILENAME), diff --git a/sqlsynthgen/make.py b/sqlsynthgen/make.py index d4335be5..03476703 100644 --- a/sqlsynthgen/make.py +++ b/sqlsynthgen/make.py @@ -4,9 +4,12 @@ from subprocess import CalledProcessError, run from sys import stderr from types import ModuleType -from typing import Any, Final, Optional +from typing import Any, Final, Optional, Union +import snsql +import yaml from mimesis.providers.base import BaseProvider +from pydantic import PostgresDsn # pylint: disable=no-name-in-module from sqlalchemy import create_engine from sqlalchemy.sql import sqltypes @@ -135,7 +138,7 @@ def _add_generator_for_table( def make_generators_from_tables( - tables_module: ModuleType, generator_config: dict + tables_module: ModuleType, generator_config: dict, src_stats_filename: Optional[str] ) -> str: """Create sqlsynthgen generator classes from a sqlacodegen-generated file. @@ -151,6 +154,14 @@ def make_generators_from_tables( generator_module_name = generator_config.get("custom_generators_module", None) if generator_module_name is not None: new_content += f"\nimport {generator_module_name}" + if src_stats_filename: + new_content += "\nimport yaml" + new_content += ( + f'\nwith open("{src_stats_filename}", "r", encoding="utf-8") as f:' + ) + new_content += ( + f"\n{INDENTATION}SRC_STATS = yaml.load(f, Loader=yaml.FullLoader)" + ) sorted_generators = "[\n" sorted_vocab = "[\n" @@ -190,7 +201,9 @@ def make_generators_from_tables( return new_content -def make_tables_file(db_dsn: str, schema_name: Optional[str]) -> str: +def make_tables_file( + db_dsn: Union[PostgresDsn, str], schema_name: Optional[str] +) -> str: """Write a file with the SQLAlchemy ORM classes. Exists with an error if sqlacodegen is unsuccessful. @@ -219,3 +232,41 @@ def make_tables_file(db_dsn: str, schema_name: Optional[str]) -> str: ) return completed_process.stdout + + +def make_src_stats( + dsn: Union[PostgresDsn, str], config: dict, stats_filename: str +) -> dict: + """Run the src-stats queries specified by the configuration. + + Query the src database with the queries in the src-stats block of the `config` + dictionary, using the differential privacy parameters set in the `opendp` block of + `config`. Record the results in a dictionary and return it, but also write them to a + YAML file called `stats_filename`. + + Args: + dsn: postgres connection string + config: a dictionary with the necessary configuration + stats_filename: path to the YAML file to write the output to + + Returns: + The dictionary of src-stats, thats is also written to `stats_filename`. + """ + engine = create_engine(dsn, echo=False, future=True) + dp_config = config.get("opendp", {}) + snsql_metadata = {"": dp_config} + src_stats = {} + for stat_data in config.get("src-stats", []): + privacy = snsql.Privacy(epsilon=stat_data["epsilon"], delta=stat_data["delta"]) + with engine.connect() as conn: + reader = snsql.from_connection( + conn.connection, + engine="postgres", + privacy=privacy, + metadata=snsql_metadata, + ) + private_result = reader.execute(stat_data["query"]) + src_stats[stat_data["name"]] = private_result[1:] + with open(stats_filename, "w", encoding="utf-8") as f: + yaml.dump(src_stats, f) + return src_stats diff --git a/tests/examples/example_stats.yaml b/tests/examples/example_stats.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/tests/examples/example_stats.yaml @@ -0,0 +1 @@ +{} diff --git a/tests/examples/expected_ssg.py b/tests/examples/expected_ssg.py index f98be8b8..976a67eb 100644 --- a/tests/examples/expected_ssg.py +++ b/tests/examples/expected_ssg.py @@ -18,6 +18,9 @@ import tests.examples.example_orm import custom_generators +import yaml +with open("tests/examples/example_stats.yaml", "r", encoding="utf-8") as f: + SRC_STATS = yaml.load(f, Loader=yaml.FullLoader) concept_vocab = FileUploader(tests.examples.example_orm.Concept.__table__) @@ -34,9 +37,9 @@ class personGenerator: def __init__(self, src_db_conn, dst_db_conn): self.name = generic.person.full_name() self.stored_from = generic.datetime.datetime(start=2022, end=2022) + self.research_opt_out = custom_generators.boolean_from_src_stats_generator(src_stats=SRC_STATS.count_opt_outs) pass self.nhs_number = generic.text.color() - self.research_opt_out = generic.development.boolean() self.source_system = generic.text.color() diff --git a/tests/examples/generator_conf.yaml b/tests/examples/generator_conf.yaml index 26ec28a2..7d75848f 100644 --- a/tests/examples/generator_conf.yaml +++ b/tests/examples/generator_conf.yaml @@ -1,3 +1,19 @@ +opendp: + public: + person: + person_id: + name: person_id + type: int + private_id: True + research_opt_out: + name: research_opt_out + type: boolean + private_id: False +src-stats: + - name: count_opt_outs + query: SELECT count(*) AS num, research_opt_out FROM person GROUP BY research_opt_out + epsilon: 1.0 + delta: 0.1 custom_generators_module: custom_generators tables: person: @@ -11,6 +27,10 @@ tables: start: 2022 end: 2022 columns_assigned: stored_from + - name: custom_generators.boolean_from_src_stats_generator + args: + src_stats: SRC_STATS.count_opt_outs + columns_assigned: research_opt_out hospital_visit: num_rows_per_pass: 3 diff --git a/tests/examples/src.dump b/tests/examples/src.dump index 5be992fb..c3df525a 100644 --- a/tests/examples/src.dump +++ b/tests/examples/src.dump @@ -105,3 +105,1006 @@ insert into public.concept values (1, 'some concept name'); -- -- PostgreSQL database dump complete -- + +-- Manual addition of some made up data, to have something to run src-stats on. +INSERT INTO public.person (person_id, name, research_opt_out, stored_from) VALUES +(1, 'Randy Random', False, '2023-03-01'), +(2, 'Randy Random', True, '2023-03-01'), +(3, 'Randy Random', True, '2023-03-01'), +(4, 'Randy Random', False, '2023-03-01'), +(5, 'Randy Random', True, '2023-03-01'), +(6, 'Randy Random', False, '2023-03-01'), +(7, 'Randy Random', False, '2023-03-01'), +(8, 'Randy Random', False, '2023-03-01'), +(9, 'Randy Random', False, '2023-03-01'), +(10, 'Randy Random', True, '2023-03-01'), +(11, 'Randy Random', False, '2023-03-01'), +(12, 'Randy Random', False, '2023-03-01'), +(13, 'Randy Random', True, '2023-03-01'), +(14, 'Randy Random', False, '2023-03-01'), +(15, 'Randy Random', True, '2023-03-01'), +(16, 'Randy Random', True, '2023-03-01'), +(17, 'Randy Random', True, '2023-03-01'), +(18, 'Randy Random', False, '2023-03-01'), +(19, 'Randy Random', False, '2023-03-01'), +(20, 'Randy Random', False, '2023-03-01'), +(21, 'Randy Random', True, '2023-03-01'), +(22, 'Randy Random', True, '2023-03-01'), +(23, 'Randy Random', False, '2023-03-01'), +(24, 'Randy Random', False, '2023-03-01'), +(25, 'Randy Random', True, '2023-03-01'), +(26, 'Randy Random', True, '2023-03-01'), +(27, 'Randy Random', False, '2023-03-01'), +(28, 'Randy Random', False, '2023-03-01'), +(29, 'Randy Random', False, '2023-03-01'), +(30, 'Randy Random', True, '2023-03-01'), +(31, 'Randy Random', True, '2023-03-01'), +(32, 'Randy Random', False, '2023-03-01'), +(33, 'Randy Random', True, '2023-03-01'), +(34, 'Randy Random', False, '2023-03-01'), +(35, 'Randy Random', True, '2023-03-01'), +(36, 'Randy Random', True, '2023-03-01'), +(37, 'Randy Random', True, '2023-03-01'), +(38, 'Randy Random', True, '2023-03-01'), +(39, 'Randy Random', True, '2023-03-01'), +(40, 'Randy Random', False, '2023-03-01'), +(41, 'Randy Random', False, '2023-03-01'), +(42, 'Randy Random', True, '2023-03-01'), +(43, 'Randy Random', False, '2023-03-01'), +(44, 'Randy Random', False, '2023-03-01'), +(45, 'Randy Random', True, '2023-03-01'), +(46, 'Randy Random', False, '2023-03-01'), +(47, 'Randy Random', False, '2023-03-01'), +(48, 'Randy Random', True, '2023-03-01'), +(49, 'Randy Random', False, '2023-03-01'), +(50, 'Randy Random', False, '2023-03-01'), +(51, 'Randy Random', False, '2023-03-01'), +(52, 'Randy Random', False, '2023-03-01'), +(53, 'Randy Random', False, '2023-03-01'), +(54, 'Randy Random', False, '2023-03-01'), +(55, 'Randy Random', False, '2023-03-01'), +(56, 'Randy Random', True, '2023-03-01'), +(57, 'Randy Random', False, '2023-03-01'), +(58, 'Randy Random', True, '2023-03-01'), +(59, 'Randy Random', False, '2023-03-01'), +(60, 'Randy Random', False, '2023-03-01'), +(61, 'Randy Random', True, '2023-03-01'), +(62, 'Randy Random', True, '2023-03-01'), +(63, 'Randy Random', True, '2023-03-01'), +(64, 'Randy Random', False, '2023-03-01'), +(65, 'Randy Random', True, '2023-03-01'), +(66, 'Randy Random', True, '2023-03-01'), +(67, 'Randy Random', True, '2023-03-01'), +(68, 'Randy Random', True, '2023-03-01'), +(69, 'Randy Random', True, '2023-03-01'), +(70, 'Randy Random', True, '2023-03-01'), +(71, 'Randy Random', True, '2023-03-01'), +(72, 'Randy Random', True, '2023-03-01'), +(73, 'Randy Random', True, '2023-03-01'), +(74, 'Randy Random', True, '2023-03-01'), +(75, 'Randy Random', True, '2023-03-01'), +(76, 'Randy Random', False, '2023-03-01'), +(77, 'Randy Random', False, '2023-03-01'), +(78, 'Randy Random', True, '2023-03-01'), +(79, 'Randy Random', False, '2023-03-01'), +(80, 'Randy Random', True, '2023-03-01'), +(81, 'Randy Random', True, '2023-03-01'), +(82, 'Randy Random', False, '2023-03-01'), +(83, 'Randy Random', True, '2023-03-01'), +(84, 'Randy Random', False, '2023-03-01'), +(85, 'Randy Random', True, '2023-03-01'), +(86, 'Randy Random', False, '2023-03-01'), +(87, 'Randy Random', True, '2023-03-01'), +(88, 'Randy Random', True, '2023-03-01'), +(89, 'Randy Random', True, '2023-03-01'), +(90, 'Randy Random', False, '2023-03-01'), +(91, 'Randy Random', True, '2023-03-01'), +(92, 'Randy Random', True, '2023-03-01'), +(93, 'Randy Random', False, '2023-03-01'), +(94, 'Randy Random', True, '2023-03-01'), +(95, 'Randy Random', False, '2023-03-01'), +(96, 'Randy Random', False, '2023-03-01'), +(97, 'Randy Random', True, '2023-03-01'), +(98, 'Randy Random', True, '2023-03-01'), +(99, 'Randy Random', True, '2023-03-01'), +(100, 'Randy Random', False, '2023-03-01'), +(101, 'Randy Random', True, '2023-03-01'), +(102, 'Randy Random', True, '2023-03-01'), +(103, 'Randy Random', True, '2023-03-01'), +(104, 'Randy Random', True, '2023-03-01'), +(105, 'Randy Random', False, '2023-03-01'), +(106, 'Randy Random', False, '2023-03-01'), +(107, 'Randy Random', True, '2023-03-01'), +(108, 'Randy Random', True, '2023-03-01'), +(109, 'Randy Random', True, '2023-03-01'), +(110, 'Randy Random', True, '2023-03-01'), +(111, 'Randy Random', False, '2023-03-01'), +(112, 'Randy Random', True, '2023-03-01'), +(113, 'Randy Random', False, '2023-03-01'), +(114, 'Randy Random', True, '2023-03-01'), +(115, 'Randy Random', True, '2023-03-01'), +(116, 'Randy Random', False, '2023-03-01'), +(117, 'Randy Random', False, '2023-03-01'), +(118, 'Randy Random', True, '2023-03-01'), +(119, 'Randy Random', True, '2023-03-01'), +(120, 'Randy Random', False, '2023-03-01'), +(121, 'Randy Random', False, '2023-03-01'), +(122, 'Randy Random', True, '2023-03-01'), +(123, 'Randy Random', True, '2023-03-01'), +(124, 'Randy Random', False, '2023-03-01'), +(125, 'Randy Random', False, '2023-03-01'), +(126, 'Randy Random', False, '2023-03-01'), +(127, 'Randy Random', False, '2023-03-01'), +(128, 'Randy Random', True, '2023-03-01'), +(129, 'Randy Random', False, '2023-03-01'), +(130, 'Randy Random', False, '2023-03-01'), +(131, 'Randy Random', True, '2023-03-01'), +(132, 'Randy Random', False, '2023-03-01'), +(133, 'Randy Random', True, '2023-03-01'), +(134, 'Randy Random', True, '2023-03-01'), +(135, 'Randy Random', False, '2023-03-01'), +(136, 'Randy Random', True, '2023-03-01'), +(137, 'Randy Random', False, '2023-03-01'), +(138, 'Randy Random', True, '2023-03-01'), +(139, 'Randy Random', False, '2023-03-01'), +(140, 'Randy Random', False, '2023-03-01'), +(141, 'Randy Random', True, '2023-03-01'), +(142, 'Randy Random', True, '2023-03-01'), +(143, 'Randy Random', True, '2023-03-01'), +(144, 'Randy Random', False, '2023-03-01'), +(145, 'Randy Random', True, '2023-03-01'), +(146, 'Randy Random', False, '2023-03-01'), +(147, 'Randy Random', False, '2023-03-01'), +(148, 'Randy Random', True, '2023-03-01'), +(149, 'Randy Random', False, '2023-03-01'), +(150, 'Randy Random', True, '2023-03-01'), +(151, 'Randy Random', False, '2023-03-01'), +(152, 'Randy Random', False, '2023-03-01'), +(153, 'Randy Random', True, '2023-03-01'), +(154, 'Randy Random', False, '2023-03-01'), +(155, 'Randy Random', False, '2023-03-01'), +(156, 'Randy Random', False, '2023-03-01'), +(157, 'Randy Random', True, '2023-03-01'), +(158, 'Randy Random', True, '2023-03-01'), +(159, 'Randy Random', False, '2023-03-01'), +(160, 'Randy Random', True, '2023-03-01'), +(161, 'Randy Random', False, '2023-03-01'), +(162, 'Randy Random', True, '2023-03-01'), +(163, 'Randy Random', True, '2023-03-01'), +(164, 'Randy Random', True, '2023-03-01'), +(165, 'Randy Random', True, '2023-03-01'), +(166, 'Randy Random', False, '2023-03-01'), +(167, 'Randy Random', False, '2023-03-01'), +(168, 'Randy Random', False, '2023-03-01'), +(169, 'Randy Random', True, '2023-03-01'), +(170, 'Randy Random', True, '2023-03-01'), +(171, 'Randy Random', False, '2023-03-01'), +(172, 'Randy Random', True, '2023-03-01'), +(173, 'Randy Random', False, '2023-03-01'), +(174, 'Randy Random', True, '2023-03-01'), +(175, 'Randy Random', True, '2023-03-01'), +(176, 'Randy Random', True, '2023-03-01'), +(177, 'Randy Random', False, '2023-03-01'), +(178, 'Randy Random', True, '2023-03-01'), +(179, 'Randy Random', True, '2023-03-01'), +(180, 'Randy Random', True, '2023-03-01'), +(181, 'Randy Random', True, '2023-03-01'), +(182, 'Randy Random', True, '2023-03-01'), +(183, 'Randy Random', False, '2023-03-01'), +(184, 'Randy Random', False, '2023-03-01'), +(185, 'Randy Random', False, '2023-03-01'), +(186, 'Randy Random', False, '2023-03-01'), +(187, 'Randy Random', True, '2023-03-01'), +(188, 'Randy Random', False, '2023-03-01'), +(189, 'Randy Random', True, '2023-03-01'), +(190, 'Randy Random', False, '2023-03-01'), +(191, 'Randy Random', False, '2023-03-01'), +(192, 'Randy Random', True, '2023-03-01'), +(193, 'Randy Random', True, '2023-03-01'), +(194, 'Randy Random', False, '2023-03-01'), +(195, 'Randy Random', True, '2023-03-01'), +(196, 'Randy Random', True, '2023-03-01'), +(197, 'Randy Random', False, '2023-03-01'), +(198, 'Randy Random', True, '2023-03-01'), +(199, 'Randy Random', False, '2023-03-01'), +(200, 'Randy Random', True, '2023-03-01'), +(201, 'Randy Random', True, '2023-03-01'), +(202, 'Randy Random', True, '2023-03-01'), +(203, 'Randy Random', True, '2023-03-01'), +(204, 'Randy Random', False, '2023-03-01'), +(205, 'Randy Random', False, '2023-03-01'), +(206, 'Randy Random', False, '2023-03-01'), +(207, 'Randy Random', False, '2023-03-01'), +(208, 'Randy Random', True, '2023-03-01'), +(209, 'Randy Random', True, '2023-03-01'), +(210, 'Randy Random', False, '2023-03-01'), +(211, 'Randy Random', True, '2023-03-01'), +(212, 'Randy Random', True, '2023-03-01'), +(213, 'Randy Random', False, '2023-03-01'), +(214, 'Randy Random', True, '2023-03-01'), +(215, 'Randy Random', True, '2023-03-01'), +(216, 'Randy Random', True, '2023-03-01'), +(217, 'Randy Random', True, '2023-03-01'), +(218, 'Randy Random', False, '2023-03-01'), +(219, 'Randy Random', False, '2023-03-01'), +(220, 'Randy Random', True, '2023-03-01'), +(221, 'Randy Random', True, '2023-03-01'), +(222, 'Randy Random', True, '2023-03-01'), +(223, 'Randy Random', False, '2023-03-01'), +(224, 'Randy Random', True, '2023-03-01'), +(225, 'Randy Random', False, '2023-03-01'), +(226, 'Randy Random', True, '2023-03-01'), +(227, 'Randy Random', False, '2023-03-01'), +(228, 'Randy Random', True, '2023-03-01'), +(229, 'Randy Random', False, '2023-03-01'), +(230, 'Randy Random', False, '2023-03-01'), +(231, 'Randy Random', True, '2023-03-01'), +(232, 'Randy Random', True, '2023-03-01'), +(233, 'Randy Random', False, '2023-03-01'), +(234, 'Randy Random', False, '2023-03-01'), +(235, 'Randy Random', True, '2023-03-01'), +(236, 'Randy Random', True, '2023-03-01'), +(237, 'Randy Random', False, '2023-03-01'), +(238, 'Randy Random', True, '2023-03-01'), +(239, 'Randy Random', False, '2023-03-01'), +(240, 'Randy Random', True, '2023-03-01'), +(241, 'Randy Random', True, '2023-03-01'), +(242, 'Randy Random', False, '2023-03-01'), +(243, 'Randy Random', False, '2023-03-01'), +(244, 'Randy Random', True, '2023-03-01'), +(245, 'Randy Random', False, '2023-03-01'), +(246, 'Randy Random', False, '2023-03-01'), +(247, 'Randy Random', True, '2023-03-01'), +(248, 'Randy Random', True, '2023-03-01'), +(249, 'Randy Random', False, '2023-03-01'), +(250, 'Randy Random', False, '2023-03-01'), +(251, 'Randy Random', True, '2023-03-01'), +(252, 'Randy Random', False, '2023-03-01'), +(253, 'Randy Random', False, '2023-03-01'), +(254, 'Randy Random', False, '2023-03-01'), +(255, 'Randy Random', True, '2023-03-01'), +(256, 'Randy Random', False, '2023-03-01'), +(257, 'Randy Random', True, '2023-03-01'), +(258, 'Randy Random', True, '2023-03-01'), +(259, 'Randy Random', True, '2023-03-01'), +(260, 'Randy Random', False, '2023-03-01'), +(261, 'Randy Random', True, '2023-03-01'), +(262, 'Randy Random', True, '2023-03-01'), +(263, 'Randy Random', False, '2023-03-01'), +(264, 'Randy Random', True, '2023-03-01'), +(265, 'Randy Random', False, '2023-03-01'), +(266, 'Randy Random', True, '2023-03-01'), +(267, 'Randy Random', False, '2023-03-01'), +(268, 'Randy Random', False, '2023-03-01'), +(269, 'Randy Random', True, '2023-03-01'), +(270, 'Randy Random', False, '2023-03-01'), +(271, 'Randy Random', False, '2023-03-01'), +(272, 'Randy Random', True, '2023-03-01'), +(273, 'Randy Random', False, '2023-03-01'), +(274, 'Randy Random', True, '2023-03-01'), +(275, 'Randy Random', False, '2023-03-01'), +(276, 'Randy Random', True, '2023-03-01'), +(277, 'Randy Random', False, '2023-03-01'), +(278, 'Randy Random', False, '2023-03-01'), +(279, 'Randy Random', True, '2023-03-01'), +(280, 'Randy Random', False, '2023-03-01'), +(281, 'Randy Random', True, '2023-03-01'), +(282, 'Randy Random', True, '2023-03-01'), +(283, 'Randy Random', True, '2023-03-01'), +(284, 'Randy Random', False, '2023-03-01'), +(285, 'Randy Random', False, '2023-03-01'), +(286, 'Randy Random', False, '2023-03-01'), +(287, 'Randy Random', True, '2023-03-01'), +(288, 'Randy Random', True, '2023-03-01'), +(289, 'Randy Random', True, '2023-03-01'), +(290, 'Randy Random', True, '2023-03-01'), +(291, 'Randy Random', False, '2023-03-01'), +(292, 'Randy Random', True, '2023-03-01'), +(293, 'Randy Random', True, '2023-03-01'), +(294, 'Randy Random', True, '2023-03-01'), +(295, 'Randy Random', False, '2023-03-01'), +(296, 'Randy Random', False, '2023-03-01'), +(297, 'Randy Random', True, '2023-03-01'), +(298, 'Randy Random', True, '2023-03-01'), +(299, 'Randy Random', False, '2023-03-01'), +(300, 'Randy Random', True, '2023-03-01'), +(301, 'Randy Random', False, '2023-03-01'), +(302, 'Randy Random', True, '2023-03-01'), +(303, 'Randy Random', True, '2023-03-01'), +(304, 'Randy Random', False, '2023-03-01'), +(305, 'Randy Random', False, '2023-03-01'), +(306, 'Randy Random', True, '2023-03-01'), +(307, 'Randy Random', True, '2023-03-01'), +(308, 'Randy Random', True, '2023-03-01'), +(309, 'Randy Random', True, '2023-03-01'), +(310, 'Randy Random', False, '2023-03-01'), +(311, 'Randy Random', True, '2023-03-01'), +(312, 'Randy Random', True, '2023-03-01'), +(313, 'Randy Random', True, '2023-03-01'), +(314, 'Randy Random', False, '2023-03-01'), +(315, 'Randy Random', True, '2023-03-01'), +(316, 'Randy Random', True, '2023-03-01'), +(317, 'Randy Random', False, '2023-03-01'), +(318, 'Randy Random', False, '2023-03-01'), +(319, 'Randy Random', False, '2023-03-01'), +(320, 'Randy Random', False, '2023-03-01'), +(321, 'Randy Random', True, '2023-03-01'), +(322, 'Randy Random', True, '2023-03-01'), +(323, 'Randy Random', False, '2023-03-01'), +(324, 'Randy Random', True, '2023-03-01'), +(325, 'Randy Random', False, '2023-03-01'), +(326, 'Randy Random', False, '2023-03-01'), +(327, 'Randy Random', True, '2023-03-01'), +(328, 'Randy Random', False, '2023-03-01'), +(329, 'Randy Random', False, '2023-03-01'), +(330, 'Randy Random', False, '2023-03-01'), +(331, 'Randy Random', False, '2023-03-01'), +(332, 'Randy Random', True, '2023-03-01'), +(333, 'Randy Random', False, '2023-03-01'), +(334, 'Randy Random', True, '2023-03-01'), +(335, 'Randy Random', True, '2023-03-01'), +(336, 'Randy Random', False, '2023-03-01'), +(337, 'Randy Random', False, '2023-03-01'), +(338, 'Randy Random', False, '2023-03-01'), +(339, 'Randy Random', False, '2023-03-01'), +(340, 'Randy Random', False, '2023-03-01'), +(341, 'Randy Random', True, '2023-03-01'), +(342, 'Randy Random', True, '2023-03-01'), +(343, 'Randy Random', True, '2023-03-01'), +(344, 'Randy Random', False, '2023-03-01'), +(345, 'Randy Random', True, '2023-03-01'), +(346, 'Randy Random', False, '2023-03-01'), +(347, 'Randy Random', False, '2023-03-01'), +(348, 'Randy Random', False, '2023-03-01'), +(349, 'Randy Random', True, '2023-03-01'), +(350, 'Randy Random', True, '2023-03-01'), +(351, 'Randy Random', True, '2023-03-01'), +(352, 'Randy Random', False, '2023-03-01'), +(353, 'Randy Random', True, '2023-03-01'), +(354, 'Randy Random', True, '2023-03-01'), +(355, 'Randy Random', True, '2023-03-01'), +(356, 'Randy Random', True, '2023-03-01'), +(357, 'Randy Random', True, '2023-03-01'), +(358, 'Randy Random', False, '2023-03-01'), +(359, 'Randy Random', False, '2023-03-01'), +(360, 'Randy Random', True, '2023-03-01'), +(361, 'Randy Random', True, '2023-03-01'), +(362, 'Randy Random', True, '2023-03-01'), +(363, 'Randy Random', True, '2023-03-01'), +(364, 'Randy Random', True, '2023-03-01'), +(365, 'Randy Random', True, '2023-03-01'), +(366, 'Randy Random', False, '2023-03-01'), +(367, 'Randy Random', True, '2023-03-01'), +(368, 'Randy Random', False, '2023-03-01'), +(369, 'Randy Random', True, '2023-03-01'), +(370, 'Randy Random', True, '2023-03-01'), +(371, 'Randy Random', False, '2023-03-01'), +(372, 'Randy Random', True, '2023-03-01'), +(373, 'Randy Random', True, '2023-03-01'), +(374, 'Randy Random', False, '2023-03-01'), +(375, 'Randy Random', True, '2023-03-01'), +(376, 'Randy Random', True, '2023-03-01'), +(377, 'Randy Random', True, '2023-03-01'), +(378, 'Randy Random', False, '2023-03-01'), +(379, 'Randy Random', False, '2023-03-01'), +(380, 'Randy Random', True, '2023-03-01'), +(381, 'Randy Random', True, '2023-03-01'), +(382, 'Randy Random', True, '2023-03-01'), +(383, 'Randy Random', False, '2023-03-01'), +(384, 'Randy Random', True, '2023-03-01'), +(385, 'Randy Random', False, '2023-03-01'), +(386, 'Randy Random', False, '2023-03-01'), +(387, 'Randy Random', True, '2023-03-01'), +(388, 'Randy Random', True, '2023-03-01'), +(389, 'Randy Random', True, '2023-03-01'), +(390, 'Randy Random', False, '2023-03-01'), +(391, 'Randy Random', False, '2023-03-01'), +(392, 'Randy Random', True, '2023-03-01'), +(393, 'Randy Random', False, '2023-03-01'), +(394, 'Randy Random', False, '2023-03-01'), +(395, 'Randy Random', False, '2023-03-01'), +(396, 'Randy Random', True, '2023-03-01'), +(397, 'Randy Random', True, '2023-03-01'), +(398, 'Randy Random', False, '2023-03-01'), +(399, 'Randy Random', True, '2023-03-01'), +(400, 'Randy Random', False, '2023-03-01'), +(401, 'Randy Random', True, '2023-03-01'), +(402, 'Randy Random', True, '2023-03-01'), +(403, 'Randy Random', True, '2023-03-01'), +(404, 'Randy Random', True, '2023-03-01'), +(405, 'Randy Random', True, '2023-03-01'), +(406, 'Randy Random', True, '2023-03-01'), +(407, 'Randy Random', False, '2023-03-01'), +(408, 'Randy Random', True, '2023-03-01'), +(409, 'Randy Random', True, '2023-03-01'), +(410, 'Randy Random', False, '2023-03-01'), +(411, 'Randy Random', False, '2023-03-01'), +(412, 'Randy Random', True, '2023-03-01'), +(413, 'Randy Random', False, '2023-03-01'), +(414, 'Randy Random', False, '2023-03-01'), +(415, 'Randy Random', False, '2023-03-01'), +(416, 'Randy Random', False, '2023-03-01'), +(417, 'Randy Random', True, '2023-03-01'), +(418, 'Randy Random', False, '2023-03-01'), +(419, 'Randy Random', True, '2023-03-01'), +(420, 'Randy Random', False, '2023-03-01'), +(421, 'Randy Random', True, '2023-03-01'), +(422, 'Randy Random', True, '2023-03-01'), +(423, 'Randy Random', True, '2023-03-01'), +(424, 'Randy Random', False, '2023-03-01'), +(425, 'Randy Random', True, '2023-03-01'), +(426, 'Randy Random', False, '2023-03-01'), +(427, 'Randy Random', True, '2023-03-01'), +(428, 'Randy Random', True, '2023-03-01'), +(429, 'Randy Random', False, '2023-03-01'), +(430, 'Randy Random', True, '2023-03-01'), +(431, 'Randy Random', False, '2023-03-01'), +(432, 'Randy Random', False, '2023-03-01'), +(433, 'Randy Random', True, '2023-03-01'), +(434, 'Randy Random', True, '2023-03-01'), +(435, 'Randy Random', True, '2023-03-01'), +(436, 'Randy Random', True, '2023-03-01'), +(437, 'Randy Random', False, '2023-03-01'), +(438, 'Randy Random', False, '2023-03-01'), +(439, 'Randy Random', False, '2023-03-01'), +(440, 'Randy Random', False, '2023-03-01'), +(441, 'Randy Random', True, '2023-03-01'), +(442, 'Randy Random', True, '2023-03-01'), +(443, 'Randy Random', False, '2023-03-01'), +(444, 'Randy Random', True, '2023-03-01'), +(445, 'Randy Random', True, '2023-03-01'), +(446, 'Randy Random', True, '2023-03-01'), +(447, 'Randy Random', False, '2023-03-01'), +(448, 'Randy Random', False, '2023-03-01'), +(449, 'Randy Random', False, '2023-03-01'), +(450, 'Randy Random', True, '2023-03-01'), +(451, 'Randy Random', False, '2023-03-01'), +(452, 'Randy Random', False, '2023-03-01'), +(453, 'Randy Random', True, '2023-03-01'), +(454, 'Randy Random', True, '2023-03-01'), +(455, 'Randy Random', True, '2023-03-01'), +(456, 'Randy Random', True, '2023-03-01'), +(457, 'Randy Random', True, '2023-03-01'), +(458, 'Randy Random', True, '2023-03-01'), +(459, 'Randy Random', True, '2023-03-01'), +(460, 'Randy Random', False, '2023-03-01'), +(461, 'Randy Random', True, '2023-03-01'), +(462, 'Randy Random', True, '2023-03-01'), +(463, 'Randy Random', False, '2023-03-01'), +(464, 'Randy Random', True, '2023-03-01'), +(465, 'Randy Random', True, '2023-03-01'), +(466, 'Randy Random', True, '2023-03-01'), +(467, 'Randy Random', True, '2023-03-01'), +(468, 'Randy Random', False, '2023-03-01'), +(469, 'Randy Random', True, '2023-03-01'), +(470, 'Randy Random', True, '2023-03-01'), +(471, 'Randy Random', True, '2023-03-01'), +(472, 'Randy Random', False, '2023-03-01'), +(473, 'Randy Random', True, '2023-03-01'), +(474, 'Randy Random', False, '2023-03-01'), +(475, 'Randy Random', False, '2023-03-01'), +(476, 'Randy Random', False, '2023-03-01'), +(477, 'Randy Random', True, '2023-03-01'), +(478, 'Randy Random', False, '2023-03-01'), +(479, 'Randy Random', False, '2023-03-01'), +(480, 'Randy Random', False, '2023-03-01'), +(481, 'Randy Random', False, '2023-03-01'), +(482, 'Randy Random', False, '2023-03-01'), +(483, 'Randy Random', True, '2023-03-01'), +(484, 'Randy Random', False, '2023-03-01'), +(485, 'Randy Random', False, '2023-03-01'), +(486, 'Randy Random', False, '2023-03-01'), +(487, 'Randy Random', False, '2023-03-01'), +(488, 'Randy Random', False, '2023-03-01'), +(489, 'Randy Random', True, '2023-03-01'), +(490, 'Randy Random', True, '2023-03-01'), +(491, 'Randy Random', True, '2023-03-01'), +(492, 'Randy Random', False, '2023-03-01'), +(493, 'Randy Random', True, '2023-03-01'), +(494, 'Randy Random', False, '2023-03-01'), +(495, 'Randy Random', True, '2023-03-01'), +(496, 'Randy Random', False, '2023-03-01'), +(497, 'Randy Random', False, '2023-03-01'), +(498, 'Randy Random', False, '2023-03-01'), +(499, 'Randy Random', False, '2023-03-01'), +(500, 'Randy Random', False, '2023-03-01'), +(501, 'Randy Random', False, '2023-03-01'), +(502, 'Randy Random', False, '2023-03-01'), +(503, 'Randy Random', True, '2023-03-01'), +(504, 'Randy Random', True, '2023-03-01'), +(505, 'Randy Random', False, '2023-03-01'), +(506, 'Randy Random', True, '2023-03-01'), +(507, 'Randy Random', False, '2023-03-01'), +(508, 'Randy Random', True, '2023-03-01'), +(509, 'Randy Random', False, '2023-03-01'), +(510, 'Randy Random', False, '2023-03-01'), +(511, 'Randy Random', False, '2023-03-01'), +(512, 'Randy Random', True, '2023-03-01'), +(513, 'Randy Random', False, '2023-03-01'), +(514, 'Randy Random', False, '2023-03-01'), +(515, 'Randy Random', True, '2023-03-01'), +(516, 'Randy Random', True, '2023-03-01'), +(517, 'Randy Random', False, '2023-03-01'), +(518, 'Randy Random', True, '2023-03-01'), +(519, 'Randy Random', True, '2023-03-01'), +(520, 'Randy Random', True, '2023-03-01'), +(521, 'Randy Random', False, '2023-03-01'), +(522, 'Randy Random', False, '2023-03-01'), +(523, 'Randy Random', True, '2023-03-01'), +(524, 'Randy Random', True, '2023-03-01'), +(525, 'Randy Random', True, '2023-03-01'), +(526, 'Randy Random', False, '2023-03-01'), +(527, 'Randy Random', False, '2023-03-01'), +(528, 'Randy Random', False, '2023-03-01'), +(529, 'Randy Random', True, '2023-03-01'), +(530, 'Randy Random', False, '2023-03-01'), +(531, 'Randy Random', True, '2023-03-01'), +(532, 'Randy Random', True, '2023-03-01'), +(533, 'Randy Random', True, '2023-03-01'), +(534, 'Randy Random', True, '2023-03-01'), +(535, 'Randy Random', False, '2023-03-01'), +(536, 'Randy Random', True, '2023-03-01'), +(537, 'Randy Random', False, '2023-03-01'), +(538, 'Randy Random', True, '2023-03-01'), +(539, 'Randy Random', True, '2023-03-01'), +(540, 'Randy Random', True, '2023-03-01'), +(541, 'Randy Random', True, '2023-03-01'), +(542, 'Randy Random', True, '2023-03-01'), +(543, 'Randy Random', True, '2023-03-01'), +(544, 'Randy Random', False, '2023-03-01'), +(545, 'Randy Random', True, '2023-03-01'), +(546, 'Randy Random', False, '2023-03-01'), +(547, 'Randy Random', True, '2023-03-01'), +(548, 'Randy Random', False, '2023-03-01'), +(549, 'Randy Random', False, '2023-03-01'), +(550, 'Randy Random', False, '2023-03-01'), +(551, 'Randy Random', False, '2023-03-01'), +(552, 'Randy Random', False, '2023-03-01'), +(553, 'Randy Random', True, '2023-03-01'), +(554, 'Randy Random', False, '2023-03-01'), +(555, 'Randy Random', False, '2023-03-01'), +(556, 'Randy Random', True, '2023-03-01'), +(557, 'Randy Random', True, '2023-03-01'), +(558, 'Randy Random', False, '2023-03-01'), +(559, 'Randy Random', False, '2023-03-01'), +(560, 'Randy Random', False, '2023-03-01'), +(561, 'Randy Random', True, '2023-03-01'), +(562, 'Randy Random', False, '2023-03-01'), +(563, 'Randy Random', False, '2023-03-01'), +(564, 'Randy Random', False, '2023-03-01'), +(565, 'Randy Random', False, '2023-03-01'), +(566, 'Randy Random', True, '2023-03-01'), +(567, 'Randy Random', False, '2023-03-01'), +(568, 'Randy Random', False, '2023-03-01'), +(569, 'Randy Random', True, '2023-03-01'), +(570, 'Randy Random', False, '2023-03-01'), +(571, 'Randy Random', True, '2023-03-01'), +(572, 'Randy Random', True, '2023-03-01'), +(573, 'Randy Random', True, '2023-03-01'), +(574, 'Randy Random', False, '2023-03-01'), +(575, 'Randy Random', False, '2023-03-01'), +(576, 'Randy Random', True, '2023-03-01'), +(577, 'Randy Random', True, '2023-03-01'), +(578, 'Randy Random', False, '2023-03-01'), +(579, 'Randy Random', False, '2023-03-01'), +(580, 'Randy Random', False, '2023-03-01'), +(581, 'Randy Random', False, '2023-03-01'), +(582, 'Randy Random', True, '2023-03-01'), +(583, 'Randy Random', False, '2023-03-01'), +(584, 'Randy Random', False, '2023-03-01'), +(585, 'Randy Random', True, '2023-03-01'), +(586, 'Randy Random', True, '2023-03-01'), +(587, 'Randy Random', True, '2023-03-01'), +(588, 'Randy Random', False, '2023-03-01'), +(589, 'Randy Random', False, '2023-03-01'), +(590, 'Randy Random', True, '2023-03-01'), +(591, 'Randy Random', True, '2023-03-01'), +(592, 'Randy Random', False, '2023-03-01'), +(593, 'Randy Random', True, '2023-03-01'), +(594, 'Randy Random', True, '2023-03-01'), +(595, 'Randy Random', False, '2023-03-01'), +(596, 'Randy Random', False, '2023-03-01'), +(597, 'Randy Random', False, '2023-03-01'), +(598, 'Randy Random', True, '2023-03-01'), +(599, 'Randy Random', False, '2023-03-01'), +(600, 'Randy Random', True, '2023-03-01'), +(601, 'Randy Random', False, '2023-03-01'), +(602, 'Randy Random', False, '2023-03-01'), +(603, 'Randy Random', True, '2023-03-01'), +(604, 'Randy Random', True, '2023-03-01'), +(605, 'Randy Random', False, '2023-03-01'), +(606, 'Randy Random', True, '2023-03-01'), +(607, 'Randy Random', False, '2023-03-01'), +(608, 'Randy Random', True, '2023-03-01'), +(609, 'Randy Random', False, '2023-03-01'), +(610, 'Randy Random', False, '2023-03-01'), +(611, 'Randy Random', False, '2023-03-01'), +(612, 'Randy Random', False, '2023-03-01'), +(613, 'Randy Random', True, '2023-03-01'), +(614, 'Randy Random', False, '2023-03-01'), +(615, 'Randy Random', True, '2023-03-01'), +(616, 'Randy Random', False, '2023-03-01'), +(617, 'Randy Random', False, '2023-03-01'), +(618, 'Randy Random', True, '2023-03-01'), +(619, 'Randy Random', True, '2023-03-01'), +(620, 'Randy Random', False, '2023-03-01'), +(621, 'Randy Random', False, '2023-03-01'), +(622, 'Randy Random', True, '2023-03-01'), +(623, 'Randy Random', False, '2023-03-01'), +(624, 'Randy Random', False, '2023-03-01'), +(625, 'Randy Random', False, '2023-03-01'), +(626, 'Randy Random', False, '2023-03-01'), +(627, 'Randy Random', False, '2023-03-01'), +(628, 'Randy Random', True, '2023-03-01'), +(629, 'Randy Random', True, '2023-03-01'), +(630, 'Randy Random', False, '2023-03-01'), +(631, 'Randy Random', True, '2023-03-01'), +(632, 'Randy Random', False, '2023-03-01'), +(633, 'Randy Random', True, '2023-03-01'), +(634, 'Randy Random', False, '2023-03-01'), +(635, 'Randy Random', False, '2023-03-01'), +(636, 'Randy Random', False, '2023-03-01'), +(637, 'Randy Random', False, '2023-03-01'), +(638, 'Randy Random', False, '2023-03-01'), +(639, 'Randy Random', False, '2023-03-01'), +(640, 'Randy Random', True, '2023-03-01'), +(641, 'Randy Random', False, '2023-03-01'), +(642, 'Randy Random', False, '2023-03-01'), +(643, 'Randy Random', True, '2023-03-01'), +(644, 'Randy Random', True, '2023-03-01'), +(645, 'Randy Random', False, '2023-03-01'), +(646, 'Randy Random', True, '2023-03-01'), +(647, 'Randy Random', False, '2023-03-01'), +(648, 'Randy Random', False, '2023-03-01'), +(649, 'Randy Random', False, '2023-03-01'), +(650, 'Randy Random', False, '2023-03-01'), +(651, 'Randy Random', False, '2023-03-01'), +(652, 'Randy Random', True, '2023-03-01'), +(653, 'Randy Random', False, '2023-03-01'), +(654, 'Randy Random', False, '2023-03-01'), +(655, 'Randy Random', True, '2023-03-01'), +(656, 'Randy Random', True, '2023-03-01'), +(657, 'Randy Random', True, '2023-03-01'), +(658, 'Randy Random', True, '2023-03-01'), +(659, 'Randy Random', True, '2023-03-01'), +(660, 'Randy Random', True, '2023-03-01'), +(661, 'Randy Random', False, '2023-03-01'), +(662, 'Randy Random', False, '2023-03-01'), +(663, 'Randy Random', True, '2023-03-01'), +(664, 'Randy Random', False, '2023-03-01'), +(665, 'Randy Random', True, '2023-03-01'), +(666, 'Randy Random', True, '2023-03-01'), +(667, 'Randy Random', True, '2023-03-01'), +(668, 'Randy Random', True, '2023-03-01'), +(669, 'Randy Random', True, '2023-03-01'), +(670, 'Randy Random', True, '2023-03-01'), +(671, 'Randy Random', True, '2023-03-01'), +(672, 'Randy Random', True, '2023-03-01'), +(673, 'Randy Random', True, '2023-03-01'), +(674, 'Randy Random', True, '2023-03-01'), +(675, 'Randy Random', False, '2023-03-01'), +(676, 'Randy Random', True, '2023-03-01'), +(677, 'Randy Random', True, '2023-03-01'), +(678, 'Randy Random', True, '2023-03-01'), +(679, 'Randy Random', True, '2023-03-01'), +(680, 'Randy Random', False, '2023-03-01'), +(681, 'Randy Random', True, '2023-03-01'), +(682, 'Randy Random', False, '2023-03-01'), +(683, 'Randy Random', True, '2023-03-01'), +(684, 'Randy Random', True, '2023-03-01'), +(685, 'Randy Random', False, '2023-03-01'), +(686, 'Randy Random', False, '2023-03-01'), +(687, 'Randy Random', True, '2023-03-01'), +(688, 'Randy Random', False, '2023-03-01'), +(689, 'Randy Random', False, '2023-03-01'), +(690, 'Randy Random', True, '2023-03-01'), +(691, 'Randy Random', False, '2023-03-01'), +(692, 'Randy Random', False, '2023-03-01'), +(693, 'Randy Random', False, '2023-03-01'), +(694, 'Randy Random', False, '2023-03-01'), +(695, 'Randy Random', False, '2023-03-01'), +(696, 'Randy Random', False, '2023-03-01'), +(697, 'Randy Random', True, '2023-03-01'), +(698, 'Randy Random', False, '2023-03-01'), +(699, 'Randy Random', True, '2023-03-01'), +(700, 'Randy Random', True, '2023-03-01'), +(701, 'Randy Random', True, '2023-03-01'), +(702, 'Randy Random', False, '2023-03-01'), +(703, 'Randy Random', True, '2023-03-01'), +(704, 'Randy Random', False, '2023-03-01'), +(705, 'Randy Random', False, '2023-03-01'), +(706, 'Randy Random', True, '2023-03-01'), +(707, 'Randy Random', False, '2023-03-01'), +(708, 'Randy Random', False, '2023-03-01'), +(709, 'Randy Random', True, '2023-03-01'), +(710, 'Randy Random', False, '2023-03-01'), +(711, 'Randy Random', True, '2023-03-01'), +(712, 'Randy Random', True, '2023-03-01'), +(713, 'Randy Random', False, '2023-03-01'), +(714, 'Randy Random', False, '2023-03-01'), +(715, 'Randy Random', False, '2023-03-01'), +(716, 'Randy Random', False, '2023-03-01'), +(717, 'Randy Random', False, '2023-03-01'), +(718, 'Randy Random', True, '2023-03-01'), +(719, 'Randy Random', False, '2023-03-01'), +(720, 'Randy Random', False, '2023-03-01'), +(721, 'Randy Random', True, '2023-03-01'), +(722, 'Randy Random', True, '2023-03-01'), +(723, 'Randy Random', True, '2023-03-01'), +(724, 'Randy Random', True, '2023-03-01'), +(725, 'Randy Random', False, '2023-03-01'), +(726, 'Randy Random', False, '2023-03-01'), +(727, 'Randy Random', False, '2023-03-01'), +(728, 'Randy Random', False, '2023-03-01'), +(729, 'Randy Random', False, '2023-03-01'), +(730, 'Randy Random', False, '2023-03-01'), +(731, 'Randy Random', False, '2023-03-01'), +(732, 'Randy Random', False, '2023-03-01'), +(733, 'Randy Random', True, '2023-03-01'), +(734, 'Randy Random', False, '2023-03-01'), +(735, 'Randy Random', True, '2023-03-01'), +(736, 'Randy Random', False, '2023-03-01'), +(737, 'Randy Random', True, '2023-03-01'), +(738, 'Randy Random', True, '2023-03-01'), +(739, 'Randy Random', False, '2023-03-01'), +(740, 'Randy Random', True, '2023-03-01'), +(741, 'Randy Random', False, '2023-03-01'), +(742, 'Randy Random', False, '2023-03-01'), +(743, 'Randy Random', True, '2023-03-01'), +(744, 'Randy Random', False, '2023-03-01'), +(745, 'Randy Random', False, '2023-03-01'), +(746, 'Randy Random', False, '2023-03-01'), +(747, 'Randy Random', True, '2023-03-01'), +(748, 'Randy Random', False, '2023-03-01'), +(749, 'Randy Random', False, '2023-03-01'), +(750, 'Randy Random', True, '2023-03-01'), +(751, 'Randy Random', False, '2023-03-01'), +(752, 'Randy Random', True, '2023-03-01'), +(753, 'Randy Random', True, '2023-03-01'), +(754, 'Randy Random', False, '2023-03-01'), +(755, 'Randy Random', True, '2023-03-01'), +(756, 'Randy Random', True, '2023-03-01'), +(757, 'Randy Random', False, '2023-03-01'), +(758, 'Randy Random', False, '2023-03-01'), +(759, 'Randy Random', False, '2023-03-01'), +(760, 'Randy Random', True, '2023-03-01'), +(761, 'Randy Random', False, '2023-03-01'), +(762, 'Randy Random', False, '2023-03-01'), +(763, 'Randy Random', True, '2023-03-01'), +(764, 'Randy Random', False, '2023-03-01'), +(765, 'Randy Random', True, '2023-03-01'), +(766, 'Randy Random', False, '2023-03-01'), +(767, 'Randy Random', True, '2023-03-01'), +(768, 'Randy Random', True, '2023-03-01'), +(769, 'Randy Random', True, '2023-03-01'), +(770, 'Randy Random', True, '2023-03-01'), +(771, 'Randy Random', False, '2023-03-01'), +(772, 'Randy Random', False, '2023-03-01'), +(773, 'Randy Random', False, '2023-03-01'), +(774, 'Randy Random', True, '2023-03-01'), +(775, 'Randy Random', True, '2023-03-01'), +(776, 'Randy Random', False, '2023-03-01'), +(777, 'Randy Random', True, '2023-03-01'), +(778, 'Randy Random', True, '2023-03-01'), +(779, 'Randy Random', True, '2023-03-01'), +(780, 'Randy Random', True, '2023-03-01'), +(781, 'Randy Random', True, '2023-03-01'), +(782, 'Randy Random', True, '2023-03-01'), +(783, 'Randy Random', False, '2023-03-01'), +(784, 'Randy Random', True, '2023-03-01'), +(785, 'Randy Random', True, '2023-03-01'), +(786, 'Randy Random', True, '2023-03-01'), +(787, 'Randy Random', False, '2023-03-01'), +(788, 'Randy Random', False, '2023-03-01'), +(789, 'Randy Random', False, '2023-03-01'), +(790, 'Randy Random', True, '2023-03-01'), +(791, 'Randy Random', True, '2023-03-01'), +(792, 'Randy Random', True, '2023-03-01'), +(793, 'Randy Random', True, '2023-03-01'), +(794, 'Randy Random', True, '2023-03-01'), +(795, 'Randy Random', True, '2023-03-01'), +(796, 'Randy Random', False, '2023-03-01'), +(797, 'Randy Random', True, '2023-03-01'), +(798, 'Randy Random', True, '2023-03-01'), +(799, 'Randy Random', False, '2023-03-01'), +(800, 'Randy Random', False, '2023-03-01'), +(801, 'Randy Random', False, '2023-03-01'), +(802, 'Randy Random', False, '2023-03-01'), +(803, 'Randy Random', True, '2023-03-01'), +(804, 'Randy Random', False, '2023-03-01'), +(805, 'Randy Random', True, '2023-03-01'), +(806, 'Randy Random', False, '2023-03-01'), +(807, 'Randy Random', False, '2023-03-01'), +(808, 'Randy Random', True, '2023-03-01'), +(809, 'Randy Random', True, '2023-03-01'), +(810, 'Randy Random', False, '2023-03-01'), +(811, 'Randy Random', False, '2023-03-01'), +(812, 'Randy Random', False, '2023-03-01'), +(813, 'Randy Random', False, '2023-03-01'), +(814, 'Randy Random', True, '2023-03-01'), +(815, 'Randy Random', True, '2023-03-01'), +(816, 'Randy Random', False, '2023-03-01'), +(817, 'Randy Random', False, '2023-03-01'), +(818, 'Randy Random', False, '2023-03-01'), +(819, 'Randy Random', True, '2023-03-01'), +(820, 'Randy Random', False, '2023-03-01'), +(821, 'Randy Random', True, '2023-03-01'), +(822, 'Randy Random', False, '2023-03-01'), +(823, 'Randy Random', True, '2023-03-01'), +(824, 'Randy Random', False, '2023-03-01'), +(825, 'Randy Random', True, '2023-03-01'), +(826, 'Randy Random', False, '2023-03-01'), +(827, 'Randy Random', True, '2023-03-01'), +(828, 'Randy Random', False, '2023-03-01'), +(829, 'Randy Random', True, '2023-03-01'), +(830, 'Randy Random', False, '2023-03-01'), +(831, 'Randy Random', False, '2023-03-01'), +(832, 'Randy Random', True, '2023-03-01'), +(833, 'Randy Random', False, '2023-03-01'), +(834, 'Randy Random', True, '2023-03-01'), +(835, 'Randy Random', False, '2023-03-01'), +(836, 'Randy Random', True, '2023-03-01'), +(837, 'Randy Random', False, '2023-03-01'), +(838, 'Randy Random', True, '2023-03-01'), +(839, 'Randy Random', False, '2023-03-01'), +(840, 'Randy Random', True, '2023-03-01'), +(841, 'Randy Random', True, '2023-03-01'), +(842, 'Randy Random', True, '2023-03-01'), +(843, 'Randy Random', True, '2023-03-01'), +(844, 'Randy Random', True, '2023-03-01'), +(845, 'Randy Random', True, '2023-03-01'), +(846, 'Randy Random', False, '2023-03-01'), +(847, 'Randy Random', True, '2023-03-01'), +(848, 'Randy Random', False, '2023-03-01'), +(849, 'Randy Random', False, '2023-03-01'), +(850, 'Randy Random', False, '2023-03-01'), +(851, 'Randy Random', True, '2023-03-01'), +(852, 'Randy Random', True, '2023-03-01'), +(853, 'Randy Random', True, '2023-03-01'), +(854, 'Randy Random', True, '2023-03-01'), +(855, 'Randy Random', True, '2023-03-01'), +(856, 'Randy Random', False, '2023-03-01'), +(857, 'Randy Random', True, '2023-03-01'), +(858, 'Randy Random', False, '2023-03-01'), +(859, 'Randy Random', False, '2023-03-01'), +(860, 'Randy Random', True, '2023-03-01'), +(861, 'Randy Random', True, '2023-03-01'), +(862, 'Randy Random', True, '2023-03-01'), +(863, 'Randy Random', True, '2023-03-01'), +(864, 'Randy Random', True, '2023-03-01'), +(865, 'Randy Random', True, '2023-03-01'), +(866, 'Randy Random', False, '2023-03-01'), +(867, 'Randy Random', False, '2023-03-01'), +(868, 'Randy Random', True, '2023-03-01'), +(869, 'Randy Random', True, '2023-03-01'), +(870, 'Randy Random', True, '2023-03-01'), +(871, 'Randy Random', False, '2023-03-01'), +(872, 'Randy Random', True, '2023-03-01'), +(873, 'Randy Random', True, '2023-03-01'), +(874, 'Randy Random', False, '2023-03-01'), +(875, 'Randy Random', True, '2023-03-01'), +(876, 'Randy Random', False, '2023-03-01'), +(877, 'Randy Random', True, '2023-03-01'), +(878, 'Randy Random', False, '2023-03-01'), +(879, 'Randy Random', False, '2023-03-01'), +(880, 'Randy Random', False, '2023-03-01'), +(881, 'Randy Random', False, '2023-03-01'), +(882, 'Randy Random', True, '2023-03-01'), +(883, 'Randy Random', False, '2023-03-01'), +(884, 'Randy Random', False, '2023-03-01'), +(885, 'Randy Random', True, '2023-03-01'), +(886, 'Randy Random', False, '2023-03-01'), +(887, 'Randy Random', False, '2023-03-01'), +(888, 'Randy Random', False, '2023-03-01'), +(889, 'Randy Random', False, '2023-03-01'), +(890, 'Randy Random', False, '2023-03-01'), +(891, 'Randy Random', True, '2023-03-01'), +(892, 'Randy Random', False, '2023-03-01'), +(893, 'Randy Random', True, '2023-03-01'), +(894, 'Randy Random', False, '2023-03-01'), +(895, 'Randy Random', False, '2023-03-01'), +(896, 'Randy Random', False, '2023-03-01'), +(897, 'Randy Random', True, '2023-03-01'), +(898, 'Randy Random', True, '2023-03-01'), +(899, 'Randy Random', True, '2023-03-01'), +(900, 'Randy Random', True, '2023-03-01'), +(901, 'Randy Random', False, '2023-03-01'), +(902, 'Randy Random', True, '2023-03-01'), +(903, 'Randy Random', True, '2023-03-01'), +(904, 'Randy Random', True, '2023-03-01'), +(905, 'Randy Random', False, '2023-03-01'), +(906, 'Randy Random', True, '2023-03-01'), +(907, 'Randy Random', True, '2023-03-01'), +(908, 'Randy Random', True, '2023-03-01'), +(909, 'Randy Random', True, '2023-03-01'), +(910, 'Randy Random', True, '2023-03-01'), +(911, 'Randy Random', True, '2023-03-01'), +(912, 'Randy Random', False, '2023-03-01'), +(913, 'Randy Random', True, '2023-03-01'), +(914, 'Randy Random', True, '2023-03-01'), +(915, 'Randy Random', False, '2023-03-01'), +(916, 'Randy Random', False, '2023-03-01'), +(917, 'Randy Random', True, '2023-03-01'), +(918, 'Randy Random', True, '2023-03-01'), +(919, 'Randy Random', False, '2023-03-01'), +(920, 'Randy Random', True, '2023-03-01'), +(921, 'Randy Random', True, '2023-03-01'), +(922, 'Randy Random', True, '2023-03-01'), +(923, 'Randy Random', False, '2023-03-01'), +(924, 'Randy Random', True, '2023-03-01'), +(925, 'Randy Random', False, '2023-03-01'), +(926, 'Randy Random', False, '2023-03-01'), +(927, 'Randy Random', False, '2023-03-01'), +(928, 'Randy Random', True, '2023-03-01'), +(929, 'Randy Random', False, '2023-03-01'), +(930, 'Randy Random', True, '2023-03-01'), +(931, 'Randy Random', False, '2023-03-01'), +(932, 'Randy Random', False, '2023-03-01'), +(933, 'Randy Random', True, '2023-03-01'), +(934, 'Randy Random', True, '2023-03-01'), +(935, 'Randy Random', True, '2023-03-01'), +(936, 'Randy Random', True, '2023-03-01'), +(937, 'Randy Random', True, '2023-03-01'), +(938, 'Randy Random', True, '2023-03-01'), +(939, 'Randy Random', False, '2023-03-01'), +(940, 'Randy Random', False, '2023-03-01'), +(941, 'Randy Random', False, '2023-03-01'), +(942, 'Randy Random', False, '2023-03-01'), +(943, 'Randy Random', False, '2023-03-01'), +(944, 'Randy Random', True, '2023-03-01'), +(945, 'Randy Random', True, '2023-03-01'), +(946, 'Randy Random', True, '2023-03-01'), +(947, 'Randy Random', True, '2023-03-01'), +(948, 'Randy Random', False, '2023-03-01'), +(949, 'Randy Random', False, '2023-03-01'), +(950, 'Randy Random', True, '2023-03-01'), +(951, 'Randy Random', True, '2023-03-01'), +(952, 'Randy Random', False, '2023-03-01'), +(953, 'Randy Random', True, '2023-03-01'), +(954, 'Randy Random', False, '2023-03-01'), +(955, 'Randy Random', True, '2023-03-01'), +(956, 'Randy Random', True, '2023-03-01'), +(957, 'Randy Random', True, '2023-03-01'), +(958, 'Randy Random', True, '2023-03-01'), +(959, 'Randy Random', False, '2023-03-01'), +(960, 'Randy Random', True, '2023-03-01'), +(961, 'Randy Random', False, '2023-03-01'), +(962, 'Randy Random', False, '2023-03-01'), +(963, 'Randy Random', False, '2023-03-01'), +(964, 'Randy Random', True, '2023-03-01'), +(965, 'Randy Random', True, '2023-03-01'), +(966, 'Randy Random', False, '2023-03-01'), +(967, 'Randy Random', True, '2023-03-01'), +(968, 'Randy Random', False, '2023-03-01'), +(969, 'Randy Random', True, '2023-03-01'), +(970, 'Randy Random', False, '2023-03-01'), +(971, 'Randy Random', False, '2023-03-01'), +(972, 'Randy Random', False, '2023-03-01'), +(973, 'Randy Random', False, '2023-03-01'), +(974, 'Randy Random', False, '2023-03-01'), +(975, 'Randy Random', True, '2023-03-01'), +(976, 'Randy Random', False, '2023-03-01'), +(977, 'Randy Random', True, '2023-03-01'), +(978, 'Randy Random', False, '2023-03-01'), +(979, 'Randy Random', False, '2023-03-01'), +(980, 'Randy Random', False, '2023-03-01'), +(981, 'Randy Random', False, '2023-03-01'), +(982, 'Randy Random', True, '2023-03-01'), +(983, 'Randy Random', False, '2023-03-01'), +(984, 'Randy Random', True, '2023-03-01'), +(985, 'Randy Random', True, '2023-03-01'), +(986, 'Randy Random', True, '2023-03-01'), +(987, 'Randy Random', False, '2023-03-01'), +(988, 'Randy Random', True, '2023-03-01'), +(989, 'Randy Random', False, '2023-03-01'), +(990, 'Randy Random', True, '2023-03-01'), +(991, 'Randy Random', True, '2023-03-01'), +(992, 'Randy Random', True, '2023-03-01'), +(993, 'Randy Random', True, '2023-03-01'), +(994, 'Randy Random', False, '2023-03-01'), +(995, 'Randy Random', True, '2023-03-01'), +(996, 'Randy Random', True, '2023-03-01'), +(997, 'Randy Random', False, '2023-03-01'), +(998, 'Randy Random', False, '2023-03-01'), +(999, 'Randy Random', False, '2023-03-01'), +(1000, 'Randy Random', True, '2023-03-01'); diff --git a/tests/test_functional.py b/tests/test_functional.py index 23037ad3..0a58becb 100644 --- a/tests/test_functional.py +++ b/tests/test_functional.py @@ -18,6 +18,8 @@ class FunctionalTestCase(RequiresDBTestCase): alt_ssg_file_path = Path("my_ssg.py") concept_file_path = Path("concept.csv") + config_file_path = Path("../examples/functional_conf.yaml") + stats_file_path = Path("../examples/example_stats.yaml") test_dir = Path("tests/workspace") start_dir = os.getcwd() @@ -58,7 +60,6 @@ def tearDown(self) -> None: def test_workflow_minimal_args(self) -> None: """Test the recommended CLI workflow runs without errors.""" - completed_process = run( ["sqlsynthgen", "make-tables"], capture_output=True, @@ -116,13 +117,27 @@ def test_workflow_maximal_args(self) -> None: ) self.assertEqual(0, completed_process.returncode) + completed_process = run( + [ + "sqlsynthgen", + "make-stats", + f"--stats-file={self.stats_file_path}", + f"--config-file={self.config_file_path}", + ], + capture_output=True, + env=self.env, + ) + self.assertEqual("", completed_process.stderr.decode("utf-8")) + self.assertEqual(0, completed_process.returncode) + completed_process = run( [ "sqlsynthgen", "make-generators", f"--orm-file={self.alt_orm_file_path}", f"--ssg-file={self.alt_ssg_file_path}", - "../examples/functional_conf.yaml", + f"--config-file={self.config_file_path}", + f"--stats-file={self.stats_file_path}", ], capture_output=True, env=self.env, diff --git a/tests/test_main.py b/tests/test_main.py index 15a68dda..b38dd7ea 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -5,12 +5,17 @@ from click.testing import Result from typer.testing import CliRunner +import yaml from sqlsynthgen.main import app from tests.utils import get_test_settings runner = CliRunner(mix_stderr=False) +EXAMPLE_ORM_PATH = "tests/examples/example_orm.py" +EXAMPLE_CONF_PATH = "tests/examples/generator_conf.yaml" +EXPECTED_SSG_PATH = "tests/examples/expected_ssg.py" + class TestCLI(TestCase): """Tests for the command-line interface.""" @@ -55,7 +60,7 @@ def test_make_generators( catch_exceptions=False, ) - mock_make.assert_called_once_with(mock_import.return_value, {}) + mock_make.assert_called_once_with(mock_import.return_value, {}, None) mock_path.return_value.write_text.assert_called_once_with( "some text", encoding="utf-8" ) @@ -178,3 +183,27 @@ def test_make_tables_errors_if_file_exists( "orm.py should not already exist. Exiting...\n", mock_stderr.getvalue() ) self.assertEqual(1, result.exit_code) + + def test_make_stats(self) -> None: + """Test the make-stats sub-command.""" + + with patch("sqlsynthgen.main.make_src_stats") as mock_make, patch( + "sqlsynthgen.main.get_settings" + ) as mock_get_settings: + mock_get_settings.return_value = get_test_settings() + output_path = "make_stats_output.yaml" + result = runner.invoke( + app, + [ + "make-stats", + f"--stats-file={output_path}", + f"--config-file={EXAMPLE_CONF_PATH}", + ], + catch_exceptions=False, + ) + self.assertSuccess(result) + with open(EXAMPLE_CONF_PATH, "r", encoding="utf8") as f: + config = yaml.safe_load(f) + mock_make.assert_called_once_with( + get_test_settings().src_postgres_dsn, config, output_path + ) diff --git a/tests/test_make.py b/tests/test_make.py index ad5ab958..c3eb7dd9 100644 --- a/tests/test_make.py +++ b/tests/test_make.py @@ -41,10 +41,11 @@ def test_make_generators_from_tables( conf_path = "generator_conf.yaml" with open(conf_path, "r", encoding="utf8") as f: config = yaml.safe_load(f) + stats_path = "example_stats.yaml" - actual = make.make_generators_from_tables(example_orm, config) - mock_download.assert_called_once() - mock_create.assert_called_once() + actual = make.make_generators_from_tables(example_orm, config, stats_path) + mock_download.assert_called_once() + mock_create.assert_called_once() self.assertEqual(expected, actual) @@ -124,3 +125,23 @@ def test_make_tables_warns_no_pk( "WARNING: Table without PK detected. sqlsynthgen may not be able to continue.\n", mock_stderr.getvalue(), ) + + def test_make_stats(self) -> None: + """Test the make_src_stats function.""" + conf_path = "generator_conf.yaml" + with open(conf_path, "r", encoding="utf8") as f: + config = yaml.safe_load(f) + + with patch("sqlsynthgen.make.yaml") as mock_yaml: + connection_string = "postgresql://postgres:password@localhost:5432/src" + src_stats = make.make_src_stats( + connection_string, config, "/tmp/tmp_test_file.yaml" + ) + mock_yaml.dump.assert_called_once() + assert set(src_stats.keys()) == set(["count_opt_outs"]) + count_opt_outs = src_stats["count_opt_outs"] + assert len(count_opt_outs) == 2 + assert isinstance(count_opt_outs[0][0], int) + assert count_opt_outs[0][1] is False + assert isinstance(count_opt_outs[1][0], int) + assert count_opt_outs[1][1] is True diff --git a/tests/workspace/custom_generators.py b/tests/workspace/custom_generators.py index f906f9d1..c96f6a88 100644 --- a/tests/workspace/custom_generators.py +++ b/tests/workspace/custom_generators.py @@ -14,3 +14,9 @@ def timespan_generator( earliest_start_year, last_start_year, min_dt, max_dt ) return start, end, delta.total_seconds() + + +def boolean_from_src_stats_generator(generic, src_stats): + num_false = int(next(x for x, y in src_stats if y == "false")) + num_true = int(next(x for x, y in src_stats if y == "true")) + return generic.weighted_boolean_provider().boolean(num_true / num_false) From 2f66a7b8e9802c2902052be3e80e62398c4c0c04 Mon Sep 17 00:00:00 2001 From: Markus Hauru Date: Thu, 2 Mar 2023 14:05:36 +0000 Subject: [PATCH 03/15] Fix path in expected_ssg.py --- sqlsynthgen/make.py | 3 +++ tests/examples/expected_ssg.py | 2 +- tests/test_main.py | 12 ++++-------- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/sqlsynthgen/make.py b/sqlsynthgen/make.py index 03476703..bcc0fe48 100644 --- a/sqlsynthgen/make.py +++ b/sqlsynthgen/make.py @@ -145,6 +145,8 @@ def make_generators_from_tables( Args: tables_module: A sqlacodegen-generated module. generator_config: Configuration to control the generator creation. + src_stats_file_name: A filename for where to read src stats from. Optional, if + `None` this feature will be skipped Returns: A string that is a valid Python module, once written to file. @@ -266,6 +268,7 @@ def make_src_stats( metadata=snsql_metadata, ) private_result = reader.execute(stat_data["query"]) + # The first entry in the list names the columns, skip that. src_stats[stat_data["name"]] = private_result[1:] with open(stats_filename, "w", encoding="utf-8") as f: yaml.dump(src_stats, f) diff --git a/tests/examples/expected_ssg.py b/tests/examples/expected_ssg.py index 976a67eb..2064720e 100644 --- a/tests/examples/expected_ssg.py +++ b/tests/examples/expected_ssg.py @@ -19,7 +19,7 @@ import tests.examples.example_orm import custom_generators import yaml -with open("tests/examples/example_stats.yaml", "r", encoding="utf-8") as f: +with open("example_stats.yaml", "r", encoding="utf-8") as f: SRC_STATS = yaml.load(f, Loader=yaml.FullLoader) concept_vocab = FileUploader(tests.examples.example_orm.Concept.__table__) diff --git a/tests/test_main.py b/tests/test_main.py index b38dd7ea..245bc27c 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -3,19 +3,15 @@ from unittest import TestCase from unittest.mock import MagicMock, call, patch +import yaml from click.testing import Result from typer.testing import CliRunner -import yaml from sqlsynthgen.main import app from tests.utils import get_test_settings runner = CliRunner(mix_stderr=False) -EXAMPLE_ORM_PATH = "tests/examples/example_orm.py" -EXAMPLE_CONF_PATH = "tests/examples/generator_conf.yaml" -EXPECTED_SSG_PATH = "tests/examples/expected_ssg.py" - class TestCLI(TestCase): """Tests for the command-line interface.""" @@ -186,7 +182,7 @@ def test_make_tables_errors_if_file_exists( def test_make_stats(self) -> None: """Test the make-stats sub-command.""" - + example_conf_path = "tests/examples/generator_conf.yaml" with patch("sqlsynthgen.main.make_src_stats") as mock_make, patch( "sqlsynthgen.main.get_settings" ) as mock_get_settings: @@ -197,12 +193,12 @@ def test_make_stats(self) -> None: [ "make-stats", f"--stats-file={output_path}", - f"--config-file={EXAMPLE_CONF_PATH}", + f"--config-file={example_conf_path}", ], catch_exceptions=False, ) self.assertSuccess(result) - with open(EXAMPLE_CONF_PATH, "r", encoding="utf8") as f: + with open(example_conf_path, "r", encoding="utf8") as f: config = yaml.safe_load(f) mock_make.assert_called_once_with( get_test_settings().src_postgres_dsn, config, output_path From 676e19d8e680986969faea6c817b0f84a41e553a Mon Sep 17 00:00:00 2001 From: Markus Hauru Date: Thu, 2 Mar 2023 14:39:57 +0000 Subject: [PATCH 04/15] Remove unnecessary example_stats.yaml --- tests/examples/example_stats.yaml | 1 - tests/test_functional.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 tests/examples/example_stats.yaml diff --git a/tests/examples/example_stats.yaml b/tests/examples/example_stats.yaml deleted file mode 100644 index 0967ef42..00000000 --- a/tests/examples/example_stats.yaml +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/tests/test_functional.py b/tests/test_functional.py index 0a58becb..4b42bc96 100644 --- a/tests/test_functional.py +++ b/tests/test_functional.py @@ -19,7 +19,7 @@ class FunctionalTestCase(RequiresDBTestCase): concept_file_path = Path("concept.csv") config_file_path = Path("../examples/functional_conf.yaml") - stats_file_path = Path("../examples/example_stats.yaml") + stats_file_path = Path("example_stats.yaml") test_dir = Path("tests/workspace") start_dir = os.getcwd() From cebb927d1fe2d22d464bd16cdb5cf3408226863d Mon Sep 17 00:00:00 2001 From: Markus Hauru Date: Thu, 2 Mar 2023 14:57:33 +0000 Subject: [PATCH 05/15] Fix boolean_from_src_stats_generator --- tests/examples/generator_conf.yaml | 3 ++- tests/workspace/custom_generators.py | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/examples/generator_conf.yaml b/tests/examples/generator_conf.yaml index 7d75848f..13f10a71 100644 --- a/tests/examples/generator_conf.yaml +++ b/tests/examples/generator_conf.yaml @@ -29,7 +29,8 @@ tables: columns_assigned: stored_from - name: custom_generators.boolean_from_src_stats_generator args: - src_stats: SRC_STATS.count_opt_outs + generic: generic + src_stats: SRC_STATS["count_opt_outs"] columns_assigned: research_opt_out hospital_visit: diff --git a/tests/workspace/custom_generators.py b/tests/workspace/custom_generators.py index c96f6a88..71ff0103 100644 --- a/tests/workspace/custom_generators.py +++ b/tests/workspace/custom_generators.py @@ -17,6 +17,6 @@ def timespan_generator( def boolean_from_src_stats_generator(generic, src_stats): - num_false = int(next(x for x, y in src_stats if y == "false")) - num_true = int(next(x for x, y in src_stats if y == "true")) - return generic.weighted_boolean_provider().boolean(num_true / num_false) + num_false = int(next(x for x, y in src_stats if y is False)) + num_true = int(next(x for x, y in src_stats if y is True)) + return generic.weighted_boolean_provider.bool(num_true / num_false) From 68f87613cb9fe17a045f8a94411450a2bf2002b1 Mon Sep 17 00:00:00 2001 From: Markus Hauru Date: Thu, 2 Mar 2023 15:35:03 +0000 Subject: [PATCH 06/15] Unify testing architecture with SSGTestCase --- tests/examples/functional_conf.yaml | 21 +++++++++++++++++++++ tests/test_create.py | 5 ++--- tests/test_functional.py | 23 +++++++++++------------ tests/test_main.py | 13 ++----------- tests/test_make.py | 6 ++---- tests/test_providers.py | 11 +++++------ tests/test_settings.py | 5 ++--- tests/test_utils.py | 5 ++--- tests/utils.py | 20 +++++++++++++++++++- 9 files changed, 66 insertions(+), 43 deletions(-) diff --git a/tests/examples/functional_conf.yaml b/tests/examples/functional_conf.yaml index 26ec28a2..13f10a71 100644 --- a/tests/examples/functional_conf.yaml +++ b/tests/examples/functional_conf.yaml @@ -1,3 +1,19 @@ +opendp: + public: + person: + person_id: + name: person_id + type: int + private_id: True + research_opt_out: + name: research_opt_out + type: boolean + private_id: False +src-stats: + - name: count_opt_outs + query: SELECT count(*) AS num, research_opt_out FROM person GROUP BY research_opt_out + epsilon: 1.0 + delta: 0.1 custom_generators_module: custom_generators tables: person: @@ -11,6 +27,11 @@ tables: start: 2022 end: 2022 columns_assigned: stored_from + - name: custom_generators.boolean_from_src_stats_generator + args: + generic: generic + src_stats: SRC_STATS["count_opt_outs"] + columns_assigned: research_opt_out hospital_visit: num_rows_per_pass: 3 diff --git a/tests/test_create.py b/tests/test_create.py index 369e98a6..4eaa6b91 100644 --- a/tests/test_create.py +++ b/tests/test_create.py @@ -1,5 +1,4 @@ """Tests for the create module.""" -from unittest import TestCase from unittest.mock import MagicMock, call, patch from sqlsynthgen.create import ( @@ -8,10 +7,10 @@ create_db_vocab, populate, ) -from tests.utils import get_test_settings +from tests.utils import SSGTestCase, get_test_settings -class MyTestCase(TestCase): +class MyTestCase(SSGTestCase): """Module test case.""" @patch("sqlsynthgen.create.create_engine") diff --git a/tests/test_functional.py b/tests/test_functional.py index 4b42bc96..82e3150e 100644 --- a/tests/test_functional.py +++ b/tests/test_functional.py @@ -65,7 +65,7 @@ def test_workflow_minimal_args(self) -> None: capture_output=True, env=self.env, ) - self.assertEqual(0, completed_process.returncode) + self.assertSuccess(completed_process.returncode) completed_process = run( ["sqlsynthgen", "make-generators"], @@ -73,7 +73,7 @@ def test_workflow_minimal_args(self) -> None: env=self.env, ) self.assertEqual("", completed_process.stderr.decode("utf-8")) - self.assertEqual(0, completed_process.returncode) + self.assertSuccess(completed_process) completed_process = run( ["sqlsynthgen", "create-tables"], @@ -81,7 +81,7 @@ def test_workflow_minimal_args(self) -> None: env=self.env, ) self.assertEqual("", completed_process.stderr.decode("utf-8")) - self.assertEqual(0, completed_process.returncode) + self.assertSuccess(completed_process) completed_process = run( ["sqlsynthgen", "create-vocab"], @@ -89,7 +89,7 @@ def test_workflow_minimal_args(self) -> None: env=self.env, ) self.assertEqual("", completed_process.stderr.decode("utf-8")) - self.assertEqual(0, completed_process.returncode) + self.assertSuccess(completed_process) completed_process = run( ["sqlsynthgen", "create-data"], @@ -97,7 +97,7 @@ def test_workflow_minimal_args(self) -> None: env=self.env, ) self.assertEqual("", completed_process.stderr.decode("utf-8")) - self.assertEqual(0, completed_process.returncode) + self.assertSuccess(completed_process) def test_workflow_maximal_args(self) -> None: """Test the CLI workflow runs with optional arguments.""" @@ -115,7 +115,7 @@ def test_workflow_maximal_args(self) -> None: "WARNING: Table without PK detected. sqlsynthgen may not be able to continue.\n", completed_process.stderr.decode("utf-8"), ) - self.assertEqual(0, completed_process.returncode) + self.assertSuccess(completed_process) completed_process = run( [ @@ -127,8 +127,7 @@ def test_workflow_maximal_args(self) -> None: capture_output=True, env=self.env, ) - self.assertEqual("", completed_process.stderr.decode("utf-8")) - self.assertEqual(0, completed_process.returncode) + self.assertSuccess(completed_process) completed_process = run( [ @@ -143,7 +142,7 @@ def test_workflow_maximal_args(self) -> None: env=self.env, ) self.assertEqual("", completed_process.stderr.decode("utf-8")) - self.assertEqual(0, completed_process.returncode) + self.assertSuccess(completed_process) completed_process = run( [ @@ -155,7 +154,7 @@ def test_workflow_maximal_args(self) -> None: env=self.env, ) self.assertEqual("", completed_process.stderr.decode("utf-8")) - self.assertEqual(0, completed_process.returncode) + self.assertSuccess(completed_process) completed_process = run( [ @@ -167,7 +166,7 @@ def test_workflow_maximal_args(self) -> None: env=self.env, ) self.assertEqual("", completed_process.stderr.decode("utf-8")) - self.assertEqual(0, completed_process.returncode) + self.assertSuccess(completed_process) completed_process = run( [ @@ -181,4 +180,4 @@ def test_workflow_maximal_args(self) -> None: env=self.env, ) self.assertEqual("", completed_process.stderr.decode("utf-8")) - self.assertEqual(0, completed_process.returncode) + self.assertSuccess(completed_process) diff --git a/tests/test_main.py b/tests/test_main.py index 245bc27c..91826f8f 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,28 +1,19 @@ """Tests for the main module.""" from io import StringIO -from unittest import TestCase from unittest.mock import MagicMock, call, patch import yaml -from click.testing import Result from typer.testing import CliRunner from sqlsynthgen.main import app -from tests.utils import get_test_settings +from tests.utils import SSGTestCase, get_test_settings runner = CliRunner(mix_stderr=False) -class TestCLI(TestCase): +class TestCLI(SSGTestCase): """Tests for the command-line interface.""" - def assertSuccess(self, result: Result) -> None: - """Give details and raise if the result isn't good.""" - # pylint: disable=invalid-name - if result.exit_code != 0: - print(result.stdout) - self.assertEqual(0, result.exit_code) - @patch("sqlsynthgen.main.import_file") @patch("sqlsynthgen.main.create_db_vocab") def test_create_vocab(self, mock_create: MagicMock, mock_import: MagicMock) -> None: diff --git a/tests/test_make.py b/tests/test_make.py index c3eb7dd9..a619384e 100644 --- a/tests/test_make.py +++ b/tests/test_make.py @@ -3,7 +3,6 @@ from io import StringIO from pathlib import Path from subprocess import CalledProcessError -from unittest import TestCase from unittest.mock import MagicMock, call, patch import yaml @@ -11,10 +10,10 @@ from sqlsynthgen import make from sqlsynthgen.make import make_tables_file from tests.examples import example_orm -from tests.utils import SysExit +from tests.utils import SSGTestCase, SysExit -class TestMake(TestCase): +class TestMake(SSGTestCase): """Tests that don't require a database.""" test_dir = Path("tests/examples") @@ -35,7 +34,6 @@ def test_make_generators_from_tables( self, mock_download: MagicMock, mock_create: MagicMock, _: MagicMock ) -> None: """Check that we can make a generators file from a tables module.""" - self.maxDiff = None # pylint: disable=invalid-name with open("expected_ssg.py", encoding="utf-8") as expected_output: expected = expected_output.read() conf_path = "generator_conf.yaml" diff --git a/tests/test_providers.py b/tests/test_providers.py index ea6a50a9..a142bcfe 100644 --- a/tests/test_providers.py +++ b/tests/test_providers.py @@ -1,13 +1,12 @@ """Tests for the providers module.""" import datetime as dt from pathlib import Path -from unittest import TestCase from sqlalchemy import Column, Integer, Text, create_engine, insert from sqlalchemy.ext.declarative import declarative_base from sqlsynthgen import providers -from tests.utils import RequiresDBTestCase, run_psql +from tests.utils import RequiresDBTestCase, SSGTestCase, run_psql # pylint: disable=invalid-name Base = declarative_base() @@ -27,7 +26,7 @@ class Person(Base): # type: ignore sex = Column(Text) -class BinaryProviderTestCase(TestCase): +class BinaryProviderTestCase(SSGTestCase): """Tests for the BytesProvider class.""" def test_bytes(self) -> None: @@ -62,7 +61,7 @@ def test_column_value(self) -> None: self.assertEqual("M", key) -class TimedeltaProvider(TestCase): +class TimedeltaProvider(SSGTestCase): """Tests for TimedeltaProvider""" def test_timedelta(self) -> None: @@ -74,7 +73,7 @@ def test_timedelta(self) -> None: assert min_dt <= delta <= max_dt -class TimespanProvider(TestCase): +class TimespanProvider(SSGTestCase): """Tests for TimespanProvider.""" def test_timespan(self) -> None: @@ -94,7 +93,7 @@ def test_timespan(self) -> None: assert end - start == delta -class TestWeightedBooleanProvider(TestCase): +class TestWeightedBooleanProvider(SSGTestCase): """Tests for WeightedBooleanProvider.""" def test_bool(self) -> None: diff --git a/tests/test_settings.py b/tests/test_settings.py index 43608a15..1c664f7d 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -1,10 +1,9 @@ """Tests for the settings module.""" -from unittest import TestCase - from sqlsynthgen.settings import Settings +from tests.utils import SSGTestCase -class TestSettings(TestCase): +class TestSettings(SSGTestCase): """Tests for the Settings class.""" def test_default_settings(self) -> None: diff --git a/tests/test_utils.py b/tests/test_utils.py index 209410ab..17d86593 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -3,14 +3,13 @@ import sys from io import StringIO from pathlib import Path -from unittest import TestCase from unittest.mock import MagicMock, patch from sqlalchemy import Column, Integer, create_engine, insert from sqlalchemy.orm import declarative_base from sqlsynthgen.utils import download_table, import_file -from tests.utils import RequiresDBTestCase, SysExit, run_psql +from tests.utils import RequiresDBTestCase, SSGTestCase, SysExit, run_psql # pylint: disable=invalid-name Base = declarative_base() @@ -28,7 +27,7 @@ class MyTable(Base): # type: ignore ) -class TestImport(TestCase): +class TestImport(SSGTestCase): """Tests for the import_file function.""" test_dir = Path("tests/examples") diff --git a/tests/utils.py b/tests/utils.py index 9fb6df48..a60df11c 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -3,6 +3,7 @@ from functools import lru_cache from pathlib import Path from subprocess import run +from typing import Any from unittest import TestCase, skipUnless from sqlsynthgen import settings @@ -50,8 +51,25 @@ def run_psql(dump_file: Path) -> None: assert completed_process.stderr == b"", completed_process.stderr +class SSGTestCase(TestCase): + """Parent class for all TestCases in SqlSynthGen.""" + + def __init__(self, *args: Any, **kwargs: Any) -> None: + """Initialize an instance of SSGTestCase.""" + self.maxDiff = None # pylint: disable=invalid-name + super().__init__(*args, **kwargs) + + def assertSuccess(self, result: Any) -> None: # pylint: disable=invalid-name + """Give details for a subprocess result and raise if the result isn't good.""" + code = result.exit_code if hasattr(result, "exit_code") else result.returncode + if code != 0: + print(result.stdout) + print(result.stderr) + self.assertEqual(0, code) + + @skipUnless(os.environ.get("REQUIRES_DB") == "1", "Set 'REQUIRES_DB=1' to enable.") -class RequiresDBTestCase(TestCase): +class RequiresDBTestCase(SSGTestCase): """A test case that only runs if REQUIRES_DB has been set to 1.""" def setUp(self) -> None: From 59724aceed1b73311fe6f558561bb588bd23b2f5 Mon Sep 17 00:00:00 2001 From: Markus Hauru Date: Thu, 2 Mar 2023 16:20:31 +0000 Subject: [PATCH 07/15] Misc fixes --- sqlsynthgen/main.py | 2 +- ...nctional_conf.yaml => example_config.yaml} | 0 tests/examples/expected_ssg.py | 2 +- tests/examples/generator_conf.yaml | 51 ------------------- tests/test_functional.py | 4 +- tests/test_main.py | 2 +- tests/test_make.py | 4 +- 7 files changed, 7 insertions(+), 58 deletions(-) rename tests/examples/{functional_conf.yaml => example_config.yaml} (100%) delete mode 100644 tests/examples/generator_conf.yaml diff --git a/sqlsynthgen/main.py b/sqlsynthgen/main.py index 80555e35..7ca546d4 100644 --- a/sqlsynthgen/main.py +++ b/sqlsynthgen/main.py @@ -134,7 +134,7 @@ def make_stats( """Compute summary statistics from the source database, write them to a YAML file. Example: - $ sqlsynthgen make_stats --config-file=generator_conf.yaml + $ sqlsynthgen make_stats --config-file=example_config.yaml """ settings = get_settings() generator_config = read_yaml_file(config_file) if config_file is not None else {} diff --git a/tests/examples/functional_conf.yaml b/tests/examples/example_config.yaml similarity index 100% rename from tests/examples/functional_conf.yaml rename to tests/examples/example_config.yaml diff --git a/tests/examples/expected_ssg.py b/tests/examples/expected_ssg.py index 2064720e..6472e4a0 100644 --- a/tests/examples/expected_ssg.py +++ b/tests/examples/expected_ssg.py @@ -37,7 +37,7 @@ class personGenerator: def __init__(self, src_db_conn, dst_db_conn): self.name = generic.person.full_name() self.stored_from = generic.datetime.datetime(start=2022, end=2022) - self.research_opt_out = custom_generators.boolean_from_src_stats_generator(src_stats=SRC_STATS.count_opt_outs) + self.research_opt_out = custom_generators.boolean_from_src_stats_generator(generic=generic, src_stats=SRC_STATS["count_opt_outs"]) pass self.nhs_number = generic.text.color() self.source_system = generic.text.color() diff --git a/tests/examples/generator_conf.yaml b/tests/examples/generator_conf.yaml deleted file mode 100644 index 13f10a71..00000000 --- a/tests/examples/generator_conf.yaml +++ /dev/null @@ -1,51 +0,0 @@ -opendp: - public: - person: - person_id: - name: person_id - type: int - private_id: True - research_opt_out: - name: research_opt_out - type: boolean - private_id: False -src-stats: - - name: count_opt_outs - query: SELECT count(*) AS num, research_opt_out FROM person GROUP BY research_opt_out - epsilon: 1.0 - delta: 0.1 -custom_generators_module: custom_generators -tables: - person: - num_rows_per_pass: 2 - custom_generators: - - name: generic.person.full_name - args: null - columns_assigned: name - - name: generic.datetime.datetime - args: - start: 2022 - end: 2022 - columns_assigned: stored_from - - name: custom_generators.boolean_from_src_stats_generator - args: - generic: generic - src_stats: SRC_STATS["count_opt_outs"] - columns_assigned: research_opt_out - - hospital_visit: - num_rows_per_pass: 3 - custom_generators: - - name: custom_generators.timespan_generator - args: - generic: generic - earliest_start_year: 2021 - last_start_year: 2022 - min_dt_days: 1 - max_dt_days: 30 - columns_assigned: - - visit_start - - visit_end - - visit_duration_seconds - concept: - vocabulary_table: true diff --git a/tests/test_functional.py b/tests/test_functional.py index 82e3150e..ad546f36 100644 --- a/tests/test_functional.py +++ b/tests/test_functional.py @@ -18,7 +18,7 @@ class FunctionalTestCase(RequiresDBTestCase): alt_ssg_file_path = Path("my_ssg.py") concept_file_path = Path("concept.csv") - config_file_path = Path("../examples/functional_conf.yaml") + config_file_path = Path("../examples/example_config.yaml") stats_file_path = Path("example_stats.yaml") test_dir = Path("tests/workspace") @@ -65,7 +65,7 @@ def test_workflow_minimal_args(self) -> None: capture_output=True, env=self.env, ) - self.assertSuccess(completed_process.returncode) + self.assertSuccess(completed_process) completed_process = run( ["sqlsynthgen", "make-generators"], diff --git a/tests/test_main.py b/tests/test_main.py index 91826f8f..3ca58610 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -173,7 +173,7 @@ def test_make_tables_errors_if_file_exists( def test_make_stats(self) -> None: """Test the make-stats sub-command.""" - example_conf_path = "tests/examples/generator_conf.yaml" + example_conf_path = "tests/examples/example_config.yaml" with patch("sqlsynthgen.main.make_src_stats") as mock_make, patch( "sqlsynthgen.main.get_settings" ) as mock_get_settings: diff --git a/tests/test_make.py b/tests/test_make.py index a619384e..8c98f316 100644 --- a/tests/test_make.py +++ b/tests/test_make.py @@ -36,7 +36,7 @@ def test_make_generators_from_tables( """Check that we can make a generators file from a tables module.""" with open("expected_ssg.py", encoding="utf-8") as expected_output: expected = expected_output.read() - conf_path = "generator_conf.yaml" + conf_path = "example_config.yaml" with open(conf_path, "r", encoding="utf8") as f: config = yaml.safe_load(f) stats_path = "example_stats.yaml" @@ -126,7 +126,7 @@ def test_make_tables_warns_no_pk( def test_make_stats(self) -> None: """Test the make_src_stats function.""" - conf_path = "generator_conf.yaml" + conf_path = "example_config.yaml" with open(conf_path, "r", encoding="utf8") as f: config = yaml.safe_load(f) From f3abee77b7ed00a6d8ed6402f80c8aefc80ad960 Mon Sep 17 00:00:00 2001 From: Markus Hauru Date: Thu, 2 Mar 2023 16:37:29 +0000 Subject: [PATCH 08/15] Deal with existing stats files gracefully --- sqlsynthgen/main.py | 6 +++- sqlsynthgen/make.py | 3 +- tests/test_functional.py | 1 + tests/test_main.py | 70 ++++++++++++++++++++++++++++------------ 4 files changed, 57 insertions(+), 23 deletions(-) diff --git a/sqlsynthgen/main.py b/sqlsynthgen/main.py index 7ca546d4..82a511d0 100644 --- a/sqlsynthgen/main.py +++ b/sqlsynthgen/main.py @@ -136,12 +136,16 @@ def make_stats( Example: $ sqlsynthgen make_stats --config-file=example_config.yaml """ + stats_file_path = Path(stats_file) + if stats_file_path.exists(): + print(f"{stats_file} should not already exist. Exiting...", file=stderr) + sys.exit(1) settings = get_settings() generator_config = read_yaml_file(config_file) if config_file is not None else {} src_dsn = settings.src_postgres_dsn if src_dsn is None: raise ValueError("Missing source database connection details.") - make_src_stats(src_dsn, generator_config, stats_file) + make_src_stats(src_dsn, generator_config, stats_file_path) @app.command() diff --git a/sqlsynthgen/make.py b/sqlsynthgen/make.py index bcc0fe48..b27e1011 100644 --- a/sqlsynthgen/make.py +++ b/sqlsynthgen/make.py @@ -1,6 +1,7 @@ """Functions to make a module of generator classes.""" import inspect import sys +from pathlib import Path from subprocess import CalledProcessError, run from sys import stderr from types import ModuleType @@ -237,7 +238,7 @@ def make_tables_file( def make_src_stats( - dsn: Union[PostgresDsn, str], config: dict, stats_filename: str + dsn: Union[PostgresDsn, str], config: dict, stats_filename: Path ) -> dict: """Run the src-stats queries specified by the configuration. diff --git a/tests/test_functional.py b/tests/test_functional.py index ad546f36..b51bab69 100644 --- a/tests/test_functional.py +++ b/tests/test_functional.py @@ -52,6 +52,7 @@ def setUp(self) -> None: self.alt_orm_file_path, self.alt_ssg_file_path, self.concept_file_path, + self.stats_file_path, ): file_path.unlink(missing_ok=True) diff --git a/tests/test_main.py b/tests/test_main.py index 3ca58610..3322b524 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,5 +1,6 @@ """Tests for the main module.""" from io import StringIO +from pathlib import Path from unittest.mock import MagicMock, call, patch import yaml @@ -171,26 +172,53 @@ def test_make_tables_errors_if_file_exists( ) self.assertEqual(1, result.exit_code) - def test_make_stats(self) -> None: + @patch("sqlsynthgen.main.Path") + @patch("sqlsynthgen.main.make_src_stats") + @patch("sqlsynthgen.main.get_settings") + def test_make_stats( + self, mock_get_settings: MagicMock, mock_make: MagicMock, mock_path: MagicMock + ) -> None: """Test the make-stats sub-command.""" example_conf_path = "tests/examples/example_config.yaml" - with patch("sqlsynthgen.main.make_src_stats") as mock_make, patch( - "sqlsynthgen.main.get_settings" - ) as mock_get_settings: - mock_get_settings.return_value = get_test_settings() - output_path = "make_stats_output.yaml" - result = runner.invoke( - app, - [ - "make-stats", - f"--stats-file={output_path}", - f"--config-file={example_conf_path}", - ], - catch_exceptions=False, - ) - self.assertSuccess(result) - with open(example_conf_path, "r", encoding="utf8") as f: - config = yaml.safe_load(f) - mock_make.assert_called_once_with( - get_test_settings().src_postgres_dsn, config, output_path - ) + output_path = Path("make_stats_output.yaml") + mock_path.return_value.exists.return_value = False + mock_get_settings.return_value = get_test_settings() + result = runner.invoke( + app, + [ + "make-stats", + f"--stats-file={output_path}", + f"--config-file={example_conf_path}", + ], + catch_exceptions=False, + ) + self.assertSuccess(result) + with open(example_conf_path, "r", encoding="utf8") as f: + config = yaml.safe_load(f) + mock_make.assert_called_once_with( + get_test_settings().src_postgres_dsn, config, mock_path.return_value + ) + + @patch("sqlsynthgen.main.Path") + @patch("sqlsynthgen.main.stderr", new_callable=StringIO) + def test_make_stats_errors_if_file_exists( + self, mock_stderr: MagicMock, mock_path: MagicMock + ) -> None: + """Test the make-stats sub-command when the stats file already exists.""" + mock_path.return_value.exists.return_value = True + example_conf_path = "tests/examples/example_config.yaml" + output_path = "make_stats_output.yaml" + result = runner.invoke( + app, + [ + "make-stats", + f"--stats-file={output_path}", + f"--config-file={example_conf_path}", + ], + catch_exceptions=False, + ) + self.assertEqual( + f"{output_path} should not already exist. Exiting...\n", + mock_stderr.getvalue(), + ) + self.assertEqual(1, result.exit_code) From 459db26ca9805c240fa79fea524487fb6ce31980 Mon Sep 17 00:00:00 2001 From: Markus Hauru Date: Thu, 2 Mar 2023 16:40:04 +0000 Subject: [PATCH 09/15] Use @patch in test_make_stats --- tests/test_make.py | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/tests/test_make.py b/tests/test_make.py index 8c98f316..2cf16dea 100644 --- a/tests/test_make.py +++ b/tests/test_make.py @@ -124,22 +124,20 @@ def test_make_tables_warns_no_pk( mock_stderr.getvalue(), ) - def test_make_stats(self) -> None: + @patch("sqlsynthgen.make.yaml") + def test_make_stats(self, mock_yaml: MagicMock) -> None: """Test the make_src_stats function.""" - conf_path = "example_config.yaml" + connection_string = "postgresql://postgres:password@localhost:5432/src" + output_file = Path("/tmp/tmp_test_file.yaml") + conf_path = Path("example_config.yaml") with open(conf_path, "r", encoding="utf8") as f: config = yaml.safe_load(f) - - with patch("sqlsynthgen.make.yaml") as mock_yaml: - connection_string = "postgresql://postgres:password@localhost:5432/src" - src_stats = make.make_src_stats( - connection_string, config, "/tmp/tmp_test_file.yaml" - ) - mock_yaml.dump.assert_called_once() - assert set(src_stats.keys()) == set(["count_opt_outs"]) - count_opt_outs = src_stats["count_opt_outs"] - assert len(count_opt_outs) == 2 - assert isinstance(count_opt_outs[0][0], int) - assert count_opt_outs[0][1] is False - assert isinstance(count_opt_outs[1][0], int) - assert count_opt_outs[1][1] is True + src_stats = make.make_src_stats(connection_string, config, output_file) + mock_yaml.dump.assert_called_once() + assert set(src_stats.keys()) == set(["count_opt_outs"]) + count_opt_outs = src_stats["count_opt_outs"] + assert len(count_opt_outs) == 2 + assert isinstance(count_opt_outs[0][0], int) + assert count_opt_outs[0][1] is False + assert isinstance(count_opt_outs[1][0], int) + assert count_opt_outs[1][1] is True From 1da8795f821d77c83ef8422c2bdf87a735566e27 Mon Sep 17 00:00:00 2001 From: Markus Hauru Date: Mon, 6 Mar 2023 10:15:23 +0000 Subject: [PATCH 10/15] Apply suggestions from code review Co-authored-by: Iain <25081046+Iain-S@users.noreply.github.com> --- sqlsynthgen/make.py | 2 +- tests/test_make.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sqlsynthgen/make.py b/sqlsynthgen/make.py index b27e1011..9ec8e19e 100644 --- a/sqlsynthgen/make.py +++ b/sqlsynthgen/make.py @@ -146,7 +146,7 @@ def make_generators_from_tables( Args: tables_module: A sqlacodegen-generated module. generator_config: Configuration to control the generator creation. - src_stats_file_name: A filename for where to read src stats from. Optional, if + src_stats_filename: A filename for where to read src stats from. Optional, if `None` this feature will be skipped Returns: diff --git a/tests/test_make.py b/tests/test_make.py index 2cf16dea..b902db0a 100644 --- a/tests/test_make.py +++ b/tests/test_make.py @@ -134,7 +134,7 @@ def test_make_stats(self, mock_yaml: MagicMock) -> None: config = yaml.safe_load(f) src_stats = make.make_src_stats(connection_string, config, output_file) mock_yaml.dump.assert_called_once() - assert set(src_stats.keys()) == set(["count_opt_outs"]) + self.assertSetEqual({"count_opt_outs"}, set(src_stats.keys()) count_opt_outs = src_stats["count_opt_outs"] assert len(count_opt_outs) == 2 assert isinstance(count_opt_outs[0][0], int) From 078eb4aaa1ff0b717b435a9d395dd5b61faf0d5e Mon Sep 17 00:00:00 2001 From: Markus Hauru Date: Mon, 6 Mar 2023 10:19:05 +0000 Subject: [PATCH 11/15] Make make stats config_file mandatory Co-authored-by: Iain <25081046+Iain-S@users.noreply.github.com> --- sqlsynthgen/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlsynthgen/main.py b/sqlsynthgen/main.py index 82a511d0..81ac1ae4 100644 --- a/sqlsynthgen/main.py +++ b/sqlsynthgen/main.py @@ -128,7 +128,7 @@ def make_generators( @app.command() def make_stats( - config_file: str = typer.Option(None), + config_file: str = typer.Option(...), stats_file: str = typer.Option(STATS_FILENAME), ) -> None: """Compute summary statistics from the source database, write them to a YAML file. From 121e9b9099ebb3d9910e21b3ca9bf4d5f8705863 Mon Sep 17 00:00:00 2001 From: Markus Hauru Date: Mon, 6 Mar 2023 10:38:37 +0000 Subject: [PATCH 12/15] Respond to review feedback --- sqlsynthgen/providers.py | 13 ++----------- tests/test_make.py | 12 ++++++------ tests/test_providers.py | 27 +++++++++++++++------------ 3 files changed, 23 insertions(+), 29 deletions(-) diff --git a/sqlsynthgen/providers.py b/sqlsynthgen/providers.py index 4f36478b..5640fcdd 100644 --- a/sqlsynthgen/providers.py +++ b/sqlsynthgen/providers.py @@ -1,10 +1,9 @@ """This module contains Mimesis Provider sub-classes.""" import datetime as dt import random -from typing import Any, Optional +from typing import Any from mimesis import Datetime, Text -from mimesis import random as mimesis_random from mimesis.providers.base import BaseDataProvider, BaseProvider from sqlalchemy.sql import func, select @@ -88,14 +87,6 @@ def timespan( class WeightedBooleanProvider(BaseProvider): """A Mimesis provider for booleans with a given probability for True.""" - def __init__(self, seed: Optional[int] = None) -> None: - """Initialize a WeightedBooleanProvider. Optionally a seed can be provided.""" - if seed is not None: - self.rand = mimesis_random.Random(seed) - else: - self.rand = mimesis_random.Random() - super().__init__() - class Meta: """Meta-class for WeightedBooleanProvider settings.""" @@ -103,4 +94,4 @@ class Meta: def bool(self, probability: float) -> bool: """Return True with given `probability`, otherwise False.""" - return self.rand.uniform(0, 1) < probability + return self.random.uniform(0, 1) < probability diff --git a/tests/test_make.py b/tests/test_make.py index b902db0a..9e2b0b9b 100644 --- a/tests/test_make.py +++ b/tests/test_make.py @@ -134,10 +134,10 @@ def test_make_stats(self, mock_yaml: MagicMock) -> None: config = yaml.safe_load(f) src_stats = make.make_src_stats(connection_string, config, output_file) mock_yaml.dump.assert_called_once() - self.assertSetEqual({"count_opt_outs"}, set(src_stats.keys()) + self.assertSetEqual({"count_opt_outs"}, set(src_stats.keys())) count_opt_outs = src_stats["count_opt_outs"] - assert len(count_opt_outs) == 2 - assert isinstance(count_opt_outs[0][0], int) - assert count_opt_outs[0][1] is False - assert isinstance(count_opt_outs[1][0], int) - assert count_opt_outs[1][1] is True + self.assertEqual(len(count_opt_outs), 2) + self.assertIsInstance(count_opt_outs[0][0], int) + self.assertIs(count_opt_outs[0][1], False) + self.assertIsInstance(count_opt_outs[1][0], int) + self.assertIs(count_opt_outs[1][1], True) diff --git a/tests/test_providers.py b/tests/test_providers.py index a142bcfe..6ccb9ecf 100644 --- a/tests/test_providers.py +++ b/tests/test_providers.py @@ -69,8 +69,9 @@ def test_timedelta(self) -> None: min_dt = dt.timedelta(days=1) max_dt = dt.timedelta(days=2) delta = providers.TimedeltaProvider().timedelta(min_dt=min_dt, max_dt=max_dt) - assert isinstance(delta, dt.timedelta) - assert min_dt <= delta <= max_dt + self.assertIsInstance(delta, dt.timedelta) + self.assertLessEqual(min_dt, delta) + self.assertLessEqual(delta, max_dt) class TimespanProvider(SSGTestCase): @@ -85,12 +86,14 @@ def test_timespan(self) -> None: start, end, delta = providers.TimespanProvider().timespan( earliest_start_year, last_start_year, min_dt, max_dt ) - assert isinstance(start, dt.datetime) - assert isinstance(end, dt.datetime) - assert isinstance(delta, dt.timedelta) - assert earliest_start_year <= start.year <= last_start_year - assert min_dt <= delta <= max_dt - assert end - start == delta + self.assertIsInstance(start, dt.datetime) + self.assertIsInstance(end, dt.datetime) + self.assertIsInstance(delta, dt.timedelta) + self.assertLessEqual(earliest_start_year, start.year) + self.assertLessEqual(start.year, last_start_year) + self.assertLessEqual(min_dt, delta) + self.assertLessEqual(delta, max_dt) + self.assertEqual(end - start, delta) class TestWeightedBooleanProvider(SSGTestCase): @@ -98,15 +101,15 @@ class TestWeightedBooleanProvider(SSGTestCase): def test_bool(self) -> None: """Test the bool method""" - assert not providers.WeightedBooleanProvider().bool(0.0) - assert providers.WeightedBooleanProvider().bool(1.0) + self.assertFalse(providers.WeightedBooleanProvider().bool(0.0)) + self.assertTrue(providers.WeightedBooleanProvider().bool(1.0)) seed = 0 num_repeats = 10000 - prov = providers.WeightedBooleanProvider(seed) + prov = providers.WeightedBooleanProvider(seed=seed) for probability in (0.1, 0.5, 0.9): bools = [prov.bool(probability) for _ in range(num_repeats)] trues = sum(bools) falses = sum(not x for x in bools) expected_odds = probability / (1 - probability) observed_odds = trues / falses - assert abs(observed_odds / expected_odds - 1.0) < 0.1 + self.assertLess(abs(observed_odds / expected_odds - 1.0), 0.1) From fc6334f9aa7cf5ceba92499c21e2f4a31150023d Mon Sep 17 00:00:00 2001 From: Markus Hauru Date: Mon, 6 Mar 2023 17:16:51 +0000 Subject: [PATCH 13/15] Adjust example epsilon and delta --- tests/examples/example_config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/examples/example_config.yaml b/tests/examples/example_config.yaml index 13f10a71..951b801e 100644 --- a/tests/examples/example_config.yaml +++ b/tests/examples/example_config.yaml @@ -12,8 +12,8 @@ opendp: src-stats: - name: count_opt_outs query: SELECT count(*) AS num, research_opt_out FROM person GROUP BY research_opt_out - epsilon: 1.0 - delta: 0.1 + epsilon: 0.1 + delta: 0.0001 custom_generators_module: custom_generators tables: person: From f0c1e4ce98da24e62864691966a315d739352c66 Mon Sep 17 00:00:00 2001 From: Markus Hauru Date: Wed, 8 Mar 2023 09:54:24 +0000 Subject: [PATCH 14/15] Respond to review feedback. --- sqlsynthgen/main.py | 4 +++- sqlsynthgen/make.py | 25 +++++++------------------ tests/examples/example_config.yaml | 2 +- tests/test_main.py | 6 ++++-- tests/test_make.py | 7 ++----- 5 files changed, 17 insertions(+), 27 deletions(-) diff --git a/sqlsynthgen/main.py b/sqlsynthgen/main.py index 81ac1ae4..b592c4e9 100644 --- a/sqlsynthgen/main.py +++ b/sqlsynthgen/main.py @@ -5,6 +5,7 @@ from typing import Final, Optional import typer +import yaml from sqlsynthgen.create import create_db_data, create_db_tables, create_db_vocab from sqlsynthgen.make import ( @@ -145,7 +146,8 @@ def make_stats( src_dsn = settings.src_postgres_dsn if src_dsn is None: raise ValueError("Missing source database connection details.") - make_src_stats(src_dsn, generator_config, stats_file_path) + src_stats = make_src_stats(src_dsn, generator_config) + stats_file_path.write_text(yaml.dump(src_stats), encoding="utf-8") @app.command() diff --git a/sqlsynthgen/make.py b/sqlsynthgen/make.py index 9ec8e19e..c9733f71 100644 --- a/sqlsynthgen/make.py +++ b/sqlsynthgen/make.py @@ -1,16 +1,13 @@ """Functions to make a module of generator classes.""" import inspect import sys -from pathlib import Path from subprocess import CalledProcessError, run from sys import stderr from types import ModuleType -from typing import Any, Final, Optional, Union +from typing import Any, Final, Optional import snsql -import yaml from mimesis.providers.base import BaseProvider -from pydantic import PostgresDsn # pylint: disable=no-name-in-module from sqlalchemy import create_engine from sqlalchemy.sql import sqltypes @@ -204,9 +201,7 @@ def make_generators_from_tables( return new_content -def make_tables_file( - db_dsn: Union[PostgresDsn, str], schema_name: Optional[str] -) -> str: +def make_tables_file(db_dsn: str, schema_name: Optional[str]) -> str: """Write a file with the SQLAlchemy ORM classes. Exists with an error if sqlacodegen is unsuccessful. @@ -237,26 +232,22 @@ def make_tables_file( return completed_process.stdout -def make_src_stats( - dsn: Union[PostgresDsn, str], config: dict, stats_filename: Path -) -> dict: +def make_src_stats(dsn: str, config: dict) -> dict: """Run the src-stats queries specified by the configuration. Query the src database with the queries in the src-stats block of the `config` - dictionary, using the differential privacy parameters set in the `opendp` block of - `config`. Record the results in a dictionary and return it, but also write them to a - YAML file called `stats_filename`. - + dictionary, using the differential privacy parameters set in the `smartnoise-sql` + block of `config`. Record the results in a dictionary and returns it. Args: dsn: postgres connection string config: a dictionary with the necessary configuration stats_filename: path to the YAML file to write the output to Returns: - The dictionary of src-stats, thats is also written to `stats_filename`. + The dictionary of src-stats. """ engine = create_engine(dsn, echo=False, future=True) - dp_config = config.get("opendp", {}) + dp_config = config.get("smartnoise-sql", {}) snsql_metadata = {"": dp_config} src_stats = {} for stat_data in config.get("src-stats", []): @@ -271,6 +262,4 @@ def make_src_stats( private_result = reader.execute(stat_data["query"]) # The first entry in the list names the columns, skip that. src_stats[stat_data["name"]] = private_result[1:] - with open(stats_filename, "w", encoding="utf-8") as f: - yaml.dump(src_stats, f) return src_stats diff --git a/tests/examples/example_config.yaml b/tests/examples/example_config.yaml index 951b801e..454a3138 100644 --- a/tests/examples/example_config.yaml +++ b/tests/examples/example_config.yaml @@ -1,4 +1,4 @@ -opendp: +smartnoise-sql: public: person: person_id: diff --git a/tests/test_main.py b/tests/test_main.py index 3322b524..cbaf0945 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -182,6 +182,7 @@ def test_make_stats( example_conf_path = "tests/examples/example_config.yaml" output_path = Path("make_stats_output.yaml") mock_path.return_value.exists.return_value = False + mock_make.return_value = {"a": 1} mock_get_settings.return_value = get_test_settings() result = runner.invoke( app, @@ -195,8 +196,9 @@ def test_make_stats( self.assertSuccess(result) with open(example_conf_path, "r", encoding="utf8") as f: config = yaml.safe_load(f) - mock_make.assert_called_once_with( - get_test_settings().src_postgres_dsn, config, mock_path.return_value + mock_make.assert_called_once_with(get_test_settings().src_postgres_dsn, config) + mock_path.return_value.write_text.assert_called_once_with( + "a: 1\n", encoding="utf-8" ) @patch("sqlsynthgen.main.Path") diff --git a/tests/test_make.py b/tests/test_make.py index 9e2b0b9b..9f3d2498 100644 --- a/tests/test_make.py +++ b/tests/test_make.py @@ -124,16 +124,13 @@ def test_make_tables_warns_no_pk( mock_stderr.getvalue(), ) - @patch("sqlsynthgen.make.yaml") - def test_make_stats(self, mock_yaml: MagicMock) -> None: + def test_make_stats(self) -> None: """Test the make_src_stats function.""" connection_string = "postgresql://postgres:password@localhost:5432/src" - output_file = Path("/tmp/tmp_test_file.yaml") conf_path = Path("example_config.yaml") with open(conf_path, "r", encoding="utf8") as f: config = yaml.safe_load(f) - src_stats = make.make_src_stats(connection_string, config, output_file) - mock_yaml.dump.assert_called_once() + src_stats = make.make_src_stats(connection_string, config) self.assertSetEqual({"count_opt_outs"}, set(src_stats.keys())) count_opt_outs = src_stats["count_opt_outs"] self.assertEqual(len(count_opt_outs), 2) From 3ee78ac0c1119bb733d91a4cae53f1d953d7d319 Mon Sep 17 00:00:00 2001 From: Markus Hauru Date: Wed, 8 Mar 2023 10:04:12 +0000 Subject: [PATCH 15/15] Silence smartnoise-sql nag in tests --- tests/examples/example_config.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/examples/example_config.yaml b/tests/examples/example_config.yaml index 454a3138..b252c544 100644 --- a/tests/examples/example_config.yaml +++ b/tests/examples/example_config.yaml @@ -1,6 +1,9 @@ smartnoise-sql: public: person: + # You may well want censor_dims to be on, but we turn it off for the + # tests to silence a smartnoise-sql nag warning. + censor_dims: False person_id: name: person_id type: int