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.
Files changed (64) hide show
  1. {quickpub-1.0.2 → quickpub-2.0.0}/LICENSE +20 -20
  2. {quickpub-1.0.2/quickpub.egg-info → quickpub-2.0.0}/PKG-INFO +22 -14
  3. quickpub-2.0.0/README.md +40 -0
  4. {quickpub-1.0.2 → quickpub-2.0.0}/pyproject.toml +2 -2
  5. {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/__main__.py +26 -34
  6. {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/classifiers.py +16 -0
  7. quickpub-2.0.0/quickpub/enforcers.py +17 -0
  8. {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/proxy.py +1 -1
  9. {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/qa.py +13 -17
  10. quickpub-2.0.0/quickpub/strategies/__init__.py +7 -0
  11. quickpub-1.0.2/quickpub/strategies/upload_strategy.py → quickpub-2.0.0/quickpub/strategies/build_schema.py +4 -3
  12. quickpub-2.0.0/quickpub/strategies/constraint_enforcer.py +16 -0
  13. quickpub-2.0.0/quickpub/strategies/implementations/__init__.py +5 -0
  14. quickpub-2.0.0/quickpub/strategies/implementations/build_schemas/__init__.py +1 -0
  15. quickpub-2.0.0/quickpub/strategies/implementations/build_schemas/setuptools_build_schema.py +27 -0
  16. quickpub-2.0.0/quickpub/strategies/implementations/constraint_enforcers/__init__.py +5 -0
  17. quickpub-2.0.0/quickpub/strategies/implementations/constraint_enforcers/license_enforcer.py +17 -0
  18. quickpub-2.0.0/quickpub/strategies/implementations/constraint_enforcers/local_version_enforcer.py +58 -0
  19. quickpub-2.0.0/quickpub/strategies/implementations/constraint_enforcers/pypi_remote_version_enforcer.py +39 -0
  20. quickpub-2.0.0/quickpub/strategies/implementations/constraint_enforcers/pypirc_enforcer.py +29 -0
  21. quickpub-2.0.0/quickpub/strategies/implementations/constraint_enforcers/readme_enforcer.py +20 -0
  22. quickpub-2.0.0/quickpub/strategies/implementations/python_providers/__init__.py +2 -0
  23. 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
  24. quickpub-2.0.0/quickpub/strategies/implementations/python_providers/default_python_provider.py +26 -0
  25. quickpub-2.0.0/quickpub/strategies/implementations/quality_assurance_runners/__init__.py +4 -0
  26. 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
  27. 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
  28. quickpub-2.0.0/quickpub/strategies/implementations/quality_assurance_runners/pytest_qa_runner.py +96 -0
  29. quickpub-2.0.0/quickpub/strategies/implementations/quality_assurance_runners/unittest_qa_runner.py +59 -0
  30. quickpub-2.0.0/quickpub/strategies/implementations/upload_targets/__init__.py +2 -0
  31. 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
  32. 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
  33. quickpub-1.0.2/quickpub/strategies/python_version_manager_strategy.py → quickpub-2.0.0/quickpub/strategies/python_provider.py +14 -3
  34. quickpub-2.0.0/quickpub/strategies/quality_assurance_runner.py +167 -0
  35. {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/strategies/quickpub_strategy.py +3 -1
  36. quickpub-1.0.2/quickpub/strategies/build_strategy.py → quickpub-2.0.0/quickpub/strategies/upload_target.py +3 -3
  37. {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/structures/dependency.py +23 -17
  38. {quickpub-1.0.2 → quickpub-2.0.0/quickpub.egg-info}/PKG-INFO +22 -14
  39. quickpub-2.0.0/quickpub.egg-info/SOURCES.txt +51 -0
  40. quickpub-2.0.0/quickpub.egg-info/requires.txt +2 -0
  41. quickpub-1.0.2/README.md +0 -32
  42. quickpub-1.0.2/quickpub/enforcers.py +0 -84
  43. quickpub-1.0.2/quickpub/strategies/__init__.py +0 -6
  44. quickpub-1.0.2/quickpub/strategies/implementations/__init__.py +0 -9
  45. quickpub-1.0.2/quickpub/strategies/implementations/pytest_qa_strategy.py +0 -1
  46. quickpub-1.0.2/quickpub/strategies/implementations/setuptools_build_strategy.py +0 -21
  47. quickpub-1.0.2/quickpub/strategies/implementations/system_interpreter.py +0 -25
  48. quickpub-1.0.2/quickpub/strategies/implementations/unittest_qa_strategy.py +0 -57
  49. quickpub-1.0.2/quickpub/strategies/quality_assurance_strategy.py +0 -98
  50. quickpub-1.0.2/quickpub.egg-info/SOURCES.txt +0 -40
  51. quickpub-1.0.2/quickpub.egg-info/requires.txt +0 -1
  52. {quickpub-1.0.2 → quickpub-2.0.0}/MANIFEST.in +0 -0
  53. {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/__init__.py +0 -0
  54. {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/files.py +0 -0
  55. {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/functions.py +0 -0
  56. {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/py.typed +0 -0
  57. {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/structures/__init__.py +0 -0
  58. {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/structures/bound.py +0 -0
  59. {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/structures/version.py +0 -0
  60. {quickpub-1.0.2 → quickpub-2.0.0}/quickpub/validators.py +0 -0
  61. {quickpub-1.0.2 → quickpub-2.0.0}/quickpub.egg-info/dependency_links.txt +0 -0
  62. {quickpub-1.0.2 → quickpub-2.0.0}/quickpub.egg-info/top_level.txt +0 -0
  63. {quickpub-1.0.2 → quickpub-2.0.0}/setup.cfg +0 -0
  64. {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: 1.0.2
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 V0.8.3
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, AdditionalConfiguration, MypyRunner, PylintRunner, UnittestRunner
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.8.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
- dependencies=["twine", "danielutils"],
54
- min_python="3.9.19",
55
- config=AdditionalConfiguration(
56
- runners=[
57
- MypyRunner(bound="<15"),
58
- PylintRunner(bound=">=0.8"),
59
- UnittestRunner(bound=">=0.8"),
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
  ```
@@ -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 = "1.0.2"
7
+ version = "2.0.0"
8
8
  authors = [
9
9
  { name = "danielnachumdev", email = "danielnachumdev@gmail.com" },
10
10
  ]
11
- dependencies = ['danielutils>=0.9.90']
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 quickpub import SystemInterpreter
6
- from strategies import BuildStrategy, UploadStrategy, QualityAssuranceStrategy, PythonVersionManagerStrategy
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
- build_strategies: List[BuildStrategy],
25
- upload_strategies: List[UploadStrategy],
26
- quality_assurance_strategies: Optional[List[QualityAssuranceStrategy]] = None,
27
- python_version_manager_strategy: PythonVersionManagerStrategy = SystemInterpreter(),
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
- demo: bool = False,
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 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>.
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
- if quality_assurance_strategies is None:
83
- quality_assurance_strategies = []
73
+ for enforcer in enforcers or []:
74
+ enforcer.enforce(name=name, version=version, demo=demo)
75
+
84
76
  try:
85
77
  res = qa(
86
- python_version_manager_strategy,
87
- quality_assurance_strategies,
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 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)
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
+ ]
@@ -13,7 +13,7 @@ def os_system(command) -> int:
13
13
  return os.system(command)
14
14
 
15
15
 
16
- def get(*args, **kwargs):
16
+ def get(*args, **kwargs) -> requests.models.Response:
17
17
  return requests.get(*args, **kwargs)
18
18
 
19
19
 
@@ -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 quickpub import QualityAssuranceStrategy
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: PythonVersionManagerStrategy, required_dependencies: List[Dependency],
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, "rInvalid version installed"))
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: PythonVersionManagerStrategy,
97
- quality_assurance_strategies: List[QualityAssuranceStrategy]) -> ProgressBarPool:
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
- python_version_manager: PythonVersionManagerStrategy,
127
- quality_assurance_strategies: List[QualityAssuranceStrategy],
125
+ python_provider: PythonProvider,
126
+ quality_assurance_strategies: List[QualityAssuranceRunner],
128
127
  package_name: str,
129
- src_folder_path: Optional[str],
128
+ src_folder_path: str,
130
129
  dependencies: list
131
130
  ) -> bool:
132
- from .strategies import SystemInterpreter
131
+ from .strategies import DefaultPythonProvider
133
132
  result = True
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)
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(python_version_manager, dependencies, executor, env_name, pool_err)
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 python_version_manager.exit_on_fail:
178
+ if python_provider.exit_on_fail:
183
179
  raise RuntimeError() from e
184
180
  return result
185
181
 
@@ -0,0 +1,7 @@
1
+ from .implementations import *
2
+ from .upload_target import *
3
+ from .quality_assurance_runner import *
4
+ from .quickpub_strategy import *
5
+ from .build_schema import *
6
+ from .python_provider import *
7
+ from .constraint_enforcer import *
@@ -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 UploadStrategy(QuickpubStrategy):
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 execute_strategy(self, *args, **kwargs) -> None: ...
12
+ def build(self, *args, **kwargs) -> None: ...
12
13
 
13
14
 
14
15
  __all__ = [
15
- 'UploadStrategy',
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,5 @@
1
+ from .constraint_enforcers import *
2
+ from .build_schemas import *
3
+ from .quality_assurance_runners import *
4
+ from .upload_targets import *
5
+ from .python_providers import *
@@ -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,5 @@
1
+ from .local_version_enforcer import *
2
+ from .license_enforcer import *
3
+ from .pypi_remote_version_enforcer import *
4
+ from .pypirc_enforcer import *
5
+ from .readme_enforcer import *
@@ -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
+ ]
@@ -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
+ ]