Skip to content

Commit 96d5377

Browse files
committed
Merge branch 'master' into t29-files-scripts
2 parents 06d6d4f + c2e8444 commit 96d5377

File tree

8 files changed

+130
-41
lines changed

8 files changed

+130
-41
lines changed

.github/workflows/tests.yaml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Tests
2+
3+
on: [push]
4+
5+
jobs:
6+
build:
7+
runs-on: ubuntu-latest
8+
strategy:
9+
matrix:
10+
python-version: [ '3.6', '3.7', '3.8', '3.9', '3.10' ]
11+
12+
name: Python ${{ matrix.python-version }}
13+
steps:
14+
15+
- uses: actions/checkout@v2
16+
17+
- name: Setup timezone
18+
uses: zcong1993/setup-timezone@master
19+
with:
20+
timezone: UTC
21+
22+
- name: Set up Python
23+
uses: actions/setup-python@v2
24+
with:
25+
python-version: ${{ matrix.python-version }}
26+
27+
28+
- name: Install Python dependencies
29+
run: |
30+
python3 -m pip install --upgrade pip
31+
pip3 install -r requirements.txt
32+
pip3 install -e .
33+
34+
- name: Test with pytest
35+
run: |
36+
pytest
37+
38+
- name: Check coverage
39+
run: |
40+
pytest --cov=cli --cov=pythonanywhere --cov=scripts --cov-fail-under=65

