pythonanywhere-core 0.2.9__py3-none-any.whl → 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- __version__ = "0.2.9"
1
+ __version__ = "0.3.0"
@@ -1,3 +1,4 @@
1
+ import getpass
1
2
  import os
2
3
  import platform
3
4
  from typing import Dict
@@ -20,6 +21,13 @@ PYTHON_VERSIONS: Dict[str, str] = {
20
21
  }
21
22
 
22
23
 
24
+ def get_username() -> str:
25
+ """Returns PythonAnywhere username from ``PYTHONANYWHERE_USERNAME``
26
+ environment variable, falling back to :func:`getpass.getuser`."""
27
+
28
+ return os.environ.get("PYTHONANYWHERE_USERNAME", getpass.getuser())
29
+
30
+
23
31
  def get_api_endpoint(username: str, flavor: str) -> str:
24
32
  hostname = os.environ.get(
25
33
  "PYTHONANYWHERE_SITE",
@@ -1,10 +1,10 @@
1
- import getpass
1
+ from pathlib import Path
2
2
  from typing import Tuple, Union
3
3
  from urllib.parse import urljoin
4
4
 
5
5
  from requests.models import Response
6
6
 
7
- from pythonanywhere_core.base import call_api, get_api_endpoint
7
+ from pythonanywhere_core.base import call_api, get_api_endpoint, get_username
8
8
  from pythonanywhere_core.exceptions import PythonAnywhereApiException
9
9
 
10
10
 
@@ -38,7 +38,7 @@ class Files:
38
38
  """
39
39
 
40
40
 
41
- base_url = get_api_endpoint(username=getpass.getuser(), flavor="files")
41
+ base_url = get_api_endpoint(username=get_username(), flavor="files")
42
42
  path_endpoint = urljoin(base_url, "path")
43
43
  sharing_endpoint = urljoin(base_url, "sharing/")
44
44
  tree_endpoint = urljoin(base_url, "tree/")
@@ -174,3 +174,23 @@ class Files:
174
174
  return result.json()
175
175
 
176
176
  raise PythonAnywhereApiException(f"GET to {url} failed, got {result}{self._error_msg(result)}")
177
+
178
+ def tree_post(self, local_dir_path: str, remote_dir_path: str) -> None:
179
+ """Uploads contents of a local directory to remote path on
180
+ PythonAnywhere. Walks `local_dir_path` recursively and uploads
181
+ each file using :meth:`path_post`, preserving directory structure.
182
+
183
+ Raises :exc:`PythonAnywhereApiException` on first upload failure."""
184
+
185
+ local_dir = Path(local_dir_path)
186
+ if not local_dir.is_dir():
187
+ raise ValueError(f"{local_dir_path} is not a directory")
188
+ for path in sorted(local_dir.rglob("*")):
189
+ if path.is_file():
190
+ relative = path.relative_to(local_dir)
191
+ remote_path = f"{remote_dir_path}/{relative}"
192
+ self.path_post(remote_path, path.read_bytes())
193
+ elif path.is_dir() and not any(path.iterdir()):
194
+ placeholder = f"{remote_dir_path}/{path.relative_to(local_dir)}/.empty"
195
+ self.path_post(placeholder, b"")
196
+ self.path_delete(placeholder)
@@ -1,6 +1,4 @@
1
- import getpass
2
-
3
- from pythonanywhere_core.base import call_api, get_api_endpoint
1
+ from pythonanywhere_core.base import call_api, get_api_endpoint, get_username
4
2
  from pythonanywhere_core.exceptions import PythonAnywhereApiException
5
3
 
6
4
 
@@ -17,7 +15,7 @@ class CPU:
17
15
  """
18
16
 
19
17
  def __init__(self):
20
- self.base_url = get_api_endpoint(username=getpass.getuser(), flavor="cpu")
18
+ self.base_url = get_api_endpoint(username=get_username(), flavor="cpu")
21
19
 
22
20
  def get_cpu_usage(self):
23
21
  """Get current CPU usage information.
@@ -1,9 +1,8 @@
1
- import getpass
2
1
  from typing import List, Optional
3
2
 
4
3
  from typing_extensions import Literal
5
4
 
6
- from pythonanywhere_core.base import call_api, get_api_endpoint
5
+ from pythonanywhere_core.base import call_api, get_api_endpoint, get_username
7
6
  from pythonanywhere_core.exceptions import PythonAnywhereApiException
8
7
 
9
8
 
@@ -28,7 +27,7 @@ class Schedule:
28
27
  - :meth:`Schedule.update`: Update an existing task.
29
28
  """
30
29
 
31
- base_url: str = get_api_endpoint(username=getpass.getuser(), flavor="schedule")
30
+ base_url: str = get_api_endpoint(username=get_username(), flavor="schedule")
32
31
 
33
32
  def create(self, params: dict) -> Optional[dict]:
34
33
  """Creates new scheduled task using `params`.
@@ -1,7 +1,6 @@
1
- import getpass
2
1
  from typing import Optional
3
2
 
4
- from pythonanywhere_core.base import call_api, get_api_endpoint
3
+ from pythonanywhere_core.base import call_api, get_api_endpoint, get_username
5
4
 
6
5
 
7
6
  class StudentsAPI:
@@ -22,7 +21,7 @@ class StudentsAPI:
22
21
  - :meth:`StudentsAPI.delete`: Remove a student.
23
22
  """
24
23
 
25
- base_url: str = get_api_endpoint(username=getpass.getuser(), flavor="students")
24
+ base_url: str = get_api_endpoint(username=get_username(), flavor="students")
26
25
 
27
26
  def get(self) -> Optional[dict]:
28
27
  """Returns list of PythonAnywhere students related with user's account.
@@ -1,14 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import os
4
- import getpass
5
4
  from pathlib import Path
6
5
  from textwrap import dedent
7
6
  from typing import Any
8
7
 
9
8
  from dateutil.parser import parse
10
9
 
11
- from pythonanywhere_core.base import call_api, get_api_endpoint, PYTHON_VERSIONS
10
+ from pythonanywhere_core.base import call_api, get_api_endpoint, get_username, PYTHON_VERSIONS
12
11
  from pythonanywhere_core.exceptions import SanityException, PythonAnywhereApiException, MissingCNAMEException
13
12
 
14
13
 
@@ -35,7 +34,7 @@ class Webapp:
35
34
  Class Methods:
36
35
  - :meth:`Webapp.list_webapps`: List all webapps for the current user.
37
36
  """
38
- username = getpass.getuser()
37
+ username = get_username()
39
38
  files_url = get_api_endpoint(username=username, flavor="files")
40
39
  webapps_url = get_api_endpoint(username=username, flavor="webapps")
41
40
 
@@ -74,11 +73,11 @@ class Webapp:
74
73
  f"You already have a webapp for {self.domain}.\n\nUse the --nuke option if you want to replace it."
75
74
  )
