quickpub 1.0.0__tar.gz → 1.0.2__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.0/quickpub.egg-info → quickpub-1.0.2}/PKG-INFO +1 -1
- {quickpub-1.0.0 → quickpub-1.0.2}/pyproject.toml +2 -2
- {quickpub-1.0.0 → quickpub-1.0.2}/quickpub/__init__.py +1 -2
- quickpub-1.0.2/quickpub/__main__.py +169 -0
- {quickpub-1.0.0 → quickpub-1.0.2}/quickpub/enforcers.py +2 -2
- {quickpub-1.0.0 → quickpub-1.0.2}/quickpub/files.py +4 -3
- quickpub-1.0.2/quickpub/functions.py +72 -0
- {quickpub-1.0.0 → quickpub-1.0.2}/quickpub/qa.py +61 -31
- quickpub-1.0.2/quickpub/strategies/__init__.py +6 -0
- quickpub-1.0.2/quickpub/strategies/build_strategy.py +16 -0
- quickpub-1.0.2/quickpub/strategies/implementations/__init__.py +9 -0
- quickpub-1.0.0/quickpub/managers/implementations/conda.py → quickpub-1.0.2/quickpub/strategies/implementations/conda_python_version_manager_strategy.py +6 -6
- quickpub-1.0.2/quickpub/strategies/implementations/git_upload_strategy.py +26 -0
- quickpub-1.0.0/quickpub/runnables/implementations/mypy.py → quickpub-1.0.2/quickpub/strategies/implementations/mypy_qa_strategy.py +5 -5
- quickpub-1.0.0/quickpub/runnables/implementations/pylint.py → quickpub-1.0.2/quickpub/strategies/implementations/pylint_qa_strategy.py +10 -7
- quickpub-1.0.2/quickpub/strategies/implementations/pypirc_upload_strategy.py +44 -0
- quickpub-1.0.2/quickpub/strategies/implementations/pytest_qa_strategy.py +1 -0
- quickpub-1.0.2/quickpub/strategies/implementations/setuptools_build_strategy.py +21 -0
- {quickpub-1.0.0/quickpub/managers → quickpub-1.0.2/quickpub/strategies}/implementations/system_interpreter.py +3 -3
- quickpub-1.0.0/quickpub/runnables/implementations/unittest.py → quickpub-1.0.2/quickpub/strategies/implementations/unittest_qa_strategy.py +4 -4
- quickpub-1.0.0/quickpub/managers/python_manager.py → quickpub-1.0.2/quickpub/strategies/python_version_manager_strategy.py +7 -6
- quickpub-1.0.0/quickpub/runnables/base_runner.py → quickpub-1.0.2/quickpub/strategies/quality_assurance_strategy.py +45 -12
- quickpub-1.0.2/quickpub/strategies/quickpub_strategy.py +10 -0
- quickpub-1.0.2/quickpub/strategies/upload_strategy.py +16 -0
- {quickpub-1.0.0 → quickpub-1.0.2}/quickpub/structures/__init__.py +1 -1
- {quickpub-1.0.0 → quickpub-1.0.2}/quickpub/structures/bound.py +3 -2
- quickpub-1.0.2/quickpub/structures/dependency.py +47 -0
- {quickpub-1.0.0 → quickpub-1.0.2}/quickpub/structures/version.py +0 -1
- {quickpub-1.0.0 → quickpub-1.0.2}/quickpub/validators.py +10 -3
- {quickpub-1.0.0 → quickpub-1.0.2/quickpub.egg-info}/PKG-INFO +1 -1
- quickpub-1.0.2/quickpub.egg-info/SOURCES.txt +40 -0
- quickpub-1.0.2/quickpub.egg-info/requires.txt +1 -0
- quickpub-1.0.0/quickpub/__main__.py +0 -105
- quickpub-1.0.0/quickpub/functions.py +0 -209
- quickpub-1.0.0/quickpub/managers/__init__.py +0 -2
- quickpub-1.0.0/quickpub/managers/implementations/__init__.py +0 -2
- quickpub-1.0.0/quickpub/runnables/__init__.py +0 -2
- quickpub-1.0.0/quickpub/runnables/configurable.py +0 -20
- quickpub-1.0.0/quickpub/runnables/has_optional_executable.py +0 -32
- quickpub-1.0.0/quickpub/runnables/implementations/__init__.py +0 -4
- quickpub-1.0.0/quickpub/runnables/implementations/pytest.py +0 -2
- quickpub-1.0.0/quickpub/runnables/runnable.py +0 -11
- quickpub-1.0.0/quickpub/structures/additional_configuration.py +0 -15
- quickpub-1.0.0/quickpub.egg-info/SOURCES.txt +0 -39
- quickpub-1.0.0/quickpub.egg-info/requires.txt +0 -2
- {quickpub-1.0.0 → quickpub-1.0.2}/LICENSE +0 -0
- {quickpub-1.0.0 → quickpub-1.0.2}/MANIFEST.in +0 -0
- {quickpub-1.0.0 → quickpub-1.0.2}/README.md +0 -0
- {quickpub-1.0.0 → quickpub-1.0.2}/quickpub/classifiers.py +0 -0
- {quickpub-1.0.0 → quickpub-1.0.2}/quickpub/proxy.py +0 -0
- {quickpub-1.0.0 → quickpub-1.0.2}/quickpub/py.typed +0 -0
- {quickpub-1.0.0 → quickpub-1.0.2}/quickpub.egg-info/dependency_links.txt +0 -0
- {quickpub-1.0.0 → quickpub-1.0.2}/quickpub.egg-info/top_level.txt +0 -0
- {quickpub-1.0.0 → quickpub-1.0.2}/setup.cfg +0 -0
- {quickpub-1.0.0 → quickpub-1.0.2}/setup.py +0 -0
|
@@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "quickpub"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.2"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name = "danielnachumdev", email = "danielnachumdev@gmail.com" },
|
|
10
10
|
]
|
|
11
|
-
dependencies = ['
|
|
11
|
+
dependencies = ['danielutils>=0.9.90']
|
|
12
12
|
keywords = []
|
|
13
13
|
license = { "file" = "./LICENSE" }
|
|
14
14
|
description = "A python package to quickly configure and publish a new package"
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
from typing import Optional, Union, List, Any
|
|
3
|
+
from danielutils import warning, file_exists, error
|
|
4
|
+
|
|
5
|
+
from quickpub import SystemInterpreter
|
|
6
|
+
from strategies import BuildStrategy, UploadStrategy, QualityAssuranceStrategy, PythonVersionManagerStrategy
|
|
7
|
+
from .validators import validate_version, validate_python_version, validate_keywords, validate_dependencies, \
|
|
8
|
+
validate_source
|
|
9
|
+
from .structures import Version, Dependency
|
|
10
|
+
from .files import create_toml, create_setup, create_manifest
|
|
11
|
+
from .classifiers import *
|
|
12
|
+
from .enforcers import enforce_local_correct_version, enforce_pypirc_exists, exit_if, enforce_remote_correct_version
|
|
13
|
+
from .qa import qa
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def publish(
|
|
17
|
+
*,
|
|
18
|
+
name: str,
|
|
19
|
+
author: str,
|
|
20
|
+
author_email: str,
|
|
21
|
+
description: str,
|
|
22
|
+
homepage: str,
|
|
23
|
+
|
|
24
|
+
build_strategies: List[BuildStrategy],
|
|
25
|
+
upload_strategies: List[UploadStrategy],
|
|
26
|
+
quality_assurance_strategies: Optional[List[QualityAssuranceStrategy]] = None,
|
|
27
|
+
python_version_manager_strategy: PythonVersionManagerStrategy = SystemInterpreter(),
|
|
28
|
+
|
|
29
|
+
explicit_src_folder_path: Optional[str] = None,
|
|
30
|
+
version: Optional[Union[Version, str]] = None,
|
|
31
|
+
readme_file_path: str = "./README.md",
|
|
32
|
+
license_file_path: str = "./LICENSE",
|
|
33
|
+
|
|
34
|
+
min_python: Optional[Union[Version, str]] = None,
|
|
35
|
+
|
|
36
|
+
keywords: Optional[List[str]] = None,
|
|
37
|
+
dependencies: Optional[List[Union[str, Dependency]]] = None,
|
|
38
|
+
demo: bool = False,
|
|
39
|
+
|
|
40
|
+
config: Optional[Any] = None,
|
|
41
|
+
) -> None:
|
|
42
|
+
"""The main function for publishing a package. It performs all necessary steps to prepare and publish the package.
|
|
43
|
+
|
|
44
|
+
:param name: The name of the package.
|
|
45
|
+
:param author: The name of the author.
|
|
46
|
+
:param author_email: The email of the author.
|
|
47
|
+
:param description: A short description of the package.
|
|
48
|
+
:param homepage: The homepage URL for the package (e.g., GitHub repository).
|
|
49
|
+
:param quality_assurance_strategies: Strategies for quality assurance.
|
|
50
|
+
:param build_strategies: Strategies for building the package.
|
|
51
|
+
:param upload_strategies: Strategies for uploading the package.
|
|
52
|
+
:param python_version_manager_strategy: Strategy for managing Python versions. Defaults to SystemInterpreter().
|
|
53
|
+
:param explicit_src_folder_path: The path to the source code of the package. Defaults to the current working directory/<name>.
|
|
54
|
+
:param version: The version for the new distribution. Defaults to "0.0.1".
|
|
55
|
+
:param readme_file_path: The path to the README file. Defaults to "./README.md".
|
|
56
|
+
:param license_file_path: The path to the license file. Defaults to "./LICENSE".
|
|
57
|
+
:param min_python: The minimum Python version required for the package. Defaults to the Python version running this script.
|
|
58
|
+
:param keywords: A list of keywords describing areas of interest for the package. Defaults to None.
|
|
59
|
+
:param dependencies: A list of dependencies for the package. Defaults to None.
|
|
60
|
+
:param demo: Whether to perform checks without making any changes. Defaults to False.
|
|
61
|
+
:param config: Reserved for future use. Defaults to None.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
None
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
enforce_pypirc_exists()
|
|
68
|
+
explicit_src_folder_path = validate_source(name, explicit_src_folder_path)
|
|
69
|
+
if explicit_src_folder_path != f"./{name}":
|
|
70
|
+
warning(
|
|
71
|
+
"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
|
+
min_python = validate_python_version(min_python) # type:ignore
|
|
78
|
+
keywords = validate_keywords(keywords)
|
|
79
|
+
validated_dependencies: List[Dependency] = validate_dependencies(dependencies)
|
|
80
|
+
enforce_remote_correct_version(name, version)
|
|
81
|
+
|
|
82
|
+
if quality_assurance_strategies is None:
|
|
83
|
+
quality_assurance_strategies = []
|
|
84
|
+
try:
|
|
85
|
+
res = qa(
|
|
86
|
+
python_version_manager_strategy,
|
|
87
|
+
quality_assurance_strategies,
|
|
88
|
+
name,
|
|
89
|
+
explicit_src_folder_path,
|
|
90
|
+
validated_dependencies
|
|
91
|
+
)
|
|
92
|
+
if not res:
|
|
93
|
+
error(f"quickpub.publish exited early as '{name}' "
|
|
94
|
+
"did not pass quality assurance step, see above "
|
|
95
|
+
"logs to pass this step.")
|
|
96
|
+
raise SystemExit(1)
|
|
97
|
+
except SystemExit as e:
|
|
98
|
+
raise e
|
|
99
|
+
except Exception as e:
|
|
100
|
+
raise RuntimeError("Quality assurance stage has failed") from e
|
|
101
|
+
|
|
102
|
+
create_setup()
|
|
103
|
+
create_toml(
|
|
104
|
+
name=name,
|
|
105
|
+
src_folder_path=explicit_src_folder_path,
|
|
106
|
+
readme_file_path=readme_file_path,
|
|
107
|
+
license_file_path=license_file_path,
|
|
108
|
+
version=version,
|
|
109
|
+
author=author,
|
|
110
|
+
author_email=author_email,
|
|
111
|
+
description=description,
|
|
112
|
+
homepage=homepage,
|
|
113
|
+
keywords=keywords,
|
|
114
|
+
dependencies=validated_dependencies,
|
|
115
|
+
classifiers=[
|
|
116
|
+
DevelopmentStatusClassifier.Alpha,
|
|
117
|
+
IntendedAudienceClassifier.Developers,
|
|
118
|
+
ProgrammingLanguageClassifier.Python3,
|
|
119
|
+
OperatingSystemClassifier.MicrosoftWindows
|
|
120
|
+
],
|
|
121
|
+
min_python=min_python
|
|
122
|
+
)
|
|
123
|
+
create_manifest(name=name)
|
|
124
|
+
if not demo:
|
|
125
|
+
for build_strategy in build_strategies:
|
|
126
|
+
build_strategy.execute_strategy()
|
|
127
|
+
for upload_strategy in upload_strategies:
|
|
128
|
+
upload_strategy.execute_strategy(name=name, version=version)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def parse_args():
|
|
132
|
+
parser = argparse.ArgumentParser(description="Publish a package")
|
|
133
|
+
|
|
134
|
+
parser.add_argument('--name', required=True, type=str, help='Name of the package')
|
|
135
|
+
parser.add_argument('--author', required=True, type=str, help='Author of the package')
|
|
136
|
+
parser.add_argument('--author_email', required=True, type=str, help='Email of the author')
|
|
137
|
+
parser.add_argument('--description', required=True, type=str, help='Description of the package')
|
|
138
|
+
parser.add_argument('--homepage', required=True, type=str, help='Homepage of the package')
|
|
139
|
+
parser.add_argument('--explicit_src_folder_path', type=str, help='Explicit source folder path')
|
|
140
|
+
parser.add_argument('--version', type=str, help='Version of the package')
|
|
141
|
+
parser.add_argument('--readme_file_path', type=str, default='./README.md', help='Path to the README file')
|
|
142
|
+
parser.add_argument('--license_file_path', type=str, default='./LICENSE', help='Path to the LICENSE file')
|
|
143
|
+
parser.add_argument('--min_python', type=str, help='Minimum Python version required')
|
|
144
|
+
parser.add_argument('--keywords', nargs='*', help='Keywords for the package')
|
|
145
|
+
parser.add_argument('--dependencies', nargs='*', help='Dependencies of the package')
|
|
146
|
+
parser.add_argument('--config', help='Additional configuration for the package')
|
|
147
|
+
|
|
148
|
+
return parser.parse_args()
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
if __name__ == '__main__':
|
|
152
|
+
print("CLI is not currently supported")
|
|
153
|
+
# args = parse_args()
|
|
154
|
+
#
|
|
155
|
+
# publish(
|
|
156
|
+
# name=args.name,
|
|
157
|
+
# author=args.author,
|
|
158
|
+
# author_email=args.author_email,
|
|
159
|
+
# description=args.description,
|
|
160
|
+
# homepage=args.homepage,
|
|
161
|
+
# explicit_src_folder_path=args.explicit_src_folder_path,
|
|
162
|
+
# version=args.version,
|
|
163
|
+
# readme_file_path=args.readme_file_path,
|
|
164
|
+
# license_file_path=args.license_file_path,
|
|
165
|
+
# min_python=args.min_python,
|
|
166
|
+
# keywords=args.keywords,
|
|
167
|
+
# dependencies=args.dependencies,
|
|
168
|
+
# config=args.config
|
|
169
|
+
# )
|
|
@@ -21,7 +21,7 @@ def _remove_suffix(s: str, suffix: str) -> str:
|
|
|
21
21
|
:return: modified string
|
|
22
22
|
"""
|
|
23
23
|
if get_python_version() >= (3, 9):
|
|
24
|
-
return s.removesuffix(suffix)
|
|
24
|
+
return s.removesuffix(suffix) # type:ignore
|
|
25
25
|
return _remove_prefix(s[::-1], suffix[::-1])[::-1]
|
|
26
26
|
|
|
27
27
|
|
|
@@ -33,7 +33,7 @@ def _remove_prefix(s: str, prefix: str) -> str:
|
|
|
33
33
|
:return:
|
|
34
34
|
"""
|
|
35
35
|
if get_python_version() >= (3, 9):
|
|
36
|
-
return s.removeprefix(prefix)
|
|
36
|
+
return s.removeprefix(prefix) # type:ignore
|
|
37
37
|
|
|
38
38
|
if s.startswith(prefix):
|
|
39
39
|
return s[len(prefix):]
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from typing import List
|
|
2
2
|
from danielutils import get_files
|
|
3
|
+
|
|
3
4
|
from .classifiers import Classifier
|
|
4
|
-
from .structures import Version
|
|
5
|
+
from .structures import Version, Dependency
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
def create_toml(
|
|
@@ -17,7 +18,7 @@ def create_toml(
|
|
|
17
18
|
homepage: str,
|
|
18
19
|
keywords: List[str],
|
|
19
20
|
min_python: Version,
|
|
20
|
-
dependencies: List[
|
|
21
|
+
dependencies: List[Dependency],
|
|
21
22
|
classifiers: List[Classifier]
|
|
22
23
|
) -> None:
|
|
23
24
|
classifiers_string = ",\n\t".join([f"\"{str(c)}\"" for c in classifiers])
|
|
@@ -40,7 +41,7 @@ version = "{version}"
|
|
|
40
41
|
authors = [
|
|
41
42
|
{{ name = "{author}", email = "{author_email}" }},
|
|
42
43
|
]
|
|
43
|
-
dependencies = {dependencies}
|
|
44
|
+
dependencies = {[str(dep) for dep in dependencies]}
|
|
44
45
|
keywords = {keywords}
|
|
45
46
|
license = {{ "file" = "{license_file_path}" }}
|
|
46
47
|
description = "{description}"
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from typing import Optional, Literal
|
|
3
|
+
from danielutils import info
|
|
4
|
+
|
|
5
|
+
from .enforcers import exit_if
|
|
6
|
+
from .structures import Version
|
|
7
|
+
import quickpub.proxy
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def build(
|
|
11
|
+
*,
|
|
12
|
+
verbose: bool = True
|
|
13
|
+
) -> None:
|
|
14
|
+
if verbose:
|
|
15
|
+
info("Creating new distribution...")
|
|
16
|
+
ret, stdout, stderr = quickpub.proxy.cm("python", "setup.py", "sdist")
|
|
17
|
+
exit_if(
|
|
18
|
+
ret != 0,
|
|
19
|
+
stderr.decode(encoding="utf8")
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def upload(
|
|
24
|
+
*,
|
|
25
|
+
name: str,
|
|
26
|
+
version: Version,
|
|
27
|
+
verbose: bool = True
|
|
28
|
+
) -> None:
|
|
29
|
+
if verbose:
|
|
30
|
+
info("Uploading")
|
|
31
|
+
ret, stdout, stderr = quickpub.proxy.cm("twine", "upload", "--config-file", ".pypirc",
|
|
32
|
+
f"dist/{name}-{version}.tar.gz")
|
|
33
|
+
exit_if(
|
|
34
|
+
ret != 0,
|
|
35
|
+
f"Failed uploading the package to pypi. Try running the following command manually:\n\ttwine upload --config-file .pypirc dist/{name}-{version}.tar.gz"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def commit(
|
|
40
|
+
*,
|
|
41
|
+
version: Version,
|
|
42
|
+
verbose: bool = True
|
|
43
|
+
) -> None:
|
|
44
|
+
if verbose:
|
|
45
|
+
info("Git")
|
|
46
|
+
info("\tStaging")
|
|
47
|
+
ret, stdout, stderr = quickpub.proxy.cm("git add .")
|
|
48
|
+
exit_if(
|
|
49
|
+
ret != 0,
|
|
50
|
+
stderr.decode(encoding="utf8")
|
|
51
|
+
)
|
|
52
|
+
if verbose:
|
|
53
|
+
info("\tCommitting")
|
|
54
|
+
ret, stdout, stderr = quickpub.proxy.cm(f"git commit -m \"updated to version {version}\"")
|
|
55
|
+
exit_if(
|
|
56
|
+
ret != 0,
|
|
57
|
+
stderr.decode(encoding="utf8")
|
|
58
|
+
)
|
|
59
|
+
if verbose:
|
|
60
|
+
info("\tPushing")
|
|
61
|
+
ret, stdout, stderr = quickpub.proxy.cm("git push")
|
|
62
|
+
exit_if(
|
|
63
|
+
ret != 0,
|
|
64
|
+
stderr.decode(encoding="utf8")
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
__all__ = [
|
|
69
|
+
"build",
|
|
70
|
+
"upload",
|
|
71
|
+
"commit",
|
|
72
|
+
]
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
+
import re
|
|
1
2
|
import sys
|
|
2
3
|
from functools import wraps
|
|
3
|
-
from typing import Optional, ContextManager, List, Callable
|
|
4
|
+
from typing import Optional, ContextManager, List, Callable, Tuple, Dict, Union
|
|
4
5
|
from danielutils import AttrContext, LayeredCommand, AsciiProgressBar, ColoredText, ProgressBarPool, TemporaryFile
|
|
5
6
|
|
|
6
|
-
from
|
|
7
|
-
from .
|
|
7
|
+
from quickpub import QualityAssuranceStrategy
|
|
8
|
+
from .strategies import PythonVersionManagerStrategy # pylint: disable=relative-beyond-top-level
|
|
9
|
+
from .structures import Dependency, Version, Bound # pylint: disable=relative-beyond-top-level
|
|
8
10
|
from .enforcers import exit_if # pylint: disable=relative-beyond-top-level
|
|
9
11
|
|
|
10
12
|
try:
|
|
11
13
|
from danielutils import MultiContext # type:ignore
|
|
12
14
|
except ImportError:
|
|
13
|
-
class MultiContext(ContextManager): # pylint: disable=missing-class-docstring
|
|
15
|
+
class MultiContext(ContextManager): # type: ignore # pylint: disable=missing-class-docstring
|
|
14
16
|
def __init__(self, *contexts: ContextManager):
|
|
15
17
|
self.contexts = contexts
|
|
16
18
|
|
|
@@ -49,12 +51,16 @@ def global_import_sanity_check(package_name: str, executor: LayeredCommand, is_s
|
|
|
49
51
|
verbose=True, err_func=err_print_func)
|
|
50
52
|
|
|
51
53
|
|
|
52
|
-
|
|
54
|
+
VERSION_REGEX: re.Pattern = re.compile(r"^\d+\.\d+\.\d+$")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def validate_dependencies(python_manager: PythonVersionManagerStrategy, required_dependencies: List[Dependency],
|
|
58
|
+
executor: LayeredCommand,
|
|
53
59
|
env_name: str, err_print_func: Callable) -> None:
|
|
54
60
|
"""
|
|
55
61
|
will check if all the dependencies of the package are installed on current env.
|
|
56
62
|
:param python_manager: the manager to use
|
|
57
|
-
:param
|
|
63
|
+
:param required_dependencies: the dependencies to check
|
|
58
64
|
:param executor: the current LayeredCommand executor
|
|
59
65
|
:param env_name: name of the currently checked environment
|
|
60
66
|
:param err_print_func: function to print errors
|
|
@@ -63,23 +69,46 @@ def validate_dependencies(python_manager: PythonManager, dependencies: List[str]
|
|
|
63
69
|
if python_manager.exit_on_fail:
|
|
64
70
|
code, out, err = executor("pip list")
|
|
65
71
|
exit_if(code != 0, f"Failed executing 'pip list' at env '{env_name}'", err_func=err_print_func)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
for
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
72
|
+
split_lines = (line.split(' ') for line in out[2:])
|
|
73
|
+
version_tuples = [(s[0], s[-1].strip()) for s in split_lines]
|
|
74
|
+
filtered_tuples = [t for t in version_tuples if VERSION_REGEX.match(t[1])]
|
|
75
|
+
currently_installed: Dict[str, Union[str, Dependency]] = {s[0]: Dependency(s[0], "==", Version.from_str(s[-1]))
|
|
76
|
+
for s in filtered_tuples}
|
|
77
|
+
currently_installed.update(**{t[0]: t[1] for t in version_tuples if not VERSION_REGEX.match(t[1])})
|
|
78
|
+
not_installed_properly: List[Tuple[Dependency, str]] = []
|
|
79
|
+
for req in required_dependencies:
|
|
80
|
+
if req.name not in currently_installed:
|
|
81
|
+
not_installed_properly.append((req, "dependency not found"))
|
|
82
|
+
else:
|
|
83
|
+
v = currently_installed[req.name]
|
|
84
|
+
if isinstance(v, str):
|
|
85
|
+
not_installed_properly.append(
|
|
86
|
+
(req, "Verion format of dependecy is not currently supported by quickpub"))
|
|
87
|
+
elif isinstance(v, Dependency):
|
|
88
|
+
if not req.is_satisfied_by(v.ver):
|
|
89
|
+
not_installed_properly.append((req, "rInvalid version installed"))
|
|
90
|
+
|
|
91
|
+
exit_if(bool(not_installed_properly),
|
|
92
|
+
f"On env '{env_name}' the following dependencies have problems: {(not_installed_properly)}",
|
|
73
93
|
err_func=err_print_func)
|
|
74
94
|
|
|
75
95
|
|
|
76
|
-
def create_progress_bar_pool(
|
|
96
|
+
def create_progress_bar_pool(python_version_manager: PythonVersionManagerStrategy,
|
|
97
|
+
quality_assurance_strategies: List[QualityAssuranceStrategy]) -> ProgressBarPool:
|
|
77
98
|
return ProgressBarPool(
|
|
78
99
|
AsciiProgressBar,
|
|
79
100
|
2,
|
|
80
101
|
individual_options=[
|
|
81
|
-
dict(
|
|
82
|
-
|
|
102
|
+
dict(
|
|
103
|
+
iterator=python_version_manager,
|
|
104
|
+
desc="Envs",
|
|
105
|
+
total=len(python_version_manager.requested_envs)
|
|
106
|
+
),
|
|
107
|
+
dict(
|
|
108
|
+
iterator=quality_assurance_strategies or [],
|
|
109
|
+
desc="Runners",
|
|
110
|
+
total=len(quality_assurance_strategies or [])
|
|
111
|
+
),
|
|
83
112
|
]
|
|
84
113
|
)
|
|
85
114
|
|
|
@@ -93,18 +122,19 @@ def create_pool_print_error(pool: ProgressBarPool):
|
|
|
93
122
|
return func
|
|
94
123
|
|
|
95
124
|
|
|
96
|
-
def qa(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
125
|
+
def qa(
|
|
126
|
+
python_version_manager: PythonVersionManagerStrategy,
|
|
127
|
+
quality_assurance_strategies: List[QualityAssuranceStrategy],
|
|
128
|
+
package_name: str,
|
|
129
|
+
src_folder_path: Optional[str],
|
|
130
|
+
dependencies: list
|
|
131
|
+
) -> bool:
|
|
132
|
+
from .strategies import SystemInterpreter
|
|
100
133
|
result = True
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
python_manager = SystemInterpreter()
|
|
106
|
-
is_system_interpreter = True
|
|
107
|
-
pool = create_progress_bar_pool(config, python_manager)
|
|
134
|
+
if python_version_manager is None:
|
|
135
|
+
python_version_manager = SystemInterpreter()
|
|
136
|
+
is_system_interpreter = isinstance(python_version_manager, SystemInterpreter)
|
|
137
|
+
pool = create_progress_bar_pool(python_version_manager, quality_assurance_strategies)
|
|
108
138
|
pool_err = create_pool_print_error(pool)
|
|
109
139
|
with MultiContext(
|
|
110
140
|
AttrContext(LayeredCommand, 'class_flush_stdout', False),
|
|
@@ -118,7 +148,7 @@ def qa(package_name: str, config: Optional[AdditionalConfiguration], src_folder_
|
|
|
118
148
|
with executor:
|
|
119
149
|
executor._prev_instance = base
|
|
120
150
|
try:
|
|
121
|
-
validate_dependencies(
|
|
151
|
+
validate_dependencies(python_version_manager, dependencies, executor, env_name, pool_err)
|
|
122
152
|
except SystemExit:
|
|
123
153
|
result = False
|
|
124
154
|
continue
|
|
@@ -135,7 +165,7 @@ def qa(package_name: str, config: Optional[AdditionalConfiguration], src_folder_
|
|
|
135
165
|
src_folder_path,
|
|
136
166
|
executor,
|
|
137
167
|
use_system_interpreter=is_system_interpreter,
|
|
138
|
-
raise_on_fail=
|
|
168
|
+
raise_on_fail=python_version_manager.exit_on_fail,
|
|
139
169
|
print_func=pool_err,
|
|
140
170
|
env_name=env_name
|
|
141
171
|
)
|
|
@@ -149,8 +179,8 @@ def qa(package_name: str, config: Optional[AdditionalConfiguration], src_folder_
|
|
|
149
179
|
f"Failed running '{runner.__class__.__name__}' on env '{env_name}'. "
|
|
150
180
|
f"Try manually: '{manual_command}'.")
|
|
151
181
|
pool.write(f"\tCaused by '{e.__cause__ or e}'")
|
|
152
|
-
if
|
|
153
|
-
raise e
|
|
182
|
+
if python_version_manager.exit_on_fail:
|
|
183
|
+
raise RuntimeError() from e
|
|
154
184
|
return result
|
|
155
185
|
|
|
156
186
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
|
|
3
|
+
from .quickpub_strategy import QuickpubStrategy
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class BuildStrategy(QuickpubStrategy):
|
|
7
|
+
def __init__(self, verbose: bool = True) -> None:
|
|
8
|
+
self.verbose = verbose
|
|
9
|
+
|
|
10
|
+
@abstractmethod
|
|
11
|
+
def execute_strategy(self, *args, **kwargs) -> None: ...
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"BuildStrategy"
|
|
16
|
+
]
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from .pypirc_upload_strategy import *
|
|
2
|
+
from .git_upload_strategy import *
|
|
3
|
+
from .setuptools_build_strategy import *
|
|
4
|
+
from .mypy_qa_strategy import *
|
|
5
|
+
from .pylint_qa_strategy import *
|
|
6
|
+
from .pytest_qa_strategy import *
|
|
7
|
+
from .unittest_qa_strategy import *
|
|
8
|
+
from .conda_python_version_manager_strategy import *
|
|
9
|
+
from .system_interpreter import *
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
from typing import Tuple, Optional, Set, Iterator
|
|
1
|
+
from typing import Tuple, Optional, Set, Iterator, List
|
|
2
2
|
from danielutils import LayeredCommand, warning
|
|
3
3
|
|
|
4
|
-
from ..
|
|
4
|
+
from ..python_version_manager_strategy import PythonVersionManagerStrategy
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
class
|
|
7
|
+
class CondaPythonVersionManagerStrategy(PythonVersionManagerStrategy):
|
|
8
8
|
def get_python_executable_name(self) -> str:
|
|
9
9
|
return "python"
|
|
10
10
|
|
|
11
|
-
def __init__(self, env_names:
|
|
12
|
-
|
|
11
|
+
def __init__(self, env_names: List[str]) -> None:
|
|
12
|
+
PythonVersionManagerStrategy.__init__(self, requested_envs=env_names, explicit_versions=[], exit_on_fail=True)
|
|
13
13
|
self._cached_available_envs: Optional[Set[str]] = None
|
|
14
14
|
|
|
15
15
|
def get_available_envs(self) -> Set[str]:
|
|
@@ -33,5 +33,5 @@ class CondaPythonManager(PythonManager):
|
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
__all__ = [
|
|
36
|
-
'
|
|
36
|
+
'CondaPythonVersionManagerStrategy',
|
|
37
37
|
]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from danielutils import info
|
|
2
|
+
|
|
3
|
+
from ..upload_strategy import UploadStrategy
|
|
4
|
+
|
|
5
|
+
class GitUploadStrategy(UploadStrategy):
|
|
6
|
+
def execute_strategy(self, version: str, **kwargs) -> None:
|
|
7
|
+
from quickpub.proxy import cm
|
|
8
|
+
from quickpub.enforcers import exit_if
|
|
9
|
+
if self.verbose:
|
|
10
|
+
info("Git")
|
|
11
|
+
info("\tStaging")
|
|
12
|
+
ret, stdout, stderr = cm("git add .")
|
|
13
|
+
exit_if(ret != 0, stderr.decode(encoding="utf8"))
|
|
14
|
+
if self.verbose:
|
|
15
|
+
info("\tCommitting")
|
|
16
|
+
ret, stdout, stderr = cm(f"git commit -m \"updated to version {version}\"")
|
|
17
|
+
exit_if(ret != 0, stderr.decode(encoding="utf8"))
|
|
18
|
+
if self.verbose:
|
|
19
|
+
info("\tPushing")
|
|
20
|
+
ret, stdout, stderr = cm("git push")
|
|
21
|
+
exit_if(ret != 0, stderr.decode(encoding="utf8"))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"GitUploadStrategy",
|
|
26
|
+
]
|
|
@@ -3,10 +3,10 @@ from typing import Optional, List
|
|
|
3
3
|
|
|
4
4
|
from danielutils import LayeredCommand
|
|
5
5
|
|
|
6
|
-
from ..
|
|
6
|
+
from ..quality_assurance_strategy import QualityAssuranceStrategy
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class MypyRunner(
|
|
9
|
+
class MypyRunner(QualityAssuranceStrategy):
|
|
10
10
|
def _install_dependencies(self, base: LayeredCommand) -> None:
|
|
11
11
|
with base:
|
|
12
12
|
base("pip install pylint")
|
|
@@ -23,8 +23,8 @@ class MypyRunner(BaseRunner):
|
|
|
23
23
|
|
|
24
24
|
def __init__(self, bound: str = "<15", configuration_path: Optional[str] = None,
|
|
25
25
|
executable_path: Optional[str] = None) -> None:
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
QualityAssuranceStrategy.__init__(self, name="mypy", bound=bound, configuration_path=configuration_path,
|
|
27
|
+
executable_path=executable_path)
|
|
28
28
|
|
|
29
29
|
def _calculate_score(self, ret, lines: List[str], verbose: bool = False) -> float:
|
|
30
30
|
from ...enforcers import exit_if
|
|
@@ -32,7 +32,7 @@ class MypyRunner(BaseRunner):
|
|
|
32
32
|
if rating_line.startswith("Success"):
|
|
33
33
|
return 0.0
|
|
34
34
|
exit_if(not (m := self.RATING_PATTERN.match(rating_line)),
|
|
35
|
-
f"Failed running MyPy, got exit code {ret}. try running manually using
|
|
35
|
+
f"Failed running MyPy, got exit code {ret}. try running manually using: {self._build_command('TARGET')}",
|
|
36
36
|
verbose=verbose)
|
|
37
37
|
num_failed = float(m.group(1))
|
|
38
38
|
active_files = float(m.group(2))
|
|
@@ -3,10 +3,10 @@ from typing import Optional, List
|
|
|
3
3
|
|
|
4
4
|
from danielutils import LayeredCommand
|
|
5
5
|
|
|
6
|
-
from
|
|
6
|
+
from strategies.quality_assurance_strategy import QualityAssuranceStrategy
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class PylintRunner(
|
|
9
|
+
class PylintRunner(QualityAssuranceStrategy):
|
|
10
10
|
def _install_dependencies(self, base: LayeredCommand) -> None:
|
|
11
11
|
with base:
|
|
12
12
|
base("pip install pylint")
|
|
@@ -15,8 +15,8 @@ class PylintRunner(BaseRunner):
|
|
|
15
15
|
|
|
16
16
|
def __init__(self, bound: str = ">=0.8", configuration_path: Optional[str] = None,
|
|
17
17
|
executable_path: Optional[str] = None) -> None:
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
QualityAssuranceStrategy.__init__(self, name="pylint", bound=bound, configuration_path=configuration_path,
|
|
19
|
+
executable_path=executable_path)
|
|
20
20
|
|
|
21
21
|
def _build_command(self, target: str, use_system_interpreter: bool = False) -> str:
|
|
22
22
|
command: str = self.get_executable()
|
|
@@ -28,10 +28,13 @@ class PylintRunner(BaseRunner):
|
|
|
28
28
|
def _calculate_score(self, ret: int, lines: List[str], verbose: bool = False) -> float:
|
|
29
29
|
from ...enforcers import exit_if
|
|
30
30
|
if len(lines) == 1 and lines[0].endswith("No module named pylint"):
|
|
31
|
-
raise RuntimeError(
|
|
32
|
-
|
|
31
|
+
raise RuntimeError("No module named pylint found")
|
|
32
|
+
index = -2
|
|
33
|
+
if lines[-1] == '\x1b[0m':
|
|
34
|
+
index += -1
|
|
35
|
+
rating_line = lines[index]
|
|
33
36
|
m = self.RATING_PATTERN.match(rating_line)
|
|
34
|
-
msg = f"Failed running Pylint, got exit code {ret}. Try running manually using
|
|
37
|
+
msg = f"Failed running Pylint, got exit code {ret}. Try running manually using: {self._build_command('TARGET')}"
|
|
35
38
|
exit_if(not m, msg)
|
|
36
39
|
rating_string = m.group(1) # type:ignore
|
|
37
40
|
numerator, denominator = rating_string.split("/")
|