From 5f296f8447c0f839a3669a06d9ed3412aeee76d1 Mon Sep 17 00:00:00 2001 From: raj_mathe Date: Mon, 10 Oct 2022 11:17:09 +0200 Subject: [PATCH] main > main: init --- .coveragerc | 22 +++ .gitignore | 86 +++++++++++ LICENSE | 0 README.md | 77 ++++++++++ justfile | 259 +++++++++++++++++++++++++++++++++ main.py | 28 ++++ pyproject.toml | 57 ++++++++ requirements.txt | 49 +++++++ templates/template-config.yaml | 0 templates/template.env | 0 10 files changed, 578 insertions(+) create mode 100644 .coveragerc create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 justfile create mode 100644 main.py create mode 100644 pyproject.toml create mode 100644 requirements.txt create mode 100644 templates/template-config.yaml create mode 100644 templates/template.env diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..2068dde --- /dev/null +++ b/.coveragerc @@ -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 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fd2b917 --- /dev/null +++ b/.gitignore @@ -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 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md new file mode 100644 index 0000000..41c9444 --- /dev/null +++ b/README.md @@ -0,0 +1,77 @@ +# Mathematik für Physiker 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. diff --git a/justfile b/justfile new file mode 100644 index 0000000..ba44a40 --- /dev/null +++ b/justfile @@ -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" diff --git a/main.py b/main.py new file mode 100644 index 0000000..c106cd8 --- /dev/null +++ b/main.py @@ -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(); diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..81cc22a --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,57 @@ +[project] +name = "course-mathe-fuer-physiker-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 +] diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..1f448d0 --- /dev/null +++ b/requirements.txt @@ -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 diff --git a/templates/template-config.yaml b/templates/template-config.yaml new file mode 100644 index 0000000..e69de29 diff --git a/templates/template.env b/templates/template.env new file mode 100644 index 0000000..e69de29