76
75
 
77
- def create(self, python_version: str, virtualenv_path: Path, project_path: Path, nuke: bool) -> None:
76
+ def create(self, python_version: str, virtualenv_path: Path | None, project_path: Path, nuke: bool) -> None:
78
77
  """Create a webapp for the given domain, using the given python version and virtualenv path
79
78
 
80
79
  :param python_version: python version to use
81
- :param virtualenv_path: path to the virtualenv
80
+ :param virtualenv_path: path to the virtualenv, or None to skip setting it
82
81
  :param project_path: path to the project
83
82
  :param nuke: if True, delete any existing webapp for this domain
84
83
 
@@ -1,7 +1,4 @@
1
- import getpass
2
-
3
-
4
- from pythonanywhere_core.base import call_api, get_api_endpoint
1
+ from pythonanywhere_core.base import call_api, get_api_endpoint, get_username
5
2
  from pythonanywhere_core.exceptions import DomainAlreadyExistsException, PythonAnywhereApiException
6
3
 
7
4
 
@@ -24,8 +21,8 @@ class Website:
24
21
  """
25
22
 
26
23
  def __init__(self) -> None:
27
- self.websites_base_url = get_api_endpoint(username=getpass.getuser(), flavor="websites")
28
- self.domains_base_url = get_api_endpoint(username=getpass.getuser(), flavor="domains")
24
+ self.websites_base_url = get_api_endpoint(username=get_username(), flavor="websites")
25
+ self.domains_base_url = get_api_endpoint(username=get_username(), flavor="domains")
29
26
 
30
27
 
31
28
  def create(self, domain_name: str, command: str) -> dict:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pythonanywhere-core
