15 Commits
0.1.1 ... 0.1.3

Author SHA1 Message Date
66f2c3c768 Bump patch version 2020-09-25 01:04:12 -04:00
fd2637113f Remove excessive bandit output from security checks 2020-09-25 01:03:31 -04:00
b10e796ca1 Standardize log message usage of 'dev-package' and 'env' terminology 2020-09-25 01:02:30 -04:00
5dfbca4ff6 Update docs to indicate dev package installation support 2020-09-25 00:56:21 -04:00
db09acd8fe Fix install of dev package dependencies from lockfile
Override default pip behavior by preemptively installing dev package dependencies
Keep support for tox default skip_install config flag
2020-09-25 00:54:45 -04:00
b339e3d6d9 Update poetry requirement to mitigate coming breaking API changes
Poetry 1.1 is due any day and when it does much of the functionality this
  module uses will be moved to poetry-core. Until this module is updated
  to use poetry-core 1.1 will be a breaking change
2020-09-25 00:38:20 -04:00
9db6838d94 Update logging calls to use the tox reporter 2020-09-24 23:56:36 -04:00
166fb7bbfc Add publish make target to automate upload 2020-09-24 22:00:58 -04:00
0ab70f4c22 Add removal of overlooked temp assets to clean make target
Expand all flags to full version for future reference
2020-09-24 21:58:40 -04:00
31fc3e6bb1 Update toxfile with new environments and test automation
Add proper testenv with pytest command to run (currently trivial) tests
Update static and security envs to use variable for path identification
  * Avoids transversals and errors caused by different working dirs
Add static-tests env for enforcing quality checks on test files
Update security env to include test files
2020-09-24 21:58:39 -04:00
b95ad7a3a0 Update readme with completed trivial test step 2020-09-24 21:58:39 -04:00
4efd05e022 Bump patch version 2020-09-24 21:58:39 -04:00
d87dc0a660 Fix constant named for PEP440 that should be named for PEP508
Update author email to be consistent with pyproject
2020-09-24 21:58:39 -04:00
eed2038e63 Add trivial tests to ensure metadata consistency between pyroject and module 2020-09-24 21:58:39 -04:00
7d3fd324e5 Add pytest dev dependency for future test framework
Add toml dev dependency for reading the pyproject
Update dev dependency list to be alphabetized
2020-09-24 21:58:39 -04:00
7 changed files with 296 additions and 62 deletions

View File

