main > main: init

This commit is contained in:
RD 2022-10-14 12:16:08 +02:00
commit ba54939a3b
29 changed files with 1365 additions and 0 deletions

22
.coveragerc Normal file
View File

@ -0,0 +1,22 @@
[run]
source="."
[report]
show_missing = true
omit =
# ignore tests folder
tests/*
# ignore thirdparty imports
src/thirdparty/*
# ignore models folder (auto generated)
models/**
# ignore __init__ files (only used for exports)
**/__init__.py
# ignore main.py, app.py (-> too macroscopic and covered by integration tests)
main.py
src/app.py
# TODO: increase code-coverage:
fail_under = 100
precision = 1
exclude_lines =
pragma: no cover

86
.gitignore vendored Normal file
View File

@ -0,0 +1,86 @@
*
!/.gitignore
################################################################
# DOCKER
################################################################
!/.dockerignore
!/Dockerfile
!/docker-compose.yaml
################################################################
# MAIN FOLDER
################################################################
!/justfile
!/Makefile
!/README.md
!/LICENSE
!/.coveragerc
!/pyproject.toml
!/requirements*
################################################################
# PROJECT FILES
################################################################
!/templates
!/templates/template*
!/src
!/src/**/
!/src/**/*.py
!/src/**/*.yaml
!/main.py
!/notebooks
!/notebooks/*.ipynb
!/notebooks/*.md
# NOTE: models are created as part of the build process:
!/models
!/models/*.yaml
!/models/README.md
!/docs
!/docs/*/
!/docs/*/Models/
!/docs/**/*.md
!/tests
!/tests/**/
!/tests/**/*.py
!/tests/resources/*.yaml
!/tests/README.md
!/dist
!/dist/VERSION
################################################################
# AUXLIARY
################################################################
/logs
/**/.env
################################################################
# TEMPLATES
################################################################
!/templates/.env
################################################################
# ARTEFACTS
################################################################
/**/__pycache__
/**/.pytest_cache
/**/.DS_Store
/**/__archive__*
################################################################
# Git Keep
################################################################
!/**/.gitkeep

0
LICENSE Normal file
View File

77
README.md Normal file
View File

