From 6db2fa59b969166cc8eaf63f003563244d071ce1 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Fri, 24 Sep 2021 16:01:03 +0100 Subject: [PATCH 01/63] adding initial skeleton --- .gitignore | 140 ++++++++++++++++++++++ analyse_properties/__init__.py | 1 + poetry.lock | 206 +++++++++++++++++++++++++++++++++ pyproject.toml | 15 +++ 4 files changed, 362 insertions(+) create mode 100644 .gitignore create mode 100644 analyse_properties/__init__.py create mode 100644 poetry.lock create mode 100644 pyproject.toml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fdf691 --- /dev/null +++ b/.gitignore @@ -0,0 +1,140 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + + diff --git a/analyse_properties/__init__.py b/analyse_properties/__init__.py new file mode 100644 index 0000000..b794fd4 --- /dev/null +++ b/analyse_properties/__init__.py @@ -0,0 +1 @@ +__version__ = '0.1.0' diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..9b8d156 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,206 @@ +[[package]] +name = "atomicwrites" +version = "1.4.0" +description = "Atomic file writes." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "attrs" +version = "21.2.0" +description = "Classes Without Boilerplate" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.extras] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"] +docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] + +[[package]] +name = "colorama" +version = "0.4.4" +description = "Cross-platform colored terminal text." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "importlib-metadata" +version = "4.8.1" +description = "Read metadata from Python packages" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} +zipp = ">=0.5" + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +perf = ["ipython"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] + +[[package]] +name = "more-itertools" +version = "8.10.0" +description = "More routines for operating on iterables, beyond itertools" +category = "dev" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "packaging" +version = "21.0" +description = "Core utilities for Python packages" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pyparsing = ">=2.0.2" + +[[package]] +name = "pluggy" +version = "0.13.1" +description = "plugin and hook calling mechanisms for python" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.dependencies] +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} + +[package.extras] +dev = ["pre-commit", "tox"] + +[[package]] +name = "py" +version = "1.10.0" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "pyparsing" +version = "2.4.7" +description = "Python parsing module" +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "pytest" +version = "5.4.3" +description = "pytest: simple powerful testing with Python" +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.dependencies] +atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} +attrs = ">=17.4.0" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} +more-itertools = ">=4.0.0" +packaging = "*" +pluggy = ">=0.12,<1.0" +py = ">=1.5.0" +wcwidth = "*" + +[package.extras] +checkqa-mypy = ["mypy (==v0.761)"] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] + +[[package]] +name = "typing-extensions" +version = "3.10.0.2" +description = "Backported and Experimental Type Hints for Python 3.5+" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "wcwidth" +version = "0.2.5" +description = "Measures the displayed width of unicode strings in a terminal" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "zipp" +version = "3.5.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] + +[metadata] +lock-version = "1.1" +python-versions = "^3.7" +content-hash = "4160ff5d9a3716f3a05ea05072168b2f442f81ce0c14e25cb50bfd21cf2b9ee0" + +[metadata.files] +atomicwrites = [ + {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, + {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, +] +attrs = [ + {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, + {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, +] +colorama = [ + {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, + {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, +] +importlib-metadata = [ + {file = "importlib_metadata-4.8.1-py3-none-any.whl", hash = "sha256:b618b6d2d5ffa2f16add5697cf57a46c76a56229b0ed1c438322e4e95645bd15"}, + {file = "importlib_metadata-4.8.1.tar.gz", hash = "sha256:f284b3e11256ad1e5d03ab86bb2ccd6f5339688ff17a4d797a0fe7df326f23b1"}, +] +more-itertools = [ + {file = "more-itertools-8.10.0.tar.gz", hash = "sha256:1debcabeb1df793814859d64a81ad7cb10504c24349368ccf214c664c474f41f"}, + {file = "more_itertools-8.10.0-py3-none-any.whl", hash = "sha256:56ddac45541718ba332db05f464bebfb0768110111affd27f66e0051f276fa43"}, +] +packaging = [ + {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"}, + {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"}, +] +pluggy = [ + {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, + {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, +] +py = [ + {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, + {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, +] +pyparsing = [ + {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, + {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, +] +pytest = [ + {file = "pytest-5.4.3-py3-none-any.whl", hash = "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1"}, + {file = "pytest-5.4.3.tar.gz", hash = "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8"}, +] +typing-extensions = [ + {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, + {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, + {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, +] +wcwidth = [ + {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, + {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, +] +zipp = [ + {file = "zipp-3.5.0-py3-none-any.whl", hash = "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3"}, + {file = "zipp-3.5.0.tar.gz", hash = "sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4"}, +] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..b7a0004 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,15 @@ +[tool.poetry] +name = "analyse_properties" +version = "0.1.0" +description = "" +authors = ["Daniel Tomlinson "] + +[tool.poetry.dependencies] +python = "^3.7" + +[tool.poetry.dev-dependencies] +pytest = "^5.2" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" From 5301d5ff04db7399eea27db9fe2929b99457f1ba Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Fri, 24 Sep 2021 16:51:56 +0100 Subject: [PATCH 02/63] updating .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4fdf691..e220705 100644 --- a/.gitignore +++ b/.gitignore @@ -137,4 +137,5 @@ dmypy.json # Cython debug symbols cython_debug/ - +# USER +data/ From 972d0a852ad930346ddfdac59b559d7599bcda70 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Fri, 24 Sep 2021 16:52:25 +0100 Subject: [PATCH 03/63] updating dev dependencies --- poetry.lock | 1319 +++++++++++++++++++++++++++++++++++++++++++++--- pyproject.toml | 4 +- 2 files changed, 1256 insertions(+), 67 deletions(-) diff --git a/poetry.lock b/poetry.lock index 9b8d156..48c24b8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,10 +1,16 @@ [[package]] -name = "atomicwrites" -version = "1.4.0" -description = "Atomic file writes." +name = "astroid" +version = "2.8.0" +description = "An abstract syntax tree for Python with inference support." category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = "~=3.6" + +[package.dependencies] +lazy-object-proxy = ">=1.4.0" +typed-ast = {version = ">=1.4.0,<1.5", markers = "implementation_name == \"cpython\" and python_version < \"3.8\""} +typing-extensions = {version = ">=3.10", markers = "python_version < \"3.10\""} +wrapt = ">=1.11,<1.13" [[package]] name = "attrs" @@ -20,6 +26,39 @@ docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] +[[package]] +name = "bottleneck" +version = "1.3.2" +description = "Fast NumPy array functions written in C" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +numpy = "*" + +[package.extras] +doc = ["numpydoc", "sphinx", "gitpython"] + +[[package]] +name = "certifi" +version = "2021.5.30" +description = "Python package for providing Mozilla's CA Bundle." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "charset-normalizer" +version = "2.0.6" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "dev" +optional = false +python-versions = ">=3.5.0" + +[package.extras] +unicode_backport = ["unicodedata2"] + [[package]] name = "colorama" version = "0.4.4" @@ -28,6 +67,81 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +[[package]] +name = "cycler" +version = "0.10.0" +description = "Composable style cycles" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +six = "*" + +[[package]] +name = "dodgy" +version = "0.2.1" +description = "Dodgy: Searches for dodgy looking lines in Python code" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "flake8" +version = "3.9.2" +description = "the modular source code checker: pep8 pyflakes and co" +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + +[package.dependencies] +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} +mccabe = ">=0.6.0,<0.7.0" +pycodestyle = ">=2.7.0,<2.8.0" +pyflakes = ">=2.3.0,<2.4.0" + +[[package]] +name = "flake8-polyfill" +version = "1.0.2" +description = "Polyfill package for Flake8 plugins" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +flake8 = "*" + +[[package]] +name = "htmlmin" +version = "0.1.12" +description = "An HTML Minifier" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "idna" +version = "3.2" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "dev" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "imagehash" +version = "4.2.1" +description = "Image Hashing library" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +numpy = "*" +pillow = "*" +PyWavelets = "*" +scipy = "*" +six = "*" + [[package]] name = "importlib-metadata" version = "4.8.1" @@ -46,46 +160,380 @@ perf = ["ipython"] testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] [[package]] -name = "more-itertools" -version = "8.10.0" -description = "More routines for operating on iterables, beyond itertools" +name = "isort" +version = "5.9.3" +description = "A Python utility / library to sort Python imports." category = "dev" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6.1,<4.0" + +[package.extras] +pipfile_deprecated_finder = ["pipreqs", "requirementslib"] +requirements_deprecated_finder = ["pipreqs", "pip-api"] +colors = ["colorama (>=0.4.3,<0.5.0)"] +plugins = ["setuptools"] [[package]] -name = "packaging" -version = "21.0" -description = "Core utilities for Python packages" +name = "jinja2" +version = "3.0.1" +description = "A very fast and expressive template engine." category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] -pyparsing = ">=2.0.2" - -[[package]] -name = "pluggy" -version = "0.13.1" -description = "plugin and hook calling mechanisms for python" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[package.dependencies] -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} +MarkupSafe = ">=2.0" [package.extras] -dev = ["pre-commit", "tox"] +i18n = ["Babel (>=2.7)"] [[package]] -name = "py" -version = "1.10.0" -description = "library with cross-python path, ini-parsing, io, code, log facilities" +name = "joblib" +version = "1.0.1" +description = "Lightweight pipelining with Python functions" +category = "dev" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "kiwisolver" +version = "1.3.2" +description = "A fast implementation of the Cassowary constraint solver" +category = "dev" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "lazy-object-proxy" +version = "1.6.0" +description = "A fast and thorough lazy object proxy." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[[package]] +name = "markupsafe" +version = "2.0.1" +description = "Safely add untrusted strings to HTML/XML markup." +category = "dev" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "matplotlib" +version = "3.4.3" +description = "Python plotting package" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +cycler = ">=0.10" +kiwisolver = ">=1.0.1" +numpy = ">=1.16" +pillow = ">=6.2.0" +pyparsing = ">=2.2.1" +python-dateutil = ">=2.7" + +[[package]] +name = "mccabe" +version = "0.6.1" +description = "McCabe checker, plugin for flake8" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "missingno" +version = "0.5.0" +description = "Missing data visualization module for Python." +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +matplotlib = "*" +numpy = "*" +scipy = "*" +seaborn = "*" + +[package.extras] +tests = ["pytest", "pytest-mpl"] + +[[package]] +name = "multimethod" +version = "1.4" +description = "Multiple argument dispatching." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +docs = ["recommonmark", "nbsphinx", "jupyter", "sphinx"] + +[[package]] +name = "networkx" +version = "2.6.3" +description = "Python package for creating and manipulating graphs and networks" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.extras] +default = ["numpy (>=1.19)", "scipy (>=1.5,!=1.6.1)", "matplotlib (>=3.3)", "pandas (>=1.1)"] +developer = ["black (==21.5b1)", "pre-commit (>=2.12)"] +doc = ["sphinx (>=4.0,<5.0)", "pydata-sphinx-theme (>=0.6,<1.0)", "sphinx-gallery (>=0.9,<1.0)", "numpydoc (>=1.1)", "pillow (>=8.2)", "nb2plots (>=0.6)", "texext (>=0.6.6)"] +extra = ["lxml (>=4.5)", "pygraphviz (>=1.7)", "pydot (>=1.4.1)"] +test = ["pytest (>=6.2)", "pytest-cov (>=2.12)", "codecov (>=2.1)"] + +[[package]] +name = "numpy" +version = "1.21.1" +description = "NumPy is the fundamental package for array computing with Python." +category = "dev" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "pandas" +version = "1.1.5" +description = "Powerful data structures for data analysis, time series, and statistics" +category = "dev" +optional = false +python-versions = ">=3.6.1" + +[package.dependencies] +numpy = ">=1.15.4" +python-dateutil = ">=2.7.3" +pytz = ">=2017.2" + +[package.extras] +test = ["pytest (>=4.0.2)", "pytest-xdist", "hypothesis (>=3.58)"] + +[[package]] +name = "pandas-profiling" +version = "3.0.0" +description = "Generate profile report for pandas DataFrame" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +htmlmin = ">=0.1.12" +jinja2 = ">=2.11.1" +joblib = "*" +matplotlib = ">=3.2.0" +missingno = ">=0.4.2" +numpy = ">=1.16.0" +pandas = ">=0.25.3,<1.0.0 || >1.0.0,<1.0.1 || >1.0.1,<1.0.2 || >1.0.2,<1.1.0 || >1.1.0" +phik = ">=0.11.1" +pydantic = ">=1.8.1" +PyYAML = ">=5.0.0" +requests = ">=2.24.0" +scipy = ">=1.4.1" +seaborn = ">=0.10.1" +tangled-up-in-unicode = "0.1.0" +tqdm = ">=4.48.2" +visions = {version = "0.7.1", extras = ["type_image_path"]} + +[package.extras] +notebook = ["jupyter-client (>=6.0.0)", "jupyter-core (>=4.6.3)", "ipywidgets (>=7.5.1)"] + +[[package]] +name = "pep8-naming" +version = "0.10.0" +description = "Check PEP-8 naming conventions, plugin for flake8" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +flake8-polyfill = ">=1.0.2,<2" + +[[package]] +name = "phik" +version = "0.12.0" +description = "Phi_K correlation analyzer library" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +joblib = ">=0.14.1" +matplotlib = ">=2.2.3" +numpy = ">=1.18.0" +pandas = ">=0.25.1" +scipy = ">=1.5.2" + +[package.extras] +test = ["pytest (>=4.0.2)", "pytest-pylint (>=0.13.0)", "nbconvert (>=5.3.1)", "jupyter-client (>=5.2.3)"] + +[[package]] +name = "pillow" +version = "8.3.2" +description = "Python Imaging Library (Fork)" +category = "dev" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "platformdirs" +version = "2.3.0" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] +test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] + +[[package]] +name = "prospector" +version = "1.5.1" +description = "" +category = "dev" +optional = false +python-versions = ">=3.6.1,<4.0" + +[package.dependencies] +dodgy = ">=0.2.1,<0.3.0" +mccabe = ">=0.6.0,<0.7.0" +pep8-naming = ">=0.3.3,<=0.10.0" +pycodestyle = ">=2.6.0,<2.9.0" +pydocstyle = ">=2.0.0" +pyflakes = ">=2.2.0,<2.4.0" +pylint = ">=2.8.3,<3" +pylint-celery = "0.3" +pylint-django = ">=2.4.4,<3.0.0" +pylint-flask = "0.6" +pylint-plugin-utils = ">=0.6,<0.7" +PyYAML = "*" +requirements-detector = ">=0.7,<0.8" +setoptconf-tmp = ">=0.3.1,<0.4.0" +toml = ">=0.10.2,<0.11.0" + +[package.extras] +with_bandit = ["bandit (>=1.5.1)"] +with_everything = ["bandit (>=1.5.1)", "frosted (>=1.4.1)", "mypy (>=0.600)", "pyroma (>=2.4)", "vulture (>=1.5)"] +with_frosted = ["frosted (>=1.4.1)"] +with_mypy = ["mypy (>=0.600)"] +with_pyroma = ["pyroma (>=2.4)"] +with_vulture = ["vulture (>=1.5)"] + +[[package]] +name = "pycodestyle" +version = "2.7.0" +description = "Python style guide checker" category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +[[package]] +name = "pydantic" +version = "1.8.2" +description = "Data validation and settings management using python 3.6 type hinting" +category = "dev" +optional = false +python-versions = ">=3.6.1" + +[package.dependencies] +typing-extensions = ">=3.7.4.3" + +[package.extras] +dotenv = ["python-dotenv (>=0.10.4)"] +email = ["email-validator (>=1.0.3)"] + +[[package]] +name = "pydocstyle" +version = "6.1.1" +description = "Python docstring style checker" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +snowballstemmer = "*" + +[package.extras] +toml = ["toml"] + +[[package]] +name = "pyflakes" +version = "2.3.1" +description = "passive checker of Python programs" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "pylint" +version = "2.11.1" +description = "python code static checker" +category = "dev" +optional = false +python-versions = "~=3.6" + +[package.dependencies] +astroid = ">=2.8.0,<2.9" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +isort = ">=4.2.5,<6" +mccabe = ">=0.6,<0.7" +platformdirs = ">=2.2.0" +toml = ">=0.7.1" +typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} + +[[package]] +name = "pylint-celery" +version = "0.3" +description = "pylint-celery is a Pylint plugin to aid Pylint in recognising and understandingerrors caused when using the Celery library" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +astroid = ">=1.0" +pylint = ">=1.0" +pylint-plugin-utils = ">=0.2.1" + +[[package]] +name = "pylint-django" +version = "2.4.4" +description = "A Pylint plugin to help Pylint understand the Django web framework" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +pylint = ">=2.0" +pylint-plugin-utils = ">=0.5" + +[package.extras] +for_tests = ["django-tables2", "factory-boy", "coverage", "pytest"] +with_django = ["django"] + +[[package]] +name = "pylint-flask" +version = "0.6" +description = "pylint-flask is a Pylint plugin to aid Pylint in recognizing and understanding errors caused when using Flask" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +pylint-plugin-utils = ">=0.2.1" + +[[package]] +name = "pylint-plugin-utils" +version = "0.6" +description = "Utilities and helpers for writing Pylint plugins" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +pylint = ">=1.7" + [[package]] name = "pyparsing" version = "2.4.7" @@ -95,27 +543,163 @@ optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] -name = "pytest" -version = "5.4.3" -description = "pytest: simple powerful testing with Python" +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pytz" +version = "2021.1" +description = "World timezone definitions, modern and historical" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "pywavelets" +version = "1.1.1" +description = "PyWavelets, wavelet transform module" category = "dev" optional = false python-versions = ">=3.5" [package.dependencies] -atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} -attrs = ">=17.4.0" -colorama = {version = "*", markers = "sys_platform == \"win32\""} -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} -more-itertools = ">=4.0.0" -packaging = "*" -pluggy = ">=0.12,<1.0" -py = ">=1.5.0" -wcwidth = "*" +numpy = ">=1.13.3" + +[[package]] +name = "pyyaml" +version = "5.4.1" +description = "YAML parser and emitter for Python" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[[package]] +name = "requests" +version = "2.26.0" +description = "Python HTTP for Humans." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} +idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} +urllib3 = ">=1.21.1,<1.27" [package.extras] -checkqa-mypy = ["mypy (==v0.761)"] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] +socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] + +[[package]] +name = "requirements-detector" +version = "0.7" +description = "Python tool to find and list requirements of a Python project" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +astroid = ">=1.4" + +[[package]] +name = "scipy" +version = "1.6.1" +description = "SciPy: Scientific Library for Python" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +numpy = ">=1.16.5" + +[[package]] +name = "seaborn" +version = "0.11.2" +description = "seaborn: statistical data visualization" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +matplotlib = ">=2.2" +numpy = ">=1.15" +pandas = ">=0.23" +scipy = ">=1.0" + +[[package]] +name = "setoptconf-tmp" +version = "0.3.1" +description = "A module for retrieving program settings from various sources in a consistant method." +category = "dev" +optional = false +python-versions = "*" + +[package.extras] +yaml = ["pyyaml"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "snowballstemmer" +version = "2.1.0" +description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "tangled-up-in-unicode" +version = "0.1.0" +description = "Access to the Unicode Character Database (UCD)" +category = "dev" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "tqdm" +version = "4.62.3" +description = "Fast, Extensible Progress Meter" +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +dev = ["py-make (>=0.1.0)", "twine", "wheel"] +notebook = ["ipywidgets (>=6)"] +telegram = ["requests"] + +[[package]] +name = "typed-ast" +version = "1.4.3" +description = "a fork of Python 2 and 3 ast modules with type comment support" +category = "dev" +optional = false +python-versions = "*" [[package]] name = "typing-extensions" @@ -126,9 +710,49 @@ optional = false python-versions = "*" [[package]] -name = "wcwidth" -version = "0.2.5" -description = "Measures the displayed width of unicode strings in a terminal" +name = "urllib3" +version = "1.26.7" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" + +[package.extras] +brotli = ["brotlipy (>=0.6.0)"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[[package]] +name = "visions" +version = "0.7.1" +description = "Visions" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +attrs = ">=19.3.0" +bottleneck = "*" +imagehash = {version = "*", optional = true, markers = "extra == \"type_image_path\""} +multimethod = "1.4" +networkx = ">=2.4" +numpy = "*" +pandas = ">=0.25.3" +Pillow = {version = "*", optional = true, markers = "extra == \"type_image_path\""} +tangled-up-in-unicode = ">=0.0.4" + +[package.extras] +all = ["numpy", "pandas (>=0.25.3)", "attrs (>=19.3.0)", "networkx (>=2.4)", "bottleneck", "tangled-up-in-unicode (>=0.0.4)", "multimethod (==1.4)", "shapely", "imagehash", "pillow", "pydot", "pygraphviz", "matplotlib"] +dev = ["setuptools (>=46.1.3)", "wheel (>=0.34.2)", "black (>=20.8b1)", "isort (>=5.0.9)", "mypy (>=0.770)", "recommonmark (>=0.6.0)", "nbsphinx", "sphinx-rtd-theme (>=0.4.3)", "sphinx-autodoc-typehints (>=1.10.3)", "ipython", "sphinx-copybutton"] +plotting = ["pydot", "pygraphviz", "matplotlib"] +test = ["matplotlib", "imagehash", "pillow", "shapely", "mypy (>=0.800)", "black (>=19.10b0)", "isort (>=5.0.9)", "big-o (>=0.10.1)", "twine (>=3.1.1)", "pydot", "pytest (>=5.2.0)", "check-manifest (>=0.41)", "pandas", "pre-commit"] +type_geometry = ["shapely"] +type_image_path = ["imagehash", "pillow"] + +[[package]] +name = "wrapt" +version = "1.12.1" +description = "Module for decorators, wrappers and monkey patching." category = "dev" optional = false python-versions = "*" @@ -148,57 +772,620 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytes [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "4160ff5d9a3716f3a05ea05072168b2f442f81ce0c14e25cb50bfd21cf2b9ee0" +content-hash = "37d2685eea70126a1b18ebe5b57cccbc14c46e647cdf5656534a74fb5aba2e61" [metadata.files] -atomicwrites = [ - {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, - {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, +astroid = [ + {file = "astroid-2.8.0-py3-none-any.whl", hash = "sha256:dcc06f6165f415220013801642bd6c9808a02967070919c4b746c6864c205471"}, + {file = "astroid-2.8.0.tar.gz", hash = "sha256:fe81f80c0b35264acb5653302ffbd935d394f1775c5e4487df745bf9c2442708"}, ] attrs = [ {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, ] +bottleneck = [ + {file = "Bottleneck-1.3.2.tar.gz", hash = "sha256:20179f0b66359792ea283b69aa16366419132f3b6cf3adadc0c48e2e8118e573"}, +] +certifi = [ + {file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"}, + {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"}, +] +charset-normalizer = [ + {file = "charset-normalizer-2.0.6.tar.gz", hash = "sha256:5ec46d183433dcbd0ab716f2d7f29d8dee50505b3fdb40c6b985c7c4f5a3591f"}, + {file = "charset_normalizer-2.0.6-py3-none-any.whl", hash = "sha256:5d209c0a931f215cee683b6445e2d77677e7e75e159f78def0db09d68fafcaa6"}, +] colorama = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] +cycler = [ + {file = "cycler-0.10.0-py2.py3-none-any.whl", hash = "sha256:1d8a5ae1ff6c5cf9b93e8811e581232ad8920aeec647c37316ceac982b08cb2d"}, + {file = "cycler-0.10.0.tar.gz", hash = "sha256:cd7b2d1018258d7247a71425e9f26463dfb444d411c39569972f4ce586b0c9d8"}, +] +dodgy = [ + {file = "dodgy-0.2.1-py3-none-any.whl", hash = "sha256:51f54c0fd886fa3854387f354b19f429d38c04f984f38bc572558b703c0542a6"}, + {file = "dodgy-0.2.1.tar.gz", hash = "sha256:28323cbfc9352139fdd3d316fa17f325cc0e9ac74438cbba51d70f9b48f86c3a"}, +] +flake8 = [ + {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, + {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, +] +flake8-polyfill = [ + {file = "flake8-polyfill-1.0.2.tar.gz", hash = "sha256:e44b087597f6da52ec6393a709e7108b2905317d0c0b744cdca6208e670d8eda"}, + {file = "flake8_polyfill-1.0.2-py2.py3-none-any.whl", hash = "sha256:12be6a34ee3ab795b19ca73505e7b55826d5f6ad7230d31b18e106400169b9e9"}, +] +htmlmin = [ + {file = "htmlmin-0.1.12.tar.gz", hash = "sha256:50c1ef4630374a5d723900096a961cff426dff46b48f34d194a81bbe14eca178"}, +] +idna = [ + {file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"}, + {file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"}, +] +imagehash = [ + {file = "ImageHash-4.2.1.tar.gz", hash = "sha256:a4af957814bc9832d9241247ff03f76e778f890c18147900b4540af124e93011"}, +] importlib-metadata = [ {file = "importlib_metadata-4.8.1-py3-none-any.whl", hash = "sha256:b618b6d2d5ffa2f16add5697cf57a46c76a56229b0ed1c438322e4e95645bd15"}, {file = "importlib_metadata-4.8.1.tar.gz", hash = "sha256:f284b3e11256ad1e5d03ab86bb2ccd6f5339688ff17a4d797a0fe7df326f23b1"}, ] -more-itertools = [ - {file = "more-itertools-8.10.0.tar.gz", hash = "sha256:1debcabeb1df793814859d64a81ad7cb10504c24349368ccf214c664c474f41f"}, - {file = "more_itertools-8.10.0-py3-none-any.whl", hash = "sha256:56ddac45541718ba332db05f464bebfb0768110111affd27f66e0051f276fa43"}, +isort = [ + {file = "isort-5.9.3-py3-none-any.whl", hash = "sha256:e17d6e2b81095c9db0a03a8025a957f334d6ea30b26f9ec70805411e5c7c81f2"}, + {file = "isort-5.9.3.tar.gz", hash = "sha256:9c2ea1e62d871267b78307fe511c0838ba0da28698c5732d54e2790bf3ba9899"}, ] -packaging = [ - {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"}, - {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"}, +jinja2 = [ + {file = "Jinja2-3.0.1-py3-none-any.whl", hash = "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4"}, + {file = "Jinja2-3.0.1.tar.gz", hash = "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"}, ] -pluggy = [ - {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, - {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, +joblib = [ + {file = "joblib-1.0.1-py3-none-any.whl", hash = "sha256:feeb1ec69c4d45129954f1b7034954241eedfd6ba39b5e9e4b6883be3332d5e5"}, + {file = "joblib-1.0.1.tar.gz", hash = "sha256:9c17567692206d2f3fb9ecf5e991084254fe631665c450b443761c4186a613f7"}, ] -py = [ - {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, - {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, +kiwisolver = [ + {file = "kiwisolver-1.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1d819553730d3c2724582124aee8a03c846ec4362ded1034c16fb3ef309264e6"}, + {file = "kiwisolver-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8d93a1095f83e908fc253f2fb569c2711414c0bfd451cab580466465b235b470"}, + {file = "kiwisolver-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c4550a359c5157aaf8507e6820d98682872b9100ce7607f8aa070b4b8af6c298"}, + {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2210f28778c7d2ee13f3c2a20a3a22db889e75f4ec13a21072eabb5693801e84"}, + {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:82f49c5a79d3839bc8f38cb5f4bfc87e15f04cbafa5fbd12fb32c941cb529cfb"}, + {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9661a04ca3c950a8ac8c47f53cbc0b530bce1b52f516a1e87b7736fec24bfff0"}, + {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ddb500a2808c100e72c075cbb00bf32e62763c82b6a882d403f01a119e3f402"}, + {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72be6ebb4e92520b9726d7146bc9c9b277513a57a38efcf66db0620aec0097e0"}, + {file = "kiwisolver-1.3.2-cp310-cp310-win32.whl", hash = "sha256:83d2c9db5dfc537d0171e32de160461230eb14663299b7e6d18ca6dca21e4977"}, + {file = "kiwisolver-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:cba430db673c29376135e695c6e2501c44c256a81495da849e85d1793ee975ad"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4116ba9a58109ed5e4cb315bdcbff9838f3159d099ba5259c7c7fb77f8537492"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19554bd8d54cf41139f376753af1a644b63c9ca93f8f72009d50a2080f870f77"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7a4cf5bbdc861987a7745aed7a536c6405256853c94abc9f3287c3fa401b174"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0007840186bacfaa0aba4466d5890334ea5938e0bb7e28078a0eb0e63b5b59d5"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec2eba188c1906b05b9b49ae55aae4efd8150c61ba450e6721f64620c50b59eb"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3dbb3cea20b4af4f49f84cffaf45dd5f88e8594d18568e0225e6ad9dec0e7967"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-win32.whl", hash = "sha256:5326ddfacbe51abf9469fe668944bc2e399181a2158cb5d45e1d40856b2a0589"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:c6572c2dab23c86a14e82c245473d45b4c515314f1f859e92608dcafbd2f19b8"}, + {file = "kiwisolver-1.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b5074fb09429f2b7bc82b6fb4be8645dcbac14e592128beeff5461dcde0af09f"}, + {file = "kiwisolver-1.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:22521219ca739654a296eea6d4367703558fba16f98688bd8ce65abff36eaa84"}, + {file = "kiwisolver-1.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c358721aebd40c243894298f685a19eb0491a5c3e0b923b9f887ef1193ddf829"}, + {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ba5a1041480c6e0a8b11a9544d53562abc2d19220bfa14133e0cdd9967e97af"}, + {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44e6adf67577dbdfa2d9f06db9fbc5639afefdb5bf2b4dfec25c3a7fbc619536"}, + {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1d45d1c74f88b9f41062716c727f78f2a59a5476ecbe74956fafb423c5c87a76"}, + {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:70adc3658138bc77a36ce769f5f183169bc0a2906a4f61f09673f7181255ac9b"}, + {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b6a5431940f28b6de123de42f0eb47b84a073ee3c3345dc109ad550a3307dd28"}, + {file = "kiwisolver-1.3.2-cp38-cp38-win32.whl", hash = "sha256:ee040a7de8d295dbd261ef2d6d3192f13e2b08ec4a954de34a6fb8ff6422e24c"}, + {file = "kiwisolver-1.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:8dc3d842fa41a33fe83d9f5c66c0cc1f28756530cd89944b63b072281e852031"}, + {file = "kiwisolver-1.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a498bcd005e8a3fedd0022bb30ee0ad92728154a8798b703f394484452550507"}, + {file = "kiwisolver-1.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:80efd202108c3a4150e042b269f7c78643420cc232a0a771743bb96b742f838f"}, + {file = "kiwisolver-1.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f8eb7b6716f5b50e9c06207a14172cf2de201e41912ebe732846c02c830455b9"}, + {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f441422bb313ab25de7b3dbfd388e790eceb76ce01a18199ec4944b369017009"}, + {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:30fa008c172355c7768159983a7270cb23838c4d7db73d6c0f6b60dde0d432c6"}, + {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f8f6c8f4f1cff93ca5058d6ec5f0efda922ecb3f4c5fb76181f327decff98b8"}, + {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba677bcaff9429fd1bf01648ad0901cea56c0d068df383d5f5856d88221fe75b"}, + {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7843b1624d6ccca403a610d1277f7c28ad184c5aa88a1750c1a999754e65b439"}, + {file = "kiwisolver-1.3.2-cp39-cp39-win32.whl", hash = "sha256:e6f5eb2f53fac7d408a45fbcdeda7224b1cfff64919d0f95473420a931347ae9"}, + {file = "kiwisolver-1.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:eedd3b59190885d1ebdf6c5e0ca56828beb1949b4dfe6e5d0256a461429ac386"}, + {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:dedc71c8eb9c5096037766390172c34fb86ef048b8e8958b4e484b9e505d66bc"}, + {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:bf7eb45d14fc036514c09554bf983f2a72323254912ed0c3c8e697b62c4c158f"}, + {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2b65bd35f3e06a47b5c30ea99e0c2b88f72c6476eedaf8cfbc8e66adb5479dcf"}, + {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25405f88a37c5f5bcba01c6e350086d65e7465fd1caaf986333d2a045045a223"}, + {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:bcadb05c3d4794eb9eee1dddf1c24215c92fb7b55a80beae7a60530a91060560"}, + {file = "kiwisolver-1.3.2.tar.gz", hash = "sha256:fc4453705b81d03568d5b808ad8f09c77c47534f6ac2e72e733f9ca4714aa75c"}, +] +lazy-object-proxy = [ + {file = "lazy-object-proxy-1.6.0.tar.gz", hash = "sha256:489000d368377571c6f982fba6497f2aa13c6d1facc40660963da62f5c379726"}, + {file = "lazy_object_proxy-1.6.0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:c6938967f8528b3668622a9ed3b31d145fab161a32f5891ea7b84f6b790be05b"}, + {file = "lazy_object_proxy-1.6.0-cp27-cp27m-win32.whl", hash = "sha256:ebfd274dcd5133e0afae738e6d9da4323c3eb021b3e13052d8cbd0e457b1256e"}, + {file = "lazy_object_proxy-1.6.0-cp27-cp27m-win_amd64.whl", hash = "sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93"}, + {file = "lazy_object_proxy-1.6.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d900d949b707778696fdf01036f58c9876a0d8bfe116e8d220cfd4b15f14e741"}, + {file = "lazy_object_proxy-1.6.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5743a5ab42ae40caa8421b320ebf3a998f89c85cdc8376d6b2e00bd12bd1b587"}, + {file = "lazy_object_proxy-1.6.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:bf34e368e8dd976423396555078def5cfc3039ebc6fc06d1ae2c5a65eebbcde4"}, + {file = "lazy_object_proxy-1.6.0-cp36-cp36m-win32.whl", hash = "sha256:b579f8acbf2bdd9ea200b1d5dea36abd93cabf56cf626ab9c744a432e15c815f"}, + {file = "lazy_object_proxy-1.6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:4f60460e9f1eb632584c9685bccea152f4ac2130e299784dbaf9fae9f49891b3"}, + {file = "lazy_object_proxy-1.6.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d7124f52f3bd259f510651450e18e0fd081ed82f3c08541dffc7b94b883aa981"}, + {file = "lazy_object_proxy-1.6.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:22ddd618cefe54305df49e4c069fa65715be4ad0e78e8d252a33debf00f6ede2"}, + {file = "lazy_object_proxy-1.6.0-cp37-cp37m-win32.whl", hash = "sha256:9d397bf41caad3f489e10774667310d73cb9c4258e9aed94b9ec734b34b495fd"}, + {file = "lazy_object_proxy-1.6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:24a5045889cc2729033b3e604d496c2b6f588c754f7a62027ad4437a7ecc4837"}, + {file = "lazy_object_proxy-1.6.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:17e0967ba374fc24141738c69736da90e94419338fd4c7c7bef01ee26b339653"}, + {file = "lazy_object_proxy-1.6.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:410283732af311b51b837894fa2f24f2c0039aa7f220135192b38fcc42bd43d3"}, + {file = "lazy_object_proxy-1.6.0-cp38-cp38-win32.whl", hash = "sha256:85fb7608121fd5621cc4377a8961d0b32ccf84a7285b4f1d21988b2eae2868e8"}, + {file = "lazy_object_proxy-1.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:d1c2676e3d840852a2de7c7d5d76407c772927addff8d742b9808fe0afccebdf"}, + {file = "lazy_object_proxy-1.6.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:b865b01a2e7f96db0c5d12cfea590f98d8c5ba64ad222300d93ce6ff9138bcad"}, + {file = "lazy_object_proxy-1.6.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4732c765372bd78a2d6b2150a6e99d00a78ec963375f236979c0626b97ed8e43"}, + {file = "lazy_object_proxy-1.6.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:9698110e36e2df951c7c36b6729e96429c9c32b3331989ef19976592c5f3c77a"}, + {file = "lazy_object_proxy-1.6.0-cp39-cp39-win32.whl", hash = "sha256:1fee665d2638491f4d6e55bd483e15ef21f6c8c2095f235fef72601021e64f61"}, + {file = "lazy_object_proxy-1.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b"}, +] +markupsafe = [ + {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, + {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, +] +matplotlib = [ + {file = "matplotlib-3.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5c988bb43414c7c2b0a31bd5187b4d27fd625c080371b463a6d422047df78913"}, + {file = "matplotlib-3.4.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f1c5efc278d996af8a251b2ce0b07bbeccb821f25c8c9846bdcb00ffc7f158aa"}, + {file = "matplotlib-3.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:eeb1859efe7754b1460e1d4991bbd4a60a56f366bc422ef3a9c5ae05f0bc70b5"}, + {file = "matplotlib-3.4.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:844a7b0233e4ff7fba57e90b8799edaa40b9e31e300b8d5efc350937fa8b1bea"}, + {file = "matplotlib-3.4.3-cp37-cp37m-win32.whl", hash = "sha256:85f0c9cf724715e75243a7b3087cf4a3de056b55e05d4d76cc58d610d62894f3"}, + {file = "matplotlib-3.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:c70b6311dda3e27672f1bf48851a0de816d1ca6aaf3d49365fbdd8e959b33d2b"}, + {file = "matplotlib-3.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b884715a59fec9ad3b6048ecf3860f3b2ce965e676ef52593d6fa29abcf7d330"}, + {file = "matplotlib-3.4.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:a78a3b51f29448c7f4d4575e561f6b0dbb8d01c13c2046ab6c5220eb25c06506"}, + {file = "matplotlib-3.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6a724e3a48a54b8b6e7c4ae38cd3d07084508fa47c410c8757e9db9791421838"}, + {file = "matplotlib-3.4.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:48e1e0859b54d5f2e29bb78ca179fd59b971c6ceb29977fb52735bfd280eb0f5"}, + {file = "matplotlib-3.4.3-cp38-cp38-win32.whl", hash = "sha256:01c9de93a2ca0d128c9064f23709362e7fefb34910c7c9e0b8ab0de8258d5eda"}, + {file = "matplotlib-3.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:ebfb01a65c3f5d53a8c2a8133fec2b5221281c053d944ae81ff5822a68266617"}, + {file = "matplotlib-3.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b8b53f336a4688cfce615887505d7e41fd79b3594bf21dd300531a4f5b4f746a"}, + {file = "matplotlib-3.4.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:fcd6f1954943c0c192bfbebbac263f839d7055409f1173f80d8b11a224d236da"}, + {file = "matplotlib-3.4.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6be8df61b1626e1a142c57e065405e869e9429b4a6dab4a324757d0dc4d42235"}, + {file = "matplotlib-3.4.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:41b6e307458988891fcdea2d8ecf84a8c92d53f84190aa32da65f9505546e684"}, + {file = "matplotlib-3.4.3-cp39-cp39-win32.whl", hash = "sha256:f72657f1596199dc1e4e7a10f52a4784ead8a711f4e5b59bea95bdb97cf0e4fd"}, + {file = "matplotlib-3.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:f15edcb0629a0801738925fe27070480f446fcaa15de65946ff946ad99a59a40"}, + {file = "matplotlib-3.4.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:556965514b259204637c360d213de28d43a1f4aed1eca15596ce83f768c5a56f"}, + {file = "matplotlib-3.4.3-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:54a026055d5f8614f184e588f6e29064019a0aa8448450214c0b60926d62d919"}, + {file = "matplotlib-3.4.3.tar.gz", hash = "sha256:fc4f526dfdb31c9bd6b8ca06bf9fab663ca12f3ec9cdf4496fb44bc680140318"}, +] +mccabe = [ + {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, + {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, +] +missingno = [ + {file = "missingno-0.5.0-py3-none-any.whl", hash = "sha256:888736337b5d18302ca9c1a970cb7e037f4b5085eb013390df2b0669c800642a"}, +] +multimethod = [ + {file = "multimethod-1.4-py2.py3-none-any.whl", hash = "sha256:2746500793c64cbd84a6ccda0043f4b58af3fcf8d6cd44b2232d5b9455b31d73"}, + {file = "multimethod-1.4.tar.gz", hash = "sha256:8b315d6c965a797899a699913cdc391ded51dca22db5d11bda3399ce24ffed76"}, +] +networkx = [ + {file = "networkx-2.6.3-py3-none-any.whl", hash = "sha256:80b6b89c77d1dfb64a4c7854981b60aeea6360ac02c6d4e4913319e0a313abef"}, + {file = "networkx-2.6.3.tar.gz", hash = "sha256:c0946ed31d71f1b732b5aaa6da5a0388a345019af232ce2f49c766e2d6795c51"}, +] +numpy = [ + {file = "numpy-1.21.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:38e8648f9449a549a7dfe8d8755a5979b45b3538520d1e735637ef28e8c2dc50"}, + {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fd7d7409fa643a91d0a05c7554dd68aa9c9bb16e186f6ccfe40d6e003156e33a"}, + {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a75b4498b1e93d8b700282dc8e655b8bd559c0904b3910b144646dbbbc03e062"}, + {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1412aa0aec3e00bc23fbb8664d76552b4efde98fb71f60737c83efbac24112f1"}, + {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e46ceaff65609b5399163de5893d8f2a82d3c77d5e56d976c8b5fb01faa6b671"}, + {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c6a2324085dd52f96498419ba95b5777e40b6bcbc20088fddb9e8cbb58885e8e"}, + {file = "numpy-1.21.1-cp37-cp37m-win32.whl", hash = "sha256:73101b2a1fef16602696d133db402a7e7586654682244344b8329cdcbbb82172"}, + {file = "numpy-1.21.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7a708a79c9a9d26904d1cca8d383bf869edf6f8e7650d85dbc77b041e8c5a0f8"}, + {file = "numpy-1.21.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95b995d0c413f5d0428b3f880e8fe1660ff9396dcd1f9eedbc311f37b5652e16"}, + {file = "numpy-1.21.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:635e6bd31c9fb3d475c8f44a089569070d10a9ef18ed13738b03049280281267"}, + {file = "numpy-1.21.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a3d5fb89bfe21be2ef47c0614b9c9c707b7362386c9a3ff1feae63e0267ccb6"}, + {file = "numpy-1.21.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8a326af80e86d0e9ce92bcc1e65c8ff88297de4fa14ee936cb2293d414c9ec63"}, + {file = "numpy-1.21.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:791492091744b0fe390a6ce85cc1bf5149968ac7d5f0477288f78c89b385d9af"}, + {file = "numpy-1.21.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0318c465786c1f63ac05d7c4dbcecd4d2d7e13f0959b01b534ea1e92202235c5"}, + {file = "numpy-1.21.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a513bd9c1551894ee3d31369f9b07460ef223694098cf27d399513415855b68"}, + {file = "numpy-1.21.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:91c6f5fc58df1e0a3cc0c3a717bb3308ff850abdaa6d2d802573ee2b11f674a8"}, + {file = "numpy-1.21.1-cp38-cp38-win32.whl", hash = "sha256:978010b68e17150db8765355d1ccdd450f9fc916824e8c4e35ee620590e234cd"}, + {file = "numpy-1.21.1-cp38-cp38-win_amd64.whl", hash = "sha256:9749a40a5b22333467f02fe11edc98f022133ee1bfa8ab99bda5e5437b831214"}, + {file = "numpy-1.21.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d7a4aeac3b94af92a9373d6e77b37691b86411f9745190d2c351f410ab3a791f"}, + {file = "numpy-1.21.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d9e7912a56108aba9b31df688a4c4f5cb0d9d3787386b87d504762b6754fbb1b"}, + {file = "numpy-1.21.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:25b40b98ebdd272bc3020935427a4530b7d60dfbe1ab9381a39147834e985eac"}, + {file = "numpy-1.21.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8a92c5aea763d14ba9d6475803fc7904bda7decc2a0a68153f587ad82941fec1"}, + {file = "numpy-1.21.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:05a0f648eb28bae4bcb204e6fd14603de2908de982e761a2fc78efe0f19e96e1"}, + {file = "numpy-1.21.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f01f28075a92eede918b965e86e8f0ba7b7797a95aa8d35e1cc8821f5fc3ad6a"}, + {file = "numpy-1.21.1-cp39-cp39-win32.whl", hash = "sha256:88c0b89ad1cc24a5efbb99ff9ab5db0f9a86e9cc50240177a571fbe9c2860ac2"}, + {file = "numpy-1.21.1-cp39-cp39-win_amd64.whl", hash = "sha256:01721eefe70544d548425a07c80be8377096a54118070b8a62476866d5208e33"}, + {file = "numpy-1.21.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2d4d1de6e6fb3d28781c73fbde702ac97f03d79e4ffd6598b880b2d95d62ead4"}, + {file = "numpy-1.21.1.zip", hash = "sha256:dff4af63638afcc57a3dfb9e4b26d434a7a602d225b42d746ea7fe2edf1342fd"}, +] +pandas = [ + {file = "pandas-1.1.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:bf23a3b54d128b50f4f9d4675b3c1857a688cc6731a32f931837d72effb2698d"}, + {file = "pandas-1.1.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5a780260afc88268a9d3ac3511d8f494fdcf637eece62fb9eb656a63d53eb7ca"}, + {file = "pandas-1.1.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:b61080750d19a0122469ab59b087380721d6b72a4e7d962e4d7e63e0c4504814"}, + {file = "pandas-1.1.5-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:0de3ddb414d30798cbf56e642d82cac30a80223ad6fe484d66c0ce01a84d6f2f"}, + {file = "pandas-1.1.5-cp36-cp36m-win32.whl", hash = "sha256:70865f96bb38fec46f7ebd66d4b5cfd0aa6b842073f298d621385ae3898d28b5"}, + {file = "pandas-1.1.5-cp36-cp36m-win_amd64.whl", hash = "sha256:19a2148a1d02791352e9fa637899a78e371a3516ac6da5c4edc718f60cbae648"}, + {file = "pandas-1.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:26fa92d3ac743a149a31b21d6f4337b0594b6302ea5575b37af9ca9611e8981a"}, + {file = "pandas-1.1.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c16d59c15d946111d2716856dd5479221c9e4f2f5c7bc2d617f39d870031e086"}, + {file = "pandas-1.1.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:3be7a7a0ca71a2640e81d9276f526bca63505850add10206d0da2e8a0a325dae"}, + {file = "pandas-1.1.5-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:573fba5b05bf2c69271a32e52399c8de599e4a15ab7cec47d3b9c904125ab788"}, + {file = "pandas-1.1.5-cp37-cp37m-win32.whl", hash = "sha256:21b5a2b033380adbdd36b3116faaf9a4663e375325831dac1b519a44f9e439bb"}, + {file = "pandas-1.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:24c7f8d4aee71bfa6401faeba367dd654f696a77151a8a28bc2013f7ced4af98"}, + {file = "pandas-1.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2860a97cbb25444ffc0088b457da0a79dc79f9c601238a3e0644312fcc14bf11"}, + {file = "pandas-1.1.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:5008374ebb990dad9ed48b0f5d0038124c73748f5384cc8c46904dace27082d9"}, + {file = "pandas-1.1.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2c2f7c670ea4e60318e4b7e474d56447cf0c7d83b3c2a5405a0dbb2600b9c48e"}, + {file = "pandas-1.1.5-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:0a643bae4283a37732ddfcecab3f62dd082996021b980f580903f4e8e01b3c5b"}, + {file = "pandas-1.1.5-cp38-cp38-win32.whl", hash = "sha256:5447ea7af4005b0daf695a316a423b96374c9c73ffbd4533209c5ddc369e644b"}, + {file = "pandas-1.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:4c62e94d5d49db116bef1bd5c2486723a292d79409fc9abd51adf9e05329101d"}, + {file = "pandas-1.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:731568be71fba1e13cae212c362f3d2ca8932e83cb1b85e3f1b4dd77d019254a"}, + {file = "pandas-1.1.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:c61c043aafb69329d0f961b19faa30b1dab709dd34c9388143fc55680059e55a"}, + {file = "pandas-1.1.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:2b1c6cd28a0dfda75c7b5957363333f01d370936e4c6276b7b8e696dd500582a"}, + {file = "pandas-1.1.5-cp39-cp39-win32.whl", hash = "sha256:c94ff2780a1fd89f190390130d6d36173ca59fcfb3fe0ff596f9a56518191ccb"}, + {file = "pandas-1.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:edda9bacc3843dfbeebaf7a701763e68e741b08fccb889c003b0a52f0ee95782"}, + {file = "pandas-1.1.5.tar.gz", hash = "sha256:f10fc41ee3c75a474d3bdf68d396f10782d013d7f67db99c0efbfd0acb99701b"}, +] +pandas-profiling = [ + {file = "pandas-profiling-3.0.0.tar.gz", hash = "sha256:785757d01a2cac5c64927fe61efdcb12b866195f880d809eaacfb6cb338c47ec"}, + {file = "pandas_profiling-3.0.0-py2.py3-none-any.whl", hash = "sha256:66aacc4aea66f2b4105bec32387e5175c2d088ba475eeefb2169ee6e89db04c6"}, +] +pep8-naming = [ + {file = "pep8-naming-0.10.0.tar.gz", hash = "sha256:f3b4a5f9dd72b991bf7d8e2a341d2e1aa3a884a769b5aaac4f56825c1763bf3a"}, + {file = "pep8_naming-0.10.0-py2.py3-none-any.whl", hash = "sha256:5d9f1056cb9427ce344e98d1a7f5665710e2f20f748438e308995852cfa24164"}, +] +phik = [ + {file = "phik-0.12.0-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:57db39d1c74c84a24d0270b63d1c629a5cb975462919895b96a8522ae0678408"}, + {file = "phik-0.12.0-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:a761997ef4ebd7028fbf6cd443170a214f2f551d9f88f91ce1bcdd2fd8ff4a82"}, + {file = "phik-0.12.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:922d19b7fe8b64e0f073815d6da2766e0c6934dd1acbcb6a4244450356efb7c0"}, + {file = "phik-0.12.0-cp36-cp36m-win32.whl", hash = "sha256:8ce9f3d8d7113afb9ee2f4e198cf094ffad719d9261a4aa0a79c8ed3aa40d158"}, + {file = "phik-0.12.0-cp36-cp36m-win_amd64.whl", hash = "sha256:3981fcdc992d16b4fe86b1656292d1be853f7b6174311a52cc74808de7dccb7d"}, + {file = "phik-0.12.0-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:e1cc94b513a28440f8450ef37cb0ef27a9d0c09947774d7c56d88a2a6d99bda9"}, + {file = "phik-0.12.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:f8fb9d55cbaa75c711a29e4cac00032638235afd80f675eb469431bef4a240c0"}, + {file = "phik-0.12.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:b1691c977935c8fe4a1c68953c813c3e9fec479936ae9296c1ecd4e655419584"}, + {file = "phik-0.12.0-cp37-cp37m-win32.whl", hash = "sha256:e66cb58584d5db5b395ee9dc69dcfbb364cbc8e9f2376deaf321153322598798"}, + {file = "phik-0.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2055b3dce325ef9a6288d1d1a55d30fd049e859ff3c9a4c4b43c46cff747ce71"}, + {file = "phik-0.12.0-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:14bb939b3855e3a2a78362411ff3ec436d061081405daa501310b63d5828c364"}, + {file = "phik-0.12.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:7b45d2881c9129f2993eb4f0333d594fc3cc6f68d84d304777e726a899d3bdbe"}, + {file = "phik-0.12.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:fae864023ba75136ae46a34279b6b7aef8c9548c3475e945b8e01a6f93400a57"}, + {file = "phik-0.12.0-cp38-cp38-win32.whl", hash = "sha256:f60d9e09ea60a558e13e15cd01bf212e90b5e5c2abff4fd3209864000b3a55c4"}, + {file = "phik-0.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:44695244414d644210230ebdc080cc94fdbd675a79d0d47633a54eb29f952102"}, + {file = "phik-0.12.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:839f578f0b3f1abf5a66be1a4218342729701125bea60e17e0ef2431cea7bdb9"}, + {file = "phik-0.12.0-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:40b3329e16a547f0d89c0f0f7b0c5588860833e2e5c25e3ac8782f0dce44e3a5"}, + {file = "phik-0.12.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ff4b38aa79f7178b39f404655aa6494b7ed70edf117da2246ac9289f8bf630cd"}, + {file = "phik-0.12.0-cp39-cp39-win32.whl", hash = "sha256:3f8a35a88a6ace67fba3ee9fae28bc9d2356dc70d80d223601e8ff06d65cab29"}, + {file = "phik-0.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:44a2f728a2a3e301355ae1cd77893093ed6303de71fc0e6c90091e2b42a5da94"}, + {file = "phik-0.12.0.tar.gz", hash = "sha256:959fd40482246e3f643cdac5ea04135b2c11a487e917af7d4e75843f47183549"}, +] +pillow = [ + {file = "Pillow-8.3.2-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:c691b26283c3a31594683217d746f1dad59a7ae1d4cfc24626d7a064a11197d4"}, + {file = "Pillow-8.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f514c2717012859ccb349c97862568fdc0479aad85b0270d6b5a6509dbc142e2"}, + {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be25cb93442c6d2f8702c599b51184bd3ccd83adebd08886b682173e09ef0c3f"}, + {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d675a876b295afa114ca8bf42d7f86b5fb1298e1b6bb9a24405a3f6c8338811c"}, + {file = "Pillow-8.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59697568a0455764a094585b2551fd76bfd6b959c9f92d4bdec9d0e14616303a"}, + {file = "Pillow-8.3.2-cp310-cp310-win32.whl", hash = "sha256:2d5e9dc0bf1b5d9048a94c48d0813b6c96fccfa4ccf276d9c36308840f40c228"}, + {file = "Pillow-8.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:11c27e74bab423eb3c9232d97553111cc0be81b74b47165f07ebfdd29d825875"}, + {file = "Pillow-8.3.2-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:11eb7f98165d56042545c9e6db3ce394ed8b45089a67124298f0473b29cb60b2"}, + {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f23b2d3079522fdf3c09de6517f625f7a964f916c956527bed805ac043799b8"}, + {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19ec4cfe4b961edc249b0e04b5618666c23a83bc35842dea2bfd5dfa0157f81b"}, + {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5a31c07cea5edbaeb4bdba6f2b87db7d3dc0f446f379d907e51cc70ea375629"}, + {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:15ccb81a6ffc57ea0137f9f3ac2737ffa1d11f786244d719639df17476d399a7"}, + {file = "Pillow-8.3.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8f284dc1695caf71a74f24993b7c7473d77bc760be45f776a2c2f4e04c170550"}, + {file = "Pillow-8.3.2-cp36-cp36m-win32.whl", hash = "sha256:4abc247b31a98f29e5224f2d31ef15f86a71f79c7f4d2ac345a5d551d6393073"}, + {file = "Pillow-8.3.2-cp36-cp36m-win_amd64.whl", hash = "sha256:a048dad5ed6ad1fad338c02c609b862dfaa921fcd065d747194a6805f91f2196"}, + {file = "Pillow-8.3.2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:06d1adaa284696785375fa80a6a8eb309be722cf4ef8949518beb34487a3df71"}, + {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd24054aaf21e70a51e2a2a5ed1183560d3a69e6f9594a4bfe360a46f94eba83"}, + {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27a330bf7014ee034046db43ccbb05c766aa9e70b8d6c5260bfc38d73103b0ba"}, + {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13654b521fb98abdecec105ea3fb5ba863d1548c9b58831dd5105bb3873569f1"}, + {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a1bd983c565f92779be456ece2479840ec39d386007cd4ae83382646293d681b"}, + {file = "Pillow-8.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4326ea1e2722f3dc00ed77c36d3b5354b8fb7399fb59230249ea6d59cbed90da"}, + {file = "Pillow-8.3.2-cp37-cp37m-win32.whl", hash = "sha256:085a90a99404b859a4b6c3daa42afde17cb3ad3115e44a75f0d7b4a32f06a6c9"}, + {file = "Pillow-8.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:18a07a683805d32826c09acfce44a90bf474e6a66ce482b1c7fcd3757d588df3"}, + {file = "Pillow-8.3.2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:4e59e99fd680e2b8b11bbd463f3c9450ab799305d5f2bafb74fefba6ac058616"}, + {file = "Pillow-8.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4d89a2e9219a526401015153c0e9dd48319ea6ab9fe3b066a20aa9aee23d9fd3"}, + {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56fd98c8294f57636084f4b076b75f86c57b2a63a8410c0cd172bc93695ee979"}, + {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b11c9d310a3522b0fd3c35667914271f570576a0e387701f370eb39d45f08a4"}, + {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0412516dcc9de9b0a1e0ae25a280015809de8270f134cc2c1e32c4eeb397cf30"}, + {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bcb04ff12e79b28be6c9988f275e7ab69f01cc2ba319fb3114f87817bb7c74b6"}, + {file = "Pillow-8.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0b9911ec70731711c3b6ebcde26caea620cbdd9dcb73c67b0730c8817f24711b"}, + {file = "Pillow-8.3.2-cp38-cp38-win32.whl", hash = "sha256:ce2e5e04bb86da6187f96d7bab3f93a7877830981b37f0287dd6479e27a10341"}, + {file = "Pillow-8.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:35d27687f027ad25a8d0ef45dd5208ef044c588003cdcedf05afb00dbc5c2deb"}, + {file = "Pillow-8.3.2-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:04835e68ef12904bc3e1fd002b33eea0779320d4346082bd5b24bec12ad9c3e9"}, + {file = "Pillow-8.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:10e00f7336780ca7d3653cf3ac26f068fa11b5a96894ea29a64d3dc4b810d630"}, + {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cde7a4d3687f21cffdf5bb171172070bb95e02af448c4c8b2f223d783214056"}, + {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c3ff00110835bdda2b1e2b07f4a2548a39744bb7de5946dc8e95517c4fb2ca6"}, + {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35d409030bf3bd05fa66fb5fdedc39c521b397f61ad04309c90444e893d05f7d"}, + {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bff50ba9891be0a004ef48828e012babaaf7da204d81ab9be37480b9020a82b"}, + {file = "Pillow-8.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7dbfbc0020aa1d9bc1b0b8bcf255a7d73f4ad0336f8fd2533fcc54a4ccfb9441"}, + {file = "Pillow-8.3.2-cp39-cp39-win32.whl", hash = "sha256:963ebdc5365d748185fdb06daf2ac758116deecb2277ec5ae98139f93844bc09"}, + {file = "Pillow-8.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:cc9d0dec711c914ed500f1d0d3822868760954dce98dfb0b7382a854aee55d19"}, + {file = "Pillow-8.3.2-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:2c661542c6f71dfd9dc82d9d29a8386287e82813b0375b3a02983feac69ef864"}, + {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:548794f99ff52a73a156771a0402f5e1c35285bd981046a502d7e4793e8facaa"}, + {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8b68f565a4175e12e68ca900af8910e8fe48aaa48fd3ca853494f384e11c8bcd"}, + {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:838eb85de6d9307c19c655c726f8d13b8b646f144ca6b3771fa62b711ebf7624"}, + {file = "Pillow-8.3.2-pp36-pypy36_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:feb5db446e96bfecfec078b943cc07744cc759893cef045aa8b8b6d6aaa8274e"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:fc0db32f7223b094964e71729c0361f93db43664dd1ec86d3df217853cedda87"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fd4fd83aa912d7b89b4b4a1580d30e2a4242f3936882a3f433586e5ab97ed0d5"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d0c8ebbfd439c37624db98f3877d9ed12c137cadd99dde2d2eae0dab0bbfc355"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6cb3dd7f23b044b0737317f892d399f9e2f0b3a02b22b2c692851fb8120d82c6"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a66566f8a22561fc1a88dc87606c69b84fa9ce724f99522cf922c801ec68f5c1"}, + {file = "Pillow-8.3.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ce651ca46d0202c302a535d3047c55a0131a720cf554a578fc1b8a2aff0e7d96"}, + {file = "Pillow-8.3.2.tar.gz", hash = "sha256:dde3f3ed8d00c72631bc19cbfff8ad3b6215062a5eed402381ad365f82f0c18c"}, +] +platformdirs = [ + {file = "platformdirs-2.3.0-py3-none-any.whl", hash = "sha256:8003ac87717ae2c7ee1ea5a84a1a61e87f3fbd16eb5aadba194ea30a9019f648"}, + {file = "platformdirs-2.3.0.tar.gz", hash = "sha256:15b056538719b1c94bdaccb29e5f81879c7f7f0f4a153f46086d155dffcd4f0f"}, +] +prospector = [ + {file = "prospector-1.5.1-py3-none-any.whl", hash = "sha256:47f8ff3fd36ae276967eb392ca20b300a7bdea66c0d0252250a4d89a6c03ab15"}, + {file = "prospector-1.5.1.tar.gz", hash = "sha256:851c2892cd615cfee91fd27cfaf7a5061d14daf2853aa8f012e927b98f919578"}, +] +pycodestyle = [ + {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, + {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, +] +pydantic = [ + {file = "pydantic-1.8.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:05ddfd37c1720c392f4e0d43c484217b7521558302e7069ce8d318438d297739"}, + {file = "pydantic-1.8.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a7c6002203fe2c5a1b5cbb141bb85060cbff88c2d78eccbc72d97eb7022c43e4"}, + {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:589eb6cd6361e8ac341db97602eb7f354551482368a37f4fd086c0733548308e"}, + {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:10e5622224245941efc193ad1d159887872776df7a8fd592ed746aa25d071840"}, + {file = "pydantic-1.8.2-cp36-cp36m-win_amd64.whl", hash = "sha256:99a9fc39470010c45c161a1dc584997f1feb13f689ecf645f59bb4ba623e586b"}, + {file = "pydantic-1.8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a83db7205f60c6a86f2c44a61791d993dff4b73135df1973ecd9eed5ea0bda20"}, + {file = "pydantic-1.8.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:41b542c0b3c42dc17da70554bc6f38cbc30d7066d2c2815a94499b5684582ecb"}, + {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:ea5cb40a3b23b3265f6325727ddfc45141b08ed665458be8c6285e7b85bd73a1"}, + {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:18b5ea242dd3e62dbf89b2b0ec9ba6c7b5abaf6af85b95a97b00279f65845a23"}, + {file = "pydantic-1.8.2-cp37-cp37m-win_amd64.whl", hash = "sha256:234a6c19f1c14e25e362cb05c68afb7f183eb931dd3cd4605eafff055ebbf287"}, + {file = "pydantic-1.8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:021ea0e4133e8c824775a0cfe098677acf6fa5a3cbf9206a376eed3fc09302cd"}, + {file = "pydantic-1.8.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e710876437bc07bd414ff453ac8ec63d219e7690128d925c6e82889d674bb505"}, + {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:ac8eed4ca3bd3aadc58a13c2aa93cd8a884bcf21cb019f8cfecaae3b6ce3746e"}, + {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:4a03cbbe743e9c7247ceae6f0d8898f7a64bb65800a45cbdc52d65e370570820"}, + {file = "pydantic-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:8621559dcf5afacf0069ed194278f35c255dc1a1385c28b32dd6c110fd6531b3"}, + {file = "pydantic-1.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8b223557f9510cf0bfd8b01316bf6dd281cf41826607eada99662f5e4963f316"}, + {file = "pydantic-1.8.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:244ad78eeb388a43b0c927e74d3af78008e944074b7d0f4f696ddd5b2af43c62"}, + {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:05ef5246a7ffd2ce12a619cbb29f3307b7c4509307b1b49f456657b43529dc6f"}, + {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:54cd5121383f4a461ff7644c7ca20c0419d58052db70d8791eacbbe31528916b"}, + {file = "pydantic-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:4be75bebf676a5f0f87937c6ddb061fa39cbea067240d98e298508c1bda6f3f3"}, + {file = "pydantic-1.8.2-py3-none-any.whl", hash = "sha256:fec866a0b59f372b7e776f2d7308511784dace622e0992a0b59ea3ccee0ae833"}, + {file = "pydantic-1.8.2.tar.gz", hash = "sha256:26464e57ccaafe72b7ad156fdaa4e9b9ef051f69e175dbbb463283000c05ab7b"}, +] +pydocstyle = [ + {file = "pydocstyle-6.1.1-py3-none-any.whl", hash = "sha256:6987826d6775056839940041beef5c08cc7e3d71d63149b48e36727f70144dc4"}, + {file = "pydocstyle-6.1.1.tar.gz", hash = "sha256:1d41b7c459ba0ee6c345f2eb9ae827cab14a7533a88c5c6f7e94923f72df92dc"}, +] +pyflakes = [ + {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, + {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, +] +pylint = [ + {file = "pylint-2.11.1-py3-none-any.whl", hash = "sha256:0f358e221c45cbd4dad2a1e4b883e75d28acdcccd29d40c76eb72b307269b126"}, + {file = "pylint-2.11.1.tar.gz", hash = "sha256:2c9843fff1a88ca0ad98a256806c82c5a8f86086e7ccbdb93297d86c3f90c436"}, +] +pylint-celery = [ + {file = "pylint-celery-0.3.tar.gz", hash = "sha256:41e32094e7408d15c044178ea828dd524beedbdbe6f83f712c5e35bde1de4beb"}, +] +pylint-django = [ + {file = "pylint-django-2.4.4.tar.gz", hash = "sha256:f63f717169b0c2e4e19c28f1c32c28290647330184fcb7427805ae9b6994f3fc"}, + {file = "pylint_django-2.4.4-py3-none-any.whl", hash = "sha256:aff49d9602a39c027b4ed7521a041438893205918f405800063b7ff692b7371b"}, +] +pylint-flask = [ + {file = "pylint-flask-0.6.tar.gz", hash = "sha256:f4d97de2216bf7bfce07c9c08b166e978fe9f2725de2a50a9845a97de7e31517"}, +] +pylint-plugin-utils = [ + {file = "pylint-plugin-utils-0.6.tar.gz", hash = "sha256:57625dcca20140f43731311cd8fd879318bf45a8b0fd17020717a8781714a25a"}, + {file = "pylint_plugin_utils-0.6-py3-none-any.whl", hash = "sha256:2f30510e1c46edf268d3a195b2849bd98a1b9433229bb2ba63b8d776e1fc4d0a"}, ] pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, ] -pytest = [ - {file = "pytest-5.4.3-py3-none-any.whl", hash = "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1"}, - {file = "pytest-5.4.3.tar.gz", hash = "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8"}, +python-dateutil = [ + {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"}, +] +pytz = [ + {file = "pytz-2021.1-py2.py3-none-any.whl", hash = "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"}, + {file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"}, +] +pywavelets = [ + {file = "PyWavelets-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:35959c041ec014648575085a97b498eafbbaa824f86f6e4a59bfdef8a3fe6308"}, + {file = "PyWavelets-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:55e39ec848ceec13c9fa1598253ae9dd5c31d09dfd48059462860d2b908fb224"}, + {file = "PyWavelets-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c06d2e340c7bf8b9ec71da2284beab8519a3908eab031f4ea126e8ccfc3fd567"}, + {file = "PyWavelets-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:be105382961745f88d8196bba5a69ee2c4455d87ad2a2e5d1eed6bd7fda4d3fd"}, + {file = "PyWavelets-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:076ca8907001fdfe4205484f719d12b4a0262dfe6652fa1cfc3c5c362d14dc84"}, + {file = "PyWavelets-1.1.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:7947e51ca05489b85928af52a34fe67022ab5b81d4ae32a4109a99e883a0635e"}, + {file = "PyWavelets-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:9e2528823ccf5a0a1d23262dfefe5034dce89cd84e4e124dc553dfcdf63ebb92"}, + {file = "PyWavelets-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:80b924edbc012ded8aa8b91cb2fd6207fb1a9a3a377beb4049b8a07445cec6f0"}, + {file = "PyWavelets-1.1.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c2a799e79cee81a862216c47e5623c97b95f1abee8dd1f9eed736df23fb653fb"}, + {file = "PyWavelets-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:d510aef84d9852653d079c84f2f81a82d5d09815e625f35c95714e7364570ad4"}, + {file = "PyWavelets-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:889d4c5c5205a9c90118c1980df526857929841df33e4cd1ff1eff77c6817a65"}, + {file = "PyWavelets-1.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:68b5c33741d26c827074b3d8f0251de1c3019bb9567b8d303eb093c822ce28f1"}, + {file = "PyWavelets-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:18a51b3f9416a2ae6e9a35c4af32cf520dd7895f2b69714f4aa2f4342fca47f9"}, + {file = "PyWavelets-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:cfe79844526dd92e3ecc9490b5031fca5f8ab607e1e858feba232b1b788ff0ea"}, + {file = "PyWavelets-1.1.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:2f7429eeb5bf9c7068002d0d7f094ed654c77a70ce5e6198737fd68ab85f8311"}, + {file = "PyWavelets-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:720dbcdd3d91c6dfead79c80bf8b00a1d8aa4e5d551dc528c6d5151e4efc3403"}, + {file = "PyWavelets-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:bc5e87b72371da87c9bebc68e54882aada9c3114e640de180f62d5da95749cd3"}, + {file = "PyWavelets-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:98b2669c5af842a70cfab33a7043fcb5e7535a690a00cd251b44c9be0be418e5"}, + {file = "PyWavelets-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e02a0558e0c2ac8b8bbe6a6ac18c136767ec56b96a321e0dfde2173adfa5a504"}, + {file = "PyWavelets-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6162dc0ae04669ea04b4b51420777b9ea2d30b0a9d02901b2a3b4d61d159c2e9"}, + {file = "PyWavelets-1.1.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:39c74740718e420d38c78ca4498568fa57976d78d5096277358e0fa9629a7aea"}, + {file = "PyWavelets-1.1.1-cp38-cp38-win32.whl", hash = "sha256:79f5b54f9dc353e5ee47f0c3f02bebd2c899d49780633aa771fed43fa20b3149"}, + {file = "PyWavelets-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:935ff247b8b78bdf77647fee962b1cc208c51a7b229db30b9ba5f6da3e675178"}, + {file = "PyWavelets-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6ebfefebb5c6494a3af41ad8c60248a95da267a24b79ed143723d4502b1fe4d7"}, + {file = "PyWavelets-1.1.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:6bc78fb9c42a716309b4ace56f51965d8b5662c3ba19d4591749f31773db1125"}, + {file = "PyWavelets-1.1.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:411e17ca6ed8cf5e18a7ca5ee06a91c25800cc6c58c77986202abf98d749273a"}, + {file = "PyWavelets-1.1.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:83c5e3eb78ce111c2f0b45f46106cc697c3cb6c4e5f51308e1f81b512c70c8fb"}, + {file = "PyWavelets-1.1.1-cp39-cp39-win32.whl", hash = "sha256:2b634a54241c190ee989a4af87669d377b37c91bcc9cf0efe33c10ff847f7841"}, + {file = "PyWavelets-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:732bab78435c48be5d6bc75486ef629d7c8f112e07b313bf1f1a2220ab437277"}, + {file = "PyWavelets-1.1.1.tar.gz", hash = "sha256:1a64b40f6acb4ffbaccce0545d7fc641744f95351f62e4c6aaa40549326008c9"}, +] +pyyaml = [ + {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"}, +] +requests = [ + {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"}, + {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"}, +] +requirements-detector = [ + {file = "requirements-detector-0.7.tar.gz", hash = "sha256:0d1e13e61ed243f9c3c86e6cbb19980bcb3a0e0619cde2ec1f3af70fdbee6f7b"}, +] +scipy = [ + {file = "scipy-1.6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a15a1f3fc0abff33e792d6049161b7795909b40b97c6cc2934ed54384017ab76"}, + {file = "scipy-1.6.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:e79570979ccdc3d165456dd62041d9556fb9733b86b4b6d818af7a0afc15f092"}, + {file = "scipy-1.6.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:a423533c55fec61456dedee7b6ee7dce0bb6bfa395424ea374d25afa262be261"}, + {file = "scipy-1.6.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:33d6b7df40d197bdd3049d64e8e680227151673465e5d85723b3b8f6b15a6ced"}, + {file = "scipy-1.6.1-cp37-cp37m-win32.whl", hash = "sha256:6725e3fbb47da428794f243864f2297462e9ee448297c93ed1dcbc44335feb78"}, + {file = "scipy-1.6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:5fa9c6530b1661f1370bcd332a1e62ca7881785cc0f80c0d559b636567fab63c"}, + {file = "scipy-1.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bd50daf727f7c195e26f27467c85ce653d41df4358a25b32434a50d8870fc519"}, + {file = "scipy-1.6.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:f46dd15335e8a320b0fb4685f58b7471702234cba8bb3442b69a3e1dc329c345"}, + {file = "scipy-1.6.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:0e5b0ccf63155d90da576edd2768b66fb276446c371b73841e3503be1d63fb5d"}, + {file = "scipy-1.6.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2481efbb3740977e3c831edfd0bd9867be26387cacf24eb5e366a6a374d3d00d"}, + {file = "scipy-1.6.1-cp38-cp38-win32.whl", hash = "sha256:68cb4c424112cd4be886b4d979c5497fba190714085f46b8ae67a5e4416c32b4"}, + {file = "scipy-1.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:5f331eeed0297232d2e6eea51b54e8278ed8bb10b099f69c44e2558c090d06bf"}, + {file = "scipy-1.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0c8a51d33556bf70367452d4d601d1742c0e806cd0194785914daf19775f0e67"}, + {file = "scipy-1.6.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:83bf7c16245c15bc58ee76c5418e46ea1811edcc2e2b03041b804e46084ab627"}, + {file = "scipy-1.6.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:794e768cc5f779736593046c9714e0f3a5940bc6dcc1dba885ad64cbfb28e9f0"}, + {file = "scipy-1.6.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:5da5471aed911fe7e52b86bf9ea32fb55ae93e2f0fac66c32e58897cfb02fa07"}, + {file = "scipy-1.6.1-cp39-cp39-win32.whl", hash = "sha256:8e403a337749ed40af60e537cc4d4c03febddcc56cd26e774c9b1b600a70d3e4"}, + {file = "scipy-1.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:a5193a098ae9f29af283dcf0041f762601faf2e595c0db1da929875b7570353f"}, + {file = "scipy-1.6.1.tar.gz", hash = "sha256:c4fceb864890b6168e79b0e714c585dbe2fd4222768ee90bc1aa0f8218691b11"}, +] +seaborn = [ + {file = "seaborn-0.11.2-py3-none-any.whl", hash = "sha256:85a6baa9b55f81a0623abddc4a26b334653ff4c6b18c418361de19dbba0ef283"}, + {file = "seaborn-0.11.2.tar.gz", hash = "sha256:cf45e9286d40826864be0e3c066f98536982baf701a7caa386511792d61ff4f6"}, +] +setoptconf-tmp = [ + {file = "setoptconf-tmp-0.3.1.tar.gz", hash = "sha256:e0480addd11347ba52f762f3c4d8afa3e10ad0affbc53e3ffddc0ca5f27d5778"}, + {file = "setoptconf_tmp-0.3.1-py3-none-any.whl", hash = "sha256:76035d5cd1593d38b9056ae12d460eca3aaa34ad05c315b69145e138ba80a745"}, +] +six = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] +snowballstemmer = [ + {file = "snowballstemmer-2.1.0-py2.py3-none-any.whl", hash = "sha256:b51b447bea85f9968c13b650126a888aabd4cb4463fca868ec596826325dedc2"}, + {file = "snowballstemmer-2.1.0.tar.gz", hash = "sha256:e997baa4f2e9139951b6f4c631bad912dfd3c792467e2f03d7239464af90e914"}, +] +tangled-up-in-unicode = [ + {file = "tangled_up_in_unicode-0.1.0-py3-none-any.whl", hash = "sha256:a06dea9cf93dcda6a720c46bb86a41e84372e3123c7fd6bef9e66add1dd41019"}, + {file = "tangled_up_in_unicode-0.1.0.tar.gz", hash = "sha256:d07ffa62a4d9e9e0a92582f869ac3a2859456f5c9241580c7a5d9fcf2e6e6315"}, +] +toml = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] +tqdm = [ + {file = "tqdm-4.62.3-py2.py3-none-any.whl", hash = "sha256:8dd278a422499cd6b727e6ae4061c40b48fce8b76d1ccbf5d34fca9b7f925b0c"}, + {file = "tqdm-4.62.3.tar.gz", hash = "sha256:d359de7217506c9851b7869f3708d8ee53ed70a1b8edbba4dbcb47442592920d"}, +] +typed-ast = [ + {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"}, + {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"}, + {file = "typed_ast-1.4.3-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528"}, + {file = "typed_ast-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428"}, + {file = "typed_ast-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3"}, + {file = "typed_ast-1.4.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f"}, + {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341"}, + {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace"}, + {file = "typed_ast-1.4.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f"}, + {file = "typed_ast-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363"}, + {file = "typed_ast-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7"}, + {file = "typed_ast-1.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266"}, + {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e"}, + {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04"}, + {file = "typed_ast-1.4.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899"}, + {file = "typed_ast-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c"}, + {file = "typed_ast-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805"}, + {file = "typed_ast-1.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a"}, + {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff"}, + {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41"}, + {file = "typed_ast-1.4.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39"}, + {file = "typed_ast-1.4.3-cp38-cp38-win32.whl", hash = "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927"}, + {file = "typed_ast-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40"}, + {file = "typed_ast-1.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3"}, + {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4"}, + {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0"}, + {file = "typed_ast-1.4.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3"}, + {file = "typed_ast-1.4.3-cp39-cp39-win32.whl", hash = "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808"}, + {file = "typed_ast-1.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c"}, + {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"}, ] typing-extensions = [ {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, ] -wcwidth = [ - {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, - {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, +urllib3 = [ + {file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"}, + {file = "urllib3-1.26.7.tar.gz", hash = "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece"}, +] +visions = [ + {file = "visions-0.7.1-py3-none-any.whl", hash = "sha256:138f45b007f5a58b8faa92f4d288e0da265e6ebf88ca6a5ec655922ab8fb95da"}, + {file = "visions-0.7.1.tar.gz", hash = "sha256:d9d10a0da8de80d0704c28c084282abbd3273065cd9e6a494b6fe7e3b339ee23"}, +] +wrapt = [ + {file = "wrapt-1.12.1.tar.gz", hash = "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"}, ] zipp = [ {file = "zipp-3.5.0-py3-none-any.whl", hash = "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3"}, diff --git a/pyproject.toml b/pyproject.toml index b7a0004..08c7745 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,9 @@ authors = ["Daniel Tomlinson "] python = "^3.7" [tool.poetry.dev-dependencies] -pytest = "^5.2" +# pytest = "^5.2" +prospector = "^1.5.1" +pandas-profiling = "^3.0.0" [build-system] requires = ["poetry-core>=1.0.0"] From 0f262daf39ddaf32a5803c6e73239be494d79611 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Fri, 24 Sep 2021 16:52:34 +0100 Subject: [PATCH 04/63] adding report.py --- exploration/report.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 exploration/report.py diff --git a/exploration/report.py b/exploration/report.py new file mode 100644 index 0000000..ff6fac8 --- /dev/null +++ b/exploration/report.py @@ -0,0 +1,15 @@ +from importlib import resources + +import pandas as pd +from pandas_profiling import ProfileReport + + +def main(): + with resources.path("analyse_properties.data", "pp-complete.csv") as csv_file: + df_report = pd.read_csv(csv_file) + profile = ProfileReport(df_report, title="Price Paid Data", minimal=True) + profile.to_file("price_paid_data_report.html") + + +if __name__ == "__main__": + main() From 9cf566260059e5466edb67c9720cad113f57de17 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Fri, 24 Sep 2021 16:52:40 +0100 Subject: [PATCH 05/63] updating notes --- notes/links.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 notes/links.md diff --git a/notes/links.md b/notes/links.md new file mode 100644 index 0000000..cd356f6 --- /dev/null +++ b/notes/links.md @@ -0,0 +1,11 @@ +# Links + +## Data + +Full dataset: + +`wget 0 http://prod.publicdata.landregistry.gov.uk.s3-website-eu-west-1.amazonaws.com/pp-complete.csv` + +Current month: + +`wget 0 http://prod.publicdata.landregistry.gov.uk.s3-website-eu-west-1.amazonaws.com/pp-monthly-update-new-version.csv` From ab993fc030e8b8109b6192acb1a18722c45b37e3 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sat, 25 Sep 2021 00:47:49 +0100 Subject: [PATCH 06/63] adding prospector.yaml --- prospector.yaml | 68 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 prospector.yaml diff --git a/prospector.yaml b/prospector.yaml new file mode 100644 index 0000000..fbfeef5 --- /dev/null +++ b/prospector.yaml @@ -0,0 +1,68 @@ +# This will enable almost every single warning +output-format: vscode +doc-warnings: true +# allow-shorthand: false +strictness: none + +ignore-patterns: + - (^|/)\..+ + +pylint: + run: true + disable: + - fixme + - bad-continuation + - missing-module-docstring + - logging-fstring-interpolation + - missing-function-docstring + enable: + + options: + max-locals: 15 + max-returns: 6 + max-branches: 12 + max-statements: 50 + # max-parents: 7 + max-attributes: 20 + min-public-methods: 0 + max-public-methods: 25 + max-module-lines: 1000 + max-line-length: 88 + +mccabe: + run: true + options: + max-complexity: 10 + +pep8: + run: true + options: + max-line-length: 88 + single-line-if-stmt: n + disable: + - E501 # line too long + +pyroma: + run: false + disable: + - PYR19 + - PYR16 + +pep257: + disable: + - D000 + - D203 + # - D213 + - D212 # multiline docstrings on first line only. + - D404 + - D100 + - D407 # numpy docstring format + - D107 # missing docstring in __init__ + # Docstrings ending with newlines and : in Returns block. + - D413 + - D406 + - D103 + + +dodgy: + run: true From c38a10ca2f7d4216ac01fae32ff07f0fa4bf9d32 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sat, 25 Sep 2021 00:48:04 +0100 Subject: [PATCH 07/63] updating beam to install gcp extras --- poetry.lock | 1144 +++++++++++++++++++++++++++++++++++++++++++++--- pyproject.toml | 1 + 2 files changed, 1091 insertions(+), 54 deletions(-) diff --git a/poetry.lock b/poetry.lock index 48c24b8..fc34624 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,6 +1,59 @@ +[[package]] +name = "apache-beam" +version = "2.32.0" +description = "Apache Beam SDK for Python" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +avro-python3 = ">=1.8.1,<1.9.2 || >1.9.2,<1.10.0" +cachetools = {version = ">=3.1.0,<5", optional = true, markers = "extra == \"gcp\""} +crcmod = ">=1.7,<2.0" +dill = ">=0.3.1.1,<0.3.2" +fastavro = ">=0.21.4,<2" +future = ">=0.18.2,<1.0.0" +google-apitools = {version = ">=0.5.31,<0.5.32", optional = true, markers = "extra == \"gcp\""} +google-auth = {version = ">=1.18.0,<2", optional = true, markers = "extra == \"gcp\""} +google-cloud-bigquery = {version = ">=1.6.0,<3", optional = true, markers = "extra == \"gcp\""} +google-cloud-bigtable = {version = ">=0.31.1,<2", optional = true, markers = "extra == \"gcp\""} +google-cloud-core = {version = ">=0.28.1,<2", optional = true, markers = "extra == \"gcp\""} +google-cloud-datastore = {version = ">=1.8.0,<2", optional = true, markers = "extra == \"gcp\""} +google-cloud-dlp = {version = ">=0.12.0,<2", optional = true, markers = "extra == \"gcp\""} +google-cloud-language = {version = ">=1.3.0,<2", optional = true, markers = "extra == \"gcp\""} +google-cloud-pubsub = {version = ">=0.39.0,<2", optional = true, markers = "extra == \"gcp\""} +google-cloud-recommendations-ai = {version = ">=0.1.0,<=0.2.0", optional = true, markers = "extra == \"gcp\""} +google-cloud-spanner = {version = ">=1.13.0,<2", optional = true, markers = "extra == \"gcp\""} +google-cloud-videointelligence = {version = ">=1.8.0,<2", optional = true, markers = "extra == \"gcp\""} +google-cloud-vision = {version = ">=0.38.0,<2", optional = true, markers = "extra == \"gcp\""} +grpcio = ">=1.29.0,<2" +grpcio-gcp = {version = ">=0.2.2,<1", optional = true, markers = "extra == \"gcp\""} +hdfs = ">=2.1.0,<3.0.0" +httplib2 = ">=0.8,<0.20.0" +numpy = ">=1.14.3,<1.21.0" +oauth2client = ">=2.0.1,<5" +orjson = {version = "<4.0", markers = "python_version >= \"3.6\""} +protobuf = ">=3.12.2,<4" +pyarrow = ">=0.15.1,<5.0.0" +pydot = ">=1.2.0,<2" +pymongo = ">=3.8.0,<4.0.0" +python-dateutil = ">=2.8.0,<3" +pytz = ">=2018.3" +requests = ">=2.24.0,<3.0.0" +typing-extensions = ">=3.7.0,<3.8.0" + +[package.extras] +aws = ["boto3 (>=1.9)"] +azure = ["azure-storage-blob (>=12.3.2)", "azure-core (>=1.7.0)"] +docs = ["Sphinx (>=1.5.2,<2.0)"] +gcp = ["cachetools (>=3.1.0,<5)", "google-apitools (>=0.5.31,<0.5.32)", "google-auth (>=1.18.0,<2)", "google-cloud-datastore (>=1.8.0,<2)", "google-cloud-pubsub (>=0.39.0,<2)", "google-cloud-bigquery (>=1.6.0,<3)", "google-cloud-core (>=0.28.1,<2)", "google-cloud-bigtable (>=0.31.1,<2)", "google-cloud-spanner (>=1.13.0,<2)", "grpcio-gcp (>=0.2.2,<1)", "google-cloud-dlp (>=0.12.0,<2)", "google-cloud-language (>=1.3.0,<2)", "google-cloud-videointelligence (>=1.8.0,<2)", "google-cloud-vision (>=0.38.0,<2)", "google-cloud-recommendations-ai (>=0.1.0,<=0.2.0)"] +interactive = ["facets-overview (>=1.0.0,<2)", "ipython (>=5.8.0,<8)", "ipykernel (>=5.2.0,<6)", "jupyter-client (>=6.1.11,<6.1.13)", "timeloop (>=1.0.2,<2)"] +interactive_test = ["nbformat (>=5.0.5,<6)", "nbconvert (>=5.6.1,<6)", "selenium (>=3.141.0,<4)", "needle (>=0.5.0,<1)", "chromedriver-binary (>=91,<92)", "pillow (>=7.1.1,<8)"] +test = ["freezegun (>=0.3.12)", "mock (>=1.0.1,<3.0.0)", "nose (>=1.3.7)", "nose-xunitmp (>=0.4.1)", "pandas (>=1.0,<1.3.0)", "parameterized (>=0.7.1,<0.8.0)", "pyhamcrest (>=1.9,!=1.10.0,<2.0.0)", "pyyaml (>=3.12,<6.0.0)", "requests-mock (>=1.7,<2.0)", "tenacity (>=5.0.2,<6.0)", "pytest (>=4.4.0,<5.0)", "pytest-xdist (>=1.29.0,<2)", "pytest-timeout (>=1.3.3,<2)", "sqlalchemy (>=1.3,<2.0)", "psycopg2-binary (>=2.8.5,<3.0.0)", "testcontainers (>=3.0.3,<4.0.0)"] + [[package]] name = "astroid" -version = "2.8.0" +version = "2.7.3" description = "An abstract syntax tree for Python with inference support." category = "dev" optional = false @@ -9,7 +62,7 @@ python-versions = "~=3.6" [package.dependencies] lazy-object-proxy = ">=1.4.0" typed-ast = {version = ">=1.4.0,<1.5", markers = "implementation_name == \"cpython\" and python_version < \"3.8\""} -typing-extensions = {version = ">=3.10", markers = "python_version < \"3.10\""} +typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} wrapt = ">=1.11,<1.13" [[package]] @@ -26,6 +79,18 @@ docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] +[[package]] +name = "avro-python3" +version = "1.9.2.1" +description = "Avro is a serialization and RPC framework." +category = "main" +optional = false +python-versions = ">=3.5" + +[package.extras] +snappy = ["python-snappy"] +zstandard = ["zstandard"] + [[package]] name = "bottleneck" version = "1.3.2" @@ -40,11 +105,19 @@ numpy = "*" [package.extras] doc = ["numpydoc", "sphinx", "gitpython"] +[[package]] +name = "cachetools" +version = "4.2.2" +description = "Extensible memoizing collections and decorators" +category = "main" +optional = false +python-versions = "~=3.5" + [[package]] name = "certifi" version = "2021.5.30" description = "Python package for providing Mozilla's CA Bundle." -category = "dev" +category = "main" optional = false python-versions = "*" @@ -52,7 +125,7 @@ python-versions = "*" name = "charset-normalizer" version = "2.0.6" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "dev" +category = "main" optional = false python-versions = ">=3.5.0" @@ -67,6 +140,14 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +[[package]] +name = "crcmod" +version = "1.7" +description = "CRC Generator" +category = "main" +optional = false +python-versions = "*" + [[package]] name = "cycler" version = "0.10.0" @@ -78,6 +159,25 @@ python-versions = "*" [package.dependencies] six = "*" +[[package]] +name = "dill" +version = "0.3.1.1" +description = "serialize all of python" +category = "main" +optional = false +python-versions = ">=2.6, !=3.0.*" + +[package.extras] +graph = ["objgraph (>=1.7.2)"] + +[[package]] +name = "docopt" +version = "0.6.2" +description = "Pythonic argument parser, that will make you smile" +category = "main" +optional = false +python-versions = "*" + [[package]] name = "dodgy" version = "0.2.1" @@ -86,6 +186,31 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "fastavro" +version = "1.4.5" +description = "Fast read/write of AVRO files" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +codecs = ["python-snappy", "zstandard", "lz4"] +lz4 = ["lz4"] +snappy = ["python-snappy"] +zstandard = ["zstandard"] + +[[package]] +name = "fasteners" +version = "0.16.3" +description = "A python package that provides useful locks." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +six = "*" + [[package]] name = "flake8" version = "3.9.2" @@ -111,6 +236,320 @@ python-versions = "*" [package.dependencies] flake8 = "*" +[[package]] +name = "future" +version = "0.18.2" +description = "Clean single-source support for Python 3 and 2" +category = "main" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "google-api-core" +version = "1.31.2" +description = "Google API client core library" +category = "main" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*" + +[package.dependencies] +google-auth = ">=1.25.0,<2.0dev" +googleapis-common-protos = ">=1.6.0,<2.0dev" +grpcio = {version = ">=1.29.0,<2.0dev", optional = true, markers = "extra == \"grpc\""} +grpcio-gcp = {version = ">=0.2.2", optional = true, markers = "extra == \"grpcgcp\""} +packaging = ">=14.3" +protobuf = ">=3.12.0" +pytz = "*" +requests = ">=2.18.0,<3.0.0dev" +six = ">=1.13.0" + +[package.extras] +grpc = ["grpcio (>=1.29.0,<2.0dev)"] +grpcgcp = ["grpcio-gcp (>=0.2.2)"] +grpcio-gcp = ["grpcio-gcp (>=0.2.2)"] + +[[package]] +name = "google-apitools" +version = "0.5.31" +description = "client libraries for humans" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.dependencies] +fasteners = ">=0.14" +httplib2 = ">=0.8" +oauth2client = ">=1.4.12" +six = ">=1.12.0" + +[package.extras] +cli = ["python-gflags (>=3.0.6)"] +testing = ["mock (>=1.0.1)"] + +[[package]] +name = "google-auth" +version = "1.35.0" +description = "Google Authentication Library" +category = "main" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*" + +[package.dependencies] +cachetools = ">=2.0.0,<5.0" +pyasn1-modules = ">=0.2.1" +rsa = {version = ">=3.1.4,<5", markers = "python_version >= \"3.6\""} +six = ">=1.9.0" + +[package.extras] +aiohttp = ["requests (>=2.20.0,<3.0.0dev)", "aiohttp (>=3.6.2,<4.0.0dev)"] +pyopenssl = ["pyopenssl (>=20.0.0)"] +reauth = ["pyu2f (>=0.1.5)"] + +[[package]] +name = "google-cloud-bigquery" +version = "2.6.1" +description = "Google BigQuery API client library" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +google-api-core = {version = ">=1.23.0,<2.0.0dev", extras = ["grpc"]} +google-cloud-core = ">=1.4.1,<2.0dev" +google-resumable-media = ">=0.6.0,<2.0dev" +proto-plus = ">=1.10.0" +protobuf = ">=3.12.0" +six = ">=1.13.0,<2.0.0dev" + +[package.extras] +all = ["google-cloud-bigquery-storage (>=2.0.0,<3.0.0dev)", "grpcio (>=1.32.0,<2.0dev)", "pyarrow (>=1.0.0,<3.0dev)", "pandas (>=0.23.0)", "tqdm (>=4.7.4,<5.0.0dev)", "opentelemetry-api (==0.11b0)", "opentelemetry-sdk (==0.11b0)", "opentelemetry-instrumentation (==0.11b0)"] +bqstorage = ["google-cloud-bigquery-storage (>=2.0.0,<3.0.0dev)", "grpcio (>=1.32.0,<2.0dev)", "pyarrow (>=1.0.0,<3.0dev)"] +opentelemetry = ["opentelemetry-api (==0.11b0)", "opentelemetry-sdk (==0.11b0)", "opentelemetry-instrumentation (==0.11b0)"] +pandas = ["pandas (>=0.23.0)", "pyarrow (>=1.0.0,<3.0dev)"] +tqdm = ["tqdm (>=4.7.4,<5.0.0dev)"] + +[[package]] +name = "google-cloud-bigtable" +version = "1.7.0" +description = "Google Cloud Bigtable API client library" +category = "main" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" + +[package.dependencies] +google-api-core = {version = ">=1.14.0,<2.0.0dev", extras = ["grpc"]} +google-cloud-core = ">=1.4.1,<2.0dev" +grpc-google-iam-v1 = ">=0.12.3,<0.13dev" + +[[package]] +name = "google-cloud-core" +version = "1.7.2" +description = "Google Cloud API client core library" +category = "main" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*" + +[package.dependencies] +google-api-core = ">=1.21.0,<2.0.0dev" +google-auth = ">=1.24.0,<2.0dev" +six = ">=1.12.0" + +[package.extras] +grpc = ["grpcio (>=1.8.2,<2.0dev)"] + +[[package]] +name = "google-cloud-datastore" +version = "1.15.3" +description = "Google Cloud Datastore API client library" +category = "main" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" + +[package.dependencies] +google-api-core = {version = ">=1.14.0,<2.0.0dev", extras = ["grpc"]} +google-cloud-core = ">=1.4.0,<2.0dev" + +[[package]] +name = "google-cloud-dlp" +version = "1.0.0" +description = "Cloud Data Loss Prevention (DLP) API API client library" +category = "main" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" + +[package.dependencies] +google-api-core = {version = ">=1.14.0,<2.0.0dev", extras = ["grpc"]} + +[[package]] +name = "google-cloud-language" +version = "1.3.0" +description = "Google Cloud Natural Language API client library" +category = "main" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" + +[package.dependencies] +google-api-core = {version = ">=1.14.0,<2.0.0dev", extras = ["grpc"]} + +[[package]] +name = "google-cloud-pubsub" +version = "1.7.0" +description = "Google Cloud Pub/Sub API client library" +category = "main" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" + +[package.dependencies] +google-api-core = {version = ">=1.14.0,<1.17.0 || >=1.20.0", extras = ["grpc"]} +grpc-google-iam-v1 = ">=0.12.3,<0.13dev" + +[[package]] +name = "google-cloud-recommendations-ai" +version = "0.2.0" +description = "" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +google-api-core = {version = ">=1.22.2,<2.0.0dev", extras = ["grpc"]} +proto-plus = ">=1.15.0" + +[[package]] +name = "google-cloud-spanner" +version = "1.19.1" +description = "Cloud Spanner API client library" +category = "main" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" + +[package.dependencies] +google-api-core = {version = ">=1.14.0,<2.0.0dev", extras = ["grpc", "grpcgcp"]} +google-cloud-core = ">=1.4.1,<2.0dev" +grpc-google-iam-v1 = ">=0.12.3,<0.13dev" + +[package.extras] +tracing = ["opentelemetry-api (==0.11b0)", "opentelemetry-sdk (==0.11b0)", "opentelemetry-instrumentation (==0.11b0)"] + +[[package]] +name = "google-cloud-videointelligence" +version = "1.16.1" +description = "Google Cloud Video Intelligence API client library" +category = "main" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" + +[package.dependencies] +google-api-core = {version = ">=1.14.0,<2.0.0dev", extras = ["grpc"]} + +[[package]] +name = "google-cloud-vision" +version = "1.0.0" +description = "Cloud Vision API API client library" +category = "main" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" + +[package.dependencies] +google-api-core = {version = ">=1.14.0,<2.0.0dev", extras = ["grpc"]} + +[[package]] +name = "google-crc32c" +version = "1.2.0" +description = "A python wrapper of the C library 'Google CRC32C'" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +testing = ["pytest"] + +[[package]] +name = "google-resumable-media" +version = "1.3.3" +description = "Utilities for Google Media Downloads and Resumable Uploads" +category = "main" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*" + +[package.dependencies] +google-crc32c = {version = ">=1.0,<2.0dev", markers = "python_version >= \"3.5\""} +six = ">=1.4.0" + +[package.extras] +aiohttp = ["aiohttp (>=3.6.2,<4.0.0dev)"] +requests = ["requests (>=2.18.0,<3.0.0dev)"] + +[[package]] +name = "googleapis-common-protos" +version = "1.53.0" +description = "Common protobufs used in Google APIs" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +grpcio = {version = ">=1.0.0", optional = true, markers = "extra == \"grpc\""} +protobuf = ">=3.12.0" + +[package.extras] +grpc = ["grpcio (>=1.0.0)"] + +[[package]] +name = "grpc-google-iam-v1" +version = "0.12.3" +description = "GRPC library for the google-iam-v1 service" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +googleapis-common-protos = {version = ">=1.5.2,<2.0.0dev", extras = ["grpc"]} +grpcio = ">=1.0.0,<2.0.0dev" + +[[package]] +name = "grpcio" +version = "1.40.0" +description = "HTTP/2-based RPC framework" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +six = ">=1.5.2" + +[package.extras] +protobuf = ["grpcio-tools (>=1.40.0)"] + +[[package]] +name = "grpcio-gcp" +version = "0.2.2" +description = "gRPC extensions for Google Cloud Platform" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +grpcio = ">=1.12.0" + +[[package]] +name = "hdfs" +version = "2.6.0" +description = "HdfsCLI: API and command line interface for HDFS." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +docopt = "*" +requests = ">=2.7.0" +six = ">=1.9.0" + +[package.extras] +avro = ["fastavro (>=0.21.19)"] +dataframe = ["fastavro (>=0.21.19)", "pandas (>=0.14.1)"] +kerberos = ["requests-kerberos (>=0.7.0)"] + [[package]] name = "htmlmin" version = "0.1.12" @@ -119,11 +558,22 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "httplib2" +version = "0.19.1" +description = "A comprehensive HTTP client library." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +pyparsing = ">=2.4.2,<3" + [[package]] name = "idna" version = "3.2" description = "Internationalized Domain Names in Applications (IDNA)" -category = "dev" +category = "main" optional = false python-versions = ">=3.5" @@ -288,12 +738,46 @@ test = ["pytest (>=6.2)", "pytest-cov (>=2.12)", "codecov (>=2.1)"] [[package]] name = "numpy" -version = "1.21.1" +version = "1.20.3" description = "NumPy is the fundamental package for array computing with Python." -category = "dev" +category = "main" optional = false python-versions = ">=3.7" +[[package]] +name = "oauth2client" +version = "4.1.3" +description = "OAuth 2.0 client library" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +httplib2 = ">=0.9.1" +pyasn1 = ">=0.1.7" +pyasn1-modules = ">=0.0.5" +rsa = ">=3.1.4" +six = ">=1.6.1" + +[[package]] +name = "orjson" +version = "3.6.3" +description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "packaging" +version = "21.0" +description = "Core utilities for Python packages" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pyparsing = ">=2.0.2" + [[package]] name = "pandas" version = "1.1.5" @@ -421,6 +905,58 @@ with_mypy = ["mypy (>=0.600)"] with_pyroma = ["pyroma (>=2.4)"] with_vulture = ["vulture (>=1.5)"] +[[package]] +name = "proto-plus" +version = "1.19.0" +description = "Beautiful, Pythonic protocol buffers." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +protobuf = ">=3.12.0" + +[package.extras] +testing = ["google-api-core[grpc] (>=1.22.2)"] + +[[package]] +name = "protobuf" +version = "3.18.0" +description = "Protocol Buffers" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pyarrow" +version = "4.0.1" +description = "Python library for Apache Arrow" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +numpy = ">=1.16.6" + +[[package]] +name = "pyasn1" +version = "0.4.8" +description = "ASN.1 types and codecs" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pyasn1-modules" +version = "0.2.8" +description = "A collection of ASN.1-based protocols modules." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +pyasn1 = ">=0.4.6,<0.5.0" + [[package]] name = "pycodestyle" version = "2.7.0" @@ -458,6 +994,17 @@ snowballstemmer = "*" [package.extras] toml = ["toml"] +[[package]] +name = "pydot" +version = "1.4.2" +description = "Python interface to Graphviz's Dot" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.dependencies] +pyparsing = ">=2.1.4" + [[package]] name = "pyflakes" version = "2.3.1" @@ -468,20 +1015,19 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pylint" -version = "2.11.1" +version = "2.10.2" description = "python code static checker" category = "dev" optional = false python-versions = "~=3.6" [package.dependencies] -astroid = ">=2.8.0,<2.9" +astroid = ">=2.7.2,<2.8" colorama = {version = "*", markers = "sys_platform == \"win32\""} isort = ">=4.2.5,<6" mccabe = ">=0.6,<0.7" platformdirs = ">=2.2.0" toml = ">=0.7.1" -typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} [[package]] name = "pylint-celery" @@ -534,11 +1080,29 @@ python-versions = "*" [package.dependencies] pylint = ">=1.7" +[[package]] +name = "pymongo" +version = "3.12.0" +description = "Python driver for MongoDB " +category = "main" +optional = false +python-versions = "*" + +[package.extras] +aws = ["pymongo-auth-aws (<2.0.0)"] +encryption = ["pymongocrypt (>=1.1.0,<2.0.0)"] +gssapi = ["pykerberos"] +ocsp = ["pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)", "certifi"] +snappy = ["python-snappy"] +srv = ["dnspython (>=1.16.0,<1.17.0)"] +tls = ["ipaddress"] +zstd = ["zstandard"] + [[package]] name = "pyparsing" version = "2.4.7" description = "Python parsing module" -category = "dev" +category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" @@ -546,7 +1110,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" name = "python-dateutil" version = "2.8.2" description = "Extensions to the standard Python datetime module" -category = "dev" +category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" @@ -557,7 +1121,7 @@ six = ">=1.5" name = "pytz" version = "2021.1" description = "World timezone definitions, modern and historical" -category = "dev" +category = "main" optional = false python-versions = "*" @@ -584,7 +1148,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" name = "requests" version = "2.26.0" description = "Python HTTP for Humans." -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" @@ -609,6 +1173,17 @@ python-versions = "*" [package.dependencies] astroid = ">=1.4" +[[package]] +name = "rsa" +version = "4.7.2" +description = "Pure-Python RSA implementation" +category = "main" +optional = false +python-versions = ">=3.5, <4" + +[package.dependencies] +pyasn1 = ">=0.1.3" + [[package]] name = "scipy" version = "1.6.1" @@ -649,7 +1224,7 @@ yaml = ["pyyaml"] name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" @@ -703,9 +1278,9 @@ python-versions = "*" [[package]] name = "typing-extensions" -version = "3.10.0.2" +version = "3.7.4.3" description = "Backported and Experimental Type Hints for Python 3.5+" -category = "dev" +category = "main" optional = false python-versions = "*" @@ -713,7 +1288,7 @@ python-versions = "*" name = "urllib3" version = "1.26.7" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" @@ -772,20 +1347,54 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytes [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "37d2685eea70126a1b18ebe5b57cccbc14c46e647cdf5656534a74fb5aba2e61" +content-hash = "a4abffb384d330caa6dc399968726f1f73ea5fd7df5aa7010c1ea3bac4156338" [metadata.files] +apache-beam = [ + {file = "apache-beam-2.32.0.zip", hash = "sha256:7ae2268577c582c10beedaed399a5d21752e633e8e2c86867354697c5ca4fbb1"}, + {file = "apache_beam-2.32.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:de479e86c49a80380af36f7196ed4c3f51b5864b7557c0aae0e3e6807c2be61e"}, + {file = "apache_beam-2.32.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:e877c5d3b0de3568f59c7a96dea5c1a2e328ac8967ca7159b8d5c85c4ddb4014"}, + {file = "apache_beam-2.32.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:58c0404f8f2c28cd899bfd5060ac594a78a0345aefd43e8e134be3bdbed36bf7"}, + {file = "apache_beam-2.32.0-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:eec887207b5ec19fdbd826a7102ac9d29c70368e5825fb75164e2eb29283bddb"}, + {file = "apache_beam-2.32.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:9c5329428e03fd2086437b232efe1e1734f2ab3677fc6187c60e13a2f144ddcd"}, + {file = "apache_beam-2.32.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:906d4f10f4cd6609648071820d3928fa8ecf6559b3316d953f3694f7e5eb6c30"}, + {file = "apache_beam-2.32.0-cp36-cp36m-win32.whl", hash = "sha256:19111b3679764051a2383675967579eff22d503f79e77482a7617a58a7e44e21"}, + {file = "apache_beam-2.32.0-cp36-cp36m-win_amd64.whl", hash = "sha256:9831714f92ca3657497e665761f2bd9db93b020cbdb2ee05ec1099ec7d12eff9"}, + {file = "apache_beam-2.32.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d310395861980dfd495f8c82526004143ca38be314e23441caf89de759b0cb4d"}, + {file = "apache_beam-2.32.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:7d851b59800cdddf1410cd1a865c96cc6c450c416874cefe622ad4585737b630"}, + {file = "apache_beam-2.32.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:cbe5dbc515e5dba0aef40118433491b30f797bdee248d2f9caaf07c61fa2c892"}, + {file = "apache_beam-2.32.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:83d5b63302cf49ed823658d4fc5e2ddfca762e7233fe48ae50841e90eb86c7cd"}, + {file = "apache_beam-2.32.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:fecab6549be7a309cde2c5711f0cac4e69ff3826880e82d6f8120e6c8dfbef30"}, + {file = "apache_beam-2.32.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cdb22c0e8f9db071e9e0357379e7bec9c738e0ddf696c1f91e5cbafefe6d3278"}, + {file = "apache_beam-2.32.0-cp37-cp37m-win32.whl", hash = "sha256:468e5403e4628309a492de2cc5d1162119a1bf1ebd5c67cf91c6ef83bc512f18"}, + {file = "apache_beam-2.32.0-cp37-cp37m-win_amd64.whl", hash = "sha256:f0bc4debf97e3120297bdc2dd983fe20a9487499dabb2059ff0f331277c79352"}, + {file = "apache_beam-2.32.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:676bdc610d4ff32c3216a60755105f70ef552cadf6c2f2ab8a0fa7ffee7c05ba"}, + {file = "apache_beam-2.32.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:f5d31d18e68237d0512b2256e38913dfe01ceec8a9e8efe09547e4f7df6a2eee"}, + {file = "apache_beam-2.32.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:ad8626a8d321f9a757ed747e792a87d9f870f95521fc59002eb10dad8940c356"}, + {file = "apache_beam-2.32.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:cb43ba5d1d0678457f201149d6ff34f93ab4af79c4bc4ac2a97d6d4953255223"}, + {file = "apache_beam-2.32.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:03f3897cf492c8b468fa8b160065dd4f98a9ab4e288ed6d0022b60a200b61da5"}, + {file = "apache_beam-2.32.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:c38ca4cd77efb6037e7e010e1a6227f0d9a2c62a345f4ac9e37b5598138187e6"}, + {file = "apache_beam-2.32.0-cp38-cp38-win32.whl", hash = "sha256:8bbce31dda6cc675b7c9d5ef27f78902500cbb3a40f8b5506e899d2325a4d96f"}, + {file = "apache_beam-2.32.0-cp38-cp38-win_amd64.whl", hash = "sha256:2faf26a10c37e7fa96ea0efbd50acace2cb2d66a70e8a480902944d81ed2335f"}, +] astroid = [ - {file = "astroid-2.8.0-py3-none-any.whl", hash = "sha256:dcc06f6165f415220013801642bd6c9808a02967070919c4b746c6864c205471"}, - {file = "astroid-2.8.0.tar.gz", hash = "sha256:fe81f80c0b35264acb5653302ffbd935d394f1775c5e4487df745bf9c2442708"}, + {file = "astroid-2.7.3-py3-none-any.whl", hash = "sha256:dc1e8b28427d6bbef6b8842b18765ab58f558c42bb80540bd7648c98412af25e"}, + {file = "astroid-2.7.3.tar.gz", hash = "sha256:3b680ce0419b8a771aba6190139a3998d14b413852506d99aff8dc2bf65ee67c"}, ] attrs = [ {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, ] +avro-python3 = [ + {file = "avro-python3-1.9.2.1.tar.gz", hash = "sha256:ca1e77a3da5ac98e8833588f71fb2e170b38e34787ee0e04920de0e9470b7d32"}, +] bottleneck = [ {file = "Bottleneck-1.3.2.tar.gz", hash = "sha256:20179f0b66359792ea283b69aa16366419132f3b6cf3adadc0c48e2e8118e573"}, ] +cachetools = [ + {file = "cachetools-4.2.2-py3-none-any.whl", hash = "sha256:2cc0b89715337ab6dbba85b5b50effe2b0c74e035d83ee8ed637cf52f12ae001"}, + {file = "cachetools-4.2.2.tar.gz", hash = "sha256:61b5ed1e22a0924aed1d23b478f37e8d52549ff8a961de2909c69bf950020cff"}, +] certifi = [ {file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"}, {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"}, @@ -798,14 +1407,49 @@ colorama = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] +crcmod = [ + {file = "crcmod-1.7.tar.gz", hash = "sha256:dc7051a0db5f2bd48665a990d3ec1cc305a466a77358ca4492826f41f283601e"}, + {file = "crcmod-1.7.win32-py2.6.msi", hash = "sha256:69a2e5c6c36d0f096a7beb4cd34e5f882ec5fd232efb710cdb85d4ff196bd52e"}, + {file = "crcmod-1.7.win32-py2.7.msi", hash = "sha256:737fb308fa2ce9aed2e29075f0d5980d4a89bfbec48a368c607c5c63b3efb90e"}, + {file = "crcmod-1.7.win32-py3.1.msi", hash = "sha256:50586ab48981f11e5b117523d97bb70864a2a1af246cf6e4f5c4a21ef4611cd1"}, +] cycler = [ {file = "cycler-0.10.0-py2.py3-none-any.whl", hash = "sha256:1d8a5ae1ff6c5cf9b93e8811e581232ad8920aeec647c37316ceac982b08cb2d"}, {file = "cycler-0.10.0.tar.gz", hash = "sha256:cd7b2d1018258d7247a71425e9f26463dfb444d411c39569972f4ce586b0c9d8"}, ] +dill = [ + {file = "dill-0.3.1.1.tar.gz", hash = "sha256:42d8ef819367516592a825746a18073ced42ca169ab1f5f4044134703e7a049c"}, +] +docopt = [ + {file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"}, +] dodgy = [ {file = "dodgy-0.2.1-py3-none-any.whl", hash = "sha256:51f54c0fd886fa3854387f354b19f429d38c04f984f38bc572558b703c0542a6"}, {file = "dodgy-0.2.1.tar.gz", hash = "sha256:28323cbfc9352139fdd3d316fa17f325cc0e9ac74438cbba51d70f9b48f86c3a"}, ] +fastavro = [ + {file = "fastavro-1.4.5-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:48e6907088c058342635b577427c8d78ab18c8d20ca58a0c5365e5eb3157c6e2"}, + {file = "fastavro-1.4.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ee068012da1d262f2ae60798ad142cb7dd91eac21d04f379553924b91a46fff"}, + {file = "fastavro-1.4.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b95e003a4c6668c102bd39cdeda7bdf38c16db46926a0b9f92800836e437f7"}, + {file = "fastavro-1.4.5-cp36-cp36m-win_amd64.whl", hash = "sha256:6187bf2a37c2ca33a78bc424e874869b35593fcd059988487faa02f6b7b57f73"}, + {file = "fastavro-1.4.5-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:e7ea611a956c508bd97d2a2bc17c3fcdec48bd1151ad05b0e251bf2e50994665"}, + {file = "fastavro-1.4.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:431d382657812d9b24f2d16663841721187e7e89b137b8b34fdeee7809d66e88"}, + {file = "fastavro-1.4.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06b531f1be2878c3eef7efdc68d637a3bfe2b6b074edde30ab6321bbb5ac1961"}, + {file = "fastavro-1.4.5-cp37-cp37m-win_amd64.whl", hash = "sha256:5d8163fe404c1c48ce973772b5a00d1f696ae04c5e3ae4aa63c89276e617af63"}, + {file = "fastavro-1.4.5-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:fe37f2e2e8e1170abe50dd113a730ffcb64d75b5a68997da2b22bb8545439642"}, + {file = "fastavro-1.4.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cad773eccad51271faacafb7a4bb8c387e456eb419090cb529c116a4d918a89"}, + {file = "fastavro-1.4.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a60af4595b68838ce736aec0e9221d3e50dd29f26c6409f63f41256bfb6ef5c8"}, + {file = "fastavro-1.4.5-cp38-cp38-win_amd64.whl", hash = "sha256:4dfcd2401759a80da6ceb4e46af660626d77c235b903db09c74d031f8e02a219"}, + {file = "fastavro-1.4.5-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:246cc9043b31a004e13204fef72917bdb4886b752defe08eb32da3d87123802f"}, + {file = "fastavro-1.4.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61603a2b46cd6ca06a250fec3011c40400683c9b57d934f3e4d5cc3fe0f3d254"}, + {file = "fastavro-1.4.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fafe37983605ed74a5ca8063951f6d5984ad871e0ff895f14afa81a6d88c316e"}, + {file = "fastavro-1.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:4043ca61362601dbc9b0b51e852207130677842e93d95b5a5327c3ad478f14e1"}, + {file = "fastavro-1.4.5.tar.gz", hash = "sha256:fb5b4b46bd9f89be07921752bac952daa872a79f94fadf01f3679da906824424"}, +] +fasteners = [ + {file = "fasteners-0.16.3-py2.py3-none-any.whl", hash = "sha256:8408e52656455977053871990bd25824d85803b9417aa348f10ba29ef0c751f7"}, + {file = "fasteners-0.16.3.tar.gz", hash = "sha256:b1ab4e5adfbc28681ce44b3024421c4f567e705cc3963c732bf1cba3348307de"}, +] flake8 = [ {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, @@ -814,9 +1458,182 @@ flake8-polyfill = [ {file = "flake8-polyfill-1.0.2.tar.gz", hash = "sha256:e44b087597f6da52ec6393a709e7108b2905317d0c0b744cdca6208e670d8eda"}, {file = "flake8_polyfill-1.0.2-py2.py3-none-any.whl", hash = "sha256:12be6a34ee3ab795b19ca73505e7b55826d5f6ad7230d31b18e106400169b9e9"}, ] +future = [ + {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, +] +google-api-core = [ + {file = "google-api-core-1.31.2.tar.gz", hash = "sha256:8500aded318fdb235130bf183c726a05a9cb7c4b09c266bd5119b86cdb8a4d10"}, + {file = "google_api_core-1.31.2-py2.py3-none-any.whl", hash = "sha256:384459a0dc98c1c8cd90b28dc5800b8705e0275a673a7144a513ae80fc77950b"}, +] +google-apitools = [ + {file = "google-apitools-0.5.31.tar.gz", hash = "sha256:4af0dd6dd4582810690251f0b57a97c1873dadfda54c5bc195844c8907624170"}, + {file = "google_apitools-0.5.31-py2-none-any.whl", hash = "sha256:6be92c1c3e93485450420bb0e365d47eb4d8a835d03ebe1963dc6da4d39a7b0e"}, +] +google-auth = [ + {file = "google-auth-1.35.0.tar.gz", hash = "sha256:b7033be9028c188ee30200b204ea00ed82ea1162e8ac1df4aa6ded19a191d88e"}, + {file = "google_auth-1.35.0-py2.py3-none-any.whl", hash = "sha256:997516b42ecb5b63e8d80f5632c1a61dddf41d2a4c2748057837e06e00014258"}, +] +google-cloud-bigquery = [ + {file = "google-cloud-bigquery-2.6.1.tar.gz", hash = "sha256:1f99fd0c0c5bde999e056a1be666e5d5bbf392f62c9e730dfcbaf6e8408d44ef"}, + {file = "google_cloud_bigquery-2.6.1-py2.py3-none-any.whl", hash = "sha256:4b4593c45e78ee5d2e55b3aa7156839e8fbc4c3b9ed2d70715c820dce48cdf97"}, +] +google-cloud-bigtable = [ + {file = "google-cloud-bigtable-1.7.0.tar.gz", hash = "sha256:90bd53a19c33c34101b8567c82a6dc0386af4118d70e1ad69b49375358a21aa6"}, + {file = "google_cloud_bigtable-1.7.0-py2.py3-none-any.whl", hash = "sha256:e372b72c573309cb4f2b9998baac5d881ba023bae500841683e8d0849641f955"}, +] +google-cloud-core = [ + {file = "google-cloud-core-1.7.2.tar.gz", hash = "sha256:b1030aadcbb2aeb4ee51475426351af83c1072456b918fb8fdb80666c4bb63b5"}, + {file = "google_cloud_core-1.7.2-py2.py3-none-any.whl", hash = "sha256:5b77935f3d9573e27007749a3b522f08d764c5b5930ff1527b2ab2743e9f0c15"}, +] +google-cloud-datastore = [ + {file = "google-cloud-datastore-1.15.3.tar.gz", hash = "sha256:3da44b4c8230a83e69dd9429324cca9d3000ee8a8bb11f3b005c7837fcd844b3"}, + {file = "google_cloud_datastore-1.15.3-py2.py3-none-any.whl", hash = "sha256:961b75b1d4b09eb044fc59825633efd8495471bf9bc015d989b8639be89ce439"}, +] +google-cloud-dlp = [ + {file = "google-cloud-dlp-1.0.0.tar.gz", hash = "sha256:2ccf04209f96b4759d8ed76da2c916a456386836caacd47ce01b6344f5b8f212"}, + {file = "google_cloud_dlp-1.0.0-py2.py3-none-any.whl", hash = "sha256:e0c57337c3fbe2bf22cc4d4deaf3d58a21603718301ee9ee4806b49f59a52e5a"}, +] +google-cloud-language = [ + {file = "google-cloud-language-1.3.0.tar.gz", hash = "sha256:2772badf8fe8ac57cd7e7840a60764603b3e19e6dbd843460a5ae8915798b32f"}, + {file = "google_cloud_language-1.3.0-py2.py3-none-any.whl", hash = "sha256:76e349fcc223c66b9aa138e05853f4bf550f0d06e37641c2c206dc2661b83f30"}, +] +google-cloud-pubsub = [ + {file = "google-cloud-pubsub-1.7.0.tar.gz", hash = "sha256:c8d098ebd208d00c8f3bb55eefecd8553e7391d59700426a97d35125f0dcb248"}, + {file = "google_cloud_pubsub-1.7.0-py2.py3-none-any.whl", hash = "sha256:b7f577621f991b513034c50f3314ef66838701b3b0dd1fca0d5e9a0e82f9f801"}, +] +google-cloud-recommendations-ai = [ + {file = "google-cloud-recommendations-ai-0.2.0.tar.gz", hash = "sha256:063acb4034469b16c430c77cdb2f49225272d86e82ccbaf9fcabfe77fd0e7a69"}, + {file = "google_cloud_recommendations_ai-0.2.0-py2.py3-none-any.whl", hash = "sha256:b2180516386edfa5ec0cc1050cc7c58ac1a7fd085a178c8edc2bbe0b6ebc925f"}, +] +google-cloud-spanner = [ + {file = "google-cloud-spanner-1.19.1.tar.gz", hash = "sha256:50c375d8224415b7b7cc19a720c745cd8fb49144db50b252d06c42121374312d"}, + {file = "google_cloud_spanner-1.19.1-py2.py3-none-any.whl", hash = "sha256:ff6869e50eb284854fec864fcaa26139c04ded7ed522ae488fff3b08ffc5dc30"}, +] +google-cloud-videointelligence = [ + {file = "google-cloud-videointelligence-1.16.1.tar.gz", hash = "sha256:bbde4a5bb479f60466dabad67d5debb30448bb2451b67bba3bfd9b67281a230a"}, + {file = "google_cloud_videointelligence-1.16.1-py2.py3-none-any.whl", hash = "sha256:98a5d043d4824ad0529f8c2a3108bc4e1ed530e76314ea2c0e39f3d81cdf378e"}, +] +google-cloud-vision = [ + {file = "google-cloud-vision-1.0.0.tar.gz", hash = "sha256:18e78b190c81d200ae4f6a46d4af57422d68b3b05b0540d5cd1806e3874142bf"}, + {file = "google_cloud_vision-1.0.0-py2.py3-none-any.whl", hash = "sha256:e61091a52f334a20e597b74e2fb42c9f27dda25323544cd157d6110fde26c9a6"}, +] +google-crc32c = [ + {file = "google-crc32c-1.2.0.tar.gz", hash = "sha256:258caf72c4ab03d91e593ed9f988c13c118754f5ce46d8bcbc40b109d14cb8b7"}, + {file = "google_crc32c-1.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b64bd23a66410883c22c156834b73515e3f3d8c890c0407620f960b4c25cc8a3"}, + {file = "google_crc32c-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:61080f164ea51e156153c601b1de35ccb574d77efb669c11ade75f8635ce2d29"}, + {file = "google_crc32c-1.2.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f563a48074de0a4ebf1ef1d55aeb16bdaa6715c33091dad3b6a32716d2a5d4a4"}, + {file = "google_crc32c-1.2.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:242274e127e349e6ede67d7232872bdac9f6c36da6233216e8e4f5923eef1a7c"}, + {file = "google_crc32c-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93f1377269cf30b15b296e760ac3f6e13ea52556a764739410fa2e7b32a39e93"}, + {file = "google_crc32c-1.2.0-cp310-cp310-win32.whl", hash = "sha256:60f9e93e29cbaa47f57230907733af884685dbac78d462019ffe02d514bbfddc"}, + {file = "google_crc32c-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:b28e81707257802d1e07aee4a2513d1316f623a1b48b78885c1ca2a9ec47949d"}, + {file = "google_crc32c-1.2.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:837a17d940dac5b0d0a88868a2be924bbb31578de20c250620c09ac7c3f9d1fd"}, + {file = "google_crc32c-1.2.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:966186c535fec30606cb7787e3caa283631f80c50cbd7226e7db1589ede0f177"}, + {file = "google_crc32c-1.2.0-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:617ec1f65d769e670dd35d9e8db0244d03bb09b8728262e28ebeab82de8d1341"}, + {file = "google_crc32c-1.2.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca0f7bcb47dbd1367bb8f2d7dfc90568a7f69e4062dd70b21a365fc361c9929d"}, + {file = "google_crc32c-1.2.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e7b98a2dabe06a460219ecad21113d1c9d793910ceeeae8b4fb64871ef203c4c"}, + {file = "google_crc32c-1.2.0-cp36-cp36m-win32.whl", hash = "sha256:a6307368bc04f07d3bdf554109d5ebd64b350c12e1a3604686e7a2d913585b1e"}, + {file = "google_crc32c-1.2.0-cp36-cp36m-win_amd64.whl", hash = "sha256:4b2f3a9f61f264029ffbaf9f503340da1e72e602650eb46d34940a431e3a2676"}, + {file = "google_crc32c-1.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ce877f9ce49db4f465d942ea910475d79148b390e5890efb2e505df9596d5ced"}, + {file = "google_crc32c-1.2.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c9a057c13a268c3a03d1fc8aa08358952b7ff560bb2893fe46dd5823cc0f47b7"}, + {file = "google_crc32c-1.2.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ad1cfabad6e9d4affd03684fde2763fa47b6d5a9696a03df3bb23f197cf55af1"}, + {file = "google_crc32c-1.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b19ee0a14107fc29a24129982f16648908363b0c43cf6a2b68ece7768c4d038b"}, + {file = "google_crc32c-1.2.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:fd55f480bb87e1f03b08a8bff13a0689efa7bf10426f1b58f2081168a05b3463"}, + {file = "google_crc32c-1.2.0-cp37-cp37m-win32.whl", hash = "sha256:6690bbdbfafc39f7031e19e07965b28b91cf41f3a66267e9e9f75b7bcbcd8ac6"}, + {file = "google_crc32c-1.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:8331f0cbf8d91e868858a95c3608c26c2b8872f0ed8464c58425995aa92cb70b"}, + {file = "google_crc32c-1.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:96e7057e29abfe763db02877b7cafff8a076145feb446106409f4fc12549d281"}, + {file = "google_crc32c-1.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:496d7d6ac406f3a8e9f1e2fea93bc5470d5ff02c6ea34745c9aa5f22c876f30e"}, + {file = "google_crc32c-1.2.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8a862ea73b86c3b6589847224195e1027a876c85dc1f87475509b58d2aaafcda"}, + {file = "google_crc32c-1.2.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:eb32e021526e905500c08aa030461621e5af934bf68a910322f5ddebb8c2bbf9"}, + {file = "google_crc32c-1.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e720b0c9df6a58d4786c299407c2561993e9abd41d37c38e09d33288a3aca0d"}, + {file = "google_crc32c-1.2.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8aa4de2ffad9d5521d9ba105a1a59126423389598cb4f9af9d28d4da845c0414"}, + {file = "google_crc32c-1.2.0-cp38-cp38-win32.whl", hash = "sha256:adb721315435d8530a9eabce2cf3731db015ca0af5f8f983bf5c6e5272385c02"}, + {file = "google_crc32c-1.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:a7920ea4770ec6b98a30e99f9ab90aacc0a447a316c165701f264234d8dbf731"}, + {file = "google_crc32c-1.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c242c82eef7fb75ee698ecc65596e324b3273ae3dd78a8e5f05bf3cb627caa3b"}, + {file = "google_crc32c-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a6694773dd45c88b2babef6b702b6233723ae4f42cca0fbc68114e81ed389188"}, + {file = "google_crc32c-1.2.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:70670518d50babd6012de3206472aa406a41b79acb11b6e46931f842e25a356a"}, + {file = "google_crc32c-1.2.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dc12aef85a7b8e5c52d7639cf23e27548f09fba798b8050f59fdd5bee08051f2"}, + {file = "google_crc32c-1.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e13c8f1fbde9b543f693c42c0f82ba6c57683d66cc2c5960c6c66fccb42a736"}, + {file = "google_crc32c-1.2.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:483694ccb1d0ceab8219afc4f20939565b09f81531bf8dd2bf3efb3ea84766fe"}, + {file = "google_crc32c-1.2.0-cp39-cp39-win32.whl", hash = "sha256:618c304e803fb5e4b1dbe4d529e1047450d913b64dc4e49826bb3e5a0ef73a9e"}, + {file = "google_crc32c-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:60c4f32d1fbd25234ff9468de24c1c8a9556e90ac94818a99c8cfc83328214d1"}, + {file = "google_crc32c-1.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4b8c7579269e3c64dda1d63cc9b9ba7615b51092c905b68d43c907be80fc641f"}, + {file = "google_crc32c-1.2.0-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c24e7e78756f617ebf006adcb0edb74aaf93a31a45440266e66f5fb2b8c75512"}, + {file = "google_crc32c-1.2.0-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:81c2e088041fb38b099b5a7fb2407deff74ee9bec3b36c38180564b4686bc1fa"}, + {file = "google_crc32c-1.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c422331bdeb5214ecc8a98f85dcbbc5b3222d173b1348874f1087b1f938313d8"}, + {file = "google_crc32c-1.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:9caf25a7f2551b117e063ce1e1f3959ef64d8c4e96587e4ce6ee1be7b441b3b7"}, +] +google-resumable-media = [ + {file = "google-resumable-media-1.3.3.tar.gz", hash = "sha256:ce38555d250bd70b0c2598bf61e99003cb8c569b0176ec0e3f38b86f9ffff581"}, + {file = "google_resumable_media-1.3.3-py2.py3-none-any.whl", hash = "sha256:092f39153cd67a4e409924edf08129f43cc72e630a1eb22abec93e80155df4ba"}, +] +googleapis-common-protos = [ + {file = "googleapis-common-protos-1.53.0.tar.gz", hash = "sha256:a88ee8903aa0a81f6c3cec2d5cf62d3c8aa67c06439b0496b49048fb1854ebf4"}, + {file = "googleapis_common_protos-1.53.0-py2.py3-none-any.whl", hash = "sha256:f6d561ab8fb16b30020b940e2dd01cd80082f4762fa9f3ee670f4419b4b8dbd0"}, +] +grpc-google-iam-v1 = [ + {file = "grpc-google-iam-v1-0.12.3.tar.gz", hash = "sha256:0bfb5b56f648f457021a91c0df0db4934b6e0c300bd0f2de2333383fe958aa72"}, +] +grpcio = [ + {file = "grpcio-1.40.0-cp35-cp35m-macosx_10_10_intel.whl", hash = "sha256:6f8f581787e739945e6cda101f312ea8a7e7082bdbb4993901eb828da6a49092"}, + {file = "grpcio-1.40.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:a4389e26a8f9338ca91effdc5436dfec67d6ecd296368dba115799ae8f8e5bdb"}, + {file = "grpcio-1.40.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:fb06708e3d173e387326abcd5182d52beb60e049db5c3d317bd85509e938afdc"}, + {file = "grpcio-1.40.0-cp35-cp35m-manylinux2014_i686.whl", hash = "sha256:f06e07161c21391682bfcac93a181a037a8aa3d561546690e9d0501189729aac"}, + {file = "grpcio-1.40.0-cp35-cp35m-manylinux2014_x86_64.whl", hash = "sha256:5ff0dcf66315f3f00e1a8eb7244c6a49bdb0cc59bef4fb65b9db8adbd78e6acb"}, + {file = "grpcio-1.40.0-cp35-cp35m-win32.whl", hash = "sha256:ba9dd97ea1738be3e81d34e6bab8ff91a0b80668a4ec81454b283d3c828cebde"}, + {file = "grpcio-1.40.0-cp35-cp35m-win_amd64.whl", hash = "sha256:e12d776a240fee3ebd002519c02d165d94ec636d3fe3d6185b361bfc9a2d3106"}, + {file = "grpcio-1.40.0-cp36-cp36m-linux_armv7l.whl", hash = "sha256:6b9b432f5665dfc802187384693b6338f05c7fc3707ebf003a89bd5132074e27"}, + {file = "grpcio-1.40.0-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:886d056f5101ac513f4aefe4d21a816d98ee3f9a8e77fc3bcb4ae1a3a24efe26"}, + {file = "grpcio-1.40.0-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:b1b34e5a6f1285d1576099c663dae28c07b474015ed21e35a243aff66a0c2aed"}, + {file = "grpcio-1.40.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:17ed13d43450ef9d1f9b78cc932bcf42844ca302235b93026dfd07fb5208d146"}, + {file = "grpcio-1.40.0-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:e19de138199502d575fcec5cf68ae48815a6efe7e5c0d0b8c97eba8c77ae9f0e"}, + {file = "grpcio-1.40.0-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:a812164ceb48cb62c3217bd6245274e693c624cc2ac0c1b11b4cea96dab054dd"}, + {file = "grpcio-1.40.0-cp36-cp36m-manylinux_2_24_aarch64.whl", hash = "sha256:eedc8c3514c10b6f11c6f406877e424ca29610883b97bb97e33b1dd2a9077f6c"}, + {file = "grpcio-1.40.0-cp36-cp36m-win32.whl", hash = "sha256:1708a0ba90c798b4313f541ffbcc25ed47e790adaafb02111204362723dabef0"}, + {file = "grpcio-1.40.0-cp36-cp36m-win_amd64.whl", hash = "sha256:d760a66c9773780837915be85a39d2cd4ab42ef32657c5f1d28475e23ab709fc"}, + {file = "grpcio-1.40.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:8a35b5f87247c893b01abf2f4f7493a18c2c5bf8eb3923b8dd1654d8377aa1a7"}, + {file = "grpcio-1.40.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:45704b9b5b85f9bcb027f90f2563d11d995c1b870a9ee4b3766f6c7ff6fc3505"}, + {file = "grpcio-1.40.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:4967949071c9e435f9565ec2f49700cebeda54836a04710fe21f7be028c0125a"}, + {file = "grpcio-1.40.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:1f9ccc9f5c0d5084d1cd917a0b5ff0142a8d269d0755592d751f8ce9e7d3d7f1"}, + {file = "grpcio-1.40.0-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:5729ca9540049f52c2e608ca110048cfabab3aeaa0d9f425361d9f8ba8506cac"}, + {file = "grpcio-1.40.0-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:edddc849bed3c5dfe215a9f9532a9bd9f670b57d7b8af603be80148b4c69e9a8"}, + {file = "grpcio-1.40.0-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:49155dfdf725c0862c428039123066b25ce61bd38ce50a21ce325f1735aac1bd"}, + {file = "grpcio-1.40.0-cp37-cp37m-win32.whl", hash = "sha256:913916823efa2e487b2ee9735b7759801d97fd1974bacdb1900e3bbd17f7d508"}, + {file = "grpcio-1.40.0-cp37-cp37m-win_amd64.whl", hash = "sha256:24277aab99c346ca36a1aa8589a0624e19a8e6f2b74c83f538f7bb1cc5ee8dbc"}, + {file = "grpcio-1.40.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:a66a30513d2e080790244a7ac3d7a3f45001f936c5c2c9613e41e2a5d7a11794"}, + {file = "grpcio-1.40.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:e2367f2b18dd4ba64cdcd9f626a920f9ec2e8228630839dc8f4a424d461137ea"}, + {file = "grpcio-1.40.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:27dee6dcd1c04c4e9ceea49f6143003569292209d2c24ca100166660805e2440"}, + {file = "grpcio-1.40.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d271e52038dec0db7c39ad9303442d6087c55e09b900e2931b86e837cf0cbc2e"}, + {file = "grpcio-1.40.0-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:41e250ec7cd7523bf49c815b5509d5821728c26fac33681d4b0d1f5f34f59f06"}, + {file = "grpcio-1.40.0-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:33dc4259fecb96e6eac20f760656b911bcb1616aa3e58b3a1d2f125714a2f5d3"}, + {file = "grpcio-1.40.0-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:72b7b8075ee822dad4b39c150d73674c1398503d389e38981e9e35a894c476de"}, + {file = "grpcio-1.40.0-cp38-cp38-win32.whl", hash = "sha256:a93490e6eff5fce3748fb2757cb4273dc21eb1b56732b8c9640fd82c1997b215"}, + {file = "grpcio-1.40.0-cp38-cp38-win_amd64.whl", hash = "sha256:d3b4b41eb0148fca3e6e6fc61d1332a7e8e7c4074fb0d1543f0b255d7f5f1588"}, + {file = "grpcio-1.40.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:fbe3b66bfa2c2f94535f6063f6db62b5b150d55a120f2f9e1175d3087429c4d9"}, + {file = "grpcio-1.40.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:ecfd80e8ea03c46b3ea7ed37d2040fcbfe739004b9e4329b8b602d06ac6fb113"}, + {file = "grpcio-1.40.0-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:d487b4daf84a14741ca1dc1c061ffb11df49d13702cd169b5837fafb5e84d9c0"}, + {file = "grpcio-1.40.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:c26de909cfd54bacdb7e68532a1591a128486af47ee3a5f828df9aa2165ae457"}, + {file = "grpcio-1.40.0-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:1d9eabe2eb2f78208f9ae67a591f73b024488449d4e0a5b27c7fca2d6901a2d4"}, + {file = "grpcio-1.40.0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:4c2baa438f51152c9b7d0835ff711add0b4bc5056c0f5df581a6112153010696"}, + {file = "grpcio-1.40.0-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:bf114be0023b145f7101f392a344692c1efd6de38a610c54a65ed3cba035e669"}, + {file = "grpcio-1.40.0-cp39-cp39-win32.whl", hash = "sha256:5f6d6b638698fa6decf7f040819aade677b583eaa21b43366232cb254a2bbac8"}, + {file = "grpcio-1.40.0-cp39-cp39-win_amd64.whl", hash = "sha256:005fe14e67291498989da67d454d805be31d57a988af28ed3a2a0a7cabb05c53"}, + {file = "grpcio-1.40.0.tar.gz", hash = "sha256:3d172158fe886a2604db1b6e17c2de2ab465fe0fe36aba2ec810ca8441cefe3a"}, +] +grpcio-gcp = [ + {file = "grpcio-gcp-0.2.2.tar.gz", hash = "sha256:e292605effc7da39b7a8734c719afb12ec4b5362add3528d8afad3aa3aa9057c"}, + {file = "grpcio_gcp-0.2.2-py2.py3-none-any.whl", hash = "sha256:1ef8e8531eab11356a3eb4c5b84e79e0d923d6782d19e1b1a45e1cabe4e783d7"}, +] +hdfs = [ + {file = "hdfs-2.6.0-py3-none-any.whl", hash = "sha256:05912125cfc68075387f271654dac185dc1aba8b347519f6a14d1395e39d7749"}, + {file = "hdfs-2.6.0.tar.gz", hash = "sha256:bc92ce4347f106d48b541f756caa930476998cfd3eed477ffbd63ae9ad1cdc22"}, +] htmlmin = [ {file = "htmlmin-0.1.12.tar.gz", hash = "sha256:50c1ef4630374a5d723900096a961cff426dff46b48f34d194a81bbe14eca178"}, ] +httplib2 = [ + {file = "httplib2-0.19.1-py3-none-any.whl", hash = "sha256:2ad195faf9faf079723f6714926e9a9061f694d07724b846658ce08d40f522b4"}, + {file = "httplib2-0.19.1.tar.gz", hash = "sha256:0b12617eeca7433d4c396a100eaecfa4b08ee99aa881e6df6e257a7aad5d533d"}, +] idna = [ {file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"}, {file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"}, @@ -1005,34 +1822,61 @@ networkx = [ {file = "networkx-2.6.3.tar.gz", hash = "sha256:c0946ed31d71f1b732b5aaa6da5a0388a345019af232ce2f49c766e2d6795c51"}, ] numpy = [ - {file = "numpy-1.21.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:38e8648f9449a549a7dfe8d8755a5979b45b3538520d1e735637ef28e8c2dc50"}, - {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fd7d7409fa643a91d0a05c7554dd68aa9c9bb16e186f6ccfe40d6e003156e33a"}, - {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a75b4498b1e93d8b700282dc8e655b8bd559c0904b3910b144646dbbbc03e062"}, - {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1412aa0aec3e00bc23fbb8664d76552b4efde98fb71f60737c83efbac24112f1"}, - {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e46ceaff65609b5399163de5893d8f2a82d3c77d5e56d976c8b5fb01faa6b671"}, - {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c6a2324085dd52f96498419ba95b5777e40b6bcbc20088fddb9e8cbb58885e8e"}, - {file = "numpy-1.21.1-cp37-cp37m-win32.whl", hash = "sha256:73101b2a1fef16602696d133db402a7e7586654682244344b8329cdcbbb82172"}, - {file = "numpy-1.21.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7a708a79c9a9d26904d1cca8d383bf869edf6f8e7650d85dbc77b041e8c5a0f8"}, - {file = "numpy-1.21.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95b995d0c413f5d0428b3f880e8fe1660ff9396dcd1f9eedbc311f37b5652e16"}, - {file = "numpy-1.21.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:635e6bd31c9fb3d475c8f44a089569070d10a9ef18ed13738b03049280281267"}, - {file = "numpy-1.21.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a3d5fb89bfe21be2ef47c0614b9c9c707b7362386c9a3ff1feae63e0267ccb6"}, - {file = "numpy-1.21.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8a326af80e86d0e9ce92bcc1e65c8ff88297de4fa14ee936cb2293d414c9ec63"}, - {file = "numpy-1.21.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:791492091744b0fe390a6ce85cc1bf5149968ac7d5f0477288f78c89b385d9af"}, - {file = "numpy-1.21.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0318c465786c1f63ac05d7c4dbcecd4d2d7e13f0959b01b534ea1e92202235c5"}, - {file = "numpy-1.21.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a513bd9c1551894ee3d31369f9b07460ef223694098cf27d399513415855b68"}, - {file = "numpy-1.21.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:91c6f5fc58df1e0a3cc0c3a717bb3308ff850abdaa6d2d802573ee2b11f674a8"}, - {file = "numpy-1.21.1-cp38-cp38-win32.whl", hash = "sha256:978010b68e17150db8765355d1ccdd450f9fc916824e8c4e35ee620590e234cd"}, - {file = "numpy-1.21.1-cp38-cp38-win_amd64.whl", hash = "sha256:9749a40a5b22333467f02fe11edc98f022133ee1bfa8ab99bda5e5437b831214"}, - {file = "numpy-1.21.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d7a4aeac3b94af92a9373d6e77b37691b86411f9745190d2c351f410ab3a791f"}, - {file = "numpy-1.21.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d9e7912a56108aba9b31df688a4c4f5cb0d9d3787386b87d504762b6754fbb1b"}, - {file = "numpy-1.21.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:25b40b98ebdd272bc3020935427a4530b7d60dfbe1ab9381a39147834e985eac"}, - {file = "numpy-1.21.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8a92c5aea763d14ba9d6475803fc7904bda7decc2a0a68153f587ad82941fec1"}, - {file = "numpy-1.21.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:05a0f648eb28bae4bcb204e6fd14603de2908de982e761a2fc78efe0f19e96e1"}, - {file = "numpy-1.21.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f01f28075a92eede918b965e86e8f0ba7b7797a95aa8d35e1cc8821f5fc3ad6a"}, - {file = "numpy-1.21.1-cp39-cp39-win32.whl", hash = "sha256:88c0b89ad1cc24a5efbb99ff9ab5db0f9a86e9cc50240177a571fbe9c2860ac2"}, - {file = "numpy-1.21.1-cp39-cp39-win_amd64.whl", hash = "sha256:01721eefe70544d548425a07c80be8377096a54118070b8a62476866d5208e33"}, - {file = "numpy-1.21.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2d4d1de6e6fb3d28781c73fbde702ac97f03d79e4ffd6598b880b2d95d62ead4"}, - {file = "numpy-1.21.1.zip", hash = "sha256:dff4af63638afcc57a3dfb9e4b26d434a7a602d225b42d746ea7fe2edf1342fd"}, + {file = "numpy-1.20.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:70eb5808127284c4e5c9e836208e09d685a7978b6a216db85960b1a112eeace8"}, + {file = "numpy-1.20.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6ca2b85a5997dabc38301a22ee43c82adcb53ff660b89ee88dded6b33687e1d8"}, + {file = "numpy-1.20.3-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c5bf0e132acf7557fc9bb8ded8b53bbbbea8892f3c9a1738205878ca9434206a"}, + {file = "numpy-1.20.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db250fd3e90117e0312b611574cd1b3f78bec046783195075cbd7ba9c3d73f16"}, + {file = "numpy-1.20.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:637d827248f447e63585ca3f4a7d2dfaa882e094df6cfa177cc9cf9cd6cdf6d2"}, + {file = "numpy-1.20.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8b7bb4b9280da3b2856cb1fc425932f46fba609819ee1c62256f61799e6a51d2"}, + {file = "numpy-1.20.3-cp37-cp37m-win32.whl", hash = "sha256:67d44acb72c31a97a3d5d33d103ab06d8ac20770e1c5ad81bdb3f0c086a56cf6"}, + {file = "numpy-1.20.3-cp37-cp37m-win_amd64.whl", hash = "sha256:43909c8bb289c382170e0282158a38cf306a8ad2ff6dfadc447e90f9961bef43"}, + {file = "numpy-1.20.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f1452578d0516283c87608a5a5548b0cdde15b99650efdfd85182102ef7a7c17"}, + {file = "numpy-1.20.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6e51534e78d14b4a009a062641f465cfaba4fdcb046c3ac0b1f61dd97c861b1b"}, + {file = "numpy-1.20.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e515c9a93aebe27166ec9593411c58494fa98e5fcc219e47260d9ab8a1cc7f9f"}, + {file = "numpy-1.20.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1c09247ccea742525bdb5f4b5ceeacb34f95731647fe55774aa36557dbb5fa4"}, + {file = "numpy-1.20.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:66fbc6fed94a13b9801fb70b96ff30605ab0a123e775a5e7a26938b717c5d71a"}, + {file = "numpy-1.20.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ea9cff01e75a956dbee133fa8e5b68f2f92175233de2f88de3a682dd94deda65"}, + {file = "numpy-1.20.3-cp38-cp38-win32.whl", hash = "sha256:f39a995e47cb8649673cfa0579fbdd1cdd33ea497d1728a6cb194d6252268e48"}, + {file = "numpy-1.20.3-cp38-cp38-win_amd64.whl", hash = "sha256:1676b0a292dd3c99e49305a16d7a9f42a4ab60ec522eac0d3dd20cdf362ac010"}, + {file = "numpy-1.20.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:830b044f4e64a76ba71448fce6e604c0fc47a0e54d8f6467be23749ac2cbd2fb"}, + {file = "numpy-1.20.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:55b745fca0a5ab738647d0e4db099bd0a23279c32b31a783ad2ccea729e632df"}, + {file = "numpy-1.20.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5d050e1e4bc9ddb8656d7b4f414557720ddcca23a5b88dd7cff65e847864c400"}, + {file = "numpy-1.20.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9c65473ebc342715cb2d7926ff1e202c26376c0dcaaee85a1fd4b8d8c1d3b2f"}, + {file = "numpy-1.20.3-cp39-cp39-win32.whl", hash = "sha256:16f221035e8bd19b9dc9a57159e38d2dd060b48e93e1d843c49cb370b0f415fd"}, + {file = "numpy-1.20.3-cp39-cp39-win_amd64.whl", hash = "sha256:6690080810f77485667bfbff4f69d717c3be25e5b11bb2073e76bb3f578d99b4"}, + {file = "numpy-1.20.3-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4e465afc3b96dbc80cf4a5273e5e2b1e3451286361b4af70ce1adb2984d392f9"}, + {file = "numpy-1.20.3.zip", hash = "sha256:e55185e51b18d788e49fe8305fd73ef4470596b33fc2c1ceb304566b99c71a69"}, +] +oauth2client = [ + {file = "oauth2client-4.1.3-py2.py3-none-any.whl", hash = "sha256:b8a81cc5d60e2d364f0b1b98f958dbd472887acaf1a5b05e21c28c31a2d6d3ac"}, + {file = "oauth2client-4.1.3.tar.gz", hash = "sha256:d486741e451287f69568a4d26d70d9acd73a2bbfa275746c535b4209891cccc6"}, +] +orjson = [ + {file = "orjson-3.6.3-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:5f78ed46b179585272a5670537f2203dbb7b3e2f8e4db1be72839cc423e2daef"}, + {file = "orjson-3.6.3-cp310-cp310-manylinux_2_24_x86_64.whl", hash = "sha256:a99f310960e3acdda72ba1e98df8bf8c9145d90a0f72719786f43f4ea6937846"}, + {file = "orjson-3.6.3-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:8a5e46418f51f03060f91d743b59aed70c8d02a5012428365cfa20b7f670e903"}, + {file = "orjson-3.6.3-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:084de43ca9b19ad58c618c9f1ff93784e0190df2d88a02ae24c3cdebe9f2e9f7"}, + {file = "orjson-3.6.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b68a601f49c0328bf16498309e56ab87c1d6c2bb0287abf70329eb958d565c62"}, + {file = "orjson-3.6.3-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:9e4a26212851ea8ff81dee7e4e0da7e1e63b5b4f4330a8b4f27e99f1ba3f758b"}, + {file = "orjson-3.6.3-cp37-cp37m-manylinux_2_24_x86_64.whl", hash = "sha256:5eb9d7f2f45e12cbc7500da4176f2d3221a73891b4be505fe79c52cbb800e872"}, + {file = "orjson-3.6.3-cp37-none-win_amd64.whl", hash = "sha256:39aa7d42c9760fba36c37adb1d9c6752696ce9443c5dcb65222dd0994b5735e1"}, + {file = "orjson-3.6.3-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:8d4430e0cc390c1d745aea3827fd0c6fd7aa5f0690de30a2fe25c406aa5efa20"}, + {file = "orjson-3.6.3-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:be79e0ddea7f3a47332ec9573365c0b8a8cce4357e9682050f53c1bc75c1571f"}, + {file = "orjson-3.6.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fce5ada0f8dd7c9e16c675626a29dfc5cc766e1eb67d8021b1e77d0861e4e850"}, + {file = "orjson-3.6.3-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:1014a6f514b39dc414fce60568c9e7f635de97a1f1f5972ebc38f88a6160944a"}, + {file = "orjson-3.6.3-cp38-cp38-manylinux_2_24_x86_64.whl", hash = "sha256:c3beff02a339f194274ec1fcf03e2c1563e84f297b568eb3d45751722454a52e"}, + {file = "orjson-3.6.3-cp38-none-win_amd64.whl", hash = "sha256:8f105e9290f901a618a0ced87f785fce2fcf6ab753699de081d82ee05c90f038"}, + {file = "orjson-3.6.3-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:7936bef5589c9955ebee3423df51709d5f3b37ef54b830239bddb9fa5ead99f4"}, + {file = "orjson-3.6.3-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:82e3afbf404cb91774f894ed7bf52fd83bb1cc6bd72221711f4ce4e7774f0560"}, + {file = "orjson-3.6.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c702c78c33416fc8a138c5ec36eef5166ecfe8990c8f99c97551cd37c396e4d"}, + {file = "orjson-3.6.3-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:4606907b9aaec9fea6159ac14f838dbd2851f18b05fb414c4b3143bff9f2bb0d"}, + {file = "orjson-3.6.3-cp39-cp39-manylinux_2_24_x86_64.whl", hash = "sha256:4ebb464b8b557a1401a03da6f41761544886db95b52280e60d25549da7427453"}, + {file = "orjson-3.6.3-cp39-none-win_amd64.whl", hash = "sha256:720a7d7ba1dcf32bbd8fb380370b1fdd06ed916caea48403edd64f2ccf7883c1"}, + {file = "orjson-3.6.3.tar.gz", hash = "sha256:353cc079cedfe990ea2d2186306f766e0d47bba63acd072e22d6df96c67be993"}, +] +packaging = [ + {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"}, + {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"}, ] pandas = [ {file = "pandas-1.1.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:bf23a3b54d128b50f4f9d4675b3c1857a688cc6731a32f931837d72effb2698d"}, @@ -1154,6 +1998,90 @@ prospector = [ {file = "prospector-1.5.1-py3-none-any.whl", hash = "sha256:47f8ff3fd36ae276967eb392ca20b300a7bdea66c0d0252250a4d89a6c03ab15"}, {file = "prospector-1.5.1.tar.gz", hash = "sha256:851c2892cd615cfee91fd27cfaf7a5061d14daf2853aa8f012e927b98f919578"}, ] +proto-plus = [ + {file = "proto-plus-1.19.0.tar.gz", hash = "sha256:ce6695ce804383ad6f392c4bb1874c323896290a1f656560de36416ba832d91e"}, + {file = "proto_plus-1.19.0-py3-none-any.whl", hash = "sha256:df7c71c08dc06403bdb0fba58cf9bf5f217198f6488c26b768f81e03a738c059"}, +] +protobuf = [ + {file = "protobuf-3.18.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9072cb18fca8998b77f969fb74d25a11d7f4a39a8b1ddc3cf76cd5abda8499cb"}, + {file = "protobuf-3.18.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f589346b5b3f702c1d30e2343c9897e6c35e7bd495c10a0e17d11ecb5ee5bd06"}, + {file = "protobuf-3.18.0-cp36-cp36m-win32.whl", hash = "sha256:93c077fd83879cf48f327a2491c24da447a09da6a7ab3cc311a6f5a61fcb5de0"}, + {file = "protobuf-3.18.0-cp36-cp36m-win_amd64.whl", hash = "sha256:3b5b81bb665aac548b413480f4e0d8c38a74bc4dea57835f288a3ce74f63dfe9"}, + {file = "protobuf-3.18.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d11465040cadcea8ecf5f0b131af5099a9696f9d0bef6f88148b372bacc1c52d"}, + {file = "protobuf-3.18.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:f6138462643adce0ed6e49007a63b7fd7dc4fda1ef4e15a70fcebe76c1407a71"}, + {file = "protobuf-3.18.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:877664b1b8d1e23553634f625e4e12aae4ff16cbbef473f8118c239d478f422a"}, + {file = "protobuf-3.18.0-cp37-cp37m-win32.whl", hash = "sha256:5201333b7aa711965c5769b250f8565a9924e8e27f8b622bbc5e6847aeaab1b1"}, + {file = "protobuf-3.18.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1f3ecec3038c2fb4dad952d3d6cb9ca301999903a09e43794fb348da48f7577f"}, + {file = "protobuf-3.18.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:17181fc0814655812aac108e755bd5185d71aa8d81bd241cec6e232c84097918"}, + {file = "protobuf-3.18.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:7646c20605fbee57e77fdbc4a90175538281b152f46ba17019916593f8062c2a"}, + {file = "protobuf-3.18.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80b0a5157f3a53043daf8eb7cfa1220b27a5a63dd6655dbd8e1e6f7b5dcd6347"}, + {file = "protobuf-3.18.0-cp38-cp38-win32.whl", hash = "sha256:5730de255c95b3403eedd1a568eb28203b913b6192ff5a3fdc3ff30f37107a38"}, + {file = "protobuf-3.18.0-cp38-cp38-win_amd64.whl", hash = "sha256:9147565f93e6699d7512747766598afe63205f226ac7b61f47954974c9aab852"}, + {file = "protobuf-3.18.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:568c049ff002a7523ed33fb612e6b97da002bf87ffb619a1fc3eadf2257a3b31"}, + {file = "protobuf-3.18.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:7e791a94db391ae22b3943fc88f6ba0e1f62b6ad58b33db7517df576c7834d23"}, + {file = "protobuf-3.18.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42c04e66ec5a38ad2171639dc9860c2f9594668f709ea3a4a192acf7346853a7"}, + {file = "protobuf-3.18.0-cp39-cp39-win32.whl", hash = "sha256:0a59ea8da307118372750e2fdfe0961622e675b8dd35e05c42384d618189a938"}, + {file = "protobuf-3.18.0-cp39-cp39-win_amd64.whl", hash = "sha256:f7c8193ec805324ff6024242b00f64a24b94d56b895f62bf28a9d72a228d4fca"}, + {file = "protobuf-3.18.0-py2.py3-none-any.whl", hash = "sha256:615099e52e9fbc9fde00177267a94ca820ecf4e80093e390753568b7d8cb3c1a"}, + {file = "protobuf-3.18.0.tar.gz", hash = "sha256:18b308946a592e245299391e53c01b5b8efc2794f49986e80f37d7b5e60a270f"}, +] +pyarrow = [ + {file = "pyarrow-4.0.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:5387db80c6a7b5598884bf4df3fc546b3373771ad614548b782e840b71704877"}, + {file = "pyarrow-4.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:76b75a9cfc572e890a1e000fd532bdd2084ec3f1ee94ee51802a477913a21072"}, + {file = "pyarrow-4.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:423cd6a14810f4e40cb76e13d4240040fc1594d69fe1c4f2c70be00ad512ade5"}, + {file = "pyarrow-4.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:e1351576877764fb4d5690e4721ce902e987c85f4ab081c70a34e1d24646586e"}, + {file = "pyarrow-4.0.1-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:0fde9c7a3d5d37f3fe5d18c4ed015e8f585b68b26d72a10d7012cad61afe43ff"}, + {file = "pyarrow-4.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:afd4f7c0a225a326d2c0039cdc8631b5e8be30f78f6b7a3e5ce741cf5dd81c72"}, + {file = "pyarrow-4.0.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:b05bdd513f045d43228247ef4d9269c88139788e2d566f4cb3e855e282ad0330"}, + {file = "pyarrow-4.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:150db335143edd00d3ec669c7c8167d401c4aa0a290749351c80bbf146892b2e"}, + {file = "pyarrow-4.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:dcd20ee0240a88772eeb5691102c276f5cdec79527fb3a0679af7f93f93cb4bd"}, + {file = "pyarrow-4.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:24040a20208e9b16ba7b284624ebfe67e40f5c40b5dc8d874da322ac0053f9d3"}, + {file = "pyarrow-4.0.1-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:e44dfd7e61c9eb6dda59bc49ad69e77945f6d049185a517c130417e3ca0494d8"}, + {file = "pyarrow-4.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ee3d87615876550fee9a523307dd4b00f0f44cf47a94a32a07793da307df31a0"}, + {file = "pyarrow-4.0.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:fa7b165cfa97158c1e6d15c68428317b4f4ae786d1dc2dbab43f1328c1eb43aa"}, + {file = "pyarrow-4.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:33c457728a1ce825b80aa8c8ed573709f1efe72003d45fa6fdbb444de9cc0b74"}, + {file = "pyarrow-4.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:72cf3477538bd8504f14d6299a387cc335444f7a188f548096dfea9533551f02"}, + {file = "pyarrow-4.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:a81adbfbe2f6528d4593b5a8962b2751838517401d14e9d4cab6787478802693"}, + {file = "pyarrow-4.0.1-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:c2733c9bcd00074ce5497dd0a7b8a10c91d3395ddce322d7021c7fdc4ea6f610"}, + {file = "pyarrow-4.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:d0f080b2d9720bec42624cb0df66f60ae66b84a2ccd1fe2c291322df915ac9db"}, + {file = "pyarrow-4.0.1-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:6b7bd8f5aa327cc32a1b9b02a76502851575f5edb110f93c59a45c70211a5618"}, + {file = "pyarrow-4.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe976695318560a97c6d31bba828eeca28c44c6f6401005e54ba476a28ac0a10"}, + {file = "pyarrow-4.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:5f2660f59dfcfd34adac7c08dc7f615920de703f191066ed6277628975f06878"}, + {file = "pyarrow-4.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:5a76ec44af838862b23fb5cfc48765bc7978f7b58a181c96ad92856280de548b"}, + {file = "pyarrow-4.0.1-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:04be0f7cb9090bd029b5b53bed628548fef569e5d0b5c6cd7f6d0106dbbc782d"}, + {file = "pyarrow-4.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:a968375c66e505f72b421f5864a37f51aad5da61b6396fa283f956e9f2b2b923"}, + {file = "pyarrow-4.0.1.tar.gz", hash = "sha256:11517f0b4f4acbab0c37c674b4d1aad3c3dfea0f6b1bb322e921555258101ab3"}, +] +pyasn1 = [ + {file = "pyasn1-0.4.8-py2.4.egg", hash = "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"}, + {file = "pyasn1-0.4.8-py2.5.egg", hash = "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf"}, + {file = "pyasn1-0.4.8-py2.6.egg", hash = "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00"}, + {file = "pyasn1-0.4.8-py2.7.egg", hash = "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8"}, + {file = "pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d"}, + {file = "pyasn1-0.4.8-py3.1.egg", hash = "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86"}, + {file = "pyasn1-0.4.8-py3.2.egg", hash = "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7"}, + {file = "pyasn1-0.4.8-py3.3.egg", hash = "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576"}, + {file = "pyasn1-0.4.8-py3.4.egg", hash = "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12"}, + {file = "pyasn1-0.4.8-py3.5.egg", hash = "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2"}, + {file = "pyasn1-0.4.8-py3.6.egg", hash = "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359"}, + {file = "pyasn1-0.4.8-py3.7.egg", hash = "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776"}, + {file = "pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"}, +] +pyasn1-modules = [ + {file = "pyasn1-modules-0.2.8.tar.gz", hash = "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e"}, + {file = "pyasn1_modules-0.2.8-py2.4.egg", hash = "sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199"}, + {file = "pyasn1_modules-0.2.8-py2.5.egg", hash = "sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405"}, + {file = "pyasn1_modules-0.2.8-py2.6.egg", hash = "sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb"}, + {file = "pyasn1_modules-0.2.8-py2.7.egg", hash = "sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8"}, + {file = "pyasn1_modules-0.2.8-py2.py3-none-any.whl", hash = "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74"}, + {file = "pyasn1_modules-0.2.8-py3.1.egg", hash = "sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d"}, + {file = "pyasn1_modules-0.2.8-py3.2.egg", hash = "sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45"}, + {file = "pyasn1_modules-0.2.8-py3.3.egg", hash = "sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4"}, + {file = "pyasn1_modules-0.2.8-py3.4.egg", hash = "sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811"}, + {file = "pyasn1_modules-0.2.8-py3.5.egg", hash = "sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed"}, + {file = "pyasn1_modules-0.2.8-py3.6.egg", hash = "sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0"}, + {file = "pyasn1_modules-0.2.8-py3.7.egg", hash = "sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd"}, +] pycodestyle = [ {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, @@ -1186,13 +2114,17 @@ pydocstyle = [ {file = "pydocstyle-6.1.1-py3-none-any.whl", hash = "sha256:6987826d6775056839940041beef5c08cc7e3d71d63149b48e36727f70144dc4"}, {file = "pydocstyle-6.1.1.tar.gz", hash = "sha256:1d41b7c459ba0ee6c345f2eb9ae827cab14a7533a88c5c6f7e94923f72df92dc"}, ] +pydot = [ + {file = "pydot-1.4.2-py2.py3-none-any.whl", hash = "sha256:66c98190c65b8d2e2382a441b4c0edfdb4f4c025ef9cb9874de478fb0793a451"}, + {file = "pydot-1.4.2.tar.gz", hash = "sha256:248081a39bcb56784deb018977e428605c1c758f10897a339fce1dd728ff007d"}, +] pyflakes = [ {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, ] pylint = [ - {file = "pylint-2.11.1-py3-none-any.whl", hash = "sha256:0f358e221c45cbd4dad2a1e4b883e75d28acdcccd29d40c76eb72b307269b126"}, - {file = "pylint-2.11.1.tar.gz", hash = "sha256:2c9843fff1a88ca0ad98a256806c82c5a8f86086e7ccbdb93297d86c3f90c436"}, + {file = "pylint-2.10.2-py3-none-any.whl", hash = "sha256:e178e96b6ba171f8ef51fbce9ca30931e6acbea4a155074d80cc081596c9e852"}, + {file = "pylint-2.10.2.tar.gz", hash = "sha256:6758cce3ddbab60c52b57dcc07f0c5d779e5daf0cf50f6faacbef1d3ea62d2a1"}, ] pylint-celery = [ {file = "pylint-celery-0.3.tar.gz", hash = "sha256:41e32094e7408d15c044178ea828dd524beedbdbe6f83f712c5e35bde1de4beb"}, @@ -1208,6 +2140,106 @@ pylint-plugin-utils = [ {file = "pylint-plugin-utils-0.6.tar.gz", hash = "sha256:57625dcca20140f43731311cd8fd879318bf45a8b0fd17020717a8781714a25a"}, {file = "pylint_plugin_utils-0.6-py3-none-any.whl", hash = "sha256:2f30510e1c46edf268d3a195b2849bd98a1b9433229bb2ba63b8d776e1fc4d0a"}, ] +pymongo = [ + {file = "pymongo-3.12.0-cp27-cp27m-macosx_10_14_intel.whl", hash = "sha256:072ba7cb65c8aa4d5c5659bf6722ee85781c9d7816dc00679b8b6f3dff1ddafc"}, + {file = "pymongo-3.12.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:d6e11ffd43184d529d6752d6dcb62b994f903038a17ea2168ef1910c96324d26"}, + {file = "pymongo-3.12.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:7412a36798966624dc4c57d64aa43c2d1100b348abd98daaac8e99e57d87e1d7"}, + {file = "pymongo-3.12.0-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e8a82e35d52ad6f867e88096a1a2b9bdc7ec4d5e65c7b4976a248bf2d1a32a93"}, + {file = "pymongo-3.12.0-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:dcd3d0009fbb6e454d729f8b22d0063bd9171c31a55e0f0271119bd4f2700023"}, + {file = "pymongo-3.12.0-cp27-cp27m-win32.whl", hash = "sha256:1bc6fe7279ff40c6818db002bf5284aa03ec181ea1b1ceaeee33c289d412afa7"}, + {file = "pymongo-3.12.0-cp27-cp27m-win_amd64.whl", hash = "sha256:e2b7670c0c8c6b501464150dd49dd0d6be6cb7f049e064124911cec5514fa19e"}, + {file = "pymongo-3.12.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:316c1b8723afa9870567cd6dff35d440b2afeda53aa13da6c5ab85f98ed6f5ca"}, + {file = "pymongo-3.12.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:255a35bf29185f44b412e31a927d9dcedda7c2c380127ecc4fbf2f61b72fa978"}, + {file = "pymongo-3.12.0-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ffbae429ba9e42d0582d3ac63fdb410338892468a2107d8ff68228ec9a39a0ed"}, + {file = "pymongo-3.12.0-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c188db6cf9e14dbbb42f5254292be96f05374a35e7dfa087cc2140f0ff4f10f6"}, + {file = "pymongo-3.12.0-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:6fb3f85870ae26896bb44e67db94045f2ebf00c5d41e6b66cdcbb5afd644fc18"}, + {file = "pymongo-3.12.0-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:aaa038eafb7186a4abbb311fcf20724be9363645882bbce540bef4797e812a7a"}, + {file = "pymongo-3.12.0-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:7d98ce3c42921bb91566121b658e0d9d59a9082a9bd6f473190607ff25ab637f"}, + {file = "pymongo-3.12.0-cp34-cp34m-win32.whl", hash = "sha256:b0a0cf39f589e52d801fdef418305562bc030cdf8929217463c8433c65fd5c2f"}, + {file = "pymongo-3.12.0-cp34-cp34m-win_amd64.whl", hash = "sha256:ceae3ab9e11a27aaab42878f1d203600dfd24f0e43678b47298219a0f10c0d30"}, + {file = "pymongo-3.12.0-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:5e574664f1468872cd40f74e4811e22b1aa4de9399d6bcfdf1ee6ea94c017fcf"}, + {file = "pymongo-3.12.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73b400fdc22de84bae0dbf1a22613928a41612ec0a3d6ed47caf7ad4d3d0f2ff"}, + {file = "pymongo-3.12.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:cbf8672edeb7b7128c4a939274801f0e32bbf5159987815e3d1eace625264a46"}, + {file = "pymongo-3.12.0-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:a634a4730ce0b0934ed75e45beba730968e12b4dafbb22f69b3b2f616d9e644e"}, + {file = "pymongo-3.12.0-cp35-cp35m-manylinux2014_i686.whl", hash = "sha256:c55782a55f4a013a78ac5b6ee4b8731a192dea7ab09f1b6b3044c96d5128edd4"}, + {file = "pymongo-3.12.0-cp35-cp35m-manylinux2014_ppc64le.whl", hash = "sha256:11f9e0cfc84ade088a38df2708d0b958bb76360181df1b2e1e1a41beaa57952b"}, + {file = "pymongo-3.12.0-cp35-cp35m-manylinux2014_s390x.whl", hash = "sha256:186104a94d39b8412f8e3de385acd990a628346a4402d4f3a288a82b8660bd22"}, + {file = "pymongo-3.12.0-cp35-cp35m-manylinux2014_x86_64.whl", hash = "sha256:70761fd3c576b027eec882b43ee0a8e5b22ff9c20cdf4d0400e104bc29e53e34"}, + {file = "pymongo-3.12.0-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:333bfad77aa9cd11711febfb75eed0bb537a1d022e1c252714dad38993590240"}, + {file = "pymongo-3.12.0-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:fa8957e9a1b202cb45e6b839c241cd986c897be1e722b81d2f32e9c6aeee80b0"}, + {file = "pymongo-3.12.0-cp35-cp35m-win32.whl", hash = "sha256:4ba0def4abef058c0e5101e05e3d5266e6fffb9795bbf8be0fe912a7361a0209"}, + {file = "pymongo-3.12.0-cp35-cp35m-win_amd64.whl", hash = "sha256:a0e5dff6701fa615f165306e642709e1c1550d5b237c5a7a6ea299886828bd50"}, + {file = "pymongo-3.12.0-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:b542d56ed1b8d5cf3bb36326f814bd2fbe8812dfd2582b80a15689ea433c0e35"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a325600c83e61e3c9cebc0c2b1c8c4140fa887f789085075e8f44c8ff2547eb9"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:48d5bc80ab0af6b60c4163c5617f5cd23f2f880d7600940870ea5055816af024"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c5cab230e7cabdae9ff23c12271231283efefb944c1b79bed79a91beb65ba547"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:d73e10772152605f6648ba4410318594f1043bbfe36d2fadee7c4b8912eff7c5"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:b1c4874331ab960429caca81acb9d2932170d66d6d6f87e65dc4507a85aca152"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:a3566acfbcde46911c52810374ecc0354fdb841284a3efef6ff7105bc007e9a8"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:b3b5b3cbc3fdf4fcfa292529df2a85b5d9c7053913a739d3069af1e12e12219f"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd3854148005c808c485c754a184c71116372263709958b42aefbef2e5dd373a"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f55c1ddcc1f6050b07d468ce594f55dbf6107b459e16f735d26818d7be1e9538"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ced944dcdd561476deef7cb7bfd4987c69fffbfeff6d02ca4d5d4fd592d559b7"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78ecb8d42f50d393af912bfb1fb1dcc9aabe9967973efb49ee577e8f1cea494c"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1970cfe2aec1bf74b40cf30c130ad10cd968941694630386db33e1d044c22a2e"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b8bf42d3b32f586f4c9e37541769993783a534ad35531ce8a4379f6fa664fba9"}, + {file = "pymongo-3.12.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:bc9ac81e73573516070d24ce15da91281922811f385645df32bd3c8a45ab4684"}, + {file = "pymongo-3.12.0-cp36-cp36m-win32.whl", hash = "sha256:d04ca462cb99077e6c059e97c072957caf2918e6e4191e3161c01c439e0193de"}, + {file = "pymongo-3.12.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f2acf9bbcd514e901f82c4ca6926bbd2ae61716728f110b4343eb0a69612d018"}, + {file = "pymongo-3.12.0-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:b754240daafecd9d5fce426b0fbaaed03f4ebb130745c8a4ae9231fffb8d75e5"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:af586e85144023686fb0af09c8cdf672484ea182f352e7ceead3d832de381e1b"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fe5872ce6f9627deac8314bdffd3862624227c3de4c17ef0cc78bbf0402999eb"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:f6977a520bd96e097c8a37a8cbb9faa1ea99d21bf84190195056e25f688af73d"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:2dbfbbded947a83a3dffc2bd1ec4750c17e40904692186e2c55a3ad314ca0222"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:a752ecd1a26000a6d67be7c9a2e93801994a8b3f866ac95b672fbc00225ca91a"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:1bab889ae7640eba739f67fcbf8eff252dddc60d4495e6ddd3a87cd9a95fdb52"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:f94c7d22fb36b184734dded7345a04ec5f95130421c775b8b0c65044ef073f34"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec5ca7c0007ce268048bbe0ffc6846ed1616cf3d8628b136e81d5e64ff3f52a2"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7c72d08acdf573455b2b9d2b75b8237654841d63a48bc2327dc102c6ee89b75a"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b6ea08758b6673610b3c5bdf47189286cf9c58b1077558706a2f6f8744922527"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46d5ec90276f71af3a29917b30f2aec2315a2759b5f8d45b3b63a07ca8a070a3"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:625befa3bc9b40746a749115cc6a15bf20b9bd7597ca55d646205b479a2c99c7"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d1131562ddc2ea8a446f66c2648d7dabec2b3816fc818528eb978a75a6d23b2e"}, + {file = "pymongo-3.12.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:eee42a1cc06565f6b21caa1f504ec15e07de7ebfd520ab57f8cb3308bc118e22"}, + {file = "pymongo-3.12.0-cp37-cp37m-win32.whl", hash = "sha256:94d38eba4d1b5eb3e6bfece0651b855a35c44f32fd91f512ab4ba41b8c0d3e66"}, + {file = "pymongo-3.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:e018a4921657c2d3f89c720b7b90b9182e277178a04a7e9542cc79d7d787ca51"}, + {file = "pymongo-3.12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7c6a9948916a7bbcc6d3a9f6fb75db1acb5546078023bfb3db6efabcd5a67527"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e9faf8d4712d5ea301d74abfcf6dafe4b7f4af7936e91f283b0ad7bf69ed3e3a"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cc2894fe91f31a513860238ede69fe47fada21f9e7ddfe73f7f9fef93a971e41"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:053b4ebf91c7395d1fcd2ce6a9edff0024575b7b2de6781554a4114448a8adc9"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:39dafa2eaf577d1969f289dc9a44501859a1897eb45bd589e93ce843fc610800"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:246ec420e4c8744fceb4e259f906211b9c198e1f345e6158dcd7cbad3737e11e"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:208debdcf76ed39ebf24f38509f50dc1c100e31e8653817fedb8e1f867850a13"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:18290649759f9db660972442aa606f845c368db9b08c4c73770f6da14113569b"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:657ad80de8ec9ed656f28844efc801a0802961e8c6a85038d97ff6f555ef4919"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b772bab31cbd9cb911e41e1a611ebc9497f9a32a7348e2747c38210f75c00f41"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2399a85b54f68008e483b2871f4a458b4c980469c7fe921595ede073e4844f1e"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e66780f14c2efaf989cd3ac613b03ee6a8e3a0ba7b96c0bb14adca71a427e55"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02dc0b0f48ed3cd06c13b7e31b066bf91e00dac5f8147b0a0a45f9009bfab857"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:070a4ef689c9438a999ec3830e69b208ff0d12251846e064d947f97d819d1d05"}, + {file = "pymongo-3.12.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:db93608a246da44d728842b8fa9e45aa9782db76955f634a707739a8d53ff544"}, + {file = "pymongo-3.12.0-cp38-cp38-win32.whl", hash = "sha256:5af390fa9faf56c93252dab09ea57cd020c9123aa921b63a0ed51832fdb492e7"}, + {file = "pymongo-3.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:a2239556ff7241584ce57be1facf25081669bb457a9e5cbe68cce4aae6567aa1"}, + {file = "pymongo-3.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cda9e628b1315beec8341e8c04aac9a0b910650b05e0751e42e399d5694aeacb"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:845a8b83798b2fb11b09928413cb32692866bfbc28830a433d9fa4c8c3720dd0"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:da8288bc4a7807c6715416deed1c57d94d5e03e93537889e002bf985be503f1a"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:a9ba2a63777027b06b116e1ea8248e66fd1bedc2c644f93124b81a91ddbf6d88"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:9a13661681d17e43009bb3e85e837aa1ec5feeea1e3654682a01b8821940f8b3"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:6b89dc51206e4971c5568c797991eaaef5dc2a6118d67165858ad11752dba055"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:701e08457183da70ed96b35a6b43e6ba1df0b47c837b063cde39a1fbe1aeda81"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:e7a33322e08021c37e89cae8ff06327503e8a1719e97c69f32c31cbf6c30d72c"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd1f49f949a658c4e8f81ed73f9aad25fcc7d4f62f767f591e749e30038c4e1d"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6d055f01b83b1a4df8bb0c61983d3bdffa913764488910af3620e5c2450bf83"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd6ff2192f34bd622883c745a56f492b1c9ccd44e14953e8051c33024a2947d5"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19d4bd0fc29aa405bb1781456c9cfff9fceabb68543741eb17234952dbc2bbb0"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:24f8aeec4d6b894a6128844e50ff423dd02462ee83addf503c598ee3a80ddf3d"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b6055e0ef451ff73c93d0348d122a0750dddf323b9361de5835dac2f6cf7fc1"}, + {file = "pymongo-3.12.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6261bee7c5abadeac7497f8f1c43e521da78dd13b0a2439f526a7b0fc3788824"}, + {file = "pymongo-3.12.0-cp39-cp39-win32.whl", hash = "sha256:2e92aa32300a0b5e4175caec7769f482b292769807024a86d674b3f19b8e3755"}, + {file = "pymongo-3.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:3ce83f17f641a62a4dfb0ba1b8a3c1ced7c842f511b5450d90c030c7828e3693"}, + {file = "pymongo-3.12.0-py2.7-macosx-10.14-intel.egg", hash = "sha256:d1740776b70367277323fafb76bcf09753a5cc9824f5d705bac22a34ff3668ea"}, + {file = "pymongo-3.12.0.tar.gz", hash = "sha256:b88d1742159bc93a078733f9789f563cef26f5e370eba810476a71aa98e5fbc2"}, +] pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, @@ -1290,6 +2322,10 @@ requests = [ requirements-detector = [ {file = "requirements-detector-0.7.tar.gz", hash = "sha256:0d1e13e61ed243f9c3c86e6cbb19980bcb3a0e0619cde2ec1f3af70fdbee6f7b"}, ] +rsa = [ + {file = "rsa-4.7.2-py3-none-any.whl", hash = "sha256:78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2"}, + {file = "rsa-4.7.2.tar.gz", hash = "sha256:9d689e6ca1b3038bc82bf8d23e944b6b6037bc02301a574935b2dd946e0353b9"}, +] scipy = [ {file = "scipy-1.6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a15a1f3fc0abff33e792d6049161b7795909b40b97c6cc2934ed54384017ab76"}, {file = "scipy-1.6.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:e79570979ccdc3d165456dd62041d9556fb9733b86b4b6d818af7a0afc15f092"}, @@ -1372,9 +2408,9 @@ typed-ast = [ {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"}, ] typing-extensions = [ - {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, - {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, - {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, + {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, + {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, + {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, ] urllib3 = [ {file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"}, diff --git a/pyproject.toml b/pyproject.toml index 08c7745..10f4200 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,6 +6,7 @@ authors = ["Daniel Tomlinson "] [tool.poetry.dependencies] python = "^3.7" +apache-beam = {extras = ["gcp"], version = "^2.32.0"} [tool.poetry.dev-dependencies] # pytest = "^5.2" From a05182892a4de3c37bc399cb17bf2199ff6f3689 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sat, 25 Sep 2021 00:48:13 +0100 Subject: [PATCH 08/63] adding documentation --- notes/documentation/answers.md | 7 +++++++ notes/documentation/beam_docs.md | 12 ++++++++++++ notes/links.md | 8 +------- 3 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 notes/documentation/answers.md create mode 100644 notes/documentation/beam_docs.md diff --git a/notes/documentation/answers.md b/notes/documentation/answers.md new file mode 100644 index 0000000..2cde55f --- /dev/null +++ b/notes/documentation/answers.md @@ -0,0 +1,7 @@ +# Answers + +## CSV + +Read a csv file into Beam: + + diff --git a/notes/documentation/beam_docs.md b/notes/documentation/beam_docs.md new file mode 100644 index 0000000..ab884b3 --- /dev/null +++ b/notes/documentation/beam_docs.md @@ -0,0 +1,12 @@ +# Beam Documentation + +## Transforms + +FlatMap: + + + + +I/O Transforms: + + diff --git a/notes/links.md b/notes/links.md index cd356f6..746f829 100644 --- a/notes/links.md +++ b/notes/links.md @@ -2,10 +2,4 @@ ## Data -Full dataset: - -`wget 0 http://prod.publicdata.landregistry.gov.uk.s3-website-eu-west-1.amazonaws.com/pp-complete.csv` - -Current month: - -`wget 0 http://prod.publicdata.landregistry.gov.uk.s3-website-eu-west-1.amazonaws.com/pp-monthly-update-new-version.csv` +https://www.gov.uk/government/statistical-data-sets/price-paid-data-downloads From 94cc22a385319dcfef292374f08ad2814763fdb5 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sat, 25 Sep 2021 00:48:34 +0100 Subject: [PATCH 09/63] adding data exploration report + code --- exploration/price_paid_data_report.html | 1439 +++++++++++++++++++++++ exploration/report.py | 22 +- 2 files changed, 1460 insertions(+), 1 deletion(-) create mode 100644 exploration/price_paid_data_report.html diff --git a/exploration/price_paid_data_report.html b/exploration/price_paid_data_report.html new file mode 100644 index 0000000..4a641eb --- /dev/null +++ b/exploration/price_paid_data_report.html @@ -0,0 +1,1439 @@ +Price Paid Data

Overview

Dataset statistics

Number of variables16
Number of observations26321785
Missing cells32579197
Missing cells (%)7.7%
Total size in memory3.1 GiB
Average record size in memory128.0 B

Variable types

Categorical15
Numeric1

Warnings

record_status has constant value "A" Constant
transaction_id has a high cardinality: 26321785 distinct values High cardinality
date_of_transfer has a high cardinality: 9698 distinct values High cardinality
postcode has a high cardinality: 1274429 distinct values High cardinality
paon has a high cardinality: 508466 distinct values High cardinality
saon has a high cardinality: 58202 distinct values High cardinality
street has a high cardinality: 320310 distinct values High cardinality
locality has a high cardinality: 23716 distinct values High cardinality
town_city has a high cardinality: 1171 distinct values High cardinality
district has a high cardinality: 463 distinct values High cardinality
county has a high cardinality: 130 distinct values High cardinality
saon has 23252525 (88.3%) missing values Missing
street has 411893 (1.6%) missing values Missing
locality has 8868564 (33.7%) missing values Missing
price is highly skewed (γ1 = 212.5121542) Skewed
transaction_id has unique values Unique

Reproduction

Analysis started2021-09-24 16:09:53.212210
Analysis finished2021-09-24 16:15:35.611974
Duration5 minutes and 42.4 seconds
Software versionpandas-profiling v3.0.0
Download configurationconfig.json

Variables

transaction_id
Categorical

HIGH CARDINALITY
UNIQUE

Distinct26321785
Distinct (%)100.0%
Missing0
Missing (%)0.0%
Memory size200.8 MiB
{A2EF370F-229F-405B-A6EC-3D501915AD67}
 
1
{5F9A7C5C-E476-4986-8722-CCD108EB8B6E}
 
1
{E31EE92A-128A-4AA3-81B2-E7A8B3A4C90D}
 
1
{919FEC05-D788-9A90-E053-6C04A8C0A300}
 
1
{6FFBE023-6AE3-451E-ADA4-8D66F231D8F8}
 
1
Other values (26321780)
26321780 

Unique

Unique26321785 ?
Unique (%)100.0%

Sample

1st row{F887F88E-7D15-4415-804E-52EAC2F10958}
2nd row{40FD4DF2-5362-407C-92BC-566E2CCE89E9}
3rd row{7A99F89E-7D81-4E45-ABD5-566E49A045EA}
4th row{28225260-E61C-4E57-8B56-566E5285B1C1}
5th row{444D34D7-9BA6-43A7-B695-4F48980E0176}

Common Values

ValueCountFrequency (%)
{A2EF370F-229F-405B-A6EC-3D501915AD67}1
 
< 0.1%
{5F9A7C5C-E476-4986-8722-CCD108EB8B6E}1
 
< 0.1%
{E31EE92A-128A-4AA3-81B2-E7A8B3A4C90D}1
 
< 0.1%
{919FEC05-D788-9A90-E053-6C04A8C0A300}1
 
< 0.1%
{6FFBE023-6AE3-451E-ADA4-8D66F231D8F8}1
 
< 0.1%
{174380A1-DCA2-4DB5-A7C3-661C6C5D9798}1
 
< 0.1%
{1D30B696-41C4-4D78-A474-EE409899F476}1
 
< 0.1%
{C18420AC-7FE9-4E93-89AC-53697390DE27}1
 
< 0.1%
{62E23376-BBCE-435C-AE3B-A2CA076580F4}1
 
< 0.1%
{BC6C63E2-BDA1-498E-9E99-3B4A64C67381}1
 
< 0.1%
Other values (26321775)26321775
> 99.9%

price
Real number (ℝ≥0)

SKEWED

Distinct218688
Distinct (%)0.8%
Missing0
Missing (%)0.0%
Infinite0
Infinite (%)0.0%
Mean205226.2064
Minimum1
Maximum630000000
Zeros0
Zeros (%)0.0%
Negative0
Negative (%)0.0%
Memory size200.8 MiB
2021-09-24T17:15:38.084341image/svg+xmlMatplotlib v3.4.3, https://matplotlib.org/

Quantile statistics

Minimum1
5-th percentile36000
Q180500
median142500
Q3235000
95-th percentile500000
Maximum630000000
Range629999999
Interquartile range (IQR)154500

Descriptive statistics

Standard deviation813350.2288
Coefficient of variation (CV)3.963188927
Kurtosis86409.10552
Mean205226.2064
Median Absolute Deviation (MAD)71290
Skewness212.5121542
Sum5.401920082 × 1012
Variance6.615385948 × 1011
MonotonicityNot monotonic
2021-09-24T17:15:38.218791image/svg+xmlMatplotlib v3.4.3, https://matplotlib.org/
Histogram with fixed size bins (bins=50)
ValueCountFrequency (%)
250000283789
 
1.1%
125000246148
 
0.9%
120000216854
 
0.8%
150000205955
 
0.8%
110000192318
 
0.7%
175000185637
 
0.7%
115000182009
 
0.7%
135000181500
 
0.7%
60000180568
 
0.7%
130000178803
 
0.7%
Other values (218678)24268204
92.2%
ValueCountFrequency (%)
1101
< 0.1%
52
 
< 0.1%
108
 
< 0.1%
113
 
< 0.1%
154
 
< 0.1%
ValueCountFrequency (%)
6300000001
< 0.1%
5943000001
< 0.1%
5692000001
< 0.1%
4485000001
< 0.1%
4483009791
< 0.1%

date_of_transfer
Categorical

HIGH CARDINALITY

Distinct9698
Distinct (%)< 0.1%
Missing0
Missing (%)0.0%
Memory size200.8 MiB
2016-03-31 00:00
 
32378
2001-06-29 00:00
 
26583
2002-05-31 00:00
 
26338
2002-06-28 00:00
 
26320
2007-06-29 00:00
 
24970
Other values (9693)
26185196 

Unique

Unique10 ?
Unique (%)< 0.1%

Sample

1st row1995-07-07 00:00
2nd row1995-02-03 00:00
3rd row1995-01-13 00:00
4th row1995-07-28 00:00
5th row1995-06-28 00:00

Common Values

ValueCountFrequency (%)
2016-03-31 00:0032378
 
0.1%
2001-06-29 00:0026583
 
0.1%
2002-05-31 00:0026338
 
0.1%
2002-06-28 00:0026320
 
0.1%
2007-06-29 00:0024970
 
0.1%
2000-06-30 00:0024927
 
0.1%
2003-11-28 00:0024802
 
0.1%
1999-05-28 00:0024335
 
0.1%
2006-06-30 00:0024308
 
0.1%
2000-03-31 00:0023428
 
0.1%
Other values (9688)26063396
99.0%

postcode
Categorical

HIGH CARDINALITY

Distinct1274429
Distinct (%)4.8%
Missing42019
Missing (%)0.2%
Memory size200.8 MiB
YO10 3FT
 
534
LU1 5FT
 
523
RH10 3HZ
 
387
L7 3AA
 
372
TR8 4LX
 
355
Other values (1274424)
26277595 

Unique

Unique88384 ?
Unique (%)0.3%

Sample

1st rowMK15 9HP
2nd rowSR6 0AQ
3rd rowCO6 1SQ
4th rowB90 4TG
5th rowDY5 1SA

Common Values

ValueCountFrequency (%)
YO10 3FT534
 
< 0.1%
LU1 5FT523
 
< 0.1%
RH10 3HZ387
 
< 0.1%
L7 3AA372
 
< 0.1%
TR8 4LX355
 
< 0.1%
M1 5GB348
 
< 0.1%
BS3 3NG322
 
< 0.1%
L5 3AA315
 
< 0.1%
L3 8HA312
 
< 0.1%
CM21 9PF305
 
< 0.1%
Other values (1274419)26275993
99.8%
(Missing)42019
 
0.2%

property_type
Categorical

Distinct5
Distinct (%)< 0.1%
Missing0
Missing (%)0.0%
Memory size200.8 MiB
T
7940720 
S
7224820 
D
6077417 
F
4730013 
O
 
348815

Unique

Unique0 ?
Unique (%)0.0%

Sample

1st rowD
2nd rowT
3rd rowT
4th rowT
5th rowS

Common Values

ValueCountFrequency (%)
T7940720
30.2%
S7224820
27.4%
D6077417
23.1%
F4730013
18.0%
O348815
 
1.3%

old_new
Categorical

Distinct2
Distinct (%)< 0.1%
Missing0
Missing (%)0.0%
Memory size200.8 MiB
N
23590329 
Y
2731456 

Unique

Unique0 ?
Unique (%)0.0%

Sample

1st rowN
2nd rowN
3rd rowN
4th rowN
5th rowN

Common Values

ValueCountFrequency (%)
N23590329
89.6%
Y2731456
 
10.4%

duration
Categorical

Distinct3
Distinct (%)< 0.1%
Missing0
Missing (%)0.0%
Memory size200.8 MiB
F
20127890 
L
6193361 
U
 
534

Unique

Unique0 ?
Unique (%)0.0%

Sample

1st rowF
2nd rowF
3rd rowF
4th rowF
5th rowF

Common Values

ValueCountFrequency (%)
F20127890
76.5%
L6193361
 
23.5%
U534
 
< 0.1%

paon
Categorical

HIGH CARDINALITY

Distinct508466
Distinct (%)1.9%
Missing4196
Missing (%)< 0.1%
Memory size200.8 MiB
1
 
656135
2
 
655728
3
 
649054
4
 
628033
5
 
605766
Other values (508461)
23122873 

Unique

Unique236792 ?
Unique (%)0.9%

Sample

1st row31
2nd row50
3rd row19
4th row37
5th row59

Common Values

ValueCountFrequency (%)
1656135
 
2.5%
2655728
 
2.5%
3649054
 
2.5%
4628033
 
2.4%
5605766
 
2.3%
6584416
 
2.2%
7559000
 
2.1%
8547016
 
2.1%
9517669
 
2.0%
10505557
 
1.9%
Other values (508456)20409215
77.5%

saon
Categorical

HIGH CARDINALITY
MISSING

Distinct58202
Distinct (%)1.9%
Missing23252525
Missing (%)88.3%
Memory size200.8 MiB
FLAT 2
 
165778
FLAT 1
 
164781
FLAT 3
 
148061
FLAT 4
 
122764
FLAT 5
 
97065
Other values (58197)
2370811 

Unique

Unique33682 ?
Unique (%)1.1%

Sample

1st row28
2nd rowFLAT 21
3rd rowFLAT 7A
4th rowFLAT 1
5th rowFLAT 8

Common Values

ValueCountFrequency (%)
FLAT 2165778
 
0.6%
FLAT 1164781
 
0.6%
FLAT 3148061
 
0.6%
FLAT 4122764
 
0.5%
FLAT 597065
 
0.4%
FLAT 682135
 
0.3%
279685
 
0.3%
178655
 
0.3%
FLAT 766209
 
0.3%
FLAT 859802
 
0.2%
Other values (58192)2004325
 
7.6%
(Missing)23252525
88.3%

street
Categorical

HIGH CARDINALITY
MISSING

Distinct320310
Distinct (%)1.2%
Missing411893
Missing (%)1.6%
Memory size200.8 MiB
HIGH STREET
 
169595
STATION ROAD
 
87514
LONDON ROAD
 
60153
CHURCH ROAD
 
49684
CHURCH STREET
 
49125
Other values (320305)
25493821 

Unique

Unique16555 ?
Unique (%)0.1%

Sample

1st rowALDRICH DRIVE
2nd rowHOWICK PARK
3rd rowBRICK KILN CLOSE
4th rowRAINSBROOK DRIVE
5th rowMERRY HILL

Common Values

ValueCountFrequency (%)
HIGH STREET169595
 
0.6%
STATION ROAD87514
 
0.3%
LONDON ROAD60153
 
0.2%
CHURCH ROAD49684
 
0.2%
CHURCH STREET49125
 
0.2%
MAIN STREET48089
 
0.2%
PARK ROAD40175
 
0.2%
VICTORIA ROAD34925
 
0.1%
CHURCH LANE32130
 
0.1%
MAIN ROAD29955
 
0.1%
Other values (320300)25308547
96.2%
(Missing)411893
 
1.6%

locality
Categorical

HIGH CARDINALITY
MISSING

Distinct23716
Distinct (%)0.1%
Missing8868564
Missing (%)33.7%
Memory size200.8 MiB
LONDON
 
899924
BIRMINGHAM
 
111310
MANCHESTER
 
100845
LIVERPOOL
 
99506
LEEDS
 
88968
Other values (23711)
16152668 

Unique

Unique836 ?
Unique (%)< 0.1%

Sample

1st rowWILLEN
2nd rowSUNDERLAND
3rd rowCOGGESHALL
4th rowSHIRLEY
5th rowBRIERLEY HILL

Common Values

ValueCountFrequency (%)
LONDON899924
 
3.4%
BIRMINGHAM111310
 
0.4%
MANCHESTER100845
 
0.4%
LIVERPOOL99506
 
0.4%
LEEDS88968
 
0.3%
BRISTOL88659
 
0.3%
SHEFFIELD76269
 
0.3%
BOURNEMOUTH60354
 
0.2%
SOUTHAMPTON56612
 
0.2%
PLYMOUTH56250
 
0.2%
Other values (23706)15814524
60.1%
(Missing)8868564
33.7%

town_city
Categorical

HIGH CARDINALITY

Distinct1171
Distinct (%)< 0.1%
Missing0
Missing (%)0.0%
Memory size200.8 MiB
LONDON
 
2031341
MANCHESTER
 
431016
BRISTOL
 
404300
BIRMINGHAM
 
386956
NOTTINGHAM
 
344685
Other values (1166)
22723487 

Unique

Unique2 ?
Unique (%)< 0.1%

Sample

1st rowMILTON KEYNES
2nd rowSUNDERLAND
3rd rowCOLCHESTER
4th rowSOLIHULL
5th rowBRIERLEY HILL

Common Values

ValueCountFrequency (%)
LONDON2031341
 
7.7%
MANCHESTER431016
 
1.6%
BRISTOL404300
 
1.5%
BIRMINGHAM386956
 
1.5%
NOTTINGHAM344685
 
1.3%
LEEDS296653
 
1.1%
LIVERPOOL272491
 
1.0%
SHEFFIELD250601
 
1.0%
LEICESTER231450
 
0.9%
SOUTHAMPTON213759
 
0.8%
Other values (1161)21458533
81.5%

district
Categorical

HIGH CARDINALITY

Distinct463
Distinct (%)< 0.1%
Missing0
Missing (%)0.0%
Memory size200.8 MiB
BIRMINGHAM
 
387632
LEEDS
 
351319
BRADFORD
 
230830
SHEFFIELD
 
213316
MANCHESTER
 
210509
Other values (458)
24928179 

Unique

Unique1 ?
Unique (%)< 0.1%

Sample

1st rowMILTON KEYNES
2nd rowSUNDERLAND
3rd rowBRAINTREE
4th rowSOLIHULL
5th rowDUDLEY

Common Values

ValueCountFrequency (%)
BIRMINGHAM387632
 
1.5%
LEEDS351319
 
1.3%
BRADFORD230830
 
0.9%
SHEFFIELD213316
 
0.8%
MANCHESTER210509
 
0.8%
CITY OF BRISTOL205163
 
0.8%
LIVERPOOL183632
 
0.7%
KIRKLEES178730
 
0.7%
WANDSWORTH177641
 
0.7%
EAST RIDING OF YORKSHIRE174522
 
0.7%
Other values (453)24008491
91.2%

county
Categorical

HIGH CARDINALITY

Distinct130
Distinct (%)< 0.1%
Missing0
Missing (%)0.0%
Memory size200.8 MiB
GREATER LONDON
3406054 
GREATER MANCHESTER
 
1165840
WEST MIDLANDS
 
1005283
WEST YORKSHIRE
 
1000437
KENT
 
747469
Other values (125)
18996702 

Unique

Unique0 ?
Unique (%)0.0%

Sample

1st rowMILTON KEYNES
2nd rowTYNE AND WEAR
3rd rowESSEX
4th rowWEST MIDLANDS
5th rowWEST MIDLANDS

Common Values

ValueCountFrequency (%)
GREATER LONDON3406054
 
12.9%
GREATER MANCHESTER1165840
 
4.4%
WEST MIDLANDS1005283
 
3.8%
WEST YORKSHIRE1000437
 
3.8%
KENT747469
 
2.8%
ESSEX732466
 
2.8%
HAMPSHIRE691504
 
2.6%
SURREY593744
 
2.3%
LANCASHIRE593351
 
2.3%
HERTFORDSHIRE559718
 
2.1%
Other values (120)15825919
60.1%

ppd_category
Categorical

Distinct2
Distinct (%)< 0.1%
Missing0
Missing (%)0.0%
Memory size200.8 MiB
A
25365945 
B
 
955840

Unique

Unique0 ?
Unique (%)0.0%

Sample

1st rowA
2nd rowA
3rd rowA
4th rowA
5th rowA

Common Values

ValueCountFrequency (%)
A25365945
96.4%
B955840
 
3.6%

record_status
Categorical

CONSTANT
REJECTED

Distinct1
Distinct (%)< 0.1%
Missing0
Missing (%)0.0%
Memory size200.8 MiB
A
26321785 

Unique

Unique0 ?
Unique (%)0.0%

Sample

1st rowA
2nd rowA
3rd rowA
4th rowA
5th rowA

Common Values

ValueCountFrequency (%)
A26321785
100.0%
\ No newline at end of file diff --git a/exploration/report.py b/exploration/report.py index ff6fac8..ed81b47 100644 --- a/exploration/report.py +++ b/exploration/report.py @@ -6,7 +6,27 @@ from pandas_profiling import ProfileReport def main(): with resources.path("analyse_properties.data", "pp-complete.csv") as csv_file: - df_report = pd.read_csv(csv_file) + df_report = pd.read_csv( + csv_file, + names=[ + "transaction_id", + "price", + "date_of_transfer", + "postcode", + "property_type", + "old_new", + "duration", + "paon", + "saon", + "street", + "locality", + "town_city", + "district", + "county", + "ppd_category", + "record_status", + ], + ) profile = ProfileReport(df_report, title="Price Paid Data", minimal=True) profile.to_file("price_paid_data_report.html") From aa61ea9c57567938afd7330357caecea9b8a2e54 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sat, 25 Sep 2021 00:48:41 +0100 Subject: [PATCH 10/63] adding latest beam pipeline code --- analyse_properties/__init__.py | 65 +++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/analyse_properties/__init__.py b/analyse_properties/__init__.py index b794fd4..dab7851 100644 --- a/analyse_properties/__init__.py +++ b/analyse_properties/__init__.py @@ -1 +1,64 @@ -__version__ = '0.1.0' +""" +Daniel Tomlinson (dtomlinson@panaetius.co.uk). + +Technical test for Street Group. +""" + +import csv +import io +from importlib import resources +from itertools import chain, islice + +import apache_beam as beam +from apache_beam.io import fileio + + +def csv_reader(csv_file): + return csv.reader(io.TextIOWrapper(csv_file.open())) + + +def slicer(element, *ranges): + return chain(*(islice(element, *r) for r in ranges)) + + +class SplitPAON(beam.DoFn): + def process(self, element): + paon_split = element[3].split(",") + + if len(paon_split) == 0: + return element + elif len(paon_split) == 1: + pass + else: + pass + + +def main(): + csv_data = resources.path( + "analyse_properties.data", "pp-monthly-update-new-version.csv" + ) + + with beam.Pipeline() as pipeline: + # Load the data + with csv_data as csv_data_file: + # https://github.com/apache/beam/blob/v2.32.0/sdks/python/apache_beam/io/fileio_test.py#L155-L170 + load = ( + pipeline + | fileio.MatchFiles(str(csv_data_file)) + | fileio.ReadMatches() + | beam.FlatMap(csv_reader) + ) + + # Clean the data + clean = ( + load + | "Drop unneeded columns" + >> beam.Map(lambda element: list(slicer(element, (1, 4), (7, 14)))) + | "Convert to Upper Case" + >> beam.Map(lambda element: [e.upper() for e in element]) + | beam.Map(print) + ) + + +if __name__ == "__main__": + main() From 47a4ac4bc3510f87e7a302563097f29af849ac49 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sat, 25 Sep 2021 01:44:37 +0100 Subject: [PATCH 11/63] adding latest beam pipeline code --- analyse_properties/__init__.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/analyse_properties/__init__.py b/analyse_properties/__init__.py index dab7851..3bce574 100644 --- a/analyse_properties/__init__.py +++ b/analyse_properties/__init__.py @@ -17,7 +17,7 @@ def csv_reader(csv_file): return csv.reader(io.TextIOWrapper(csv_file.open())) -def slicer(element, *ranges): +def slice_by_range(element, *ranges): return chain(*(islice(element, *r) for r in ranges)) @@ -27,12 +27,18 @@ class SplitPAON(beam.DoFn): if len(paon_split) == 0: return element - elif len(paon_split) == 1: - pass - else: + elif len(paon_split) > 0: pass +class DropEmptyColumn(bean.doFn): + def __init__(self, index): + self.index = index + + def process(self, element): + column = element[self.index] + + def main(): csv_data = resources.path( "analyse_properties.data", "pp-monthly-update-new-version.csv" @@ -53,7 +59,7 @@ def main(): clean = ( load | "Drop unneeded columns" - >> beam.Map(lambda element: list(slicer(element, (1, 4), (7, 14)))) + >> beam.Map(lambda element: list(slice_by_range(element, (1, 4), (7, 14)))) | "Convert to Upper Case" >> beam.Map(lambda element: [e.upper() for e in element]) | beam.Map(print) From 214ce77d8f7d0dfd15540e2c4f167c0108d42886 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sat, 25 Sep 2021 16:47:08 +0100 Subject: [PATCH 12/63] adding debug.py --- analyse_properties/debug.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 analyse_properties/debug.py diff --git a/analyse_properties/debug.py b/analyse_properties/debug.py new file mode 100644 index 0000000..ab44457 --- /dev/null +++ b/analyse_properties/debug.py @@ -0,0 +1,24 @@ +import apache_beam as beam + + +class DebugShowEmptyColumn(beam.DoFn): + def __init__(self, index): + self.index = index + + def process(self, element): + column = element[self.index] + if len(column) == 0: + yield element + return None + + +class DebugShowColumnWithValueIn(beam.DoFn): + def __init__(self, index, value): + self.index = index + self.value = value + + def process(self, element): + column = element[self.index] + if self.value in column: + yield element + return None From 539e4c7786b65a30724f6aa45b43fdaf0e8d8a68 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sat, 25 Sep 2021 16:47:17 +0100 Subject: [PATCH 13/63] adding latesty beam pipeline code --- analyse_properties/__init__.py | 72 ++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 11 deletions(-) diff --git a/analyse_properties/__init__.py b/analyse_properties/__init__.py index 3bce574..1e91284 100644 --- a/analyse_properties/__init__.py +++ b/analyse_properties/__init__.py @@ -5,6 +5,7 @@ Technical test for Street Group. """ import csv +import hashlib import io from importlib import resources from itertools import chain, islice @@ -12,6 +13,8 @@ from itertools import chain, islice import apache_beam as beam from apache_beam.io import fileio +from analyse_properties.debug import DebugShowEmptyColumn, DebugShowColumnWithValueIn + def csv_reader(csv_file): return csv.reader(io.TextIOWrapper(csv_file.open())) @@ -21,27 +24,58 @@ def slice_by_range(element, *ranges): return chain(*(islice(element, *r) for r in ranges)) -class SplitPAON(beam.DoFn): - def process(self, element): - paon_split = element[3].split(",") - - if len(paon_split) == 0: - return element - elif len(paon_split) > 0: - pass - - -class DropEmptyColumn(bean.doFn): +class DropRecordsSingleEmptyColumn(beam.DoFn): def __init__(self, index): self.index = index def process(self, element): column = element[self.index] + if len(column) == 0: + return None + yield element + + +class DropRecordsTwoEmptyColumn(beam.DoFn): + def __init__(self, index_0, index_1): + self.index_0 = index_0 + self.index_1 = index_1 + + def process(self, element): + column_0 = element[self.index_0] + column_1 = element[self.index_1] + if len(column_0) == 0 and len(column_1) == 0: + return None + yield element + + +class SplitColumn(beam.DoFn): + def __init__(self, index, split_char): + self.index = index + self.split_char = split_char + + def process(self, element): + try: + part_0, part_1 = element[self.index].split(self.split_char) + element[self.index] = part_1.strip() + element.append(part_0.strip()) + yield element + except ValueError: + element.append("") + yield element + + +class GenerateUniqueID(beam.DoFn): + def process(self, element): + unique_string = ",".join(element[2:]) + hashed_string = hashlib.md5(unique_string.encode()) + element.append(hashed_string.hexdigest()) + yield element def main(): csv_data = resources.path( "analyse_properties.data", "pp-monthly-update-new-version.csv" + # "analyse_properties.data", "pp-complete.csv" ) with beam.Pipeline() as pipeline: @@ -62,6 +96,22 @@ def main(): >> beam.Map(lambda element: list(slice_by_range(element, (1, 4), (7, 14)))) | "Convert to Upper Case" >> beam.Map(lambda element: [e.upper() for e in element]) + | "Strip leading/trailing whitespace" + >> beam.Map(lambda element: [e.strip() for e in element]) + | "Drop Empty Postcodes" + >> beam.ParDo(DropRecordsSingleEmptyColumn(2)) + | "Drop empty PAON if missing SAON" + >> beam.ParDo(DropRecordsTwoEmptyColumn(3, 4)) + # | beam.ParDo(DebugShowColumnWithValueIn(3, ",")) + | beam.ParDo(DebugShowColumnWithValueIn(2, "AL1 4SZ")) + | beam.ParDo(SplitColumn(3, ",")) + # | beam.Map(print) + ) + + # Prepare the data + prepare = ( + clean + | beam.ParDo(GenerateUniqueID()) | beam.Map(print) ) From a37e7817c3d502f4ffb47782f812d82a3e957ac2 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sat, 25 Sep 2021 16:47:17 +0100 Subject: [PATCH 14/63] adding latest beam pipeline code --- analyse_properties/__init__.py | 72 ++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 11 deletions(-) diff --git a/analyse_properties/__init__.py b/analyse_properties/__init__.py index 3bce574..1e91284 100644 --- a/analyse_properties/__init__.py +++ b/analyse_properties/__init__.py @@ -5,6 +5,7 @@ Technical test for Street Group. """ import csv +import hashlib import io from importlib import resources from itertools import chain, islice @@ -12,6 +13,8 @@ from itertools import chain, islice import apache_beam as beam from apache_beam.io import fileio +from analyse_properties.debug import DebugShowEmptyColumn, DebugShowColumnWithValueIn + def csv_reader(csv_file): return csv.reader(io.TextIOWrapper(csv_file.open())) @@ -21,27 +24,58 @@ def slice_by_range(element, *ranges): return chain(*(islice(element, *r) for r in ranges)) -class SplitPAON(beam.DoFn): - def process(self, element): - paon_split = element[3].split(",") - - if len(paon_split) == 0: - return element - elif len(paon_split) > 0: - pass - - -class DropEmptyColumn(bean.doFn): +class DropRecordsSingleEmptyColumn(beam.DoFn): def __init__(self, index): self.index = index def process(self, element): column = element[self.index] + if len(column) == 0: + return None + yield element + + +class DropRecordsTwoEmptyColumn(beam.DoFn): + def __init__(self, index_0, index_1): + self.index_0 = index_0 + self.index_1 = index_1 + + def process(self, element): + column_0 = element[self.index_0] + column_1 = element[self.index_1] + if len(column_0) == 0 and len(column_1) == 0: + return None + yield element + + +class SplitColumn(beam.DoFn): + def __init__(self, index, split_char): + self.index = index + self.split_char = split_char + + def process(self, element): + try: + part_0, part_1 = element[self.index].split(self.split_char) + element[self.index] = part_1.strip() + element.append(part_0.strip()) + yield element + except ValueError: + element.append("") + yield element + + +class GenerateUniqueID(beam.DoFn): + def process(self, element): + unique_string = ",".join(element[2:]) + hashed_string = hashlib.md5(unique_string.encode()) + element.append(hashed_string.hexdigest()) + yield element def main(): csv_data = resources.path( "analyse_properties.data", "pp-monthly-update-new-version.csv" + # "analyse_properties.data", "pp-complete.csv" ) with beam.Pipeline() as pipeline: @@ -62,6 +96,22 @@ def main(): >> beam.Map(lambda element: list(slice_by_range(element, (1, 4), (7, 14)))) | "Convert to Upper Case" >> beam.Map(lambda element: [e.upper() for e in element]) + | "Strip leading/trailing whitespace" + >> beam.Map(lambda element: [e.strip() for e in element]) + | "Drop Empty Postcodes" + >> beam.ParDo(DropRecordsSingleEmptyColumn(2)) + | "Drop empty PAON if missing SAON" + >> beam.ParDo(DropRecordsTwoEmptyColumn(3, 4)) + # | beam.ParDo(DebugShowColumnWithValueIn(3, ",")) + | beam.ParDo(DebugShowColumnWithValueIn(2, "AL1 4SZ")) + | beam.ParDo(SplitColumn(3, ",")) + # | beam.Map(print) + ) + + # Prepare the data + prepare = ( + clean + | beam.ParDo(GenerateUniqueID()) | beam.Map(print) ) From 24420c89350985bba5dbd32dcbb72c98cc8ebee3 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sat, 25 Sep 2021 18:25:08 +0100 Subject: [PATCH 15/63] adding latest beam pipeline code --- analyse_properties/__init__.py | 83 ++++++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 9 deletions(-) diff --git a/analyse_properties/__init__.py b/analyse_properties/__init__.py index 1e91284..88c30c7 100644 --- a/analyse_properties/__init__.py +++ b/analyse_properties/__init__.py @@ -65,16 +65,60 @@ class SplitColumn(beam.DoFn): class GenerateUniqueID(beam.DoFn): + def __init__(self, all_columns=False): + self.all_columns = all_columns + def process(self, element): - unique_string = ",".join(element[2:]) + unique_string = ( + ",".join(element[2:]) if not self.all_columns else ",".join(element) + ) hashed_string = hashlib.md5(unique_string.encode()) element.append(hashed_string.hexdigest()) yield element +class DeduplicateByGroup(beam.DoFn): + def process(self, element): + if len(element[1]) > 0: + deduplicated_element = (element[0], [element[1][0]]) + yield deduplicated_element + else: + yield element + + +class RemoveUniqueID(beam.DoFn): + def process(self, element): + element_no_id = element[-1][0] + element_no_id.pop(-1) + yield element_no_id + + +class ConvertDataToDict(beam.DoFn): + @property + def dict_keys(self): + return [ + "price", + "transaction_date", + "postcode", + "number", + "flat_appartment", + "street", + "locality", + "town_city", + "district", + "county", + "building", + "property_id", + ] + + def process(self, element): + pass + + def main(): csv_data = resources.path( - "analyse_properties.data", "pp-monthly-update-new-version.csv" + "analyse_properties.data", + "pp-monthly-update-new-version.csv" # "analyse_properties.data", "pp-complete.csv" ) @@ -90,7 +134,7 @@ def main(): ) # Clean the data - clean = ( + clean_drop = ( load | "Drop unneeded columns" >> beam.Map(lambda element: list(slice_by_range(element, (1, 4), (7, 14)))) @@ -98,23 +142,44 @@ def main(): >> beam.Map(lambda element: [e.upper() for e in element]) | "Strip leading/trailing whitespace" >> beam.Map(lambda element: [e.strip() for e in element]) - | "Drop Empty Postcodes" - >> beam.ParDo(DropRecordsSingleEmptyColumn(2)) + | "Drop Empty Postcodes" >> beam.ParDo(DropRecordsSingleEmptyColumn(2)) | "Drop empty PAON if missing SAON" >> beam.ParDo(DropRecordsTwoEmptyColumn(3, 4)) # | beam.ParDo(DebugShowColumnWithValueIn(3, ",")) - | beam.ParDo(DebugShowColumnWithValueIn(2, "AL1 4SZ")) - | beam.ParDo(SplitColumn(3, ",")) + # | beam.ParDo(DebugShowColumnWithValueIn(2, "AL1 4SZ")) + # | beam.ParDo(DebugShowColumnWithValueIn(2, "B16 0AE")) + | "Split PAON into two columns if separated by comma" + >> beam.ParDo(SplitColumn(3, ",")) + ) + + clean_deduplicate = ( + clean_drop + | "Generate unique ID for all columns" + >> beam.ParDo(GenerateUniqueID(all_columns=True)) + | "Group by the ID for all columns" + >> beam.GroupBy(lambda element: element[-1]) + | "Deduplicate by the ID for all columns" + >> beam.ParDo(DeduplicateByGroup()) # | beam.Map(print) ) # Prepare the data prepare = ( - clean - | beam.ParDo(GenerateUniqueID()) + clean_deduplicate + | "Remove previous unique ID" >> beam.ParDo(RemoveUniqueID()) + | "Generate unique ID ignoring price & date" + >> beam.ParDo(GenerateUniqueID()) + | "Group by the ID ignoring price & date" + >> beam.GroupBy(lambda element: element[-1]) | beam.Map(print) ) + # Format the data + formatted = ( + prepare + # | "Convert list to dict object" >> + ) + if __name__ == "__main__": main() From a7c52b10854a7b79ad5a117f2fe8e4450065a125 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sat, 25 Sep 2021 22:15:10 +0100 Subject: [PATCH 16/63] updating .gitignore --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index e220705..ea6db59 100644 --- a/.gitignore +++ b/.gitignore @@ -138,4 +138,6 @@ dmypy.json cython_debug/ # USER -data/ + +# ignore the data csv files for input/output +**/data/**/*.csv From 1bd54f188ddc4d95929f194d739e434aa44b53ef Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sat, 25 Sep 2021 22:15:39 +0100 Subject: [PATCH 17/63] updating folder structure for data input/output --- analyse_properties/data/__init__.py | 0 analyse_properties/data/input/__init__.py | 0 analyse_properties/data/output/__init__.py | 0 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 analyse_properties/data/__init__.py create mode 100644 analyse_properties/data/input/__init__.py create mode 100644 analyse_properties/data/output/__init__.py diff --git a/analyse_properties/data/__init__.py b/analyse_properties/data/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/analyse_properties/data/input/__init__.py b/analyse_properties/data/input/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/analyse_properties/data/output/__init__.py b/analyse_properties/data/output/__init__.py new file mode 100644 index 0000000..e69de29 From adfbd8e93d678b064747118c6458817ae2fc8575 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sat, 25 Sep 2021 22:15:46 +0100 Subject: [PATCH 18/63] updating prospector.yaml --- prospector.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/prospector.yaml b/prospector.yaml index fbfeef5..5c944a1 100644 --- a/prospector.yaml +++ b/prospector.yaml @@ -15,6 +15,10 @@ pylint: - missing-module-docstring - logging-fstring-interpolation - missing-function-docstring + - abstract-method + - missing-class-docstring + - super-init-not-called + - arguments-differ enable: options: @@ -62,7 +66,12 @@ pep257: - D413 - D406 - D103 + - D101 # missing docstring in public class + - D102 # missing docstring in public method +pyflakes: + disable: + - F401 # unused import dodgy: run: true From 2e42a453b0b0aa0b9dd88d584cf7b0b1d1e6a69f Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sat, 25 Sep 2021 22:15:58 +0100 Subject: [PATCH 19/63] adding latest beam pipeline code --- analyse_properties/__init__.py | 123 +++++++++++++++++++++++++++------ 1 file changed, 101 insertions(+), 22 deletions(-) diff --git a/analyse_properties/__init__.py b/analyse_properties/__init__.py index 88c30c7..d2a362d 100644 --- a/analyse_properties/__init__.py +++ b/analyse_properties/__init__.py @@ -5,10 +5,13 @@ Technical test for Street Group. """ import csv +from datetime import datetime +from pprint import pprint import hashlib import io from importlib import resources -from itertools import chain, islice +import itertools +import pathlib import apache_beam as beam from apache_beam.io import fileio @@ -21,7 +24,7 @@ def csv_reader(csv_file): def slice_by_range(element, *ranges): - return chain(*(islice(element, *r) for r in ranges)) + return itertools.chain(*(itertools.islice(element, *r) for r in ranges)) class DropRecordsSingleEmptyColumn(beam.DoFn): @@ -94,30 +97,103 @@ class RemoveUniqueID(beam.DoFn): class ConvertDataToDict(beam.DoFn): - @property - def dict_keys(self): - return [ - "price", - "transaction_date", - "postcode", - "number", - "flat_appartment", - "street", - "locality", - "town_city", - "district", - "county", - "building", - "property_id", + @staticmethod + def get_latest_transaction(transaction_dates): + transaction_dates = [ + datetime.strptime(individual_transaction, "%Y-%m-%d") + for individual_transaction in transaction_dates ] + return max(transaction_dates).strftime("%Y") + + @staticmethod + def get_readable_address(address_components: list, address_comparisons: list): + # Get pairwise comparison to see if two locality/town/district/counties + # are equivalent + pairwise_comparison = [ + x == y + for i, x in enumerate(address_comparisons) + for j, y in enumerate(address_comparisons) + if i > j + ] + # Create a mask to eliminate the redundant parts of the address + mask = [True, True, True, True] + if pairwise_comparison[0]: + mask[1] = False + if pairwise_comparison[1] or pairwise_comparison[2]: + mask[2] = False + if pairwise_comparison[3] or pairwise_comparison[4] or pairwise_comparison[5]: + mask[3] = False + # Apply the mask + applied_mask = list(itertools.compress(address_comparisons, mask)) + # Filter out empty items in list + deduplicated_address_part = list(filter(None, applied_mask)) + # print(deduplicated_address_part) + + # Filter out any missing parts of the address components + cleaned_address_components = list(filter(None, address_components)) + + # Return the readable address + return "\n".join( + itertools.chain.from_iterable( + [ + cleaned_address_components[0:-1], + deduplicated_address_part, + [cleaned_address_components[-1]], + ] + ) + ) def process(self, element): - pass + property_transactions = [ + { + "price": entry[0], + "transaction_date": entry[1].replace(" 00:00", ""), + "year": entry[1][0:4], + } + for entry in element[-1] + ] + + json_object = { + "property_id": element[0], + "readable_address": None, + "flat_appartment": element[-1][0][4], + "builing": element[-1][0][10], + "number": element[-1][0][3], + "street": element[-1][0][5], + "locality": element[-1][0][6], + "town": element[-1][0][7], + "district": element[-1][0][8], + "county": element[-1][0][9], + "postcode": element[-1][0][2], + "property_transactions": property_transactions, + "latest_transaction_year": self.get_latest_transaction( + [ + transaction["transaction_date"] + for transaction in property_transactions + ] + ), + } + + json_object["readable_address"] = self.get_readable_address( + [ + json_object["flat_appartment"], + json_object["builing"], + f'{json_object["number"]} {json_object["street"]}', + json_object["postcode"], + ], + [ + json_object["locality"], + json_object["town"], + json_object["district"], + json_object["county"], + ], + ) + yield json_object def main(): csv_data = resources.path( - "analyse_properties.data", + "analyse_properties.data.input", "pp-monthly-update-new-version.csv" # "analyse_properties.data", "pp-complete.csv" ) @@ -160,7 +236,6 @@ def main(): >> beam.GroupBy(lambda element: element[-1]) | "Deduplicate by the ID for all columns" >> beam.ParDo(DeduplicateByGroup()) - # | beam.Map(print) ) # Prepare the data @@ -171,15 +246,19 @@ def main(): >> beam.ParDo(GenerateUniqueID()) | "Group by the ID ignoring price & date" >> beam.GroupBy(lambda element: element[-1]) - | beam.Map(print) ) # Format the data formatted = ( prepare - # | "Convert list to dict object" >> + | "Convert the prepared data into a dict object" + >> beam.ParDo(ConvertDataToDict()) + | beam.Map(pprint) ) + # Save the data + with resources.path("analyse_properties.data.output") + if __name__ == "__main__": main() From 54cf5e3e36a70ee60a575104824bd5e39fbef505 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sun, 26 Sep 2021 01:09:48 +0100 Subject: [PATCH 20/63] updating prospector.yaml --- prospector.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/prospector.yaml b/prospector.yaml index 5c944a1..86f9e76 100644 --- a/prospector.yaml +++ b/prospector.yaml @@ -19,6 +19,7 @@ pylint: - missing-class-docstring - super-init-not-called - arguments-differ + - inconsistent-return-statements enable: options: From 9fdc6dce05f7abef2f79b57941abcc6075ec8baf Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sun, 26 Sep 2021 01:10:09 +0100 Subject: [PATCH 21/63] migrate beam pipeline to main.py --- analyse_properties/__init__.py | 259 ----------------------------- analyse_properties/main.py | 293 +++++++++++++++++++++++++++++++++ 2 files changed, 293 insertions(+), 259 deletions(-) create mode 100644 analyse_properties/main.py diff --git a/analyse_properties/__init__.py b/analyse_properties/__init__.py index d2a362d..5bc925e 100644 --- a/analyse_properties/__init__.py +++ b/analyse_properties/__init__.py @@ -3,262 +3,3 @@ Daniel Tomlinson (dtomlinson@panaetius.co.uk). Technical test for Street Group. """ - -import csv -from datetime import datetime -from pprint import pprint -import hashlib -import io -from importlib import resources -import itertools -import pathlib - -import apache_beam as beam -from apache_beam.io import fileio - -from analyse_properties.debug import DebugShowEmptyColumn, DebugShowColumnWithValueIn - - -def csv_reader(csv_file): - return csv.reader(io.TextIOWrapper(csv_file.open())) - - -def slice_by_range(element, *ranges): - return itertools.chain(*(itertools.islice(element, *r) for r in ranges)) - - -class DropRecordsSingleEmptyColumn(beam.DoFn): - def __init__(self, index): - self.index = index - - def process(self, element): - column = element[self.index] - if len(column) == 0: - return None - yield element - - -class DropRecordsTwoEmptyColumn(beam.DoFn): - def __init__(self, index_0, index_1): - self.index_0 = index_0 - self.index_1 = index_1 - - def process(self, element): - column_0 = element[self.index_0] - column_1 = element[self.index_1] - if len(column_0) == 0 and len(column_1) == 0: - return None - yield element - - -class SplitColumn(beam.DoFn): - def __init__(self, index, split_char): - self.index = index - self.split_char = split_char - - def process(self, element): - try: - part_0, part_1 = element[self.index].split(self.split_char) - element[self.index] = part_1.strip() - element.append(part_0.strip()) - yield element - except ValueError: - element.append("") - yield element - - -class GenerateUniqueID(beam.DoFn): - def __init__(self, all_columns=False): - self.all_columns = all_columns - - def process(self, element): - unique_string = ( - ",".join(element[2:]) if not self.all_columns else ",".join(element) - ) - hashed_string = hashlib.md5(unique_string.encode()) - element.append(hashed_string.hexdigest()) - yield element - - -class DeduplicateByGroup(beam.DoFn): - def process(self, element): - if len(element[1]) > 0: - deduplicated_element = (element[0], [element[1][0]]) - yield deduplicated_element - else: - yield element - - -class RemoveUniqueID(beam.DoFn): - def process(self, element): - element_no_id = element[-1][0] - element_no_id.pop(-1) - yield element_no_id - - -class ConvertDataToDict(beam.DoFn): - @staticmethod - def get_latest_transaction(transaction_dates): - transaction_dates = [ - datetime.strptime(individual_transaction, "%Y-%m-%d") - for individual_transaction in transaction_dates - ] - return max(transaction_dates).strftime("%Y") - - @staticmethod - def get_readable_address(address_components: list, address_comparisons: list): - # Get pairwise comparison to see if two locality/town/district/counties - # are equivalent - pairwise_comparison = [ - x == y - for i, x in enumerate(address_comparisons) - for j, y in enumerate(address_comparisons) - if i > j - ] - # Create a mask to eliminate the redundant parts of the address - mask = [True, True, True, True] - if pairwise_comparison[0]: - mask[1] = False - if pairwise_comparison[1] or pairwise_comparison[2]: - mask[2] = False - if pairwise_comparison[3] or pairwise_comparison[4] or pairwise_comparison[5]: - mask[3] = False - # Apply the mask - applied_mask = list(itertools.compress(address_comparisons, mask)) - # Filter out empty items in list - deduplicated_address_part = list(filter(None, applied_mask)) - # print(deduplicated_address_part) - - # Filter out any missing parts of the address components - cleaned_address_components = list(filter(None, address_components)) - - # Return the readable address - return "\n".join( - itertools.chain.from_iterable( - [ - cleaned_address_components[0:-1], - deduplicated_address_part, - [cleaned_address_components[-1]], - ] - ) - ) - - def process(self, element): - property_transactions = [ - { - "price": entry[0], - "transaction_date": entry[1].replace(" 00:00", ""), - "year": entry[1][0:4], - } - for entry in element[-1] - ] - - json_object = { - "property_id": element[0], - "readable_address": None, - "flat_appartment": element[-1][0][4], - "builing": element[-1][0][10], - "number": element[-1][0][3], - "street": element[-1][0][5], - "locality": element[-1][0][6], - "town": element[-1][0][7], - "district": element[-1][0][8], - "county": element[-1][0][9], - "postcode": element[-1][0][2], - "property_transactions": property_transactions, - "latest_transaction_year": self.get_latest_transaction( - [ - transaction["transaction_date"] - for transaction in property_transactions - ] - ), - } - - json_object["readable_address"] = self.get_readable_address( - [ - json_object["flat_appartment"], - json_object["builing"], - f'{json_object["number"]} {json_object["street"]}', - json_object["postcode"], - ], - [ - json_object["locality"], - json_object["town"], - json_object["district"], - json_object["county"], - ], - ) - yield json_object - - -def main(): - csv_data = resources.path( - "analyse_properties.data.input", - "pp-monthly-update-new-version.csv" - # "analyse_properties.data", "pp-complete.csv" - ) - - with beam.Pipeline() as pipeline: - # Load the data - with csv_data as csv_data_file: - # https://github.com/apache/beam/blob/v2.32.0/sdks/python/apache_beam/io/fileio_test.py#L155-L170 - load = ( - pipeline - | fileio.MatchFiles(str(csv_data_file)) - | fileio.ReadMatches() - | beam.FlatMap(csv_reader) - ) - - # Clean the data - clean_drop = ( - load - | "Drop unneeded columns" - >> beam.Map(lambda element: list(slice_by_range(element, (1, 4), (7, 14)))) - | "Convert to Upper Case" - >> beam.Map(lambda element: [e.upper() for e in element]) - | "Strip leading/trailing whitespace" - >> beam.Map(lambda element: [e.strip() for e in element]) - | "Drop Empty Postcodes" >> beam.ParDo(DropRecordsSingleEmptyColumn(2)) - | "Drop empty PAON if missing SAON" - >> beam.ParDo(DropRecordsTwoEmptyColumn(3, 4)) - # | beam.ParDo(DebugShowColumnWithValueIn(3, ",")) - # | beam.ParDo(DebugShowColumnWithValueIn(2, "AL1 4SZ")) - # | beam.ParDo(DebugShowColumnWithValueIn(2, "B16 0AE")) - | "Split PAON into two columns if separated by comma" - >> beam.ParDo(SplitColumn(3, ",")) - ) - - clean_deduplicate = ( - clean_drop - | "Generate unique ID for all columns" - >> beam.ParDo(GenerateUniqueID(all_columns=True)) - | "Group by the ID for all columns" - >> beam.GroupBy(lambda element: element[-1]) - | "Deduplicate by the ID for all columns" - >> beam.ParDo(DeduplicateByGroup()) - ) - - # Prepare the data - prepare = ( - clean_deduplicate - | "Remove previous unique ID" >> beam.ParDo(RemoveUniqueID()) - | "Generate unique ID ignoring price & date" - >> beam.ParDo(GenerateUniqueID()) - | "Group by the ID ignoring price & date" - >> beam.GroupBy(lambda element: element[-1]) - ) - - # Format the data - formatted = ( - prepare - | "Convert the prepared data into a dict object" - >> beam.ParDo(ConvertDataToDict()) - | beam.Map(pprint) - ) - - # Save the data - with resources.path("analyse_properties.data.output") - - -if __name__ == "__main__": - main() diff --git a/analyse_properties/main.py b/analyse_properties/main.py new file mode 100644 index 0000000..95b8299 --- /dev/null +++ b/analyse_properties/main.py @@ -0,0 +1,293 @@ +import csv +from datetime import datetime +import hashlib +import io +from importlib import resources +import itertools +import pathlib + +import apache_beam as beam +from apache_beam.io import fileio + +# from analyse_properties.debug import DebugShowEmptyColumn, DebugShowColumnWithValueIn + + +def csv_reader(csv_file): + """Read in a csv file.""" + return csv.reader(io.TextIOWrapper(csv_file.open())) + + +def slice_by_range(element, *ranges): + """Slice a list with multiple ranges.""" + return itertools.chain(*(itertools.islice(element, *r) for r in ranges)) + + +class DropRecordsSingleEmptyColumn(beam.DoFn): + """If a given item in a list is empty, drop this entry from the PCollection.""" + + def __init__(self, index): + self.index = index + + def process(self, element): + column = element[self.index] + if len(column) == 0: + return None + yield element + + +class DropRecordsTwoEmptyColumn(beam.DoFn): + """If two given items in a list are both empty, drop this entry from the PCollection.""" + + def __init__(self, index_0, index_1): + self.index_0 = index_0 + self.index_1 = index_1 + + def process(self, element): + column_0 = element[self.index_0] + column_1 = element[self.index_1] + if len(column_0) == 0 and len(column_1) == 0: + return None + yield element + + +class SplitColumn(beam.DoFn): + """Split an item in a list into two separate items in the PCollection.""" + + def __init__(self, index, split_char): + self.index = index + self.split_char = split_char + + def process(self, element): + # If there is a split based on the split_char, then keep the first result in + # place and append the second. + try: + part_0, part_1 = element[self.index].split(self.split_char) + element[self.index] = part_1.strip() + element.append(part_0.strip()) + yield element + except ValueError: + element.append("") + yield element + + +class GenerateUniqueID(beam.DoFn): + """ + Generate a unique ID for the PCollection, either for all the columns or for the + uniquely identifying data only. + """ + + def __init__(self, all_columns=False): + self.all_columns = all_columns + + def process(self, element): + unique_string = ( + ",".join(element[2:]) if not self.all_columns else ",".join(element) + ) + hashed_string = hashlib.md5(unique_string.encode()) + # append the hash to the end + element.append(hashed_string.hexdigest()) + yield element + + +class DeduplicateByID(beam.DoFn): + """ + If the PCollection has multiple entries after being grouped by ID for all columns, + deduplicate the list to keep only one. + """ + + def process(self, element): + if len(element[1]) > 0: + deduplicated_element = (element[0], [element[1][0]]) + yield deduplicated_element + else: + yield element + + +class RemoveUniqueID(beam.DoFn): + """Remove the unique ID from the PCollection, transforming it back into a list.""" + + def process(self, element): + element_no_id = element[-1][0] + element_no_id.pop(-1) + yield element_no_id + + +class ConvertDataToDict(beam.DoFn): + """Convert the processed data into a dict to be exported as a JSON object.""" + + @staticmethod + def get_latest_transaction(transaction_dates): + """Get the date of the latest transaction.""" + transaction_dates = [ + datetime.strptime(individual_transaction, "%Y-%m-%d") + for individual_transaction in transaction_dates + ] + return max(transaction_dates).strftime("%Y") + + @staticmethod + def get_readable_address(address_components: list, address_comparisons: list): + # Get pairwise comparison to see if two locality/town/district/counties + # are equivalent + pairwise_comparison = [ + x == y + for i, x in enumerate(address_comparisons) + for j, y in enumerate(address_comparisons) + if i > j + ] + # Create a mask to eliminate the redundant parts of the address + mask = [True, True, True, True] + if pairwise_comparison[0]: + mask[1] = False + if pairwise_comparison[1] or pairwise_comparison[2]: + mask[2] = False + if pairwise_comparison[3] or pairwise_comparison[4] or pairwise_comparison[5]: + mask[3] = False + # Apply the mask + applied_mask = list(itertools.compress(address_comparisons, mask)) + # Filter out empty items in list + deduplicated_address_part = list(filter(None, applied_mask)) + + # Filter out any missing parts of the address components + cleaned_address_components = list(filter(None, address_components)) + + # Return the readable address + return "\n".join( + itertools.chain.from_iterable( + [ + cleaned_address_components[0:-1], + deduplicated_address_part, + [cleaned_address_components[-1]], + ] + ) + ) + + def process(self, element): + # Group together all the transactions for the property. + property_transactions = [ + { + "price": entry[0], + "transaction_date": entry[1].replace(" 00:00", ""), + "year": entry[1][0:4], + } + for entry in element[-1] + ] + + # Create the dict to hold all the information about the property. + json_object = { + "property_id": element[0], + "readable_address": None, + "flat_appartment": element[-1][0][4], + "builing": element[-1][0][10], + "number": element[-1][0][3], + "street": element[-1][0][5], + "locality": element[-1][0][6], + "town": element[-1][0][7], + "district": element[-1][0][8], + "county": element[-1][0][9], + "postcode": element[-1][0][2], + "property_transactions": property_transactions, + "latest_transaction_year": self.get_latest_transaction( + [ + transaction["transaction_date"] + for transaction in property_transactions + ] + ), + } + + # Create a human readable address to go in the dict. + json_object["readable_address"] = self.get_readable_address( + [ + json_object["flat_appartment"], + json_object["builing"], + f'{json_object["number"]} {json_object["street"]}', + json_object["postcode"], + ], + [ + json_object["locality"], + json_object["town"], + json_object["district"], + json_object["county"], + ], + ) + yield json_object + + +def main(): + # Load in the data from a csv file. + csv_data = resources.path( + # "analyse_properties.data.input", + # "pp-monthly-update-new-version.csv" + "analyse_properties.data.input", "pp-complete.csv" + ) + + with beam.Pipeline() as pipeline: + # Load the data + with csv_data as csv_data_file: + # https://github.com/apache/beam/blob/v2.32.0/sdks/python/apache_beam/io/fileio_test.py#L155-L170 + load = ( + pipeline + | fileio.MatchFiles(str(csv_data_file)) + | fileio.ReadMatches() + | beam.FlatMap(csv_reader) + ) + + # Clean the data by dropping unneeded rows. + clean_drop = ( + load + | "Drop unneeded columns" + >> beam.Map(lambda element: list(slice_by_range(element, (1, 4), (7, 14)))) + | "Convert to Upper Case" + >> beam.Map(lambda element: [e.upper() for e in element]) + | "Strip leading/trailing whitespace" + >> beam.Map(lambda element: [e.strip() for e in element]) + | "Drop Empty Postcodes" >> beam.ParDo(DropRecordsSingleEmptyColumn(2)) + | "Drop empty PAON if missing SAON" + >> beam.ParDo(DropRecordsTwoEmptyColumn(3, 4)) + | "Split PAON into two columns if separated by comma" + >> beam.ParDo(SplitColumn(3, ",")) + ) + + # Clean the data by creating an ID, and deduplicating to eliminate repeated rows. + clean_deduplicate = ( + clean_drop + | "Generate unique ID for all columns" + >> beam.ParDo(GenerateUniqueID(all_columns=True)) + | "Group by the ID for all columns" + >> beam.GroupBy(lambda element: element[-1]) + | "Deduplicate by the ID for all columns" >> beam.ParDo(DeduplicateByID()) + ) + + # Prepare the data by generating an ID using the uniquely identifying information only + # and grouping them by this ID. + prepare = ( + clean_deduplicate + | "Remove previous unique ID" >> beam.ParDo(RemoveUniqueID()) + | "Generate unique ID ignoring price & date" + >> beam.ParDo(GenerateUniqueID()) + | "Group by the ID ignoring price & date" + >> beam.GroupBy(lambda element: element[-1]) + ) + + # Format the data into a dict. + formatted = ( + prepare + | "Convert the prepared data into a dict object" + >> beam.ParDo(ConvertDataToDict()) + ) + + # Save the data to a .json file. + output_file = pathlib.Path(__file__).parent / "data" / "output" / "pp-complete" + output = ( + formatted + | "Combine into one PCollection" >> beam.combiners.ToList() + | "Save to .json file" + >> beam.io.WriteToText( + file_path_prefix=str(output_file), + file_name_suffix=".json", + shard_name_template="", + ) + ) + + +if __name__ == "__main__": + main() From f804e85cc3247b679f8427f8837db7a881009575 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sun, 26 Sep 2021 01:10:32 +0100 Subject: [PATCH 22/63] updating .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ea6db59..bf17437 100644 --- a/.gitignore +++ b/.gitignore @@ -141,3 +141,4 @@ cython_debug/ # ignore the data csv files for input/output **/data/**/*.csv +**/data/**/*.json From 07d176be795e51b0f4a7c9837dbe7b82ba73ee58 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sun, 26 Sep 2021 01:10:53 +0100 Subject: [PATCH 23/63] updating .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index bf17437..3875f91 100644 --- a/.gitignore +++ b/.gitignore @@ -142,3 +142,4 @@ cython_debug/ # ignore the data csv files for input/output **/data/**/*.csv **/data/**/*.json +.vscode/settings.json From 2a43ea19463190f79c82486807e24a942a42c617 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sun, 26 Sep 2021 01:18:23 +0100 Subject: [PATCH 24/63] adding download script for data set --- download_data.sh | 5 +++++ 1 file changed, 5 insertions(+) create mode 100755 download_data.sh diff --git a/download_data.sh b/download_data.sh new file mode 100755 index 0000000..d69c6e4 --- /dev/null +++ b/download_data.sh @@ -0,0 +1,5 @@ +# Full data set +wget https://storage.googleapis.com/street-group-technical-test-dmot/pp-complete.csv -P analyse_properties/data/input + +# Monthly update data set +# wget https://storage.googleapis.com/street-group-technical-test-dmot/pp-monthly-update-new-version.csv -P analyse_properties/data/input From 7962f40e320c3dc8d4c79d75cc06eb37aa21a774 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sun, 26 Sep 2021 01:34:06 +0100 Subject: [PATCH 25/63] adding initial docs --- docs/index.md | 5 + mkdocs.yaml | 40 ++++++++ poetry.lock | 213 ++++++++++++++++++++++++++++++++++++++++-- pyproject.toml | 2 + requirements-docs.txt | 6 ++ 5 files changed, 259 insertions(+), 7 deletions(-) create mode 100644 docs/index.md create mode 100644 mkdocs.yaml create mode 100644 requirements-docs.txt diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..165bd01 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,5 @@ +# Welcome + +## Introduction + +This documentation accompanies the technical test for the Street Group. diff --git a/mkdocs.yaml b/mkdocs.yaml new file mode 100644 index 0000000..b092c7d --- /dev/null +++ b/mkdocs.yaml @@ -0,0 +1,40 @@ +site_name: The Street Group Technical Test +repo_url: https://github.com/dtomlinson91/street_group_tech_test +use_directory_urls: false +nav: + - Documentation: + - Welcome: index.md + # - Installation: documentation/installation.md + # - Usage: documentation/usage.md + # - Comments and Caveats: + # - Introduction: comments_caveats/introduction.md + # - Time limit: comments_caveats/time_limit.md + # - Third party libraries: comments_caveats/third_party_libraries.md + # - Areas of improvement and comments: comments_caveats/area_of_improvement_comments.md + # - Similar names algorithm: comments_caveats/similar_names.md + # - Reference: + # - deduplicator.main: reference/api_documentation_main.md + # - Changelog: changelog/changelog.md +theme: + name: material + palette: + primary: indigo + accent: blue + feature: + tabs: true +markdown_extensions: + - admonition + - codehilite: + guess_lang: true + - toc: + permalink: true + - pymdownx.superfences + # - pymdownx.arithmatex: + # generic: true +plugins: + - search: + lang: en +extra_javascript: + - javascripts/config.js + - https://polyfill.io/v3/polyfill.min.js?features=es6 + - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js diff --git a/poetry.lock b/poetry.lock index fc34624..7e7231e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -132,11 +132,23 @@ python-versions = ">=3.5.0" [package.extras] unicode_backport = ["unicodedata2"] +[[package]] +name = "click" +version = "8.0.1" +description = "Composable command line interface toolkit" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} + [[package]] name = "colorama" version = "0.4.4" description = "Cross-platform colored terminal text." -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" @@ -244,6 +256,20 @@ category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +[[package]] +name = "ghp-import" +version = "2.0.1" +description = "Copy your docs directly to the gh-pages branch." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +python-dateutil = ">=2.8.1" + +[package.extras] +dev = ["twine", "markdown", "flake8"] + [[package]] name = "google-api-core" version = "1.31.2" @@ -596,7 +622,7 @@ six = "*" name = "importlib-metadata" version = "4.8.1" description = "Read metadata from Python packages" -category = "dev" +category = "main" optional = false python-versions = ">=3.6" @@ -627,7 +653,7 @@ plugins = ["setuptools"] name = "jinja2" version = "3.0.1" description = "A very fast and expressive template engine." -category = "dev" +category = "main" optional = false python-versions = ">=3.6" @@ -661,11 +687,25 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +[[package]] +name = "markdown" +version = "3.3.4" +description = "Python implementation of Markdown." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} + +[package.extras] +testing = ["coverage", "pyyaml"] + [[package]] name = "markupsafe" version = "2.0.1" description = "Safely add untrusted strings to HTML/XML markup." -category = "dev" +category = "main" optional = false python-versions = ">=3.6" @@ -693,6 +733,14 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "mergedeep" +version = "1.3.4" +description = "A deep merge function for 🐍." +category = "main" +optional = false +python-versions = ">=3.6" + [[package]] name = "missingno" version = "0.5.0" @@ -710,6 +758,52 @@ seaborn = "*" [package.extras] tests = ["pytest", "pytest-mpl"] +[[package]] +name = "mkdocs" +version = "1.2.2" +description = "Project documentation with Markdown." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +click = ">=3.3" +ghp-import = ">=1.0" +importlib-metadata = ">=3.10" +Jinja2 = ">=2.10.1" +Markdown = ">=3.2.1" +mergedeep = ">=1.3.4" +packaging = ">=20.5" +PyYAML = ">=3.10" +pyyaml-env-tag = ">=0.1" +watchdog = ">=2.0" + +[package.extras] +i18n = ["babel (>=2.9.0)"] + +[[package]] +name = "mkdocs-material" +version = "7.3.0" +description = "A Material Design theme for MkDocs" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +markdown = ">=3.2" +mkdocs = ">=1.2.2" +mkdocs-material-extensions = ">=1.0" +Pygments = ">=2.4" +pymdown-extensions = ">=7.0" + +[[package]] +name = "mkdocs-material-extensions" +version = "1.0.3" +description = "Extension pack for Python Markdown." +category = "main" +optional = false +python-versions = ">=3.6" + [[package]] name = "multimethod" version = "1.4" @@ -1013,6 +1107,14 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +[[package]] +name = "pygments" +version = "2.10.0" +description = "Pygments is a syntax highlighting package written in Python." +category = "main" +optional = false +python-versions = ">=3.5" + [[package]] name = "pylint" version = "2.10.2" @@ -1080,6 +1182,17 @@ python-versions = "*" [package.dependencies] pylint = ">=1.7" +[[package]] +name = "pymdown-extensions" +version = "8.2" +description = "Extension pack for Python Markdown." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +Markdown = ">=3.2" + [[package]] name = "pymongo" version = "3.12.0" @@ -1140,10 +1253,21 @@ numpy = ">=1.13.3" name = "pyyaml" version = "5.4.1" description = "YAML parser and emitter for Python" -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +[[package]] +name = "pyyaml-env-tag" +version = "0.1" +description = "A custom YAML tag for referencing environment variables in YAML files. " +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pyyaml = "*" + [[package]] name = "requests" version = "2.26.0" @@ -1324,6 +1448,17 @@ test = ["matplotlib", "imagehash", "pillow", "shapely", "mypy (>=0.800)", "black type_geometry = ["shapely"] type_image_path = ["imagehash", "pillow"] +[[package]] +name = "watchdog" +version = "2.1.5" +description = "Filesystem events monitoring" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +watchmedo = ["PyYAML (>=3.10)", "argh (>=0.24.1)"] + [[package]] name = "wrapt" version = "1.12.1" @@ -1336,7 +1471,7 @@ python-versions = "*" name = "zipp" version = "3.5.0" description = "Backport of pathlib-compatible object wrapper for zip files" -category = "dev" +category = "main" optional = false python-versions = ">=3.6" @@ -1347,7 +1482,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytes [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "a4abffb384d330caa6dc399968726f1f73ea5fd7df5aa7010c1ea3bac4156338" +content-hash = "c9292b385b6067c194a7e31bc62ea4c04c99b951d3f4fa1b9b8f081ddf270c4c" [metadata.files] apache-beam = [ @@ -1403,6 +1538,10 @@ charset-normalizer = [ {file = "charset-normalizer-2.0.6.tar.gz", hash = "sha256:5ec46d183433dcbd0ab716f2d7f29d8dee50505b3fdb40c6b985c7c4f5a3591f"}, {file = "charset_normalizer-2.0.6-py3-none-any.whl", hash = "sha256:5d209c0a931f215cee683b6445e2d77677e7e75e159f78def0db09d68fafcaa6"}, ] +click = [ + {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"}, + {file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"}, +] colorama = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, @@ -1461,6 +1600,9 @@ flake8-polyfill = [ future = [ {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, ] +ghp-import = [ + {file = "ghp-import-2.0.1.tar.gz", hash = "sha256:753de2eace6e0f7d4edfb3cce5e3c3b98cd52aadb80163303d1d036bda7b4483"}, +] google-api-core = [ {file = "google-api-core-1.31.2.tar.gz", hash = "sha256:8500aded318fdb235130bf183c726a05a9cb7c4b09c266bd5119b86cdb8a4d10"}, {file = "google_api_core-1.31.2-py2.py3-none-any.whl", hash = "sha256:384459a0dc98c1c8cd90b28dc5800b8705e0275a673a7144a513ae80fc77950b"}, @@ -1727,6 +1869,10 @@ lazy-object-proxy = [ {file = "lazy_object_proxy-1.6.0-cp39-cp39-win32.whl", hash = "sha256:1fee665d2638491f4d6e55bd483e15ef21f6c8c2095f235fef72601021e64f61"}, {file = "lazy_object_proxy-1.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b"}, ] +markdown = [ + {file = "Markdown-3.3.4-py3-none-any.whl", hash = "sha256:96c3ba1261de2f7547b46a00ea8463832c921d3f9d6aba3f255a6f71386db20c"}, + {file = "Markdown-3.3.4.tar.gz", hash = "sha256:31b5b491868dcc87d6c24b7e3d19a0d730d59d3e46f4eea6430a321bed387a49"}, +] markupsafe = [ {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"}, @@ -1810,9 +1956,25 @@ mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] +mergedeep = [ + {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, + {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, +] missingno = [ {file = "missingno-0.5.0-py3-none-any.whl", hash = "sha256:888736337b5d18302ca9c1a970cb7e037f4b5085eb013390df2b0669c800642a"}, ] +mkdocs = [ + {file = "mkdocs-1.2.2-py3-none-any.whl", hash = "sha256:d019ff8e17ec746afeb54eb9eb4112b5e959597aebc971da46a5c9486137f0ff"}, + {file = "mkdocs-1.2.2.tar.gz", hash = "sha256:a334f5bd98ec960638511366eb8c5abc9c99b9083a0ed2401d8791b112d6b078"}, +] +mkdocs-material = [ + {file = "mkdocs-material-7.3.0.tar.gz", hash = "sha256:07db0580fa96c3473aee99ec3fb4606a1a5a1e4f4467e64c0cd1ba8da5b6476e"}, + {file = "mkdocs_material-7.3.0-py2.py3-none-any.whl", hash = "sha256:b183c27dc0f44e631bbc32c51057f61a3e2ba8b3c1080e59f944167eeba9ff1d"}, +] +mkdocs-material-extensions = [ + {file = "mkdocs-material-extensions-1.0.3.tar.gz", hash = "sha256:bfd24dfdef7b41c312ede42648f9eb83476ea168ec163b613f9abd12bbfddba2"}, + {file = "mkdocs_material_extensions-1.0.3-py3-none-any.whl", hash = "sha256:a82b70e533ce060b2a5d9eb2bc2e1be201cf61f901f93704b4acf6e3d5983a44"}, +] multimethod = [ {file = "multimethod-1.4-py2.py3-none-any.whl", hash = "sha256:2746500793c64cbd84a6ccda0043f4b58af3fcf8d6cd44b2232d5b9455b31d73"}, {file = "multimethod-1.4.tar.gz", hash = "sha256:8b315d6c965a797899a699913cdc391ded51dca22db5d11bda3399ce24ffed76"}, @@ -2122,6 +2284,10 @@ pyflakes = [ {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, ] +pygments = [ + {file = "Pygments-2.10.0-py3-none-any.whl", hash = "sha256:b8e67fe6af78f492b3c4b3e2970c0624cbf08beb1e493b2c99b9fa1b67a20380"}, + {file = "Pygments-2.10.0.tar.gz", hash = "sha256:f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6"}, +] pylint = [ {file = "pylint-2.10.2-py3-none-any.whl", hash = "sha256:e178e96b6ba171f8ef51fbce9ca30931e6acbea4a155074d80cc081596c9e852"}, {file = "pylint-2.10.2.tar.gz", hash = "sha256:6758cce3ddbab60c52b57dcc07f0c5d779e5daf0cf50f6faacbef1d3ea62d2a1"}, @@ -2140,6 +2306,10 @@ pylint-plugin-utils = [ {file = "pylint-plugin-utils-0.6.tar.gz", hash = "sha256:57625dcca20140f43731311cd8fd879318bf45a8b0fd17020717a8781714a25a"}, {file = "pylint_plugin_utils-0.6-py3-none-any.whl", hash = "sha256:2f30510e1c46edf268d3a195b2849bd98a1b9433229bb2ba63b8d776e1fc4d0a"}, ] +pymdown-extensions = [ + {file = "pymdown-extensions-8.2.tar.gz", hash = "sha256:b6daa94aad9e1310f9c64c8b1f01e4ce82937ab7eb53bfc92876a97aca02a6f4"}, + {file = "pymdown_extensions-8.2-py3-none-any.whl", hash = "sha256:141452d8ed61165518f2c923454bf054866b85cf466feedb0eb68f04acdc2560"}, +] pymongo = [ {file = "pymongo-3.12.0-cp27-cp27m-macosx_10_14_intel.whl", hash = "sha256:072ba7cb65c8aa4d5c5659bf6722ee85781c9d7816dc00679b8b6f3dff1ddafc"}, {file = "pymongo-3.12.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:d6e11ffd43184d529d6752d6dcb62b994f903038a17ea2168ef1910c96324d26"}, @@ -2315,6 +2485,10 @@ pyyaml = [ {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, ] +pyyaml-env-tag = [ + {file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"}, + {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"}, +] requests = [ {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"}, {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"}, @@ -2420,6 +2594,31 @@ visions = [ {file = "visions-0.7.1-py3-none-any.whl", hash = "sha256:138f45b007f5a58b8faa92f4d288e0da265e6ebf88ca6a5ec655922ab8fb95da"}, {file = "visions-0.7.1.tar.gz", hash = "sha256:d9d10a0da8de80d0704c28c084282abbd3273065cd9e6a494b6fe7e3b339ee23"}, ] +watchdog = [ + {file = "watchdog-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5f57ce4f7e498278fb2a091f39359930144a0f2f90ea8cbf4523c4e25de34028"}, + {file = "watchdog-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8b74d0d92a69a7ab5f101f9fe74e44ba017be269efa824337366ccbb4effde85"}, + {file = "watchdog-2.1.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:59767f476cd1f48531bf378f0300565d879688c82da8369ca8c52f633299523c"}, + {file = "watchdog-2.1.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:814d396859c95598f7576d15bc257c3bd3ba61fa4bc1db7dfc18f09070ded7da"}, + {file = "watchdog-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:28777dbed3bbd95f9c70f461443990a36c07dbf49ae7cd69932cdd1b8fb2850c"}, + {file = "watchdog-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5cf78f794c9d7bc64a626ef4f71aff88f57a7ae288e0b359a9c6ea711a41395f"}, + {file = "watchdog-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:43bf728eb7830559f329864ab5da2302c15b2efbac24ad84ccc09949ba753c40"}, + {file = "watchdog-2.1.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a7053d4d22dc95c5e0c90aeeae1e4ed5269d2f04001798eec43a654a03008d22"}, + {file = "watchdog-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6f3ad1d973fe8fc8fe64ba38f6a934b74346342fa98ef08ad5da361a05d46044"}, + {file = "watchdog-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:41d44ef21a77a32b55ce9bf59b75777063751f688de51098859b7c7f6466589a"}, + {file = "watchdog-2.1.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ed4ca4351cd2bb0d863ee737a2011ca44d8d8be19b43509bd4507f8a449b376b"}, + {file = "watchdog-2.1.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8874d5ad6b7f43b18935d9b0183e29727a623a216693d6938d07dfd411ba462f"}, + {file = "watchdog-2.1.5-py3-none-manylinux2014_aarch64.whl", hash = "sha256:50a7f81f99d238f72185f481b493f9de80096e046935b60ea78e1276f3d76960"}, + {file = "watchdog-2.1.5-py3-none-manylinux2014_armv7l.whl", hash = "sha256:e40e33a4889382824846b4baa05634e1365b47c6fa40071dc2d06b4d7c715fc1"}, + {file = "watchdog-2.1.5-py3-none-manylinux2014_i686.whl", hash = "sha256:78b1514067ff4089f4dac930b043a142997a5b98553120919005e97fbaba6546"}, + {file = "watchdog-2.1.5-py3-none-manylinux2014_ppc64.whl", hash = "sha256:58ae842300cbfe5e62fb068c83901abe76e4f413234b7bec5446e4275eb1f9cb"}, + {file = "watchdog-2.1.5-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:b0cc7d8b7d60da6c313779d85903ce39a63d89d866014b085f720a083d5f3e9a"}, + {file = "watchdog-2.1.5-py3-none-manylinux2014_s390x.whl", hash = "sha256:e60d3bb7166b7cb830b86938d1eb0e6cfe23dfd634cce05c128f8f9967895193"}, + {file = "watchdog-2.1.5-py3-none-manylinux2014_x86_64.whl", hash = "sha256:51af09ae937ada0e9a10cc16988ec03c649754a91526170b6839b89fc56d6acb"}, + {file = "watchdog-2.1.5-py3-none-win32.whl", hash = "sha256:9391003635aa783957b9b11175d9802d3272ed67e69ef2e3394c0b6d9d24fa9a"}, + {file = "watchdog-2.1.5-py3-none-win_amd64.whl", hash = "sha256:eab14adfc417c2c983fbcb2c73ef3f28ba6990d1fff45d1180bf7e38bda0d98d"}, + {file = "watchdog-2.1.5-py3-none-win_ia64.whl", hash = "sha256:a2888a788893c4ef7e562861ec5433875b7915f930a5a7ed3d32c048158f1be5"}, + {file = "watchdog-2.1.5.tar.gz", hash = "sha256:5563b005907613430ef3d4aaac9c78600dd5704e84764cb6deda4b3d72807f09"}, +] wrapt = [ {file = "wrapt-1.12.1.tar.gz", hash = "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"}, ] diff --git a/pyproject.toml b/pyproject.toml index 10f4200..70e34d7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,6 +7,8 @@ authors = ["Daniel Tomlinson "] [tool.poetry.dependencies] python = "^3.7" apache-beam = {extras = ["gcp"], version = "^2.32.0"} +mkdocs = "^1.2.2" +mkdocs-material = "^7.3.0" [tool.poetry.dev-dependencies] # pytest = "^5.2" diff --git a/requirements-docs.txt b/requirements-docs.txt new file mode 100644 index 0000000..5f99f40 --- /dev/null +++ b/requirements-docs.txt @@ -0,0 +1,6 @@ +apache-beam==2.32.0; python_version >= "3.6" +avro-python3==1.9.2.1; python_version >= "3.6" +cachetools==4.2.2; python_version >= "3.6" and python_version < "4.0" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.6.0") +certifi==2021.5.30; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" +mkdocs-material==7.3.0 +mkdocs==1.2.2; python_version >= "3.6" From 7f9b7e4bfd2e40633da4534aa67877cd559b9499 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sun, 26 Sep 2021 06:03:55 +0100 Subject: [PATCH 26/63] moving inputs/outputs to use pathlib --- analyse_properties/data/__init__.py | 0 analyse_properties/data/input/__init__.py | 0 analyse_properties/data/output/__init__.py | 0 analyse_properties/main.py | 37 +++++++++------------- download_data.sh | 4 +-- 5 files changed, 17 insertions(+), 24 deletions(-) delete mode 100644 analyse_properties/data/__init__.py delete mode 100644 analyse_properties/data/input/__init__.py delete mode 100644 analyse_properties/data/output/__init__.py diff --git a/analyse_properties/data/__init__.py b/analyse_properties/data/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/analyse_properties/data/input/__init__.py b/analyse_properties/data/input/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/analyse_properties/data/output/__init__.py b/analyse_properties/data/output/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/analyse_properties/main.py b/analyse_properties/main.py index 95b8299..cf43f89 100644 --- a/analyse_properties/main.py +++ b/analyse_properties/main.py @@ -1,22 +1,13 @@ -import csv from datetime import datetime import hashlib -import io -from importlib import resources import itertools import pathlib import apache_beam as beam -from apache_beam.io import fileio # from analyse_properties.debug import DebugShowEmptyColumn, DebugShowColumnWithValueIn -def csv_reader(csv_file): - """Read in a csv file.""" - return csv.reader(io.TextIOWrapper(csv_file.open())) - - def slice_by_range(element, *ranges): """Slice a list with multiple ranges.""" return itertools.chain(*(itertools.islice(element, *r) for r in ranges)) @@ -214,22 +205,22 @@ class ConvertDataToDict(beam.DoFn): def main(): # Load in the data from a csv file. - csv_data = resources.path( - # "analyse_properties.data.input", - # "pp-monthly-update-new-version.csv" - "analyse_properties.data.input", "pp-complete.csv" + input_file = ( + pathlib.Path(__file__).parents[1] + / "data" + / "input" + / "pp-monthly-update-new-version.csv" ) with beam.Pipeline() as pipeline: # Load the data - with csv_data as csv_data_file: - # https://github.com/apache/beam/blob/v2.32.0/sdks/python/apache_beam/io/fileio_test.py#L155-L170 - load = ( - pipeline - | fileio.MatchFiles(str(csv_data_file)) - | fileio.ReadMatches() - | beam.FlatMap(csv_reader) - ) + load = ( + pipeline + | "Read input data" >> beam.io.ReadFromText(str(input_file)) + | "Split by ','" >> beam.Map(lambda element: element.split(",")) + | "Remove leading and trailing quotes" + >> beam.Map(lambda element: [el.strip('"') for el in element]) + ) # Clean the data by dropping unneeded rows. clean_drop = ( @@ -276,7 +267,9 @@ def main(): ) # Save the data to a .json file. - output_file = pathlib.Path(__file__).parent / "data" / "output" / "pp-complete" + output_file = ( + pathlib.Path(__file__).parents[1] / "data" / "output" / "pp-complete" + ) output = ( formatted | "Combine into one PCollection" >> beam.combiners.ToList() diff --git a/download_data.sh b/download_data.sh index d69c6e4..dc0fa7a 100755 --- a/download_data.sh +++ b/download_data.sh @@ -1,5 +1,5 @@ # Full data set -wget https://storage.googleapis.com/street-group-technical-test-dmot/pp-complete.csv -P analyse_properties/data/input +# wget https://storage.googleapis.com/street-group-technical-test-dmot/pp-complete.csv -P data/input # Monthly update data set -# wget https://storage.googleapis.com/street-group-technical-test-dmot/pp-monthly-update-new-version.csv -P analyse_properties/data/input +wget https://storage.googleapis.com/street-group-technical-test-dmot/pp-monthly-update-new-version.csv -P data/input From 62bd0196adf3a7b5cf29926fea8273ab70d050ac Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sun, 26 Sep 2021 06:11:42 +0100 Subject: [PATCH 27/63] removing shard_name_template from output file --- analyse_properties/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/analyse_properties/main.py b/analyse_properties/main.py index cf43f89..0053233 100644 --- a/analyse_properties/main.py +++ b/analyse_properties/main.py @@ -277,7 +277,6 @@ def main(): >> beam.io.WriteToText( file_path_prefix=str(output_file), file_name_suffix=".json", - shard_name_template="", ) ) From c4e81065b1ea57e126ef6d40041246cca2f84148 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sun, 26 Sep 2021 14:55:05 +0100 Subject: [PATCH 28/63] adding pyenv 3.7.9 --- .python-version | 1 + 1 file changed, 1 insertion(+) create mode 100644 .python-version diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..c77a7de --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.7.9 From b8a997084d767c09dc050213086f02326140754c Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sun, 26 Sep 2021 14:55:48 +0100 Subject: [PATCH 29/63] removing requirements.txt for documentation --- requirements-docs.txt | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 requirements-docs.txt diff --git a/requirements-docs.txt b/requirements-docs.txt deleted file mode 100644 index 5f99f40..0000000 --- a/requirements-docs.txt +++ /dev/null @@ -1,6 +0,0 @@ -apache-beam==2.32.0; python_version >= "3.6" -avro-python3==1.9.2.1; python_version >= "3.6" -cachetools==4.2.2; python_version >= "3.6" and python_version < "4.0" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.6.0") -certifi==2021.5.30; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" -mkdocs-material==7.3.0 -mkdocs==1.2.2; python_version >= "3.6" From 7f874fa6f6db8b25caadda738685fa78508817f5 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sun, 26 Sep 2021 14:56:01 +0100 Subject: [PATCH 30/63] updating README.md --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1f0f4ae..c308a39 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,9 @@ # street_group_tech_test -Technical Test for Street Group + +Technical Test for Street Group for Daniel Tomlinson. + +## Documentation + +Read the documentation on github pages for instructions around running the code and a discussion on the approach. + +https://dtomlinson91.github.io/street_group_tech_test/ From e6ec110d546b31c9d7778ed36386bf6dd3ccef94 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sun, 26 Sep 2021 14:56:53 +0100 Subject: [PATCH 31/63] updating download data script for new location in GCS --- download_data.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/download_data.sh b/download_data.sh index dc0fa7a..eb647da 100755 --- a/download_data.sh +++ b/download_data.sh @@ -1,5 +1,5 @@ # Full data set -# wget https://storage.googleapis.com/street-group-technical-test-dmot/pp-complete.csv -P data/input +# wget https://storage.googleapis.com/street-group-technical-test-dmot/input/pp-complete.csv -P data/input # Monthly update data set -wget https://storage.googleapis.com/street-group-technical-test-dmot/pp-monthly-update-new-version.csv -P data/input +wget https://storage.googleapis.com/street-group-technical-test-dmot/input/pp-monthly-update-new-version.csv -P data/input From 9f53c669752f9687114296dd37570cbccde0cfd0 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sun, 26 Sep 2021 15:57:00 +0100 Subject: [PATCH 32/63] adding latest beam pipeline code for dataflow --- analyse_properties/main.py | 49 ++++++++++++++++++++++++++++---------- notes/dataflow.md | 17 +++++++++++++ 2 files changed, 53 insertions(+), 13 deletions(-) create mode 100644 notes/dataflow.md diff --git a/analyse_properties/main.py b/analyse_properties/main.py index 0053233..c4f9df8 100644 --- a/analyse_properties/main.py +++ b/analyse_properties/main.py @@ -1,9 +1,12 @@ +import argparse from datetime import datetime import hashlib import itertools +import logging import pathlib import apache_beam as beam +from apache_beam.options.pipeline_options import PipelineOptions, SetupOptions # from analyse_properties.debug import DebugShowEmptyColumn, DebugShowColumnWithValueIn @@ -87,7 +90,7 @@ class DeduplicateByID(beam.DoFn): """ def process(self, element): - if len(element[1]) > 0: + if len(list(element[1])) > 0: deduplicated_element = (element[0], [element[1][0]]) yield deduplicated_element else: @@ -203,20 +206,42 @@ class ConvertDataToDict(beam.DoFn): yield json_object -def main(): - # Load in the data from a csv file. +def run(argv=None, save_main_session=True): + """Entrypoint and definition of the pipeline.""" + # Default input/output files input_file = ( pathlib.Path(__file__).parents[1] / "data" / "input" / "pp-monthly-update-new-version.csv" ) + output_file = ( + pathlib.Path(__file__).parents[1] + / "data" + / "output" + / "pp-monthly-update-new-version" + ) - with beam.Pipeline() as pipeline: + # Arguments + parser = argparse.ArgumentParser() + parser.add_argument( + "--input", dest="input", default=str(input_file), help="Input file." + ) + parser.add_argument( + "--output", dest="output", default=str(output_file), help="Output file." + ) + known_args, pipeline_args = parser.parse_known_args(argv) + + # Pipeline options. save_main_session needed for DataFlow for global imports. + pipeline_options = PipelineOptions(pipeline_args) + pipeline_options.view_as(SetupOptions).save_main_session = save_main_session + + # Load in the data from a csv file. + with beam.Pipeline(options=pipeline_options) as pipeline: # Load the data load = ( pipeline - | "Read input data" >> beam.io.ReadFromText(str(input_file)) + | "Read input data" >> beam.io.ReadFromText(known_args.input) | "Split by ','" >> beam.Map(lambda element: element.split(",")) | "Remove leading and trailing quotes" >> beam.Map(lambda element: [el.strip('"') for el in element]) @@ -248,8 +273,8 @@ def main(): | "Deduplicate by the ID for all columns" >> beam.ParDo(DeduplicateByID()) ) - # Prepare the data by generating an ID using the uniquely identifying information only - # and grouping them by this ID. + # Prepare the data by generating an ID using the uniquely identifying + # information only and grouping them by this ID. prepare = ( clean_deduplicate | "Remove previous unique ID" >> beam.ParDo(RemoveUniqueID()) @@ -267,19 +292,17 @@ def main(): ) # Save the data to a .json file. - output_file = ( - pathlib.Path(__file__).parents[1] / "data" / "output" / "pp-complete" - ) - output = ( + ( formatted | "Combine into one PCollection" >> beam.combiners.ToList() | "Save to .json file" >> beam.io.WriteToText( - file_path_prefix=str(output_file), + file_path_prefix=known_args.output, file_name_suffix=".json", ) ) if __name__ == "__main__": - main() + logging.getLogger().setLevel(logging.INFO) + run() diff --git a/notes/dataflow.md b/notes/dataflow.md new file mode 100644 index 0000000..54f16df --- /dev/null +++ b/notes/dataflow.md @@ -0,0 +1,17 @@ +# DataFlow + + + +Export env variable: + +`export GOOGLE_APPLICATION_CREDENTIALS="/home/dtomlinson/git-repos/work/street_group/street_group_tech_test/street-group-0c490d23a9d0.json"` + +Run the pipeline: + +python -m analyse_properties.main \ + --region europe-west2 \ + --input gs://street-group-technical-test-dmot/input/pp-monthly-update-new-version.csv \ + --output gs://street-group-technical-test-dmot/input/pp-monthly-update-new-version \ + --runner DataflowRunner \ + --project street-group \ + --temp_location gs://street-group-technical-test-dmot/tmp From 8047b5ced44c3bd0904a006275899694877901d0 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sun, 26 Sep 2021 16:16:58 +0100 Subject: [PATCH 33/63] adding latest beam pipeline code for dataflow --- analyse_properties/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analyse_properties/main.py b/analyse_properties/main.py index c4f9df8..f3c27f9 100644 --- a/analyse_properties/main.py +++ b/analyse_properties/main.py @@ -91,7 +91,7 @@ class DeduplicateByID(beam.DoFn): def process(self, element): if len(list(element[1])) > 0: - deduplicated_element = (element[0], [element[1][0]]) + deduplicated_element = list(list(element[0]), list([element[1][0]])) yield deduplicated_element else: yield element From bb71d55f8ca4d9339e50e3f4f1e6ef6fdd073adb Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sun, 26 Sep 2021 16:23:19 +0100 Subject: [PATCH 34/63] adding latest beam pipeline code for dataflow --- analyse_properties/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analyse_properties/main.py b/analyse_properties/main.py index f3c27f9..ac1c899 100644 --- a/analyse_properties/main.py +++ b/analyse_properties/main.py @@ -91,7 +91,7 @@ class DeduplicateByID(beam.DoFn): def process(self, element): if len(list(element[1])) > 0: - deduplicated_element = list(list(element[0]), list([element[1][0]])) + deduplicated_element = (list(element[0]), [list(element[1])[0]]) yield deduplicated_element else: yield element From fded8589327ea1d0dca9d3e389efbb383fc98ef7 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sun, 26 Sep 2021 17:15:17 +0100 Subject: [PATCH 35/63] moving dataflow notes --- notes/{ => documentation}/dataflow.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) rename notes/{ => documentation}/dataflow.md (69%) diff --git a/notes/dataflow.md b/notes/documentation/dataflow.md similarity index 69% rename from notes/dataflow.md rename to notes/documentation/dataflow.md index 54f16df..d0a82ea 100644 --- a/notes/dataflow.md +++ b/notes/documentation/dataflow.md @@ -11,7 +11,14 @@ Run the pipeline: python -m analyse_properties.main \ --region europe-west2 \ --input gs://street-group-technical-test-dmot/input/pp-monthly-update-new-version.csv \ - --output gs://street-group-technical-test-dmot/input/pp-monthly-update-new-version \ + --output gs://street-group-technical-test-dmot/output/pp-monthly-update-new-version \ --runner DataflowRunner \ --project street-group \ --temp_location gs://street-group-technical-test-dmot/tmp + + +## Errors + +Unsubscriptable error on window: + + From 8856a9763f8ce39b0294291263c119b89f1288d7 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sun, 26 Sep 2021 17:15:24 +0100 Subject: [PATCH 36/63] updating prospector.yaml --- prospector.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/prospector.yaml b/prospector.yaml index 86f9e76..190f1a2 100644 --- a/prospector.yaml +++ b/prospector.yaml @@ -20,6 +20,7 @@ pylint: - super-init-not-called - arguments-differ - inconsistent-return-statements + - expression-not-assigned enable: options: From 4e3771c72832068ada1a163acecffeecd84b904d Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sun, 26 Sep 2021 17:15:35 +0100 Subject: [PATCH 37/63] adding latest beam pipeline code for dataflow --- analyse_properties/main.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/analyse_properties/main.py b/analyse_properties/main.py index ac1c899..6c86ddb 100644 --- a/analyse_properties/main.py +++ b/analyse_properties/main.py @@ -170,15 +170,15 @@ class ConvertDataToDict(beam.DoFn): json_object = { "property_id": element[0], "readable_address": None, - "flat_appartment": element[-1][0][4], - "builing": element[-1][0][10], - "number": element[-1][0][3], - "street": element[-1][0][5], - "locality": element[-1][0][6], - "town": element[-1][0][7], - "district": element[-1][0][8], - "county": element[-1][0][9], - "postcode": element[-1][0][2], + "flat_appartment": list(element[-1])[0][4], + "builing": list(element[-1])[0][10], + "number": list(element[-1])[0][3], + "street": list(element[-1])[0][5], + "locality": list(element[-1])[0][6], + "town": list(element[-1])[0][7], + "district": list(element[-1])[0][8], + "county": list(element[-1])[0][9], + "postcode": list(element[-1])[0][2], "property_transactions": property_transactions, "latest_transaction_year": self.get_latest_transaction( [ From 8e8469579e7b9166505ca4aec66b423f9ad4be8f Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sun, 26 Sep 2021 20:29:11 +0100 Subject: [PATCH 38/63] updating beam pipeline to use GroupByKey --- analyse_properties/main.py | 73 +++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 25 deletions(-) diff --git a/analyse_properties/main.py b/analyse_properties/main.py index 6c86ddb..6a190de 100644 --- a/analyse_properties/main.py +++ b/analyse_properties/main.py @@ -2,6 +2,7 @@ import argparse from datetime import datetime import hashlib import itertools +import json import logging import pathlib @@ -12,17 +13,37 @@ from apache_beam.options.pipeline_options import PipelineOptions, SetupOptions def slice_by_range(element, *ranges): - """Slice a list with multiple ranges.""" + """ + Slice a list with multiple ranges. + + Args: + element : The element. + *ranges (tuple): Tuples containing a start,end index to slice the element. + E.g (0, 3), (5, 6) - Keeps columns 0,1,2,5. Drops everything else. + + Returns: + list: The list sliced by the ranges + """ return itertools.chain(*(itertools.islice(element, *r) for r in ranges)) class DropRecordsSingleEmptyColumn(beam.DoFn): - """If a given item in a list is empty, drop this entry from the PCollection.""" - def __init__(self, index): self.index = index def process(self, element): + """ + Drop the entire row if a given column is empty. + + Args: + element : The element + + Returns: + None: If the length of the column is 0, drop the element. + + Yields: + element: If the length of the column isn't 0, keep the element. + """ column = element[self.index] if len(column) == 0: return None @@ -78,9 +99,9 @@ class GenerateUniqueID(beam.DoFn): ",".join(element[2:]) if not self.all_columns else ",".join(element) ) hashed_string = hashlib.md5(unique_string.encode()) - # append the hash to the end - element.append(hashed_string.hexdigest()) - yield element + # add the hash as a key to the data. + new_element = (hashed_string.hexdigest(), list(element)) + yield new_element class DeduplicateByID(beam.DoFn): @@ -91,7 +112,7 @@ class DeduplicateByID(beam.DoFn): def process(self, element): if len(list(element[1])) > 0: - deduplicated_element = (list(element[0]), [list(element[1])[0]]) + deduplicated_element = (element[0], [list(element[1])[0]]) yield deduplicated_element else: yield element @@ -102,7 +123,6 @@ class RemoveUniqueID(beam.DoFn): def process(self, element): element_no_id = element[-1][0] - element_no_id.pop(-1) yield element_no_id @@ -169,7 +189,7 @@ class ConvertDataToDict(beam.DoFn): # Create the dict to hold all the information about the property. json_object = { "property_id": element[0], - "readable_address": None, + # "readable_address": None, "flat_appartment": list(element[-1])[0][4], "builing": list(element[-1])[0][10], "number": list(element[-1])[0][3], @@ -189,20 +209,20 @@ class ConvertDataToDict(beam.DoFn): } # Create a human readable address to go in the dict. - json_object["readable_address"] = self.get_readable_address( - [ - json_object["flat_appartment"], - json_object["builing"], - f'{json_object["number"]} {json_object["street"]}', - json_object["postcode"], - ], - [ - json_object["locality"], - json_object["town"], - json_object["district"], - json_object["county"], - ], - ) + # json_object["readable_address"] = self.get_readable_address( + # [ + # json_object["flat_appartment"], + # json_object["builing"], + # f'{json_object["number"]} {json_object["street"]}', + # json_object["postcode"], + # ], + # [ + # json_object["locality"], + # json_object["town"], + # json_object["district"], + # json_object["county"], + # ], + # ) yield json_object @@ -259,6 +279,7 @@ def run(argv=None, save_main_session=True): | "Drop Empty Postcodes" >> beam.ParDo(DropRecordsSingleEmptyColumn(2)) | "Drop empty PAON if missing SAON" >> beam.ParDo(DropRecordsTwoEmptyColumn(3, 4)) + # | beam.ParDo(DebugShowColumnWithValueIn(2, "B16 0AE")) | "Split PAON into two columns if separated by comma" >> beam.ParDo(SplitColumn(3, ",")) ) @@ -269,7 +290,7 @@ def run(argv=None, save_main_session=True): | "Generate unique ID for all columns" >> beam.ParDo(GenerateUniqueID(all_columns=True)) | "Group by the ID for all columns" - >> beam.GroupBy(lambda element: element[-1]) + >> beam.GroupByKey() | "Deduplicate by the ID for all columns" >> beam.ParDo(DeduplicateByID()) ) @@ -281,7 +302,8 @@ def run(argv=None, save_main_session=True): | "Generate unique ID ignoring price & date" >> beam.ParDo(GenerateUniqueID()) | "Group by the ID ignoring price & date" - >> beam.GroupBy(lambda element: element[-1]) + >> beam.GroupByKey() + # | beam.Map(print) ) # Format the data into a dict. @@ -295,6 +317,7 @@ def run(argv=None, save_main_session=True): ( formatted | "Combine into one PCollection" >> beam.combiners.ToList() + | "Format output" >> beam.Map(json.dumps) | "Save to .json file" >> beam.io.WriteToText( file_path_prefix=known_args.output, From 99e67c2840d4a3382c1912d82ce539ba1f35c4ed Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sun, 26 Sep 2021 23:28:12 +0100 Subject: [PATCH 39/63] updating download_data script with new bucket --- download_data.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/download_data.sh b/download_data.sh index eb647da..d179f9b 100755 --- a/download_data.sh +++ b/download_data.sh @@ -1,5 +1,5 @@ # Full data set -# wget https://storage.googleapis.com/street-group-technical-test-dmot/input/pp-complete.csv -P data/input +# wget https://storage.googleapis.com/street-group-technical-test-dmot-euw1/input/pp-complete.csv -P data/input # Monthly update data set -wget https://storage.googleapis.com/street-group-technical-test-dmot/input/pp-monthly-update-new-version.csv -P data/input +wget https://storage.googleapis.com/street-group-technical-test-dmot-euw1/input/pp-monthly-update-new-version.csv -P data/input From 1941fcb7bf9eded77bab1700e1e863465ba534bd Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sun, 26 Sep 2021 23:28:21 +0100 Subject: [PATCH 40/63] update prospector.yaml --- prospector.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/prospector.yaml b/prospector.yaml index 190f1a2..ead732e 100644 --- a/prospector.yaml +++ b/prospector.yaml @@ -21,6 +21,7 @@ pylint: - arguments-differ - inconsistent-return-statements - expression-not-assigned + - line-too-long enable: options: From eaa36877f69e560c8a25a77a13bc6faeb25a9f86 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sun, 26 Sep 2021 23:28:35 +0100 Subject: [PATCH 41/63] update dataflow documentation with new commands for vpc --- notes/documentation/dataflow.md | 52 +++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/notes/documentation/dataflow.md b/notes/documentation/dataflow.md index d0a82ea..fd483e4 100644 --- a/notes/documentation/dataflow.md +++ b/notes/documentation/dataflow.md @@ -2,23 +2,65 @@ +## Examples + +Full example of beam pipeline on dataflow: + + + +## Setup + Export env variable: `export GOOGLE_APPLICATION_CREDENTIALS="/home/dtomlinson/git-repos/work/street_group/street_group_tech_test/street-group-0c490d23a9d0.json"` -Run the pipeline: +## Run pipeline +### Dataflow + +#### Monthly dataset + +```bash python -m analyse_properties.main \ - --region europe-west2 \ - --input gs://street-group-technical-test-dmot/input/pp-monthly-update-new-version.csv \ - --output gs://street-group-technical-test-dmot/output/pp-monthly-update-new-version \ + --region europe-west1 \ + --input gs://street-group-technical-test-dmot-euw1/input/pp-monthly-update-new-version.csv \ + --output gs://street-group-technical-test-dmot-euw1/output/pp-monthly-update-new-version \ --runner DataflowRunner \ --project street-group \ - --temp_location gs://street-group-technical-test-dmot/tmp + --temp_location gs://street-group-technical-test-dmot-euw1/tmp \ + --subnetwork=https://www.googleapis.com/compute/v1/projects/street-group/regions/europe-west1/subnetworks/europe-west-1-dataflow \ + --no_use_public_ips +``` +#### Full dataset + +```bash +python -m analyse_properties.main \ + --region europe-west1 \ + --input gs://street-group-technical-test-dmot-euw1/input/pp-complete.csv \ + --output gs://street-group-technical-test-dmot-euw1/output/pp-complete \ + --runner DataflowRunner \ + --project street-group \ + --temp_location gs://street-group-technical-test-dmot-euw1/tmp \ + --subnetwork=https://www.googleapis.com/compute/v1/projects/street-group/regions/europe-west1/subnetworks/europe-west-1-dataflow \ + --no_use_public_ips +``` + +### Locally + +Run the pipeline locally: + +`python -m analyse_properties.main --runner DirectRunner` ## Errors Unsubscriptable error on window: + +## Documentation + +Running in its own private VPC without public IPs + +- +- From a8fc06c7643056d578af67cf376a76a05485b48f Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Sun, 26 Sep 2021 23:28:58 +0100 Subject: [PATCH 42/63] adding latest beam pipeline code for dataflow with group optimisation --- analyse_properties/main.py | 112 ++++++++++++++++++++++++++++++------- 1 file changed, 92 insertions(+), 20 deletions(-) diff --git a/analyse_properties/main.py b/analyse_properties/main.py index 6a190de..702c977 100644 --- a/analyse_properties/main.py +++ b/analyse_properties/main.py @@ -85,7 +85,7 @@ class SplitColumn(beam.DoFn): yield element -class GenerateUniqueID(beam.DoFn): +class CreateMappingTable(beam.DoFn): """ Generate a unique ID for the PCollection, either for all the columns or for the uniquely identifying data only. @@ -104,6 +104,49 @@ class GenerateUniqueID(beam.DoFn): yield new_element +# class CreateMappingTable(beam.DoFn): +# def process(self, element): +# unique_string = ",".join(element) +# hashed_string = hashlib.md5(unique_string.encode()) +# new_element = {hashed_string.hexdigest(): list(element)} +# yield new_element + + +class CreateUniquePropertyID(beam.DoFn): + def process(self, element): + unique_string = ",".join(element[-1][2:]) + hashed_string = hashlib.md5(unique_string.encode()) + new_element = (hashed_string.hexdigest(), element[0]) + yield new_element + + +class DeduplicateIDs(beam.DoFn): + def process(self, element): + deduplicated_list = list(set(element[-1])) + new_element = (element[0], deduplicated_list) + yield new_element + + +# class InsertDataForID(beam.DoFn): +# def __init__(self, mapping_table): +# self.mapping_table = mapping_table + +# def process(self, element): +# replaced_list = [self.mapping_table[x] for x in element[-1]] +# new_element = (element[0], replaced_list) +# yield new_element + + +def insert_data_for_id(element, mapping_table): + replaced_list = [] + for data_id in element[-1]: + replaced_list.append(mapping_table[data_id]) + # replaced_list = [mapping_table[x] for x in element[-1]] + new_element = (element[0], replaced_list) + yield new_element + + +# old class DeduplicateByID(beam.DoFn): """ If the PCollection has multiple entries after being grouped by ID for all columns, @@ -280,37 +323,66 @@ def run(argv=None, save_main_session=True): | "Drop empty PAON if missing SAON" >> beam.ParDo(DropRecordsTwoEmptyColumn(3, 4)) # | beam.ParDo(DebugShowColumnWithValueIn(2, "B16 0AE")) + # | beam.ParDo(DebugShowColumnWithValueIn(2, "B90 3LA")) | "Split PAON into two columns if separated by comma" >> beam.ParDo(SplitColumn(3, ",")) ) - # Clean the data by creating an ID, and deduplicating to eliminate repeated rows. - clean_deduplicate = ( - clean_drop - | "Generate unique ID for all columns" - >> beam.ParDo(GenerateUniqueID(all_columns=True)) - | "Group by the ID for all columns" - >> beam.GroupByKey() - | "Deduplicate by the ID for all columns" >> beam.ParDo(DeduplicateByID()) - ) + # # Clean the data by creating an ID, and deduplicating to eliminate repeated rows. + # clean_deduplicate = ( + # clean_drop + # | "Generate ID using all columns" + # >> beam.ParDo(GenerateUniqueID(all_columns=True)) + # | "Group by the ID for all columns" >> beam.GroupByKey() + # | "Deduplicate by the ID for all columns" >> beam.ParDo(DeduplicateByID()) + # ) - # Prepare the data by generating an ID using the uniquely identifying - # information only and grouping them by this ID. - prepare = ( - clean_deduplicate - | "Remove previous unique ID" >> beam.ParDo(RemoveUniqueID()) - | "Generate unique ID ignoring price & date" - >> beam.ParDo(GenerateUniqueID()) - | "Group by the ID ignoring price & date" - >> beam.GroupByKey() + # Create a mapping table + mapping_table_raw = ( + clean_drop + | "Create a mapping table with key of id_all_columns and value of cleaned data." + >> beam.ParDo(CreateMappingTable(all_columns=True)) # | beam.Map(print) ) + mapping_table_condensed = ( + mapping_table_raw + | "Condense mapping table into single dict" >> beam.combiners.ToDict() + # | beam.Map(print) + ) + + prepared = ( + mapping_table_raw + | "Create unique ID ignoring price & date" + >> beam.ParDo(CreateUniquePropertyID()) + | "Group IDs using all columns by IDs ignoring price & date" + >> beam.GroupByKey() + | "Deduplicate to eliminate repeated transactions" + >> beam.ParDo(DeduplicateIDs()) + | "Insert the raw data using the mapping table" + >> beam.FlatMap( + insert_data_for_id, beam.pvalue.AsSingleton(mapping_table_condensed) + ) + # | beam.Map(print) + ) + + # # Prepare the data by generating an ID using the uniquely identifying + # # information only and grouping them by this ID. + # prepare = ( + # clean_deduplicate + # | "Remove previous unique ID" >> beam.ParDo(RemoveUniqueID()) + # | "Generate unique ID ignoring price & date old" + # >> beam.ParDo(GenerateUniqueID()) + # | "Group by the ID ignoring price & date" >> beam.GroupByKey() + # # | beam.Map(print) + # ) + # Format the data into a dict. formatted = ( - prepare + prepared | "Convert the prepared data into a dict object" >> beam.ParDo(ConvertDataToDict()) + # | beam.Map(print) ) # Save the data to a .json file. From 377e3c703f214d2cafb443b38f07ae0d6c1f9b22 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Mon, 27 Sep 2021 01:35:48 +0100 Subject: [PATCH 43/63] updating dataflow documentation --- notes/documentation/dataflow.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/notes/documentation/dataflow.md b/notes/documentation/dataflow.md index fd483e4..63a6fa1 100644 --- a/notes/documentation/dataflow.md +++ b/notes/documentation/dataflow.md @@ -43,9 +43,14 @@ python -m analyse_properties.main \ --project street-group \ --temp_location gs://street-group-technical-test-dmot-euw1/tmp \ --subnetwork=https://www.googleapis.com/compute/v1/projects/street-group/regions/europe-west1/subnetworks/europe-west-1-dataflow \ - --no_use_public_ips + --no_use_public_ips \ + --worker_machine_type=n1-highmem-8 ``` + —-disk_size_gb=50 \ + + + ### Locally Run the pipeline locally: @@ -64,3 +69,17 @@ Running in its own private VPC without public IPs - - + +Error help + +- +- + +Scaling + +Using DataFlowPrime: +Use `--experiments=enable_prime` + +Deploying a pipeline (with scaling options): + +Available VM types (with pricing): From 3a745794402a6fc963dc8fdc2f672e1608685898 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Mon, 27 Sep 2021 03:18:17 +0100 Subject: [PATCH 44/63] adding latest beam pipeline code for dataflow with group optimisation --- analyse_properties/main.py | 172 ++++++++++++++----------------------- 1 file changed, 65 insertions(+), 107 deletions(-) diff --git a/analyse_properties/main.py b/analyse_properties/main.py index 702c977..241f3f7 100644 --- a/analyse_properties/main.py +++ b/analyse_properties/main.py @@ -9,8 +9,6 @@ import pathlib import apache_beam as beam from apache_beam.options.pipeline_options import PipelineOptions, SetupOptions -# from analyse_properties.debug import DebugShowEmptyColumn, DebugShowColumnWithValueIn - def slice_by_range(element, *ranges): """ @@ -28,22 +26,23 @@ def slice_by_range(element, *ranges): class DropRecordsSingleEmptyColumn(beam.DoFn): + """ + Drop the entire row if a given column is empty. + + Args: + index : The index of the column in the list. + + Returns: + None: If the length of the column is 0, drop the element. + + Yields: + element: If the length of the column isn't 0, keep the element. + """ + def __init__(self, index): self.index = index def process(self, element): - """ - Drop the entire row if a given column is empty. - - Args: - element : The element - - Returns: - None: If the length of the column is 0, drop the element. - - Yields: - element: If the length of the column isn't 0, keep the element. - """ column = element[self.index] if len(column) == 0: return None @@ -51,7 +50,19 @@ class DropRecordsSingleEmptyColumn(beam.DoFn): class DropRecordsTwoEmptyColumn(beam.DoFn): - """If two given items in a list are both empty, drop this entry from the PCollection.""" + """ + Drop the entire row if both of two given columns are empty. + + Args: + index_0 : The index of the first column in the list. + index_1 : The index of the second column in the list. + + Returns: + None: If the length of both columns is 0, drop the element. + + Yields: + element: If the length of both columns isn't 0, keep the element. + """ def __init__(self, index_0, index_1): self.index_0 = index_0 @@ -66,7 +77,14 @@ class DropRecordsTwoEmptyColumn(beam.DoFn): class SplitColumn(beam.DoFn): - """Split an item in a list into two separate items in the PCollection.""" + """ + Split one column into two columns by a character. + + Args: + index : The index of the column in the list. + split_char: The character to split the column by. + + """ def __init__(self, index, split_char): self.index = index @@ -74,7 +92,7 @@ class SplitColumn(beam.DoFn): def process(self, element): # If there is a split based on the split_char, then keep the first result in - # place and append the second. + # place and append the second column at the end. try: part_0, part_1 = element[self.index].split(self.split_char) element[self.index] = part_1.strip() @@ -87,8 +105,16 @@ class SplitColumn(beam.DoFn): class CreateMappingTable(beam.DoFn): """ - Generate a unique ID for the PCollection, either for all the columns or for the - uniquely identifying data only. + Create a mapping table to be used as a side-input. + + This mapping table has a key of an id generated across all columns and a value of + the raw property data. + + The table is used to populate the raw property data after a GroupByKey which is done on ids only + in order to reduce the amount of data processed in the GroupByKey operation. + + Args: + all_columns """ def __init__(self, all_columns=False): @@ -104,14 +130,6 @@ class CreateMappingTable(beam.DoFn): yield new_element -# class CreateMappingTable(beam.DoFn): -# def process(self, element): -# unique_string = ",".join(element) -# hashed_string = hashlib.md5(unique_string.encode()) -# new_element = {hashed_string.hexdigest(): list(element)} -# yield new_element - - class CreateUniquePropertyID(beam.DoFn): def process(self, element): unique_string = ",".join(element[-1][2:]) @@ -127,48 +145,12 @@ class DeduplicateIDs(beam.DoFn): yield new_element -# class InsertDataForID(beam.DoFn): -# def __init__(self, mapping_table): -# self.mapping_table = mapping_table - -# def process(self, element): -# replaced_list = [self.mapping_table[x] for x in element[-1]] -# new_element = (element[0], replaced_list) -# yield new_element - - def insert_data_for_id(element, mapping_table): - replaced_list = [] - for data_id in element[-1]: - replaced_list.append(mapping_table[data_id]) - # replaced_list = [mapping_table[x] for x in element[-1]] + replaced_list = [mapping_table[data_id] for data_id in element[-1]] new_element = (element[0], replaced_list) yield new_element -# old -class DeduplicateByID(beam.DoFn): - """ - If the PCollection has multiple entries after being grouped by ID for all columns, - deduplicate the list to keep only one. - """ - - def process(self, element): - if len(list(element[1])) > 0: - deduplicated_element = (element[0], [list(element[1])[0]]) - yield deduplicated_element - else: - yield element - - -class RemoveUniqueID(beam.DoFn): - """Remove the unique ID from the PCollection, transforming it back into a list.""" - - def process(self, element): - element_no_id = element[-1][0] - yield element_no_id - - class ConvertDataToDict(beam.DoFn): """Convert the processed data into a dict to be exported as a JSON object.""" @@ -232,7 +214,7 @@ class ConvertDataToDict(beam.DoFn): # Create the dict to hold all the information about the property. json_object = { "property_id": element[0], - # "readable_address": None, + "readable_address": None, "flat_appartment": list(element[-1])[0][4], "builing": list(element[-1])[0][10], "number": list(element[-1])[0][3], @@ -252,20 +234,20 @@ class ConvertDataToDict(beam.DoFn): } # Create a human readable address to go in the dict. - # json_object["readable_address"] = self.get_readable_address( - # [ - # json_object["flat_appartment"], - # json_object["builing"], - # f'{json_object["number"]} {json_object["street"]}', - # json_object["postcode"], - # ], - # [ - # json_object["locality"], - # json_object["town"], - # json_object["district"], - # json_object["county"], - # ], - # ) + json_object["readable_address"] = self.get_readable_address( + [ + json_object["flat_appartment"], + json_object["builing"], + f'{json_object["number"]} {json_object["street"]}', + json_object["postcode"], + ], + [ + json_object["locality"], + json_object["town"], + json_object["district"], + json_object["county"], + ], + ) yield json_object @@ -276,13 +258,15 @@ def run(argv=None, save_main_session=True): pathlib.Path(__file__).parents[1] / "data" / "input" - / "pp-monthly-update-new-version.csv" + / "pp-2020.csv" + # / "pp-complete.csv" ) output_file = ( pathlib.Path(__file__).parents[1] / "data" / "output" - / "pp-monthly-update-new-version" + / "pp-2020" + # / "pp-complete" ) # Arguments @@ -322,33 +306,20 @@ def run(argv=None, save_main_session=True): | "Drop Empty Postcodes" >> beam.ParDo(DropRecordsSingleEmptyColumn(2)) | "Drop empty PAON if missing SAON" >> beam.ParDo(DropRecordsTwoEmptyColumn(3, 4)) - # | beam.ParDo(DebugShowColumnWithValueIn(2, "B16 0AE")) - # | beam.ParDo(DebugShowColumnWithValueIn(2, "B90 3LA")) | "Split PAON into two columns if separated by comma" >> beam.ParDo(SplitColumn(3, ",")) ) - # # Clean the data by creating an ID, and deduplicating to eliminate repeated rows. - # clean_deduplicate = ( - # clean_drop - # | "Generate ID using all columns" - # >> beam.ParDo(GenerateUniqueID(all_columns=True)) - # | "Group by the ID for all columns" >> beam.GroupByKey() - # | "Deduplicate by the ID for all columns" >> beam.ParDo(DeduplicateByID()) - # ) - # Create a mapping table mapping_table_raw = ( clean_drop | "Create a mapping table with key of id_all_columns and value of cleaned data." >> beam.ParDo(CreateMappingTable(all_columns=True)) - # | beam.Map(print) ) mapping_table_condensed = ( mapping_table_raw | "Condense mapping table into single dict" >> beam.combiners.ToDict() - # | beam.Map(print) ) prepared = ( @@ -363,26 +334,13 @@ def run(argv=None, save_main_session=True): >> beam.FlatMap( insert_data_for_id, beam.pvalue.AsSingleton(mapping_table_condensed) ) - # | beam.Map(print) ) - # # Prepare the data by generating an ID using the uniquely identifying - # # information only and grouping them by this ID. - # prepare = ( - # clean_deduplicate - # | "Remove previous unique ID" >> beam.ParDo(RemoveUniqueID()) - # | "Generate unique ID ignoring price & date old" - # >> beam.ParDo(GenerateUniqueID()) - # | "Group by the ID ignoring price & date" >> beam.GroupByKey() - # # | beam.Map(print) - # ) - # Format the data into a dict. formatted = ( prepared | "Convert the prepared data into a dict object" >> beam.ParDo(ConvertDataToDict()) - # | beam.Map(print) ) # Save the data to a .json file. From 7db1edb90c3c447218d5d25479064dbb006935d2 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Mon, 27 Sep 2021 03:18:33 +0100 Subject: [PATCH 45/63] updating download_data script with pp-2020 dataset --- download_data.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/download_data.sh b/download_data.sh index d179f9b..01d789a 100755 --- a/download_data.sh +++ b/download_data.sh @@ -2,4 +2,7 @@ # wget https://storage.googleapis.com/street-group-technical-test-dmot-euw1/input/pp-complete.csv -P data/input # Monthly update data set -wget https://storage.googleapis.com/street-group-technical-test-dmot-euw1/input/pp-monthly-update-new-version.csv -P data/input +# wget https://storage.googleapis.com/street-group-technical-test-dmot-euw1/input/pp-monthly-update-new-version.csv -P data/input + +# 2020 data set +wget https://storage.googleapis.com/street-group-technical-test-dmot-euw1/input/pp-2020.csv -P data/input From f2ed60426dba030bfbbb3e1a9ed14a0a0ed8cace Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Mon, 27 Sep 2021 03:18:42 +0100 Subject: [PATCH 46/63] adding temporary notes --- notes/tmp/errordata | 27 ++++++++++++++++++++++++++ notes/tmp/exampledata | 44 +++++++++++++++++++++++++++++++++++++++++++ notes/tmp/runningdata | 16 ++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 notes/tmp/errordata create mode 100644 notes/tmp/exampledata create mode 100644 notes/tmp/runningdata diff --git a/notes/tmp/errordata b/notes/tmp/errordata new file mode 100644 index 0000000..2df356d --- /dev/null +++ b/notes/tmp/errordata @@ -0,0 +1,27 @@ +"Error message from worker: Traceback (most recent call last): + File "/usr/local/lib/python3.7/site-packages/dataflow_worker/batchworker.py", line 651, in do_work + work_executor.execute() + File "/usr/local/lib/python3.7/site-packages/dataflow_worker/executor.py", line 181, in execute + op.finish() + File "dataflow_worker/native_operations.py", line 93, in dataflow_worker.native_operations.NativeWriteOperation.finish + File "dataflow_worker/native_operations.py", line 94, in dataflow_worker.native_operations.NativeWriteOperation.finish + File "dataflow_worker/native_operations.py", line 95, in dataflow_worker.native_operations.NativeWriteOperation.finish + File "/usr/local/lib/python3.7/site-packages/dataflow_worker/nativeavroio.py", line 308, in __exit__ + self._data_file_writer.flush() + File "fastavro/_write.pyx", line 664, in fastavro._write.Writer.flush + File "fastavro/_write.pyx", line 639, in fastavro._write.Writer.dump + File "fastavro/_write.pyx", line 451, in fastavro._write.snappy_write_block + File "fastavro/_write.pyx", line 458, in fastavro._write.snappy_write_block + File "/usr/local/lib/python3.7/site-packages/apache_beam/io/filesystemio.py", line 200, in write + self._uploader.put(b) + File "/usr/local/lib/python3.7/site-packages/apache_beam/io/gcp/gcsio.py", line 720, in put + self._conn.send_bytes(data.tobytes()) + File "/usr/local/lib/python3.7/multiprocessing/connection.py", line 200, in send_bytes + self._send_bytes(m[offset:offset + size]) + File "/usr/local/lib/python3.7/multiprocessing/connection.py", line 393, in _send_bytes + header = struct.pack("!i", n) +struct.error: 'i' format requires -2147483648 <= number <= 2147483647 +" + + +"Out of memory: Killed process 2042 (python) total-vm:28616496kB, anon-rss:25684136kB, file-rss:0kB, shmem-rss:0kB, UID:0 pgtables:51284kB oom_score_adj:900" diff --git a/notes/tmp/exampledata b/notes/tmp/exampledata new file mode 100644 index 0000000..97c9248 --- /dev/null +++ b/notes/tmp/exampledata @@ -0,0 +1,44 @@ +[{ + "property_id": "3cf3c06632c46754696f2017933702f3", + "flat_appartment": "", + "builing": "", + "number": "63", + "street": "ROTTON PARK STREET", + "locality": "", + "town": "BIRMINGHAM", + "district": "BIRMINGHAM", + "county": "WEST MIDLANDS", + "postcode": "B16 0AE", + "property_transactions": [ + { "price": "385000", "transaction_date": "2021-01-08", "year": "2021" }, + { "price": "701985", "transaction_date": "2019-03-28", "year": "2019" }, + { "price": "1748761", "transaction_date": "2020-05-27", "year": "2020" } + ], + "latest_transaction_year": "2021" +}, +{ + "property_id": "c650d5d7bb0daf0a19bb2cacabbee74e", + "readable_address": "16 STATION ROAD\nPARKGATE\nNESTON\nCHESHIRE WEST AND CHESTER\nCH64 6QJ", + "flat_appartment": "", + "builing": "", + "number": "16", + "street": "STATION ROAD", + "locality": "PARKGATE", + "town": "NESTON", + "district": "CHESHIRE WEST AND CHESTER", + "county": "CHESHIRE WEST AND CHESTER", + "postcode": "CH64 6QJ", + "property_transactions": [ + { + "price": "280000", + "transaction_date": "2020-11-30", + "year": "2020" + }, + { + "price": "265000", + "transaction_date": "2020-05-29", + "year": "2020" + } + ], + "latest_transaction_year": "2020" +}] diff --git a/notes/tmp/runningdata b/notes/tmp/runningdata new file mode 100644 index 0000000..0929edb --- /dev/null +++ b/notes/tmp/runningdata @@ -0,0 +1,16 @@ + + +Create Mapping table +('fd4634faec47c29de40bbf7840723b41', ['317500', '2020-11-13 00:00', 'B90 3LA', '1', '', 'VERSTONE ROAD', 'SHIRLEY', 'SOLIHULL', 'SOLIHULL', 'WEST MIDLANDS', '']) +('fd4634faec47c29de40bbf7840723b41', ['317500', '2020-11-13 00:00', 'B90 3LA', '1', '', 'VERSTONE ROAD', 'SHIRLEY', 'SOLIHULL', 'SOLIHULL', 'WEST MIDLANDS', '']) + +Condensing +{'fd4634faec47c29de40bbf7840723b41': ['317500', '2020-11-13 00:00', 'B90 3LA', '1', '', 'VERSTONE ROAD', 'SHIRLEY', 'SOLIHULL', 'SOLIHULL', 'WEST MIDLANDS', '']} + + +Prepared +GroupByKey +('fe205bfe66bc7f18c50c8f3d77ec3e30', ['fd4634faec47c29de40bbf7840723b41', 'fd4634faec47c29de40bbf7840723b41']) + +deduplicated +('fe205bfe66bc7f18c50c8f3d77ec3e30', ['fd4634faec47c29de40bbf7840723b41']) From f60beb456514cdadfaf5b68d3472f8c9af7a849d Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Mon, 27 Sep 2021 03:18:49 +0100 Subject: [PATCH 47/63] updating dataflow notes --- notes/documentation/dataflow.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/notes/documentation/dataflow.md b/notes/documentation/dataflow.md index 63a6fa1..f263c04 100644 --- a/notes/documentation/dataflow.md +++ b/notes/documentation/dataflow.md @@ -18,18 +18,19 @@ Export env variable: ### Dataflow -#### Monthly dataset +#### Yearly dataset ```bash python -m analyse_properties.main \ --region europe-west1 \ - --input gs://street-group-technical-test-dmot-euw1/input/pp-monthly-update-new-version.csv \ - --output gs://street-group-technical-test-dmot-euw1/output/pp-monthly-update-new-version \ + --input gs://street-group-technical-test-dmot-euw1/input/pp-2020.csv \ + --output gs://street-group-technical-test-dmot-euw1/output/pp-2020 \ --runner DataflowRunner \ --project street-group \ --temp_location gs://street-group-technical-test-dmot-euw1/tmp \ --subnetwork=https://www.googleapis.com/compute/v1/projects/street-group/regions/europe-west1/subnetworks/europe-west-1-dataflow \ - --no_use_public_ips + --no_use_public_ips \ + --worker_machine_type=n1-highmem-2 ``` #### Full dataset @@ -44,13 +45,11 @@ python -m analyse_properties.main \ --temp_location gs://street-group-technical-test-dmot-euw1/tmp \ --subnetwork=https://www.googleapis.com/compute/v1/projects/street-group/regions/europe-west1/subnetworks/europe-west-1-dataflow \ --no_use_public_ips \ - --worker_machine_type=n1-highmem-8 + --worker_machine_type=n1-highmem-8 \ + --num_workers=3 \ + --autoscaling_algorithm=NONE ``` - —-disk_size_gb=50 \ - - - ### Locally Run the pipeline locally: @@ -83,3 +82,7 @@ Use `--experiments=enable_prime` Deploying a pipeline (with scaling options): Available VM types (with pricing): + +Performance + +Sideinput performance: From 391861d80cabdd644829eebde80d745191dcba2a Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Mon, 27 Sep 2021 03:39:30 +0100 Subject: [PATCH 48/63] adding latest beam pipeline code --- analyse_properties/main.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/analyse_properties/main.py b/analyse_properties/main.py index 241f3f7..d2bce05 100644 --- a/analyse_properties/main.py +++ b/analyse_properties/main.py @@ -83,7 +83,6 @@ class SplitColumn(beam.DoFn): Args: index : The index of the column in the list. split_char: The character to split the column by. - """ def __init__(self, index, split_char): @@ -107,30 +106,40 @@ class CreateMappingTable(beam.DoFn): """ Create a mapping table to be used as a side-input. - This mapping table has a key of an id generated across all columns and a value of + This mapping table has a key of an ID generated across all columns and a value of the raw property data. - The table is used to populate the raw property data after a GroupByKey which is done on ids only - in order to reduce the amount of data processed in the GroupByKey operation. + The table is used to populate the raw property data after a GroupByKey using + only the IDs in order to reduce the amount of data processed in the GroupByKey operation. Args: - all_columns + all_columns(bool): If True will use all fields to calculate the ID. If false + will exclude the first two. """ def __init__(self, all_columns=False): self.all_columns = all_columns def process(self, element): + # Join the row into a string. unique_string = ( ",".join(element[2:]) if not self.all_columns else ",".join(element) ) + # Hash the string. hashed_string = hashlib.md5(unique_string.encode()) - # add the hash as a key to the data. + # Format the resulting PCollection with the key of id and value of raw data. new_element = (hashed_string.hexdigest(), list(element)) yield new_element class CreateUniquePropertyID(beam.DoFn): + """ + Create a unique property ID which does not include the price and date of sale. + + Uses each row of the mapping table to create a PCollection with a key of the + unique property ID and a value of the ID generated across all columns. + """ + def process(self, element): unique_string = ",".join(element[-1][2:]) hashed_string = hashlib.md5(unique_string.encode()) From cad6612ebee81858485a605651db30263671c33a Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Mon, 27 Sep 2021 03:39:40 +0100 Subject: [PATCH 49/63] updating dataflow notes --- notes/documentation/dataflow.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/notes/documentation/dataflow.md b/notes/documentation/dataflow.md index f263c04..83c98f8 100644 --- a/notes/documentation/dataflow.md +++ b/notes/documentation/dataflow.md @@ -86,3 +86,8 @@ Available VM types (with pricing): + +Common use cases: + +- Part 1 +- Part 2 From f9eeb8bfadb69068b204472be37d52398cf82744 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Mon, 27 Sep 2021 21:17:39 +0100 Subject: [PATCH 50/63] adding latest beam pipeline code for dataflow --- analyse_properties/main.py | 88 ++++++++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 28 deletions(-) diff --git a/analyse_properties/main.py b/analyse_properties/main.py index d2bce05..969a09d 100644 --- a/analyse_properties/main.py +++ b/analyse_properties/main.py @@ -9,6 +9,7 @@ import pathlib import apache_beam as beam from apache_beam.options.pipeline_options import PipelineOptions, SetupOptions +from analyse_properties.debug import * # noqa def slice_by_range(element, *ranges): """ @@ -36,7 +37,7 @@ class DropRecordsSingleEmptyColumn(beam.DoFn): None: If the length of the column is 0, drop the element. Yields: - element: If the length of the column isn't 0, keep the element. + element: If the length of the column is >0, keep the element. """ def __init__(self, index): @@ -61,7 +62,7 @@ class DropRecordsTwoEmptyColumn(beam.DoFn): None: If the length of both columns is 0, drop the element. Yields: - element: If the length of both columns isn't 0, keep the element. + element: If the length of both columns is >0, keep the element. """ def __init__(self, index_0, index_1): @@ -90,14 +91,15 @@ class SplitColumn(beam.DoFn): self.split_char = split_char def process(self, element): - # If there is a split based on the split_char, then keep the first result in - # place and append the second column at the end. + # If there is a split based on the split_char, then keep the second result in + # place (street number) and append the first result (building) at the end. try: part_0, part_1 = element[self.index].split(self.split_char) element[self.index] = part_1.strip() element.append(part_0.strip()) yield element except ValueError: + # append a blank column to keep column numbers consistent. element.append("") yield element @@ -111,20 +113,11 @@ class CreateMappingTable(beam.DoFn): The table is used to populate the raw property data after a GroupByKey using only the IDs in order to reduce the amount of data processed in the GroupByKey operation. - - Args: - all_columns(bool): If True will use all fields to calculate the ID. If false - will exclude the first two. """ - def __init__(self, all_columns=False): - self.all_columns = all_columns - def process(self, element): # Join the row into a string. - unique_string = ( - ",".join(element[2:]) if not self.all_columns else ",".join(element) - ) + unique_string = ",".join(element) # Hash the string. hashed_string = hashlib.md5(unique_string.encode()) # Format the resulting PCollection with the key of id and value of raw data. @@ -148,6 +141,8 @@ class CreateUniquePropertyID(beam.DoFn): class DeduplicateIDs(beam.DoFn): + """Deduplicate a list of IDs.""" + def process(self, element): deduplicated_list = list(set(element[-1])) new_element = (element[0], deduplicated_list) @@ -155,6 +150,16 @@ class DeduplicateIDs(beam.DoFn): def insert_data_for_id(element, mapping_table): + """ + Replace the ID with the raw data from the mapping table. + + Args: + element: The element. + mapping_table (dict): The mapping table. + + Yields: + The element with IDs replaced with raw data. + """ replaced_list = [mapping_table[data_id] for data_id in element[-1]] new_element = (element[0], replaced_list) yield new_element @@ -165,7 +170,15 @@ class ConvertDataToDict(beam.DoFn): @staticmethod def get_latest_transaction(transaction_dates): - """Get the date of the latest transaction.""" + """ + Get the date of the latest transaction for a list of dates. + + Args: + transaction_dates (str): A date in the form "%Y-%m-%d". + + Returns: + str: The year in the form "%Y" of the latest transaction date. + """ transaction_dates = [ datetime.strptime(individual_transaction, "%Y-%m-%d") for individual_transaction in transaction_dates @@ -173,7 +186,17 @@ class ConvertDataToDict(beam.DoFn): return max(transaction_dates).strftime("%Y") @staticmethod - def get_readable_address(address_components: list, address_comparisons: list): + def get_readable_address(address_components, address_comparisons): + """ + Create a human readable address from the locality/town/district/county columns. + + Args: + address_components (list): The preceeding parts of the address (street, postcode etc.) + address_comparisons (list): The locality/town/district/county. + + Returns: + str: The complete address deduplicated & cleaned. + """ # Get pairwise comparison to see if two locality/town/district/counties # are equivalent pairwise_comparison = [ @@ -194,7 +217,6 @@ class ConvertDataToDict(beam.DoFn): applied_mask = list(itertools.compress(address_comparisons, mask)) # Filter out empty items in list deduplicated_address_part = list(filter(None, applied_mask)) - # Filter out any missing parts of the address components cleaned_address_components = list(filter(None, address_components)) @@ -213,9 +235,9 @@ class ConvertDataToDict(beam.DoFn): # Group together all the transactions for the property. property_transactions = [ { - "price": entry[0], + "price": int(entry[0]), "transaction_date": entry[1].replace(" 00:00", ""), - "year": entry[1][0:4], + "year": int(entry[1][0:4]), } for entry in element[-1] ] @@ -234,12 +256,12 @@ class ConvertDataToDict(beam.DoFn): "county": list(element[-1])[0][9], "postcode": list(element[-1])[0][2], "property_transactions": property_transactions, - "latest_transaction_year": self.get_latest_transaction( + "latest_transaction_year": int(self.get_latest_transaction( [ transaction["transaction_date"] for transaction in property_transactions ] - ), + )), } # Create a human readable address to go in the dict. @@ -262,6 +284,8 @@ class ConvertDataToDict(beam.DoFn): def run(argv=None, save_main_session=True): """Entrypoint and definition of the pipeline.""" + logging.getLogger().setLevel(logging.INFO) + # Default input/output files input_file = ( pathlib.Path(__file__).parents[1] @@ -281,10 +305,16 @@ def run(argv=None, save_main_session=True): # Arguments parser = argparse.ArgumentParser() parser.add_argument( - "--input", dest="input", default=str(input_file), help="Input file." + "--input", + dest="input", + default=str(input_file), + help="Full path to the input file.", ) parser.add_argument( - "--output", dest="output", default=str(output_file), help="Output file." + "--output", + dest="output", + default=str(output_file), + help="Full path to the output file without extension.", ) known_args, pipeline_args = parser.parse_known_args(argv) @@ -292,7 +322,6 @@ def run(argv=None, save_main_session=True): pipeline_options = PipelineOptions(pipeline_args) pipeline_options.view_as(SetupOptions).save_main_session = save_main_session - # Load in the data from a csv file. with beam.Pipeline(options=pipeline_options) as pipeline: # Load the data load = ( @@ -303,7 +332,7 @@ def run(argv=None, save_main_session=True): >> beam.Map(lambda element: [el.strip('"') for el in element]) ) - # Clean the data by dropping unneeded rows. + # Clean the data. clean_drop = ( load | "Drop unneeded columns" @@ -323,19 +352,22 @@ def run(argv=None, save_main_session=True): mapping_table_raw = ( clean_drop | "Create a mapping table with key of id_all_columns and value of cleaned data." - >> beam.ParDo(CreateMappingTable(all_columns=True)) + >> beam.ParDo(CreateMappingTable()) ) + # Condense mapping table into a single dict. mapping_table_condensed = ( mapping_table_raw | "Condense mapping table into single dict" >> beam.combiners.ToDict() ) + # Prepare the data by creating IDs, grouping together and using mapping table + # to reinsert raw data. prepared = ( mapping_table_raw | "Create unique ID ignoring price & date" >> beam.ParDo(CreateUniquePropertyID()) - | "Group IDs using all columns by IDs ignoring price & date" + | "Group by ID" >> beam.GroupByKey() | "Deduplicate to eliminate repeated transactions" >> beam.ParDo(DeduplicateIDs()) @@ -356,7 +388,7 @@ def run(argv=None, save_main_session=True): ( formatted | "Combine into one PCollection" >> beam.combiners.ToList() - | "Format output" >> beam.Map(json.dumps) + | "Format output" >> beam.Map(json.dumps, indent=2) | "Save to .json file" >> beam.io.WriteToText( file_path_prefix=known_args.output, From dffc6aa553815aa3eb5f0e09b5fef8a7ec514837 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Mon, 27 Sep 2021 21:17:49 +0100 Subject: [PATCH 51/63] adding debug print --- analyse_properties/debug.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/analyse_properties/debug.py b/analyse_properties/debug.py index ab44457..ae59b79 100644 --- a/analyse_properties/debug.py +++ b/analyse_properties/debug.py @@ -22,3 +22,9 @@ class DebugShowColumnWithValueIn(beam.DoFn): if self.value in column: yield element return None + + +class DebugPrint(beam.DoFn): + def process(self, element): + print(element) + yield element From 3263b3dd8b724e4475857fcbfb52f89a3477eab6 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Mon, 27 Sep 2021 21:18:06 +0100 Subject: [PATCH 52/63] moving panda-profiling report into docs --- .../pandas-profiling/report.html | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename exploration/price_paid_data_report.html => docs/pandas-profiling/report.html (100%) diff --git a/exploration/price_paid_data_report.html b/docs/pandas-profiling/report.html similarity index 100% rename from exploration/price_paid_data_report.html rename to docs/pandas-profiling/report.html From 886a37ca94eae3c8ac904d1a6b736c36c2564207 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Mon, 27 Sep 2021 21:18:14 +0100 Subject: [PATCH 53/63] updating report.py --- exploration/report.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/exploration/report.py b/exploration/report.py index ed81b47..954609c 100644 --- a/exploration/report.py +++ b/exploration/report.py @@ -1,13 +1,16 @@ -from importlib import resources +import pathlib import pandas as pd from pandas_profiling import ProfileReport def main(): - with resources.path("analyse_properties.data", "pp-complete.csv") as csv_file: + input_file = ( + pathlib.Path(__file__).parents[1] / "data" / "input" / "pp-complete.csv" + ) + with input_file.open() as csv: df_report = pd.read_csv( - csv_file, + csv, names=[ "transaction_id", "price", From 76434fae5b47c79fbcabc13b1c9009f498523274 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Mon, 27 Sep 2021 21:18:28 +0100 Subject: [PATCH 54/63] adding entrypoint command --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 70e34d7..0f73a0c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,3 +18,6 @@ pandas-profiling = "^3.0.0" [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" + +[tool.poetry.scripts] +"analyse-properties" = "analyse_properties.main:run" From cbb8a7e2376c5efb48edb595dc9d4f61070eaf0b Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Mon, 27 Sep 2021 21:19:28 +0100 Subject: [PATCH 55/63] adding initial docs --- docs/discussion/approach.md | 1 + docs/discussion/cleaning.md | 115 +++++++++++++++++++++++++++++ docs/discussion/exploration.md | 30 ++++++++ docs/discussion/introduction.md | 9 +++ docs/documentation/installation.md | 26 +++++++ docs/documentation/usage.md | 56 ++++++++++++++ docs/index.md | 7 ++ mkdocs.yaml | 31 ++++---- notes/documentation/dataflow.md | 4 +- 9 files changed, 261 insertions(+), 18 deletions(-) create mode 100644 docs/discussion/approach.md create mode 100644 docs/discussion/cleaning.md create mode 100644 docs/discussion/exploration.md create mode 100644 docs/discussion/introduction.md create mode 100644 docs/documentation/installation.md create mode 100644 docs/documentation/usage.md diff --git a/docs/discussion/approach.md b/docs/discussion/approach.md new file mode 100644 index 0000000..c95f645 --- /dev/null +++ b/docs/discussion/approach.md @@ -0,0 +1 @@ +# Approach diff --git a/docs/discussion/cleaning.md b/docs/discussion/cleaning.md new file mode 100644 index 0000000..a2659ba --- /dev/null +++ b/docs/discussion/cleaning.md @@ -0,0 +1,115 @@ +# Cleaning + +In this page we discuss the cleaning stages and how best to prepare the data. + +## Uniquely identify a property. + +To uniquely identify a property with the data we have it is enough to have a Postcode and the PAON (or SAON or combination of both). + +### Postcode + +Because so few properties are missing a postcode (0.2% of all records) we will drop all rows that do not have one. We will drop some properties that could be identified uniquely with some more work, but the properties that are missing a postcode tend to be unusual/commercial/industrial (e.g a powerplant). + +### PAON/SAON + +The PAON has 3 possible formats: + +- The street number. +- The building name. +- The building name and street number (comma delimited). + +The SAON: + +- Identifies the appartment/flat number for the building. +- If the SAON is present (only 11.7% of values) then the PAON will either be + - The building name. + - The building name and street number. + +Because of the way the PAON and SOAN are defined, if any row is missing **both** of these columns we will drop it. As only having the postcode is not enough (generally speaking) to uniquely identify a property. + +!!! tip + In a production environment we could send these rows to a sink table (in BigQuery for example), rather than drop them outright. Collecting these rows over time might show some patterns on how we can uniquely identify properties that are missing these fields. + +We split the PAON as part of the cleaning stage. If the PAON contains a comma then it contains the building name and street number. We keep the street number in the same position as the PAON and insert the building name as a new column at the end of the row. If the PAON does not contain a comma we insert a blank column at the end to keep the number of columns in the PCollection consistent. + +### Unneeded columns + +To try keep computation costs/time down, I decided to drop the categorical columns provided. These include: + +- Property Type. +- Old/New. +- Duration. +- PPD Category Type. +- Record Status - monthly file only. + +Initially I was attempting to work against the full dataset so dropping these columns would make a difference in the amount of data that needs processing. + +These columns do provide some relevant information (old/new, duration, property type) and these could be included back into the pipeline fairly easily. Due to time constraints I was unable to make this change. + +In addition, I also dropped the transaction unique identifier column. I wanted the IDs calculated in the pipeline to be consistent in format, and hashing a string (md5) isn't that expensive to calculate with complexity $\mathcal{O}(n)$. + +### General cleaning + +#### Upper case + +As all strings in the dataset are upper case, we convert everything in the row to upper case to enforce consistency across the dataset. + +#### Strip leading/trailing whitespace + +We strip all leading/trailing whitespace from each column to enforce consistency. + +#### Repeated rows + +Some of the data is repeated: + +- Some rows repeated, with the same date + price + address information but with a unique transaction id. + +
+ Example (PCollection) + +```json +[ + { + "fd4634faec47c29de40bbf7840723b41": [ + "317500", + "2020-11-13 00:00", + "B90 3LA", + "1", + "", + "VERSTONE ROAD", + "SHIRLEY", + "SOLIHULL", + "SOLIHULL", + "WEST MIDLANDS", + "" + ] + }, + { + "fd4634faec47c29de40bbf7840723b41": [ + "317500", + "2020-11-13 00:00", + "B90 3LA", + "1", + "", + "VERSTONE ROAD", + "SHIRLEY", + "SOLIHULL", + "SOLIHULL", + "WEST MIDLANDS", + "" + ] + } +] +``` + +
+ +These rows will be deduplicated as part of the pipeline. + +- Some rows have the same date + address information, but different prices. + +It would be very unusual to see multiple transactions on the same date for the same property. One reason could be that there was a data entry error, resulting in two different transactions with only one being the real price. As the date column does not contain the time (it is fixed at `00:00`) it is impossible to tell. + +Another reason could be missing building/flat/appartment information in this entry. + +We **keep** these in the data, resulting in some properties having multiple transactions with different prices on the same date. Without a time or more information to go on, it is difficult to see how these could be filtered out. diff --git a/docs/discussion/exploration.md b/docs/discussion/exploration.md new file mode 100644 index 0000000..53ec14a --- /dev/null +++ b/docs/discussion/exploration.md @@ -0,0 +1,30 @@ +# Data Exploration Report + +A brief exploration was done on the **full** dataset using the module `pandas-profiling`. The module uses `pandas` to load a dataset and automatically produce quantile/descriptive statistics, common values, extreme values, skew, kurtosis etc. and produces a report `.html` file that can be viewed interatively in your browser. + +The script used to generate this report is located in `./exploration/report.py` and can be viewed below. + +
+ report.py +```python +--8<-- "exploration/report.py" +``` +
+ +The report can be viewed by clicking the Data Exploration Report tab at the top of the page. + +## Interesting observations + +When looking at the report we are looking for data quality and missing observations. The statistics are interesting to see but are largely irrelevant for this task. + +The data overall looks very good for a dataset of its size (~27 million records). For important fields there are no missing values: + +- Every row has a price. +- Every row has a unique transaction ID. +- Every row has a transaction date. + +Some fields that we will need are missing data: + +- ~42,000 (0.2%) are missing a Postcode. +- ~4,000 (<0.1%) are missing a PAON (primary addressable object name). +- ~412,000 (1.6%) are missing a Street Name. diff --git a/docs/discussion/introduction.md b/docs/discussion/introduction.md new file mode 100644 index 0000000..8315849 --- /dev/null +++ b/docs/discussion/introduction.md @@ -0,0 +1,9 @@ +# Introduction + +This section will go through some discussion of the test including: + +- Data exploration +- Cleaning the data +- Interpreting the results +- Deploying on GCP DataFlow +- Improvements diff --git a/docs/documentation/installation.md b/docs/documentation/installation.md new file mode 100644 index 0000000..fca1f70 --- /dev/null +++ b/docs/documentation/installation.md @@ -0,0 +1,26 @@ +# Installation + +The task is written in Python 3.7.9 using Apache Beam 2.32.0. Python versions 3.6.14 and 3.8.11 should also be compatible but have not been tested. + +The task has been tested on MacOS Big Sur and WSL2. The task should run on Windows but this wasn't tested. + +For Beam 2.32.0 the supported versions of the Python SDK can be found [here](https://cloud.google.com/dataflow/docs/concepts/sdk-worker-dependencies#sdk-for-python). + +## Poetry + +The test uses [Poetry](https://python-poetry.org) for dependency management. + +!!! info inline end + If you already have Poetry installed globally you can go straight to the `poetry install` step. + +In a virtual environment install poetry: + +```bash +pip install poetry +``` + +From the root of the repo install the dependencies with: + +```bash +poetry install --no-dev +``` diff --git a/docs/documentation/usage.md b/docs/documentation/usage.md new file mode 100644 index 0000000..1c19bbd --- /dev/null +++ b/docs/documentation/usage.md @@ -0,0 +1,56 @@ +# Usage + +This page documents how to run the pipeline locally to complete the task for the [dataset for 2020](https://www.gov.uk/government/statistical-data-sets/price-paid-data-downloads#section-1). + +The pipeline also runs in GCP using DataFlow and is discussed further on but can be viewed here. We also discuss how to adapt the pipeline so it can run against [the full dataset](https://www.gov.uk/government/statistical-data-sets/price-paid-data-downloads#single-file). + +## Download dataset + +The input data by default should go in `./data/input`. + +For convenience the data is available publicly in a GCP Cloud Storage bucket. + +Run: + +```bash +wget https://storage.googleapis.com/street-group-technical-test-dmot-euw1/input/pp-2020.csv -P data/input +``` + +to download the data for 2020 and place in the input directory above. + +## Entrypoint + +The entrypoint to the pipeline is `analyse-properties`. + +## Available options + +Running + +```bash +analyse-properties --help +``` + +gives the following output: + +```bash +usage: analyse-properties [-h] [--input INPUT] [--output OUTPUT] + +optional arguments: + -h, --help show this help message and exit + --input INPUT Full path to the input file. + --output OUTPUT Full path to the output file without extension. +``` + +The default value for input is `./data/input/pp-2020.csv` and the default value for output is `./data/output/pp-2020`. + +If passing in values for `input`/`output` these should be **full** paths to the files. The test will parse these inputs as a `str()` and pass this to `#!python beam.io.ReadFromText()`. + +## Run the pipeline + +To run the pipeline and complete the task run: + +```bash +analyse-properties --runner DirectRunner +``` + +The pipeline will use the 2020 dataset located in `./data/input` and output the resulting `.json` to `./data/output`. diff --git a/docs/index.md b/docs/index.md index 165bd01..6164af6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -3,3 +3,10 @@ ## Introduction This documentation accompanies the technical test for the Street Group. + +The following pages will guide the user through installing the requirements, and running the task to complete the test. In addition, there is some discussion around the approach, and any improvements that could be made. + +Navigate sections using the tabs at the top of the page. Pages in this section can be viewed in order by using the section links in the left menu, or by using bar at the bottom of the page. The table of contents in the right menu can be used to navigate sections on each page. + +!!! note + All paths in this documentation, e.g `./analyse_properties/data/output` refer to the location of the directory/file from the root of the repo. diff --git a/mkdocs.yaml b/mkdocs.yaml index b092c7d..424a20f 100644 --- a/mkdocs.yaml +++ b/mkdocs.yaml @@ -4,37 +4,36 @@ use_directory_urls: false nav: - Documentation: - Welcome: index.md - # - Installation: documentation/installation.md - # - Usage: documentation/usage.md - # - Comments and Caveats: - # - Introduction: comments_caveats/introduction.md - # - Time limit: comments_caveats/time_limit.md - # - Third party libraries: comments_caveats/third_party_libraries.md - # - Areas of improvement and comments: comments_caveats/area_of_improvement_comments.md - # - Similar names algorithm: comments_caveats/similar_names.md - # - Reference: - # - deduplicator.main: reference/api_documentation_main.md - # - Changelog: changelog/changelog.md + - Installation: documentation/installation.md + - Usage: documentation/usage.md + - Discussion: + - Introduction: discussion/introduction.md + - Data Exploration Report: discussion/exploration.md + - Cleaning: discussion/cleaning.md + - Approach: discussion/approach.md + - Data Exploration Report: pandas-profiling/report.html theme: name: material palette: primary: indigo accent: blue - feature: - tabs: true + features: + navigation.tabs: true markdown_extensions: - admonition - codehilite: guess_lang: true - toc: permalink: true + - pymdownx.highlight - pymdownx.superfences - # - pymdownx.arithmatex: - # generic: true + - pymdownx.inlinehilite + - pymdownx.snippets + - pymdownx.arithmatex: + generic: true plugins: - search: lang: en extra_javascript: - - javascripts/config.js - https://polyfill.io/v3/polyfill.min.js?features=es6 - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js diff --git a/notes/documentation/dataflow.md b/notes/documentation/dataflow.md index 83c98f8..b5228e6 100644 --- a/notes/documentation/dataflow.md +++ b/notes/documentation/dataflow.md @@ -22,11 +22,11 @@ Export env variable: ```bash python -m analyse_properties.main \ + --runner DataflowRunner \ + --project street-group \ --region europe-west1 \ --input gs://street-group-technical-test-dmot-euw1/input/pp-2020.csv \ --output gs://street-group-technical-test-dmot-euw1/output/pp-2020 \ - --runner DataflowRunner \ - --project street-group \ --temp_location gs://street-group-technical-test-dmot-euw1/tmp \ --subnetwork=https://www.googleapis.com/compute/v1/projects/street-group/regions/europe-west1/subnetworks/europe-west-1-dataflow \ --no_use_public_ips \ From cfdee9d3ed9d799e871db984b477a3a95064440c Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Mon, 27 Sep 2021 21:20:34 +0100 Subject: [PATCH 56/63] adding commands.md to notes --- notes/commands.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 notes/commands.md diff --git a/notes/commands.md b/notes/commands.md new file mode 100644 index 0000000..f0d85b6 --- /dev/null +++ b/notes/commands.md @@ -0,0 +1,6 @@ +# Commands + +## mkdocs + +`mkdocs serve` +`mkdocs gh-deploy` From 4056ca1f327ec6eb7e9ddee059f75be2f75f4b78 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Mon, 27 Sep 2021 23:16:18 +0100 Subject: [PATCH 57/63] commenting out debug imports --- analyse_properties/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analyse_properties/main.py b/analyse_properties/main.py index 969a09d..a4f347c 100644 --- a/analyse_properties/main.py +++ b/analyse_properties/main.py @@ -9,7 +9,7 @@ import pathlib import apache_beam as beam from apache_beam.options.pipeline_options import PipelineOptions, SetupOptions -from analyse_properties.debug import * # noqa +# from analyse_properties.debug import * # noqa def slice_by_range(element, *ranges): """ From 4561f1a3569f94b9c33958740a546de0ba3e7f02 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Mon, 27 Sep 2021 23:16:30 +0100 Subject: [PATCH 58/63] updating documentation --- ...PH-2021-09-27-22_29_32.png:Zone.Identifier | 3 + docs/dataflow/img/successful_dataflow_job.png | Bin 0 -> 383341 bytes docs/dataflow/index.md | 50 ++++++++++ docs/dataflow/scaling.md | 70 +++++++++++++ docs/discussion/approach.md | 94 ++++++++++++++++++ docs/discussion/cleaning.md | 39 ++++++++ docs/discussion/introduction.md | 2 - docs/discussion/results.md | 51 ++++++++++ mkdocs.yaml | 4 + notes/documentation/dataflow.md | 2 + 10 files changed, 313 insertions(+), 2 deletions(-) create mode 100644 docs/dataflow/img/screencapture-console-cloud-google-dataflow-jobs-europe-west1-2021-09-27-08-08-57-10745415117326954715-step-mainTab-JOB-GRAPH-2021-09-27-22_29_32.png:Zone.Identifier create mode 100644 docs/dataflow/img/successful_dataflow_job.png create mode 100644 docs/dataflow/index.md create mode 100644 docs/dataflow/scaling.md create mode 100644 docs/discussion/results.md diff --git a/docs/dataflow/img/screencapture-console-cloud-google-dataflow-jobs-europe-west1-2021-09-27-08-08-57-10745415117326954715-step-mainTab-JOB-GRAPH-2021-09-27-22_29_32.png:Zone.Identifier b/docs/dataflow/img/screencapture-console-cloud-google-dataflow-jobs-europe-west1-2021-09-27-08-08-57-10745415117326954715-step-mainTab-JOB-GRAPH-2021-09-27-22_29_32.png:Zone.Identifier new file mode 100644 index 0000000..053d112 --- /dev/null +++ b/docs/dataflow/img/screencapture-console-cloud-google-dataflow-jobs-europe-west1-2021-09-27-08-08-57-10745415117326954715-step-mainTab-JOB-GRAPH-2021-09-27-22_29_32.png:Zone.Identifier @@ -0,0 +1,3 @@ +[ZoneTransfer] +ZoneId=3 +HostUrl=about:internet diff --git a/docs/dataflow/img/successful_dataflow_job.png b/docs/dataflow/img/successful_dataflow_job.png new file mode 100644 index 0000000000000000000000000000000000000000..a0da4895af32ffbd1a31b99ac522c4700c9f782d GIT binary patch literal 383341 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%0AtnWSG@R8vL7?Q)*>jnP~NeB4r8++#Vn~2G6 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�_{LzATo2}<+Ev56to3Eaa2Rn|Z4J`BC@L9PD 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 vWna3c-cS(=s% z56&c&K&G41+ooE(R51Z1v0*dhh#$zJ`~}X6qb*|F2JQU!$p%^$o(!5{zn)aU>}Lv^ z=V<=VGk5BhyQd>VfJfrGabSdKGzUI-XV*vNVt+Ix;32x{)Vc~HUYS6O{G2CAr@jt~ zc#2X8^hPjyIqI&l4?trh*ghFTuwEg&6vyX{afl EBJliEXBfJ_zbSBdV`YCL z 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

Rq)EoFac&Mj2a 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 literal 0 HcmV?d00001 diff --git a/docs/dataflow/index.md b/docs/dataflow/index.md new file mode 100644 index 0000000..a21fc9a --- /dev/null +++ b/docs/dataflow/index.md @@ -0,0 +1,50 @@ +# Running on DataFlow + +The pipeline runs as is on GCP DataFlow. The following documents how I deployed to my personal GCP account but the approach may vary depending on project/account in GCP. + +## Prerequisites + +### Cloud Storage + +- A Cloud Storage bucket with the following structure: + +``` +./input +./output +./tmp +``` + +- Place the input files into the `./input` directory in the bucket. + +### VPC + +To get around public IP quotas I created a VPC in the `europe-west1` region that has `Private Google Access` turned to `ON`. + +## Command + +!!! tip + We need to choose a `worker_machine_type` with sufficient memory to run the pipeline. As the pipeline uses a mapping table, and DataFlow autoscales on CPU and not memory usage, we need a machine with more ram than usual to ensure sufficient memory when running on one worker. For `pp-2020.csv` the type `n1-highmem-2` with 2vCPU and 13GB of ram was chosen and completed successfully in ~10 minutes using only 1 worker. + +Assuming the `pp-2020.csv` file has been placed in the `./input` directory in the bucket you can run a command similar to: + +!!! caution + Use the command `python -m analyse_properties.main` as the entrypoint to the pipeline and not `analyse-properties` as the module isn't installed with poetry on the workers with the configuration below. + +```bash +python -m analyse_properties.main \ + --runner DataflowRunner \ + --project street-group \ + --region europe-west1 \ + --input gs://street-group-technical-test-dmot-euw1/input/pp-2020.csv \ + --output gs://street-group-technical-test-dmot-euw1/output/pp-2020 \ + --temp_location gs://street-group-technical-test-dmot-euw1/tmp \ + --subnetwork=https://www.googleapis.com/compute/v1/projects/street-group/regions/europe-west1/subnetworks/europe-west-1-dataflow \ + --no_use_public_ips \ + --worker_machine_type=n1-highmem-2 +``` + +The output file from this pipeline is publically available and can be downloaded [here](https://storage.googleapis.com/street-group-technical-test-dmot-euw1/output/pp-2020-00000-of-00001.json). + +The job graph for this pipeline is displayed below: + +![JobGraph](img/successful_dataflow_job.png) diff --git a/docs/dataflow/scaling.md b/docs/dataflow/scaling.md new file mode 100644 index 0000000..6cd10a3 --- /dev/null +++ b/docs/dataflow/scaling.md @@ -0,0 +1,70 @@ +# Scaling to the full DataSet + +As is the pipeline will not run against the full dataset. But with a little work done to the existing pipeline I believe it is possible to work against the full dataset of ~27 million rows. + +## Mapping table + +Using a mapping table as a side-input means that for the full dataset this table is going to be huge. + +Side inputs are stored in memory on the workers, with such a huge table the machines are going to quickly run out of available memory when autoscaling is applied. + +Running the pipeline against the full dataset resulted in the following error: + +```text +"Out of memory: Killed process 2042 (python) total-vm:28616496kB, anon-rss:25684136kB, file-rss:0kB, shmem-rss:0kB, UID:0 pgtables:51284kB oom_score_adj:900" +``` + +with the pipeline job failing to process anything and the rows being processed per/sec gradually falling to zero as the workers killed the Python process to try free up more memory. This resulted in autoscaling down (as the CPU decreased) and the entire pipeline stagnated. + +Using a higher tiered `worker_machine_type`, disabling autoscaling, and fixing the workers to the maximum number of vCPUs available to the quota results in pipeline options: + +```bash +--worker_machine_type=n1-highmem-8 \ +--num_workers=3 \ +--autoscaling_algorithm=NONE +``` + +with 156GB of RAM available to the pipeline with 52GB on each worker. + +The pipeline was able to progress further until Python threw an error and the pipeline failed and shut down: + +```text +"Error message from worker: Traceback (most recent call last): + File "/usr/local/lib/python3.7/site-packages/dataflow_worker/batchworker.py", line 651, in do_work + work_executor.execute() + ... + File "/usr/local/lib/python3.7/multiprocessing/connection.py", line 393, in _send_bytes + header = struct.pack("!i", n) +struct.error: 'i' format requires -2147483648 <= number <= 2147483647 +``` + +The number 2147483647 being the maximum value for a 32bit integer. + +As the side-input needs to be pickled (or serialised), this tells us that the table is far too large to be pickled and passed to the other workers. No amount of CPU/Memory can fix the problem. + +## Patterns + +Google have several patterns for large side-inputs which are documented here: + +- Part 1 +- Part 2 + +## Solution + +A possible solution would be to leverage BigQuery to store the results of the mapping table in as the pipeline progresses. We can make use of BigQueries array type to literally store the raw array as we process each row. + +In addition to creating the mapping table `(key, value)` pairs, we also save these pairs to BigQuery at this stage. We then yield the element as it is currently written to allow the subsequent stages to make use of this data. + +Remove the condense mapping table stage as it is no longer needed. + +Instead of using: + +```python +beam.FlatMap( + insert_data_for_id, beam.pvalue.AsSingleton(mapping_table_condensed) +) +``` + +to insert the results of the mapping table we write a new `DoFn` that takes the element, and for each `id_all_columns` in the array we make a call to BigQuery to get the array for this ID and insert it at this stage. + +Because each `id_all_columns` and its corresponding data is only used once, there would be no need to cache the results from BigQuery, however some work could be done to see if we could pull back more than one row at a time and cache these, saving time/costs in calls to BigQuery. diff --git a/docs/discussion/approach.md b/docs/discussion/approach.md index c95f645..252e0e5 100644 --- a/docs/discussion/approach.md +++ b/docs/discussion/approach.md @@ -1 +1,95 @@ # Approach + +The general approach to the pipeline is: + +## Loading stage + +- Load using `#!python beam.io.ReadFromText()` +- Split the string loaded by `,` as it's a comma delimited `.csv`. +- Strip the leading/trailing `"` marks. + +The result is an array with each element representing a single column in that row. + +## Cleaning stage + +Already discussed. + +## Create a mapping table + +The mapping table takes each row and creates a `(key,value)` pair with: + +- The key being the id across all columns (`id_all_columns`). +- The value being the raw data as an array. + +The mapping table is then condensed to a single dictionary with these key, value pairs and is used as a side input further down the pipeline. + +This mapping table is created to ensure the `GroupByKey` operation is as quick as possible. The more data you have to process in a `GroupByKey`, the longer the operation takes. By doing the `GroupByKey` using just the ids, the pipeline can process the files much quicker than if we included the raw data in this operation. + +## Prepare stage + +- Take the mapping table data (before it is condensed) and create a unique id ignoring the price and date (`id_without_price_date`). + +This id will not be unique: for properties with more than one transaction they will share this id. + +- Create a `(key, value)` pair with: + - The key being `id_without_price_date`. + - The value being `id_all_columns`. +- Group by `id_without_price_date`. + +This results in a PCollection that looks like: `(id_without_price_date, [id_all_columns,...])` + +- Deduplicate the `id_all_columns` inside this array to eliminate repeated rows that are exactly the same. +- Use the mapping table as a side input to reinsert the raw data using the `id_all_columns`. + +

+ Example for No.1 B90 3LA + +Mapping table (pre condensed): + +```json +('fd4634faec47c29de40bbf7840723b41', ['317500', '2020-11-13 00:00', 'B90 3LA', '1', '', 'VERSTONE ROAD', 'SHIRLEY', 'SOLIHULL', 'SOLIHULL', 'WEST MIDLANDS', '']) +('fd4634faec47c29de40bbf7840723b41', ['317500', '2020-11-13 00:00', 'B90 3LA', '1', '', 'VERSTONE ROAD', 'SHIRLEY', 'SOLIHULL', 'SOLIHULL', 'WEST MIDLANDS', '']) +``` + +Mapping table (condensed): + +```json +{'fd4634faec47c29de40bbf7840723b41': ['317500', '2020-11-13 00:00', 'B90 3LA', '1', '', 'VERSTONE ROAD', 'SHIRLEY', 'SOLIHULL', 'SOLIHULL', 'WEST MIDLANDS', '']} +``` + +Prepared (key, value): + +```json +('fe205bfe66bc7f18c50c8f3d77ec3e30', 'fd4634faec47c29de40bbf7840723b41') +('fe205bfe66bc7f18c50c8f3d77ec3e30', 'fd4634faec47c29de40bbf7840723b41') +``` + +Prepared (GroupByKey): + +```json +('fe205bfe66bc7f18c50c8f3d77ec3e30', ['fd4634faec47c29de40bbf7840723b41', 'fd4634faec47c29de40bbf7840723b41']) +``` + +Prepared (Deduplicated): + +```json +('fe205bfe66bc7f18c50c8f3d77ec3e30', ['fd4634faec47c29de40bbf7840723b41']) +``` + +Use mapping table as side input: + +```json +('fe205bfe66bc7f18c50c8f3d77ec3e30', ['317500', '2020-11-13 00:00', 'B90 3LA', '1', '', 'VERSTONE ROAD', 'SHIRLEY', 'SOLIHULL', 'SOLIHULL', 'WEST MIDLANDS', '']) +``` + +
+ +## Format stage + +This stage takes the result and constructs a `json` object out of the grouped data. The schema for this output is discussed in the following page. + +## Save stage + +- The PCollection is combined with `#!python beam.combiners.ToList()` +- Apply `json.dumps()` for proper quotation marks for strings. +- Write to text with `#!python beam.io.WriteToText`. diff --git a/docs/discussion/cleaning.md b/docs/discussion/cleaning.md index a2659ba..314a829 100644 --- a/docs/discussion/cleaning.md +++ b/docs/discussion/cleaning.md @@ -44,6 +44,8 @@ To try keep computation costs/time down, I decided to drop the categorical colum Initially I was attempting to work against the full dataset so dropping these columns would make a difference in the amount of data that needs processing. +These columns are also not consistent. E.g the property `63` `B16, 0AE` has three transactions. Two of these transactions have a property type of `Other` and one transaction has a property type of `Terraced`. + These columns do provide some relevant information (old/new, duration, property type) and these could be included back into the pipeline fairly easily. Due to time constraints I was unable to make this change. In addition, I also dropped the transaction unique identifier column. I wanted the IDs calculated in the pipeline to be consistent in format, and hashing a string (md5) isn't that expensive to calculate with complexity $\mathcal{O}(n)$. @@ -113,3 +115,40 @@ It would be very unusual to see multiple transactions on the same date for the s Another reason could be missing building/flat/appartment information in this entry. We **keep** these in the data, resulting in some properties having multiple transactions with different prices on the same date. Without a time or more information to go on, it is difficult to see how these could be filtered out. + +
+ Example (Output) + +```json +[ + { + "property_id": "20d5c335c8d822a40baab0ecd57e92a4", + "readable_address": "53 PAVENHAM DRIVE\nBIRMINGHAM\nWEST MIDLANDS\nB5 7TN", + "flat_appartment": "", + "builing": "", + "number": "53", + "street": "PAVENHAM DRIVE", + "locality": "", + "town": "BIRMINGHAM", + "district": "BIRMINGHAM", + "county": "WEST MIDLANDS", + "postcode": "B5 7TN", + "property_transactions": [ + { + "price": 270000, + "transaction_date": "2020-04-23", + "year": 2020 + }, + { + "price": 364000, + "transaction_date": "2020-04-23", + "year": 2020 + } + ], + "latest_transaction_year": 2020 + } +] + +``` + +
diff --git a/docs/discussion/introduction.md b/docs/discussion/introduction.md index 8315849..33b5e1f 100644 --- a/docs/discussion/introduction.md +++ b/docs/discussion/introduction.md @@ -5,5 +5,3 @@ This section will go through some discussion of the test including: - Data exploration - Cleaning the data - Interpreting the results -- Deploying on GCP DataFlow -- Improvements diff --git a/docs/discussion/results.md b/docs/discussion/results.md new file mode 100644 index 0000000..747841d --- /dev/null +++ b/docs/discussion/results.md @@ -0,0 +1,51 @@ +# Results + +The resulting output `.json` looks like (for the previous example using No. 1 `B90 3LA`): + +```json +[ + { + "property_id": "fe205bfe66bc7f18c50c8f3d77ec3e30", + "readable_address": "1 VERSTONE ROAD\nSHIRLEY\nSOLIHULL\nWEST MIDLANDS\nB90 3LA", + "flat_appartment": "", + "builing": "", + "number": "1", + "street": "VERSTONE ROAD", + "locality": "SHIRLEY", + "town": "SOLIHULL", + "district": "SOLIHULL", + "county": "WEST MIDLANDS", + "postcode": "B90 3LA", + "property_transactions": [ + { + "price": 317500, + "transaction_date": "2020-11-13", + "year": 2020 + } + ], + "latest_transaction_year": 2020 + } +] +``` + +The standard property information is included, we will briefly discuss the additional fields included in this output file. + +## readable_address + +The components that make up the address in the dataset are often repetitive, with the locality, town/city, district and county often sharing the same result. This can result in hard to read addresses if we just stacked all the components sequentially. + +The `readable_address` provides an easy to read address that strips this repetiveness out, by doing pairwise comparisons to each of the four components and applying a mask. The result is an address that could be served to the end user, or easily displayed on a page. + +This saves any user having to apply the same logic to simply display the address somewhere, the full address of a property should be easy to read and easily accessible. + +## property_transactions + +This array contains an object for each transaction for that property that has the price and year as an `int`, with the date having the `00:00` time stripped out. + +## latest_transaction_year + +The date of the latest transaction is extracted from the array of `property_transactions` and placed in the top level of the `json` object. This allows any end user to easily search for properties that haven't been sold in a period of time, without having to write this logic themselves. + +A consumer should be able to use this data to answer questions like: + +- Give me all properties in the town of Solihull that haven't been sold in the past 10 years. diff --git a/mkdocs.yaml b/mkdocs.yaml index 424a20f..d732f6c 100644 --- a/mkdocs.yaml +++ b/mkdocs.yaml @@ -11,6 +11,10 @@ nav: - Data Exploration Report: discussion/exploration.md - Cleaning: discussion/cleaning.md - Approach: discussion/approach.md + - Results: discussion/results.md + - DataFlow: + - Running on DataFlow: dataflow/index.md + - Scaling to the Full DataSet: dataflow/scaling.md - Data Exploration Report: pandas-profiling/report.html theme: name: material diff --git a/notes/documentation/dataflow.md b/notes/documentation/dataflow.md index b5228e6..ddfd1ff 100644 --- a/notes/documentation/dataflow.md +++ b/notes/documentation/dataflow.md @@ -91,3 +91,5 @@ Common use cases: - Part 1 - Part 2 + +Side inputs: From 4d3e5fbc234fef36694fe882029ef5e0f3821a3e Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Mon, 27 Sep 2021 23:58:19 +0100 Subject: [PATCH 59/63] updating latest beam pipeline with default inputs --- analyse_properties/main.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/analyse_properties/main.py b/analyse_properties/main.py index a4f347c..6d43e9d 100644 --- a/analyse_properties/main.py +++ b/analyse_properties/main.py @@ -286,20 +286,12 @@ def run(argv=None, save_main_session=True): """Entrypoint and definition of the pipeline.""" logging.getLogger().setLevel(logging.INFO) - # Default input/output files + # Default input/output files when ran from base of repo with files in ./data input_file = ( - pathlib.Path(__file__).parents[1] - / "data" - / "input" - / "pp-2020.csv" - # / "pp-complete.csv" + pathlib.Path("./data/input/pp-2020.csv") ) output_file = ( - pathlib.Path(__file__).parents[1] - / "data" - / "output" - / "pp-2020" - # / "pp-complete" + pathlib.Path("./data/output/pp-2020") ) # Arguments From 577aa9e3882e1f98affdb95a94e527c74317863a Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Mon, 27 Sep 2021 23:58:27 +0100 Subject: [PATCH 60/63] updating poetry --- poetry.lock | 141 +++++++++++++++++++++++++------------------------ pyproject.toml | 4 +- 2 files changed, 73 insertions(+), 72 deletions(-) diff --git a/poetry.lock b/poetry.lock index 7e7231e..fe4e217 100644 --- a/poetry.lock +++ b/poetry.lock @@ -136,7 +136,7 @@ unicode_backport = ["unicodedata2"] name = "click" version = "8.0.1" description = "Composable command line interface toolkit" -category = "main" +category = "dev" optional = false python-versions = ">=3.6" @@ -148,7 +148,7 @@ importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} name = "colorama" version = "0.4.4" description = "Cross-platform colored terminal text." -category = "main" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" @@ -258,9 +258,9 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "ghp-import" -version = "2.0.1" +version = "2.0.2" description = "Copy your docs directly to the gh-pages branch." -category = "main" +category = "dev" optional = false python-versions = "*" @@ -268,7 +268,7 @@ python-versions = "*" python-dateutil = ">=2.8.1" [package.extras] -dev = ["twine", "markdown", "flake8"] +dev = ["twine", "markdown", "flake8", "wheel"] [[package]] name = "google-api-core" @@ -535,7 +535,7 @@ grpcio = ">=1.0.0,<2.0.0dev" [[package]] name = "grpcio" -version = "1.40.0" +version = "1.41.0" description = "HTTP/2-based RPC framework" category = "main" optional = false @@ -545,7 +545,7 @@ python-versions = "*" six = ">=1.5.2" [package.extras] -protobuf = ["grpcio-tools (>=1.40.0)"] +protobuf = ["grpcio-tools (>=1.41.0)"] [[package]] name = "grpcio-gcp" @@ -622,7 +622,7 @@ six = "*" name = "importlib-metadata" version = "4.8.1" description = "Read metadata from Python packages" -category = "main" +category = "dev" optional = false python-versions = ">=3.6" @@ -653,7 +653,7 @@ plugins = ["setuptools"] name = "jinja2" version = "3.0.1" description = "A very fast and expressive template engine." -category = "main" +category = "dev" optional = false python-versions = ">=3.6" @@ -691,7 +691,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" name = "markdown" version = "3.3.4" description = "Python implementation of Markdown." -category = "main" +category = "dev" optional = false python-versions = ">=3.6" @@ -705,7 +705,7 @@ testing = ["coverage", "pyyaml"] name = "markupsafe" version = "2.0.1" description = "Safely add untrusted strings to HTML/XML markup." -category = "main" +category = "dev" optional = false python-versions = ">=3.6" @@ -737,7 +737,7 @@ python-versions = "*" name = "mergedeep" version = "1.3.4" description = "A deep merge function for 🐍." -category = "main" +category = "dev" optional = false python-versions = ">=3.6" @@ -762,7 +762,7 @@ tests = ["pytest", "pytest-mpl"] name = "mkdocs" version = "1.2.2" description = "Project documentation with Markdown." -category = "main" +category = "dev" optional = false python-versions = ">=3.6" @@ -785,7 +785,7 @@ i18n = ["babel (>=2.9.0)"] name = "mkdocs-material" version = "7.3.0" description = "A Material Design theme for MkDocs" -category = "main" +category = "dev" optional = false python-versions = "*" @@ -800,7 +800,7 @@ pymdown-extensions = ">=7.0" name = "mkdocs-material-extensions" version = "1.0.3" description = "Extension pack for Python Markdown." -category = "main" +category = "dev" optional = false python-versions = ">=3.6" @@ -956,7 +956,7 @@ python-versions = ">=3.6" [[package]] name = "platformdirs" -version = "2.3.0" +version = "2.4.0" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false @@ -1111,7 +1111,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" name = "pygments" version = "2.10.0" description = "Pygments is a syntax highlighting package written in Python." -category = "main" +category = "dev" optional = false python-versions = ">=3.5" @@ -1186,7 +1186,7 @@ pylint = ">=1.7" name = "pymdown-extensions" version = "8.2" description = "Extension pack for Python Markdown." -category = "main" +category = "dev" optional = false python-versions = ">=3.6" @@ -1253,7 +1253,7 @@ numpy = ">=1.13.3" name = "pyyaml" version = "5.4.1" description = "YAML parser and emitter for Python" -category = "main" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" @@ -1261,7 +1261,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" name = "pyyaml-env-tag" version = "0.1" description = "A custom YAML tag for referencing environment variables in YAML files. " -category = "main" +category = "dev" optional = false python-versions = ">=3.6" @@ -1452,7 +1452,7 @@ type_image_path = ["imagehash", "pillow"] name = "watchdog" version = "2.1.5" description = "Filesystem events monitoring" -category = "main" +category = "dev" optional = false python-versions = ">=3.6" @@ -1471,7 +1471,7 @@ python-versions = "*" name = "zipp" version = "3.5.0" description = "Backport of pathlib-compatible object wrapper for zip files" -category = "main" +category = "dev" optional = false python-versions = ">=3.6" @@ -1482,7 +1482,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytes [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "c9292b385b6067c194a7e31bc62ea4c04c99b951d3f4fa1b9b8f081ddf270c4c" +content-hash = "c710ab077268b067a2d2e900a7ca426bac3a9d9512d63ef3b517cd0e55477329" [metadata.files] apache-beam = [ @@ -1601,7 +1601,8 @@ future = [ {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, ] ghp-import = [ - {file = "ghp-import-2.0.1.tar.gz", hash = "sha256:753de2eace6e0f7d4edfb3cce5e3c3b98cd52aadb80163303d1d036bda7b4483"}, + {file = "ghp-import-2.0.2.tar.gz", hash = "sha256:947b3771f11be850c852c64b561c600fdddf794bab363060854c1ee7ad05e071"}, + {file = "ghp_import-2.0.2-py3-none-any.whl", hash = "sha256:5f8962b30b20652cdffa9c5a9812f7de6bcb56ec475acac579807719bf242c46"}, ] google-api-core = [ {file = "google-api-core-1.31.2.tar.gz", hash = "sha256:8500aded318fdb235130bf183c726a05a9cb7c4b09c266bd5119b86cdb8a4d10"}, @@ -1716,50 +1717,50 @@ grpc-google-iam-v1 = [ {file = "grpc-google-iam-v1-0.12.3.tar.gz", hash = "sha256:0bfb5b56f648f457021a91c0df0db4934b6e0c300bd0f2de2333383fe958aa72"}, ] grpcio = [ - {file = "grpcio-1.40.0-cp35-cp35m-macosx_10_10_intel.whl", hash = "sha256:6f8f581787e739945e6cda101f312ea8a7e7082bdbb4993901eb828da6a49092"}, - {file = "grpcio-1.40.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:a4389e26a8f9338ca91effdc5436dfec67d6ecd296368dba115799ae8f8e5bdb"}, - {file = "grpcio-1.40.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:fb06708e3d173e387326abcd5182d52beb60e049db5c3d317bd85509e938afdc"}, - {file = "grpcio-1.40.0-cp35-cp35m-manylinux2014_i686.whl", hash = "sha256:f06e07161c21391682bfcac93a181a037a8aa3d561546690e9d0501189729aac"}, - {file = "grpcio-1.40.0-cp35-cp35m-manylinux2014_x86_64.whl", hash = "sha256:5ff0dcf66315f3f00e1a8eb7244c6a49bdb0cc59bef4fb65b9db8adbd78e6acb"}, - {file = "grpcio-1.40.0-cp35-cp35m-win32.whl", hash = "sha256:ba9dd97ea1738be3e81d34e6bab8ff91a0b80668a4ec81454b283d3c828cebde"}, - {file = "grpcio-1.40.0-cp35-cp35m-win_amd64.whl", hash = "sha256:e12d776a240fee3ebd002519c02d165d94ec636d3fe3d6185b361bfc9a2d3106"}, - {file = "grpcio-1.40.0-cp36-cp36m-linux_armv7l.whl", hash = "sha256:6b9b432f5665dfc802187384693b6338f05c7fc3707ebf003a89bd5132074e27"}, - {file = "grpcio-1.40.0-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:886d056f5101ac513f4aefe4d21a816d98ee3f9a8e77fc3bcb4ae1a3a24efe26"}, - {file = "grpcio-1.40.0-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:b1b34e5a6f1285d1576099c663dae28c07b474015ed21e35a243aff66a0c2aed"}, - {file = "grpcio-1.40.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:17ed13d43450ef9d1f9b78cc932bcf42844ca302235b93026dfd07fb5208d146"}, - {file = "grpcio-1.40.0-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:e19de138199502d575fcec5cf68ae48815a6efe7e5c0d0b8c97eba8c77ae9f0e"}, - {file = "grpcio-1.40.0-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:a812164ceb48cb62c3217bd6245274e693c624cc2ac0c1b11b4cea96dab054dd"}, - {file = "grpcio-1.40.0-cp36-cp36m-manylinux_2_24_aarch64.whl", hash = "sha256:eedc8c3514c10b6f11c6f406877e424ca29610883b97bb97e33b1dd2a9077f6c"}, - {file = "grpcio-1.40.0-cp36-cp36m-win32.whl", hash = "sha256:1708a0ba90c798b4313f541ffbcc25ed47e790adaafb02111204362723dabef0"}, - {file = "grpcio-1.40.0-cp36-cp36m-win_amd64.whl", hash = "sha256:d760a66c9773780837915be85a39d2cd4ab42ef32657c5f1d28475e23ab709fc"}, - {file = "grpcio-1.40.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:8a35b5f87247c893b01abf2f4f7493a18c2c5bf8eb3923b8dd1654d8377aa1a7"}, - {file = "grpcio-1.40.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:45704b9b5b85f9bcb027f90f2563d11d995c1b870a9ee4b3766f6c7ff6fc3505"}, - {file = "grpcio-1.40.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:4967949071c9e435f9565ec2f49700cebeda54836a04710fe21f7be028c0125a"}, - {file = "grpcio-1.40.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:1f9ccc9f5c0d5084d1cd917a0b5ff0142a8d269d0755592d751f8ce9e7d3d7f1"}, - {file = "grpcio-1.40.0-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:5729ca9540049f52c2e608ca110048cfabab3aeaa0d9f425361d9f8ba8506cac"}, - {file = "grpcio-1.40.0-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:edddc849bed3c5dfe215a9f9532a9bd9f670b57d7b8af603be80148b4c69e9a8"}, - {file = "grpcio-1.40.0-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:49155dfdf725c0862c428039123066b25ce61bd38ce50a21ce325f1735aac1bd"}, - {file = "grpcio-1.40.0-cp37-cp37m-win32.whl", hash = "sha256:913916823efa2e487b2ee9735b7759801d97fd1974bacdb1900e3bbd17f7d508"}, - {file = "grpcio-1.40.0-cp37-cp37m-win_amd64.whl", hash = "sha256:24277aab99c346ca36a1aa8589a0624e19a8e6f2b74c83f538f7bb1cc5ee8dbc"}, - {file = "grpcio-1.40.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:a66a30513d2e080790244a7ac3d7a3f45001f936c5c2c9613e41e2a5d7a11794"}, - {file = "grpcio-1.40.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:e2367f2b18dd4ba64cdcd9f626a920f9ec2e8228630839dc8f4a424d461137ea"}, - {file = "grpcio-1.40.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:27dee6dcd1c04c4e9ceea49f6143003569292209d2c24ca100166660805e2440"}, - {file = "grpcio-1.40.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d271e52038dec0db7c39ad9303442d6087c55e09b900e2931b86e837cf0cbc2e"}, - {file = "grpcio-1.40.0-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:41e250ec7cd7523bf49c815b5509d5821728c26fac33681d4b0d1f5f34f59f06"}, - {file = "grpcio-1.40.0-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:33dc4259fecb96e6eac20f760656b911bcb1616aa3e58b3a1d2f125714a2f5d3"}, - {file = "grpcio-1.40.0-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:72b7b8075ee822dad4b39c150d73674c1398503d389e38981e9e35a894c476de"}, - {file = "grpcio-1.40.0-cp38-cp38-win32.whl", hash = "sha256:a93490e6eff5fce3748fb2757cb4273dc21eb1b56732b8c9640fd82c1997b215"}, - {file = "grpcio-1.40.0-cp38-cp38-win_amd64.whl", hash = "sha256:d3b4b41eb0148fca3e6e6fc61d1332a7e8e7c4074fb0d1543f0b255d7f5f1588"}, - {file = "grpcio-1.40.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:fbe3b66bfa2c2f94535f6063f6db62b5b150d55a120f2f9e1175d3087429c4d9"}, - {file = "grpcio-1.40.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:ecfd80e8ea03c46b3ea7ed37d2040fcbfe739004b9e4329b8b602d06ac6fb113"}, - {file = "grpcio-1.40.0-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:d487b4daf84a14741ca1dc1c061ffb11df49d13702cd169b5837fafb5e84d9c0"}, - {file = "grpcio-1.40.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:c26de909cfd54bacdb7e68532a1591a128486af47ee3a5f828df9aa2165ae457"}, - {file = "grpcio-1.40.0-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:1d9eabe2eb2f78208f9ae67a591f73b024488449d4e0a5b27c7fca2d6901a2d4"}, - {file = "grpcio-1.40.0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:4c2baa438f51152c9b7d0835ff711add0b4bc5056c0f5df581a6112153010696"}, - {file = "grpcio-1.40.0-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:bf114be0023b145f7101f392a344692c1efd6de38a610c54a65ed3cba035e669"}, - {file = "grpcio-1.40.0-cp39-cp39-win32.whl", hash = "sha256:5f6d6b638698fa6decf7f040819aade677b583eaa21b43366232cb254a2bbac8"}, - {file = "grpcio-1.40.0-cp39-cp39-win_amd64.whl", hash = "sha256:005fe14e67291498989da67d454d805be31d57a988af28ed3a2a0a7cabb05c53"}, - {file = "grpcio-1.40.0.tar.gz", hash = "sha256:3d172158fe886a2604db1b6e17c2de2ab465fe0fe36aba2ec810ca8441cefe3a"}, + {file = "grpcio-1.41.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:9ecd0fc34aa46eeac24f4d20e67bafaf72ca914f99690bf2898674905eaddaf9"}, + {file = "grpcio-1.41.0-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:d539ebd05a2bbfbf897d41738d37d162d5c3d9f2b1f8ddf2c4f75e2c9cf59907"}, + {file = "grpcio-1.41.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:2410000eb57cf76b05b37d2aee270b686f0a7876710850a2bba92b4ed133e026"}, + {file = "grpcio-1.41.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be3c6ac822edb509aeef41361ca9c8c5ee52cb9e4973e1977d2bb7d6a460fd97"}, + {file = "grpcio-1.41.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0c4bdd1d646365d10ba1468bcf234ea5ad46e8ce2b115983e8563248614910a"}, + {file = "grpcio-1.41.0-cp310-cp310-win32.whl", hash = "sha256:7033199706526e7ee06a362e38476dfdf2ddbad625c19b67ed30411d1bb25a18"}, + {file = "grpcio-1.41.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb64abf0d92134cb0ba4496a3b7ab918588eee42de20e5b3507fe6ee16db97ee"}, + {file = "grpcio-1.41.0-cp36-cp36m-linux_armv7l.whl", hash = "sha256:b6b68c444abbaf4a2b944a61cf35726ab9645f45d416bcc7cf4addc4b2f2d53d"}, + {file = "grpcio-1.41.0-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:5292a627b44b6d3065de4a364ead23bab3c9d7a7c05416a9de0c0624d0fe03f4"}, + {file = "grpcio-1.41.0-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:1820845e7e6410240eff97742e9f76cd5bf10ca01d36a322e86c0bd5340ac25b"}, + {file = "grpcio-1.41.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:462178987f0e5c60d6d1b79e4e95803a4cd789db961d6b3f087245906bb5ae04"}, + {file = "grpcio-1.41.0-cp36-cp36m-manylinux_2_17_aarch64.whl", hash = "sha256:7b07cbbd4eea56738e995fcbba3b60e41fd9aa9dac937fb7985c5dcbc7626260"}, + {file = "grpcio-1.41.0-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a92e4df5330cd384984e04804104ae34f521345917813aa86fc0930101a3697"}, + {file = "grpcio-1.41.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ccd2f1cf11768d1f6fbe4e13e8b8fb0ccfe9914ceeff55a367d5571e82eeb543"}, + {file = "grpcio-1.41.0-cp36-cp36m-win32.whl", hash = "sha256:59645b2d9f19b5ff30cb46ddbcaa09c398f9cd81e4e476b21c7c55ae1e942807"}, + {file = "grpcio-1.41.0-cp36-cp36m-win_amd64.whl", hash = "sha256:0abd56d90dff3ed566807520de1385126dded21e62d3490a34c180a91f94c1f4"}, + {file = "grpcio-1.41.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:9674a9d3f23702e35a89e22504f41b467893cf704f627cc9cdd118cf1dcc8e26"}, + {file = "grpcio-1.41.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:c95dd6e60e059ff770a2ac9f5a202b75dd64d76b0cd0c48f27d58907e43ed6a6"}, + {file = "grpcio-1.41.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:a3cd7f945d3e3b82ebd2a4c9862eb9891a5ac87f84a7db336acbeafd86e6c402"}, + {file = "grpcio-1.41.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:c07acd49541f5f6f9984fe0adf162d77bf70e0f58e77f9960c6f571314ff63a4"}, + {file = "grpcio-1.41.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:7da3f6f6b857399c9ad85bcbffc83189e547a0a1a777ab68f5385154f8bc1ed4"}, + {file = "grpcio-1.41.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39ce785f0cbd07966a9019386b7a054615b2da63da3c7727f371304d000a1890"}, + {file = "grpcio-1.41.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07594e585a5ba25cf331ddb63095ca51010c34e328a822cb772ffbd5daa62cb5"}, + {file = "grpcio-1.41.0-cp37-cp37m-win32.whl", hash = "sha256:3bbeee115b05b22f6a9fa9bc78f9ab8d9d6bb8c16fdfc60401fc8658beae1099"}, + {file = "grpcio-1.41.0-cp37-cp37m-win_amd64.whl", hash = "sha256:dcb5f324712a104aca4a459e524e535f205f36deb8005feb4f9d3ff0a22b5177"}, + {file = "grpcio-1.41.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:83c1e731c2b76f26689ad88534cafefe105dcf385567bead08f5857cb308246b"}, + {file = "grpcio-1.41.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:5d4b30d068b022e412adcf9b14c0d9bcbc872e9745b91467edc0a4c700a8bba6"}, + {file = "grpcio-1.41.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d71aa430b2ac40e18e388504ac34cc91d49d811855ca507c463a21059bf364f0"}, + {file = "grpcio-1.41.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:c8c5bc498f6506b6041c30afb7a55c57a9fd535d1a0ac7cdba9b5fd791a85633"}, + {file = "grpcio-1.41.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:a144f6cecbb61aace12e5920840338a3d246123a41d795e316e2792e9775ad15"}, + {file = "grpcio-1.41.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e516124010ef60d5fc2e0de0f1f987599249dc55fd529001f17f776a4145767f"}, + {file = "grpcio-1.41.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1e0a4c86d4cbd93059d5eeceed6e1c2e3e1494e1bf40be9b8ab14302c576162"}, + {file = "grpcio-1.41.0-cp38-cp38-win32.whl", hash = "sha256:a614224719579044bd7950554d3b4c1793bb5715cbf0f0399b1f21d283c40ef6"}, + {file = "grpcio-1.41.0-cp38-cp38-win_amd64.whl", hash = "sha256:b2de4e7b5a930be04a4d05c9f5fce7e9191217ccdc174b026c2a7928770dca9f"}, + {file = "grpcio-1.41.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:056806e83eaa09d0af0e452dd353db8f7c90aa2dedcce1112a2d21592550f6b1"}, + {file = "grpcio-1.41.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:5502832b7cec670a880764f51a335a19b10ff5ab2e940e1ded67f39b88aa02b1"}, + {file = "grpcio-1.41.0-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:585847ed190ea9cb4d632eb0ebf58f1d299bbca5e03284bc3d0fa08bab6ea365"}, + {file = "grpcio-1.41.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:d0cc0393744ce3ce1b237ae773635cc928470ff46fb0d3f677e337a38e5ed4f6"}, + {file = "grpcio-1.41.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:2882b62f74de8c8a4f7b2be066f6230ecc46f4edc8f42db1fb7358200abe3b25"}, + {file = "grpcio-1.41.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:297ee755d3c6cd7e7d3770f298f4d4d4b000665943ae6d2888f7407418a9a510"}, + {file = "grpcio-1.41.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ace080a9c3c673c42adfd2116875a63fec9613797be01a6105acf7721ed0c693"}, + {file = "grpcio-1.41.0-cp39-cp39-win32.whl", hash = "sha256:1bcbeac764bbae329bc2cc9e95d0f4d3b0fb456b92cf12e7e06e3e860a4b31cf"}, + {file = "grpcio-1.41.0-cp39-cp39-win_amd64.whl", hash = "sha256:4537bb9e35af62c5189493792a8c34d127275a6d175c8ad48b6314cacba4021e"}, + {file = "grpcio-1.41.0.tar.gz", hash = "sha256:15c04d695833c739dbb25c88eaf6abd9a461ec0dbd32f44bc8769335a495cf5a"}, ] grpcio-gcp = [ {file = "grpcio-gcp-0.2.2.tar.gz", hash = "sha256:e292605effc7da39b7a8734c719afb12ec4b5362add3528d8afad3aa3aa9057c"}, @@ -2153,8 +2154,8 @@ pillow = [ {file = "Pillow-8.3.2.tar.gz", hash = "sha256:dde3f3ed8d00c72631bc19cbfff8ad3b6215062a5eed402381ad365f82f0c18c"}, ] platformdirs = [ - {file = "platformdirs-2.3.0-py3-none-any.whl", hash = "sha256:8003ac87717ae2c7ee1ea5a84a1a61e87f3fbd16eb5aadba194ea30a9019f648"}, - {file = "platformdirs-2.3.0.tar.gz", hash = "sha256:15b056538719b1c94bdaccb29e5f81879c7f7f0f4a153f46086d155dffcd4f0f"}, + {file = "platformdirs-2.4.0-py3-none-any.whl", hash = "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d"}, + {file = "platformdirs-2.4.0.tar.gz", hash = "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2"}, ] prospector = [ {file = "prospector-1.5.1-py3-none-any.whl", hash = "sha256:47f8ff3fd36ae276967eb392ca20b300a7bdea66c0d0252250a4d89a6c03ab15"}, diff --git a/pyproject.toml b/pyproject.toml index 0f73a0c..133d21a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,13 +7,13 @@ authors = ["Daniel Tomlinson "] [tool.poetry.dependencies] python = "^3.7" apache-beam = {extras = ["gcp"], version = "^2.32.0"} -mkdocs = "^1.2.2" -mkdocs-material = "^7.3.0" [tool.poetry.dev-dependencies] # pytest = "^5.2" prospector = "^1.5.1" pandas-profiling = "^3.0.0" +mkdocs = "^1.2.2" +mkdocs-material = "^7.3.0" [build-system] requires = ["poetry-core>=1.0.0"] From c481c1a97681de2457e76e67f762a6eefd15c9de Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Tue, 28 Sep 2021 00:07:08 +0100 Subject: [PATCH 61/63] adding requirements.txt --- requirements.txt | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..6389478 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,53 @@ +apache-beam==2.32.0; python_version >= "3.6" +avro-python3==1.9.2.1; python_version >= "3.6" +cachetools==4.2.2; python_version >= "3.6" and python_version < "4.0" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.6.0") +certifi==2021.5.30; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" +charset-normalizer==2.0.6; python_full_version >= "3.6.0" and python_version >= "3.6" +crcmod==1.7; python_version >= "3.6" +dill==0.3.1.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.1.0" and python_version >= "3.6" +docopt==0.6.2; python_version >= "3.6" +fastavro==1.4.5; python_version >= "3.6" +fasteners==0.16.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" +future==0.18.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6" +google-api-core==1.31.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.6.0" +google-apitools==0.5.31; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" +google-auth==1.35.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.6.0" +google-cloud-bigquery==2.6.1; python_version >= "3.6" +google-cloud-bigtable==1.7.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0" +google-cloud-core==1.7.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.6.0" +google-cloud-datastore==1.15.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0" +google-cloud-dlp==1.0.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0" +google-cloud-language==1.3.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0" +google-cloud-pubsub==1.7.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" +google-cloud-recommendations-ai==0.2.0; python_version >= "3.6" +google-cloud-spanner==1.19.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0" +google-cloud-videointelligence==1.16.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0" +google-cloud-vision==1.0.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0" +google-crc32c==1.2.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.6.0" +google-resumable-media==1.3.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.6.0" +googleapis-common-protos==1.53.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.6.0" +grpc-google-iam-v1==0.12.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" +grpcio-gcp==0.2.2; python_version >= "3.6" +grpcio==1.41.0; python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0") +hdfs==2.6.0; python_version >= "3.6" +httplib2==0.19.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" +idna==3.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" +numpy==1.20.3; python_version >= "3.7" +oauth2client==4.1.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" +orjson==3.6.3; python_version >= "3.7" +packaging==21.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.6.0" +proto-plus==1.19.0; python_version >= "3.6" +protobuf==3.18.0; python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.6.0") +pyarrow==4.0.1; python_version >= "3.6" +pyasn1-modules==0.2.8; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.6.0" +pyasn1==0.4.8; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.6.0") or python_version >= "3.6" and python_full_version >= "3.6.0" and python_version < "4" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.6.0") +pydot==1.4.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" +pymongo==3.12.0; python_version >= "3.6" +pyparsing==2.4.7; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" +python-dateutil==2.8.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6" +pytz==2021.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.6.0" +requests==2.26.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" +rsa==4.7.2; python_version >= "3.6" and python_version < "4" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.6.0") +six==1.16.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.6.0" +typing-extensions==3.7.4.3; python_version >= "3.6" +urllib3==1.26.7; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version < "4" and python_version >= "3.6" From 8a0d8085a2cf98ba0981d73150ca71e762352c5e Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Tue, 28 Sep 2021 00:29:41 +0100 Subject: [PATCH 62/63] updating documentation --- docs/dataflow/index.md | 3 --- docs/dataflow/scaling.md | 2 +- docs/discussion/approach.md | 2 +- docs/discussion/cleaning.md | 4 ++-- docs/documentation/installation.md | 21 +++++++++++++-------- docs/documentation/usage.md | 17 ++++++++++------- docs/index.md | 2 +- 7 files changed, 28 insertions(+), 23 deletions(-) diff --git a/docs/dataflow/index.md b/docs/dataflow/index.md index a21fc9a..70cd31a 100644 --- a/docs/dataflow/index.md +++ b/docs/dataflow/index.md @@ -27,9 +27,6 @@ To get around public IP quotas I created a VPC in the `europe-west1` region that Assuming the `pp-2020.csv` file has been placed in the `./input` directory in the bucket you can run a command similar to: -!!! caution - Use the command `python -m analyse_properties.main` as the entrypoint to the pipeline and not `analyse-properties` as the module isn't installed with poetry on the workers with the configuration below. - ```bash python -m analyse_properties.main \ --runner DataflowRunner \ diff --git a/docs/dataflow/scaling.md b/docs/dataflow/scaling.md index 6cd10a3..66d6b1c 100644 --- a/docs/dataflow/scaling.md +++ b/docs/dataflow/scaling.md @@ -55,7 +55,7 @@ A possible solution would be to leverage BigQuery to store the results of the ma In addition to creating the mapping table `(key, value)` pairs, we also save these pairs to BigQuery at this stage. We then yield the element as it is currently written to allow the subsequent stages to make use of this data. -Remove the condense mapping table stage as it is no longer needed. +Remove the condense mapping table stage as it is no longer needed (which also saves a bit of time). Instead of using: diff --git a/docs/discussion/approach.md b/docs/discussion/approach.md index 252e0e5..343c917 100644 --- a/docs/discussion/approach.md +++ b/docs/discussion/approach.md @@ -21,7 +21,7 @@ The mapping table takes each row and creates a `(key,value)` pair with: - The key being the id across all columns (`id_all_columns`). - The value being the raw data as an array. -The mapping table is then condensed to a single dictionary with these key, value pairs and is used as a side input further down the pipeline. +The mapping table is then condensed to a single dictionary with these key, value pairs (automatically deduplicating repeated rows) and is used as a side input further down the pipeline. This mapping table is created to ensure the `GroupByKey` operation is as quick as possible. The more data you have to process in a `GroupByKey`, the longer the operation takes. By doing the `GroupByKey` using just the ids, the pipeline can process the files much quicker than if we included the raw data in this operation. diff --git a/docs/discussion/cleaning.md b/docs/discussion/cleaning.md index 314a829..8daaa58 100644 --- a/docs/discussion/cleaning.md +++ b/docs/discussion/cleaning.md @@ -64,7 +64,7 @@ We strip all leading/trailing whitespace from each column to enforce consistency Some of the data is repeated: -- Some rows repeated, with the same date + price + address information but with a unique transaction id. +- Some rows are repeated, with the same date + price + address information but with a unique transaction id.
Example (PCollection) @@ -87,7 +87,7 @@ Some of the data is repeated: ] }, { - "fd4634faec47c29de40bbf7840723b41": [ + "gd4634faec47c29de40bbf7840723b42": [ "317500", "2020-11-13 00:00", "B90 3LA", diff --git a/docs/documentation/installation.md b/docs/documentation/installation.md index fca1f70..c2ebd22 100644 --- a/docs/documentation/installation.md +++ b/docs/documentation/installation.md @@ -6,21 +6,26 @@ The task has been tested on MacOS Big Sur and WSL2. The task should run on Windo For Beam 2.32.0 the supported versions of the Python SDK can be found [here](https://cloud.google.com/dataflow/docs/concepts/sdk-worker-dependencies#sdk-for-python). -## Poetry +## Pip -The test uses [Poetry](https://python-poetry.org) for dependency management. - -!!! info inline end - If you already have Poetry installed globally you can go straight to the `poetry install` step. - -In a virtual environment install poetry: +In a virtual environment run from the root of the repo: ```bash -pip install poetry +pip install -r requirements.txt ``` +## Poetry (Alternative) + +Install [Poetry](https://python-poetry.org) *globally* + From the root of the repo install the dependencies with: ```bash poetry install --no-dev ``` + +Activate the shell with: + +```bash +poetry shell +``` diff --git a/docs/documentation/usage.md b/docs/documentation/usage.md index 1c19bbd..bf6192f 100644 --- a/docs/documentation/usage.md +++ b/docs/documentation/usage.md @@ -2,7 +2,7 @@ This page documents how to run the pipeline locally to complete the task for the [dataset for 2020](https://www.gov.uk/government/statistical-data-sets/price-paid-data-downloads#section-1). -The pipeline also runs in GCP using DataFlow and is discussed further on but can be viewed here. We also discuss how to adapt the pipeline so it can run against [the full dataset](https://www.gov.uk/government/statistical-data-sets/price-paid-data-downloads#single-file). +The pipeline also runs in GCP using DataFlow and is discussed further on but can be viewed [here](../dataflow/index.md). We also discuss how to adapt the pipeline so it can run against [the full dataset](https://www.gov.uk/government/statistical-data-sets/price-paid-data-downloads#single-file). ## Download dataset @@ -20,20 +20,20 @@ to download the data for 2020 and place in the input directory above. ## Entrypoint -The entrypoint to the pipeline is `analyse-properties`. +The entrypoint to the pipeline is `analyse_properties.main`. ## Available options Running ```bash -analyse-properties --help +python -m analyse_properties.main --help ``` gives the following output: ```bash -usage: analyse-properties [-h] [--input INPUT] [--output OUTPUT] +usage: analyse_properties.main [-h] [--input INPUT] [--output OUTPUT] optional arguments: -h, --help show this help message and exit @@ -43,14 +43,17 @@ optional arguments: The default value for input is `./data/input/pp-2020.csv` and the default value for output is `./data/output/pp-2020`. -If passing in values for `input`/`output` these should be **full** paths to the files. The test will parse these inputs as a `str()` and pass this to `#!python beam.io.ReadFromText()`. - ## Run the pipeline To run the pipeline and complete the task run: ```bash -analyse-properties --runner DirectRunner +python -m analyse_properties.main \ +--runner DirectRunner \ +--input ./data/input/pp-2020.csv \ +--output ./data/output/pp-2020 ``` +from the root of the repo. + The pipeline will use the 2020 dataset located in `./data/input` and output the resulting `.json` to `./data/output`. diff --git a/docs/index.md b/docs/index.md index 6164af6..9fc56e2 100644 --- a/docs/index.md +++ b/docs/index.md @@ -4,7 +4,7 @@ This documentation accompanies the technical test for the Street Group. -The following pages will guide the user through installing the requirements, and running the task to complete the test. In addition, there is some discussion around the approach, and any improvements that could be made. +The following pages will guide the user through installing the requirements, and running the task to complete the test. In addition, there is some discussion around the approach, and scaling the pipeline. Navigate sections using the tabs at the top of the page. Pages in this section can be viewed in order by using the section links in the left menu, or by using bar at the bottom of the page. The table of contents in the right menu can be used to navigate sections on each page. From e172b704a7ca78cabc87b8ba12e93ed7543801e7 Mon Sep 17 00:00:00 2001 From: Daniel Tomlinson Date: Tue, 28 Sep 2021 10:47:28 +0100 Subject: [PATCH 63/63] typo in documentation --- docs/dataflow/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dataflow/index.md b/docs/dataflow/index.md index 70cd31a..01106df 100644 --- a/docs/dataflow/index.md +++ b/docs/dataflow/index.md @@ -40,7 +40,7 @@ python -m analyse_properties.main \ --worker_machine_type=n1-highmem-2 ``` -The output file from this pipeline is publically available and can be downloaded [here](https://storage.googleapis.com/street-group-technical-test-dmot-euw1/output/pp-2020-00000-of-00001.json). +The output file from this pipeline is publicly available and can be downloaded [here](https://storage.googleapis.com/street-group-technical-test-dmot-euw1/output/pp-2020-00000-of-00001.json). The job graph for this pipeline is displayed below: