mirror of
				https://github.com/enpaul/tox-poetry-installer.git
				synced 2025-10-30 07:20:49 +00:00 
			
		
		
		
	Compare commits
	
		
			7 Commits
		
	
	
		
			dependabot
			...
			1d3b7834c6
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 1d3b7834c6 | |||
| a270261e6c | |||
| fdaee670c4 | |||
| 62f90de297 | |||
| f853a4b0b7 | |||
| 0a46b2d876 | |||
| c06cdfe8c2 | 
| @@ -227,7 +227,6 @@ error will be set to one of the "Status" values below to indicate what the error | |||||||
| | `LockedDepNotFoundError`        | Indicates that an item specified in the `locked_deps` config option does not match the name of a package in the Poetry lockfile.                                                                                                | | | `LockedDepNotFoundError`        | Indicates that an item specified in the `locked_deps` config option does not match the name of a package in the Poetry lockfile.                                                                                                | | ||||||
| | `LockedDepsRequiredError`       | Indicates that a test environment with the `require_locked_deps` config option set to `true` also specified unlocked dependencies using the [`deps`](https://tox.readthedocs.io/en/latest/config.html#conf-deps) config option. | | | `LockedDepsRequiredError`       | Indicates that a test environment with the `require_locked_deps` config option set to `true` also specified unlocked dependencies using the [`deps`](https://tox.readthedocs.io/en/latest/config.html#conf-deps) config option. | | ||||||
| | `PoetryNotInstalledError`       | Indicates that the `poetry` module could not be imported under the current runtime environment, and `require_poetry = true` was specified.                                                                                      | | | `PoetryNotInstalledError`       | Indicates that the `poetry` module could not be imported under the current runtime environment, and `require_poetry = true` was specified.                                                                                      | | ||||||
| | `RequiresUnsafeDepError`        | Indicates that the package-under-test depends on a package that Poetry has classified as unsafe and cannot be installed.                                                                                                        | |  | ||||||
|  |  | ||||||
| > ℹ️ **Note:** One or more of these errors can be caused by the `pyproject.toml` being out | > ℹ️ **Note:** One or more of these errors can be caused by the `pyproject.toml` being out | ||||||
| > of sync with the Poetry lockfile. If this is the case, than a warning will be logged | > of sync with the Poetry lockfile. If this is the case, than a warning will be logged | ||||||
|   | |||||||
							
								
								
									
										1629
									
								
								poetry.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1629
									
								
								poetry.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -34,13 +34,10 @@ classifiers = [ | |||||||
| [tool.poetry.plugins.tox] | [tool.poetry.plugins.tox] | ||||||
| poetry_installer = "tox_poetry_installer" | poetry_installer = "tox_poetry_installer" | ||||||
|  |  | ||||||
| [tool.poetry.extras] |  | ||||||
| poetry = ["poetry", "cleo"] |  | ||||||
|  |  | ||||||
| [tool.poetry.dependencies] | [tool.poetry.dependencies] | ||||||
| python = "^3.7" | python = "^3.7" | ||||||
| cleo = {version = ">=1.0,<3.0", optional = true} | cleo = ">=1.0,<3.0" | ||||||
| poetry = {version = "^1.5.0", optional = true} | poetry = "^1.5.0" | ||||||
| poetry-core = "^1.1.0" | poetry-core = "^1.1.0" | ||||||
| tox = "^4" | tox = "^4" | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										525
									
								
								tests/test-project/poetry.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										525
									
								
								tests/test-project/poetry.lock
									
									
									
										generated
									
									
									
								
							| @@ -1,109 +1,80 @@ | |||||||
| # This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. |  | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "appdirs" | name = "appdirs" | ||||||
| version = "1.4.4" | version = "1.4.4" | ||||||
| description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." | description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." | ||||||
|  | category = "main" | ||||||
| optional = false | optional = false | ||||||
| python-versions = "*" | python-versions = "*" | ||||||
| files = [ |  | ||||||
|     {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, |  | ||||||
|     {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, |  | ||||||
| ] |  | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "attrs" | name = "attrs" | ||||||
| version = "20.3.0" | version = "20.3.0" | ||||||
| description = "Classes Without Boilerplate" | description = "Classes Without Boilerplate" | ||||||
|  | category = "main" | ||||||
| optional = false | optional = false | ||||||
| python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" | ||||||
| files = [ |  | ||||||
|     {file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"}, |  | ||||||
|     {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"}, |  | ||||||
| ] |  | ||||||
|  |  | ||||||
| [package.extras] | [package.extras] | ||||||
| dev = ["coverage[toml] (>=5.0.2)", "furo", "hypothesis", "pre-commit", "pympler", "pytest (>=4.3.0)", "six", "sphinx", "zope.interface"] | dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] | ||||||
| docs = ["furo", "sphinx", "zope.interface"] | docs = ["furo", "sphinx", "zope.interface"] | ||||||
| tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] | tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] | ||||||
| tests-no-zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] | tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "certifi" | name = "certifi" | ||||||
| version = "2020.12.5" | version = "2020.12.5" | ||||||
| description = "Python package for providing Mozilla's CA Bundle." | description = "Python package for providing Mozilla's CA Bundle." | ||||||
|  | category = "main" | ||||||
| optional = false | optional = false | ||||||
| python-versions = "*" | python-versions = "*" | ||||||
| files = [ |  | ||||||
|     {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, |  | ||||||
|     {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"}, |  | ||||||
| ] |  | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "chardet" | name = "chardet" | ||||||
| version = "4.0.0" | version = "4.0.0" | ||||||
| description = "Universal encoding detector for Python 2 and 3" | description = "Universal encoding detector for Python 2 and 3" | ||||||
|  | category = "main" | ||||||
| optional = false | optional = false | ||||||
| python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" | ||||||
| files = [ |  | ||||||
|     {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, |  | ||||||
|     {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, |  | ||||||
| ] |  | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "click" | name = "click" | ||||||
| version = "7.1.2" | version = "7.1.2" | ||||||
| description = "Composable command line interface toolkit" | description = "Composable command line interface toolkit" | ||||||
|  | category = "main" | ||||||
| optional = false | optional = false | ||||||
| python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" | ||||||
| files = [ |  | ||||||
|     {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, |  | ||||||
|     {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, |  | ||||||
| ] |  | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "colorama" | name = "colorama" | ||||||
| version = "0.4.4" | version = "0.4.4" | ||||||
| description = "Cross-platform colored terminal text." | description = "Cross-platform colored terminal text." | ||||||
|  | category = "main" | ||||||
| optional = false | optional = false | ||||||
| python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" | ||||||
| files = [ |  | ||||||
|     {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, |  | ||||||
|     {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, |  | ||||||
| ] |  | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "distlib" | name = "distlib" | ||||||
| version = "0.3.1" | version = "0.3.1" | ||||||
| description = "Distribution utilities" | description = "Distribution utilities" | ||||||
|  | category = "main" | ||||||
| optional = false | optional = false | ||||||
| python-versions = "*" | python-versions = "*" | ||||||
| files = [ |  | ||||||
|     {file = "distlib-0.3.1-py2.py3-none-any.whl", hash = "sha256:8c09de2c67b3e7deef7184574fc060ab8a793e7adbb183d942c389c8b13c52fb"}, |  | ||||||
|     {file = "distlib-0.3.1.zip", hash = "sha256:edf6116872c863e1aa9d5bb7cb5e05a022c519a4594dc703843343a9ddd9bff1"}, |  | ||||||
| ] |  | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "filelock" | name = "filelock" | ||||||
| version = "3.0.12" | version = "3.0.12" | ||||||
| description = "A platform independent file lock." | description = "A platform independent file lock." | ||||||
|  | category = "main" | ||||||
| optional = false | optional = false | ||||||
| python-versions = "*" | python-versions = "*" | ||||||
| files = [ |  | ||||||
|     {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"}, |  | ||||||
|     {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"}, |  | ||||||
| ] |  | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "flask" | name = "flask" | ||||||
| version = "1.1.2" | version = "1.1.2" | ||||||
| description = "A simple framework for building complex web applications." | description = "A simple framework for building complex web applications." | ||||||
|  | category = "main" | ||||||
| optional = false | optional = false | ||||||
| python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" | ||||||
| files = [ |  | ||||||
|     {file = "Flask-1.1.2-py2.py3-none-any.whl", hash = "sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"}, |  | ||||||
|     {file = "Flask-1.1.2.tar.gz", hash = "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060"}, |  | ||||||
| ] |  | ||||||
|  |  | ||||||
| [package.dependencies] | [package.dependencies] | ||||||
| click = ">=5.1" | click = ">=5.1" | ||||||
| @@ -112,79 +83,64 @@ Jinja2 = ">=2.10.1" | |||||||
| Werkzeug = ">=0.15" | Werkzeug = ">=0.15" | ||||||
|  |  | ||||||
| [package.extras] | [package.extras] | ||||||
| dev = ["coverage", "pallets-sphinx-themes", "pytest", "sphinx", "sphinx-issues", "sphinxcontrib-log-cabinet", "tox"] | dev = ["pytest", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"] | ||||||
| docs = ["pallets-sphinx-themes", "sphinx", "sphinx-issues", "sphinxcontrib-log-cabinet"] | docs = ["sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"] | ||||||
| dotenv = ["python-dotenv"] | dotenv = ["python-dotenv"] | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "idna" | name = "idna" | ||||||
| version = "2.10" | version = "2.10" | ||||||
| description = "Internationalized Domain Names in Applications (IDNA)" | description = "Internationalized Domain Names in Applications (IDNA)" | ||||||
|  | category = "main" | ||||||
| optional = false | optional = false | ||||||
| python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" | ||||||
| files = [ |  | ||||||
|     {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, |  | ||||||
|     {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, |  | ||||||
| ] |  | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "importlib-metadata" | name = "importlib-metadata" | ||||||
| version = "3.10.1" | version = "3.10.1" | ||||||
| description = "Read metadata from Python packages" | description = "Read metadata from Python packages" | ||||||
|  | category = "main" | ||||||
| optional = false | optional = false | ||||||
| python-versions = ">=3.6" | python-versions = ">=3.6" | ||||||
| files = [ |  | ||||||
|     {file = "importlib_metadata-3.10.1-py3-none-any.whl", hash = "sha256:2ec0faae539743ae6aaa84b49a169670a465f7f5d64e6add98388cc29fd1f2f6"}, |  | ||||||
|     {file = "importlib_metadata-3.10.1.tar.gz", hash = "sha256:c9356b657de65c53744046fa8f7358afe0714a1af7d570c00c3835c2d724a7c1"}, |  | ||||||
| ] |  | ||||||
|  |  | ||||||
| [package.dependencies] | [package.dependencies] | ||||||
| typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} | typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} | ||||||
| zipp = ">=0.5" | zipp = ">=0.5" | ||||||
|  |  | ||||||
| [package.extras] | [package.extras] | ||||||
| docs = ["jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx"] | docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] | ||||||
| testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pep517", "pyfakefs", "pytest (>=4.6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-flake8", "pytest-mypy"] | testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "importlib-resources" | name = "importlib-resources" | ||||||
| version = "5.1.2" | version = "5.1.2" | ||||||
| description = "Read resources from Python packages" | description = "Read resources from Python packages" | ||||||
|  | category = "main" | ||||||
| optional = false | optional = false | ||||||
| python-versions = ">=3.6" | python-versions = ">=3.6" | ||||||
| files = [ |  | ||||||
|     {file = "importlib_resources-5.1.2-py3-none-any.whl", hash = "sha256:ebab3efe74d83b04d6bf5cd9a17f0c5c93e60fb60f30c90f56265fce4682a469"}, |  | ||||||
|     {file = "importlib_resources-5.1.2.tar.gz", hash = "sha256:642586fc4740bd1cad7690f836b3321309402b20b332529f25617ff18e8e1370"}, |  | ||||||
| ] |  | ||||||
|  |  | ||||||
| [package.dependencies] | [package.dependencies] | ||||||
| zipp = {version = ">=0.4", markers = "python_version < \"3.8\""} | zipp = {version = ">=0.4", markers = "python_version < \"3.8\""} | ||||||
|  |  | ||||||
| [package.extras] | [package.extras] | ||||||
| docs = ["jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx"] | docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] | ||||||
| testing = ["pytest (>=4.6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=1.2.3)", "pytest-cov", "pytest-enabler", "pytest-flake8", "pytest-mypy"] | testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "pytest-black (>=0.3.7)", "pytest-mypy"] | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "itsdangerous" | name = "itsdangerous" | ||||||
| version = "1.1.0" | version = "1.1.0" | ||||||
| description = "Various helpers to pass data to untrusted environments and back." | description = "Various helpers to pass data to untrusted environments and back." | ||||||
|  | category = "main" | ||||||
| optional = false | optional = false | ||||||
| python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" | ||||||
| files = [ |  | ||||||
|     {file = "itsdangerous-1.1.0-py2.py3-none-any.whl", hash = "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"}, |  | ||||||
|     {file = "itsdangerous-1.1.0.tar.gz", hash = "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19"}, |  | ||||||
| ] |  | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "jinja2" | name = "jinja2" | ||||||
| version = "2.11.3" | version = "2.11.3" | ||||||
| description = "A very fast and expressive template engine." | description = "A very fast and expressive template engine." | ||||||
|  | category = "main" | ||||||
| optional = false | optional = false | ||||||
| python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" | ||||||
| files = [ |  | ||||||
|     {file = "Jinja2-2.11.3-py2.py3-none-any.whl", hash = "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419"}, |  | ||||||
|     {file = "Jinja2-2.11.3.tar.gz", hash = "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"}, |  | ||||||
| ] |  | ||||||
|  |  | ||||||
| [package.dependencies] | [package.dependencies] | ||||||
| MarkupSafe = ">=0.23" | MarkupSafe = ">=0.23" | ||||||
| @@ -196,9 +152,247 @@ i18n = ["Babel (>=0.8)"] | |||||||
| name = "markupsafe" | name = "markupsafe" | ||||||
| version = "1.1.1" | version = "1.1.1" | ||||||
| description = "Safely add untrusted strings to HTML/XML markup." | description = "Safely add untrusted strings to HTML/XML markup." | ||||||
|  | category = "main" | ||||||
| optional = false | optional = false | ||||||
| python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" | python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" | ||||||
| files = [ |  | ||||||
|  | [[package]] | ||||||
|  | name = "packaging" | ||||||
|  | version = "20.9" | ||||||
|  | description = "Core utilities for Python packages" | ||||||
|  | category = "main" | ||||||
|  | optional = false | ||||||
|  | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" | ||||||
|  |  | ||||||
|  | [package.dependencies] | ||||||
|  | pyparsing = ">=2.0.2" | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "pluggy" | ||||||
|  | version = "0.13.1" | ||||||
|  | description = "plugin and hook calling mechanisms for python" | ||||||
|  | category = "main" | ||||||
|  | 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 = "main" | ||||||
|  | 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 = "main" | ||||||
|  | optional = false | ||||||
|  | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "python-dateutil" | ||||||
|  | version = "2.8.1" | ||||||
|  | description = "Extensions to the standard Python datetime module" | ||||||
|  | category = "main" | ||||||
|  | optional = false | ||||||
|  | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" | ||||||
|  |  | ||||||
|  | [package.dependencies] | ||||||
|  | six = ">=1.5" | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "requests" | ||||||
|  | version = "2.25.1" | ||||||
|  | description = "Python HTTP for Humans." | ||||||
|  | category = "main" | ||||||
|  | optional = false | ||||||
|  | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" | ||||||
|  |  | ||||||
|  | [package.dependencies] | ||||||
|  | certifi = ">=2017.4.17" | ||||||
|  | chardet = ">=3.0.2,<5" | ||||||
|  | idna = ">=2.5,<3" | ||||||
|  | urllib3 = ">=1.21.1,<1.27" | ||||||
|  |  | ||||||
|  | [package.extras] | ||||||
|  | security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] | ||||||
|  | socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "six" | ||||||
|  | version = "1.15.0" | ||||||
|  | description = "Python 2 and 3 compatibility utilities" | ||||||
|  | category = "main" | ||||||
|  | optional = false | ||||||
|  | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "toml" | ||||||
|  | version = "0.10.2" | ||||||
|  | description = "Python Library for Tom's Obvious, Minimal Language" | ||||||
|  | category = "main" | ||||||
|  | optional = false | ||||||
|  | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "tox" | ||||||
|  | version = "3.23.0" | ||||||
|  | description = "tox is a generic virtualenv management and test command line tool" | ||||||
|  | category = "main" | ||||||
|  | optional = false | ||||||
|  | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" | ||||||
|  |  | ||||||
|  | [package.dependencies] | ||||||
|  | colorama = {version = ">=0.4.1", markers = "platform_system == \"Windows\""} | ||||||
|  | filelock = ">=3.0.0" | ||||||
|  | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} | ||||||
|  | packaging = ">=14" | ||||||
|  | pluggy = ">=0.12.0" | ||||||
|  | py = ">=1.4.17" | ||||||
|  | six = ">=1.14.0" | ||||||
|  | toml = ">=0.9.4" | ||||||
|  | virtualenv = ">=16.0.0,<20.0.0 || >20.0.0,<20.0.1 || >20.0.1,<20.0.2 || >20.0.2,<20.0.3 || >20.0.3,<20.0.4 || >20.0.4,<20.0.5 || >20.0.5,<20.0.6 || >20.0.6,<20.0.7 || >20.0.7" | ||||||
|  |  | ||||||
|  | [package.extras] | ||||||
|  | docs = ["pygments-github-lexers (>=0.0.5)", "sphinx (>=2.0.0)", "sphinxcontrib-autoprogram (>=0.1.5)", "towncrier (>=18.5.0)"] | ||||||
|  | testing = ["flaky (>=3.4.0)", "freezegun (>=0.3.11)", "psutil (>=5.6.1)", "pytest (>=4.0.0)", "pytest-cov (>=2.5.1)", "pytest-mock (>=1.10.0)", "pytest-randomly (>=1.0.0)", "pytest-xdist (>=1.22.2)", "pathlib2 (>=2.3.3)"] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "typing-extensions" | ||||||
|  | version = "3.7.4.3" | ||||||
|  | description = "Backported and Experimental Type Hints for Python 3.5+" | ||||||
|  | category = "main" | ||||||
|  | optional = false | ||||||
|  | python-versions = "*" | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "urllib3" | ||||||
|  | version = "1.26.4" | ||||||
|  | description = "HTTP library with thread-safe connection pooling, file post, and more." | ||||||
|  | category = "main" | ||||||
|  | optional = false | ||||||
|  | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" | ||||||
|  |  | ||||||
|  | [package.extras] | ||||||
|  | secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] | ||||||
|  | socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] | ||||||
|  | brotli = ["brotlipy (>=0.6.0)"] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "virtualenv" | ||||||
|  | version = "20.4.3" | ||||||
|  | description = "Virtual Python Environment builder" | ||||||
|  | category = "main" | ||||||
|  | optional = false | ||||||
|  | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" | ||||||
|  |  | ||||||
|  | [package.dependencies] | ||||||
|  | appdirs = ">=1.4.3,<2" | ||||||
|  | distlib = ">=0.3.1,<1" | ||||||
|  | filelock = ">=3.0.0,<4" | ||||||
|  | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} | ||||||
|  | importlib-resources = {version = ">=1.0", markers = "python_version < \"3.7\""} | ||||||
|  | six = ">=1.9.0,<2" | ||||||
|  |  | ||||||
|  | [package.extras] | ||||||
|  | docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=19.9.0rc1)"] | ||||||
|  | testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)", "xonsh (>=0.9.16)"] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "werkzeug" | ||||||
|  | version = "1.0.1" | ||||||
|  | description = "The comprehensive WSGI web application library." | ||||||
|  | category = "main" | ||||||
|  | optional = false | ||||||
|  | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" | ||||||
|  |  | ||||||
|  | [package.extras] | ||||||
|  | dev = ["pytest", "pytest-timeout", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinx-issues"] | ||||||
|  | watchdog = ["watchdog"] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "zipp" | ||||||
|  | version = "3.4.1" | ||||||
|  | description = "Backport of pathlib-compatible object wrapper for zip files" | ||||||
|  | category = "main" | ||||||
|  | optional = false | ||||||
|  | python-versions = ">=3.6" | ||||||
|  |  | ||||||
|  | [package.extras] | ||||||
|  | docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] | ||||||
|  | testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] | ||||||
|  |  | ||||||
|  | [metadata] | ||||||
|  | lock-version = "1.1" | ||||||
|  | python-versions = "^3.6.1" | ||||||
|  | content-hash = "af9db950cd722e7dc52b691fb58abc1e22ab48b34ddfe4c5258b3c755a3892fa" | ||||||
|  |  | ||||||
|  | [metadata.files] | ||||||
|  | appdirs = [ | ||||||
|  |     {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, | ||||||
|  |     {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, | ||||||
|  | ] | ||||||
|  | attrs = [ | ||||||
|  |     {file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"}, | ||||||
|  |     {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"}, | ||||||
|  | ] | ||||||
|  | certifi = [ | ||||||
|  |     {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, | ||||||
|  |     {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"}, | ||||||
|  | ] | ||||||
|  | chardet = [ | ||||||
|  |     {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, | ||||||
|  |     {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, | ||||||
|  | ] | ||||||
|  | click = [ | ||||||
|  |     {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, | ||||||
|  |     {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, | ||||||
|  | ] | ||||||
|  | colorama = [ | ||||||
|  |     {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, | ||||||
|  |     {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, | ||||||
|  | ] | ||||||
|  | distlib = [ | ||||||
|  |     {file = "distlib-0.3.1-py2.py3-none-any.whl", hash = "sha256:8c09de2c67b3e7deef7184574fc060ab8a793e7adbb183d942c389c8b13c52fb"}, | ||||||
|  |     {file = "distlib-0.3.1.zip", hash = "sha256:edf6116872c863e1aa9d5bb7cb5e05a022c519a4594dc703843343a9ddd9bff1"}, | ||||||
|  | ] | ||||||
|  | filelock = [ | ||||||
|  |     {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"}, | ||||||
|  |     {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"}, | ||||||
|  | ] | ||||||
|  | flask = [ | ||||||
|  |     {file = "Flask-1.1.2-py2.py3-none-any.whl", hash = "sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"}, | ||||||
|  |     {file = "Flask-1.1.2.tar.gz", hash = "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060"}, | ||||||
|  | ] | ||||||
|  | idna = [ | ||||||
|  |     {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, | ||||||
|  |     {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, | ||||||
|  | ] | ||||||
|  | importlib-metadata = [ | ||||||
|  |     {file = "importlib_metadata-3.10.1-py3-none-any.whl", hash = "sha256:2ec0faae539743ae6aaa84b49a169670a465f7f5d64e6add98388cc29fd1f2f6"}, | ||||||
|  |     {file = "importlib_metadata-3.10.1.tar.gz", hash = "sha256:c9356b657de65c53744046fa8f7358afe0714a1af7d570c00c3835c2d724a7c1"}, | ||||||
|  | ] | ||||||
|  | importlib-resources = [ | ||||||
|  |     {file = "importlib_resources-5.1.2-py3-none-any.whl", hash = "sha256:ebab3efe74d83b04d6bf5cd9a17f0c5c93e60fb60f30c90f56265fce4682a469"}, | ||||||
|  |     {file = "importlib_resources-5.1.2.tar.gz", hash = "sha256:642586fc4740bd1cad7690f836b3321309402b20b332529f25617ff18e8e1370"}, | ||||||
|  | ] | ||||||
|  | itsdangerous = [ | ||||||
|  |     {file = "itsdangerous-1.1.0-py2.py3-none-any.whl", hash = "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"}, | ||||||
|  |     {file = "itsdangerous-1.1.0.tar.gz", hash = "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19"}, | ||||||
|  | ] | ||||||
|  | jinja2 = [ | ||||||
|  |     {file = "Jinja2-2.11.3-py2.py3-none-any.whl", hash = "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419"}, | ||||||
|  |     {file = "Jinja2-2.11.3.tar.gz", hash = "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"}, | ||||||
|  | ] | ||||||
|  | markupsafe = [ | ||||||
|     {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"}, |     {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"}, | ||||||
|     {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"}, |     {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"}, | ||||||
|     {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"}, |     {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"}, | ||||||
| @@ -252,225 +446,60 @@ files = [ | |||||||
|     {file = "MarkupSafe-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8"}, |     {file = "MarkupSafe-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8"}, | ||||||
|     {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, |     {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, | ||||||
| ] | ] | ||||||
|  | packaging = [ | ||||||
| [[package]] |  | ||||||
| name = "packaging" |  | ||||||
| version = "20.9" |  | ||||||
| description = "Core utilities for Python packages" |  | ||||||
| optional = false |  | ||||||
| python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" |  | ||||||
| files = [ |  | ||||||
|     {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, |     {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, | ||||||
|     {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, |     {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, | ||||||
| ] | ] | ||||||
|  | pluggy = [ | ||||||
| [package.dependencies] |  | ||||||
| pyparsing = ">=2.0.2" |  | ||||||
|  |  | ||||||
| [[package]] |  | ||||||
| name = "pluggy" |  | ||||||
| version = "0.13.1" |  | ||||||
| description = "plugin and hook calling mechanisms for python" |  | ||||||
| optional = false |  | ||||||
| python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" |  | ||||||
| files = [ |  | ||||||
|     {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, |     {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, | ||||||
|     {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, |     {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, | ||||||
| ] | ] | ||||||
|  | py = [ | ||||||
| [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" |  | ||||||
| optional = false |  | ||||||
| python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" |  | ||||||
| files = [ |  | ||||||
|     {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, |     {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, | ||||||
|     {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, |     {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, | ||||||
| ] | ] | ||||||
|  | pyparsing = [ | ||||||
| [[package]] |  | ||||||
| name = "pyparsing" |  | ||||||
| version = "2.4.7" |  | ||||||
| description = "Python parsing module" |  | ||||||
| optional = false |  | ||||||
| python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" |  | ||||||
| files = [ |  | ||||||
|     {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, |     {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, | ||||||
|     {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, |     {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, | ||||||
| ] | ] | ||||||
|  | python-dateutil = [ | ||||||
| [[package]] |  | ||||||
| name = "python-dateutil" |  | ||||||
| version = "2.8.1" |  | ||||||
| description = "Extensions to the standard Python datetime module" |  | ||||||
| optional = false |  | ||||||
| python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" |  | ||||||
| files = [ |  | ||||||
|     {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, |     {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, | ||||||
|     {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, |     {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, | ||||||
| ] | ] | ||||||
|  | requests = [ | ||||||
| [package.dependencies] |  | ||||||
| six = ">=1.5" |  | ||||||
|  |  | ||||||
| [[package]] |  | ||||||
| name = "requests" |  | ||||||
| version = "2.25.1" |  | ||||||
| description = "Python HTTP for Humans." |  | ||||||
| optional = false |  | ||||||
| python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" |  | ||||||
| files = [ |  | ||||||
|     {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, |     {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, | ||||||
|     {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, |     {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, | ||||||
| ] | ] | ||||||
|  | six = [ | ||||||
| [package.dependencies] |  | ||||||
| certifi = ">=2017.4.17" |  | ||||||
| chardet = ">=3.0.2,<5" |  | ||||||
| idna = ">=2.5,<3" |  | ||||||
| urllib3 = ">=1.21.1,<1.27" |  | ||||||
|  |  | ||||||
| [package.extras] |  | ||||||
| security = ["cryptography (>=1.3.4)", "pyOpenSSL (>=0.14)"] |  | ||||||
| socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] |  | ||||||
|  |  | ||||||
| [[package]] |  | ||||||
| name = "six" |  | ||||||
| version = "1.15.0" |  | ||||||
| description = "Python 2 and 3 compatibility utilities" |  | ||||||
| optional = false |  | ||||||
| python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" |  | ||||||
| files = [ |  | ||||||
|     {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, |     {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, | ||||||
|     {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, |     {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, | ||||||
| ] | ] | ||||||
|  | toml = [ | ||||||
| [[package]] |  | ||||||
| name = "toml" |  | ||||||
| version = "0.10.2" |  | ||||||
| description = "Python Library for Tom's Obvious, Minimal Language" |  | ||||||
| optional = false |  | ||||||
| python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" |  | ||||||
| files = [ |  | ||||||
|     {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, |     {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, | ||||||
|     {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, |     {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, | ||||||
| ] | ] | ||||||
|  | tox = [ | ||||||
| [[package]] |  | ||||||
| name = "tox" |  | ||||||
| version = "3.23.0" |  | ||||||
| description = "tox is a generic virtualenv management and test command line tool" |  | ||||||
| optional = false |  | ||||||
| python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" |  | ||||||
| files = [ |  | ||||||
|     {file = "tox-3.23.0-py2.py3-none-any.whl", hash = "sha256:e007673f3595cede9b17a7c4962389e4305d4a3682a6c5a4159a1453b4f326aa"}, |     {file = "tox-3.23.0-py2.py3-none-any.whl", hash = "sha256:e007673f3595cede9b17a7c4962389e4305d4a3682a6c5a4159a1453b4f326aa"}, | ||||||
|     {file = "tox-3.23.0.tar.gz", hash = "sha256:05a4dbd5e4d3d8269b72b55600f0b0303e2eb47ad5c6fe76d3576f4c58d93661"}, |     {file = "tox-3.23.0.tar.gz", hash = "sha256:05a4dbd5e4d3d8269b72b55600f0b0303e2eb47ad5c6fe76d3576f4c58d93661"}, | ||||||
| ] | ] | ||||||
|  | typing-extensions = [ | ||||||
| [package.dependencies] |  | ||||||
| colorama = {version = ">=0.4.1", markers = "platform_system == \"Windows\""} |  | ||||||
| filelock = ">=3.0.0" |  | ||||||
| importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} |  | ||||||
| packaging = ">=14" |  | ||||||
| pluggy = ">=0.12.0" |  | ||||||
| py = ">=1.4.17" |  | ||||||
| six = ">=1.14.0" |  | ||||||
| toml = ">=0.9.4" |  | ||||||
| virtualenv = ">=16.0.0,<20.0.0 || >20.0.0,<20.0.1 || >20.0.1,<20.0.2 || >20.0.2,<20.0.3 || >20.0.3,<20.0.4 || >20.0.4,<20.0.5 || >20.0.5,<20.0.6 || >20.0.6,<20.0.7 || >20.0.7" |  | ||||||
|  |  | ||||||
| [package.extras] |  | ||||||
| docs = ["pygments-github-lexers (>=0.0.5)", "sphinx (>=2.0.0)", "sphinxcontrib-autoprogram (>=0.1.5)", "towncrier (>=18.5.0)"] |  | ||||||
| testing = ["flaky (>=3.4.0)", "freezegun (>=0.3.11)", "pathlib2 (>=2.3.3)", "psutil (>=5.6.1)", "pytest (>=4.0.0)", "pytest-cov (>=2.5.1)", "pytest-mock (>=1.10.0)", "pytest-randomly (>=1.0.0)", "pytest-xdist (>=1.22.2)"] |  | ||||||
|  |  | ||||||
| [[package]] |  | ||||||
| name = "typing-extensions" |  | ||||||
| version = "3.7.4.3" |  | ||||||
| description = "Backported and Experimental Type Hints for Python 3.5+" |  | ||||||
| optional = false |  | ||||||
| python-versions = "*" |  | ||||||
| files = [ |  | ||||||
|     {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, |     {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-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, | ||||||
|     {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, |     {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, | ||||||
| ] | ] | ||||||
|  | urllib3 = [ | ||||||
| [[package]] |     {file = "urllib3-1.26.4-py2.py3-none-any.whl", hash = "sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df"}, | ||||||
| name = "urllib3" |     {file = "urllib3-1.26.4.tar.gz", hash = "sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937"}, | ||||||
| version = "1.26.19" |  | ||||||
| description = "HTTP library with thread-safe connection pooling, file post, and more." |  | ||||||
| optional = false |  | ||||||
| python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" |  | ||||||
| files = [ |  | ||||||
|     {file = "urllib3-1.26.19-py2.py3-none-any.whl", hash = "sha256:37a0344459b199fce0e80b0d3569837ec6b6937435c5244e7fd73fa6006830f3"}, |  | ||||||
|     {file = "urllib3-1.26.19.tar.gz", hash = "sha256:3e3d753a8618b86d7de333b4223005f68720bcd6a7d2bcb9fbd2229ec7c1e429"}, |  | ||||||
| ] | ] | ||||||
|  | virtualenv = [ | ||||||
| [package.extras] |  | ||||||
| brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] |  | ||||||
| secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] |  | ||||||
| socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] |  | ||||||
|  |  | ||||||
| [[package]] |  | ||||||
| name = "virtualenv" |  | ||||||
| version = "20.4.3" |  | ||||||
| description = "Virtual Python Environment builder" |  | ||||||
| optional = false |  | ||||||
| python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" |  | ||||||
| files = [ |  | ||||||
|     {file = "virtualenv-20.4.3-py2.py3-none-any.whl", hash = "sha256:83f95875d382c7abafe06bd2a4cdd1b363e1bb77e02f155ebe8ac082a916b37c"}, |     {file = "virtualenv-20.4.3-py2.py3-none-any.whl", hash = "sha256:83f95875d382c7abafe06bd2a4cdd1b363e1bb77e02f155ebe8ac082a916b37c"}, | ||||||
|     {file = "virtualenv-20.4.3.tar.gz", hash = "sha256:49ec4eb4c224c6f7dd81bb6d0a28a09ecae5894f4e593c89b0db0885f565a107"}, |     {file = "virtualenv-20.4.3.tar.gz", hash = "sha256:49ec4eb4c224c6f7dd81bb6d0a28a09ecae5894f4e593c89b0db0885f565a107"}, | ||||||
| ] | ] | ||||||
|  | werkzeug = [ | ||||||
| [package.dependencies] |  | ||||||
| appdirs = ">=1.4.3,<2" |  | ||||||
| distlib = ">=0.3.1,<1" |  | ||||||
| filelock = ">=3.0.0,<4" |  | ||||||
| importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} |  | ||||||
| importlib-resources = {version = ">=1.0", markers = "python_version < \"3.7\""} |  | ||||||
| six = ">=1.9.0,<2" |  | ||||||
|  |  | ||||||
| [package.extras] |  | ||||||
| docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=19.9.0rc1)"] |  | ||||||
| testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "packaging (>=20.0)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "xonsh (>=0.9.16)"] |  | ||||||
|  |  | ||||||
| [[package]] |  | ||||||
| name = "werkzeug" |  | ||||||
| version = "1.0.1" |  | ||||||
| description = "The comprehensive WSGI web application library." |  | ||||||
| optional = false |  | ||||||
| python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" |  | ||||||
| files = [ |  | ||||||
|     {file = "Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43"}, |     {file = "Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43"}, | ||||||
|     {file = "Werkzeug-1.0.1.tar.gz", hash = "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"}, |     {file = "Werkzeug-1.0.1.tar.gz", hash = "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"}, | ||||||
| ] | ] | ||||||
|  | zipp = [ | ||||||
| [package.extras] |  | ||||||
| dev = ["coverage", "pallets-sphinx-themes", "pytest", "pytest-timeout", "sphinx", "sphinx-issues", "tox"] |  | ||||||
| watchdog = ["watchdog"] |  | ||||||
|  |  | ||||||
| [[package]] |  | ||||||
| name = "zipp" |  | ||||||
| version = "3.4.1" |  | ||||||
| description = "Backport of pathlib-compatible object wrapper for zip files" |  | ||||||
| optional = false |  | ||||||
| python-versions = ">=3.6" |  | ||||||
| files = [ |  | ||||||
|     {file = "zipp-3.4.1-py3-none-any.whl", hash = "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"}, |     {file = "zipp-3.4.1-py3-none-any.whl", hash = "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"}, | ||||||
|     {file = "zipp-3.4.1.tar.gz", hash = "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76"}, |     {file = "zipp-3.4.1.tar.gz", hash = "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76"}, | ||||||
| ] | ] | ||||||
|  |  | ||||||
| [package.extras] |  | ||||||
| docs = ["jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx"] |  | ||||||
| testing = ["func-timeout", "jaraco.itertools", "pytest (>=4.6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=1.2.3)", "pytest-cov", "pytest-enabler", "pytest-flake8", "pytest-mypy"] |  | ||||||
|  |  | ||||||
| [metadata] |  | ||||||
| lock-version = "2.0" |  | ||||||
| python-versions = "^3.6.1" |  | ||||||
| content-hash = "af9db950cd722e7dc52b691fb58abc1e22ab48b34ddfe4c5258b3c755a3892fa" |  | ||||||
|   | |||||||
| @@ -37,7 +37,7 @@ try: | |||||||
|     from poetry.installation.operations.install import Install |     from poetry.installation.operations.install import Install | ||||||
|     from poetry.poetry import Poetry |     from poetry.poetry import Poetry | ||||||
|     from poetry.utils.env import VirtualEnv |     from poetry.utils.env import VirtualEnv | ||||||
| except ImportError: | except ImportError as err: | ||||||
|     raise exceptions.PoetryNotInstalledError( |     raise exceptions.PoetryNotInstalledError( | ||||||
|         f"No version of Poetry could be imported under the current environment for '{sys.executable}'" |         f"Failed to import a supported version of Poetry under the current environment '{sys.executable}': {err}" | ||||||
|     ) from None |     ) from None | ||||||
|   | |||||||
| @@ -19,9 +19,5 @@ PEP508_VERSION_DELIMITERS: Tuple[str, ...] = ("~=", "==", "!=", ">", "<") | |||||||
| # console output. | # console output. | ||||||
| REPORTER_PREFIX: str = f"{__about__.__title__}:" | REPORTER_PREFIX: str = f"{__about__.__title__}:" | ||||||
|  |  | ||||||
| # Internal list of packages that poetry has deemed unsafe and are excluded from the lockfile |  | ||||||
| # TODO: This functionality is no longer needed, should remove in a future update. |  | ||||||
| UNSAFE_PACKAGES: Set[str] = set() |  | ||||||
|  |  | ||||||
| # Number of threads to use for installing dependencies by default | # Number of threads to use for installing dependencies by default | ||||||
| DEFAULT_INSTALL_THREADS: int = 10 | DEFAULT_INSTALL_THREADS: int = 10 | ||||||
|   | |||||||
| @@ -11,7 +11,6 @@ All exceptions should inherit from the common base exception :exc:`ToxPoetryInst | |||||||
|    +-- LockedDepNotFoundError |    +-- LockedDepNotFoundError | ||||||
|    +-- ExtraNotFoundError |    +-- ExtraNotFoundError | ||||||
|    +-- LockedDepsRequiredError |    +-- LockedDepsRequiredError | ||||||
|    +-- RequiresUnsafeDepError |  | ||||||
|  |  | ||||||
| """ | """ | ||||||
|  |  | ||||||
| @@ -42,7 +41,3 @@ class ExtraNotFoundError(ToxPoetryInstallerException): | |||||||
|  |  | ||||||
| class LockedDepsRequiredError(ToxPoetryInstallerException): | class LockedDepsRequiredError(ToxPoetryInstallerException): | ||||||
|     """Environment cannot specify unlocked dependencies when locked dependencies are required""" |     """Environment cannot specify unlocked dependencies when locked dependencies are required""" | ||||||
|  |  | ||||||
|  |  | ||||||
| class RequiresUnsafeDepError(ToxPoetryInstallerException): |  | ||||||
|     """Package under test depends on an unsafe dependency and cannot be installed""" |  | ||||||
|   | |||||||
| @@ -1,175 +0,0 @@ | |||||||
| """Main hook definition module |  | ||||||
|  |  | ||||||
| All implementations of tox hooks are defined here, as well as any single-use helper functions |  | ||||||
| specifically related to implementing the hooks (to keep the size/readability of the hook functions |  | ||||||
| themselves manageable). |  | ||||||
| """ |  | ||||||
| from itertools import chain |  | ||||||
| from typing import List |  | ||||||
|  |  | ||||||
| from tox.config.cli.parser import ToxParser |  | ||||||
| from tox.config.sets import EnvConfigSet |  | ||||||
| from tox.plugin import impl |  | ||||||
| from tox.tox_env.api import ToxEnv as ToxVirtualEnv |  | ||||||
|  |  | ||||||
| from tox_poetry_installer import constants |  | ||||||
| from tox_poetry_installer import exceptions |  | ||||||
| from tox_poetry_installer import installer |  | ||||||
| from tox_poetry_installer import logger |  | ||||||
| from tox_poetry_installer import utilities |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @impl |  | ||||||
| def tox_add_option(parser: ToxParser): |  | ||||||
|     """Add additional command line arguments to tox to configure plugin behavior""" |  | ||||||
|     parser.add_argument( |  | ||||||
|         "--require-poetry", |  | ||||||
|         action="store_true", |  | ||||||
|         dest="require_poetry", |  | ||||||
|         help="(deprecated) Trigger a failure if Poetry is not available to Tox", |  | ||||||
|     ) |  | ||||||
|  |  | ||||||
|     parser.add_argument( |  | ||||||
|         "--parallel-install-threads", |  | ||||||
|         type=int, |  | ||||||
|         dest="parallel_install_threads", |  | ||||||
|         default=constants.DEFAULT_INSTALL_THREADS, |  | ||||||
|         help="Number of locked dependencies to install simultaneously; set to 0 to disable parallel installation", |  | ||||||
|     ) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @impl |  | ||||||
| def tox_add_env_config(env_conf: EnvConfigSet): |  | ||||||
|     """Add required env configuration options to the tox INI file""" |  | ||||||
|     env_conf.add_config( |  | ||||||
|         "poetry_dep_groups", |  | ||||||
|         of_type=List[str], |  | ||||||
|         default=[], |  | ||||||
|         desc="List of Poetry dependency groups to install to the environment", |  | ||||||
|     ) |  | ||||||
|  |  | ||||||
|     env_conf.add_config( |  | ||||||
|         "install_project_deps", |  | ||||||
|         of_type=bool, |  | ||||||
|         default=True, |  | ||||||
|         desc="Automatically install all Poetry primary dependencies to the environment", |  | ||||||
|     ) |  | ||||||
|  |  | ||||||
|     env_conf.add_config( |  | ||||||
|         "require_locked_deps", |  | ||||||
|         of_type=bool, |  | ||||||
|         default=False, |  | ||||||
|         desc="Require all dependencies in the environment be installed using the Poetry lockfile", |  | ||||||
|     ) |  | ||||||
|  |  | ||||||
|     env_conf.add_config( |  | ||||||
|         "require_poetry", |  | ||||||
|         of_type=bool, |  | ||||||
|         default=False, |  | ||||||
|         desc="Trigger a failure if Poetry is not available to Tox", |  | ||||||
|     ) |  | ||||||
|  |  | ||||||
|     env_conf.add_config( |  | ||||||
|         "locked_deps", |  | ||||||
|         of_type=List[str], |  | ||||||
|         default=[], |  | ||||||
|         desc="List of locked dependencies to install to the environment using the Poetry lockfile", |  | ||||||
|     ) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @impl |  | ||||||
| def tox_on_install( |  | ||||||
|     tox_env: ToxVirtualEnv, section: str  # pylint: disable=unused-argument |  | ||||||
| ) -> None: |  | ||||||
|     """Install the dependencies for the current environment |  | ||||||
|  |  | ||||||
|     Loads the local Poetry environment and the corresponding lockfile then pulls the dependencies |  | ||||||
|     specified by the Tox environment. Finally these dependencies are installed into the Tox |  | ||||||
|     environment using the Poetry ``PipInstaller`` backend. |  | ||||||
|  |  | ||||||
|     :param venv: Tox virtual environment object with configuration for the local Tox environment. |  | ||||||
|     :param action: Tox action object |  | ||||||
|     """ |  | ||||||
|     try: |  | ||||||
|         poetry = utilities.check_preconditions(tox_env) |  | ||||||
|     except exceptions.SkipEnvironment as err: |  | ||||||
|         if ( |  | ||||||
|             isinstance(err, exceptions.PoetryNotInstalledError) |  | ||||||
|             and tox_env.conf["require_poetry"] |  | ||||||
|         ): |  | ||||||
|             logger.error(str(err)) |  | ||||||
|             raise err |  | ||||||
|         logger.info(str(err)) |  | ||||||
|         return |  | ||||||
|  |  | ||||||
|     logger.info(f"Loaded project pyproject.toml from {poetry.file}") |  | ||||||
|  |  | ||||||
|     virtualenv = utilities.convert_virtualenv(tox_env) |  | ||||||
|  |  | ||||||
|     if not poetry.locker.is_fresh(): |  | ||||||
|         logger.warning( |  | ||||||
|             f"The Poetry lock file is not up to date with the latest changes in {poetry.file}" |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|     try: |  | ||||||
|         if tox_env.conf["require_locked_deps"] and tox_env.conf["deps"].lines(): |  | ||||||
|             raise exceptions.LockedDepsRequiredError( |  | ||||||
|                 f"Unlocked dependencies '{tox_env.conf['deps']}' specified for environment '{tox_env.name}' which requires locked dependencies" |  | ||||||
|             ) |  | ||||||
|  |  | ||||||
|         packages = utilities.build_package_map(poetry) |  | ||||||
|  |  | ||||||
|         group_deps = utilities.dedupe_packages( |  | ||||||
|             list( |  | ||||||
|                 chain( |  | ||||||
|                     *[ |  | ||||||
|                         utilities.find_group_deps(group, packages, virtualenv, poetry) |  | ||||||
|                         for group in tox_env.conf["poetry_dep_groups"] |  | ||||||
|                     ] |  | ||||||
|                 ) |  | ||||||
|             ) |  | ||||||
|         ) |  | ||||||
|         logger.info( |  | ||||||
|             f"Identified {len(group_deps)} group dependencies to install to env" |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|         env_deps = utilities.find_additional_deps( |  | ||||||
|             packages, virtualenv, poetry, tox_env.conf["locked_deps"] |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|         logger.info( |  | ||||||
|             f"Identified {len(env_deps)} environment dependencies to install to env" |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|         # extras are not set in a testenv if skip_install=true |  | ||||||
|         try: |  | ||||||
|             extras = tox_env.conf["extras"] |  | ||||||
|         except KeyError: |  | ||||||
|             extras = [] |  | ||||||
|  |  | ||||||
|         if tox_env.conf["install_project_deps"]: |  | ||||||
|             project_deps = utilities.find_project_deps( |  | ||||||
|                 packages, virtualenv, poetry, extras |  | ||||||
|             ) |  | ||||||
|             logger.info( |  | ||||||
|                 f"Identified {len(project_deps)} project dependencies to install to env" |  | ||||||
|             ) |  | ||||||
|         else: |  | ||||||
|             project_deps = [] |  | ||||||
|             logger.info("Env does not install project package dependencies, skipping") |  | ||||||
|     except exceptions.ToxPoetryInstallerException as err: |  | ||||||
|         logger.error(str(err)) |  | ||||||
|         raise err |  | ||||||
|     except Exception as err: |  | ||||||
|         logger.error(f"Internal plugin error: {err}") |  | ||||||
|         raise err |  | ||||||
|  |  | ||||||
|     dependencies = utilities.dedupe_packages(group_deps + env_deps + project_deps) |  | ||||||
|  |  | ||||||
|     logger.info(f"Installing {len(dependencies)} dependencies from Poetry lock file") |  | ||||||
|     installer.install( |  | ||||||
|         poetry, |  | ||||||
|         tox_env, |  | ||||||
|         dependencies, |  | ||||||
|         tox_env.options.parallel_install_threads, |  | ||||||
|     ) |  | ||||||
							
								
								
									
										4
									
								
								tox_poetry_installer/hooks/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								tox_poetry_installer/hooks/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | |||||||
|  | # pylint: disable=missing-module-docstring | ||||||
|  | from tox_poetry_installer.hooks.tox_add_env_config import tox_add_env_config | ||||||
|  | from tox_poetry_installer.hooks.tox_add_option import tox_add_option | ||||||
|  | from tox_poetry_installer.hooks.tox_on_install import tox_on_install | ||||||
							
								
								
									
										43
									
								
								tox_poetry_installer/hooks/tox_add_env_config.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								tox_poetry_installer/hooks/tox_add_env_config.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | |||||||
|  | """Add required env configuration options to the tox INI file""" | ||||||
|  | from typing import List | ||||||
|  |  | ||||||
|  | from tox.config.sets import EnvConfigSet | ||||||
|  | from tox.plugin import impl | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @impl | ||||||
|  | def tox_add_env_config(env_conf: EnvConfigSet): | ||||||
|  |     env_conf.add_config( | ||||||
|  |         "poetry_dep_groups", | ||||||
|  |         of_type=List[str], | ||||||
|  |         default=[], | ||||||
|  |         desc="List of Poetry dependency groups to install to the environment", | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     env_conf.add_config( | ||||||
|  |         "install_project_deps", | ||||||
|  |         of_type=bool, | ||||||
|  |         default=True, | ||||||
|  |         desc="Automatically install all Poetry primary dependencies to the environment", | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     env_conf.add_config( | ||||||
|  |         "require_locked_deps", | ||||||
|  |         of_type=bool, | ||||||
|  |         default=False, | ||||||
|  |         desc="Require all dependencies in the environment be installed using the Poetry lockfile", | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     env_conf.add_config( | ||||||
|  |         "require_poetry", | ||||||
|  |         of_type=bool, | ||||||
|  |         default=False, | ||||||
|  |         desc="Trigger a failure if Poetry is not available to Tox", | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     env_conf.add_config( | ||||||
|  |         "locked_deps", | ||||||
|  |         of_type=List[str], | ||||||
|  |         default=[], | ||||||
|  |         desc="List of locked dependencies to install to the environment using the Poetry lockfile", | ||||||
|  |     ) | ||||||
							
								
								
									
										16
									
								
								tox_poetry_installer/hooks/tox_add_option.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								tox_poetry_installer/hooks/tox_add_option.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | """Add additional command line arguments to tox to configure plugin behavior""" | ||||||
|  | from tox.config.cli.parser import ToxParser | ||||||
|  | from tox.plugin import impl | ||||||
|  |  | ||||||
|  | from tox_poetry_installer import constants | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @impl | ||||||
|  | def tox_add_option(parser: ToxParser): | ||||||
|  |     parser.add_argument( | ||||||
|  |         "--parallel-install-threads", | ||||||
|  |         type=int, | ||||||
|  |         dest="parallel_install_threads", | ||||||
|  |         default=constants.DEFAULT_INSTALL_THREADS, | ||||||
|  |         help="Number of locked dependencies to install simultaneously; set to 0 to disable parallel installation", | ||||||
|  |     ) | ||||||
| @@ -1,10 +1,17 @@ | |||||||
| """Helper utility functions, usually bridging Tox and Poetry functionality""" | """Install the dependencies for the current environment | ||||||
| # Silence this one globally to support the internal function imports for the proxied poetry module. | 
 | ||||||
| # See the docstring in 'tox_poetry_installer._poetry' for more context. | Loads the local Poetry environment and the corresponding lockfile then pulls the dependencies | ||||||
| # pylint: disable=import-outside-toplevel | specified by the Tox environment. Finally these dependencies are installed into the Tox | ||||||
|  | environment using the Poetry ``PipInstaller`` backend. | ||||||
|  | """ | ||||||
| import collections | import collections | ||||||
|  | import concurrent.futures | ||||||
|  | import contextlib | ||||||
| import typing | import typing | ||||||
|  | from datetime import datetime | ||||||
|  | from itertools import chain | ||||||
| from pathlib import Path | from pathlib import Path | ||||||
|  | from typing import Collection | ||||||
| from typing import Dict | from typing import Dict | ||||||
| from typing import List | from typing import List | ||||||
| from typing import Sequence | from typing import Sequence | ||||||
| @@ -12,6 +19,7 @@ from typing import Set | |||||||
| 
 | 
 | ||||||
| from poetry.core.packages.dependency import Dependency as PoetryDependency | from poetry.core.packages.dependency import Dependency as PoetryDependency | ||||||
| from poetry.core.packages.package import Package as PoetryPackage | from poetry.core.packages.package import Package as PoetryPackage | ||||||
|  | from tox.plugin import impl | ||||||
| from tox.tox_env.api import ToxEnv as ToxVirtualEnv | from tox.tox_env.api import ToxEnv as ToxVirtualEnv | ||||||
| from tox.tox_env.package import PackageToxEnv | from tox.tox_env.package import PackageToxEnv | ||||||
| 
 | 
 | ||||||
| @@ -26,6 +34,93 @@ if typing.TYPE_CHECKING: | |||||||
| PackageMap = Dict[str, List[PoetryPackage]] | PackageMap = Dict[str, List[PoetryPackage]] | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @impl | ||||||
|  | def tox_on_install( | ||||||
|  |     tox_env: ToxVirtualEnv, section: str  # pylint: disable=unused-argument | ||||||
|  | ) -> None: | ||||||
|  |     try: | ||||||
|  |         poetry = check_preconditions(tox_env) | ||||||
|  |     except exceptions.SkipEnvironment as err: | ||||||
|  |         if ( | ||||||
|  |             isinstance(err, exceptions.PoetryNotInstalledError) | ||||||
|  |             and tox_env.conf["require_poetry"] | ||||||
|  |         ): | ||||||
|  |             logger.error(str(err)) | ||||||
|  |             raise err | ||||||
|  |         logger.info(str(err)) | ||||||
|  |         return | ||||||
|  | 
 | ||||||
|  |     logger.info(f"Loaded project pyproject.toml from {poetry.file}") | ||||||
|  | 
 | ||||||
|  |     virtualenv = convert_virtualenv(tox_env) | ||||||
|  | 
 | ||||||
|  |     if not poetry.locker.is_fresh(): | ||||||
|  |         logger.warning( | ||||||
|  |             f"The Poetry lock file is not up to date with the latest changes in {poetry.file}" | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |     try: | ||||||
|  |         if tox_env.conf["require_locked_deps"] and tox_env.conf["deps"].lines(): | ||||||
|  |             raise exceptions.LockedDepsRequiredError( | ||||||
|  |                 f"Unlocked dependencies '{tox_env.conf['deps']}' specified for environment '{tox_env.name}' which requires locked dependencies" | ||||||
|  |             ) | ||||||
|  | 
 | ||||||
|  |         packages = build_package_map(poetry) | ||||||
|  | 
 | ||||||
|  |         group_deps = dedupe_packages( | ||||||
|  |             list( | ||||||
|  |                 chain( | ||||||
|  |                     *[ | ||||||
|  |                         find_group_deps(group, packages, virtualenv, poetry) | ||||||
|  |                         for group in tox_env.conf["poetry_dep_groups"] | ||||||
|  |                     ] | ||||||
|  |                 ) | ||||||
|  |             ) | ||||||
|  |         ) | ||||||
|  |         logger.info( | ||||||
|  |             f"Identified {len(group_deps)} group dependencies to install to env" | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |         env_deps = find_additional_deps( | ||||||
|  |             packages, virtualenv, poetry, tox_env.conf["locked_deps"] | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |         logger.info( | ||||||
|  |             f"Identified {len(env_deps)} environment dependencies to install to env" | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |         # extras are not set in a testenv if skip_install=true | ||||||
|  |         try: | ||||||
|  |             extras = tox_env.conf["extras"] | ||||||
|  |         except KeyError: | ||||||
|  |             extras = [] | ||||||
|  | 
 | ||||||
|  |         if tox_env.conf["install_project_deps"]: | ||||||
|  |             project_deps = find_project_deps(packages, virtualenv, poetry, extras) | ||||||
|  |             logger.info( | ||||||
|  |                 f"Identified {len(project_deps)} project dependencies to install to env" | ||||||
|  |             ) | ||||||
|  |         else: | ||||||
|  |             project_deps = [] | ||||||
|  |             logger.info("Env does not install project package dependencies, skipping") | ||||||
|  |     except exceptions.ToxPoetryInstallerException as err: | ||||||
|  |         logger.error(str(err)) | ||||||
|  |         raise err | ||||||
|  |     except Exception as err: | ||||||
|  |         logger.error(f"Internal plugin error: {err}") | ||||||
|  |         raise err | ||||||
|  | 
 | ||||||
|  |     dependencies = dedupe_packages(group_deps + env_deps + project_deps) | ||||||
|  | 
 | ||||||
|  |     logger.info(f"Installing {len(dependencies)} dependencies from Poetry lock file") | ||||||
|  |     install_package( | ||||||
|  |         poetry, | ||||||
|  |         tox_env, | ||||||
|  |         dependencies, | ||||||
|  |         tox_env.options.parallel_install_threads, | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| def check_preconditions(venv: ToxVirtualEnv) -> "_poetry.Poetry": | def check_preconditions(venv: ToxVirtualEnv) -> "_poetry.Poetry": | ||||||
|     """Check that the local project environment meets expectations""" |     """Check that the local project environment meets expectations""" | ||||||
| 
 | 
 | ||||||
| @@ -37,13 +132,6 @@ def check_preconditions(venv: ToxVirtualEnv) -> "_poetry.Poetry": | |||||||
|     if isinstance(venv, PackageToxEnv): |     if isinstance(venv, PackageToxEnv): | ||||||
|         raise exceptions.SkipEnvironment(f"Skipping Tox provisioning env '{venv.name}'") |         raise exceptions.SkipEnvironment(f"Skipping Tox provisioning env '{venv.name}'") | ||||||
| 
 | 
 | ||||||
|     if venv.options.require_poetry: |  | ||||||
|         logger.warning( |  | ||||||
|             "DEPRECATION: The '--require-poetry' runtime option is deprecated and will be " |  | ||||||
|             "removed in version 1.0.0. Please update test environments that require Poetry to " |  | ||||||
|             "set the 'require_poetry = true' option in tox.ini" |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
|     from tox_poetry_installer import _poetry |     from tox_poetry_installer import _poetry | ||||||
| 
 | 
 | ||||||
|     try: |     try: | ||||||
| @@ -53,36 +141,12 @@ def check_preconditions(venv: ToxVirtualEnv) -> "_poetry.Poetry": | |||||||
|     # |     # | ||||||
|     # ``RuntimeError`` is dangerous to blindly catch because it can be (and in Poetry's case, |     # ``RuntimeError`` is dangerous to blindly catch because it can be (and in Poetry's case, | ||||||
|     # is) raised in many different places for different purposes. |     # is) raised in many different places for different purposes. | ||||||
|     except RuntimeError: |     except RuntimeError as err: | ||||||
|         raise exceptions.SkipEnvironment( |         raise exceptions.SkipEnvironment( | ||||||
|             "Project does not use Poetry for env management, skipping installation of locked dependencies" |             f"Skipping installation of locked dependencies due to a Poetry error: {err}" | ||||||
|         ) from None |         ) from None | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def convert_virtualenv(venv: ToxVirtualEnv) -> "_poetry.VirtualEnv": |  | ||||||
|     """Convert a Tox venv to a Poetry venv |  | ||||||
| 
 |  | ||||||
|     :param venv: Tox ``VirtualEnv`` object representing a tox virtual environment |  | ||||||
|     :returns: Poetry ``VirtualEnv`` object representing a poetry virtual environment |  | ||||||
|     """ |  | ||||||
|     from tox_poetry_installer import _poetry |  | ||||||
| 
 |  | ||||||
|     return _poetry.VirtualEnv(path=Path(venv.env_dir)) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def build_package_map(poetry: "_poetry.Poetry") -> PackageMap: |  | ||||||
|     """Build the mapping of package names to objects |  | ||||||
| 
 |  | ||||||
|     :param poetry: Populated poetry object to load locked packages from |  | ||||||
|     :returns: Mapping of package names to Poetry package objects |  | ||||||
|     """ |  | ||||||
|     packages = collections.defaultdict(list) |  | ||||||
|     for package in poetry.locker.locked_repository().packages: |  | ||||||
|         packages[package.name].append(package) |  | ||||||
| 
 |  | ||||||
|     return packages |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def identify_transients( | def identify_transients( | ||||||
|     dep_name: str, |     dep_name: str, | ||||||
|     packages: PackageMap, |     packages: PackageMap, | ||||||
| @@ -139,13 +203,6 @@ def identify_transients( | |||||||
|     except KeyError as err: |     except KeyError as err: | ||||||
|         missing = err.args[0] |         missing = err.args[0] | ||||||
| 
 | 
 | ||||||
|         if missing in constants.UNSAFE_PACKAGES: |  | ||||||
|             logger.warning( |  | ||||||
|                 f"Installing package '{missing}' using Poetry is not supported and will be skipped" |  | ||||||
|             ) |  | ||||||
|             logger.debug(f"Skipping {missing}: designated unsafe by Poetry") |  | ||||||
|             return [] |  | ||||||
| 
 |  | ||||||
|         if missing in allow_missing: |         if missing in allow_missing: | ||||||
|             logger.debug(f"Skipping {missing}: package is allowed to be unlocked") |             logger.debug(f"Skipping {missing}: package is allowed to be unlocked") | ||||||
|             return [] |             return [] | ||||||
| @@ -178,11 +235,6 @@ def find_project_deps( | |||||||
|     :param extras: Sequence of extra names to include the dependencies of |     :param extras: Sequence of extra names to include the dependencies of | ||||||
|     """ |     """ | ||||||
| 
 | 
 | ||||||
|     if any(dep.name in constants.UNSAFE_PACKAGES for dep in poetry.package.requires): |  | ||||||
|         raise exceptions.RequiresUnsafeDepError( |  | ||||||
|             f"Project package requires one or more unsafe dependencies ({', '.join(constants.UNSAFE_PACKAGES)}) which cannot be installed with Poetry" |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
|     required_dep_names = [ |     required_dep_names = [ | ||||||
|         item.name for item in poetry.package.requires if not item.is_optional() |         item.name for item in poetry.package.requires if not item.is_optional() | ||||||
|     ] |     ] | ||||||
| @@ -283,6 +335,76 @@ def find_dev_deps( | |||||||
|     return dedupe_packages(dev_group_deps + legacy_dev_group_deps) |     return dedupe_packages(dev_group_deps + legacy_dev_group_deps) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | def install_package( | ||||||
|  |     poetry: "_poetry.Poetry", | ||||||
|  |     venv: ToxVirtualEnv, | ||||||
|  |     packages: Collection["_poetry.PoetryPackage"], | ||||||
|  |     parallels: int = 0, | ||||||
|  | ): | ||||||
|  |     """Install a bunch of packages to a virtualenv | ||||||
|  | 
 | ||||||
|  |     :param poetry: Poetry object the packages were sourced from | ||||||
|  |     :param venv: Tox virtual environment to install the packages to | ||||||
|  |     :param packages: List of packages to install to the virtual environment | ||||||
|  |     :param parallels: Number of parallel processes to use for installing dependency packages, or | ||||||
|  |                       ``None`` to disable parallelization. | ||||||
|  |     """ | ||||||
|  |     from tox_poetry_installer import _poetry | ||||||
|  | 
 | ||||||
|  |     logger.info(f"Installing {len(packages)} packages to environment at {venv.env_dir}") | ||||||
|  | 
 | ||||||
|  |     install_executor = _poetry.Executor( | ||||||
|  |         env=convert_virtualenv(venv), | ||||||
|  |         io=_poetry.NullIO(), | ||||||
|  |         pool=poetry.pool, | ||||||
|  |         config=_poetry.Config(), | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     installed: Set[_poetry.PoetryPackage] = set() | ||||||
|  | 
 | ||||||
|  |     def logged_install(dependency: _poetry.PoetryPackage) -> None: | ||||||
|  |         start = datetime.now() | ||||||
|  |         logger.debug(f"Installing {dependency}") | ||||||
|  |         install_executor.execute([_poetry.Install(package=dependency)]) | ||||||
|  |         end = datetime.now() | ||||||
|  |         logger.debug(f"Finished installing {dependency} in {end - start}") | ||||||
|  | 
 | ||||||
|  |     @contextlib.contextmanager | ||||||
|  |     def _optional_parallelize(): | ||||||
|  |         """A bit of cheat, really | ||||||
|  | 
 | ||||||
|  |         A context manager that exposes a common interface for the caller that optionally | ||||||
|  |         enables/disables the usage of the parallel thread pooler depending on the value of | ||||||
|  |         the ``parallels`` parameter. | ||||||
|  |         """ | ||||||
|  |         if parallels > 0: | ||||||
|  |             with concurrent.futures.ThreadPoolExecutor( | ||||||
|  |                 max_workers=parallels | ||||||
|  |             ) as executor: | ||||||
|  |                 yield executor.submit | ||||||
|  |         else: | ||||||
|  |             yield lambda func, arg: func(arg) | ||||||
|  | 
 | ||||||
|  |     with _optional_parallelize() as executor: | ||||||
|  |         futures = [] | ||||||
|  |         for dependency in packages: | ||||||
|  |             if dependency not in installed: | ||||||
|  |                 installed.add(dependency) | ||||||
|  |                 logger.debug(f"Queuing {dependency}") | ||||||
|  |                 future = executor(logged_install, dependency) | ||||||
|  |                 if future is not None: | ||||||
|  |                     futures.append(future) | ||||||
|  |             else: | ||||||
|  |                 logger.debug(f"Skipping {dependency}, already installed") | ||||||
|  |         logger.debug("Waiting for installs to finish...") | ||||||
|  | 
 | ||||||
|  |         for future in concurrent.futures.as_completed(futures): | ||||||
|  |             # Don't actually care about the return value, just waiting on the | ||||||
|  |             # future to ensure any exceptions that were raised in the called | ||||||
|  |             # function are propagated. | ||||||
|  |             future.result() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| def dedupe_packages(packages: Sequence[PoetryPackage]) -> List[PoetryPackage]: | def dedupe_packages(packages: Sequence[PoetryPackage]) -> List[PoetryPackage]: | ||||||
|     """Deduplicates a sequence of PoetryPackages while preserving ordering |     """Deduplicates a sequence of PoetryPackages while preserving ordering | ||||||
| 
 | 
 | ||||||
| @@ -292,3 +414,27 @@ def dedupe_packages(packages: Sequence[PoetryPackage]) -> List[PoetryPackage]: | |||||||
|     # Make this faster, avoid method lookup below |     # Make this faster, avoid method lookup below | ||||||
|     seen_add = seen.add |     seen_add = seen.add | ||||||
|     return [p for p in packages if not (p in seen or seen_add(p))] |     return [p for p in packages if not (p in seen or seen_add(p))] | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def convert_virtualenv(venv: ToxVirtualEnv) -> "_poetry.VirtualEnv": | ||||||
|  |     """Convert a Tox venv to a Poetry venv | ||||||
|  | 
 | ||||||
|  |     :param venv: Tox ``VirtualEnv`` object representing a tox virtual environment | ||||||
|  |     :returns: Poetry ``VirtualEnv`` object representing a poetry virtual environment | ||||||
|  |     """ | ||||||
|  |     from tox_poetry_installer import _poetry | ||||||
|  | 
 | ||||||
|  |     return _poetry.VirtualEnv(path=Path(venv.env_dir)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def build_package_map(poetry: "_poetry.Poetry") -> PackageMap: | ||||||
|  |     """Build the mapping of package names to objects | ||||||
|  | 
 | ||||||
|  |     :param poetry: Populated poetry object to load locked packages from | ||||||
|  |     :returns: Mapping of package names to Poetry package objects | ||||||
|  |     """ | ||||||
|  |     packages = collections.defaultdict(list) | ||||||
|  |     for package in poetry.locker.locked_repository().packages: | ||||||
|  |         packages[package.name].append(package) | ||||||
|  | 
 | ||||||
|  |     return packages | ||||||
| @@ -1,88 +0,0 @@ | |||||||
| """Funcationality for performing virtualenv installation""" |  | ||||||
| # Silence this one globally to support the internal function imports for the proxied poetry module. |  | ||||||
| # See the docstring in 'tox_poetry_installer._poetry' for more context. |  | ||||||
| # pylint: disable=import-outside-toplevel |  | ||||||
| import concurrent.futures |  | ||||||
| import contextlib |  | ||||||
| import typing |  | ||||||
| from datetime import datetime |  | ||||||
| from typing import Collection |  | ||||||
| from typing import Set |  | ||||||
|  |  | ||||||
| from tox.tox_env.api import ToxEnv as ToxVirtualEnv |  | ||||||
|  |  | ||||||
| from tox_poetry_installer import logger |  | ||||||
| from tox_poetry_installer import utilities |  | ||||||
|  |  | ||||||
| if typing.TYPE_CHECKING: |  | ||||||
|     from tox_poetry_installer import _poetry |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def install( |  | ||||||
|     poetry: "_poetry.Poetry", |  | ||||||
|     venv: ToxVirtualEnv, |  | ||||||
|     packages: Collection["_poetry.PoetryPackage"], |  | ||||||
|     parallels: int = 0, |  | ||||||
| ): |  | ||||||
|     """Install a bunch of packages to a virtualenv |  | ||||||
|  |  | ||||||
|     :param poetry: Poetry object the packages were sourced from |  | ||||||
|     :param venv: Tox virtual environment to install the packages to |  | ||||||
|     :param packages: List of packages to install to the virtual environment |  | ||||||
|     :param parallels: Number of parallel processes to use for installing dependency packages, or |  | ||||||
|                       ``None`` to disable parallelization. |  | ||||||
|     """ |  | ||||||
|     from tox_poetry_installer import _poetry |  | ||||||
|  |  | ||||||
|     logger.info(f"Installing {len(packages)} packages to environment at {venv.env_dir}") |  | ||||||
|  |  | ||||||
|     install_executor = _poetry.Executor( |  | ||||||
|         env=utilities.convert_virtualenv(venv), |  | ||||||
|         io=_poetry.NullIO(), |  | ||||||
|         pool=poetry.pool, |  | ||||||
|         config=_poetry.Config(), |  | ||||||
|     ) |  | ||||||
|  |  | ||||||
|     installed: Set[_poetry.PoetryPackage] = set() |  | ||||||
|  |  | ||||||
|     def logged_install(dependency: _poetry.PoetryPackage) -> None: |  | ||||||
|         start = datetime.now() |  | ||||||
|         logger.debug(f"Installing {dependency}") |  | ||||||
|         install_executor.execute([_poetry.Install(package=dependency)]) |  | ||||||
|         end = datetime.now() |  | ||||||
|         logger.debug(f"Finished installing {dependency} in {end - start}") |  | ||||||
|  |  | ||||||
|     @contextlib.contextmanager |  | ||||||
|     def _optional_parallelize(): |  | ||||||
|         """A bit of cheat, really |  | ||||||
|  |  | ||||||
|         A context manager that exposes a common interface for the caller that optionally |  | ||||||
|         enables/disables the usage of the parallel thread pooler depending on the value of |  | ||||||
|         the ``parallels`` parameter. |  | ||||||
|         """ |  | ||||||
|         if parallels > 0: |  | ||||||
|             with concurrent.futures.ThreadPoolExecutor( |  | ||||||
|                 max_workers=parallels |  | ||||||
|             ) as executor: |  | ||||||
|                 yield executor.submit |  | ||||||
|         else: |  | ||||||
|             yield lambda func, arg: func(arg) |  | ||||||
|  |  | ||||||
|     with _optional_parallelize() as executor: |  | ||||||
|         futures = [] |  | ||||||
|         for dependency in packages: |  | ||||||
|             if dependency not in installed: |  | ||||||
|                 installed.add(dependency) |  | ||||||
|                 logger.debug(f"Queuing {dependency}") |  | ||||||
|                 future = executor(logged_install, dependency) |  | ||||||
|                 if future is not None: |  | ||||||
|                     futures.append(future) |  | ||||||
|             else: |  | ||||||
|                 logger.debug(f"Skipping {dependency}, already installed") |  | ||||||
|         logger.debug("Waiting for installs to finish...") |  | ||||||
|  |  | ||||||
|         for future in concurrent.futures.as_completed(futures): |  | ||||||
|             # Don't actually care about the return value, just waiting on the |  | ||||||
|             # future to ensure any exceptions that were raised in the called |  | ||||||
|             # function are propagated. |  | ||||||
|             future.result() |  | ||||||
		Reference in New Issue
	
	Block a user