generated from KOLANICH/python_project_boilerplate.py
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 8e36e85
Showing
21 changed files
with
565 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
root = true | ||
|
||
[*] | ||
charset = utf-8 | ||
indent_style = tab | ||
indent_size = 4 | ||
insert_final_newline = true | ||
end_of_line = lf | ||
|
||
[*.{yml,yaml}] | ||
indent_style = space | ||
indent_size = 2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
KOLANICH/python_project_boilerplate.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
version: 2 | ||
updates: | ||
- package-ecosystem: "pip" | ||
directory: "/" | ||
schedule: | ||
interval: "daily" | ||
allow: | ||
- dependency-type: "all" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
name: CI | ||
on: | ||
push: | ||
branches: [master] | ||
pull_request: | ||
branches: [master] | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-22.04 | ||
steps: | ||
- name: typical python workflow | ||
uses: KOLANICH-GHActions/typical-python-workflow@master | ||
with: | ||
github_token: ${{ secrets.GITHUB_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
__pycache__ | ||
*.pyc | ||
*.pyo | ||
*.egg-info | ||
build | ||
dist | ||
.eggs | ||
/monkeytype.sqlite3 | ||
/*.srctrldb | ||
/*.srctrlbm | ||
/*.srctrlprj |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
#image: pypy:latest | ||
image: registry.gitlab.com/kolanich-subgroups/docker-images/fixed_python:latest | ||
|
||
variables: | ||
DOCKER_DRIVER: overlay2 | ||
SAST_ANALYZER_IMAGE_TAG: latest | ||
SAST_DISABLE_DIND: "true" | ||
SAST_CONFIDENCE_LEVEL: 5 | ||
CODECLIMATE_VERSION: latest | ||
|
||
include: | ||
- template: SAST.gitlab-ci.yml | ||
- template: Code-Quality.gitlab-ci.yml | ||
- template: License-Management.gitlab-ci.yml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
No codes of conduct! Just do what you feel is right and say what you feel is right using the language you feel is right. If you feel that it is right to [make an own fork with a CoCs and SJWs](https://en.wikipedia.org/wiki/Bender_Rodriguez), just do that. We here are doing the work, not accusing each other in violating codes of conduct. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import typing | ||
from abc import ABC, abstractmethod | ||
from pathlib import Path | ||
|
||
from .utils.pathListTools import ClassesImportSpecT, ClassPathT, appendPathsList, dedupPreservingOrder, getTupleFromPathProperty, pathsList2String | ||
|
||
|
||
class JVMInitializer(ABC): | ||
#__slots__ = ("sys", ) # we inject loaded classes right into this class | ||
|
||
classPathPropertyName = "sys.class.path" | ||
classPathPropertyName = "java.class.path" # new | ||
libPathPropertyName = "java.library.path" | ||
|
||
def __init__(self, classPaths: ClassPathT, classes2import: ClassesImportSpecT, *, libPaths=None) -> None: | ||
self.prepareJVM() | ||
self.sys = self.loadClass("java.lang.System") | ||
classPaths = list(classPaths) | ||
self.appendClassPath(classPaths) | ||
self.loadClasses(classes2import) | ||
|
||
class _Implements(type): | ||
"""Used as a metaclass to wrap python classes implementing interfaces defined in JVM code""" | ||
|
||
__slots__ = () | ||
|
||
def _Override(self, meth: typing.Callable) -> typing.Callable: | ||
"""Used as a decorator to wrap python methods overriding methods defined in JVM code""" | ||
return meth | ||
|
||
@abstractmethod | ||
def selectJVM(self) -> Path: | ||
"""Returns Path to libjvm.so""" | ||
raise NotImplementedError() | ||
|
||
@abstractmethod | ||
def prepareJVM(self): | ||
"""Starts JVM and sets its settings""" | ||
raise NotImplementedError() | ||
|
||
def reflClass2Class(self, cls) -> typing.Any: # pylint: disable=no-self-use | ||
"""Transforms a reflection object for a class into an object usable by python""" | ||
return cls | ||
|
||
def reflectClass(self, cls) -> typing.Any: | ||
"""Transforms a a class into a reflection object for a class""" | ||
raise NotImplementedError | ||
|
||
@abstractmethod | ||
def loadClass(self, name: str) -> typing.Any: | ||
"""Returns a class""" | ||
raise NotImplementedError() | ||
|
||
def getSysPropsDict(self): | ||
return {str(k): str(self.sys.getProperty(k)) for k in self.sys.getProperties()} | ||
|
||
@property | ||
def libPathStr(self) -> str: | ||
"""libpath string""" | ||
return str(self.sys.getProperty(self.__class__.libPathPropertyName)) | ||
|
||
@libPathStr.setter | ||
def libPathStr(self, classPath: str) -> None: | ||
self.sys.setProperty(self.__class__.libPathPropertyName, classPath) | ||
|
||
@property | ||
def classPathStr(self) -> str: | ||
"""classpath string""" | ||
return str(self.sys.getProperty(self.__class__.classPathPropertyName)) | ||
|
||
@classPathStr.setter | ||
def classPathStr(self, classPath: str) -> None: | ||
self.sys.setProperty(self.__class__.classPathPropertyName, classPath) | ||
|
||
@property | ||
def classPath(self) -> typing.Iterable[str]: | ||
"""classpath string separated into paths""" | ||
return getTupleFromPathProperty(self.classPathStr) | ||
|
||
@classPath.setter | ||
def classPath(self, classPaths: ClassPathT) -> None: | ||
self.classPathStr = pathsList2String(classPaths) | ||
|
||
def appendClassPath(self, classPaths: ClassPathT) -> None: | ||
"""Adds a jar into classpath""" | ||
self.classPath = appendPathsList(classPaths, self.classPath) | ||
|
||
@property | ||
def libPath(self) -> typing.Iterable[str]: | ||
"""classpath string separated into paths""" | ||
return getTupleFromPathProperty(self.libPathStr) | ||
|
||
@libPath.setter | ||
def libPath(self, libPaths: ClassPathT) -> None: | ||
self.libPathStr = pathsList2String(libPaths) | ||
|
||
def appendLibPath(self, libPaths: ClassPathT) -> None: | ||
"""Adds a lib into libpath""" | ||
self.libPath = appendPathsList(libPaths, self.libPath) | ||
|
||
def loadClasses(self, classes2import: ClassesImportSpecT) -> None: | ||
"""Loads the classes that are required to be loaded and injects them into `self`, using the last component of a path as a property. Processes single `$` within paths correctly.""" | ||
if isinstance(classes2import, (list, tuple)): | ||
newSpec = {} | ||
for el in classes2import: | ||
if isinstance(el, tuple): | ||
name = el[1] | ||
path = el[0] | ||
else: | ||
name = el.split(".")[-1] | ||
path = el | ||
|
||
nameDollarSplitted = name.split("$") | ||
if len(nameDollarSplitted) == 2: | ||
name = nameDollarSplitted[1] | ||
elif len(nameDollarSplitted) > 2: | ||
raise ValueError(name) | ||
|
||
newSpec[name] = path | ||
|
||
classes2import = newSpec | ||
|
||
for name, className in newSpec.items(): | ||
setattr(self, name, self.loadClass(className)) | ||
else: | ||
raise ValueError("`classes2import` have wrong type", classes2import) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
__all__ = ("SelectedJVMInitializer", "ClassPathT", "ClassesImportSpecT") | ||
import sys | ||
from importlib import import_module | ||
|
||
from .utils.pathListTools import ClassesImportSpecT, ClassPathT | ||
|
||
implPkgNameMapping = {"cpython": "JPype", "graalpython": "GraalVM"} | ||
|
||
implPkgName = implPkgNameMapping[sys.implementation.name] | ||
pkg = import_module(".impls." + implPkgName, __package__) | ||
SelectedJVMInitializer = pkg.SelectedJVMInitializer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
from pathlib import Path | ||
|
||
import java # pylint: disable=import-error | ||
|
||
from ..JVMInitializer import JVMInitializer | ||
|
||
|
||
class GraalVMInitializer(JVMInitializer): | ||
__slots__ = ("ClassLoader", "_systemClassLoader") | ||
|
||
def prepareJVM(self): | ||
self.ClassLoader = java.type("java.lang.ClassLoader") | ||
self._systemClassLoader = self.ClassLoader.getSystemClassLoader() | ||
|
||
def selectJVM(self) -> Path: # pylint: disable=no-self-use | ||
return None | ||
|
||
def loadClass(self, name: str): | ||
return self._systemClassLoader.loadClass(name) | ||
|
||
|
||
SelectedJVMInitializer = GraalVMInitializer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
import typing | ||
import warnings | ||
from pathlib import Path | ||
|
||
import _jpype | ||
import jpype | ||
import jpype.beans | ||
|
||
from ..JVMInitializer import JVMInitializer | ||
from ..utils.pathListTools import ClassesImportSpecT, ClassPathT, appendPathsList, getTupleFromPathProperty, pathsList2String | ||
|
||
ji = None | ||
|
||
|
||
class RootClassLoaderWrapper: | ||
__slots__ = ("cl", "children") | ||
|
||
def __init__(self, cl): | ||
self.cl = cl | ||
self.children = {} | ||
|
||
def free(self): | ||
del self.cl | ||
|
||
|
||
class ClassLoaderWrapper(RootClassLoaderWrapper): | ||
__slots__ = ("cl", "children", "parent") | ||
|
||
def __init__(self, cl, parent): | ||
super().__init__(cl) | ||
self.parent = parent | ||
parent.children[id(cl)] = self | ||
|
||
def free(self): | ||
if self.children: | ||
raise ValueError("Cannot free a loader with children") | ||
|
||
del self.parent[id(self.cl)] | ||
super().free() | ||
|
||
|
||
class _JPypeInitializer(JVMInitializer): | ||
__slots__ = ("_allowShutdown", "_libPaths") | ||
classPathPropertyName = "java.class.path" | ||
|
||
_defaultLibsPaths = None | ||
|
||
def __init__(self, classPaths: ClassPathT, classes2import: ClassesImportSpecT, *, libPaths=None, _allowShutdown: bool = False) -> None: | ||
self._allowShutdown = _allowShutdown | ||
self._libPaths = libPaths | ||
if _allowShutdown: | ||
warnings.warn("`_allowShutdown` was used to allow `jpype.shutdownJVM`. See https://jpype.readthedocs.io/en/latest/userguide.html#unloading-the-jvm and https://github.com/jpype-project/jpype/blob/master/native/common/jp_context.cpp#L290") | ||
|
||
# these ones are defered. Before JVM is initialized they are accumulated by JPipe itself. They are not the same as loaded in runtime. Ones loaded in runtime may have various conflicts because of different classloaders. | ||
for cp in classPaths: | ||
jpype._classpath.addClassPath(cp.absolute()) | ||
|
||
# because JPype accumulates them itself, we put here nothing | ||
super().__init__([], classes2import) | ||
|
||
def selectJVM(self) -> Path: | ||
return Path(jpype.getDefaultJVMPath()) | ||
|
||
@property | ||
def classPath(self, classPath: ClassPathT) -> None: | ||
return super().classPath | ||
|
||
@classPath.setter | ||
def classPath(self, classPath: ClassPathT) -> None: | ||
raise NotImplementedError("For this backend redefining classpath is not supported, use `appendClassPath`") | ||
|
||
def appendClassPath(self, classPaths: ClassPathT) -> None: | ||
for cp in classPaths: | ||
jpype._classpath.addClassPath(cp.absolute()) | ||
|
||
def appendLibPath(self, libPaths: ClassPathT) -> None: | ||
raise NotImplementedError("Unavailable in JPype. Restart the JVM.") | ||
|
||
def loadClass(self, name: str): | ||
res = jpype.JClass(name) | ||
|
||
assert isinstance(res, jpype._jpype._JClass), "Class `" + repr(name) + "` is not loaded (res.__class__ == " + repr(res.__class__) + "), it's JPype drawback that when something is missing it returns a `jpype._jpackage.JPackage`, that errors only when one tries to instantiate it as a class" # pylint: disable=c-extension-no-member,protected-access | ||
return res | ||
|
||
def reflClass2Class(self, cls) -> typing.Any: # pylint: disable=no-self-use | ||
return jpype.types.JClass(cls) | ||
|
||
def prepareJVM(self) -> None: | ||
if jpype.isJVMStarted(): | ||
warnings.warn("JPype disallows starting multiple JVMs or restarting it. Assuming that JVM is already started with needed arguments, such as classpath.") | ||
if not self._allowShutdown: | ||
return | ||
jpype.shutdownJVM() | ||
|
||
# WARNING | ||
# 1. sys.class.path doesn't work | ||
# 2. only classpath set via "-Djava.class.path=" takes effect, https://github.com/jpype-project/jpype/issues/177 | ||
# 3. only libpath set at start up via "-Djava.library.path=" takes effect | ||
args = [jpype.getDefaultJVMPath(), "-ea"] | ||
if self._libPaths: | ||
if self.__class__._defaultLibsPaths is None: | ||
from ..utils.javaPropsInASeparateProcess import getDefaultJavaPropsFromSubprocess | ||
|
||
defaultProps = getDefaultJavaPropsFromSubprocess(self) | ||
self.__class__._defaultLibsPaths = getTupleFromPathProperty(defaultProps.get(self.__class__.libPathPropertyName, "")) | ||
|
||
libPaths = appendPathsList(self.__class__._defaultLibsPaths, self._libPaths) | ||
args.append("-D" + self.__class__.libPathPropertyName + "=" + pathsList2String(libPaths)) | ||
|
||
jpype.startJVM(*args, convertStrings=False, ignoreUnrecognized=False) | ||
|
||
def reflectClass(self, cls) -> typing.Any: | ||
return cls.class_ | ||
|
||
@staticmethod | ||
def _Implements(className: str, parents: typing.Tuple[typing.Type, ...], attrs: typing.Dict[str, typing.Any]): | ||
interface = parents[0] | ||
res = type(className, (), attrs) | ||
dec = jpype.JImplements(interface) | ||
return dec(res) | ||
|
||
_Override = staticmethod(jpype.JOverride) | ||
|
||
|
||
class JPypeInitializer(_JPypeInitializer): | ||
__slots__ = () | ||
|
||
def __new__(cls, classPaths: ClassPathT, classes2import: ClassesImportSpecT, *args, **kwargs): | ||
global ji | ||
if ji is None: | ||
ji = _JPypeInitializer(classPaths, classes2import, *args, **kwargs) | ||
else: | ||
ji.appendClassPath(classPaths) | ||
ji.loadClasses(classes2import) | ||
|
||
return ji | ||
|
||
|
||
SelectedJVMInitializer = JPypeInitializer |
Empty file.
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
__all__ = ("extractClassesFromAJar",) | ||
|
||
import typing | ||
import zipfile | ||
from pathlib import Path, PurePath | ||
|
||
|
||
def _extractClassesFromAJar(jarPath: Path) -> typing.Iterator[typing.Tuple[str, ...]]: | ||
classExt = ".class" | ||
with zipfile.ZipFile(jarPath) as z: | ||
for f in z.infolist(): | ||
if f.filename.endswith(classExt): | ||
path = PurePath(f.filename) | ||
yield path.parts[:-1] + (path.stem,) | ||
|
||
|
||
def extractClassesFromAJar(jarPath: Path) -> typing.Any: | ||
return tuple(sorted(_extractClassesFromAJar(jarPath))) |
Oops, something went wrong.