quickpub 1.0.2__tar.gz → 2.0.0__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.
- {quickpub-1.0.2 → quickpub-2.0.0}/LICENSE +20 -20
- {quickpub-1.0.2/quickpub.egg-info → quickpub-2.0.0}/PKG-INFO +22 -14
- quickpub-2.0.0/README.md +40 -0
- {quickpub-1.0.2 → quickpub-2.0.0}/pyproject.toml +2 -2
- {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/__main__.py +26 -34
- {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/classifiers.py +16 -0
- quickpub-2.0.0/quickpub/enforcers.py +17 -0
- {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/proxy.py +1 -1
- {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/qa.py +13 -17
- quickpub-2.0.0/quickpub/strategies/__init__.py +7 -0
- quickpub-1.0.2/quickpub/strategies/upload_strategy.py → quickpub-2.0.0/quickpub/strategies/build_schema.py +4 -3
- quickpub-2.0.0/quickpub/strategies/constraint_enforcer.py +16 -0
- quickpub-2.0.0/quickpub/strategies/implementations/__init__.py +5 -0
- quickpub-2.0.0/quickpub/strategies/implementations/build_schemas/__init__.py +1 -0
- quickpub-2.0.0/quickpub/strategies/implementations/build_schemas/setuptools_build_schema.py +27 -0
- quickpub-2.0.0/quickpub/strategies/implementations/constraint_enforcers/__init__.py +5 -0
- quickpub-2.0.0/quickpub/strategies/implementations/constraint_enforcers/license_enforcer.py +17 -0
- quickpub-2.0.0/quickpub/strategies/implementations/constraint_enforcers/local_version_enforcer.py +58 -0
- quickpub-2.0.0/quickpub/strategies/implementations/constraint_enforcers/pypi_remote_version_enforcer.py +39 -0
- quickpub-2.0.0/quickpub/strategies/implementations/constraint_enforcers/pypirc_enforcer.py +29 -0
- quickpub-2.0.0/quickpub/strategies/implementations/constraint_enforcers/readme_enforcer.py +20 -0
- quickpub-2.0.0/quickpub/strategies/implementations/python_providers/__init__.py +2 -0
- quickpub-1.0.2/quickpub/strategies/implementations/conda_python_version_manager_strategy.py → quickpub-2.0.0/quickpub/strategies/implementations/python_providers/conda_python_provider.py +9 -13
- quickpub-2.0.0/quickpub/strategies/implementations/python_providers/default_python_provider.py +26 -0
- quickpub-2.0.0/quickpub/strategies/implementations/quality_assurance_runners/__init__.py +4 -0
- quickpub-1.0.2/quickpub/strategies/implementations/mypy_qa_strategy.py → quickpub-2.0.0/quickpub/strategies/implementations/quality_assurance_runners/mypy_qa_runner.py +20 -12
- quickpub-1.0.2/quickpub/strategies/implementations/pylint_qa_strategy.py → quickpub-2.0.0/quickpub/strategies/implementations/quality_assurance_runners/pylint_qa_runner.py +5 -5
- quickpub-2.0.0/quickpub/strategies/implementations/quality_assurance_runners/pytest_qa_runner.py +96 -0
- quickpub-2.0.0/quickpub/strategies/implementations/quality_assurance_runners/unittest_qa_runner.py +59 -0
- quickpub-2.0.0/quickpub/strategies/implementations/upload_targets/__init__.py +2 -0
- quickpub-1.0.2/quickpub/strategies/implementations/git_upload_strategy.py → quickpub-2.0.0/quickpub/strategies/implementations/upload_targets/github_upload_target.py +4 -4
- quickpub-1.0.2/quickpub/strategies/implementations/pypirc_upload_strategy.py → quickpub-2.0.0/quickpub/strategies/implementations/upload_targets/pypirc_upload_target.py +6 -6
- quickpub-1.0.2/quickpub/strategies/python_version_manager_strategy.py → quickpub-2.0.0/quickpub/strategies/python_provider.py +14 -3
- quickpub-2.0.0/quickpub/strategies/quality_assurance_runner.py +167 -0
- {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/strategies/quickpub_strategy.py +3 -1
- quickpub-1.0.2/quickpub/strategies/build_strategy.py → quickpub-2.0.0/quickpub/strategies/upload_target.py +3 -3
- {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/structures/dependency.py +23 -17
- {quickpub-1.0.2 → quickpub-2.0.0/quickpub.egg-info}/PKG-INFO +22 -14
- quickpub-2.0.0/quickpub.egg-info/SOURCES.txt +51 -0
- quickpub-2.0.0/quickpub.egg-info/requires.txt +2 -0
- quickpub-1.0.2/README.md +0 -32
- quickpub-1.0.2/quickpub/enforcers.py +0 -84
- quickpub-1.0.2/quickpub/strategies/__init__.py +0 -6
- quickpub-1.0.2/quickpub/strategies/implementations/__init__.py +0 -9
- quickpub-1.0.2/quickpub/strategies/implementations/pytest_qa_strategy.py +0 -1
- quickpub-1.0.2/quickpub/strategies/implementations/setuptools_build_strategy.py +0 -21
- quickpub-1.0.2/quickpub/strategies/implementations/system_interpreter.py +0 -25
- quickpub-1.0.2/quickpub/strategies/implementations/unittest_qa_strategy.py +0 -57
- quickpub-1.0.2/quickpub/strategies/quality_assurance_strategy.py +0 -98
- quickpub-1.0.2/quickpub.egg-info/SOURCES.txt +0 -40
- quickpub-1.0.2/quickpub.egg-info/requires.txt +0 -1
- {quickpub-1.0.2 → quickpub-2.0.0}/MANIFEST.in +0 -0
- {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/__init__.py +0 -0
- {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/files.py +0 -0
- {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/functions.py +0 -0
- {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/py.typed +0 -0
- {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/structures/__init__.py +0 -0
- {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/structures/bound.py +0 -0
- {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/structures/version.py +0 -0
- {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/validators.py +0 -0
- {quickpub-1.0.2 → quickpub-2.0.0}/quickpub.egg-info/dependency_links.txt +0 -0
- {quickpub-1.0.2 → quickpub-2.0.0}/quickpub.egg-info/top_level.txt +0 -0
- {quickpub-1.0.2 → quickpub-2.0.0}/setup.cfg +0 -0
- {quickpub-1.0.2 → quickpub-2.0.0}/setup.py +0 -0
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2022 danielnachumdev
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 danielnachumdev
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
21
|
SOFTWARE.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: quickpub
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: A python package to quickly configure and publish a new package
|
|
5
5
|
Author-email: danielnachumdev <danielnachumdev@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -34,35 +34,43 @@ Requires-Python: >=3.8.0
|
|
|
34
34
|
Description-Content-Type: text/markdown
|
|
35
35
|
License-File: LICENSE
|
|
36
36
|
|
|
37
|
-
# quickpub
|
|
37
|
+
# quickpub V1.0.3
|
|
38
38
|
**Tested python versions**: `3.8.0`, `3.9.0`, `3.10.13`,
|
|
39
39
|
|
|
40
40
|
Example usage of how this package was published
|
|
41
|
+
|
|
41
42
|
```python
|
|
42
|
-
from quickpub import publish,
|
|
43
|
+
from quickpub import publish, MypyRunner, PylintRunner, UnittestRunner, CondaPythonProvider,
|
|
44
|
+
PypircUploadTarget, SetuptoolsBuildSchema, GithubUploadTarget, PypircEnforcer, ReadmeEnforcer, LicenseEnforcer,
|
|
45
|
+
PypiRemoteVersionEnforcer, LocalVersionEnforcer
|
|
43
46
|
|
|
44
47
|
|
|
45
48
|
def main() -> None:
|
|
46
49
|
publish(
|
|
47
50
|
name="quickpub",
|
|
48
|
-
version="0.
|
|
51
|
+
version="1.0.3",
|
|
49
52
|
author="danielnachumdev",
|
|
50
53
|
author_email="danielnachumdev@gmail.com",
|
|
51
54
|
description="A python package to quickly configure and publish a new package",
|
|
52
55
|
homepage="https://github.com/danielnachumdev/quickpub",
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
56
|
+
enforcers=[
|
|
57
|
+
PypircEnforcer(), ReadmeEnforcer(), LicenseEnforcer(),
|
|
58
|
+
LocalVersionEnforcer(), PypiRemoteVersionEnforcer()
|
|
59
|
+
],
|
|
60
|
+
build_schemas=[SetuptoolsBuildSchema()],
|
|
61
|
+
upload_targets=[PypircUploadTarget(), GithubUploadTarget()],
|
|
62
|
+
python_interpreter_provider=CondaPythonProvider(["base", "390", "380"]),
|
|
63
|
+
global_quality_assurance_runners=[
|
|
64
|
+
MypyRunner(bound="<=15", configuration_path="./mypy.ini"),
|
|
65
|
+
PylintRunner(bound=">=0.8", configuration_path="./.pylintrc"),
|
|
66
|
+
UnittestRunner(bound=">=0.8"),
|
|
67
|
+
],
|
|
68
|
+
dependencies=["danielutils>=0.9.92", "requests"],
|
|
69
|
+
min_python="3.8.0",
|
|
70
|
+
demo=True
|
|
62
71
|
)
|
|
63
72
|
|
|
64
73
|
|
|
65
74
|
if __name__ == '__main__':
|
|
66
75
|
main()
|
|
67
|
-
|
|
68
76
|
```
|
quickpub-2.0.0/README.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# quickpub V1.0.3
|
|
2
|
+
**Tested python versions**: `3.8.0`, `3.9.0`, `3.10.13`,
|
|
3
|
+
|
|
4
|
+
Example usage of how this package was published
|
|
5
|
+
|
|
6
|
+
```python
|
|
7
|
+
from quickpub import publish, MypyRunner, PylintRunner, UnittestRunner, CondaPythonProvider,
|
|
8
|
+
PypircUploadTarget, SetuptoolsBuildSchema, GithubUploadTarget, PypircEnforcer, ReadmeEnforcer, LicenseEnforcer,
|
|
9
|
+
PypiRemoteVersionEnforcer, LocalVersionEnforcer
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main() -> None:
|
|
13
|
+
publish(
|
|
14
|
+
name="quickpub",
|
|
15
|
+
version="1.0.3",
|
|
16
|
+
author="danielnachumdev",
|
|
17
|
+
author_email="danielnachumdev@gmail.com",
|
|
18
|
+
description="A python package to quickly configure and publish a new package",
|
|
19
|
+
homepage="https://github.com/danielnachumdev/quickpub",
|
|
20
|
+
enforcers=[
|
|
21
|
+
PypircEnforcer(), ReadmeEnforcer(), LicenseEnforcer(),
|
|
22
|
+
LocalVersionEnforcer(), PypiRemoteVersionEnforcer()
|
|
23
|
+
],
|
|
24
|
+
build_schemas=[SetuptoolsBuildSchema()],
|
|
25
|
+
upload_targets=[PypircUploadTarget(), GithubUploadTarget()],
|
|
26
|
+
python_interpreter_provider=CondaPythonProvider(["base", "390", "380"]),
|
|
27
|
+
global_quality_assurance_runners=[
|
|
28
|
+
MypyRunner(bound="<=15", configuration_path="./mypy.ini"),
|
|
29
|
+
PylintRunner(bound=">=0.8", configuration_path="./.pylintrc"),
|
|
30
|
+
UnittestRunner(bound=">=0.8"),
|
|
31
|
+
],
|
|
32
|
+
dependencies=["danielutils>=0.9.92", "requests"],
|
|
33
|
+
min_python="3.8.0",
|
|
34
|
+
demo=True
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
if __name__ == '__main__':
|
|
39
|
+
main()
|
|
40
|
+
```
|
|
@@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "quickpub"
|
|
7
|
-
version = "
|
|
7
|
+
version = "2.0.0"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name = "danielnachumdev", email = "danielnachumdev@gmail.com" },
|
|
10
10
|
]
|
|
11
|
-
dependencies = ['danielutils>=0.9.
|
|
11
|
+
dependencies = ['danielutils>=0.9.92', 'requests']
|
|
12
12
|
keywords = []
|
|
13
13
|
license = { "file" = "./LICENSE" }
|
|
14
14
|
description = "A python package to quickly configure and publish a new package"
|
|
@@ -2,14 +2,13 @@ import argparse
|
|
|
2
2
|
from typing import Optional, Union, List, Any
|
|
3
3
|
from danielutils import warning, file_exists, error
|
|
4
4
|
|
|
5
|
-
from
|
|
6
|
-
|
|
5
|
+
from .strategies import BuildSchema, ConstraintEnforcer, UploadTarget, QualityAssuranceRunner, PythonProvider, \
|
|
6
|
+
DefaultPythonProvider
|
|
7
7
|
from .validators import validate_version, validate_python_version, validate_keywords, validate_dependencies, \
|
|
8
8
|
validate_source
|
|
9
9
|
from .structures import Version, Dependency
|
|
10
10
|
from .files import create_toml, create_setup, create_manifest
|
|
11
11
|
from .classifiers import *
|
|
12
|
-
from .enforcers import enforce_local_correct_version, enforce_pypirc_exists, exit_if, enforce_remote_correct_version
|
|
13
12
|
from .qa import qa
|
|
14
13
|
|
|
15
14
|
|
|
@@ -21,22 +20,21 @@ def publish(
|
|
|
21
20
|
description: str,
|
|
22
21
|
homepage: str,
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
build_schemas: List[BuildSchema],
|
|
24
|
+
upload_targets: List[UploadTarget],
|
|
25
|
+
enforcers: Optional[List[ConstraintEnforcer]] = None,
|
|
26
|
+
global_quality_assurance_runners: Optional[List[QualityAssuranceRunner]] = None,
|
|
27
|
+
python_interpreter_provider: PythonProvider = DefaultPythonProvider(),
|
|
28
28
|
|
|
29
|
-
explicit_src_folder_path: Optional[str] = None,
|
|
30
|
-
version: Optional[Union[Version, str]] = None,
|
|
31
29
|
readme_file_path: str = "./README.md",
|
|
32
30
|
license_file_path: str = "./LICENSE",
|
|
33
|
-
|
|
31
|
+
version: Optional[Union[Version, str]] = None,
|
|
34
32
|
min_python: Optional[Union[Version, str]] = None,
|
|
35
|
-
|
|
36
|
-
keywords: Optional[List[str]] = None,
|
|
37
33
|
dependencies: Optional[List[Union[str, Dependency]]] = None,
|
|
38
|
-
|
|
34
|
+
keywords: Optional[List[str]] = None,
|
|
35
|
+
explicit_src_folder_path: Optional[str] = None,
|
|
39
36
|
|
|
37
|
+
demo: bool = False,
|
|
40
38
|
config: Optional[Any] = None,
|
|
41
39
|
) -> None:
|
|
42
40
|
"""The main function for publishing a package. It performs all necessary steps to prepare and publish the package.
|
|
@@ -46,11 +44,11 @@ def publish(
|
|
|
46
44
|
:param author_email: The email of the author.
|
|
47
45
|
:param description: A short description of the package.
|
|
48
46
|
:param homepage: The homepage URL for the package (e.g., GitHub repository).
|
|
49
|
-
:param
|
|
50
|
-
:param
|
|
51
|
-
:param
|
|
52
|
-
:param
|
|
53
|
-
:param explicit_src_folder_path: The path to the source code of the package. Defaults to
|
|
47
|
+
:param global_quality_assurance_runners: Strategies for quality assurance. These will run on all Envs supplies by the supplier.
|
|
48
|
+
:param build_schemas: Strategies for building the package.
|
|
49
|
+
:param upload_targets: Strategies for uploading the package.
|
|
50
|
+
:param python_interpreter_provider: Strategy for managing Python versions. Defaults to SystemInterpreter().
|
|
51
|
+
:param explicit_src_folder_path: The path to the source code of the package. Defaults to <current working directory>/<name>.
|
|
54
52
|
:param version: The version for the new distribution. Defaults to "0.0.1".
|
|
55
53
|
:param readme_file_path: The path to the README file. Defaults to "./README.md".
|
|
56
54
|
:param license_file_path: The path to the license file. Defaults to "./LICENSE".
|
|
@@ -63,28 +61,22 @@ def publish(
|
|
|
63
61
|
Returns:
|
|
64
62
|
None
|
|
65
63
|
"""
|
|
66
|
-
|
|
67
|
-
enforce_pypirc_exists()
|
|
64
|
+
version = validate_version(version)
|
|
68
65
|
explicit_src_folder_path = validate_source(name, explicit_src_folder_path)
|
|
69
66
|
if explicit_src_folder_path != f"./{name}":
|
|
70
67
|
warning(
|
|
71
68
|
"The source folder's name is different from the package's name. this may not be currently supported correctly")
|
|
72
|
-
exit_if(not file_exists(readme_file_path), f"Could not find readme file at {readme_file_path}")
|
|
73
|
-
exit_if(not file_exists(license_file_path), f"Could not find license file at {license_file_path}")
|
|
74
|
-
version = validate_version(version)
|
|
75
|
-
if not demo:
|
|
76
|
-
enforce_local_correct_version(name, version)
|
|
77
69
|
min_python = validate_python_version(min_python) # type:ignore
|
|
78
70
|
keywords = validate_keywords(keywords)
|
|
79
71
|
validated_dependencies: List[Dependency] = validate_dependencies(dependencies)
|
|
80
|
-
enforce_remote_correct_version(name, version)
|
|
81
72
|
|
|
82
|
-
|
|
83
|
-
|
|
73
|
+
for enforcer in enforcers or []:
|
|
74
|
+
enforcer.enforce(name=name, version=version, demo=demo)
|
|
75
|
+
|
|
84
76
|
try:
|
|
85
77
|
res = qa(
|
|
86
|
-
|
|
87
|
-
|
|
78
|
+
python_interpreter_provider,
|
|
79
|
+
global_quality_assurance_runners or [],
|
|
88
80
|
name,
|
|
89
81
|
explicit_src_folder_path,
|
|
90
82
|
validated_dependencies
|
|
@@ -122,10 +114,10 @@ def publish(
|
|
|
122
114
|
)
|
|
123
115
|
create_manifest(name=name)
|
|
124
116
|
if not demo:
|
|
125
|
-
for
|
|
126
|
-
|
|
127
|
-
for
|
|
128
|
-
|
|
117
|
+
for schema in build_schemas:
|
|
118
|
+
schema.build()
|
|
119
|
+
for target in upload_targets:
|
|
120
|
+
target.upload(name=name, version=version)
|
|
129
121
|
|
|
130
122
|
|
|
131
123
|
def parse_args():
|
|
@@ -3,6 +3,10 @@ from enum import Enum
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class Classifier(Enum):
|
|
6
|
+
"""
|
|
7
|
+
A base enum class for all classifiers.
|
|
8
|
+
"""
|
|
9
|
+
|
|
6
10
|
def _str(self) -> str:
|
|
7
11
|
return str(self.value)
|
|
8
12
|
|
|
@@ -36,6 +40,9 @@ class Classifier(Enum):
|
|
|
36
40
|
|
|
37
41
|
|
|
38
42
|
class DevelopmentStatusClassifier(Classifier):
|
|
43
|
+
"""
|
|
44
|
+
An enum class for specifying the development state of the package
|
|
45
|
+
"""
|
|
39
46
|
# https://pypi.org/classifiers/
|
|
40
47
|
Planning = 1
|
|
41
48
|
PreAlpha = 2
|
|
@@ -51,15 +58,24 @@ class DevelopmentStatusClassifier(Classifier):
|
|
|
51
58
|
|
|
52
59
|
|
|
53
60
|
class IntendedAudienceClassifier(Classifier):
|
|
61
|
+
"""
|
|
62
|
+
An enum class for specifying the intended audience
|
|
63
|
+
"""
|
|
54
64
|
CustomerService = "CustomerService"
|
|
55
65
|
Developers = "Developers"
|
|
56
66
|
|
|
57
67
|
|
|
58
68
|
class ProgrammingLanguageClassifier(Classifier):
|
|
69
|
+
"""
|
|
70
|
+
An enum class for specifying the target language level
|
|
71
|
+
"""
|
|
59
72
|
Python3 = "Python :: 3"
|
|
60
73
|
|
|
61
74
|
|
|
62
75
|
class OperatingSystemClassifier(Classifier):
|
|
76
|
+
"""
|
|
77
|
+
An enum class for specifying the target operating system
|
|
78
|
+
"""
|
|
63
79
|
MicrosoftWindows = "Microsoft :: Windows"
|
|
64
80
|
|
|
65
81
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from typing import Union, Callable
|
|
3
|
+
|
|
4
|
+
from danielutils import error
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def exit_if(predicate: Union[bool, Callable[[], bool]], msg: str, *, verbose: bool = True,
|
|
8
|
+
err_func: Callable[[str], None] = error) -> None:
|
|
9
|
+
if (isinstance(predicate, bool) and predicate) or (callable(predicate) and predicate()):
|
|
10
|
+
if verbose:
|
|
11
|
+
err_func(msg)
|
|
12
|
+
sys.exit(1)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"exit_if"
|
|
17
|
+
]
|
|
@@ -4,8 +4,7 @@ from functools import wraps
|
|
|
4
4
|
from typing import Optional, ContextManager, List, Callable, Tuple, Dict, Union
|
|
5
5
|
from danielutils import AttrContext, LayeredCommand, AsciiProgressBar, ColoredText, ProgressBarPool, TemporaryFile
|
|
6
6
|
|
|
7
|
-
from
|
|
8
|
-
from .strategies import PythonVersionManagerStrategy # pylint: disable=relative-beyond-top-level
|
|
7
|
+
from .strategies import PythonProvider, QualityAssuranceRunner # pylint: disable=relative-beyond-top-level
|
|
9
8
|
from .structures import Dependency, Version, Bound # pylint: disable=relative-beyond-top-level
|
|
10
9
|
from .enforcers import exit_if # pylint: disable=relative-beyond-top-level
|
|
11
10
|
|
|
@@ -54,7 +53,7 @@ def global_import_sanity_check(package_name: str, executor: LayeredCommand, is_s
|
|
|
54
53
|
VERSION_REGEX: re.Pattern = re.compile(r"^\d+\.\d+\.\d+$")
|
|
55
54
|
|
|
56
55
|
|
|
57
|
-
def validate_dependencies(python_manager:
|
|
56
|
+
def validate_dependencies(python_manager: PythonProvider, required_dependencies: List[Dependency],
|
|
58
57
|
executor: LayeredCommand,
|
|
59
58
|
env_name: str, err_print_func: Callable) -> None:
|
|
60
59
|
"""
|
|
@@ -86,15 +85,15 @@ def validate_dependencies(python_manager: PythonVersionManagerStrategy, required
|
|
|
86
85
|
(req, "Verion format of dependecy is not currently supported by quickpub"))
|
|
87
86
|
elif isinstance(v, Dependency):
|
|
88
87
|
if not req.is_satisfied_by(v.ver):
|
|
89
|
-
not_installed_properly.append((req, "
|
|
88
|
+
not_installed_properly.append((req, "Invalid version installed"))
|
|
90
89
|
|
|
91
90
|
exit_if(bool(not_installed_properly),
|
|
92
91
|
f"On env '{env_name}' the following dependencies have problems: {(not_installed_properly)}",
|
|
93
92
|
err_func=err_print_func)
|
|
94
93
|
|
|
95
94
|
|
|
96
|
-
def create_progress_bar_pool(python_version_manager:
|
|
97
|
-
quality_assurance_strategies: List[
|
|
95
|
+
def create_progress_bar_pool(python_version_manager: PythonProvider,
|
|
96
|
+
quality_assurance_strategies: List[QualityAssuranceRunner]) -> ProgressBarPool:
|
|
98
97
|
return ProgressBarPool(
|
|
99
98
|
AsciiProgressBar,
|
|
100
99
|
2,
|
|
@@ -123,18 +122,16 @@ def create_pool_print_error(pool: ProgressBarPool):
|
|
|
123
122
|
|
|
124
123
|
|
|
125
124
|
def qa(
|
|
126
|
-
|
|
127
|
-
quality_assurance_strategies: List[
|
|
125
|
+
python_provider: PythonProvider,
|
|
126
|
+
quality_assurance_strategies: List[QualityAssuranceRunner],
|
|
128
127
|
package_name: str,
|
|
129
|
-
src_folder_path:
|
|
128
|
+
src_folder_path: str,
|
|
130
129
|
dependencies: list
|
|
131
130
|
) -> bool:
|
|
132
|
-
from .strategies import
|
|
131
|
+
from .strategies import DefaultPythonProvider
|
|
133
132
|
result = True
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
is_system_interpreter = isinstance(python_version_manager, SystemInterpreter)
|
|
137
|
-
pool = create_progress_bar_pool(python_version_manager, quality_assurance_strategies)
|
|
133
|
+
is_system_interpreter = isinstance(python_provider, DefaultPythonProvider)
|
|
134
|
+
pool = create_progress_bar_pool(python_provider, quality_assurance_strategies)
|
|
138
135
|
pool_err = create_pool_print_error(pool)
|
|
139
136
|
with MultiContext(
|
|
140
137
|
AttrContext(LayeredCommand, 'class_flush_stdout', False),
|
|
@@ -148,7 +145,7 @@ def qa(
|
|
|
148
145
|
with executor:
|
|
149
146
|
executor._prev_instance = base
|
|
150
147
|
try:
|
|
151
|
-
validate_dependencies(
|
|
148
|
+
validate_dependencies(python_provider, dependencies, executor, env_name, pool_err)
|
|
152
149
|
except SystemExit:
|
|
153
150
|
result = False
|
|
154
151
|
continue
|
|
@@ -165,7 +162,6 @@ def qa(
|
|
|
165
162
|
src_folder_path,
|
|
166
163
|
executor,
|
|
167
164
|
use_system_interpreter=is_system_interpreter,
|
|
168
|
-
raise_on_fail=python_version_manager.exit_on_fail,
|
|
169
165
|
print_func=pool_err,
|
|
170
166
|
env_name=env_name
|
|
171
167
|
)
|
|
@@ -179,7 +175,7 @@ def qa(
|
|
|
179
175
|
f"Failed running '{runner.__class__.__name__}' on env '{env_name}'. "
|
|
180
176
|
f"Try manually: '{manual_command}'.")
|
|
181
177
|
pool.write(f"\tCaused by '{e.__cause__ or e}'")
|
|
182
|
-
if
|
|
178
|
+
if python_provider.exit_on_fail:
|
|
183
179
|
raise RuntimeError() from e
|
|
184
180
|
return result
|
|
185
181
|
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
|
+
from typing import Type
|
|
2
3
|
|
|
3
4
|
from .quickpub_strategy import QuickpubStrategy
|
|
4
5
|
|
|
5
6
|
|
|
6
|
-
class
|
|
7
|
+
class BuildSchema(QuickpubStrategy):
|
|
7
8
|
def __init__(self, verbose: bool = True) -> None:
|
|
8
9
|
self.verbose = verbose
|
|
9
10
|
|
|
10
11
|
@abstractmethod
|
|
11
|
-
def
|
|
12
|
+
def build(self, *args, **kwargs) -> None: ...
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
__all__ = [
|
|
15
|
-
|
|
16
|
+
"BuildSchema"
|
|
16
17
|
]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from typing import Type
|
|
3
|
+
|
|
4
|
+
from .quickpub_strategy import QuickpubStrategy
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ConstraintEnforcer(QuickpubStrategy):
|
|
8
|
+
EXCEPTION_TYPE: Type[BaseException] = SystemExit
|
|
9
|
+
|
|
10
|
+
@abstractmethod
|
|
11
|
+
def enforce(self, **kwargs) -> None: ...
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
'ConstraintEnforcer'
|
|
16
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .setuptools_build_schema import *
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
3
|
+
from danielutils import info, file_exists, LayeredCommand
|
|
4
|
+
|
|
5
|
+
from ...build_schema import BuildSchema
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SetuptoolsBuildSchema(BuildSchema):
|
|
9
|
+
def __init__(self, setup_file_path: str = "./setup.py", backend: Literal["toml"] = "toml") -> None:
|
|
10
|
+
self._backend = backend
|
|
11
|
+
self._setup_file_path = setup_file_path
|
|
12
|
+
|
|
13
|
+
def build(self, verbose: bool = False, *args, **kwargs) -> None:
|
|
14
|
+
if not file_exists(self._setup_file_path):
|
|
15
|
+
raise self.EXCEPTION_TYPE(f"Could not find {self._setup_file_path} file")
|
|
16
|
+
if verbose:
|
|
17
|
+
info("Creating new distribution...")
|
|
18
|
+
with LayeredCommand("", instance_flush_stdout=False, instance_flush_stderr=False,
|
|
19
|
+
instance_raise_on_fail=False) as exc:
|
|
20
|
+
ret, stdout, stderr = exc("python " + self._setup_file_path + " sdist")
|
|
21
|
+
if ret != 0:
|
|
22
|
+
raise self.EXCEPTION_TYPE(stderr)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"SetuptoolsBuildSchema",
|
|
27
|
+
]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from danielutils import file_exists
|
|
2
|
+
|
|
3
|
+
from ...constraint_enforcer import ConstraintEnforcer
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class LicenseEnforcer(ConstraintEnforcer):
|
|
7
|
+
def __init__(self, path: str = "./LICENSE") -> None:
|
|
8
|
+
self.path = path
|
|
9
|
+
|
|
10
|
+
def enforce(self, **kwargs) -> None:
|
|
11
|
+
if not file_exists(self.path):
|
|
12
|
+
raise self.EXCEPTION_TYPE(f"Could not find license file at '{self.path}'")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"LicenseEnforcer",
|
|
17
|
+
]
|
quickpub-2.0.0/quickpub/strategies/implementations/constraint_enforcers/local_version_enforcer.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from danielutils import directory_exists, get_files, get_python_version
|
|
2
|
+
|
|
3
|
+
from quickpub import Version
|
|
4
|
+
from ...constraint_enforcer import ConstraintEnforcer
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _remove_suffix(s: str, suffix: str) -> str:
|
|
8
|
+
"""
|
|
9
|
+
This function is needed because str.removesuffix is not implemented in python == 3.8.0
|
|
10
|
+
:param s: string to remove from
|
|
11
|
+
:param suffix: substring to remove
|
|
12
|
+
:return: modified string
|
|
13
|
+
"""
|
|
14
|
+
if get_python_version() >= (3, 9):
|
|
15
|
+
return s.removesuffix(suffix) # type:ignore
|
|
16
|
+
return _remove_prefix(s[::-1], suffix[::-1])[::-1]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _remove_prefix(s: str, prefix: str) -> str:
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
:param s:
|
|
23
|
+
:param prefix:
|
|
24
|
+
:return:
|
|
25
|
+
"""
|
|
26
|
+
if get_python_version() >= (3, 9):
|
|
27
|
+
return s.removeprefix(prefix) # type:ignore
|
|
28
|
+
|
|
29
|
+
if s.startswith(prefix):
|
|
30
|
+
return s[len(prefix):]
|
|
31
|
+
return s
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class LocalVersionEnforcer(ConstraintEnforcer):
|
|
35
|
+
def enforce(self, name: str, version: Version, demo: bool = False, **kwargs) -> None: # type: ignore
|
|
36
|
+
if demo:
|
|
37
|
+
return
|
|
38
|
+
|
|
39
|
+
if not directory_exists("./dist"):
|
|
40
|
+
return
|
|
41
|
+
|
|
42
|
+
prev_builds = get_files("./dist")
|
|
43
|
+
if len(prev_builds) == 0:
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
max_local_version = Version(0, 0, 0)
|
|
47
|
+
for d in prev_builds:
|
|
48
|
+
d = _remove_suffix(_remove_prefix(d, f"{name}-"), ".tar.gz")
|
|
49
|
+
v: Version = Version.from_str(d)
|
|
50
|
+
max_local_version = max(max_local_version, v)
|
|
51
|
+
if version <= max_local_version:
|
|
52
|
+
raise self.EXCEPTION_TYPE(
|
|
53
|
+
f"Specified version is '{version}' but (locally available) latest existing is '{max_local_version}'")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
__all__ = [
|
|
57
|
+
'LocalVersionEnforcer'
|
|
58
|
+
]
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from danielutils import RetryExecutor, ExponentialBackOffStrategy, ConstantBackOffStrategy
|
|
2
|
+
from requests import Response
|
|
3
|
+
|
|
4
|
+
from proxy import get # type: ignore
|
|
5
|
+
from quickpub import Version
|
|
6
|
+
from ...constraint_enforcer import ConstraintEnforcer
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class PypiRemoteVersionEnforcer(ConstraintEnforcer):
|
|
10
|
+
_HTTP_FAILED_MESSAGE: str = "Failed to send http request"
|
|
11
|
+
|
|
12
|
+
def enforce(self, name: str, version: Version, demo: bool = False, **kwargs) -> None: # type: ignore
|
|
13
|
+
if demo:
|
|
14
|
+
return
|
|
15
|
+
url = f"https://pypi.org/project/{name}/"
|
|
16
|
+
|
|
17
|
+
timeout_strategy = ExponentialBackOffStrategy(1.1, 1.5)
|
|
18
|
+
|
|
19
|
+
def wrapper() -> Response:
|
|
20
|
+
return get(url, timeout=timeout_strategy.get_backoff())
|
|
21
|
+
|
|
22
|
+
executor: RetryExecutor[Response] = RetryExecutor(ConstantBackOffStrategy(1))
|
|
23
|
+
response = executor.execute(wrapper, 5)
|
|
24
|
+
if response is None:
|
|
25
|
+
raise SystemExit(self._HTTP_FAILED_MESSAGE)
|
|
26
|
+
html = response.content.decode()
|
|
27
|
+
i = html.index(f" {name} ")
|
|
28
|
+
try:
|
|
29
|
+
remote_version = Version.from_str(html[i:i + 50].splitlines()[0].strip().split()[1])
|
|
30
|
+
except Exception as e:
|
|
31
|
+
raise SystemExit(f"{self.__class__.__name__} encountered an unexpected error while parsing.") from e
|
|
32
|
+
if not version > remote_version:
|
|
33
|
+
raise SystemExit(
|
|
34
|
+
f"Specified version is '{version}' but (remotely available) latest existing is '{remote_version}'")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
__all__ = [
|
|
38
|
+
'PypiRemoteVersionEnforcer'
|
|
39
|
+
]
|