diff --git a/code/python/.coveragerc b/code/python/.coveragerc new file mode 100644 index 0000000..5c04fc8 --- /dev/null +++ b/code/python/.coveragerc @@ -0,0 +1,18 @@ +[run] +source="." + +[report] +show_missing = true +omit = + # ignore tests folder + tests/* + # ignore thirdparty imports + src/thirdparty/* + # ignore __init__ files (only used for exports) + **/__init__.py + # ignore main.py + main.py +# TODO: increase code-coverage: +precision = 0 +exclude_lines = + pragma: no cover diff --git a/code/python/.gitignore b/code/python/.gitignore index b6c71eb..199bcf1 100644 --- a/code/python/.gitignore +++ b/code/python/.gitignore @@ -6,10 +6,11 @@ ################################################################ !/.env -!/Makefile +!/justfile +!/.coveragerc !/README.md !/LICENSE -!/requirements +!/requirements.txt !/pyproject.toml ################################################################ @@ -19,6 +20,7 @@ !/src !/src/**/ !/src/**/*.py +!/main.py !/tests !/tests/**/ diff --git a/code/python/Makefile b/code/python/Makefile deleted file mode 100644 index 9726919..0000000 --- a/code/python/Makefile +++ /dev/null @@ -1,94 +0,0 @@ -SHELL:=/usr/bin/env bash -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Makefile -# NOTE: Do not change the contents of this file! -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -include .env - -################################ -# VARIABLES -################################ - -ARTEFACT_NAME:=${APPNAME} -PYTHON:=python3 -ifeq ($(OS),Windows_NT) -ARTEFACT_NAME:=${APPNAME}.exe -PYTHON=py -3 -endif - -################################ -# Macros -################################ - -define create_file_if_not_exists - @touch "$(1)"; -endef - -define create_folder_if_not_exists - if ! [ -d "$(1)" ]; then mkdir "$(1)"; fi -endef - -define delete_if_file_exists - @if [ -f "$(1)" ]; then rm "$(1)"; fi -endef - -define delete_if_folder_exists - @if [ -d "$(1)" ]; then rm -rf "$(1)"; fi -endef - -define clean_all_files - @find . -type f -name "$(1)" -exec basename {} \; - @find . -type f -name "$(1)" -exec rm {} \; 2> /dev/null -endef - -define clean_all_folders - @find . -type d -name "$(1)" -exec basename {} \; - @find . -type d -name "$(1)" -exec rm -rf {} \; 2> /dev/null -endef - -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# TARGETS -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -################################ -# BASIC TARGETS: setup, build, run -################################ -setup: check-system-requirements setup-no-checks -setup-no-checks: - @${PYTHON} -m pip install -r "requirements" -run: - @${PYTHON} src/main.py; -all: setup run -################################ -# TARGETS: testing -################################ -tests: unit-tests -unit-tests: - @# For logging purposes (since stdout is rechanneled): - @$(call delete_if_file_exists,logs/debug.log) - @$(call create_folder_if_not_exists,logs) - @$(call create_file_if_not_exists,logs/debug.log) - @# for python unit tests: - @${PYTHON} -m pytest tests --cache-clear --verbose -k test_ - @cat logs/debug.log -################################ -# AUXILIARY (INTERNAL TARGETS) -################################ -check-system-requirements: - @if ! ( ${PYTHON} --version >> /dev/null 2> /dev/null ); then \ - echo "Install Python 3.10.x first!"; \ - exit 1; \ - fi - @${PYTHON} --version -################################ -# TARGETS: clean -################################ -clean: - @echo "All system artefacts will be force removed." - @$(call clean_all_files,.DS_Store) - @echo "All build artefacts will be force removed." - @$(call clean_all_folders,__pycache__) - @$(call clean_all_folders,.pytest_cache) - @$(call delete_if_file_exists,dist/${ARTEFACT_NAME}) - @exit 0 diff --git a/code/python/justfile b/code/python/justfile new file mode 100644 index 0000000..e2aab57 --- /dev/null +++ b/code/python/justfile @@ -0,0 +1,147 @@ +set shell := [ "bash", "-uc" ] +_default: + @- just --unsorted --choose +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Justfile +# NOTE: Do not change the contents of this file! +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# VARIABLES +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +PYTHON := if os_family() == "windows" { "py -3" } else { "python3" } + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Macros +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +_create-file-if-not-exists fname: + @touch "{{fname}}"; + +_create-folder-if-not-exists path: + @if ! [ -d "{{path}}" ]; then mkdir "{{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 pattern: + @find . -type f -name "{{pattern}}" -exec basename {} \; 2> /dev/null + @- find . -type f -name "{{pattern}}" -exec rm {} \; 2> /dev/null + +_clean-all-folders pattern: + @find . -type d -name "{{pattern}}" -exec basename {} \; 2> /dev/null + @- find . -type d -name "{{pattern}}" -exec rm -rf {} \; 2> /dev/null + +_docker-build-and-log service: + @docker compose up --build -d {{service}} && docker compose logs -f --tail=0 {{service}} + +_docker-build-and-interact service container: + @docker compose up --build -d {{service}} && docker attach {{container}} + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# TARGETS +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# TARGETS: build +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +build: + @{{PYTHON}} -m pip install --disable-pip-version-check -r requirements.txt + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# TARGETS: run +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +run: + @{{PYTHON}} main.py + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# TARGETS: tests +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +tests: tests-unit +tests-logs: + @just _create-logs + @- just tests + @just _display-logs +tests-unit-logs: + @just _create-logs + @- just tests-unit + @just _display-logs +tests-unit: + @{{PYTHON}} -m pytest tests \ + --ignore=tests/integration \ + --cov-reset \ + --cov=. \ + 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 clean-sessions +clean-sessions: + @echo "All sessions will be force removed." + @- just _delete-if-folder-exists ".secrets" 2> /dev/null +clean-basic: + @echo "All system artefacts will be force removed." + @- just _clean-all-files ".DS_Store" 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" + @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 + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# TARGETS: logging, session +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +_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: requirements +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +check-system: + @echo "Operating System detected: {{os_family()}}." + @echo "Python command used: {{PYTHON}}." diff --git a/code/python/src/main.py b/code/python/main.py similarity index 84% rename from code/python/src/main.py rename to code/python/main.py index 2da3148..7fcc3f3 100644 --- a/code/python/src/main.py +++ b/code/python/main.py @@ -12,11 +12,11 @@ os.chdir(os.path.join(os.path.dirname(__file__), '..')); sys.path.insert(0, os.getcwd()); from src.core.log import *; -from src.local.maths import *; +from src.thirdparty.maths import *; from src.graphs.graph import *; from src.graphs.tarjan import *; from src.travel.naive import *; -from src.string_alignment.hirschberg import *; +from src.hirschberg import *; # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # GLOBAL CONSTANTS/VARIABLES @@ -41,8 +41,7 @@ def enter(): # verbose=True, # ); ## Beispiel für Seminarwoche 10 (Blatt 9): - hirschberg_algorithm_once( - # hirschberg_algorithm( + hirschberg_algorithm( # Y = 'ANSPANNEN', # X = 'ANSTRENGEN', # Y = 'AGAT', @@ -51,9 +50,14 @@ def enter(): X = 'happily ever, lol', # Y = 'apple', # X = 'happily', - mode = DisplayMode.COSTS, - # mode = DisplayMode.MOVES, - # mode = DisplayMode.COSTS_AND_MOVES, + once = True, + verb = VerboseMode.COSTS, + # verb = VerboseMode.MOVES, + # verb = VerboseMode.COSTS_AND_MOVES, + show = [ + # DisplayOptions.ATOMS, + # DisplayOptions.TREE, + ], ); return; diff --git a/code/python/pyproject.toml b/code/python/pyproject.toml index b691501..7d2fa11 100644 --- a/code/python/pyproject.toml +++ b/code/python/pyproject.toml @@ -1,8 +1,56 @@ +[project] +name = "uni-leipzig-ads-2-2022" +version = "1.0.0" +description = "Zusatzcode, um Algorithmen und Datenstrukturen im Kurs ADS2 zu demonstrieren." +authors = [ "Raj Dahya" ] +maintainers = [ "raj_mathe" ] +license = "MIT" +readme = "README.md" +python = "^3.10" +homepage = "https://gitea.math.uni-leipzig.de/raj_mathe" +repository = "https://gitea.math.uni-leipzig.de/raj_mathe/ads2_2022" +documentation = "https://gitea.math.uni-leipzig.de/raj_mathe/ads2_2022/README.md" +keywords = [ + "algorithmmen und datenstrukturen 2", + "sommersemester", + "2022", + "universität leipzig", +] +# 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 = [ - "**/test_*.py", + "**/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_", + "--no-cov-on-fail", + "--cov-report=term", + "--cov-config=.coveragerc", ] diff --git a/code/python/requirements b/code/python/requirements.txt similarity index 100% rename from code/python/requirements rename to code/python/requirements.txt