@ -0,0 +1,77 @@
# Algorithmen und Datenstrukturen I, WiSe 2022-23 #
Der Inhalt dieses Repository ist keineswegs verpflichtend, sondern dient dem Zweck, „Handnotizen“ anzubieten.
Es besteht hier kein Anspruch auf Vollständigkeit.
Es werden hier keine offiziellen Lösungen für die Übungsblätter gespeichert.
Die offiziellen Notizen zum Kurs sowie alle Übungsblätter, (Abgabe)termine, _etc._
findet man ausschließlich auf der **Moodle**-Seite.
## (Wesentliche) Struktur des Repositorys ##
```text
.
├── ./notebooks # Python/Jupyter Notebooks
│ ├── ...
│ └── ... *.ipynb Dateien
├── ./src # Quellcode
│ ├── ...
│ └── ... *.py Dateien
├── ./templates # Templates für Konfiguration
│ ├── ...
│ └── ... *.yaml Dateien
├── ./setup # User Konfiguration
│ ├── ...
│ └── ... *.yaml Dateien
├── ./tests # enthält ggf. automatisiertes Testing
├── ./dist # enthält VERSION infos
├── ./models # erzeugte Modelle
├── ./docs # Dokumentation für erzeugte Modelle
├── justfile
├── README.md
├── LICENSE
├── requirements.txt
└── main.py
```
## Gebrauchshinweise ##
### Systemvoraussetzungen ###
- [**python 3.10.x**](https://www.python.org/downloads)
- optional: **bash** (für Windowsuser siehe [git for windows](https://gitforwindows.org), was bash mit installiert)
- optional: das [**justfile** Tool](https://github.com/casey/just#installation) (für Windowsuser wird die das [Chocolatey](https://chocolatey.org/install) Tool empfohlen, um dieses Tool installieren zu können)
### Setup ###
Für den Gebrauch der Python-Skripte + Notebooks braucht man einige Packages.
Um diese zu installiere führe man
```bash
just build
# oder
just build-requirements
```
aus. Alternativ kann man
```bash
python3 -m pip install -r --disable-pip-version-check -r requirements.txt
# für Windowsuser:
py -3 -m pip install -r --disable-pip-version-check -r requirements.txt
```
verwenden.
### Ausführung ###
Die Notebooks kann man direkt in dem [**jupyter**](https://jupyter.org) GUI öffnen,
oder in einem bash Terminal führe man
```bash
just notebook xyz
```
aus, um den Notebook **notebooks/xyz.ipynb** zu starten.
Alternativ, kann man
``` bash
python3 -m jupyter notebook notebooks/xyz.ipynb
# für Windowsuser:
py -3 -m jupyter notebook notebooks/xyz.ipynb
```
verwenden.

1
dist/VERSION vendored Normal file
View File

@ -0,0 +1 @@
0.0.0

259
justfile Normal file
View File

@ -0,0 +1,259 @@
# set shell := [ "bash", "-uc" ]
_default:
@- just --unsorted --list
menu:
@- just --unsorted --choose
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Justfile
# NOTE: Do not change the contents of this file!
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# VARIABLES
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OS := if os_family() == "windows" { "windows" } else { "linux" }
PYTHON := if os_family() == "windows" { "py -3" } else { "python3" }
GEN_MODELS := "datamodel-codegen"
GEN_MODELS_DOCUMENTATION := "openapi-generator"
PORT := "8000"
URL_API := "http://127.0.0.1:8000/docs"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Macros
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
_create-file-if-not-exists fname:
@touch "{{fname}}";
_create-folder-if-not-exists path:
@if ! [[ -d "{{path}}" ]]; then mkdir -p "{{path}}"; fi
_delete-if-file-exists fname:
@if [[ -f "{{fname}}" ]]; then rm "{{fname}}"; fi
_delete-if-folder-exists path:
@if [[ -d "{{path}}" ]]; then rm -rf "{{path}}"; fi
_clean-all-files path pattern:
@find {{path}} -type f -name "{{pattern}}" -exec basename {} \; 2> /dev/null
@- find {{path}} -type f -name "{{pattern}}" -exec rm {} \; 2> /dev/null
_clean-all-folders path pattern:
@find {{path}} -type d -name "{{pattern}}" -exec basename {} \; 2> /dev/null
@- find {{path}} -type d -name "{{pattern}}" -exec rm -rf {} \; 2> /dev/null
_copy-file-if-not-exists path_from path_to:
@- cp -n "{{path_from}}" "{{path_to}}"
_check-python-tool tool name:
#!/usr/bin/env bash
success=false
{{tool}} --help >> /dev/null 2> /dev/null && success=true;
# NOTE: if exitcode is 251 (= help or print version), then render success.
[[ "$?" == "251" ]] && success=true;
# FAIL tool not installed
if ( $success ); then
echo -e "Tool \x1b[2;3m{{tool}}\x1b[0m installed correctly.";
exit 0;
else
echo -e "Tool \x1b[2;3m{{tool}}\x1b[0m did not work." >> /dev/stderr;
echo -e "Ensure that \x1b[2;3m{{name}}\x1b[0m (-> \x1b[1mjust build\x1b[0m) installed correctly and system paths are set." >> /dev/stderr;
exit 1;
fi
_generate-models path name:
@{{GEN_MODELS}} \
--input-file-type openapi \
--encoding "UTF-8" \
--disable-timestamp \
--use-schema-description \
--allow-population-by-field-name \
--snake-case-field \
--strict-nullable \
--target-python-version 3.10 \
--input {{path}}/{{name}}-schema.yaml \
--output {{path}}/generated/{{name}}.py
_generate-models-documentation path_schema path_docs name:
@{{GEN_MODELS_DOCUMENTATION}} generate \
--input-spec {{path_schema}}/{{name}}-schema.yaml \
--generator-name markdown \
--output "{{path_docs}}/{{name}}"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# TARGETS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# TARGETS: build
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
build:
@just build-misc
@just build-requirements
@just _check-system-requirements
@just build-models
build-misc:
@# create database if not exists:
@just _create-folder-if-not-exists "data"
@# copy template of configs to setup if not exists:
@just _create-folder-if-not-exists "setup"
@just _copy-file-if-not-exists "templates/template-config.yaml" "setup/config.yaml"
@just _copy-file-if-not-exists "templates/template.env" ".env"
build-requirements:
@{{PYTHON}} -m pip install --disable-pip-version-check -r requirements.txt
build-models:
@echo "Generate data models from schemata."
@just _delete-if-folder-exists "models/generated"
@just _create-folder-if-not-exists "models/generated"
@- #just _generate-models "models" "config"
build-documentation:
@echo "Generate documentations data models from schemata."
@just _delete-if-folder-exists "docs"
@just _create-folder-if-not-exists "docs"
@- #just _generate-models-documentation "models" "docs" "config"
@- just _clean-all-files "." .openapi-generator*
@- just _clean-all-folders "." .openapi-generator*
dist:
@just build
@just build-documentation
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# TARGETS: run
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# runs using commandline interface
run:
@# create config/data folders if missing:
@just build-misc
@# run source code als cli
@{{PYTHON}} main.py
# runs python notebook (in browser)
notebook name="main":
@# create config/data folders if missing:
@just build-misc
@# run notebook
@{{PYTHON}} -m jupyter notebook notebooks/{{name}}.ipynb
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# TARGETS: tests
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tests: tests-unit tests-integration
tests-logs:
@just _create-logs
@- just tests
@just _display-logs
tests-unit-logs:
@just _create-logs
@- just tests-unit
@just _display-logs
tests-integration-logs:
@just _create-logs
@- just tests-integration
@just _display-logs
tests-unit:
@{{PYTHON}} -m pytest tests \
--ignore=tests/integration \
--cov-reset \
--cov=. \
2> /dev/null
tests-integration:
@{{PYTHON}} -m pytest tests/integration 2> /dev/null
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# TARGETS: qa
# NOTE: use for development only.
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
qa:
@{{PYTHON}} -m coverage report -m
coverage source_path tests_path:
@just _create-logs
@-just _coverage-no-logs "{{source_path}}" "{{tests_path}}"
@just _display-logs
_coverage-no-logs source_path tests_path:
@{{PYTHON}} -m pytest {{tests_path}} \
--ignore=tests/integration \
--cov-reset \
--cov={{source_path}} \
--capture=tee-sys \
2> /dev/null
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# TARGETS: clean
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
clean:
@just clean-basic
@just pre-commit
pre-commit:
@echo "Clean python notebooks."
@{{PYTHON}} -m jupyter nbconvert --clear-output --inplace **/*.ipynb
@- {{PYTHON}} -m jupytext --update-metadata '{"vscode":""}' **/*.ipynb 2> /dev/null
@- {{PYTHON}} -m jupytext --update-metadata '{"vscode":null}' **/*.ipynb 2> /dev/null
clean-basic:
@echo "All system artefacts will be force removed."
@- just _clean-all-files "." ".DS_Store" 2> /dev/null
@echo "All build artefacts will be force removed."
@- just _clean-all-folders "." "__pycache__" 2> /dev/null
@- just _delete-if-folder-exists "models/generated" 2> /dev/null
@echo "All test artefacts will be force removed."
@- just _clean-all-folders "." ".pytest_cache" 2> /dev/null
@- just _delete-if-file-exists ".coverage" 2> /dev/null
@- just _delete-if-folder-exists "logs" 2> /dev/null
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# TARGETS: logging
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
_create-logs:
@# For logging purposes (since stdout is rechanneled):
@just _delete-if-file-exists "logs/debug.log"
@just _create-folder-if-not-exists "logs"
@just _create-file-if-not-exists "logs/debug.log"
_display-logs:
@echo ""
@echo "Content of logs/debug.log:"
@echo "----------------"
@echo ""
@- cat logs/debug.log
@echo ""
@echo "----------------"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# TARGETS: processes
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
api-process:
#!/usr/bin/env bash
if [[ "{{OS}}" == "linux" ]]; then
ps aux | grep "uvicorn src.api:app"
else
netstat -ano | findstr "uvicorn src.api:app"
fi
kill-api-process:
#!/usr/bin/env bash
# NOTE: only need to do this for linux.
if [[ "{{OS}}" == "linux" ]]; then
echo "Terminating all processes associated to app and port {{PORT}}."
while read pid; do
if [[ "$pid" == "" ]]; then continue; fi
echo "- killing process $pid:"
kill -9 ${pid};
done <<< $( pgrep -f "uvicorn src.api:app --port {{PORT}}" )
fi
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# TARGETS: requirements
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
_check-system:
@echo "Operating System detected: {{os_family()}}."
@echo "Python command used: {{PYTHON}}."
_check-system-requirements:
@just _check-python-tool "{{GEN_MODELS}}" "datamodel-code-generator"
@just _check-python-tool "{{GEN_MODELS_DOCUMENTATION}}" "openapi-code-generator"

28
main.py Normal file
View File

@ -0,0 +1,28 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import os;
import sys;
os.chdir(os.path.dirname(__file__));
sys.path.insert(0, os.getcwd());
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# MAIN
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def enter():
print('Not yet implemented.');
return;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXECUTION
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if __name__ == '__main__':
# sys.tracebacklimit = 0;
enter();

57
pyproject.toml Normal file
View File

@ -0,0 +1,57 @@
[project]
name = "course-ads-1"
version = "X.Y.Z"
description = ""
authors = [ "gitea.math.uni-leipzig.de/raj_mathe" ]
maintainers = [ "gitea.math.uni-leipzig.de/raj_mathe" ]
license = "MIT"
readme = "README.md"
python = "^3.10"
homepage = "https://gitea.math.uni-leipzig.de/raj_mathe/mfp1-2022"
repository = "https://gitea.math.uni-leipzig.de/raj_mathe/mfp1-2022"
documentation = "https://gitea.math.uni-leipzig.de/raj_mathe/mfp1-2022/src/README.md"
keywords = [
"python",
]
# cf. https://pypi.org/classifiers
classifiers = [
"Development Status :: 3 - Alpha",
"Environment :: Console",
"Intended Audience :: Developers",
"Operating System :: Unix",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.10",
]
[tool.pytest.ini_options]
minversion = "7.1.1"
testpaths = [
"tests",
]
python_files = [
"**/tests_*.py",
]
asyncio_mode = "auto"
filterwarnings = [
"error",
"ignore::UserWarning",
"ignore::DeprecationWarning",
]
# NOTE: appends (not prepends) flags:
addopts = [
"--order-dependencies",
"--order-group-scope=module",
"--cache-clear",
"--verbose",
"--maxfail=1",
"-k test_",
# NOTE: will be ignored, if --cov not used (e.g. integration tests):
"--no-cov-on-fail",
"--cov-report=term",
"--cov-config=.coveragerc",
# NOTE: for development purposes only:
# "-s", # verbose print/err capturing disabled
# "--capture=tee-sys", # verbose print/err capturing enabled
]

49
requirements.txt Normal file
View File

@ -0,0 +1,49 @@
pip>=22.2.2
wheel>=0.37.1
# jupyter
ipython>=8.3.0
jupyter>=1.0.0
# running
codetiming>=1.3.0
# testing + dev
coverage[toml]>=6.4
pytest>=7.1.1
pytest-asyncio>=0.18.3
pytest-cov>=3.0.0
pytest-lazy-fixture>=0.6.3
pytest-order>=1.0.1
testfixtures>=6.18.5
# misc
importlib>=1.0.4
authlib>=1.0.1
passlib>=1.7.4
psutil>=5.9.0
pathlib>=1.0.1
lorem>=0.1.1
safetywrap>=1.5.0
typing>=3.7.4.3
nptyping>=2.1.1
typing-extensions>=3.10.0.2
# config
python-dotenv>=0.20.0
jsonschema>=4.4.0
lazy-load>=0.8.2
pyyaml>=5.4.1
pydantic>=1.9.1
datamodel-code-generator>=0.12.0
# maths
fraction>=2.2.0
numpy>=1.22.4
matplotlib>=3.5.1
# tables, data frames
pandas>=1.4.2
tabulate>=0.8.10
# array-to-latex>=0.82 # <- has issues
qiskit[visualization]>=0.38.0

0
src/__init__.py Normal file
View File

0
src/core/__init__.py Normal file
View File

215
src/core/calls.py Normal file
View File

@ -0,0 +1,215 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from __future__ import annotations;
from src.thirdparty.code import *;
from src.thirdparty.config import *;
from src.thirdparty.types import *;
from src.core.utils import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__all__ = [
'CallState',
'GetState',
'CallValue',
'CallError',
'keep_calm_and_carry_on',
'run_safely',
'to_async',
];
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# CONSTANTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# local usage only
T = TypeVar('T');
V = TypeVar('V');
ARGS = ParamSpec('ARGS');
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Class State for keeping track of results in the course of a computation
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@dataclass
class CallState(Generic[V]):
'''
An auxiliary class which keeps track of the latest state of during calls.
'''
tag: Option[str] = field(default=None);
result: Optional[V] = field(default=None, repr=False);
timestamp: str = field(default_factory=get_timestamp_string);
has_action: bool = field(default=False);
no_action: bool = field(default=False);
has_error: bool = field(default=False);
values: list[tuple[bool, dict]] = field(default_factory=list, repr=False);
errors: list[str] = field(default_factory=list, repr=False);
def __copy__(self) -> CallState:
return CallState(**asdict(self));
def __add__(self, other) -> CallState:
'''
Combines states sequentially:
- takes on latest `timestamp`.
- takes on lates `value`.
- takes on `tag` of latest non-null value.
- takes on latest value of `no_action`
- `has_action` = `true` <==> at least one action taken,
unless `no_action` = `true`.
- `has_error` = `true` <==> at least one error occurred.
'''
if isinstance(other, CallState):
no_action = other.no_action;
has_action = False if no_action else (self.has_action or other.has_action);
return CallState(
tag = other.tag or self.tag,
value = other.value,
timestamp = other.timestamp,
has_action = has_action,
no_action = no_action,
has_error = self.has_error or other.has_error,
values = self.values + other.values,
errors = self.errors + other.errors,
);
raise Exception('Cannot add states!');
## NOTE: only need __radd__ for additions of form <other> + <state>
def __radd__(self, other) -> CallState:
if other == 0:
return self.__copy__();
raise Exception('Cannot add a CallState to the right of a non-zero object!');
def get_result(self) -> V:
if self.result is not None:
return self.result;
raise Exception('No result set!');
@property
def first_data(self) -> dict:
'''
Returns data in first value collected or else defaults to empty dictionary.
'''
return self.values[0][1] if len(self.values) > 0 else dict();
@property
def data(self) -> list[dict]:
'''
Returns the data collected.
'''
return [ data for _, data in self.values ];
@property
def data_log(self) -> list[dict]:
'''
Returns the data to be logged.
'''
return [ data for log, data in self.values if log == True ];
@property
def data_log_json(self) -> list[str]:
'''
Returns the data to be logged as json.
'''
return list(map(json.dumps, self.data_log));
def GetState(result: Result[CallState, CallState]) -> CallState:
if isinstance(result, Ok):
return result.unwrap();
return result.unwrap_err();
def CallValue(
tag: str = None,
result: Optional[V] = None,
has_action: bool = True,
no_action: bool = False,
value: Option[tuple[bool, dict] | list[tuple[bool, dict]]] = Nothing(),
) -> CallState[V]:
x = [];
if isinstance(value, Some):
x = value.unwrap() or [];
x = x if isinstance(x, list) else [ x ];
X = CallState(tag=tag, result=result, values=x, has_action=has_action, no_action=no_action, has_error=False);
return X;
def CallError(
tag: str = None,
has_action: bool = True,
error: Option[str | BaseException | list[str | BaseException]] = Nothing(),
) -> CallState[V]:
x = [];
if isinstance(error, Some):
x = error.unwrap() or [];
x = x if isinstance(x, list) else [ x ];
x = list(map(str, x));
return CallState(tag=tag, errors=x, has_action=has_action, has_error=True);
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# DECORATOR - forces methods to run safely
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def run_safely(tag: str | None = None, error_message: str | None = None):
'''
Creates a decorator for an action to perform it safely.
@inputs (parameters)
- `tag` - optional string to aid error tracking.
- `error_message` - optional string for an error message.
### Example usage ###
```py
@run_safely(tag='recognise int', error_message='unrecognise string')
def action1(x: str) -> Result[int, CallState]:
return Ok(int(x));
assert action1('5') == Ok(5);
result = action1('not a number');
assert isinstance(result, Err);
err = result.unwrap_err();
assert isinstance(err, CallState);
assert err.tag == 'recognise int';
assert err.errors == ['unrecognise string'];
@run_safely('recognise int')
def action2(x: str) -> Result[int, CallState]:
return Ok(int(x));
assert action2('5') == Ok(5);
result = action2('not a number');
assert isinstance(result, Err);
err = result.unwrap_err();
assert isinstance(err, CallState);
assert err.tag == 'recognise int';
assert len(err.errors) == 1;
```
NOTE: in the second example, err.errors is a list containing
the stringified Exception generated when calling `int('not a number')`.
'''
def dec(action: Callable[ARGS, Result[V, CallState]]) -> Callable[ARGS, Result[V, CallState]]:
'''
Wraps action with return type Result[..., CallState],
so that it is performed safely a promise,
catching any internal exceptions as an Err(...)-component of the Result.
'''
@wraps(action)
def wrapped_action(*_, **__) -> Result[V, CallState]:
# NOTE: intercept Exceptions first, then flatten:
return Result.of(lambda: action(*_, **__)) \
.or_else(
lambda err: Err(CallError(
tag = tag or action.__name__,
error = Some(error_message or err),
))
) \
.flatmap(lambda value: value); # necessary to flatten result.
return wrapped_action;
return dec;

61
src/core/env.py Normal file
View File

@ -0,0 +1,61 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from src.thirdparty.code import *;
from src.thirdparty.config import *;
from src.thirdparty.system import *;
from src.thirdparty.types import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__all__ = [
'get_env_string',
'get_env_optional_string',
'get_env_int',
'get_env_optional_int',
'get_env_float',
'get_env_optional_float',
];
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# AUXILIARY METHODS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def get_env_value(env: dict, key: str, default: Any = None) -> Any: # pragma: no cover
return env[key] if key in env else default;
def get_env_string(env: dict, key: str, default: Optional[str] = None) -> str:
result = Result.of(lambda: str(env[key] or default));
if default is None:
return result.unwrap();
return result.unwrap_or(default);
def get_env_optional_string(env: dict, key: str) -> Optional[str]:
result = Result.of(lambda: str(env[key]));
return result.unwrap_or(None);
def get_env_int(env: dict, key: str, default: Optional[int] = None) -> int:
result = Result.of(lambda: int(env[key] or default));
if default is None:
return result.unwrap();
return result.unwrap_or(default);
def get_env_optional_int(env: dict, key: str) -> Optional[int]:
result = Result.of(lambda: int(env[key]));
return result.unwrap_or(None);
def get_env_float(env: dict, key: str, default: Optional[float] = None) -> float:
result = Result.of(lambda: float(env[key] or default));
if default is None:
return result.unwrap();
return result.unwrap_or(default);
def get_env_optional_float(env: dict, key: str) -> Optional[float]:
result = Result.of(lambda: float(env[key]));
return result.unwrap_or(None);

163
src/core/log.py Normal file
View File

@ -0,0 +1,163 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from src.thirdparty.code import *;
from src.thirdparty.io import *;
from src.thirdparty.log import *;
from src.thirdparty.misc import *;
from src.thirdparty.types import *;
from src.core.calls import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__all__ = [
'LOG_LEVELS',
'configure_logging',
'log_info',
'log_debug',
'log_warn',
'log_error',
'log_fatal',
'log_result',
'log_dev',
'catch_fatal',
'prompt_user_input',
'prompt_secure_user_input',
'prompt_confirmation',
];
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# CONSTANTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LOG_LEVELS(Enum): # pragma: no cover
INFO = logging.INFO;
DEBUG = logging.DEBUG;
# local usage only
_LOGGING_DEBUG_FILE: str = 'logs/debug.log';
T = TypeVar('T');
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# METHODS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def configure_logging(level: LOG_LEVELS): # pragma: no cover
logging.basicConfig(
format = '%(asctime)s [\x1b[1m%(levelname)s\x1b[0m] %(message)s',
level = level.value,
datefmt = r'%Y-%m-%d %H:%M:%S',
);
return;
def log_debug(*messages: Any):
logging.debug(*messages);
def log_info(*messages: Any):
logging.info(*messages);
def log_warn(*messages: Any):
logging.warning(*messages);
def log_error(*messages: Any):
logging.error(*messages);
def log_fatal(*messages: Any):
logging.fatal(*messages);
exit(1);
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Special Methods
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Intercept fatal errors
def catch_fatal(method: Callable[[], T]) -> T:
try:
return method();
except Exception as e:
log_fatal(e);
def log_result(result: Result[CallState, CallState], debug: bool = False):
'''
Logs safely encapsulated result of call as either debug/info or error.
@inputs
- `result` - the result of the call.
- `debug = False` (default) - if the result is okay, will be logged as an INFO message.
- `debug = True` - if the result is okay, will be logged as a DEBUG message.
'''
if isinstance(result, Ok):
value = result.unwrap();
log_debug(value);
for x in value.data_log:
log_info(x);
else:
err = result.unwrap_err();
log_debug(err);
for e in err.errors:
log_error(e);
return;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# DEBUG LOGGING FOR DEVELOPMENT
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def log_dev(*messages: Any): # pragma: no cover
with open(_LOGGING_DEBUG_FILE, 'a') as fp:
print(*messages, file=fp);
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# User Input
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def prompt_user_input(message: str, expectedformat: Callable) -> Optional[str]:
answer = None;
while True:
try:
answer = input(f'{message}: ');
## Capture Meta+C:
except KeyboardInterrupt:
print('');
return None;
## Capture Meta+D:
except EOFError:
print('');
return None;
except:
continue;
if expectedformat(answer):
break;
return answer;
def prompt_secure_user_input(message: str, expectedformat: Callable) -> Optional[str]:
answer = None;
while True:
try:
## TODO: zeige **** ohne Zeilenumbruch an.
answer = getpass(f'{message}: ', stream=None);
## Capture Meta+C:
except KeyboardInterrupt:
print('');
return None;
## Capture Meta+D:
except EOFError:
print('');
return None;
except:
continue;
if expectedformat(answer):
break;
return answer;
def prompt_confirmation(message: str, default: bool = False) -> bool:
answer = prompt_user_input(message, lambda x: not not re.match(r'^(y|yes|j|ja|n|no|nein)$', x));
if isinstance(answer, str):
return True if re.match(r'^(y|yes|j|ja)$', answer) else False;
return default;

36
src/core/utils.py Normal file
View File

@ -0,0 +1,36 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from src.thirdparty.code import *;
from src.thirdparty.misc import *;
from src.thirdparty.types import *;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__all__ = [
'flatten',
'get_timestamp_string',
];
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# METHODS - date, time
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def get_timestamp() -> datetime: # pragma: no cover
return datetime.now();
def get_timestamp_string() -> str: # pragma: no cover
return str(get_timestamp());
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# METHODS arrays
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def flatten(X: list[list[Any]]) -> list[Any]:
return list(itertools_chain.from_iterable(X));

0
src/thirdparty/__init__.py vendored Normal file
View File

51
src/thirdparty/code.py vendored Normal file
View File

@ -0,0 +1,51 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from functools import partial;
from functools import reduce;
from functools import wraps;
from dataclasses import Field;
from dataclasses import MISSING;
from dataclasses import asdict;
from dataclasses import dataclass;
from dataclasses import field;
from itertools import chain as itertools_chain;
from itertools import product as itertools_product;
from operator import itemgetter;
from pydantic import BaseModel;
# cf. https://github.com/mplanchard/safetywrap
from safetywrap import Ok;
from safetywrap import Err;
from safetywrap import Nothing;
from safetywrap import Result;
from safetywrap import Option;
from safetywrap import Some;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__all__ = [
'partial',
'reduce',
'wraps',
'asdict',
'dataclass',
'field',
'Field',
'MISSING',
'itertools_chain',
'itertools_product',
'itemgetter',
'BaseModel',
'Err',
'Nothing',
'Ok',
'Option',
'Result',
'Some',
];

32
src/thirdparty/config.py vendored Normal file
View File

@ -0,0 +1,32 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from dotenv import load_dotenv;
from dotenv import dotenv_values;
import json;
import jsonschema;
from lazy_load import lazy;
from yaml import add_constructor;
from yaml import load as yaml_load;
from yaml import FullLoader as yaml_FullLoader;
from yaml import add_path_resolver as yaml_add_path_resolver;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__all__ = [
'load_dotenv',
'dotenv_values',
'json',
'jsonschema',
'lazy',
'add_constructor',
'yaml_load',
'yaml_FullLoader',
'yaml_add_path_resolver',
];

16
src/thirdparty/io.py vendored Normal file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from getpass import getpass;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__all__ = [
'getpass',
];

18
src/thirdparty/log.py vendored Normal file
View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import logging;
from logging import LogRecord;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__all__ = [
'logging',
'LogRecord',
];

22
src/thirdparty/maths.py vendored Normal file
View File

@ -0,0 +1,22 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from fractions import Fraction;
import math;
import numpy as np;
import random;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__all__ = [
'Fraction',
'math',
'np',
'random',
];

24
src/thirdparty/misc.py vendored Normal file
View File

@ -0,0 +1,24 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from datetime import datetime;
from datetime import timedelta;
import lorem;
import re;
from textwrap import dedent;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__all__ = [
'lorem',
're',
'datetime',
'timedelta',
'dedent',
];

27
src/thirdparty/render.py vendored Normal file
View File

@ -0,0 +1,27 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from IPython.display import Latex;
from IPython.display import display_latex;
from IPython.display import display_png;
from IPython.display import display_markdown;
from IPython.display import display;
# from array_to_latex import to_ltx as array_to_latex; # <- has issues
from qiskit.visualization import array_to_latex;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__all__ = [
'Latex',
'display',
'display_latex',
'display_png',
'display_markdown',
'array_to_latex',
];

16
src/thirdparty/run.py vendored Normal file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from codetiming import Timer;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__all__ = [
'Timer',
];

20
src/thirdparty/system.py vendored Normal file
View File

@ -0,0 +1,20 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import os;
from pathlib import Path;
import sys;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__all__ = [
'os',
'Path',
'sys',
];

84
src/thirdparty/types.py vendored Normal file
View File

@ -0,0 +1,84 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from enum import Enum;
from io import BytesIO;
from nptyping import NDArray;
from nptyping import Shape;
from nptyping import Bool;
from nptyping import UInt;
from nptyping import UInt8;
from nptyping import UInt32;
from nptyping import UInt64;
from nptyping import Int;
from nptyping import Int32;
from nptyping import Int64;
from nptyping import Float;
from nptyping import Float32;
from nptyping import Float64;
from numpy import uint8;
from numpy import int32;
from numpy import int64;
from numpy import float32;
from numpy import float64;
from numpy import complex64;
from numpy import complex128;
from pydantic import conint;
from typing import Any;
from typing import Awaitable;
from typing import Callable;
from typing import ClassVar;
from typing import Coroutine;
from typing import Generator;
from typing import Generic;
from typing import Optional;
from typing import Type;
from typing import TypeVar;
from typing_extensions import Concatenate;
from typing_extensions import ParamSpec;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__all__ = [
'Enum',
'BytesIO',
'NDArray',
'Shape',
'Bool',
'UInt',
'UInt8',
'UInt32',
'UInt64',
'Int',
'Int32',
'Int64',
'Float',
'Float32',
'Float64',
'uint8',
'int32',
'int64',
'float32',
'float64',
'complex64',
'complex128',
'conint',
'Any',
'Awaitable',
'Callable',
'ClassVar',
'Coroutine',
'Generator',
'Generic',
'Optional',
'Type',
'TypeVar',
'Concatenate',
'ParamSpec',
];

View File

0
templates/template.env Normal file
View File

1
tests/README.md Normal file
View File

@ -0,0 +1 @@
# Tests #