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
# You can set these variables from the command line
PROJECT = tox_poetry_installer
.PHONY: help
# Put it first so that "make" without argument is like "make help"
# Adapted from:
@@ -11,19 +8,18 @@ help: ## List Makefile targets
$(info Makefile documentation)
@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:
rm -rf ./.mypy_cache
rm -rf ./.tox
rm -f .coverage
rm --recursive --force ./.mypy_cache
rm --recursive --force ./.tox
rm --recursive --force tests/__pycache__/
rm --recursive --force .pytest_cache/
rm --force .coverage
clean-py:
rm -rf ./dist
rm -rf ./build
rm -rf ./*.egg-info
rm -rf __pycache__/
rm --recursive --force ./dist
rm --recursive --force ./build
rm --recursive --force ./*.egg-info
rm --recursive --force __pycache__/
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
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
- [ ] 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.
- [ ] Support the [`extras`](https://tox.readthedocs.io/en/latest/config.html#conf-extras)
Tox configuration option
@@ -265,7 +265,7 @@ usage in production systems.
environments when necessary.
- [ ] Add warnings when an unsupported Tox configuration option is detected while using the
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.
- [ ] 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

142
poetry.lock generated
View File

@@ -44,6 +44,15 @@ wrapt = ">=1.11,<2.0"
python = "<3.8"
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]]
category = "main"
description = "Classes Without Boilerplate"
@@ -227,6 +236,17 @@ optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
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]]
category = "main"
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"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
version = "1.5.4"
version = "1.5.5"
[package.extras]
license = ["editdistance"]
@@ -390,6 +410,14 @@ version = ">=0.4"
[package.extras]
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]]
category = "dev"
description = "IPython: Productive Interactive Computing"
@@ -540,6 +568,14 @@ optional = false
python-versions = "*"
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]]
category = "main"
description = "MessagePack (de)serializer."
@@ -825,6 +861,48 @@ version = "0.14.11"
[package.dependencies]
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]]
category = "main"
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"]
[metadata]
content-hash = "6262af10558561473850e085068f2450a508201316904bea1ac850673a4109b2"
content-hash = "8df0839a479a0483c969368ef8f61f553773f27bdc0a569603c7141b6c360680"
python-versions = "^3.6"
[metadata.files]
@@ -1125,6 +1203,10 @@ astroid = [
{file = "astroid-2.4.2-py3-none-any.whl", hash = "sha256:bc58d83eb610252fd8de6363e39d4f1d0619c894b0ed24603b881c02e64c7386"},
{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 = [
{file = "attrs-20.2.0-py2.py3-none-any.whl", hash = "sha256:fce7fc47dfc976152e82d53ff92fa0407700c21acd20886a13777a0d20e655dc"},
{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.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 = [
{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"},
@@ -1275,8 +1393,8 @@ html5lib = [
{file = "html5lib-1.1.tar.gz", hash = "sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f"},
]
identify = [
{file = "identify-1.5.4-py2.py3-none-any.whl", hash = "sha256:d7da7de6825568daa4449858ce328ecc0e1ada2554d972a6f4f90e736aaf499a"},
{file = "identify-1.5.4.tar.gz", hash = "sha256:e4db4796b3b0cf4f9cb921da51430abffff2d4ba7d7c521184ed5252bd90d461"},
{file = "identify-1.5.5-py2.py3-none-any.whl", hash = "sha256:da683bfb7669fa749fc7731f378229e2dbf29a1d1337cbde04106f02236eb29d"},
{file = "identify-1.5.5.tar.gz", hash = "sha256:7c22c384a2c9b32c5cc891d13f923f6b2653aa83e2d75d8f79be240d6c86c4f4"},
]
idna = [
{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.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 = [
{file = "ipython-7.18.1-py3-none-any.whl", hash = "sha256:2e22c1f74477b5106a6fb301c342ab8c64bb75d702e350f05a649e8cb40a0fb8"},
{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.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 = [
{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"},
@@ -1472,6 +1598,14 @@ pyparsing = [
pyrsistent = [
{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 = [
{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"},

View File

@@ -1,6 +1,6 @@
[tool.poetry]
name = "tox-poetry-installer"
version = "0.1.1"
version = "0.1.3"
license = "MIT"
authors = ["Ethan Paul <24588726+enpaul@users.noreply.github.com>"]
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]
python = "^3.6"
poetry = "^1.0.0"
poetry = ">=1.0.0, <1.1.0"
tox = "^2.3.0 || ^3.0.0"
[tool.poetry.dev-dependencies]
bandit = "^1.6.2"
black = {version = "^20.8b1", allow-prereleases = true}
ipython = {version = "^7.18.1", python = "^3.7"}
mypy = "^0.782"
pre-commit = {version = "^2.7.1", python = "^3.6.1"}
pylint = "^2.4.4"
pytest = "^6.0.2"
pytest-cov = "^2.10.1"
reorder-python-imports = {version = "^2.3.5", python = "^3.6.1"}
safety = "^1.9.0"
toml = "^0.10.1"
tox = "^3.20.0"
black = {version = "^20.8b1", allow-prereleases = true}
[build-system]
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]
envlist = py36, py37, py38, static, security
envlist = py36, py37, py38, static, static-tests, security
isolated_build = true
[testenv]
description = Run the tests
deps =
requests
pytest
pytest-cov
toml
commands =
pip freeze
pytest --cov tox_poetry_installer --cov-config {toxinidir}/.coveragerc tests/ --cov-report term-missing
[testenv:static]
description = Static code quality checks and formatting enforcement
basepython = python3.7
description = Static formatting and quality enforcement
basepython = python3.8
ignore_errors = true
deps =
pylint
@@ -20,21 +22,41 @@ deps =
reorder-python-imports
pre-commit
commands =
black tox_poetry_installer.py
reorder-python-imports tox_poetry_installer.py
pylint tox_poetry_installer.py
mypy tox_poetry_installer.py --ignore-missing-imports --no-strict-optional
black {toxinidir}/tox_poetry_installer.py
reorder-python-imports {toxinidir}/tox_poetry_installer.py
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]
description = Security checks
basepython = python3.7
ignore_errors = true
[testenv:static-tests]
description = Static formatting and quality enforcement for the tests
basepython = python3.8
ingore_errors = true
deps =
bandit
safety
pylint
mypy
black
reorder-python-imports
allowlist_externals =
bash
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"

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
use Poetry's ``PipInstaller`` class to install those packages into the Tox environment.
"""
import logging
from pathlib import Path
from typing import Dict
from typing import List
from typing import Optional
from typing import Sequence
from typing import Tuple
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.utils.env import VirtualEnv as PoetryVirtualEnv
from tox import hookimpl
from tox import reporter
from tox.action import Action as ToxAction
from tox.venv import VirtualEnv as ToxVirtualEnv
__title__ = "tox-poetry-installer"
__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/"
__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):
@@ -43,9 +46,24 @@ class NoLockedDependencyError(ToxPoetryInstallerException):
"""Cannot install a package that is not in the lockfile"""
def _make_poetry(venv: ToxVirtualEnv) -> Poetry:
"""Helper to make a poetry object from a toxenv"""
return PoetryFactory().create_poetry(venv.envconfig.config.toxinidir)
def _install_to_venv(
poetry: Poetry, venv: ToxVirtualEnv, packages: Sequence[PoetryPackage]
):
"""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(
@@ -72,6 +90,9 @@ def _find_locked_dependencies(
def find_transients(name: str) -> List[PoetryPackage]:
if name in PoetryProvider.UNSAFE_PACKAGES:
reporter.warning(
f"{_REPORTER_PREFIX} installing '{name}' using Poetry is not supported; skipping"
)
return []
transients = [packages[name]]
for dep in packages[name].requires:
@@ -81,7 +102,9 @@ def _find_locked_dependencies(
return find_transients(top_level.name)
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"
else:
message = (
@@ -107,34 +130,48 @@ def tox_testenv_install_deps(
:param action: Tox action object
"""
logger = logging.getLogger(__name__)
if action.name == venv.envconfig.config.isolated_build_env:
logger.debug(
f"Environment {action.name} is isolated build environment; skipping Poetry-based dependency installation"
reporter.verbosity1(
f"{_REPORTER_PREFIX} skipping isolated build env '{action.name}'"
)
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] = []
for env_dependency in venv.envconfig.deps:
dependencies += _find_locked_dependencies(poetry, env_dependency.name)
logger.debug(
f"Identified {len(dependencies)} dependencies for environment {action.name}"
reporter.verbosity1(
f"{_REPORTER_PREFIX} identified {len(dependencies)} actual dependencies from {len(venv.envconfig.deps)} specified env dependencies"
)
installer = PoetryPipInstaller(
env=PoetryVirtualEnv(path=Path(venv.envconfig.envdir)),
io=PoetryNullIO(),
pool=poetry.pool,
reporter.verbosity0(
f"{_REPORTER_PREFIX} ({venv.name}) installing {len(dependencies)} env dependencies from lockfile"
)
_install_to_venv(poetry, venv, dependencies)
for dependency in dependencies:
logger.info(f"Installing environment dependency: {dependency}")
installer.install(dependency)
if not venv.envconfig.skip_install:
reporter.verbosity1(
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