3
- Version: 0.2.9
3
+ Version: 0.3.0
4
4
  Summary: API wrapper for programmatic management of PythonAnywhere services.
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -0,0 +1,13 @@
1
+ pythonanywhere_core/__init__.py,sha256=VrXpHDu3erkzwl_WXrqINBm9xWkcyUy53IQOj042dOs,22
2
+ pythonanywhere_core/base.py,sha256=l4GiEa-oe-EyAc_knX9kqmzQsPEIAH3ec1CivkWeK3Q,3454
3
+ pythonanywhere_core/exceptions.py,sha256=37aZy6txVFuiXfUdRJA5d7NQ1N5vbkdOveqv8rwnDbk,691
4
+ pythonanywhere_core/files.py,sha256=XjOsxei_tDgrubUVMmH4iYgc4sTmoFNk5EtZMJR3-0Q,7531
5
+ pythonanywhere_core/resources.py,sha256=VBXspr1sGhfAVSFoTQtwpeN5CDG9-wHZwXJ3-5vy7dY,1167
6
+ pythonanywhere_core/schedule.py,sha256=payqSYJf92gQzsZwVBtccXH4m_C--AAbdbf5DOtImhs,3900
7
+ pythonanywhere_core/students.py,sha256=VfdftRrwPFEb-m2LW7pbiS9LiffwFNTfHpVeLXMQLLc,1774
8
+ pythonanywhere_core/webapp.py,sha256=inwCDOHY_7IVQXJTeAxucn5vYPpJNdn-JLM3ji5gHwQ,11308
9
+ pythonanywhere_core/website.py,sha256=t2CIASC2WPQ051z2kbUgWNh_f6TfpWL4bKXqZHlqHSw,4339
10
+ pythonanywhere_core-0.3.0.dist-info/METADATA,sha256=bBzG7pSRywkSwgbg0HHGyvmiVLNKJ1EX7ba1-aU2jV8,1880
11
+ pythonanywhere_core-0.3.0.dist-info/WHEEL,sha256=kJCRJT_g0adfAJzTx2GUMmS80rTJIVHRCfG0DQgLq3o,88
12
+ pythonanywhere_core-0.3.0.dist-info/licenses/LICENSE,sha256=zOJT_E5Fv8crFEKS5ulv0btbjnUiIkdsEBPEBmLHRlQ,1080
13
+ pythonanywhere_core-0.3.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.2.1
2
+ Generator: poetry-core 2.3.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,13 +0,0 @@
1
- pythonanywhere_core/__init__.py,sha256=F8OVhAhMXSkvvXYgZtbPn2SG1AQC3joK4yu-FrHt81Y,22
2
- pythonanywhere_core/base.py,sha256=fMdyaccJdpeB8ZN2QqqEmUPYSaAp3ZdvFxgDexR0Bfg,3195
3
- pythonanywhere_core/exceptions.py,sha256=37aZy6txVFuiXfUdRJA5d7NQ1N5vbkdOveqv8rwnDbk,691
4
- pythonanywhere_core/files.py,sha256=qIfbcg472TPeOejpif_i64PtWP_qROlxoz5JbePzX8Q,6491
5
- pythonanywhere_core/resources.py,sha256=NzzL-eNyo26Lr5FVJSAaxTq0Ia0vP3tIew_N7yFiFlk,1172
6
- pythonanywhere_core/schedule.py,sha256=giSO-Gssshkto9de2hSA3VeNKotXYu-lBG-iyqDolIw,3904
7
- pythonanywhere_core/students.py,sha256=PeBLUP7AOCRwCDiaH71wURwFx3H3PLQW91f5AjOPQmU,1778
8
- pythonanywhere_core/webapp.py,sha256=Fg-c_qnoXYK_VN3bMQjBPoVkRj49KZt_7OkWdqwW_Us,11277
9
- pythonanywhere_core/website.py,sha256=6Q_37QDKkuKE3771V056aiPmrQ0v8ot6U59CIaZwQzk,4348
10
- pythonanywhere_core-0.2.9.dist-info/METADATA,sha256=eYEs0j3fTbw5u1ayGidBnCzzFFKzECKpMWWQYPSnWl0,1880
11
- pythonanywhere_core-0.2.9.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
12
- pythonanywhere_core-0.2.9.dist-info/licenses/LICENSE,sha256=zOJT_E5Fv8crFEKS5ulv0btbjnUiIkdsEBPEBmLHRlQ,1080
13
- pythonanywhere_core-0.2.9.dist-info/RECORD,,