ae-pythonanywhere 0.3.1__tar.gz → 0.3.3__tar.gz

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,4 +1,4 @@
1
- <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.project_tpls v0.3.56 -->
1
+ <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.project_tpls v0.3.68 -->
2
2
  ### GNU GENERAL PUBLIC LICENSE
3
3
 
4
4
  Version 3, 29 June 2007
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ae_pythonanywhere
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Summary: ae namespace module portion pythonanywhere: PythonAnywhere Web API Client
5
5
  Home-page: https://gitlab.com/ae-group/ae_pythonanywhere
6
6
  Author: AndiEcker
@@ -16,7 +16,7 @@ Classifier: Natural Language :: English
16
16
  Classifier: Operating System :: OS Independent
17
17
  Classifier: Programming Language :: Python
18
18
  Classifier: Programming Language :: Python :: 3
19
- Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.12
20
20
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
21
  Classifier: Typing :: Typed
22
22
  Requires-Python: >=3.9
@@ -26,13 +26,12 @@ Requires-Dist: requests
26
26
  Requires-Dist: types-requests
27
27
  Requires-Dist: ae_base
28
28
  Requires-Dist: ae_paths
29
- Requires-Dist: ae_dev_ops
30
29
  Provides-Extra: dev
31
30
  Requires-Dist: aedev_project_tpls; extra == "dev"
32
31
  Requires-Dist: ae_ae; extra == "dev"
33
32
  Requires-Dist: anybadge; extra == "dev"
34
33
  Requires-Dist: coverage-badge; extra == "dev"
35
- Requires-Dist: aedev_git_repo_manager; extra == "dev"
34
+ Requires-Dist: aedev_project_manager; extra == "dev"
36
35
  Requires-Dist: flake8; extra == "dev"
37
36
  Requires-Dist: mypy; extra == "dev"
38
37
  Requires-Dist: pylint; extra == "dev"
@@ -45,7 +44,7 @@ Provides-Extra: docs
45
44
  Provides-Extra: tests
46
45
  Requires-Dist: anybadge; extra == "tests"
47
46
  Requires-Dist: coverage-badge; extra == "tests"
48
- Requires-Dist: aedev_git_repo_manager; extra == "tests"
47
+ Requires-Dist: aedev_project_manager; extra == "tests"
49
48
  Requires-Dist: flake8; extra == "tests"
50
49
  Requires-Dist: mypy; extra == "tests"
51
50
  Requires-Dist: pylint; extra == "tests"
@@ -69,15 +68,15 @@ Dynamic: requires-dist
69
68
  Dynamic: requires-python
70
69
  Dynamic: summary
71
70
 
72
- <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae v0.3.97 -->
73
- <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.namespace_root_tpls v0.3.19 -->
74
- # pythonanywhere 0.3.1
71
+ <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae v0.3.101 -->
72
+ <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.namespace_root_tpls v0.3.22 -->
73
+ # pythonanywhere 0.3.3
75
74
 
