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.
Files changed (55) hide show
  1. {quickpub-1.0.0/quickpub.egg-info → quickpub-1.0.2}/PKG-INFO +1 -1
  2. {quickpub-1.0.0 → quickpub-1.0.2}/pyproject.toml +2 -2
  3. {quickpub-1.0.0 → quickpub-1.0.2}/quickpub/__init__.py +1 -2
  4. quickpub-1.0.2/quickpub/__main__.py +169 -0
  5. {quickpub-1.0.0 → quickpub-1.0.2}/quickpub/enforcers.py +2 -2
  6. {quickpub-1.0.0 → quickpub-1.0.2}/quickpub/files.py +4 -3
  7. quickpub-1.0.2/quickpub/functions.py +72 -0
  8. {quickpub-1.0.0 → quickpub-1.0.2}/quickpub/qa.py +61 -31
  9. quickpub-1.0.2/quickpub/strategies/__init__.py +6 -0
  10. quickpub-1.0.2/quickpub/strategies/build_strategy.py +16 -0
  11. quickpub-1.0.2/quickpub/strategies/implementations/__init__.py +9 -0
  12. quickpub-1.0.0/quickpub/managers/implementations/conda.py → quickpub-1.0.2/quickpub/strategies/implementations/conda_python_version_manager_strategy.py +6 -6
  13. quickpub-1.0.2/quickpub/strategies/implementations/git_upload_strategy.py +26 -0
  14. quickpub-1.0.0/quickpub/runnables/implementations/mypy.py → quickpub-1.0.2/quickpub/strategies/implementations/mypy_qa_strategy.py +5 -5
  15. quickpub-1.0.0/quickpub/runnables/implementations/pylint.py → quickpub-1.0.2/quickpub/strategies/implementations/pylint_qa_strategy.py +10 -7
  16. quickpub-1.0.2/quickpub/strategies/implementations/pypirc_upload_strategy.py +44 -0
  17. quickpub-1.0.2/quickpub/strategies/implementations/pytest_qa_strategy.py +1 -0
  18. quickpub-1.0.2/quickpub/strategies/implementations/setuptools_build_strategy.py +21 -0
  19. {quickpub-1.0.0/quickpub/managers → quickpub-1.0.2/quickpub/strategies}/implementations/system_interpreter.py +3 -3
  20. quickpub-1.0.0/quickpub/runnables/implementations/unittest.py → quickpub-1.0.2/quickpub/strategies/implementations/unittest_qa_strategy.py +4 -4
  21. quickpub-1.0.0/quickpub/managers/python_manager.py → quickpub-1.0.2/quickpub/strategies/python_version_manager_strategy.py +7 -6
  22. quickpub-1.0.0/quickpub/runnables/base_runner.py → quickpub-1.0.2/quickpub/strategies/quality_assurance_strategy.py +45 -12
  23. quickpub-1.0.2/quickpub/strategies/quickpub_strategy.py +10 -0
  24. quickpub-1.0.2/quickpub/strategies/upload_strategy.py +16 -0
  25. {quickpub-1.0.0 → quickpub-1.0.2}/quickpub/structures/__init__.py +1 -1
  26. {quickpub-1.0.0 → quickpub-1.0.2}/quickpub/structures/bound.py +3 -2
  27. quickpub-1.0.2/quickpub/structures/dependency.py +47 -0
  28. {quickpub-1.0.0 → quickpub-1.0.2}/quickpub/structures/version.py +0 -1
  29. {quickpub-1.0.0 → quickpub-1.0.2}/quickpub/validators.py +10 -3
  30. {quickpub-1.0.0 → quickpub-1.0.2/quickpub.egg-info}/PKG-INFO +1 -1
  31. quickpub-1.0.2/quickpub.egg-info/SOURCES.txt +40 -0
  32. quickpub-1.0.2/quickpub.egg-info/requires.txt +1 -0
  33. quickpub-1.0.0/quickpub/__main__.py +0 -105
  34. quickpub-1.0.0/quickpub/functions.py +0 -209
  35. quickpub-1.0.0/quickpub/managers/__init__.py +0 -2
  36. quickpub-1.0.0/quickpub/managers/implementations/__init__.py +0 -2
  37. quickpub-1.0.0/quickpub/runnables/__init__.py +0 -2
  38. quickpub-1.0.0/quickpub/runnables/configurable.py +0 -20
  39. quickpub-1.0.0/quickpub/runnables/has_optional_executable.py +0 -32
  40. quickpub-1.0.0/quickpub/runnables/implementations/__init__.py +0 -4
  41. quickpub-1.0.0/quickpub/runnables/implementations/pytest.py +0 -2
  42. quickpub-1.0.0/quickpub/runnables/runnable.py +0 -11
  43. quickpub-1.0.0/quickpub/structures/additional_configuration.py +0 -15
  44. quickpub-1.0.0/quickpub.egg-info/SOURCES.txt +0 -39
  45. quickpub-1.0.0/quickpub.egg-info/requires.txt +0 -2
  46. {quickpub-1.0.0 → quickpub-1.0.2}/LICENSE +0 -0
  47. {quickpub-1.0.0 → quickpub-1.0.2}/MANIFEST.in +0 -0
  48. {quickpub-1.0.0 → quickpub-1.0.2}/README.md +0 -0
  49. {quickpub-1.0.0 → quickpub-1.0.2}/quickpub/classifiers.py +0 -0
  50. {quickpub-1.0.0 → quickpub-1.0.2}/quickpub/proxy.py +0 -0
  51. {quickpub-1.0.0 → quickpub-1.0.2}/quickpub/py.typed +0 -0
  52. {quickpub-1.0.0 → quickpub-1.0.2}/quickpub.egg-info/dependency_links.txt +0 -0
  53. {quickpub-1.0.0 → quickpub-1.0.2}/quickpub.egg-info/top_level.txt +0 -0
  54. {quickpub-1.0.0 → quickpub-1.0.2}/setup.cfg +0 -0
  55. {quickpub-1.0.0 → quickpub-1.0.2}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: quickpub
