quickpub 0.8.3__tar.gz → 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {quickpub-0.8.3/quickpub.egg-info → quickpub-1.0.0}/PKG-INFO +1 -1
- {quickpub-0.8.3 → quickpub-1.0.0}/pyproject.toml +1 -1
- {quickpub-0.8.3 → quickpub-1.0.0}/quickpub/__init__.py +1 -0
- {quickpub-0.8.3 → quickpub-1.0.0}/quickpub/__main__.py +25 -22
- {quickpub-0.8.3 → quickpub-1.0.0}/quickpub/enforcers.py +4 -5
- {quickpub-0.8.3 → quickpub-1.0.0}/quickpub/files.py +6 -7
- {quickpub-0.8.3 → quickpub-1.0.0}/quickpub/functions.py +0 -7
- quickpub-1.0.0/quickpub/managers/__init__.py +2 -0
- quickpub-1.0.0/quickpub/managers/implementations/__init__.py +2 -0
- quickpub-1.0.0/quickpub/managers/implementations/conda.py +37 -0
- quickpub-1.0.0/quickpub/managers/implementations/system_interpreter.py +25 -0
- quickpub-1.0.0/quickpub/managers/python_manager.py +30 -0
- {quickpub-0.8.3 → quickpub-1.0.0}/quickpub/proxy.py +8 -11
- quickpub-1.0.0/quickpub/qa.py +159 -0
- quickpub-1.0.0/quickpub/runnables/base_runner.py +65 -0
- {quickpub-0.8.3 → quickpub-1.0.0}/quickpub/runnables/has_optional_executable.py +9 -4
- quickpub-1.0.0/quickpub/runnables/implementations/mypy.py +45 -0
- quickpub-1.0.0/quickpub/runnables/implementations/pylint.py +43 -0
- quickpub-1.0.0/quickpub/runnables/implementations/pytest.py +2 -0
- {quickpub-0.8.3 → quickpub-1.0.0}/quickpub/runnables/implementations/unittest.py +13 -6
- {quickpub-0.8.3 → quickpub-1.0.0}/quickpub/structures/additional_configuration.py +3 -1
- {quickpub-0.8.3 → quickpub-1.0.0}/quickpub/structures/bound.py +6 -0
- {quickpub-0.8.3 → quickpub-1.0.0}/quickpub/structures/version.py +5 -1
- {quickpub-0.8.3 → quickpub-1.0.0}/quickpub/validators.py +4 -7
- {quickpub-0.8.3 → quickpub-1.0.0/quickpub.egg-info}/PKG-INFO +1 -1
- {quickpub-0.8.3 → quickpub-1.0.0}/quickpub.egg-info/SOURCES.txt +7 -2
- quickpub-0.8.3/quickpub/custom_types.py +0 -12
- quickpub-0.8.3/quickpub/runnables/common_check.py +0 -53
- quickpub-0.8.3/quickpub/runnables/implementations/mypy.py +0 -31
- quickpub-0.8.3/quickpub/runnables/implementations/pylint.py +0 -30
- quickpub-0.8.3/quickpub/runnables/implementations/pytest.py +0 -1
- {quickpub-0.8.3 → quickpub-1.0.0}/LICENSE +0 -0
- {quickpub-0.8.3 → quickpub-1.0.0}/MANIFEST.in +0 -0
- {quickpub-0.8.3 → quickpub-1.0.0}/README.md +0 -0
- {quickpub-0.8.3 → quickpub-1.0.0}/quickpub/classifiers.py +0 -0
- {quickpub-0.8.3 → quickpub-1.0.0}/quickpub/py.typed +0 -0
- {quickpub-0.8.3 → quickpub-1.0.0}/quickpub/runnables/__init__.py +0 -0
- {quickpub-0.8.3 → quickpub-1.0.0}/quickpub/runnables/configurable.py +0 -0
- {quickpub-0.8.3 → quickpub-1.0.0}/quickpub/runnables/implementations/__init__.py +0 -0
- {quickpub-0.8.3 → quickpub-1.0.0}/quickpub/runnables/runnable.py +0 -0
- {quickpub-0.8.3 → quickpub-1.0.0}/quickpub/structures/__init__.py +0 -0
- {quickpub-0.8.3 → quickpub-1.0.0}/quickpub.egg-info/dependency_links.txt +0 -0
- {quickpub-0.8.3 → quickpub-1.0.0}/quickpub.egg-info/requires.txt +0 -0
- {quickpub-0.8.3 → quickpub-1.0.0}/quickpub.egg-info/top_level.txt +0 -0
- {quickpub-0.8.3 → quickpub-1.0.0}/setup.cfg +0 -0
- {quickpub-0.8.3 → quickpub-1.0.0}/setup.py +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
from typing import Optional, Union, List
|
|
2
|
-
from danielutils import warning, file_exists
|
|
2
|
+
from danielutils import warning, file_exists, error
|
|
3
3
|
from .validators import validate_version, validate_python_version, validate_keywords, validate_dependencies, \
|
|
4
4
|
validate_source
|
|
5
|
-
from .functions import build, upload, commit
|
|
5
|
+
from .functions import build, upload, commit
|
|
6
6
|
from .structures import Version, AdditionalConfiguration
|
|
7
7
|
from .files import create_toml, create_setup, create_manifest
|
|
8
8
|
from .classifiers import *
|
|
9
9
|
from .enforcers import enforce_local_correct_version, enforce_pypirc_exists, exit_if, enforce_remote_correct_version
|
|
10
|
-
from .
|
|
10
|
+
from .qa import qa
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def publish(
|
|
@@ -17,10 +17,10 @@ def publish(
|
|
|
17
17
|
author_email: str,
|
|
18
18
|
description: str,
|
|
19
19
|
homepage: str,
|
|
20
|
-
|
|
20
|
+
explicit_src_folder_path: Optional[str] = None,
|
|
21
21
|
version: Optional[Union[Version, str]] = None,
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
readme_file_path: str = "./README.md",
|
|
23
|
+
license_file_path: str = "./LICENSE",
|
|
24
24
|
|
|
25
25
|
min_python: Optional[Union[Version, str]] = None,
|
|
26
26
|
|
|
@@ -36,23 +36,22 @@ def publish(
|
|
|
36
36
|
author_email (str): The email of the author
|
|
37
37
|
description (str): A short description for the package
|
|
38
38
|
homepage (str): The homepage for the package. URL to the github repo is a good option.
|
|
39
|
-
|
|
39
|
+
explicit_src_folder_path (Optional[Path], optional): The path to the source code of the package. if None defaults to CWD/<name>
|
|
40
40
|
version (Optional[Union[Version, str]], optional): The version to create the new distribution. if None defaults to 0.0.1
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
readme_file_path (Path, optional): The path to the readme file. Defaults to "./README.md".
|
|
42
|
+
license_file_path (Path, optional): The path to the license file . Defaults to "./LICENSE".
|
|
43
43
|
min_python (Optional[Union[Version, str]], optional): The minimum version of python required for this package to run. Defaults to the version of python running this script.
|
|
44
44
|
keywords (Optional[list[str]], optional): A list of keywords to describe areas of interests of this package. Defaults to None.
|
|
45
45
|
dependencies (Optional[list[str]], optional): A list of the dependencies for this package. Defaults to None.
|
|
46
46
|
config (Optional[Config], optional): reserved for future use. Defaults to None.
|
|
47
47
|
"""
|
|
48
48
|
enforce_pypirc_exists()
|
|
49
|
-
|
|
50
|
-
if
|
|
49
|
+
explicit_src_folder_path = validate_source(name, explicit_src_folder_path)
|
|
50
|
+
if explicit_src_folder_path != f"./{name}":
|
|
51
51
|
warning(
|
|
52
52
|
"The source folder's name is different from the package's name. this may not be currently supported correctly")
|
|
53
|
-
exit_if(not file_exists(
|
|
54
|
-
exit_if(not file_exists(license)
|
|
55
|
-
f"Could not find license file at {license}")
|
|
53
|
+
exit_if(not file_exists(readme_file_path), f"Could not find readme file at {readme_file_path}")
|
|
54
|
+
exit_if(not file_exists(license_file_path), f"Could not find license file at {license_file_path}")
|
|
56
55
|
version = validate_version(version)
|
|
57
56
|
enforce_local_correct_version(name, version)
|
|
58
57
|
min_python = validate_python_version(min_python) # type:ignore
|
|
@@ -60,17 +59,22 @@ def publish(
|
|
|
60
59
|
dependencies = validate_dependencies(dependencies)
|
|
61
60
|
enforce_remote_correct_version(name, version)
|
|
62
61
|
|
|
63
|
-
|
|
64
|
-
if config
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
try:
|
|
63
|
+
if not qa(name, config, explicit_src_folder_path, dependencies):
|
|
64
|
+
error(
|
|
65
|
+
f"quickpub.publish exited early as '{name}' did not pass quality assurance step, see above logs to pass this step.")
|
|
66
|
+
raise SystemExit(1)
|
|
67
|
+
except SystemExit as e:
|
|
68
|
+
raise e
|
|
69
|
+
except Exception as e:
|
|
70
|
+
raise RuntimeError("Quality assurance stage has failed") from e
|
|
67
71
|
|
|
68
72
|
create_setup()
|
|
69
73
|
create_toml(
|
|
70
74
|
name=name,
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
src_folder_path=explicit_src_folder_path,
|
|
76
|
+
readme_file_path=readme_file_path,
|
|
77
|
+
license_file_path=license_file_path,
|
|
74
78
|
version=version,
|
|
75
79
|
author=author,
|
|
76
80
|
author_email=author_email,
|
|
@@ -96,7 +100,6 @@ def publish(
|
|
|
96
100
|
commit(
|
|
97
101
|
version=version
|
|
98
102
|
)
|
|
99
|
-
metrics()
|
|
100
103
|
|
|
101
104
|
# if __name__ == '__main__':
|
|
102
105
|
# publish()
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
from typing import Union, Callable
|
|
3
3
|
|
|
4
|
-
import requests
|
|
5
|
-
# from bs4 import BeautifulSoup
|
|
6
4
|
from danielutils import directory_exists, get_files, error, file_exists, get_python_version
|
|
7
5
|
from .structures import Version
|
|
8
|
-
from .proxy import get
|
|
9
6
|
|
|
10
7
|
|
|
11
|
-
def exit_if(predicate: Union[bool, Callable[[], bool]], msg: str
|
|
8
|
+
def exit_if(predicate: Union[bool, Callable[[], bool]], msg: str, *, verbose: bool = True,
|
|
9
|
+
err_func: Callable[[str], None] = error) -> None:
|
|
12
10
|
if (isinstance(predicate, bool) and predicate) or (callable(predicate) and predicate()):
|
|
13
|
-
|
|
11
|
+
if verbose:
|
|
12
|
+
err_func(msg)
|
|
14
13
|
sys.exit(1)
|
|
15
14
|
|
|
16
15
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from typing import List
|
|
2
2
|
from danielutils import get_files
|
|
3
|
-
from .custom_types import Path
|
|
4
3
|
from .classifiers import Classifier
|
|
5
4
|
from .structures import Version
|
|
6
5
|
|
|
@@ -8,9 +7,9 @@ from .structures import Version
|
|
|
8
7
|
def create_toml(
|
|
9
8
|
*,
|
|
10
9
|
name: str,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
src_folder_path: str,
|
|
11
|
+
readme_file_path: str,
|
|
12
|
+
license_file_path: str,
|
|
14
13
|
version: Version,
|
|
15
14
|
author: str,
|
|
16
15
|
author_email: str,
|
|
@@ -25,7 +24,7 @@ def create_toml(
|
|
|
25
24
|
if len(classifiers_string) > 0:
|
|
26
25
|
classifiers_string = f"\n\t{classifiers_string}\n"
|
|
27
26
|
py_typed = ""
|
|
28
|
-
for file in get_files(
|
|
27
|
+
for file in get_files(src_folder_path):
|
|
29
28
|
if file == "py.typed":
|
|
30
29
|
py_typed = f"""[tool.setuptools.package-data]
|
|
31
30
|
"{name}" = ["py.typed"]"""
|
|
@@ -43,9 +42,9 @@ authors = [
|
|
|
43
42
|
]
|
|
44
43
|
dependencies = {dependencies}
|
|
45
44
|
keywords = {keywords}
|
|
46
|
-
license = {{ "file" = "{
|
|
45
|
+
license = {{ "file" = "{license_file_path}" }}
|
|
47
46
|
description = "{description}"
|
|
48
|
-
readme = {{file = "{
|
|
47
|
+
readme = {{file = "{readme_file_path}", content-type = "text/markdown"}}
|
|
49
48
|
requires-python = ">={min_python}"
|
|
50
49
|
classifiers = [{classifiers_string}]
|
|
51
50
|
|
|
@@ -7,8 +7,6 @@ from .structures import Version
|
|
|
7
7
|
import quickpub.proxy
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
10
|
def prev_main():
|
|
13
11
|
import re
|
|
14
12
|
from danielutils import cmrt, cm, read_file, get_files, directory_exists, create_directory # type:ignore
|
|
@@ -204,13 +202,8 @@ def commit(
|
|
|
204
202
|
)
|
|
205
203
|
|
|
206
204
|
|
|
207
|
-
def metrics(testing_client: Optional[Literal["pytest", "unitest"]] = None):
|
|
208
|
-
pass
|
|
209
|
-
|
|
210
|
-
|
|
211
205
|
__all__ = [
|
|
212
206
|
"build",
|
|
213
207
|
"upload",
|
|
214
208
|
"commit",
|
|
215
|
-
"metrics"
|
|
216
209
|
]
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from typing import Tuple, Optional, Set, Iterator
|
|
2
|
+
from danielutils import LayeredCommand, warning
|
|
3
|
+
|
|
4
|
+
from ..python_manager import PythonManager
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class CondaPythonManager(PythonManager):
|
|
8
|
+
def get_python_executable_name(self) -> str:
|
|
9
|
+
return "python"
|
|
10
|
+
|
|
11
|
+
def __init__(self, env_names: list[str]) -> None:
|
|
12
|
+
PythonManager.__init__(self, requested_envs=env_names, explicit_versions=[])
|
|
13
|
+
self._cached_available_envs: Optional[Set[str]] = None
|
|
14
|
+
|
|
15
|
+
def get_available_envs(self) -> Set[str]:
|
|
16
|
+
if self._cached_available_envs is not None:
|
|
17
|
+
return self._cached_available_envs
|
|
18
|
+
|
|
19
|
+
with LayeredCommand(instance_flush_stdout=False, instance_flush_stderr=False) as base:
|
|
20
|
+
code, out, err = base("conda env list")
|
|
21
|
+
res = set([line.split(' ')[0] for line in out[2:] if len(line.split(' ')) > 1])
|
|
22
|
+
|
|
23
|
+
self._cached_available_envs = res
|
|
24
|
+
return res
|
|
25
|
+
|
|
26
|
+
def __iter__(self) -> Iterator[Tuple[str, LayeredCommand]]:
|
|
27
|
+
available_envs = self.get_available_envs()
|
|
28
|
+
for name in self.requested_envs:
|
|
29
|
+
if name not in available_envs:
|
|
30
|
+
warning(f"Couldn't find env '{name}'")
|
|
31
|
+
continue
|
|
32
|
+
yield name, LayeredCommand(f"conda activate {name}")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
__all__ = [
|
|
36
|
+
'CondaPythonManager',
|
|
37
|
+
]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from typing import Set, Tuple, Iterator
|
|
3
|
+
|
|
4
|
+
from danielutils import LayeredCommand
|
|
5
|
+
|
|
6
|
+
from .. import PythonManager
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class SystemInterpreter(PythonManager):
|
|
10
|
+
def get_python_executable_name(self) -> str:
|
|
11
|
+
return sys.executable
|
|
12
|
+
|
|
13
|
+
def __init__(self) -> None:
|
|
14
|
+
PythonManager.__init__(self, requested_envs=["system"], explicit_versions=[], exit_on_fail=True)
|
|
15
|
+
|
|
16
|
+
def __iter__(self) -> Iterator[Tuple[str, LayeredCommand]]:
|
|
17
|
+
return iter([("system", LayeredCommand(""))])
|
|
18
|
+
|
|
19
|
+
def get_available_envs(self) -> Set[str]:
|
|
20
|
+
return set("system")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"SystemInterpreter",
|
|
25
|
+
]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Tuple, Set, Iterator
|
|
3
|
+
from danielutils import LayeredCommand
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class PythonManager(ABC):
|
|
7
|
+
def __init__(self, auto_install_dependencies: bool = True, *, requested_envs: list[str],
|
|
8
|
+
explicit_versions: list[str],
|
|
9
|
+
exit_on_fail: bool = False) -> None:
|
|
10
|
+
self.auto_install_dependencies = auto_install_dependencies
|
|
11
|
+
self.requested_envs = requested_envs
|
|
12
|
+
self.explicit_versions = explicit_versions
|
|
13
|
+
self.exit_on_fail = exit_on_fail
|
|
14
|
+
|
|
15
|
+
@abstractmethod
|
|
16
|
+
def __iter__(self) -> Iterator[Tuple[str, LayeredCommand]]: ...
|
|
17
|
+
|
|
18
|
+
@abstractmethod
|
|
19
|
+
def get_available_envs(self) -> Set[str]: ...
|
|
20
|
+
|
|
21
|
+
def __len__(self) -> int:
|
|
22
|
+
return len(self.requested_envs)
|
|
23
|
+
|
|
24
|
+
@abstractmethod
|
|
25
|
+
def get_python_executable_name(self) -> str: ...
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
'PythonManager'
|
|
30
|
+
]
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Tuple
|
|
1
3
|
import danielutils
|
|
2
4
|
import requests
|
|
3
|
-
from typing import Tuple
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
# need it like this for the testing
|
|
@@ -8,20 +9,16 @@ def cm(*args, **kwargs) -> Tuple[int, bytes, bytes]:
|
|
|
8
9
|
return danielutils.cm(*args, **kwargs)
|
|
9
10
|
|
|
10
11
|
|
|
11
|
-
def
|
|
12
|
-
return
|
|
12
|
+
def os_system(command) -> int:
|
|
13
|
+
return os.system(command)
|
|
13
14
|
|
|
14
15
|
|
|
15
|
-
def
|
|
16
|
-
|
|
17
|
-
if verbose:
|
|
18
|
-
return func(*args, **kwargs)
|
|
19
|
-
|
|
20
|
-
return wrapper
|
|
16
|
+
def get(*args, **kwargs):
|
|
17
|
+
return requests.get(*args, **kwargs)
|
|
21
18
|
|
|
22
19
|
|
|
23
20
|
__all__ = [
|
|
24
21
|
"cm",
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
'os_system',
|
|
23
|
+
"get"
|
|
27
24
|
]
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from functools import wraps
|
|
3
|
+
from typing import Optional, ContextManager, List, Callable
|
|
4
|
+
from danielutils import AttrContext, LayeredCommand, AsciiProgressBar, ColoredText, ProgressBarPool, TemporaryFile
|
|
5
|
+
|
|
6
|
+
from .managers import PythonManager # pylint: disable=relative-beyond-top-level
|
|
7
|
+
from .structures import AdditionalConfiguration # pylint: disable=relative-beyond-top-level
|
|
8
|
+
from .enforcers import exit_if # pylint: disable=relative-beyond-top-level
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
from danielutils import MultiContext # type:ignore
|
|
12
|
+
except ImportError:
|
|
13
|
+
class MultiContext(ContextManager): # pylint: disable=missing-class-docstring #type:ignore
|
|
14
|
+
def __init__(self, *contexts: ContextManager):
|
|
15
|
+
self.contexts = contexts
|
|
16
|
+
|
|
17
|
+
def __enter__(self):
|
|
18
|
+
for context in self.contexts:
|
|
19
|
+
context.__enter__()
|
|
20
|
+
return self
|
|
21
|
+
|
|
22
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
23
|
+
for context in self.contexts:
|
|
24
|
+
context.__exit__(exc_type, exc_val, exc_tb)
|
|
25
|
+
|
|
26
|
+
def __getitem__(self, index):
|
|
27
|
+
return self.contexts[index]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def global_import_sanity_check(package_name: str, executor: LayeredCommand, is_system_interpreter: bool,
|
|
31
|
+
env_name: str, err_print_func) -> None:
|
|
32
|
+
"""
|
|
33
|
+
Will check that importing from the package works as a sanity check.
|
|
34
|
+
:param package_name: Name of the package
|
|
35
|
+
:param executor: the previously ued LayeredCommand executor
|
|
36
|
+
:param is_system_interpreter: whether or not the system interpreter is used
|
|
37
|
+
:param env_name: The name of the currently tested environment
|
|
38
|
+
:param err_print_func: the function to print our errors
|
|
39
|
+
:return: None
|
|
40
|
+
"""
|
|
41
|
+
p = sys.executable if is_system_interpreter else "python"
|
|
42
|
+
file_name = "./__sanity_check_main.py"
|
|
43
|
+
with TemporaryFile(file_name) as f:
|
|
44
|
+
f.write([f"from {package_name} import *"])
|
|
45
|
+
code, _, _ = executor(f"{p} {file_name}")
|
|
46
|
+
exit_if(code != 0,
|
|
47
|
+
f"Env '{env_name}' failed sanity check. "
|
|
48
|
+
f"Try manually running the following script 'from {package_name} import *'",
|
|
49
|
+
verbose=True, err_func=err_print_func)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def validate_dependencies(python_manager: PythonManager, dependencies: List[str], executor: LayeredCommand,
|
|
53
|
+
env_name: str, err_print_func: Callable) -> None:
|
|
54
|
+
"""
|
|
55
|
+
will check if all the dependencies of the package are installed on current env.
|
|
56
|
+
:param python_manager: the manager to use
|
|
57
|
+
:param dependencies: the dependencies to check
|
|
58
|
+
:param executor: the current LayeredCommand executor
|
|
59
|
+
:param env_name: name of the currently checked environment
|
|
60
|
+
:param err_print_func: function to print errors
|
|
61
|
+
:return: None
|
|
62
|
+
"""
|
|
63
|
+
if python_manager.exit_on_fail:
|
|
64
|
+
code, out, err = executor("pip list")
|
|
65
|
+
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}",
|
|
73
|
+
err_func=err_print_func)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def create_progress_bar_pool(config, python_manager) -> ProgressBarPool:
|
|
77
|
+
return ProgressBarPool(
|
|
78
|
+
AsciiProgressBar,
|
|
79
|
+
2,
|
|
80
|
+
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 [])),
|
|
83
|
+
]
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def create_pool_print_error(pool: ProgressBarPool):
|
|
88
|
+
@wraps(pool.write)
|
|
89
|
+
def func(*args, **kwargs):
|
|
90
|
+
msg = "".join([ColoredText.red("ERROR"), ": ", *args])
|
|
91
|
+
pool.write(msg, **kwargs)
|
|
92
|
+
|
|
93
|
+
return func
|
|
94
|
+
|
|
95
|
+
|
|
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
|
|
100
|
+
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)
|
|
108
|
+
pool_err = create_pool_print_error(pool)
|
|
109
|
+
with MultiContext(
|
|
110
|
+
AttrContext(LayeredCommand, 'class_flush_stdout', False),
|
|
111
|
+
AttrContext(LayeredCommand, 'class_flush_stderr', False),
|
|
112
|
+
AttrContext(LayeredCommand, 'class_raise_on_fail', False),
|
|
113
|
+
base := LayeredCommand()
|
|
114
|
+
):
|
|
115
|
+
for env_name, executor in pool[0]:
|
|
116
|
+
pool[0].desc = f"Env '{env_name}'"
|
|
117
|
+
pool[0].update(0, refresh=True)
|
|
118
|
+
with executor:
|
|
119
|
+
executor._prev_instance = base
|
|
120
|
+
try:
|
|
121
|
+
validate_dependencies(python_manager, dependencies, executor, env_name, pool_err)
|
|
122
|
+
except SystemExit:
|
|
123
|
+
result = False
|
|
124
|
+
continue
|
|
125
|
+
try:
|
|
126
|
+
global_import_sanity_check(package_name, executor, is_system_interpreter, env_name, pool_err)
|
|
127
|
+
except SystemExit:
|
|
128
|
+
result = False
|
|
129
|
+
continue
|
|
130
|
+
for runner in pool[1]:
|
|
131
|
+
pool[1].desc = f"Runner '{runner.__class__.__name__}'"
|
|
132
|
+
pool[1].update(0, refresh=True)
|
|
133
|
+
try:
|
|
134
|
+
runner.run(
|
|
135
|
+
src_folder_path,
|
|
136
|
+
executor,
|
|
137
|
+
use_system_interpreter=is_system_interpreter,
|
|
138
|
+
raise_on_fail=python_manager.exit_on_fail,
|
|
139
|
+
print_func=pool_err,
|
|
140
|
+
env_name=env_name
|
|
141
|
+
)
|
|
142
|
+
except SystemExit:
|
|
143
|
+
result = False
|
|
144
|
+
continue
|
|
145
|
+
except Exception as e:
|
|
146
|
+
result = False
|
|
147
|
+
manual_command = executor._build_command(runner._build_command(src_folder_path))
|
|
148
|
+
pool_err(
|
|
149
|
+
f"Failed running '{runner.__class__.__name__}' on env '{env_name}'. "
|
|
150
|
+
f"Try manually: '{manual_command}'.")
|
|
151
|
+
pool.write(f"\tCaused by '{e.__cause__ or e}'")
|
|
152
|
+
if python_manager.exit_on_fail:
|
|
153
|
+
raise e
|
|
154
|
+
return result
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
__all__ = [
|
|
158
|
+
'qa'
|
|
159
|
+
]
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from typing import Optional, Union, List
|
|
3
|
+
|
|
4
|
+
from danielutils import LayeredCommand
|
|
5
|
+
|
|
6
|
+
from .has_optional_executable import HasOptionalExecutable
|
|
7
|
+
from .runnable import Runnable
|
|
8
|
+
from .configurable import Configurable
|
|
9
|
+
from ..structures import Bound
|
|
10
|
+
from ..proxy import os_system
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BaseRunner(Runnable, Configurable, HasOptionalExecutable):
|
|
14
|
+
|
|
15
|
+
def __init__(self, *, name: str, bound: Union[str, Bound], target: Optional[str] = None,
|
|
16
|
+
configuration_path: Optional[str] = None,
|
|
17
|
+
executable_path: Optional[str] = None, auto_install: bool = False) -> None:
|
|
18
|
+
Configurable.__init__(self, configuration_path)
|
|
19
|
+
HasOptionalExecutable.__init__(self, name, executable_path)
|
|
20
|
+
self.bound: Bound = bound if isinstance(bound, Bound) else Bound.from_string(bound)
|
|
21
|
+
self.target = target
|
|
22
|
+
|
|
23
|
+
@abstractmethod
|
|
24
|
+
def _build_command(self, target: str, use_system_interpreter: bool = False) -> str:
|
|
25
|
+
...
|
|
26
|
+
|
|
27
|
+
@abstractmethod
|
|
28
|
+
def _install_dependencies(self, base: LayeredCommand) -> None:
|
|
29
|
+
...
|
|
30
|
+
|
|
31
|
+
def _pre_command(self) -> None:
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
def _post_command(self) -> None:
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
def run(self, target: str, executor: LayeredCommand, *_, verbose: bool = True, # type: ignore
|
|
38
|
+
use_system_interpreter: bool = False, raise_on_fail: bool = False, print_func, env_name: str) -> None:
|
|
39
|
+
# =====================================
|
|
40
|
+
# IMPORTANT: need to explicitly override it here
|
|
41
|
+
executor._executor = os_system
|
|
42
|
+
# =====================================
|
|
43
|
+
command = self._build_command(target, use_system_interpreter)
|
|
44
|
+
self._pre_command()
|
|
45
|
+
try:
|
|
46
|
+
ret, out, err = executor(command, command_raise_on_fail=raise_on_fail)
|
|
47
|
+
score = self._calculate_score(ret, "".join(out + err).splitlines(), verbose=verbose)
|
|
48
|
+
from ..enforcers import exit_if
|
|
49
|
+
exit_if(not self.bound.compare_against(score),
|
|
50
|
+
f"On env '{env_name}' runner '{self.__class__.__name__}' failed to pass it's defined bound. Got a score of {score} but expected {self.bound}",
|
|
51
|
+
verbose=verbose, err_func=print_func)
|
|
52
|
+
except Exception as e:
|
|
53
|
+
raise RuntimeError(
|
|
54
|
+
f"On env {env_name}, failed to run {self.__class__.__name__}. Try running manually:\n{executor._build_command(command)}") from e
|
|
55
|
+
finally:
|
|
56
|
+
self._post_command()
|
|
57
|
+
|
|
58
|
+
@abstractmethod
|
|
59
|
+
def _calculate_score(self, ret: int, command_output: List[str], *, verbose: bool = False) -> float:
|
|
60
|
+
...
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
__all__ = [
|
|
64
|
+
"BaseRunner"
|
|
65
|
+
]
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import sys
|
|
2
|
+
from typing import Any, Protocol, Optional, cast
|
|
2
3
|
from danielutils import get_os, OSType, file_exists
|
|
3
4
|
|
|
4
5
|
|
|
@@ -16,10 +17,14 @@ class HasOptionalExecutable():
|
|
|
16
17
|
if not file_exists(self.executable_path):
|
|
17
18
|
raise FileNotFoundError(f"Executable not found {self.executable_path}")
|
|
18
19
|
|
|
19
|
-
def get_executable(self) -> str:
|
|
20
|
+
def get_executable(self, use_system_interpreter: bool = False) -> str:
|
|
20
21
|
if self.use_executable:
|
|
21
|
-
return self.executable_path
|
|
22
|
-
|
|
22
|
+
return cast(str, self.executable_path)
|
|
23
|
+
|
|
24
|
+
p = self.PYTHON
|
|
25
|
+
if use_system_interpreter:
|
|
26
|
+
p = sys.executable
|
|
27
|
+
return f"{p} -m {self.name}"
|
|
23
28
|
|
|
24
29
|
|
|
25
30
|
__all__ = [
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from typing import Optional, List
|
|
3
|
+
|
|
4
|
+
from danielutils import LayeredCommand
|
|
5
|
+
|
|
6
|
+
from ..base_runner import BaseRunner
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class MypyRunner(BaseRunner):
|
|
10
|
+
def _install_dependencies(self, base: LayeredCommand) -> None:
|
|
11
|
+
with base:
|
|
12
|
+
base("pip install pylint")
|
|
13
|
+
|
|
14
|
+
def _build_command(self, target: str, use_system_interpreter: bool = False) -> str:
|
|
15
|
+
command: str = self.get_executable(use_system_interpreter)
|
|
16
|
+
if self.has_config:
|
|
17
|
+
command += f" --config-file {self.config_path}"
|
|
18
|
+
command += f" {target}"
|
|
19
|
+
return command
|
|
20
|
+
|
|
21
|
+
RATING_PATTERN: re.Pattern = re.compile(
|
|
22
|
+
"Found (\d+(?:\.\d+)?) errors in (\d+(?:\.\d+)?) files \(checked (\d+(?:\.\d+)?) source files\)")
|
|
23
|
+
|
|
24
|
+
def __init__(self, bound: str = "<15", configuration_path: Optional[str] = None,
|
|
25
|
+
executable_path: Optional[str] = None) -> None:
|
|
26
|
+
BaseRunner.__init__(self, name="mypy", bound=bound, configuration_path=configuration_path,
|
|
27
|
+
executable_path=executable_path)
|
|
28
|
+
|
|
29
|
+
def _calculate_score(self, ret, lines: List[str], verbose: bool = False) -> float:
|
|
30
|
+
from ...enforcers import exit_if
|
|
31
|
+
rating_line = lines[-1]
|
|
32
|
+
if rating_line.startswith("Success"):
|
|
33
|
+
return 0.0
|
|
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')}",
|
|
36
|
+
verbose=verbose)
|
|
37
|
+
num_failed = float(m.group(1))
|
|
38
|
+
active_files = float(m.group(2))
|
|
39
|
+
total_files = float(m.group(3))
|
|
40
|
+
return num_failed
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
__all__ = [
|
|
44
|
+
'MypyRunner',
|
|
45
|
+
]
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from typing import Optional, List
|
|
3
|
+
|
|
4
|
+
from danielutils import LayeredCommand
|
|
5
|
+
|
|
6
|
+
from ..base_runner import BaseRunner
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class PylintRunner(BaseRunner):
|
|
10
|
+
def _install_dependencies(self, base: LayeredCommand) -> None:
|
|
11
|
+
with base:
|
|
12
|
+
base("pip install pylint")
|
|
13
|
+
|
|
14
|
+
RATING_PATTERN: re.Pattern = re.compile(r".*?([\d\.\/]+)")
|
|
15
|
+
|
|
16
|
+
def __init__(self, bound: str = ">=0.8", configuration_path: Optional[str] = None,
|
|
17
|
+
executable_path: Optional[str] = None) -> None:
|
|
18
|
+
BaseRunner.__init__(self, name="pylint", bound=bound, configuration_path=configuration_path,
|
|
19
|
+
executable_path=executable_path)
|
|
20
|
+
|
|
21
|
+
def _build_command(self, target: str, use_system_interpreter: bool = False) -> str:
|
|
22
|
+
command: str = self.get_executable()
|
|
23
|
+
if self.has_config:
|
|
24
|
+
command += f" --rcfile {self.config_path}"
|
|
25
|
+
command += f" {target}"
|
|
26
|
+
return command
|
|
27
|
+
|
|
28
|
+
def _calculate_score(self, ret: int, lines: List[str], verbose: bool = False) -> float:
|
|
29
|
+
from ...enforcers import exit_if
|
|
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]
|
|
33
|
+
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')}"
|
|
35
|
+
exit_if(not m, msg)
|
|
36
|
+
rating_string = m.group(1) # type:ignore
|
|
37
|
+
numerator, denominator = rating_string.split("/")
|
|
38
|
+
return float(numerator) / float(denominator)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
__all__ = [
|
|
42
|
+
"PylintRunner",
|
|
43
|
+
]
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import re
|
|
2
2
|
import os
|
|
3
3
|
from typing import Optional, List
|
|
4
|
-
from danielutils import get_current_working_directory, set_current_working_directory
|
|
5
|
-
from ..common_check import CommonCheck
|
|
4
|
+
from danielutils import get_current_working_directory, set_current_working_directory, LayeredCommand, warning
|
|
6
5
|
|
|
6
|
+
from ..base_runner import BaseRunner
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class UnittestRunner(BaseRunner):
|
|
10
|
+
def _install_dependencies(self, base: LayeredCommand) -> None:
|
|
11
|
+
return None
|
|
7
12
|
|
|
8
|
-
class UnittestRunner(CommonCheck):
|
|
9
13
|
def _pre_command(self):
|
|
10
14
|
self._cwd = get_current_working_directory()
|
|
15
|
+
if self.target is None:
|
|
16
|
+
self.target = ""
|
|
17
|
+
warning("This is not supposed to happen. See quickpub's UnitestRunner._pre_command")
|
|
11
18
|
set_current_working_directory(os.path.join(self._cwd, self.target))
|
|
12
19
|
|
|
13
20
|
def _post_command(self):
|
|
@@ -16,16 +23,16 @@ class UnittestRunner(CommonCheck):
|
|
|
16
23
|
RATING_PATTERN: re.Pattern = re.compile(r".*?([\d\.\/]+)")
|
|
17
24
|
|
|
18
25
|
def __init__(self, target: Optional[str] = "./tests", bound: str = ">=0.8") -> None:
|
|
19
|
-
|
|
26
|
+
BaseRunner.__init__(self, name="unittest", bound=bound, target=target)
|
|
20
27
|
self._cwd = ""
|
|
21
28
|
|
|
22
|
-
def _build_command(self, src: str, *args) -> str:
|
|
29
|
+
def _build_command(self, src: str, *args, use_system_interpreter: bool = False) -> str:
|
|
23
30
|
command: str = self.get_executable()
|
|
24
31
|
rel = os.path.relpath(src, self.target).removesuffix(src.lstrip("./\\"))
|
|
25
32
|
command += f" discover -s {rel}"
|
|
26
33
|
return command # f"cd {self.target}; {command}" # f"; cd {self.target}"
|
|
27
34
|
|
|
28
|
-
def _calculate_score(self, ret: int, lines: List[str]) -> float:
|
|
35
|
+
def _calculate_score(self, ret: int, lines: List[str], *, verbose: bool = False) -> float:
|
|
29
36
|
from ...enforcers import exit_if
|
|
30
37
|
num_tests_line = lines[-3]
|
|
31
38
|
num_failed_line = lines[-1] if lines[-1] != "OK" else "0"
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
2
|
from typing import Optional, List
|
|
3
3
|
from ..runnables import Runnable
|
|
4
|
+
from ..managers import PythonManager
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
@dataclass(frozen=True)
|
|
7
8
|
class AdditionalConfiguration:
|
|
8
|
-
|
|
9
|
+
python_manager: Optional[PythonManager] = None
|
|
10
|
+
runners: Optional[List[Runnable]] = None
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
__all__ = [
|
|
@@ -24,6 +24,12 @@ class Bound:
|
|
|
24
24
|
return Bound(op, float(splits[-1])) # type:ignore
|
|
25
25
|
raise ValueError("Invalid 'Bound' format")
|
|
26
26
|
|
|
27
|
+
def __str__(self) -> str:
|
|
28
|
+
return f"{self.operator}{self.value}"
|
|
29
|
+
|
|
30
|
+
def __repr__(self) -> str:
|
|
31
|
+
return f"{self.__class__.__name__}(operator='{self.operator}', value='{self.value}')"
|
|
32
|
+
|
|
27
33
|
|
|
28
34
|
__all__ = [
|
|
29
35
|
'Bound'
|
|
@@ -5,7 +5,11 @@ from dataclasses import dataclass
|
|
|
5
5
|
class Version:
|
|
6
6
|
@staticmethod
|
|
7
7
|
def from_str(version_str: str) -> "Version":
|
|
8
|
-
|
|
8
|
+
try:
|
|
9
|
+
return Version(*list(map(int, version_str.split("."))))
|
|
10
|
+
except Exception as e:
|
|
11
|
+
raise ValueError(f"Failed converting '{version_str}' to instance of 'Version' in 'Version.from_str") from e
|
|
12
|
+
|
|
9
13
|
|
|
10
14
|
major: int = 0
|
|
11
15
|
minor: int = 0
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
from typing import Optional, Union, List
|
|
2
2
|
|
|
3
3
|
from danielutils import get_python_version
|
|
4
|
-
from .custom_types import Path
|
|
5
4
|
from .structures import Version
|
|
6
5
|
|
|
7
6
|
|
|
8
|
-
def validate_version(version: Optional[Union[str, Version]]) -> Version:
|
|
7
|
+
def validate_version(version: Optional[Union[str, Version]] = None) -> Version:
|
|
9
8
|
if version is None:
|
|
10
|
-
|
|
11
|
-
else:
|
|
12
|
-
version: Version = version if isinstance(version, Version) else Version.from_str(version) # type: ignore
|
|
13
|
-
return version
|
|
9
|
+
return Version(0, 0, 1)
|
|
10
|
+
return version if isinstance(version, Version) else Version.from_str(version) # type: ignore
|
|
14
11
|
|
|
15
12
|
|
|
16
13
|
def validate_python_version(min_python: Optional[Version]) -> Version:
|
|
@@ -31,7 +28,7 @@ def validate_dependencies(dependencies: Optional[List[str]]) -> List[str]:
|
|
|
31
28
|
return dependencies
|
|
32
29
|
|
|
33
30
|
|
|
34
|
-
def validate_source(name: str, src: Optional[
|
|
31
|
+
def validate_source(name: str, src: Optional[str] = None) -> str:
|
|
35
32
|
if src is not None:
|
|
36
33
|
return src
|
|
37
34
|
return f"./{name}"
|
|
@@ -6,20 +6,25 @@ setup.py
|
|
|
6
6
|
quickpub/__init__.py
|
|
7
7
|
quickpub/__main__.py
|
|
8
8
|
quickpub/classifiers.py
|
|
9
|
-
quickpub/custom_types.py
|
|
10
9
|
quickpub/enforcers.py
|
|
11
10
|
quickpub/files.py
|
|
12
11
|
quickpub/functions.py
|
|
13
12
|
quickpub/proxy.py
|
|
14
13
|
quickpub/py.typed
|
|
14
|
+
quickpub/qa.py
|
|
15
15
|
quickpub/validators.py
|
|
16
16
|
quickpub.egg-info/PKG-INFO
|
|
17
17
|
quickpub.egg-info/SOURCES.txt
|
|
18
18
|
quickpub.egg-info/dependency_links.txt
|
|
19
19
|
quickpub.egg-info/requires.txt
|
|
20
20
|
quickpub.egg-info/top_level.txt
|
|
21
|
+
quickpub/managers/__init__.py
|
|
22
|
+
quickpub/managers/python_manager.py
|
|
23
|
+
quickpub/managers/implementations/__init__.py
|
|
24
|
+
quickpub/managers/implementations/conda.py
|
|
25
|
+
quickpub/managers/implementations/system_interpreter.py
|
|
21
26
|
quickpub/runnables/__init__.py
|
|
22
|
-
quickpub/runnables/
|
|
27
|
+
quickpub/runnables/base_runner.py
|
|
23
28
|
quickpub/runnables/configurable.py
|
|
24
29
|
quickpub/runnables/has_optional_executable.py
|
|
25
30
|
quickpub/runnables/runnable.py
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
from abc import abstractmethod
|
|
2
|
-
from typing import Optional, Union, List
|
|
3
|
-
|
|
4
|
-
from danielutils import cm, info
|
|
5
|
-
|
|
6
|
-
from .has_optional_executable import HasOptionalExecutable
|
|
7
|
-
from .runnable import Runnable
|
|
8
|
-
from .configurable import Configurable
|
|
9
|
-
from ..structures import Bound
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class CommonCheck(Runnable, Configurable, HasOptionalExecutable):
|
|
13
|
-
|
|
14
|
-
def __init__(self, name: str, bound: Union[str, Bound], target: Optional[str] = None,
|
|
15
|
-
configuration_path: Optional[str] = None,
|
|
16
|
-
executable_path: Optional[str] = None) -> None:
|
|
17
|
-
Configurable.__init__(self, configuration_path)
|
|
18
|
-
HasOptionalExecutable.__init__(self, name, executable_path)
|
|
19
|
-
self.bound: Bound = bound if isinstance(bound, Bound) else Bound.from_string(bound)
|
|
20
|
-
self.target = target
|
|
21
|
-
|
|
22
|
-
@abstractmethod
|
|
23
|
-
def _build_command(self, target: str) -> str:
|
|
24
|
-
...
|
|
25
|
-
|
|
26
|
-
def _pre_command(self):
|
|
27
|
-
pass
|
|
28
|
-
|
|
29
|
-
def _post_command(self):
|
|
30
|
-
pass
|
|
31
|
-
|
|
32
|
-
def run(self, target: str, *_) -> None:
|
|
33
|
-
command = self._build_command(target)
|
|
34
|
-
info(f"Running {self.name}")
|
|
35
|
-
self._pre_command()
|
|
36
|
-
try:
|
|
37
|
-
ret, out, err = cm(command)
|
|
38
|
-
score = self._calculate_score(ret, b"".join([out, err]).decode("utf-8").splitlines())
|
|
39
|
-
from ..enforcers import exit_if
|
|
40
|
-
exit_if(not self.bound.compare_against(score), f"{self.name} failed to pass it's defined bound")
|
|
41
|
-
except Exception as e:
|
|
42
|
-
raise RuntimeError(f"Failed to run {self.name}, try running manually:\n{self._build_command('TARGET')}") from e
|
|
43
|
-
finally:
|
|
44
|
-
self._post_command()
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
@abstractmethod
|
|
48
|
-
def _calculate_score(self, ret: int, command_output: List[str]) -> float: ...
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
__all__ = [
|
|
52
|
-
"CommonCheck"
|
|
53
|
-
]
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import re
|
|
2
|
-
from typing import Optional, List
|
|
3
|
-
from ..common_check import CommonCheck
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class MypyRunner(CommonCheck):
|
|
7
|
-
def _build_command(self, target: str) -> str:
|
|
8
|
-
command: str = self.get_executable()
|
|
9
|
-
if self.has_config:
|
|
10
|
-
command += f" --config-file {self.config_path}"
|
|
11
|
-
command += f" {target}"
|
|
12
|
-
return command
|
|
13
|
-
|
|
14
|
-
RATING_PATTERN: re.Pattern = re.compile(r".*?([\d\.\/]+)")
|
|
15
|
-
|
|
16
|
-
def __init__(self, bound: str = "<15", configuration_path: Optional[str] = None,
|
|
17
|
-
executable_path: Optional[str] = None) -> None:
|
|
18
|
-
CommonCheck.__init__(self, "mypy", bound, configuration_path, executable_path)
|
|
19
|
-
|
|
20
|
-
def _calculate_score(self, ret, lines: List[str]) -> float:
|
|
21
|
-
from ...enforcers import exit_if
|
|
22
|
-
rating_line = lines[-1]
|
|
23
|
-
exit_if(not (m := self.RATING_PATTERN.match(rating_line)),
|
|
24
|
-
f"Failed running MyPy, got exit code {ret}. try running manually using:\n\t{self._build_command('TARGE')}")
|
|
25
|
-
rating_string = m.group(1)
|
|
26
|
-
return float(rating_string)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
__all__ = [
|
|
30
|
-
'MypyRunner',
|
|
31
|
-
]
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import re
|
|
2
|
-
from typing import Optional, List
|
|
3
|
-
from ..common_check import CommonCheck
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class PylintRunner(CommonCheck):
|
|
7
|
-
RATING_PATTERN: re.Pattern = re.compile(r".*?([\d\.\/]+)")
|
|
8
|
-
def __init__(self, bound: str = ">=0.8", configuration_path: Optional[str] = None,
|
|
9
|
-
executable_path: Optional[str] = None) -> None:
|
|
10
|
-
CommonCheck.__init__(self, "pylint", bound, configuration_path, executable_path)
|
|
11
|
-
|
|
12
|
-
def _build_command(self, target: str) -> str:
|
|
13
|
-
command: str = self.get_executable()
|
|
14
|
-
if self.has_config:
|
|
15
|
-
command += f" --rcfile {self.config_path}"
|
|
16
|
-
command += f" {target}"
|
|
17
|
-
return command
|
|
18
|
-
def _calculate_score(self, ret: int, lines: List[str]) -> float:
|
|
19
|
-
from ...enforcers import exit_if
|
|
20
|
-
rating_line = lines[-2]
|
|
21
|
-
exit_if(not (m := self.RATING_PATTERN.match(rating_line)),
|
|
22
|
-
f"Failed running Pylint, got exit code {ret}. try running manually using:\n\t{self._build_command('TARGET')}")
|
|
23
|
-
rating_string = m.group(1) # type:ignore
|
|
24
|
-
numerator, denominator = rating_string.split("/")
|
|
25
|
-
return float(numerator) / float(denominator)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
__all__ = [
|
|
29
|
-
"PylintRunner",
|
|
30
|
-
]
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
# TODO
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|