README.md

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,60 @@
1-
[![Build Status](https://travis-ci.org/pythonanywhere/helper_scripts.svg?branch=master)](https://travis-ci.org/pythonanywhere/helper_scripts)
1+
![Build Status](https://github.com/pythonanywhere/helper_scripts/actions/workflows/tests.yaml/badge.svg)
22
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
33
[![PyPI](https://img.shields.io/pypi/v/pythonanywhere)](https://pypi.org/project/pythonanywhere/)
44
[![Downloads](https://pepy.tech/badge/pythonanywhere)](https://pepy.tech/project/pythonanywhere)
55

6-
# PythonAnywhere helper scripts
6+
# PythonAnywhere cli tool
77

8-
These scripts are designed to be run from PythonAnywhere consoles
8+
`pa` is a single command to manage PythonAnywhere services.
9+
10+
It is designed to be run from PythonAnywhere consoles, but many subcommands can be executed directly
11+
from your own machine (see [usage](#Usage) below).
912

1013
## Installing
14+
### On PythonAnywhere
15+
In a PythonAnywhere Bash console, run:
16+
17+
pip3.9 install --user pythonanywhere
1118

12-
pip3.6 install --user pythonanywhere
19+
If there is no `python3.9` on your PythonAnywhere account,
20+
you should upgrade your account to the newest system image.
21+
See [here](https://help.pythonanywhere.com/pages/ChangingSystemImage) how to do that.
22+
`pa` works with python 3.6, 3.7 and 3.8, but we recommend using the latest system image.
23+
24+
### On your own machine
25+
Install the `pythonanywhere` package from [PyPI](https://pypi.org/project/pythonanywhere/).
26+
We recommend using `pipx` if you want to use it only as a cli tool, or a virtual environment
27+
if you want to use a programmatic interface in your own code.
1328

14-
If there is no `python3.6` on your PythonAnywhere account,
15-
you should contact [[email protected]](mailto:[email protected]) and ask for an upgrade.
16-
1729
## Usage
1830

19-
There are two ways to use that package. You can just run the scripts or use underlying api wrappers directly in your scripts.
31+
There are two ways to use the package. You can just run the scripts or use the underlying api wrappers directly in your scripts.
32+
33+
### Command line interface
34+
35+
### Running `pa` on your local machine
36+
37+
`pa` expects the presence of some environment variables that are provided when you run your code in a PythonAnywere console.
38+
You need to provide them if you run `pa` on your local machine.
39+
40+
`API_TOKEN` -- you need to set this to allow `pa` to connect to the [PythonAnywere API](https://help.pythonanywhere.com/pages/API).
41+
To get an API token, log into PythonAnywhere and go to the "Account" page using the link at the top right.
42+
Click on the "API token" tab, and click the "Create a new API token" button to get your token.
2043

21-
There are scripts provided for dealing with web apps:
44+
`PYTHONANYWHERE_SITE` is used to connect to PythonAnywhere API and defaults to `www.pythonanywhere.com`,
45+
but you may need to set it to `eu.pythonanywhere.com` if you use our EU site.
2246

23-
* [pa_autoconfigure_django.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_autoconfigure_django.py)
24-
* [pa_create_webapp_with_virtualenv.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_create_webapp_with_virtualenv.py)
25-
* [pa_delete_webapp_logs.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_delete_webapp_logs.py)
26-
* [pa_install_webapp_letsencrypt_ssl.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_install_webapp_letsencrypt_ssl.py)
27-
* [pa_install_webapp_ssl.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_install_webapp_ssl.py)
28-
* [pa_reload_webapp.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_reload_webapp.py)
29-
* [pa_start_django_webapp_with_virtualenv.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_start_django_webapp_with_virtualenv.py)
47+
If your username on PythonAnywhere is different from the username on your local machine,
48+
you may need to set `USER` for the environment you run `pa` in.
3049

31-
and scheduled tasks:
50+
### Programmatic usage in your code
3251

33-
* [pa_create_scheduled_task.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_create_scheduled_task.py)
34-
* [pa_delete_scheduled_task.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_delete_scheduled_task.py)
35-
* [pa_get_scheduled_tasks_list.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_get_scheduled_tasks_list.py)
36-
* [pa_get_scheduled_task_specs.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_get_scheduled_task_specs.py)
37-
* [pa_update_scheduled_task.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_update_scheduled_task.py)
52+
Take a look at the [`pythonanywhere.task`](https://github.com/pythonanywhere/helper_scripts/blob/master/pythonanywhere/task.py)
53+
module and docstrings of `pythonanywhere.task.Task` class and its methods.
3854

39-
Run any of them with `--help` flag to get information about usage.
55+
### Legacy scripts
4056

41-
See the [blog post](https://blog.pythonanywhere.com/155/)
57+
Some legacy [scripts](https://github.com/pythonanywhere/helper_scripts/blob/master/legacy.md) (separate for each action) are still available.
4258

4359
## Contributing
4460

legacy.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Legacy scripts
2+
3+
We still provide separate scripts for specific actions that are now all integrated
4+
into unified `pa` cli tool. We will keep them available for people who rely on them in
5+
their workflow, but we plan to drop them when we release 1.0.
6+
7+
There are scripts provided for dealing with web apps:
8+
9+
* [pa_autoconfigure_django.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_autoconfigure_django.py)
10+
* [pa_create_webapp_with_virtualenv.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_create_webapp_with_virtualenv.py)
11+
* [pa_delete_webapp_logs.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_delete_webapp_logs.py)
12+
* [pa_install_webapp_letsencrypt_ssl.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_install_webapp_letsencrypt_ssl.py)
13+
* [pa_install_webapp_ssl.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_install_webapp_ssl.py)
14+
* [pa_reload_webapp.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_reload_webapp.py)
15+
* [pa_start_django_webapp_with_virtualenv.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_start_django_webapp_with_virtualenv.py)
16+
17+
and scheduled tasks:
18+
19+
* [pa_create_scheduled_task.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_create_scheduled_task.py)
20+
* [pa_delete_scheduled_task.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_delete_scheduled_task.py)
21+
* [pa_get_scheduled_tasks_list.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_get_scheduled_tasks_list.py)
22+
* [pa_get_scheduled_task_specs.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_get_scheduled_task_specs.py)
23+
* [pa_update_scheduled_task.py](https://github.com/pythonanywhere/helper_scripts/blob/master/scripts/pa_update_scheduled_task.py)
24+
25+
Run any of them with `--help` flag to get information about usage.
26+
27+
See the [blog post](https://blog.pythonanywhere.com/155/) about how it all started.

pythonanywhere/api/base.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
import requests
44

55
PYTHON_VERSIONS = {
6-
"3.6": "python36", "3.7": "python37", "3.8": "python38", "3.9": "python39",
6+
"3.6": "python36",
7+
"3.7": "python37",
8+
"3.8": "python38",
9+
"3.9": "python39",
10+
"3.10": "python310",
711
}
812

913

@@ -49,5 +53,3 @@ def call_api(url, method, **kwargs):
4953
f"Authentication error {response.status_code} calling API: {response.text}"
5054
)
5155
return response
52-
53-

requirements.txt

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
python-dateutil==2.8.1
2+
click==8.0.3
23
docopt==0.6.2
34
packaging
45
psutil==5.7.0
5-
pytest==5.4.2
6-
pytest-cov==2.8.1
7-
pytest-mock==3.1.0
6+
pytest==6.2.5
7+
pytest-cov==3.0.0
8+
pytest-mock==3.6.1
89
pytest-mypy==0.6.2
9-
requests==2.23.0
10-
responses==0.10.14
10+
requests==2.26.0
11+
responses==0.16.0
1112
schema==0.7.2
12-
tabulate==0.8.7
13-
typer==0.3.2
13+
tabulate==0.8.9
14+
typer==0.4.0
15+
urllib3==1.26.7
1416
virtualenvwrapper==4.8.4

setup.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
setup(
1111
name="pythonanywhere",
12-
version="0.9.8",
12+
version="0.9.11",
1313
description="PythonAnywhere helper tools for users",
1414
long_description=long_description,
1515
long_description_content_type="text/markdown",
@@ -22,6 +22,8 @@
2222
"Intended Audience :: Developers",
2323
"Topic :: Software Development :: Libraries",
2424
"License :: OSI Approved :: MIT License",
25+
"Programming Language :: Python :: 3.10",
26+
"Programming Language :: Python :: 3.9",
2527
"Programming Language :: Python :: 3.8",
2628
"Programming Language :: Python :: 3.7",
2729
"Programming Language :: Python :: 3.6",

tests/test_cli_schedule.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,12 @@ def test_validates_minutes(self):
7070
result = runner.invoke(app, ["set", "-c", "echo foo", "-h", "8", "-m", "66"])
7171

7272
assert "Invalid value" in result.stdout
73-
assert "66 is not in the valid range of 0 to 59" in result.stdout
73+
assert "66 is not in the range 0<=x<=59" in result.stdout
7474

7575
def test_validates_hours(self):
7676
result = runner.invoke(app, ["set", "-c", "echo foo", "-h", "66", "-m", "1"])
7777
assert "Invalid value" in result.stdout
78-
assert "66 is not in the valid range of 0 to 23" in result.stdout
78+
assert "66 is not in the range 0<=x<=23" in result.stdout
7979

8080
def test_logs_warning_when_create_schedule_raises(self, mocker):
8181
mock_logger = mocker.patch("cli.schedule.get_logger").return_value
@@ -347,11 +347,11 @@ def test_ensures_proper_hourly_params(self, mocker):
347347

348348
def test_validates_minute(self):
349349
result = runner.invoke(app, ["update", "42", "--minute", "88"])
350-
assert "88 is not in the valid range of 0 to 59" in result.stdout
350+
assert "88 is not in the range 0<=x<=59" in result.stdout
351351

352352
def test_validates_hour(self):
353353
result = runner.invoke(app, ["update", "42", "--daily", "--hour", "33"])
354-
assert "33 is not in the valid range of 0 to 23" in result.stdout
354+
assert "33 is not in the range 0<=x<=23" in result.stdout
355355

356356
def test_complains_when_no_id_provided(self):
357357
result = runner.invoke(app, ["update"])

tests/test_django_project.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ def test_actually_produces_wsgi_file_that_can_import_project_non_nested(
476476
running_python_version = ".".join(python_version().split(".")[:2])
477477
project = DjangoProject("mydomain.com", running_python_version)
478478
shutil.copytree(str(non_nested_submodule), str(project.project_path))
479-
if running_python_version in ["3.7", "3.8"]:
479+
if running_python_version in ["3.7", "3.8", "3.9", "3.10"]:
480480
project.create_virtualenv(django_version="latest")
481481
else:
482482
project.create_virtualenv()
@@ -496,7 +496,7 @@ def test_actually_produces_wsgi_file_that_can_import_nested_project(
496496
running_python_version = ".".join(python_version().split(".")[:2])
497497
project = DjangoProject("mydomain.com", running_python_version)
498498
shutil.copytree(str(more_nested_submodule), str(project.project_path))
499-
if running_python_version in ["3.7", "3.8"]:
499+
if running_python_version in ["3.7", "3.8", "3.9", "3.10"]:
500500
project.create_virtualenv(django_version="latest")
501501
else:
502502
project.create_virtualenv()

0 commit comments

Comments
 (0)