Tests - parallelize python tests w/ pytest-xdist
This commit is contained in:
parent
df7532a633
commit
872105e2d3
2
.gitignore
vendored
2
.gitignore
vendored
@ -8,7 +8,7 @@ Makefile.custom.config
|
|||||||
__pycache__
|
__pycache__
|
||||||
uploads
|
uploads
|
||||||
.cache
|
.cache
|
||||||
.coverage
|
.coverage*
|
||||||
coverage.xml
|
coverage.xml
|
||||||
.env
|
.env
|
||||||
.mypy_cache
|
.mypy_cache
|
||||||
|
2
Makefile
2
Makefile
@ -232,6 +232,8 @@ test-e2e-client:
|
|||||||
E2E_ARGS=client $(PYTEST) e2e --driver firefox $(PYTEST_ARGS)
|
E2E_ARGS=client $(PYTEST) e2e --driver firefox $(PYTEST_ARGS)
|
||||||
|
|
||||||
test-python:
|
test-python:
|
||||||
|
# for tests parallelization: 4 workers max.
|
||||||
|
# make test-python PYTEST_ARGS="-p no:warnings -n auto --maxprocesses=4"
|
||||||
$(PYTEST) fittrackee --cov-config .coveragerc --cov=fittrackee --cov-report term-missing $(PYTEST_ARGS)
|
$(PYTEST) fittrackee --cov-config .coveragerc --cov=fittrackee --cov-report term-missing $(PYTEST_ARGS)
|
||||||
|
|
||||||
test-client:
|
test-client:
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
DROP DATABASE IF EXISTS fittrackee;
|
DROP DATABASE IF EXISTS fittrackee;
|
||||||
DROP DATABASE IF EXISTS fittrackee_test;
|
DROP DATABASE IF EXISTS fittrackee_test;
|
||||||
|
DROP DATABASE IF EXISTS fittrackee_test_gw0;
|
||||||
|
DROP DATABASE IF EXISTS fittrackee_test_gw1;
|
||||||
|
DROP DATABASE IF EXISTS fittrackee_test_gw2;
|
||||||
|
DROP DATABASE IF EXISTS fittrackee_test_gw3;
|
||||||
DROP SCHEMA IF EXISTS fittrackee;
|
DROP SCHEMA IF EXISTS fittrackee;
|
||||||
DROP USER IF EXISTS fittrackee;
|
DROP USER IF EXISTS fittrackee;
|
||||||
|
|
||||||
@ -7,3 +11,7 @@ CREATE USER fittrackee WITH PASSWORD 'fittrackee';
|
|||||||
CREATE SCHEMA fittrackee AUTHORIZATION fittrackee;
|
CREATE SCHEMA fittrackee AUTHORIZATION fittrackee;
|
||||||
CREATE DATABASE fittrackee OWNER fittrackee;
|
CREATE DATABASE fittrackee OWNER fittrackee;
|
||||||
CREATE DATABASE fittrackee_test OWNER fittrackee;
|
CREATE DATABASE fittrackee_test OWNER fittrackee;
|
||||||
|
CREATE DATABASE fittrackee_test_gw0 OWNER fittrackee;
|
||||||
|
CREATE DATABASE fittrackee_test_gw1 OWNER fittrackee;
|
||||||
|
CREATE DATABASE fittrackee_test_gw2 OWNER fittrackee;
|
||||||
|
CREATE DATABASE fittrackee_test_gw3 OWNER fittrackee;
|
||||||
|
@ -10,6 +10,12 @@ if os.getenv('APP_SETTINGS') == 'fittrackee.config.TestingConfig':
|
|||||||
else:
|
else:
|
||||||
broker = RedisBroker
|
broker = RedisBroker
|
||||||
|
|
||||||
|
XDIST_WORKER = (
|
||||||
|
f"_{os.getenv('PYTEST_XDIST_WORKER')}"
|
||||||
|
if os.getenv('PYTEST_XDIST_WORKER')
|
||||||
|
else ''
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BaseConfig:
|
class BaseConfig:
|
||||||
|
|
||||||
@ -74,7 +80,13 @@ class DevelopmentConfig(BaseConfig):
|
|||||||
class TestingConfig(BaseConfig):
|
class TestingConfig(BaseConfig):
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
TESTING = True
|
TESTING = True
|
||||||
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_TEST_URL')
|
SQLALCHEMY_DATABASE_URI = (
|
||||||
|
os.environ.get('DATABASE_TEST_URL', '') + XDIST_WORKER
|
||||||
|
)
|
||||||
|
UPLOAD_FOLDER = os.path.join(
|
||||||
|
os.getenv('UPLOAD_FOLDER', current_app.root_path),
|
||||||
|
'uploads' + XDIST_WORKER,
|
||||||
|
)
|
||||||
SECRET_KEY = 'test key' # nosec
|
SECRET_KEY = 'test key' # nosec
|
||||||
BCRYPT_LOG_ROUNDS = 4
|
BCRYPT_LOG_ROUNDS = 4
|
||||||
TOKEN_EXPIRATION_DAYS = 0
|
TOKEN_EXPIRATION_DAYS = 0
|
||||||
|
@ -41,7 +41,11 @@ class TestTestingConfig:
|
|||||||
app.config.from_object('fittrackee.config.TestingConfig')
|
app.config.from_object('fittrackee.config.TestingConfig')
|
||||||
|
|
||||||
assert app.config['SQLALCHEMY_DATABASE_URI'] == os.environ.get(
|
assert app.config['SQLALCHEMY_DATABASE_URI'] == os.environ.get(
|
||||||
'DATABASE_TEST_URL'
|
'DATABASE_TEST_URL', ''
|
||||||
|
) + (
|
||||||
|
f"_{os.getenv('PYTEST_XDIST_WORKER')}"
|
||||||
|
if os.getenv('PYTEST_XDIST_WORKER')
|
||||||
|
else ''
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_it_does_not_preserve_context_on_exception(
|
def test_it_does_not_preserve_context_on_exception(
|
||||||
|
@ -8,6 +8,7 @@ os.environ['APP_SETTINGS'] = 'fittrackee.config.TestingConfig'
|
|||||||
# to avoid resetting dev database during tests
|
# to avoid resetting dev database during tests
|
||||||
os.environ['DATABASE_URL'] = os.environ['DATABASE_TEST_URL']
|
os.environ['DATABASE_URL'] = os.environ['DATABASE_TEST_URL']
|
||||||
TEMP_FOLDER = '/tmp/FitTrackee'
|
TEMP_FOLDER = '/tmp/FitTrackee'
|
||||||
|
os.makedirs(TEMP_FOLDER, exist_ok=True)
|
||||||
os.environ['UPLOAD_FOLDER'] = TEMP_FOLDER
|
os.environ['UPLOAD_FOLDER'] = TEMP_FOLDER
|
||||||
os.environ['APP_LOG'] = TEMP_FOLDER + '/fittrackee.log'
|
os.environ['APP_LOG'] = TEMP_FOLDER + '/fittrackee.log'
|
||||||
os.environ['AUTHLIB_INSECURE_TRANSPORT'] = '1'
|
os.environ['AUTHLIB_INSECURE_TRANSPORT'] = '1'
|
||||||
|
7
fittrackee/tests/fixtures/fixtures_app.py
vendored
7
fittrackee/tests/fixtures/fixtures_app.py
vendored
@ -18,7 +18,11 @@ def get_app_config(
|
|||||||
max_users: Optional[int] = None,
|
max_users: Optional[int] = None,
|
||||||
) -> Optional[AppConfig]:
|
) -> Optional[AppConfig]:
|
||||||
if with_config:
|
if with_config:
|
||||||
config = AppConfig()
|
config = AppConfig.query.one_or_none()
|
||||||
|
if not config:
|
||||||
|
config = AppConfig()
|
||||||
|
db.session.add(config)
|
||||||
|
db.session.flush()
|
||||||
config.gpx_limit_import = 10 if max_workouts is None else max_workouts
|
config.gpx_limit_import = 10 if max_workouts is None else max_workouts
|
||||||
config.max_single_file_size = (
|
config.max_single_file_size = (
|
||||||
(1 if max_single_file_size is None else max_single_file_size)
|
(1 if max_single_file_size is None else max_single_file_size)
|
||||||
@ -31,7 +35,6 @@ def get_app_config(
|
|||||||
* 1024
|
* 1024
|
||||||
)
|
)
|
||||||
config.max_users = 100 if max_users is None else max_users
|
config.max_users = 100 if max_users is None else max_users
|
||||||
db.session.add(config)
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return config
|
return config
|
||||||
return None
|
return None
|
||||||
|
@ -172,7 +172,7 @@ class TestCreateOAuth2Client:
|
|||||||
|
|
||||||
class TestOAuthCheckScopes:
|
class TestOAuthCheckScopes:
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'input_scope', ['', 1, random_string(), [random_string(), 'readwrite']]
|
'input_scope', ['', 1, 'invalid_scope', ['invalid_scope', 'readwrite']]
|
||||||
)
|
)
|
||||||
def test_it_raises_error_when_scope_is_invalid(
|
def test_it_raises_error_when_scope_is_invalid(
|
||||||
self, input_scope: Any
|
self, input_scope: Any
|
||||||
@ -184,11 +184,11 @@ class TestOAuthCheckScopes:
|
|||||||
'input_scope,expected_scope',
|
'input_scope,expected_scope',
|
||||||
[
|
[
|
||||||
('profile:read', 'profile:read'),
|
('profile:read', 'profile:read'),
|
||||||
('profile:read ' + random_string(), 'profile:read'),
|
('profile:read invalid_scope:read', 'profile:read'),
|
||||||
('profile:write', 'profile:write'),
|
('profile:write', 'profile:write'),
|
||||||
('profile:read profile:write', 'profile:read profile:write'),
|
('profile:read profile:write', 'profile:read profile:write'),
|
||||||
(
|
(
|
||||||
'profile:write profile:read ' + random_string(),
|
'profile:write invalid_scope:read profile:read',
|
||||||
'profile:write profile:read',
|
'profile:write profile:read',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
from typing import Union
|
from typing import Union
|
||||||
from uuid import uuid4
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@ -34,7 +33,7 @@ class TestReadableDuration:
|
|||||||
('en', '30 seconds'),
|
('en', '30 seconds'),
|
||||||
('fr', '30 secondes'),
|
('fr', '30 secondes'),
|
||||||
(None, '30 seconds'),
|
(None, '30 seconds'),
|
||||||
(uuid4().hex, '30 seconds'),
|
('invalid_locale', '30 seconds'),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_it_returns_duration_in_locale(
|
def test_it_returns_duration_in_locale(
|
||||||
|
66
poetry.lock
generated
66
poetry.lock
generated
@ -280,6 +280,17 @@ python-versions = ">=3.7"
|
|||||||
[package.extras]
|
[package.extras]
|
||||||
test = ["pytest (>=6)"]
|
test = ["pytest (>=6)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "execnet"
|
||||||
|
version = "1.9.0"
|
||||||
|
description = "execnet: rapid multi-Python deployment"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
testing = ["pre-commit"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flake8"
|
name = "flake8"
|
||||||
version = "3.9.2"
|
version = "3.9.2"
|
||||||
@ -745,6 +756,17 @@ python-versions = ">=3.6"
|
|||||||
[package.extras]
|
[package.extras]
|
||||||
twisted = ["twisted"]
|
twisted = ["twisted"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "psutil"
|
||||||
|
version = "5.9.4"
|
||||||
|
description = "Cross-platform lib for process and system monitoring in Python."
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "psycopg2-binary"
|
name = "psycopg2-binary"
|
||||||
version = "2.9.5"
|
version = "2.9.5"
|
||||||
@ -1002,6 +1024,24 @@ hjson = ["hjson"]
|
|||||||
toml = ["toml"]
|
toml = ["toml"]
|
||||||
yaml = ["PyYAML"]
|
yaml = ["PyYAML"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pytest-xdist"
|
||||||
|
version = "3.0.2"
|
||||||
|
description = "pytest xdist plugin for distributed testing and loop-on-failing modes"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
execnet = ">=1.1"
|
||||||
|
psutil = {version = ">=3.0", optional = true, markers = "extra == \"psutil\""}
|
||||||
|
pytest = ">=6.2.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
psutil = ["psutil (>=3.0)"]
|
||||||
|
setproctitle = ["setproctitle"]
|
||||||
|
testing = ["filelock"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "python-dateutil"
|
name = "python-dateutil"
|
||||||
version = "2.8.2"
|
version = "2.8.2"
|
||||||
@ -1577,7 +1617,7 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools"
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "1.1"
|
lock-version = "1.1"
|
||||||
python-versions = "^3.7"
|
python-versions = "^3.7"
|
||||||
content-hash = "b8ef9801e4dcd04375d3a5e83303ddc8a1b65ad35a127e1e2fd115e85cbe095c"
|
content-hash = "ae84573fe28fd08fc1a7917d20ca97f73e070a668cf0baa0ac546d3a6f7e58ae"
|
||||||
|
|
||||||
[metadata.files]
|
[metadata.files]
|
||||||
alabaster = [
|
alabaster = [
|
||||||
@ -1840,6 +1880,10 @@ exceptiongroup = [
|
|||||||
{file = "exceptiongroup-1.0.1-py3-none-any.whl", hash = "sha256:4d6c0aa6dd825810941c792f53d7b8d71da26f5e5f84f20f9508e8f2d33b140a"},
|
{file = "exceptiongroup-1.0.1-py3-none-any.whl", hash = "sha256:4d6c0aa6dd825810941c792f53d7b8d71da26f5e5f84f20f9508e8f2d33b140a"},
|
||||||
{file = "exceptiongroup-1.0.1.tar.gz", hash = "sha256:73866f7f842ede6cb1daa42c4af078e2035e5f7607f0e2c762cc51bb31bbe7b2"},
|
{file = "exceptiongroup-1.0.1.tar.gz", hash = "sha256:73866f7f842ede6cb1daa42c4af078e2035e5f7607f0e2c762cc51bb31bbe7b2"},
|
||||||
]
|
]
|
||||||
|
execnet = [
|
||||||
|
{file = "execnet-1.9.0-py2.py3-none-any.whl", hash = "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"},
|
||||||
|
{file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"},
|
||||||
|
]
|
||||||
flake8 = [
|
flake8 = [
|
||||||
{file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"},
|
{file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"},
|
||||||
{file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"},
|
{file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"},
|
||||||
@ -2165,6 +2209,22 @@ prometheus-client = [
|
|||||||
{file = "prometheus_client-0.15.0-py3-none-any.whl", hash = "sha256:db7c05cbd13a0f79975592d112320f2605a325969b270a94b71dcabc47b931d2"},
|
{file = "prometheus_client-0.15.0-py3-none-any.whl", hash = "sha256:db7c05cbd13a0f79975592d112320f2605a325969b270a94b71dcabc47b931d2"},
|
||||||
{file = "prometheus_client-0.15.0.tar.gz", hash = "sha256:be26aa452490cfcf6da953f9436e95a9f2b4d578ca80094b4458930e5f584ab1"},
|
{file = "prometheus_client-0.15.0.tar.gz", hash = "sha256:be26aa452490cfcf6da953f9436e95a9f2b4d578ca80094b4458930e5f584ab1"},
|
||||||
]
|
]
|
||||||
|
psutil = [
|
||||||
|
{file = "psutil-5.9.4-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c1ca331af862803a42677c120aff8a814a804e09832f166f226bfd22b56feee8"},
|
||||||
|
{file = "psutil-5.9.4-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:68908971daf802203f3d37e78d3f8831b6d1014864d7a85937941bb35f09aefe"},
|
||||||
|
{file = "psutil-5.9.4-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:3ff89f9b835100a825b14c2808a106b6fdcc4b15483141482a12c725e7f78549"},
|
||||||
|
{file = "psutil-5.9.4-cp27-cp27m-win32.whl", hash = "sha256:852dd5d9f8a47169fe62fd4a971aa07859476c2ba22c2254d4a1baa4e10b95ad"},
|
||||||
|
{file = "psutil-5.9.4-cp27-cp27m-win_amd64.whl", hash = "sha256:9120cd39dca5c5e1c54b59a41d205023d436799b1c8c4d3ff71af18535728e94"},
|
||||||
|
{file = "psutil-5.9.4-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6b92c532979bafc2df23ddc785ed116fced1f492ad90a6830cf24f4d1ea27d24"},
|
||||||
|
{file = "psutil-5.9.4-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:efeae04f9516907be44904cc7ce08defb6b665128992a56957abc9b61dca94b7"},
|
||||||
|
{file = "psutil-5.9.4-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:54d5b184728298f2ca8567bf83c422b706200bcbbfafdc06718264f9393cfeb7"},
|
||||||
|
{file = "psutil-5.9.4-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16653106f3b59386ffe10e0bad3bb6299e169d5327d3f187614b1cb8f24cf2e1"},
|
||||||
|
{file = "psutil-5.9.4-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54c0d3d8e0078b7666984e11b12b88af2db11d11249a8ac8920dd5ef68a66e08"},
|
||||||
|
{file = "psutil-5.9.4-cp36-abi3-win32.whl", hash = "sha256:149555f59a69b33f056ba1c4eb22bb7bf24332ce631c44a319cec09f876aaeff"},
|
||||||
|
{file = "psutil-5.9.4-cp36-abi3-win_amd64.whl", hash = "sha256:fd8522436a6ada7b4aad6638662966de0d61d241cb821239b2ae7013d41a43d4"},
|
||||||
|
{file = "psutil-5.9.4-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:6001c809253a29599bc0dfd5179d9f8a5779f9dffea1da0f13c53ee568115e1e"},
|
||||||
|
{file = "psutil-5.9.4.tar.gz", hash = "sha256:3d7f9739eb435d4b1338944abe23f49584bde5395f27487d2ee25ad9a8774a62"},
|
||||||
|
]
|
||||||
psycopg2-binary = [
|
psycopg2-binary = [
|
||||||
{file = "psycopg2-binary-2.9.5.tar.gz", hash = "sha256:33e632d0885b95a8b97165899006c40e9ecdc634a529dca7b991eb7de4ece41c"},
|
{file = "psycopg2-binary-2.9.5.tar.gz", hash = "sha256:33e632d0885b95a8b97165899006c40e9ecdc634a529dca7b991eb7de4ece41c"},
|
||||||
{file = "psycopg2_binary-2.9.5-cp310-cp310-macosx_10_15_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:0775d6252ccb22b15da3b5d7adbbf8cfe284916b14b6dc0ff503a23edb01ee85"},
|
{file = "psycopg2_binary-2.9.5-cp310-cp310-macosx_10_15_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:0775d6252ccb22b15da3b5d7adbbf8cfe284916b14b6dc0ff503a23edb01ee85"},
|
||||||
@ -2315,6 +2375,10 @@ pytest-variables = [
|
|||||||
{file = "pytest-variables-2.0.0.tar.gz", hash = "sha256:1c9e4fc321e33be7d1b352ac9cf20fdd2c39a8e4e6fa2dcd042aaf70ed516be7"},
|
{file = "pytest-variables-2.0.0.tar.gz", hash = "sha256:1c9e4fc321e33be7d1b352ac9cf20fdd2c39a8e4e6fa2dcd042aaf70ed516be7"},
|
||||||
{file = "pytest_variables-2.0.0-py3-none-any.whl", hash = "sha256:1a24a30b7acf9654d71bcdc8b10c1eb0d81b73b3eec72d810703c522475d643b"},
|
{file = "pytest_variables-2.0.0-py3-none-any.whl", hash = "sha256:1a24a30b7acf9654d71bcdc8b10c1eb0d81b73b3eec72d810703c522475d643b"},
|
||||||
]
|
]
|
||||||
|
pytest-xdist = [
|
||||||
|
{file = "pytest-xdist-3.0.2.tar.gz", hash = "sha256:688da9b814370e891ba5de650c9327d1a9d861721a524eb917e620eec3e90291"},
|
||||||
|
{file = "pytest_xdist-3.0.2-py3-none-any.whl", hash = "sha256:9feb9a18e1790696ea23e1434fa73b325ed4998b0e9fcb221f16fd1945e6df1b"},
|
||||||
|
]
|
||||||
python-dateutil = [
|
python-dateutil = [
|
||||||
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
|
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
|
||||||
{file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
|
{file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
|
||||||
|
@ -59,6 +59,7 @@ pytest-flake8 = "^1.1"
|
|||||||
pytest-isort = "^3.1"
|
pytest-isort = "^3.1"
|
||||||
pytest-runner = "^6.0"
|
pytest-runner = "^6.0"
|
||||||
pytest-selenium = "^2.0.1"
|
pytest-selenium = "^2.0.1"
|
||||||
|
pytest-xdist = {extras = ["psutil"], version = "^3.0.2"}
|
||||||
recommonmark = "^0.7"
|
recommonmark = "^0.7"
|
||||||
sphinx = "^5.1"
|
sphinx = "^5.1"
|
||||||
sphinx-bootstrap-theme = "^0.8.1"
|
sphinx-bootstrap-theme = "^0.8.1"
|
||||||
|
Loading…
Reference in New Issue
Block a user