Skip to content

Commit e6ff943

Browse files
committed
Initial commit
0 parents  commit e6ff943

File tree

14 files changed

+430
-0
lines changed

14 files changed

+430
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
https://github.com/prebuilder/AnyVer.py.git

.editorconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
indent_style = tab
6+
indent_size = 4
7+
insert_final_newline = true
8+
end_of_line = lf
9+
10+
[*.{yml,yaml}]
11+
indent_style = space
12+
indent_size = 2

.github/.templateMarker

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
KOLANICH/python_project_boilerplate.py

.github/dependabot.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "pip"
4+
directory: "/"
5+
schedule:
6+
interval: "daily"
7+
allow:
8+
- dependency-type: "all"

.github/workflows/CI.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
name: CI
2+
on:
3+
push:
4+
branches: [master]
5+
pull_request:
6+
branches: [master]
7+
8+
jobs:
9+
build:
10+
runs-on: ubuntu-22.04
11+
steps:
12+
- name: typical python workflow
13+
uses: KOLANICH-GHActions/typical-python-workflow@master
14+
with:
15+
github_token: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
__pycache__
2+
*.pyc
3+
*.pyo
4+
/*.egg-info
5+
/build
6+
/dist
7+
/.eggs
8+
*.sqlite3
9+
*.sqlite
10+
/.mypy_cache
11+
*.py,cover
12+
/.coverage
13+
/rspec.xml
14+
/monkeytype.sqlite3
15+
/*.srctrldb
16+
/*.srctrlbm
17+
/*.srctrlprj

.gitlab-ci.yml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#image: pypy:latest
2+
image: registry.gitlab.com/kolanich-subgroups/docker-images/fixed_python:latest
3+
stages:
4+
- dependencies
5+
- build
6+
- test
7+
- trigger
8+
9+
variables:
10+
DOCKER_DRIVER: overlay2
11+
SAST_ANALYZER_IMAGE_TAG: latest
12+
SAST_DISABLE_DIND: "true"
13+
14+
include:
15+
- template: SAST.gitlab-ci.yml
16+
#- template: DAST.gitlab-ci.yml
17+
#- template: License-Management.gitlab-ci.yml
18+
#- template: Container-Scanning.gitlab-ci.yml
19+
#- template: Dependency-Scanning.gitlab-ci.yml
20+
- template: Code-Quality.gitlab-ci.yml
21+
22+
23+
build:
24+
tags:
25+
- shared
26+
stage: build
27+
variables:
28+
GIT_DEPTH: "1"
29+
PYTHONUSERBASE: ${CI_PROJECT_DIR}/python_user_packages
30+
31+
before_script:
32+
- export PYTHON_MODULES_DIR=${PYTHONUSERBASE}/lib/python3.8
33+
- export EXECUTABLE_DEPENDENCIES_DIR=${PYTHONUSERBASE}/bin
34+
- export PATH="$PATH:$EXECUTABLE_DEPENDENCIES_DIR" # don't move into `variables` any of them, it is unordered
35+
- mkdir ./wheels
36+
- pip install --upgrade --pre --user git+https://gitlab.com/KOLANICH/AnyVer.py.git
37+
38+
script:
39+
- python3 ./setup.py bdist_wheel
40+
- mv ./dist/*.whl ./wheels/PackageRef-0.CI_python-py3-none-any.whl
41+
- pip3 install --upgrade --pre --user ./wheels/PackageRef-0.CI_python-py3-none-any.whl
42+
- coverage run --source=PackageRef --branch -m pytest --junitxml=./rspec.xml ./tests/tests.py
43+
- coverage report -m
44+
- coverage xml
45+
46+
coverage: /^TOTAL\\s+.+?(\\d{1,3}%)$/
47+
48+
cache:
49+
paths:
50+
- $PYTHONUSERBASE
51+
52+
artifacts:
53+
paths:
54+
- wheels
55+
reports:
56+
junit: ./rspec.xml
57+
cobertura: ./coverage.xml
58+

Code_Of_Conduct.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
No codes of conduct!

MANIFEST.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
include UNLICENSE
2+
include *.md
3+
include tests
4+
include .editorconfig

PackageRef/__init__.py

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
__all__ = ("PackageRef", "PackageRef", "VersionedPackageRef")
2+
import inspect
3+
import typing
4+
5+
6+
class IncompatibleVersionPostfix:
7+
__slots__ = ()
8+
9+
def __call__(self, ver: "BasePackageRef"):
10+
raise NotImplementedError
11+
12+
13+
class IncompatibleVersionPostfixDot(IncompatibleVersionPostfix):
14+
__slots__ = ("count",)
15+
16+
def __init__(self, count: int) -> None:
17+
self.count = count
18+
19+
def __call__(self, ver: "BasePackageRef") -> str:
20+
return ".".join(map(str, ver[: self.count]))
21+
22+
23+
class IncompatibleVersionPostfixFormat(IncompatibleVersionPostfix):
24+
__slots__ = ("format",)
25+
26+
def __init__(self, format: str) -> None:
27+
self.format = format
28+
29+
def __call__(self, ver: "BasePackageRef") -> str:
30+
return self.format.format(*ver)
31+
32+
33+
versionsPostfixesTypesMapping = {
34+
int: IncompatibleVersionPostfixDot,
35+
str: IncompatibleVersionPostfixFormat,
36+
}
37+
38+
BasePackageRefT = typing.Type["BasePackageRef"]
39+
40+
41+
class BasePackageRef:
42+
__slots__ = ("name", "arch", "versionPostfix")
43+
44+
def __init__(self, name: str, arch: str = "amd64", versionPostfix: typing.Union[str, int, callable, IncompatibleVersionPostfix] = None) -> None:
45+
self.name = name
46+
self.arch = arch
47+
48+
argType = type(versionPostfix)
49+
if argType in versionsPostfixesTypesMapping:
50+
versionPostfix = versionsPostfixesTypesMapping[argType](versionPostfix)
51+
self.versionPostfix = versionPostfix
52+
53+
_reprOrder = ("name", "arch")
54+
55+
def _metadataInnerReprStr(self):
56+
return ", ".join(vn + "=" + repr(getattr(self, vn)) for vn in self.__class__._reprOrder)
57+
58+
def asTuple(self) -> typing.Tuple[str, str]:
59+
return (self.name, self.arch)
60+
61+
def recreatorFull(self, cls: BasePackageRefT) -> typing.Mapping[str, typing.Any]:
62+
s = inspect.signature(cls.__init__)
63+
dic = {}
64+
pIter = iter(s.parameters.values())
65+
selfArg = next(pIter)
66+
assert selfArg.name == "self"
67+
68+
for p in pIter:
69+
n = p.name
70+
dic[n] = getattr(self, n)
71+
return dic
72+
73+
def downgrade(self) -> "BasePackageRef":
74+
mro = self.__class__.mro()
75+
cls = mro[1]
76+
assert issubclass(cls, __class__), "Cannot downgrade lower than " + __class__.__name__ + " :" + repr(mro)
77+
return self.clone(cls=cls)
78+
79+
def clone(self, cls: typing.Optional[BasePackageRefT] = None, **kwargs) -> "BasePackageRef":
80+
if cls is None:
81+
cls = self.__class__
82+
83+
if issubclass(cls, self.__class__): # upgrade or clone
84+
k = self.recreatorFull(self.__class__)
85+
elif issubclass(self.__class__, cls): # downgrade or clone
86+
k = self.recreatorFull(cls)
87+
else:
88+
raise ValueError("Only upgrades, downgrades and clones are allowed")
89+
90+
k.update(kwargs)
91+
res = cls(**k)
92+
return res
93+
94+
def __hash__(self) -> int:
95+
return hash(self.asTuple())
96+
97+
def __eq__(self, other: "BasePackageRef") -> bool:
98+
return isinstance(other, __class__) and self.asTuple() == other.asTuple()
99+
100+
def __repr__(self) -> str:
101+
return self.__class__.__name__ + "(" + self._metadataInnerReprStr() + ",...)"
102+
103+
def toPath(self):
104+
return "_".join(str(el) for el in self.asTuple()).replace("/", "_").replace("\\", "_")
105+
106+
def toName(self) -> str:
107+
return self.name
108+
109+
def __str__(self) -> str:
110+
return self.toName() + (":" + self.arch if self.arch is not None else "")
111+
112+
113+
class PackageRef(BasePackageRef):
114+
"""A reference to a package. Used to identify a package in a system installed package manager. It is an incomplete class without version"""
115+
116+
__slots__ = ("group",)
117+
118+
def __init__(self, name: str, arch: str = "amd64", group: typing.Optional[str] = None, versionPostfix: int = 0) -> None:
119+
super().__init__(name=name, arch=arch, versionPostfix=versionPostfix)
120+
self.group = group
121+
122+
_reprOrder = ("name", "group", "arch")
123+
124+
def asTuple(self) -> typing.Tuple[str, str, str]:
125+
return (self.name, self.arch, self.group)
126+
127+
def __str__(self) -> str:
128+
return (str(self.group) + "@" if self.group is not None else "") + super().__str__()
129+
130+
131+
try:
132+
from AnyVer import AnyVer, _AnyVer
133+
134+
class VersionedPackageRef(PackageRef):
135+
"""A reference to a package. Used to identify a package in a system installed package manager. Also used to identify a package globally"""
136+
137+
__slots__ = ("_version",)
138+
139+
def __init__(self, name: str, arch: str = "amd64", group: typing.Optional[str] = None, version: typing.Optional[typing.Union[str, _AnyVer]] = None, versionPostfix: int = 0) -> None:
140+
super().__init__(name, arch=arch, group=group, versionPostfix=versionPostfix)
141+
assert version is not None
142+
if isinstance(version, str):
143+
version = AnyVer(version)
144+
self.version = version
145+
146+
@property
147+
def version(self):
148+
return self._version
149+
150+
@version.setter
151+
def version(self, version: typing.Optional[typing.Union[str, _AnyVer]]):
152+
if version is not None:
153+
version = AnyVer(version)
154+
155+
self._version = version
156+
157+
def asTuple(self) -> typing.Tuple[str, str, str, _AnyVer]:
158+
return super().asTuple() + (self.version,)
159+
160+
_reprOrder = PackageRef._reprOrder + ("version",)
161+
162+
def toName(self) -> str:
163+
return super().toName() + (self.versionPostfix(self.version) if self.versionPostfix else "")
164+
165+
def __str__(self) -> str:
166+
return super().__str__() + " " + str(self.version)
167+
168+
except ImportError:
169+
warnings.warn("`AnyVer` is not present, so " + VersionedPackageRef.__name__ + " is not available")

0 commit comments

Comments
 (0)