76
75
  [![GitLab develop](https://img.shields.io/gitlab/pipeline/ae-group/ae_pythonanywhere/develop?logo=python)](
77
76
  https://gitlab.com/ae-group/ae_pythonanywhere)
78
77
  [![LatestPyPIrelease](
79
- https://img.shields.io/gitlab/pipeline/ae-group/ae_pythonanywhere/release0.3.1?logo=python)](
80
- https://gitlab.com/ae-group/ae_pythonanywhere/-/tree/release0.3.1)
78
+ https://img.shields.io/gitlab/pipeline/ae-group/ae_pythonanywhere/release0.3.3?logo=python)](
79
+ https://gitlab.com/ae-group/ae_pythonanywhere/-/tree/release0.3.3)
81
80
  [![PyPIVersions](https://img.shields.io/pypi/v/ae_pythonanywhere)](
82
81
  https://pypi.org/project/ae-pythonanywhere/#history)
83
82
 
@@ -1,12 +1,12 @@
1
- <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae v0.3.97 -->
2
- <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.namespace_root_tpls v0.3.19 -->
3
- # pythonanywhere 0.3.1
1
+ <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae v0.3.101 -->
2
+ <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.namespace_root_tpls v0.3.22 -->
3
+ # pythonanywhere 0.3.3
4
4
 
5
5
  [![GitLab develop](https://img.shields.io/gitlab/pipeline/ae-group/ae_pythonanywhere/develop?logo=python)](
6
6
  https://gitlab.com/ae-group/ae_pythonanywhere)
7
7
  [![LatestPyPIrelease](
8
- https://img.shields.io/gitlab/pipeline/ae-group/ae_pythonanywhere/release0.3.1?logo=python)](
9
- https://gitlab.com/ae-group/ae_pythonanywhere/-/tree/release0.3.1)
8
+ https://img.shields.io/gitlab/pipeline/ae-group/ae_pythonanywhere/release0.3.3?logo=python)](
9
+ https://gitlab.com/ae-group/ae_pythonanywhere/-/tree/release0.3.3)
10
10
  [![PyPIVersions](https://img.shields.io/pypi/v/ae_pythonanywhere)](
11
11
  https://pypi.org/project/ae-pythonanywhere/#history)
12
12
 
@@ -38,8 +38,6 @@ the following examples demonstrate key functionality, including how to initializ
38
38
  the :class:`PythonanywhereApi` and list deployed files/folders, excluding common
39
39
  temporary directories::
40
40
 
41
- .. code-block:: python
42
-
43
41
  from ae.paths import Collector
44
42
  from ae.pythonanywhere import PythonanywhereApi
45
43
 
@@ -69,13 +67,13 @@ temporary directories::
69
67
  else:
70
68
  print("No files found or project directory is empty.")
71
69
 
70
+
72
71
  more useful methods
73
72
  -------------------
74
73
 
75
74
  the most useful methods of the :class:`PythonanywhereAPI` class are (check the source code for more):~
76
75
 
77
76
  * :meth:`~PythonanywhereAPI.deployed_file_content`: determine the file content of a file, deployed to the web server.
78
- * :meth:`~PythonanywhereAPI.deployed_version`: determine the version of the deployed django project package.
79
77
  * :meth:`~PythonanywhereAPI.deploy_file`: add or update a project file to the web server.
80
78
  * :meth:`~PythonanywhereAPI.delete_file_or_folder`: delete a file or folder on the web server.
81
79
 
@@ -94,12 +92,11 @@ from typing import Any, Callable, Container, Iterable, Optional, Union, cast
94
92
 
95
93
  import requests
96
94
 
97
- from ae.base import PY_INIT, ErrorMsgMixin # type: ignore
95
+ from ae.base import ErrorMsgMixin # type: ignore
98
96
  from ae.paths import Collector, CollYieldItems, SearcherRetType, coll_items # type: ignore
99
- from ae.dev_ops import code_version # type: ignore
100
97
 
101
98
 
102
- __version__ = '0.3.1'
99
+ __version__ = '0.3.3'
103
100
 
104
101
 
105
102
  class PythonanywhereApi(ErrorMsgMixin): # pylint: disable=too-many-instance-attributes
@@ -299,15 +296,6 @@ class PythonanywhereApi(ErrorMsgMixin): # pylint: disable=too-many-instance-a
299
296
  return None
300
297
  return response.content
301
298
 
302
- def deployed_version(self) -> str:
303
- """ determine the version of a deployed django project package.
304
-
305
- :return: version string of the package deployed to the web host/server
306
- or empty string if package version file or version-in-file not found.
307
- """
308
- init_file_content = self.deployed_file_content(os.path.join(self.project_name, PY_INIT))
309
- return "" if init_file_content is None else code_version(init_file_content)
310
-
311
299
  def deploy_file(self, file_path: str, file_content: bytes) -> str:
312
300
  """ add or update a project file to the web server.
313
301
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ae_pythonanywhere
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Summary: ae namespace module portion pythonanywhere: PythonAnywhere Web API Client
5
5
  Home-page: https://gitlab.com/ae-group/ae_pythonanywhere
6
6
  Author: AndiEcker
@@ -16,7 +16,7 @@ Classifier: Natural Language :: English
16
16
  Classifier: Operating System :: OS Independent
17
17
  Classifier: Programming Language :: Python
18
18
  Classifier: Programming Language :: Python :: 3
19
- Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.12
20
20
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
21
  Classifier: Typing :: Typed
22
22
  Requires-Python: >=3.9
@@ -26,13 +26,12 @@ Requires-Dist: requests
26
26
  Requires-Dist: types-requests
27
27
  Requires-Dist: ae_base
28
28
  Requires-Dist: ae_paths
29
- Requires-Dist: ae_dev_ops
30
29
  Provides-Extra: dev
31
30
  Requires-Dist: aedev_project_tpls; extra == "dev"
32
31
  Requires-Dist: ae_ae; extra == "dev"
33
32
  Requires-Dist: anybadge; extra == "dev"
34
33
  Requires-Dist: coverage-badge; extra == "dev"
35
- Requires-Dist: aedev_git_repo_manager; extra == "dev"
34
+ Requires-Dist: aedev_project_manager; extra == "dev"
36
35
  Requires-Dist: flake8; extra == "dev"
37
36
  Requires-Dist: mypy; extra == "dev"
38
37
  Requires-Dist: pylint; extra == "dev"
@@ -45,7 +44,7 @@ Provides-Extra: docs
45
44
  Provides-Extra: tests
46
45
  Requires-Dist: anybadge; extra == "tests"
47
46
  Requires-Dist: coverage-badge; extra == "tests"
48
- Requires-Dist: aedev_git_repo_manager; extra == "tests"
47
+ Requires-Dist: aedev_project_manager; extra == "tests"
49
48
  Requires-Dist: flake8; extra == "tests"
50
49
  Requires-Dist: mypy; extra == "tests"
51
50
  Requires-Dist: pylint; extra == "tests"
@@ -69,15 +68,15 @@ Dynamic: requires-dist
69
68
  Dynamic: requires-python
70
69
  Dynamic: summary
71
70
 
72
- <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae v0.3.97 -->
73
- <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.namespace_root_tpls v0.3.19 -->
74
- # pythonanywhere 0.3.1
71
+ <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae v0.3.101 -->
72
+ <!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.namespace_root_tpls v0.3.22 -->
73
+ # pythonanywhere 0.3.3
75
74
 
76
75
  [![GitLab develop](https://img.shields.io/gitlab/pipeline/ae-group/ae_pythonanywhere/develop?logo=python)](
77
76
  https://gitlab.com/ae-group/ae_pythonanywhere)
78
77
  [![LatestPyPIrelease](
79
- https://img.shields.io/gitlab/pipeline/ae-group/ae_pythonanywhere/release0.3.1?logo=python)](
80
- https://gitlab.com/ae-group/ae_pythonanywhere/-/tree/release0.3.1)
78
+ https://img.shields.io/gitlab/pipeline/ae-group/ae_pythonanywhere/release0.3.3?logo=python)](
79
+ https://gitlab.com/ae-group/ae_pythonanywhere/-/tree/release0.3.3)
81
80
  [![PyPIVersions](https://img.shields.io/pypi/v/ae_pythonanywhere)](
82
81
  https://pypi.org/project/ae-pythonanywhere/#history)
83
82
 
@@ -2,14 +2,13 @@ requests
2
2
  types-requests
3
3
  ae_base
4
4
  ae_paths
5
- ae_dev_ops
6
5
 
7
6
  [dev]
8
7
  aedev_project_tpls
9
8
  ae_ae
10
9
  anybadge
11
10
  coverage-badge
12
- aedev_git_repo_manager
11
+ aedev_project_manager
13
12
  flake8
14
13
  mypy
15
14
  pylint
@@ -24,7 +23,7 @@ types-setuptools
24
23
  [tests]
25
24
  anybadge
26
25
  coverage-badge
27
- aedev_git_repo_manager
26
+ aedev_project_manager
28
27
  flake8
29
28
  mypy
30
29
  pylint
@@ -1,4 +1,4 @@
1
- # THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.project_tpls v0.3.56
1
+ # THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.project_tpls v0.3.68
2
2
  [build-system]
3
3
  requires = ["setuptools>=42", "wheel"]
4
4
  build-backend = "setuptools.build_meta"
@@ -1,4 +1,4 @@
1
- # THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.project_tpls v0.3.56
1
+ # THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.project_tpls v0.3.68
2
2
  """ setup of ae namespace module portion pythonanywhere: PythonAnywhere Web API Client. """
3
3
  # noinspection PyUnresolvedReferences
4
4
  import sys
@@ -12,26 +12,26 @@ setup_kwargs = {
12
12
  'author_email': 'aecker2@gmail.com',
13
13
  'classifiers': [ 'Development Status :: 3 - Alpha', 'Natural Language :: English', 'Operating System :: OS Independent',
14
14
  'Programming Language :: Python', 'Programming Language :: Python :: 3',
15
- 'Programming Language :: Python :: 3.9', 'Topic :: Software Development :: Libraries :: Python Modules',
15
+ 'Programming Language :: Python :: 3.12', 'Topic :: Software Development :: Libraries :: Python Modules',
16
16
  'Typing :: Typed'],
17
17
  'description': 'ae namespace module portion pythonanywhere: PythonAnywhere Web API Client',
18
- 'extras_require': { 'dev': [ 'aedev_project_tpls', 'ae_ae', 'anybadge', 'coverage-badge', 'aedev_git_repo_manager', 'flake8',
18
+ 'extras_require': { 'dev': [ 'aedev_project_tpls', 'ae_ae', 'anybadge', 'coverage-badge', 'aedev_project_manager', 'flake8',
19
19
  'mypy', 'pylint', 'pytest', 'pytest-cov', 'pytest-django', 'typing', 'types-setuptools'],
20
20
  'docs': [],
21
- 'tests': [ 'anybadge', 'coverage-badge', 'aedev_git_repo_manager', 'flake8', 'mypy', 'pylint', 'pytest',
21
+ 'tests': [ 'anybadge', 'coverage-badge', 'aedev_project_manager', 'flake8', 'mypy', 'pylint', 'pytest',
22
22
  'pytest-cov', 'pytest-django', 'typing', 'types-setuptools']},
23
- 'install_requires': ['requests', 'types-requests', 'ae_base', 'ae_paths', 'ae_dev_ops'],
23
+ 'install_requires': ['requests', 'types-requests', 'ae_base', 'ae_paths'],
24
24
  'keywords': ['configuration', 'development', 'environment', 'productivity'],
25
25
  'license': 'GPL-3.0-or-later',
26
- 'long_description': ('<!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae v0.3.97 -->\n'
27
- '<!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.namespace_root_tpls v0.3.19 -->\n'
28
- '# pythonanywhere 0.3.1\n'
26
+ 'long_description': ('<!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project ae.ae v0.3.101 -->\n'
27
+ '<!-- THIS FILE IS EXCLUSIVELY MAINTAINED by the project aedev.namespace_root_tpls v0.3.22 -->\n'
28
+ '# pythonanywhere 0.3.3\n'
29
29
  '\n'
30
30
  '[![GitLab develop](https://img.shields.io/gitlab/pipeline/ae-group/ae_pythonanywhere/develop?logo=python)](\n'
31
31
  ' https://gitlab.com/ae-group/ae_pythonanywhere)\n'
32
32
  '[![LatestPyPIrelease](\n'
33
- ' https://img.shields.io/gitlab/pipeline/ae-group/ae_pythonanywhere/release0.3.1?logo=python)](\n'
34
- ' https://gitlab.com/ae-group/ae_pythonanywhere/-/tree/release0.3.1)\n'
33
+ ' https://img.shields.io/gitlab/pipeline/ae-group/ae_pythonanywhere/release0.3.3?logo=python)](\n'
34
+ ' https://gitlab.com/ae-group/ae_pythonanywhere/-/tree/release0.3.3)\n'
35
35
  '[![PyPIVersions](https://img.shields.io/pypi/v/ae_pythonanywhere)](\n'
36
36
  ' https://pypi.org/project/ae-pythonanywhere/#history)\n'
37
37
  '\n'
@@ -108,7 +108,7 @@ setup_kwargs = {
108
108
  'Source': 'https://ae.readthedocs.io/en/latest/_modules/ae/pythonanywhere.html'},
109
109
  'python_requires': '>=3.9',
110
110
  'url': 'https://gitlab.com/ae-group/ae_pythonanywhere',
111
- 'version': '0.3.1',
111
+ 'version': '0.3.3',
112
112
  'zip_safe': True,
113
113
  }
114
114
 
@@ -1,27 +1,31 @@
1
- """ unit tests for ae_pythonanywhere module package.
1
+ """ unit and integration tests of the ae_pythonanywhere module package.
2
2
 
3
- minimal testing because of the rate-limits on pythonanywhere.com (each endpoint has a 40 requests per minute rate limit,
4
- apart from the send_input endpoint on consoles, which is 120 requests per minute - see
3
+ minimal and only local integration testing because of the rate-limits on pythonanywhere.com (each endpoint has a 40
4
+ requests per minute rate limit, apart from the send_input endpoint on consoles, which is 120 requests per minute - see
5
5
  `https://help.pythonanywhere.com/pages/API`__ for more details).
6
6
  """
7
7
  import os
8
8
  import pytest
9
9
  import requests
10
10
 
11
- from conftest import skip_gitlab_ci
12
11
  from unittest.mock import Mock, patch
13
12
 
14
- from ae.base import PY_CACHE_FOLDER, PY_INIT, load_dotenvs, norm_name
15
- from ae.shell import get_domain_user_variable, get_main_app
13
+ from conftest import skip_gitlab_ci
14
+
15
+ from ae.base import PY_CACHE_FOLDER, PY_INIT, load_dotenvs, norm_name, os_path_join
16
+ from ae.shell import get_domain_user_var
16
17
  from ae.pythonanywhere import PythonanywhereApi
17
18
 
18
19
 
19
- TEST_PROJECT_NAME = 'ae_pythonanywhere_tests' #: package name used for integrity tests on web server
20
+ TST_DOMAIN_NAME = 'python_anywhere.tst'
21
+ TST_USER_NAME = 'py_any_user'
22
+ TST_WEB_TOKEN = 'py_any_token'
23
+ TST_PROJECT_NAME = 'ae_pythonanywhere_tests' #: package name used for local unit and integration tests
20
24
 
21
- pkg0_ini_path = os.path.join(TEST_PROJECT_NAME, PY_INIT)
25
+ pkg0_ini_path = os.path.join(TST_PROJECT_NAME, PY_INIT)
22
26
  pkg0_version = '333.66.9'
23
27
  pkg0_ini_content = f'""" test package doc string. """\n\n__version__ = \'{pkg0_version}\'\n'.encode()
24
- pkg0_static_file = f'{TEST_PROJECT_NAME}/static/baseball.html'
28
+ pkg0_static_file = f'{TST_PROJECT_NAME}/static/baseball.html'
25
29
 
26
30
  pkg1_name = "test_pkg1"
27
31
  pkg1_file_path = f'{pkg1_name}/namespace_mod.py'
@@ -51,24 +55,28 @@ skipped_lean_paths = {'not_deployed_root_file.xxx',
51
55
  all_file_paths = all_pkg_paths | skipped_web_paths | skipped_lean_paths | static_file_paths
52
56
 
53
57
 
58
+ @pytest.fixture
59
+ def api_obj():
60
+ yield PythonanywhereApi(TST_DOMAIN_NAME, TST_USER_NAME, TST_WEB_TOKEN, TST_PROJECT_NAME)
61
+
62
+
54
63
  @pytest.fixture(scope='class')
55
64
  def connection():
56
- """ provide personal pythonanywhere remote web server for tests only running locally with personal credentials. """
57
- main_app = get_main_app()
58
- load_dotenvs(main_app)
65
+ """ pythonanywhere remote web server connection for integration tests, only run locally using .env credentials. """
66
+ load_dotenvs()
59
67
 
60
68
  web_domain = "www.pythonanywhere.com"
61
69
  web_user = os.environ.get('PDV_AUTHOR')
62
- web_token = get_domain_user_variable(main_app, 'web_token', domain=web_domain, user=web_user)
70
+ web_token = get_domain_user_var('web_token', domain=web_domain, user=web_user)
63
71
 
64
- remote_connection = PythonanywhereApi(web_domain, web_user, web_token, TEST_PROJECT_NAME)
72
+ remote_connection = PythonanywhereApi(web_domain, web_user, web_token, TST_PROJECT_NAME)
65
73
 
66
74
  yield remote_connection
67
75
 
68
76
 
69
77
  @pytest.fixture(scope='class')
70
78
  def con_pkg(connection):
71
- """ provide personal pythonanywhere remote web server connection plus test package for tests """
79
+ """ provide personal pythonanywhere remote web server connection plus test package for integration tests """
72
80
  del_fil = 'test0/sub4/del_file.txt'
73
81
  assert not connection.deploy_file(del_fil, b"deleted to test empty root folder")
74
82
  assert connection.error_message == ""
@@ -91,13 +99,118 @@ def test_pythonanywhere_declarations():
91
99
  """ test the module declarations (also for having at least one test case running on gitlab ci). """
92
100
  assert PythonanywhereApi
93
101
 
94
- assert norm_name(TEST_PROJECT_NAME) == TEST_PROJECT_NAME
102
+ assert norm_name(TST_PROJECT_NAME) == TST_PROJECT_NAME
95
103
 
96
104
  assert requests # not-used-inspection-warning workaround, used for requests.Response.json() patching
97
105
 
98
106
 
107
+ class TestPythonanywhereApi:
108
+ def test_instantiation(self, api_obj):
109
+ assert TST_DOMAIN_NAME in api_obj.base_url
110
+ assert TST_USER_NAME == api_obj.web_user
111
+ assert TST_USER_NAME in api_obj.base_url
112
+ assert TST_USER_NAME in api_obj.pkg_files_url_part
113
+ assert TST_WEB_TOKEN in api_obj.protocol_headers['Authorization']
114
+ assert TST_PROJECT_NAME == api_obj.project_name
115
+ assert TST_PROJECT_NAME in api_obj.pkg_files_url_part
116
+
117
+ def test_project_name_setter(self, api_obj):
118
+ api_obj.project_name = 'new-prj-name'
119
+
120
+ assert 'new-prj-name' == api_obj.project_name
121
+ assert 'new-prj-name' in api_obj.pkg_files_url_part
122
+
123
+ def test__folder_items(self, api_obj):
124
+ response_mock = Mock(status_code=200, json=lambda: {'file-name': {'type': 'file-type'}})
125
+ with patch('ae.pythonanywhere.PythonanywhereApi._request', return_value=response_mock):
126
+ ret = api_obj._folder_items('folder-path')
127
+ assert isinstance(ret, list) and len(ret) == 1
128
+ assert ret[0]['file_path'] == os_path_join('folder-path', 'file-name')
129
+ assert ret[0]['type'] == 'file-type'
130
+ assert not api_obj.error_message # 404 error gets reset
131
+
132
+ def test__folder_items_err_inexistent_file_path(self, api_obj):
133
+ assert api_obj._folder_items('inexistent_file_path') is None
134
+ assert api_obj.error_message
135
+
136
+ def test__folder_items_err_inexistent_folder(self, api_obj):
137
+ with patch('ae.pythonanywhere.PythonanywhereApi._request', return_value=Mock(status_code=404)):
138
+ api_obj.error_message = 'simulate folder not found 404 error'
139
+ assert api_obj._folder_items('any_folder_path') is None
140
+ assert not api_obj.error_message # 404 error gets reset
141
+
142
+ def test__folder_items_err_empty_folder(self, api_obj):
143
+ with patch('ae.pythonanywhere.PythonanywhereApi._request', return_value=Mock(status_code=200, json=lambda: {})):
144
+ assert api_obj._folder_items('any_folder_path') == []
145
+ assert not api_obj.error_message
146
+
147
+ def test__from_json_err(self, api_obj):
148
+ assert api_obj._from_json(Mock(json=lambda: 1 / 0, content='err-content')) is None
149
+ assert 'err-content' in api_obj.error_message
150
+
151
+ def test_available_consoles(self, api_obj):
152
+ response_mock = Mock(json=lambda: [{'console-name': 'any-type'}])
153
+ with patch('ae.pythonanywhere.PythonanywhereApi._request', return_value=response_mock):
154
+ ret = api_obj.available_consoles()
155
+ assert isinstance(ret, list) and len(ret) == 1
156
+ assert ret[0]['console-name'] == 'any-type'
157
+ assert not api_obj.error_message
158
+
159
+ def test_available_consoles_err(self, api_obj):
160
+ response_mock = Mock(json=lambda: None)
161
+ with patch('ae.pythonanywhere.PythonanywhereApi._request', return_value=response_mock):
162
+ ret = api_obj.available_consoles()
163
+ assert ret == []
164
+
165
+ def test_console_execute(self, api_obj):
166
+ response_mock = Mock(json=lambda: {'output': 'out-put-str'})
167
+ with patch('ae.pythonanywhere.PythonanywhereApi._request', return_value=response_mock):
168
+ ret = api_obj.console_execute(699, 'command-str')
169
+ assert ret == 'out-put-str'
170
+ assert not api_obj.error_message
171
+
172
+ def test_console_execute_err(self, api_obj):
173
+ api_obj.error_message = 'con_exe_err-message'
174
+ with patch('ae.pythonanywhere.PythonanywhereApi._request', return_value=Mock()):
175
+ ret = api_obj.console_execute(699, 'command-str')
176
+ assert ret == ""
177
+ assert api_obj.error_message
178
+
179
+ def test_deployed_code_files(self, api_obj):
180
+ with patch('ae.pythonanywhere.PythonanywhereApi._request',
181
+ return_value=Mock(json=lambda: {'file-Name': {'type': 'any.type'}})):
182
+ ret = api_obj.deployed_code_files('folder-path/*.py')
183
+ assert ret == {'file-Name'}
184
+
185
+ def test_deployed_code_files_err(self, api_obj):
186
+ with patch('ae.pythonanywhere.PythonanywhereApi.find_project_files', return_value=None):
187
+ ret = api_obj.deployed_code_files('folder-path/*.py')
188
+ assert ret is None
189
+
190
+ def test_deployed_file_content(self, api_obj):
191
+ with patch('ae.pythonanywhere.PythonanywhereApi._request', return_value=Mock(content=b'content-str')):
192
+ ret = api_obj.deployed_file_content('folder-path/file.path.xxx')
193
+ assert ret == b'content-str'
194
+
195
+ def test_deployed_file_content_err(self, api_obj):
196
+ api_obj.error_message = 'dep_fil_content-err-message'
197
+ with patch('ae.pythonanywhere.PythonanywhereApi._request', return_value=Mock(content=b'content-str')):
198
+ ret = api_obj.deployed_file_content('folder-path/file.path.xxx')
199
+ assert ret is None
200
+
201
+ def test_deploy_file(self, api_obj):
202
+ with patch('ae.pythonanywhere.PythonanywhereApi._request', return_value=Mock()):
203
+ ret = api_obj.deploy_file('folder-path/file.path.xxx', b'file-content')
204
+ assert ret is api_obj.error_message
205
+
206
+ def test_delete_file_or_folder(self, api_obj):
207
+ with patch('ae.pythonanywhere.PythonanywhereApi._request', return_value=Mock()):
208
+ ret = api_obj.delete_file_or_folder('folder-path/file.path.xxx')
209
+ assert ret is api_obj.error_message
210
+
211
+
99
212
  @skip_gitlab_ci # skip on gitlab because of missing remote repository user account token
100
- class TestHostRunningOnlyLocally:
213
+ class TestIntegrationRunningOnlyLocally:
101
214
  def test_init_and_clean_up_from_last_failed_test_run(self, connection):
102
215
  assert connection.error_message == ""
103
216
 
@@ -110,19 +223,18 @@ class TestHostRunningOnlyLocally:
110
223
  assert connection.error_message == ""
111
224
  assert isinstance(consoles, list)
112
225
 
113
- def test_deploy_file_and_deployed_file_content_and_deployed_version(self, con_pkg):
226
+ def test_deployed_file_content(self, con_pkg):
114
227
  con_pkg.error_message = "" # clear con_pkg instance error from last test method
115
228
 
116
229
  assert con_pkg.deployed_file_content(pkg0_ini_path) == pkg0_ini_content
117
- assert con_pkg.error_message == ""
118
230
 
119
- assert con_pkg.deployed_version() == pkg0_version
120
231
  assert con_pkg.error_message == ""
121
232
 
122
233
  inv_fil_path = "not/existing/file_path"
234
+
123
235
  assert con_pkg.deployed_file_content(inv_fil_path) is None
124
- assert inv_fil_path in con_pkg.error_message
125
236
 
237
+ assert inv_fil_path in con_pkg.error_message
126
238
  con_pkg.error_message = "" # clear con_pkg instance error
127
239
 
128
240
  def test_files_iterator_absolute_path(self, con_pkg):
@@ -293,12 +405,12 @@ class TestHostRunningOnlyLocally:
293
405
 
294
406
 
295
407
  @skip_gitlab_ci # skip on gitlab because of missing remote repository user account token
296
- class TestHostRunningOnlyLocallyWithPatchedSkipper:
408
+ class TestIntegrationRunningOnlyLocallyWithPatchedSkipper:
297
409
  # with con_pkg.skip_enter_folder patched by deployed_code_file() or find_project_files()
298
410
  def test_deployed_code_files(self, con_pkg):
299
411
  con_pkg.error_message = "" # clear con_pkg instance error from last test method
300
412
 
301
- assert con_pkg.deployed_code_files({os.path.join(TEST_PROJECT_NAME, '**', '*.py')}) == {pkg0_ini_path}
413
+ assert con_pkg.deployed_code_files({os.path.join(TST_PROJECT_NAME, '**', '*.py')}) == {pkg0_ini_path}
302
414
  assert con_pkg.error_message == ""
303
415
 
304
416
  found_paths = con_pkg.deployed_code_files(['*/**/media*/*'])
@@ -322,7 +434,7 @@ class TestHostRunningOnlyLocallyWithPatchedSkipper:
322
434
  assert found_paths == {pkg0_static_file, pkg2_static_file} # static_ini_file get excluded
323
435
 
324
436
  found_paths = con_pkg.deployed_code_files(['**/static/*'],
325
- skip_file_path=lambda _: _.startswith(f'{TEST_PROJECT_NAME}/static/'))
437
+ skip_file_path=lambda _: _.startswith(f'{TST_PROJECT_NAME}/static/'))
326
438
  assert con_pkg.error_message == ""
327
439
  assert found_paths == {static_ini_file, pkg2_static_file} # pkg0_static_file get excluded
328
440