From 488c713c6c1d36df2f828fa73df6e8e294644c2e Mon Sep 17 00:00:00 2001 From: Filip Lajszczak Date: Tue, 20 Apr 2021 17:32:05 +0100 Subject: [PATCH 01/11] python3.9 version mapping. --- pythonanywhere/api/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pythonanywhere/api/base.py b/pythonanywhere/api/base.py index 6c7664f..b14d546 100644 --- a/pythonanywhere/api/base.py +++ b/pythonanywhere/api/base.py @@ -3,7 +3,7 @@ import requests PYTHON_VERSIONS = { - "3.6": "python36", "3.7": "python37", "3.8": "python38", + "3.6": "python36", "3.7": "python37", "3.8": "python38", "3.9": "python39", } From 127cc950341e22fa72143d10d5a6f5e5d0c7a255 Mon Sep 17 00:00:00 2001 From: Filip Lajszczak Date: Thu, 17 Jun 2021 13:02:26 +0100 Subject: [PATCH 02/11] adds python3.9 to classifiers and bups up version. by Giles and Filip --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 37614e4..0d69c9b 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ setup( name="pythonanywhere", - version="0.9.8", + version="0.9.9", description="PythonAnywhere helper tools for users", long_description=long_description, long_description_content_type="text/markdown", @@ -22,6 +22,7 @@ "Intended Audience :: Developers", "Topic :: Software Development :: Libraries", "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.6", From f62fd2eea52eadab9545e22e62d934320003a018 Mon Sep 17 00:00:00 2001 From: Filip Lajszczak Date: Fri, 16 Jul 2021 16:22:09 +0100 Subject: [PATCH 03/11] #5 #21 legacy scripts described separately. --- legacy.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 legacy.md diff --git a/legacy.md b/legacy.md new file mode 100644 index 0000000..432f34e --- /dev/null +++ b/legacy.md @@ -0,0 +1,27 @@ +# Legacy scripts + +We still provide separate scripts for specific actions that are now all integrated +into unified `pa` cli tool. We will keep them available for people who rely on them in +their workflow, but we plan to drop them when we release 1.0. + +There are scripts provided for dealing with web apps: + +* [pa_autoconfigure_django.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_autoconfigure_django.py) +* [pa_create_webapp_with_virtualenv.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_create_webapp_with_virtualenv.py) +* [pa_delete_webapp_logs.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_delete_webapp_logs.py) +* [pa_install_webapp_letsencrypt_ssl.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_install_webapp_letsencrypt_ssl.py) +* [pa_install_webapp_ssl.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_install_webapp_ssl.py) +* [pa_reload_webapp.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_reload_webapp.py) +* [pa_start_django_webapp_with_virtualenv.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_start_django_webapp_with_virtualenv.py) + +and scheduled tasks: + +* [pa_create_scheduled_task.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_create_scheduled_task.py) +* [pa_delete_scheduled_task.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_delete_scheduled_task.py) +* [pa_get_scheduled_tasks_list.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_get_scheduled_tasks_list.py) +* [pa_get_scheduled_task_specs.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_get_scheduled_task_specs.py) +* [pa_update_scheduled_task.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_update_scheduled_task.py) + +Run any of them with `--help` flag to get information about usage. + +See the [blog post](https://blog.pythonanywhere.com/155/) about how it all started. From fc00dabbd487b795c16f2f856cf018f778acd492 Mon Sep 17 00:00:00 2001 From: Filip Lajszczak Date: Sun, 18 Jul 2021 11:40:47 +0100 Subject: [PATCH 04/11] #5 #21 updates readme. --- README.md | 60 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 4deda82..613b77b 100644 --- a/README.md +++ b/README.md @@ -3,42 +3,58 @@ [![PyPI](https://img.shields.io/pypi/v/pythonanywhere)](https://pypi.org/project/pythonanywhere/) [![Downloads](https://pepy.tech/badge/pythonanywhere)](https://pepy.tech/project/pythonanywhere) -# PythonAnywhere helper scripts +# PythonAnywhere cli tool -These scripts are designed to be run from PythonAnywhere consoles +`pa` is a single command to manage PythonAnywhere services. + +It is designed to be run from PythonAnywhere consoles, but many subcommands could be executed directly +from the local machine (see [usage](#Usage) below). ## Installing +### On PythonAnywhere +In PythonAnywhere bash console run: + + pip3.9 install --user pythonanywhere - pip3.6 install --user pythonanywhere +If there is no `python3.9` on your PythonAnywhere account, +you should upgrade your account to the new system image. +See [here](https://help.pythonanywhere.com/pages/ChangingSystemImage) how to do it. +`pa` works with python 3.6, 3.7 and 3.8, but we recommend using the latest system image + +### On your local machine +Install `pythonanywhere` package from [PyPI](https://pypi.org/project/pythonanywhere/). +We recommend using `pipx` if you want to use it only as a cli tool or the virtual environment +if you want to use a programmatic interface in your own code. -If there is no `python3.6` on your PythonAnywhere account, -you should contact [support@pythonanywhere.com](mailto:support@pythonanywhere.com) and ask for an upgrade. - ## Usage There are two ways to use that package. You can just run the scripts or use underlying api wrappers directly in your scripts. -There are scripts provided for dealing with web apps: +### Command line interface + +### Running `pa` on your local machine + +`pa` expects the presence of some environmental variables that are provided when you run your code in PythonAnywere console. +You need to provide them if you run `pa` on your local machine. + +`API_TOKEN` You need to set it to allow `pa` to connect to [PythonAnywere API](https://help.pythonanywhere.com/pages/API). +To get an API token log into PythonAnywhere, and go to the “Account” page using the link at the top right. +Click on the “API token” tab and click the “Create a new API token” button to get your token. + +`PYTHONANYWHERE_SITE` is used to connect to PythonAnywhere API and defaults to `www.pythonanywhere.com`, +but you may need to set it to `eu.pythonanywhere.com` if you use our EU site. -* [pa_autoconfigure_django.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_autoconfigure_django.py) -* [pa_create_webapp_with_virtualenv.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_create_webapp_with_virtualenv.py) -* [pa_delete_webapp_logs.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_delete_webapp_logs.py) -* [pa_install_webapp_letsencrypt_ssl.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_install_webapp_letsencrypt_ssl.py) -* [pa_install_webapp_ssl.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_install_webapp_ssl.py) -* [pa_reload_webapp.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_reload_webapp.py) -* [pa_start_django_webapp_with_virtualenv.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_start_django_webapp_with_virtualenv.py) +If your username on PythonAnywhere is different from the username on your local machine, +you may need to set `USER` for the environment you run `pa` in. -and scheduled tasks: +### Programmatic usage in your code -* [pa_create_scheduled_task.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_create_scheduled_task.py) -* [pa_delete_scheduled_task.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_delete_scheduled_task.py) -* [pa_get_scheduled_tasks_list.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_get_scheduled_tasks_list.py) -* [pa_get_scheduled_task_specs.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_get_scheduled_task_specs.py) -* [pa_update_scheduled_task.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_update_scheduled_task.py) +Take a look at [`pythonanywhere.task`](https://github.com/pythonanywhere/helper_scripts/blob/master/pythonanywhere/task.py) +module and docstrings of `pythonanywhere.task.Task` class and its methods. -Run any of them with `--help` flag to get information about usage. +### Legacy scripts -See the [blog post](https://blog.pythonanywhere.com/155/) +Legacy [scripts](https://github.com/pythonanywhere/helper_scripts/blob/master/legacy.md) (separate for each action) are still available. ## Contributing From 3d556e765f7b2cf2f47e1f7817761104229df9f7 Mon Sep 17 00:00:00 2001 From: Giles Thomas Date: Wed, 11 Aug 2021 19:10:36 +0100 Subject: [PATCH 05/11] Grammar tweaks --- README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 613b77b..40e8afb 100644 --- a/README.md +++ b/README.md @@ -7,39 +7,39 @@ `pa` is a single command to manage PythonAnywhere services. -It is designed to be run from PythonAnywhere consoles, but many subcommands could be executed directly +It is designed to be run from PythonAnywhere consoles, but many subcommands can be executed directly from the local machine (see [usage](#Usage) below). ## Installing ### On PythonAnywhere -In PythonAnywhere bash console run: +In a PythonAnywhere Bash console, run: pip3.9 install --user pythonanywhere If there is no `python3.9` on your PythonAnywhere account, -you should upgrade your account to the new system image. -See [here](https://help.pythonanywhere.com/pages/ChangingSystemImage) how to do it. -`pa` works with python 3.6, 3.7 and 3.8, but we recommend using the latest system image +you should upgrade your account to the newest system image. +See [here](https://help.pythonanywhere.com/pages/ChangingSystemImage) how to do that. +`pa` works with python 3.6, 3.7 and 3.8, but we recommend using the latest system image. ### On your local machine Install `pythonanywhere` package from [PyPI](https://pypi.org/project/pythonanywhere/). -We recommend using `pipx` if you want to use it only as a cli tool or the virtual environment +We recommend using `pipx` if you want to use it only as a cli tool, or a virtual environment if you want to use a programmatic interface in your own code. ## Usage -There are two ways to use that package. You can just run the scripts or use underlying api wrappers directly in your scripts. +There are two ways to use the package. You can just run the scripts or use the underlying api wrappers directly in your scripts. ### Command line interface ### Running `pa` on your local machine -`pa` expects the presence of some environmental variables that are provided when you run your code in PythonAnywere console. +`pa` expects the presence of some environment variables that are provided when you run your code in PythonAnywere console. You need to provide them if you run `pa` on your local machine. -`API_TOKEN` You need to set it to allow `pa` to connect to [PythonAnywere API](https://help.pythonanywhere.com/pages/API). -To get an API token log into PythonAnywhere, and go to the “Account” page using the link at the top right. -Click on the “API token” tab and click the “Create a new API token” button to get your token. +`API_TOKEN` -- you need to set this to allow `pa` to connect to the [PythonAnywere API](https://help.pythonanywhere.com/pages/API). +To get an API token log, into PythonAnywhere and go to the “Account” page using the link at the top right. +Click on the "API token" tab, and click the “Create a new API token” button to get your token. `PYTHONANYWHERE_SITE` is used to connect to PythonAnywhere API and defaults to `www.pythonanywhere.com`, but you may need to set it to `eu.pythonanywhere.com` if you use our EU site. @@ -49,12 +49,12 @@ you may need to set `USER` for the environment you run `pa` in. ### Programmatic usage in your code -Take a look at [`pythonanywhere.task`](https://github.com/pythonanywhere/helper_scripts/blob/master/pythonanywhere/task.py) +Take a look at the [`pythonanywhere.task`](https://github.com/pythonanywhere/helper_scripts/blob/master/pythonanywhere/task.py) module and docstrings of `pythonanywhere.task.Task` class and its methods. ### Legacy scripts -Legacy [scripts](https://github.com/pythonanywhere/helper_scripts/blob/master/legacy.md) (separate for each action) are still available. +Some legacy [scripts](https://github.com/pythonanywhere/helper_scripts/blob/master/legacy.md) (separate for each action) are still available. ## Contributing From 5fd1d1fe35be0041e8e8d7ed5628cc6685dba9b7 Mon Sep 17 00:00:00 2001 From: Giles Thomas Date: Wed, 11 Aug 2021 19:13:01 +0100 Subject: [PATCH 06/11] Further tweak --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 40e8afb..d9555e5 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ There are two ways to use the package. You can just run the scripts or use the u ### Running `pa` on your local machine -`pa` expects the presence of some environment variables that are provided when you run your code in PythonAnywere console. +`pa` expects the presence of some environment variables that are provided when you run your code in a PythonAnywere console. You need to provide them if you run `pa` on your local machine. `API_TOKEN` -- you need to set this to allow `pa` to connect to the [PythonAnywere API](https://help.pythonanywhere.com/pages/API). From e80e0c81d9d1b6caab71ffbc52a5ffe6176ed9b5 Mon Sep 17 00:00:00 2001 From: Giles Thomas Date: Wed, 11 Aug 2021 19:13:28 +0100 Subject: [PATCH 07/11] ...and more --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d9555e5..c69dc93 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ `pa` is a single command to manage PythonAnywhere services. It is designed to be run from PythonAnywhere consoles, but many subcommands can be executed directly -from the local machine (see [usage](#Usage) below). +from your own machine (see [usage](#Usage) below). ## Installing ### On PythonAnywhere From e93e9c6cf524c856a1f49e27f22c6b575be4c381 Mon Sep 17 00:00:00 2001 From: Giles Thomas Date: Wed, 11 Aug 2021 19:17:05 +0100 Subject: [PATCH 08/11] And hopefully that's it. --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c69dc93..b38d4fc 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,8 @@ you should upgrade your account to the newest system image. See [here](https://help.pythonanywhere.com/pages/ChangingSystemImage) how to do that. `pa` works with python 3.6, 3.7 and 3.8, but we recommend using the latest system image. -### On your local machine -Install `pythonanywhere` package from [PyPI](https://pypi.org/project/pythonanywhere/). +### On your own machine +Install the `pythonanywhere` package from [PyPI](https://pypi.org/project/pythonanywhere/). We recommend using `pipx` if you want to use it only as a cli tool, or a virtual environment if you want to use a programmatic interface in your own code. @@ -38,8 +38,8 @@ There are two ways to use the package. You can just run the scripts or use the u You need to provide them if you run `pa` on your local machine. `API_TOKEN` -- you need to set this to allow `pa` to connect to the [PythonAnywere API](https://help.pythonanywhere.com/pages/API). -To get an API token log, into PythonAnywhere and go to the “Account” page using the link at the top right. -Click on the "API token" tab, and click the “Create a new API token” button to get your token. +To get an API token, log into PythonAnywhere and go to the "Account" page using the link at the top right. +Click on the "API token" tab, and click the "Create a new API token" button to get your token. `PYTHONANYWHERE_SITE` is used to connect to PythonAnywhere API and defaults to `www.pythonanywhere.com`, but you may need to set it to `eu.pythonanywhere.com` if you use our EU site. From 84ccbc3ceb2172a351fc2f054c1eccb6a2834478 Mon Sep 17 00:00:00 2001 From: Filip Lajszczak Date: Fri, 17 Dec 2021 08:44:06 +0000 Subject: [PATCH 09/11] bumps up version to 0.9.10 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 0d69c9b..fab31cc 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ setup( name="pythonanywhere", - version="0.9.9", + version="0.9.10", description="PythonAnywhere helper tools for users", long_description=long_description, long_description_content_type="text/markdown", From dab32e85b9ca2b62b43c0da476da3444ec22f1f1 Mon Sep 17 00:00:00 2001 From: Filip Lajszczak Date: Fri, 17 Dec 2021 11:00:26 +0000 Subject: [PATCH 10/11] updates requirements and setup for python 3.10 --- pythonanywhere/api/base.py | 6 +++++- requirements.txt | 16 +++++++++------- setup.py | 3 ++- tests/test_cli_schedule.py | 8 ++++---- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/pythonanywhere/api/base.py b/pythonanywhere/api/base.py index b14d546..512b028 100644 --- a/pythonanywhere/api/base.py +++ b/pythonanywhere/api/base.py @@ -3,7 +3,11 @@ import requests PYTHON_VERSIONS = { - "3.6": "python36", "3.7": "python37", "3.8": "python38", "3.9": "python39", + "3.6": "python36", + "3.7": "python37", + "3.8": "python38", + "3.9": "python39", + "3.10": "python310", } diff --git a/requirements.txt b/requirements.txt index d62baf6..cea5aec 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,14 +1,16 @@ python-dateutil==2.8.1 +click==8.0.3 docopt==0.6.2 packaging psutil==5.7.0 -pytest==5.4.2 -pytest-cov==2.8.1 -pytest-mock==3.1.0 +pytest==6.2.5 +pytest-cov==3.0.0 +pytest-mock==3.6.1 pytest-mypy==0.6.2 -requests==2.23.0 -responses==0.10.14 +requests==2.26.0 +responses==0.16.0 schema==0.7.2 -tabulate==0.8.7 -typer==0.3.2 +tabulate==0.8.9 +typer==0.4.0 +urllib3==1.26.7 virtualenvwrapper==4.8.4 diff --git a/setup.py b/setup.py index fab31cc..11b974a 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ setup( name="pythonanywhere", - version="0.9.10", + version="0.9.11", description="PythonAnywhere helper tools for users", long_description=long_description, long_description_content_type="text/markdown", @@ -22,6 +22,7 @@ "Intended Audience :: Developers", "Topic :: Software Development :: Libraries", "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.7", diff --git a/tests/test_cli_schedule.py b/tests/test_cli_schedule.py index 6791eec..e9b58ff 100644 --- a/tests/test_cli_schedule.py +++ b/tests/test_cli_schedule.py @@ -69,12 +69,12 @@ def test_validates_minutes(self): result = runner.invoke(app, ["set", "-c", "echo foo", "-h", "8", "-m", "66"]) assert "Invalid value" in result.stdout - assert "66 is not in the valid range of 0 to 59" in result.stdout + assert "66 is not in the range 0<=x<=59" in result.stdout def test_validates_hours(self): result = runner.invoke(app, ["set", "-c", "echo foo", "-h", "66", "-m", "1"]) assert "Invalid value" in result.stdout - assert "66 is not in the valid range of 0 to 23" in result.stdout + assert "66 is not in the range 0<=x<=23" in result.stdout def test_logs_warning_when_create_schedule_raises(self, mocker): mock_logger = mocker.patch("cli.schedule.get_logger").return_value @@ -346,11 +346,11 @@ def test_ensures_proper_hourly_params(self, mocker): def test_validates_minute(self): result = runner.invoke(app, ["update", "42", "--minute", "88"]) - assert "88 is not in the valid range of 0 to 59" in result.stdout + assert "88 is not in the range 0<=x<=59" in result.stdout def test_validates_hour(self): result = runner.invoke(app, ["update", "42", "--daily", "--hour", "33"]) - assert "33 is not in the valid range of 0 to 23" in result.stdout + assert "33 is not in the range 0<=x<=23" in result.stdout def test_complains_when_no_id_provided(self): result = runner.invoke(app, ["update"]) From c2e8444146e7e1e37af5e5330bd83fb45fa5587c Mon Sep 17 00:00:00 2001 From: Filip Lajszczak Date: Fri, 17 Dec 2021 09:59:48 +0000 Subject: [PATCH 11/11] Setup github actions test --- .github/workflows/tests.yaml | 40 ++++++++++++++++++++++++++++++++++++ README.md | 2 +- tests/test_django_project.py | 4 ++-- 3 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/tests.yaml diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml new file mode 100644 index 0000000..4259262 --- /dev/null +++ b/.github/workflows/tests.yaml @@ -0,0 +1,40 @@ +name: Tests + +on: [push] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [ '3.6', '3.7', '3.8', '3.9', '3.10' ] + + name: Python ${{ matrix.python-version }} + steps: + + - uses: actions/checkout@v2 + + - name: Setup timezone + uses: zcong1993/setup-timezone@master + with: + timezone: UTC + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + + - name: Install Python dependencies + run: | + python3 -m pip install --upgrade pip + pip3 install -r requirements.txt + pip3 install -e . + + - name: Test with pytest + run: | + pytest + + - name: Check coverage + run: | + pytest --cov=cli --cov=pythonanywhere --cov=scripts --cov-fail-under=65 \ No newline at end of file diff --git a/README.md b/README.md index b38d4fc..eba75c8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.org/pythonanywhere/helper_scripts.svg?branch=master)](https://travis-ci.org/pythonanywhere/helper_scripts) +![Build Status](https://github.com/pythonanywhere/helper_scripts/actions/workflows/tests.yaml/badge.svg) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![PyPI](https://img.shields.io/pypi/v/pythonanywhere)](https://pypi.org/project/pythonanywhere/) [![Downloads](https://pepy.tech/badge/pythonanywhere)](https://pepy.tech/project/pythonanywhere) diff --git a/tests/test_django_project.py b/tests/test_django_project.py index d3102a9..258504b 100644 --- a/tests/test_django_project.py +++ b/tests/test_django_project.py @@ -476,7 +476,7 @@ def test_actually_produces_wsgi_file_that_can_import_project_non_nested( running_python_version = ".".join(python_version().split(".")[:2]) project = DjangoProject("mydomain.com", running_python_version) shutil.copytree(str(non_nested_submodule), str(project.project_path)) - if running_python_version in ["3.7", "3.8"]: + if running_python_version in ["3.7", "3.8", "3.9", "3.10"]: project.create_virtualenv(django_version="latest") else: project.create_virtualenv() @@ -496,7 +496,7 @@ def test_actually_produces_wsgi_file_that_can_import_nested_project( running_python_version = ".".join(python_version().split(".")[:2]) project = DjangoProject("mydomain.com", running_python_version) shutil.copytree(str(more_nested_submodule), str(project.project_path)) - if running_python_version in ["3.7", "3.8"]: + if running_python_version in ["3.7", "3.8", "3.9", "3.10"]: project.create_virtualenv(django_version="latest") else: project.create_virtualenv()