@@ -1,8 +1,5 @@
# tox-poetry-installer makefile # tox-poetry-installer makefile
# You can set these variables from the command line
PROJECT = tox_poetry_installer
.PHONY: help .PHONY: help
# Put it first so that "make" without argument is like "make help" # Put it first so that "make" without argument is like "make help"
# Adapted from: # Adapted from:
@@ -11,19 +8,18 @@ help: ## List Makefile targets
$(info Makefile documentation) $(info Makefile documentation)
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-10s\033[0m %s\n", $$1, $$2}' @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-10s\033[0m %s\n", $$1, $$2}'
tox: clean
tox
clean-tox: clean-tox:
rm -rf ./.mypy_cache rm --recursive --force ./.mypy_cache
rm -rf ./.tox rm --recursive --force ./.tox
rm -f .coverage rm --recursive --force tests/__pycache__/
rm --recursive --force .pytest_cache/
rm --force .coverage
clean-py: clean-py:
rm -rf ./dist rm --recursive --force ./dist
rm -rf ./build rm --recursive --force ./build
rm -rf ./*.egg-info rm --recursive --force ./*.egg-info
rm -rf __pycache__/ rm --recursive --force __pycache__/
clean: clean-tox clean-py; ## Clean temp build/cache files and directories clean: clean-tox clean-py; ## Clean temp build/cache files and directories
@@ -34,4 +30,7 @@ source: ## Build Python source distribution package
poetry build --format sdist poetry build --format sdist
test: ## Run the project testsuite(s) test: ## Run the project testsuite(s)
poetry run tox -r poetry run tox --recreate
publish: wheel source ## Build and upload to pypi (requires $PYPI_API_KEY be set)
poetry publish --username __token__ --password $(PYPI_API_KEY)

View File

@@ -255,7 +255,7 @@ usage in production systems.
### Path to Beta ### Path to Beta
- [ ] Verify that primary package dependencies (from the `.package` env) are installed - [X] Verify that primary package dependencies (from the `.package` env) are installed
correctly using the Poetry backend. correctly using the Poetry backend.
- [ ] Support the [`extras`](https://tox.readthedocs.io/en/latest/config.html#conf-extras) - [ ] Support the [`extras`](https://tox.readthedocs.io/en/latest/config.html#conf-extras)
Tox configuration option Tox configuration option
@@ -265,7 +265,7 @@ usage in production systems.
environments when necessary. environments when necessary.
- [ ] Add warnings when an unsupported Tox configuration option is detected while using the - [ ] Add warnings when an unsupported Tox configuration option is detected while using the
Poetry backend. Poetry backend.
- [ ] Add trivial tests to ensure the project metadata is consistent between the pyproject.toml - [X] Add trivial tests to ensure the project metadata is consistent between the pyproject.toml
and the module constants. and the module constants.
- [ ] Update to use [poetry-core](https://github.com/python-poetry/poetry-core) - [ ] Update to use [poetry-core](https://github.com/python-poetry/poetry-core)
Tox configuration option) and improve robustness of the Tox and Poetry module imports Tox configuration option) and improve robustness of the Tox and Poetry module imports

142
poetry.lock generated
View File

@@ -44,6 +44,15 @@ wrapt = ">=1.11,<2.0"
python = "<3.8" python = "<3.8"
version = ">=1.4.0,<1.5" version = ">=1.4.0,<1.5"
[[package]]
category = "dev"
description = "Atomic file writes."
marker = "sys_platform == \"win32\""
name = "atomicwrites"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "1.4.0"
[[package]] [[package]]
category = "main" category = "main"
description = "Classes Without Boilerplate" description = "Classes Without Boilerplate"
@@ -227,6 +236,17 @@ 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.*"
version = "0.4.3" version = "0.4.3"
[[package]]
category = "dev"
description = "Code coverage measurement for Python"
name = "coverage"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
version = "5.3"
[package.extras]
toml = ["toml"]
[[package]] [[package]]
category = "main" category = "main"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
@@ -344,7 +364,7 @@ marker = "python_version >= \"3.6.1\" and python_version < \"4.0.0\""
name = "identify" name = "identify"
optional = false optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
version = "1.5.4" version = "1.5.5"
[package.extras] [package.extras]
license = ["editdistance"] license = ["editdistance"]
@@ -390,6 +410,14 @@ version = ">=0.4"
[package.extras] [package.extras]
docs = ["sphinx", "rst.linker", "jaraco.packaging"] docs = ["sphinx", "rst.linker", "jaraco.packaging"]
[[package]]
category = "dev"
description = "iniconfig: brain-dead simple config-ini parsing"
name = "iniconfig"
optional = false
python-versions = "*"
version = "1.0.1"
[[package]] [[package]]
category = "dev" category = "dev"
description = "IPython: Productive Interactive Computing" description = "IPython: Productive Interactive Computing"
@@ -540,6 +568,14 @@ optional = false
python-versions = "*" python-versions = "*"
version = "0.6.1" version = "0.6.1"
[[package]]
category = "dev"
description = "More routines for operating on iterables, beyond itertools"
name = "more-itertools"
optional = false
python-versions = ">=3.5"
version = "8.5.0"
[[package]] [[package]]
category = "main" category = "main"
description = "MessagePack (de)serializer." description = "MessagePack (de)serializer."
@@ -825,6 +861,48 @@ version = "0.14.11"
[package.dependencies] [package.dependencies]
six = "*" six = "*"
[[package]]
category = "dev"
description = "pytest: simple powerful testing with Python"
name = "pytest"
optional = false
python-versions = ">=3.5"
version = "6.0.2"
[package.dependencies]
atomicwrites = ">=1.0"
attrs = ">=17.4.0"
colorama = "*"
iniconfig = "*"
more-itertools = ">=4.0.0"
packaging = "*"
pluggy = ">=0.12,<1.0"
py = ">=1.8.2"
toml = "*"
[package.dependencies.importlib-metadata]
python = "<3.8"
version = ">=0.12"
[package.extras]
checkqa_mypy = ["mypy (0.780)"]
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
[[package]]
category = "dev"
description = "Pytest plugin for measuring coverage."
name = "pytest-cov"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "2.10.1"
[package.dependencies]
coverage = ">=4.4"
pytest = ">=4.6"
[package.extras]
testing = ["fields", "hunter", "process-tests (2.0.2)", "six", "pytest-xdist", "virtualenv"]
[[package]] [[package]]
category = "main" category = "main"
description = "" description = ""
@@ -1105,7 +1183,7 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
[metadata] [metadata]
content-hash = "6262af10558561473850e085068f2450a508201316904bea1ac850673a4109b2" content-hash = "8df0839a479a0483c969368ef8f61f553773f27bdc0a569603c7141b6c360680"
python-versions = "^3.6" python-versions = "^3.6"
[metadata.files] [metadata.files]
@@ -1125,6 +1203,10 @@ astroid = [
{file = "astroid-2.4.2-py3-none-any.whl", hash = "sha256:bc58d83eb610252fd8de6363e39d4f1d0619c894b0ed24603b881c02e64c7386"}, {file = "astroid-2.4.2-py3-none-any.whl", hash = "sha256:bc58d83eb610252fd8de6363e39d4f1d0619c894b0ed24603b881c02e64c7386"},
{file = "astroid-2.4.2.tar.gz", hash = "sha256:2f4078c2a41bf377eea06d71c9d2ba4eb8f6b1af2135bec27bbbb7d8f12bb703"}, {file = "astroid-2.4.2.tar.gz", hash = "sha256:2f4078c2a41bf377eea06d71c9d2ba4eb8f6b1af2135bec27bbbb7d8f12bb703"},
] ]
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 = [ attrs = [
{file = "attrs-20.2.0-py2.py3-none-any.whl", hash = "sha256:fce7fc47dfc976152e82d53ff92fa0407700c21acd20886a13777a0d20e655dc"}, {file = "attrs-20.2.0-py2.py3-none-any.whl", hash = "sha256:fce7fc47dfc976152e82d53ff92fa0407700c21acd20886a13777a0d20e655dc"},
{file = "attrs-20.2.0.tar.gz", hash = "sha256:26b54ddbbb9ee1d34d5d3668dd37d6cf74990ab23c828c2888dccdceee395594"}, {file = "attrs-20.2.0.tar.gz", hash = "sha256:26b54ddbbb9ee1d34d5d3668dd37d6cf74990ab23c828c2888dccdceee395594"},
@@ -1218,6 +1300,42 @@ colorama = [
{file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"}, {file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"},
{file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"}, {file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"},
] ]
coverage = [
{file = "coverage-5.3-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:bd3166bb3b111e76a4f8e2980fa1addf2920a4ca9b2b8ca36a3bc3dedc618270"},
{file = "coverage-5.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9342dd70a1e151684727c9c91ea003b2fb33523bf19385d4554f7897ca0141d4"},
{file = "coverage-5.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:63808c30b41f3bbf65e29f7280bf793c79f54fb807057de7e5238ffc7cc4d7b9"},
{file = "coverage-5.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:4d6a42744139a7fa5b46a264874a781e8694bb32f1d76d8137b68138686f1729"},
{file = "coverage-5.3-cp27-cp27m-win32.whl", hash = "sha256:86e9f8cd4b0cdd57b4ae71a9c186717daa4c5a99f3238a8723f416256e0b064d"},
{file = "coverage-5.3-cp27-cp27m-win_amd64.whl", hash = "sha256:7858847f2d84bf6e64c7f66498e851c54de8ea06a6f96a32a1d192d846734418"},
{file = "coverage-5.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:530cc8aaf11cc2ac7430f3614b04645662ef20c348dce4167c22d99bec3480e9"},
{file = "coverage-5.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:381ead10b9b9af5f64646cd27107fb27b614ee7040bb1226f9c07ba96625cbb5"},
{file = "coverage-5.3-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:71b69bd716698fa62cd97137d6f2fdf49f534decb23a2c6fc80813e8b7be6822"},
{file = "coverage-5.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1d44bb3a652fed01f1f2c10d5477956116e9b391320c94d36c6bf13b088a1097"},
{file = "coverage-5.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:1c6703094c81fa55b816f5ae542c6ffc625fec769f22b053adb42ad712d086c9"},
{file = "coverage-5.3-cp35-cp35m-win32.whl", hash = "sha256:cedb2f9e1f990918ea061f28a0f0077a07702e3819602d3507e2ff98c8d20636"},
{file = "coverage-5.3-cp35-cp35m-win_amd64.whl", hash = "sha256:7f43286f13d91a34fadf61ae252a51a130223c52bfefb50310d5b2deb062cf0f"},
{file = "coverage-5.3-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:c851b35fc078389bc16b915a0a7c1d5923e12e2c5aeec58c52f4aa8085ac8237"},
{file = "coverage-5.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:aac1ba0a253e17889550ddb1b60a2063f7474155465577caa2a3b131224cfd54"},
{file = "coverage-5.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2b31f46bf7b31e6aa690d4c7a3d51bb262438c6dcb0d528adde446531d0d3bb7"},
{file = "coverage-5.3-cp36-cp36m-win32.whl", hash = "sha256:c5f17ad25d2c1286436761b462e22b5020d83316f8e8fcb5deb2b3151f8f1d3a"},
{file = "coverage-5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:aef72eae10b5e3116bac6957de1df4d75909fc76d1499a53fb6387434b6bcd8d"},
{file = "coverage-5.3-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:e8caf961e1b1a945db76f1b5fa9c91498d15f545ac0ababbe575cfab185d3bd8"},
{file = "coverage-5.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:29a6272fec10623fcbe158fdf9abc7a5fa032048ac1d8631f14b50fbfc10d17f"},
{file = "coverage-5.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2d43af2be93ffbad25dd959899b5b809618a496926146ce98ee0b23683f8c51c"},
{file = "coverage-5.3-cp37-cp37m-win32.whl", hash = "sha256:c3888a051226e676e383de03bf49eb633cd39fc829516e5334e69b8d81aae751"},
{file = "coverage-5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9669179786254a2e7e57f0ecf224e978471491d660aaca833f845b72a2df3709"},
{file = "coverage-5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0203acd33d2298e19b57451ebb0bed0ab0c602e5cf5a818591b4918b1f97d516"},
{file = "coverage-5.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:582ddfbe712025448206a5bc45855d16c2e491c2dd102ee9a2841418ac1c629f"},
{file = "coverage-5.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:0f313707cdecd5cd3e217fc68c78a960b616604b559e9ea60cc16795c4304259"},
{file = "coverage-5.3-cp38-cp38-win32.whl", hash = "sha256:78e93cc3571fd928a39c0b26767c986188a4118edc67bc0695bc7a284da22e82"},
{file = "coverage-5.3-cp38-cp38-win_amd64.whl", hash = "sha256:8f264ba2701b8c9f815b272ad568d555ef98dfe1576802ab3149c3629a9f2221"},
{file = "coverage-5.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:50691e744714856f03a86df3e2bff847c2acede4c191f9a1da38f088df342978"},
{file = "coverage-5.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9361de40701666b034c59ad9e317bae95c973b9ff92513dd0eced11c6adf2e21"},
{file = "coverage-5.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:c1b78fb9700fc961f53386ad2fd86d87091e06ede5d118b8a50dea285a071c24"},
{file = "coverage-5.3-cp39-cp39-win32.whl", hash = "sha256:cb7df71de0af56000115eafd000b867d1261f786b5eebd88a0ca6360cccfaca7"},
{file = "coverage-5.3-cp39-cp39-win_amd64.whl", hash = "sha256:47a11bdbd8ada9b7ee628596f9d97fbd3851bd9999d398e9436bd67376dbece7"},
{file = "coverage-5.3.tar.gz", hash = "sha256:280baa8ec489c4f542f8940f9c4c2181f0306a8ee1a54eceba071a449fb870a0"},
]
cryptography = [ cryptography = [
{file = "cryptography-3.1.1-cp27-cp27m-macosx_10_10_x86_64.whl", hash = "sha256:65beb15e7f9c16e15934569d29fb4def74ea1469d8781f6b3507ab896d6d8719"}, {file = "cryptography-3.1.1-cp27-cp27m-macosx_10_10_x86_64.whl", hash = "sha256:65beb15e7f9c16e15934569d29fb4def74ea1469d8781f6b3507ab896d6d8719"},
{file = "cryptography-3.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:983c0c3de4cb9fcba68fd3f45ed846eb86a2a8b8d8bc5bb18364c4d00b3c61fe"}, {file = "cryptography-3.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:983c0c3de4cb9fcba68fd3f45ed846eb86a2a8b8d8bc5bb18364c4d00b3c61fe"},
@@ -1275,8 +1393,8 @@ html5lib = [
{file = "html5lib-1.1.tar.gz", hash = "sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f"}, {file = "html5lib-1.1.tar.gz", hash = "sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f"},
] ]
identify = [ identify = [
{file = "identify-1.5.4-py2.py3-none-any.whl", hash = "sha256:d7da7de6825568daa4449858ce328ecc0e1ada2554d972a6f4f90e736aaf499a"}, {file = "identify-1.5.5-py2.py3-none-any.whl", hash = "sha256:da683bfb7669fa749fc7731f378229e2dbf29a1d1337cbde04106f02236eb29d"},
{file = "identify-1.5.4.tar.gz", hash = "sha256:e4db4796b3b0cf4f9cb921da51430abffff2d4ba7d7c521184ed5252bd90d461"}, {file = "identify-1.5.5.tar.gz", hash = "sha256:7c22c384a2c9b32c5cc891d13f923f6b2653aa83e2d75d8f79be240d6c86c4f4"},
] ]
idna = [ idna = [
{file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"},
@@ -1290,6 +1408,10 @@ importlib-resources = [
{file = "importlib_resources-3.0.0-py2.py3-none-any.whl", hash = "sha256:d028f66b66c0d5732dae86ba4276999855e162a749c92620a38c1d779ed138a7"}, {file = "importlib_resources-3.0.0-py2.py3-none-any.whl", hash = "sha256:d028f66b66c0d5732dae86ba4276999855e162a749c92620a38c1d779ed138a7"},
{file = "importlib_resources-3.0.0.tar.gz", hash = "sha256:19f745a6eca188b490b1428c8d1d4a0d2368759f32370ea8fb89cad2ab1106c3"}, {file = "importlib_resources-3.0.0.tar.gz", hash = "sha256:19f745a6eca188b490b1428c8d1d4a0d2368759f32370ea8fb89cad2ab1106c3"},
] ]
iniconfig = [
{file = "iniconfig-1.0.1-py3-none-any.whl", hash = "sha256:80cf40c597eb564e86346103f609d74efce0f6b4d4f30ec8ce9e2c26411ba437"},
{file = "iniconfig-1.0.1.tar.gz", hash = "sha256:e5f92f89355a67de0595932a6c6c02ab4afddc6fcdc0bfc5becd0d60884d3f69"},
]
ipython = [ ipython = [
{file = "ipython-7.18.1-py3-none-any.whl", hash = "sha256:2e22c1f74477b5106a6fb301c342ab8c64bb75d702e350f05a649e8cb40a0fb8"}, {file = "ipython-7.18.1-py3-none-any.whl", hash = "sha256:2e22c1f74477b5106a6fb301c342ab8c64bb75d702e350f05a649e8cb40a0fb8"},
{file = "ipython-7.18.1.tar.gz", hash = "sha256:a331e78086001931de9424940699691ad49dfb457cea31f5471eae7b78222d5e"}, {file = "ipython-7.18.1.tar.gz", hash = "sha256:a331e78086001931de9424940699691ad49dfb457cea31f5471eae7b78222d5e"},
@@ -1349,6 +1471,10 @@ mccabe = [
{file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
{file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
] ]
more-itertools = [
{file = "more-itertools-8.5.0.tar.gz", hash = "sha256:6f83822ae94818eae2612063a5101a7311e68ae8002005b5e05f03fd74a86a20"},
{file = "more_itertools-8.5.0-py3-none-any.whl", hash = "sha256:9b30f12df9393f0d28af9210ff8efe48d10c94f73e5daf886f10c4b0b0b4f03c"},
]
msgpack = [ msgpack = [
{file = "msgpack-1.0.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:cec8bf10981ed70998d98431cd814db0ecf3384e6b113366e7f36af71a0fca08"}, {file = "msgpack-1.0.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:cec8bf10981ed70998d98431cd814db0ecf3384e6b113366e7f36af71a0fca08"},
{file = "msgpack-1.0.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aa5c057eab4f40ec47ea6f5a9825846be2ff6bf34102c560bad5cad5a677c5be"}, {file = "msgpack-1.0.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aa5c057eab4f40ec47ea6f5a9825846be2ff6bf34102c560bad5cad5a677c5be"},
@@ -1472,6 +1598,14 @@ pyparsing = [
pyrsistent = [ pyrsistent = [
{file = "pyrsistent-0.14.11.tar.gz", hash = "sha256:3ca82748918eb65e2d89f222b702277099aca77e34843c5eb9d52451173970e2"}, {file = "pyrsistent-0.14.11.tar.gz", hash = "sha256:3ca82748918eb65e2d89f222b702277099aca77e34843c5eb9d52451173970e2"},
] ]
pytest = [
{file = "pytest-6.0.2-py3-none-any.whl", hash = "sha256:0e37f61339c4578776e090c3b8f6b16ce4db333889d65d0efb305243ec544b40"},
{file = "pytest-6.0.2.tar.gz", hash = "sha256:c8f57c2a30983f469bf03e68cdfa74dc474ce56b8f280ddcb080dfd91df01043"},
]
pytest-cov = [
{file = "pytest-cov-2.10.1.tar.gz", hash = "sha256:47bd0ce14056fdd79f93e1713f88fad7bdcc583dcd7783da86ef2f085a0bb88e"},
{file = "pytest_cov-2.10.1-py2.py3-none-any.whl", hash = "sha256:45ec2d5182f89a81fc3eb29e3d1ed3113b9e9a873bcddb2a71faaab066110191"},
]
pywin32-ctypes = [ pywin32-ctypes = [
{file = "pywin32-ctypes-0.2.0.tar.gz", hash = "sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942"}, {file = "pywin32-ctypes-0.2.0.tar.gz", hash = "sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942"},
{file = "pywin32_ctypes-0.2.0-py2.py3-none-any.whl", hash = "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"}, {file = "pywin32_ctypes-0.2.0-py2.py3-none-any.whl", hash = "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"},

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "tox-poetry-installer" name = "tox-poetry-installer"
version = "0.1.1" version = "0.1.3"
license = "MIT" license = "MIT"
authors = ["Ethan Paul <24588726+enpaul@users.noreply.github.com>"] authors = ["Ethan Paul <24588726+enpaul@users.noreply.github.com>"]
description = "Tox plugin to install Tox environment dependencies using the Poetry backend and lockfile" description = "Tox plugin to install Tox environment dependencies using the Poetry backend and lockfile"
@@ -27,19 +27,22 @@ poetry_installer = "tox_poetry_installer"
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.6" python = "^3.6"
poetry = "^1.0.0" poetry = ">=1.0.0, <1.1.0"
tox = "^2.3.0 || ^3.0.0" tox = "^2.3.0 || ^3.0.0"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
bandit = "^1.6.2" bandit = "^1.6.2"
black = {version = "^20.8b1", allow-prereleases = true}
ipython = {version = "^7.18.1", python = "^3.7"} ipython = {version = "^7.18.1", python = "^3.7"}
mypy = "^0.782" mypy = "^0.782"
pre-commit = {version = "^2.7.1", python = "^3.6.1"} pre-commit = {version = "^2.7.1", python = "^3.6.1"}
pylint = "^2.4.4" pylint = "^2.4.4"
pytest = "^6.0.2"
pytest-cov = "^2.10.1"
reorder-python-imports = {version = "^2.3.5", python = "^3.6.1"} reorder-python-imports = {version = "^2.3.5", python = "^3.6.1"}
safety = "^1.9.0" safety = "^1.9.0"
toml = "^0.10.1"
tox = "^3.20.0" tox = "^3.20.0"
black = {version = "^20.8b1", allow-prereleases = true}
[build-system] [build-system]
requires = ["poetry>=1.0.0"] requires = ["poetry>=1.0.0"]

39
tests/test_metadata.py Normal file
View File

@@ -0,0 +1,39 @@
"""Ensure that the pyproject and module metadata never drift out of sync
The next best thing to having one source of truth is having a way to ensure all of your
sources of truth agree with each other.
"""
from pathlib import Path
import toml
import tox_poetry_installer
def test_metadata():
"""Test that module metadata matches pyproject poetry metadata"""
with (Path(__file__).resolve().parent / ".." / "pyproject.toml").open() as infile:
pyproject = toml.load(infile, _dict=dict)
assert pyproject["tool"]["poetry"]["name"] == tox_poetry_installer.__title__
assert pyproject["tool"]["poetry"]["version"] == tox_poetry_installer.__version__
assert pyproject["tool"]["poetry"]["license"] == tox_poetry_installer.__license__
assert (
pyproject["tool"]["poetry"]["description"] == tox_poetry_installer.__summary__
)
assert pyproject["tool"]["poetry"]["repository"] == tox_poetry_installer.__url__
assert (
all(
item in tox_poetry_installer.__authors__
for item in pyproject["tool"]["poetry"]["authors"]
)
is True
)
assert (
all(
item in pyproject["tool"]["poetry"]["authors"]
for item in tox_poetry_installer.__authors__
)
is True
)

54
tox.ini
View File

@@ -1,17 +1,19 @@
[tox] [tox]
envlist = py36, py37, py38, static, security envlist = py36, py37, py38, static, static-tests, security
isolated_build = true isolated_build = true
[testenv] [testenv]
description = Run the tests description = Run the tests
deps = deps =
requests pytest
pytest-cov
toml
commands = commands =
pip freeze pytest --cov tox_poetry_installer --cov-config {toxinidir}/.coveragerc tests/ --cov-report term-missing
[testenv:static] [testenv:static]
description = Static code quality checks and formatting enforcement description = Static formatting and quality enforcement
basepython = python3.7 basepython = python3.8
ignore_errors = true ignore_errors = true
deps = deps =
pylint pylint
@@ -20,21 +22,41 @@ deps =
reorder-python-imports reorder-python-imports
pre-commit pre-commit
commands = commands =
black tox_poetry_installer.py black {toxinidir}/tox_poetry_installer.py
reorder-python-imports tox_poetry_installer.py reorder-python-imports {toxinidir}/tox_poetry_installer.py
pylint tox_poetry_installer.py
mypy tox_poetry_installer.py --ignore-missing-imports --no-strict-optional
pre-commit run --all-files pre-commit run --all-files
pylint --rcfile {toxinidir}/.pylintrc {toxinidir}/tox_poetry_installer.py
mypy --ignore-missing-imports --no-strict-optional {toxinidir}/tox_poetry_installer.py
[testenv:security] [testenv:static-tests]
description = Security checks description = Static formatting and quality enforcement for the tests
basepython = python3.7 basepython = python3.8
ignore_errors = true ingore_errors = true
deps = deps =
bandit pylint
safety mypy
black
reorder-python-imports
allowlist_externals = allowlist_externals =
bash bash
commands = commands =
bandit tox_poetry_installer.py --recursive black {toxinidir}/tests/
bash -c "reorder-python-imports {toxinidir}/tests/*.py --unclassifiable-application-module tox_poetry_installer"
pylint --rcfile {toxinidir}/.pylintrc {toxinidir}/tests/
mypy --ignore-missing-imports --no-strict-optional {toxinidir}/tests/
[testenv:security]
description = Security checks
basepython = python3.8
ignore_errors = true
skip_install = true
deps =
bandit
safety
poetry
allowlist_externals =
bash
commands =
bandit --quiet {toxinidir}/tox_poetry_installer.py
bash -c "bandit --quiet --skip B101 {toxinidir}/tests/*.py"
bash -c "poetry export --format requirements.txt --without-hashes --dev | safety check --stdin --bare" bash -c "poetry export --format requirements.txt --without-hashes --dev | safety check --stdin --bare"

View File

@@ -5,11 +5,11 @@ installation functionality to install dependencies from the Poetry lockfile for
does this by using ``poetry`` to read in the lockfile, identify necessary dependencies, and then does this by using ``poetry`` to read in the lockfile, identify necessary dependencies, and then
use Poetry's ``PipInstaller`` class to install those packages into the Tox environment. use Poetry's ``PipInstaller`` class to install those packages into the Tox environment.
""" """
import logging
from pathlib import Path from pathlib import Path
from typing import Dict from typing import Dict
from typing import List from typing import List
from typing import Optional from typing import Optional
from typing import Sequence
from typing import Tuple from typing import Tuple
from poetry.factory import Factory as PoetryFactory from poetry.factory import Factory as PoetryFactory
@@ -20,19 +20,22 @@ from poetry.packages import Package as PoetryPackage
from poetry.puzzle.provider import Provider as PoetryProvider from poetry.puzzle.provider import Provider as PoetryProvider
from poetry.utils.env import VirtualEnv as PoetryVirtualEnv from poetry.utils.env import VirtualEnv as PoetryVirtualEnv
from tox import hookimpl from tox import hookimpl
from tox import reporter
from tox.action import Action as ToxAction from tox.action import Action as ToxAction
from tox.venv import VirtualEnv as ToxVirtualEnv from tox.venv import VirtualEnv as ToxVirtualEnv
__title__ = "tox-poetry-installer" __title__ = "tox-poetry-installer"
__summary__ = "Tox plugin to install Tox environment dependencies using the Poetry backend and lockfile" __summary__ = "Tox plugin to install Tox environment dependencies using the Poetry backend and lockfile"
__version__ = "0.1.0" __version__ = "0.1.3"
__url__ = "https://github.com/enpaul/tox-poetry-installer/" __url__ = "https://github.com/enpaul/tox-poetry-installer/"
__license__ = "MIT" __license__ = "MIT"
__authors__ = ["Ethan Paul <e@enp.one>"] __authors__ = ["Ethan Paul <24588726+enpaul@users.noreply.github.com>"]
PEP440_VERSION_DELIMITERS: Tuple[str, ...] = ("~=", "==", "!=", ">", "<") _PEP508_VERSION_DELIMITERS: Tuple[str, ...] = ("~=", "==", "!=", ">", "<")
_REPORTER_PREFIX = f"[{__title__}]:"
class ToxPoetryInstallerException(Exception): class ToxPoetryInstallerException(Exception):
@@ -43,9 +46,24 @@ class NoLockedDependencyError(ToxPoetryInstallerException):
"""Cannot install a package that is not in the lockfile""" """Cannot install a package that is not in the lockfile"""
def _make_poetry(venv: ToxVirtualEnv) -> Poetry: def _install_to_venv(
"""Helper to make a poetry object from a toxenv""" poetry: Poetry, venv: ToxVirtualEnv, packages: Sequence[PoetryPackage]
return PoetryFactory().create_poetry(venv.envconfig.config.toxinidir) ):
"""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
"""
installer = PoetryPipInstaller(
env=PoetryVirtualEnv(path=Path(venv.envconfig.envdir)),
io=PoetryNullIO(),
pool=poetry.pool,
)
for dependency in packages:
reporter.verbosity1(f"{_REPORTER_PREFIX} installing {dependency}")
installer.install(dependency)
def _find_locked_dependencies( def _find_locked_dependencies(
@@ -72,6 +90,9 @@ def _find_locked_dependencies(
def find_transients(name: str) -> List[PoetryPackage]: def find_transients(name: str) -> List[PoetryPackage]:
if name in PoetryProvider.UNSAFE_PACKAGES: if name in PoetryProvider.UNSAFE_PACKAGES:
reporter.warning(
f"{_REPORTER_PREFIX} installing '{name}' using Poetry is not supported; skipping"
)
return [] return []
transients = [packages[name]] transients = [packages[name]]
for dep in packages[name].requires: for dep in packages[name].requires:
@@ -81,7 +102,9 @@ def _find_locked_dependencies(
return find_transients(top_level.name) return find_transients(top_level.name)
except KeyError: except KeyError:
if any(delimiter in dependency_name for delimiter in PEP440_VERSION_DELIMITERS): if any(
delimiter in dependency_name for delimiter in _PEP508_VERSION_DELIMITERS
):
message = "specifying a version in the tox environment definition is incompatible with installing from a lockfile" message = "specifying a version in the tox environment definition is incompatible with installing from a lockfile"
else: else:
message = ( message = (
@@ -107,34 +130,48 @@ def tox_testenv_install_deps(
:param action: Tox action object :param action: Tox action object
""" """
logger = logging.getLogger(__name__)
if action.name == venv.envconfig.config.isolated_build_env: if action.name == venv.envconfig.config.isolated_build_env:
logger.debug( reporter.verbosity1(
f"Environment {action.name} is isolated build environment; skipping Poetry-based dependency installation" f"{_REPORTER_PREFIX} skipping isolated build env '{action.name}'"
) )
return None return None
poetry = _make_poetry(venv) poetry = PoetryFactory().create_poetry(venv.envconfig.config.toxinidir)
logger.debug(f"Loaded project pyproject.toml from {poetry.file}") reporter.verbosity1(
f"{_REPORTER_PREFIX} loaded project pyproject.toml from {poetry.file}"
)
dependencies: List[PoetryPackage] = [] dependencies: List[PoetryPackage] = []
for env_dependency in venv.envconfig.deps: for env_dependency in venv.envconfig.deps:
dependencies += _find_locked_dependencies(poetry, env_dependency.name) dependencies += _find_locked_dependencies(poetry, env_dependency.name)
logger.debug( reporter.verbosity1(
f"Identified {len(dependencies)} dependencies for environment {action.name}" f"{_REPORTER_PREFIX} identified {len(dependencies)} actual dependencies from {len(venv.envconfig.deps)} specified env dependencies"
) )
installer = PoetryPipInstaller( reporter.verbosity0(
env=PoetryVirtualEnv(path=Path(venv.envconfig.envdir)), f"{_REPORTER_PREFIX} ({venv.name}) installing {len(dependencies)} env dependencies from lockfile"
io=PoetryNullIO(),
pool=poetry.pool,
) )
_install_to_venv(poetry, venv, dependencies)
for dependency in dependencies: if not venv.envconfig.skip_install:
logger.info(f"Installing environment dependency: {dependency}") reporter.verbosity1(
installer.install(dependency) f"{_REPORTER_PREFIX} env specifies 'skip_install = false', performing installation of dev-package dependencies"
)
primary_dependencies = poetry.locker.locked_repository(False).packages
reporter.verbosity1(
f"{_REPORTER_PREFIX} identified {len(primary_dependencies)} dependencies of dev-package"
)
reporter.verbosity0(
f"{_REPORTER_PREFIX} ({venv.name}) installing {len(primary_dependencies)} dev-package dependencies from lockfile"
)
_install_to_venv(poetry, venv, primary_dependencies)
else:
reporter.verbosity1(
f"{_REPORTER_PREFIX} env specifies 'skip_install = true', skipping installation of dev-package package"
)
return dependencies return dependencies