3
- Version: 1.0.0
3
+ Version: 1.0.2
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
@@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "quickpub"
7
- version = "1.0.0"
7
+ version = "1.0.2"
8
8
  authors = [
9
9
  { name = "danielnachumdev", email = "danielnachumdev@gmail.com" },
10
10
  ]
11
- dependencies = ['twine', 'danielutils']
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"
@@ -1,4 +1,3 @@
1
1
  from .structures import *
2
- from .runnables import *
3
- from .managers import *
2
+ from .strategies import *
4
3
  from .__main__ import publish
@@ -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[str],
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 .managers import PythonManager # pylint: disable=relative-beyond-top-level
7
- from .structures import AdditionalConfiguration # pylint: disable=relative-beyond-top-level
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 #type:ignore
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
- def validate_dependencies(python_manager: PythonManager, dependencies: List[str], executor: LayeredCommand,
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 dependencies: the dependencies to check
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
- installed = [line.split(' ')[0] for line in out[2:]]
67
- not_installed = []
68
- for dep in dependencies:
69
- if dep not in installed:
70
- not_installed.append(dep)
71
- exit_if(not (len(not_installed) == 0),
72
- f"On env '{env_name}' the following dependencies are not installed: {not_installed}",
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(config, python_manager) -> ProgressBarPool:
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(iterable=python_manager, desc="Envs", total=len(python_manager.requested_envs)),
82
- dict(iterable=config.runners or [], desc="Runners", total=len(config.runners or [])),
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(package_name: str, config: Optional[AdditionalConfiguration], src_folder_path: Optional[str],
97
- dependencies: list) -> bool:
98
- if config is None:
99
- return True
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
- python_manager = config.python_manager
102
- is_system_interpreter: bool = False
103
- if python_manager is None:
104
- from .managers import SystemInterpreter
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(python_manager, dependencies, executor, env_name, pool_err)
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=python_manager.exit_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 python_manager.exit_on_fail:
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,6 @@
1
+ from .implementations import *
2
+ from .upload_strategy import *
3
+ from .quality_assurance_strategy import *
4
+ from .quickpub_strategy import *
5
+ from .build_strategy import *
6
+ from .python_version_manager_strategy import *
@@ -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 ..python_manager import PythonManager
4
+ from ..python_version_manager_strategy import PythonVersionManagerStrategy
5
5
 
6
6
 
7
- class CondaPythonManager(PythonManager):
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: list[str]) -> None:
12
- PythonManager.__init__(self, requested_envs=env_names, explicit_versions=[])
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
- 'CondaPythonManager',
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 ..base_runner import BaseRunner
6
+ from ..quality_assurance_strategy import QualityAssuranceStrategy
7
7
 
8
8
 
9
- class MypyRunner(BaseRunner):
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
- BaseRunner.__init__(self, name="mypy", bound=bound, configuration_path=configuration_path,
27
- executable_path=executable_path)
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:\n\t{self._build_command('TARGET')}",
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 ..base_runner import BaseRunner
6
+ from strategies.quality_assurance_strategy import QualityAssuranceStrategy
7
7
 
8
8
 
9
- class PylintRunner(BaseRunner):
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
- BaseRunner.__init__(self, name="pylint", bound=bound, configuration_path=configuration_path,
19
- executable_path=executable_path)
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(f"No module named pylint found")
32
- rating_line = lines[-2]
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:\n\t{self._build_command('TARGET')}"
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("/")