6 Commits
Author SHA1 Message Date
mathias2784 605f423ff0 gitea workflow
Tests / test_and_lint (push) Failing after 6s
2026-10-01 17:27:50 +02:00
mathias2784 e78d55759c fix some tests concerning logging 2026-10-01 17:27:29 +02:00
mathias2784 0cb912466e test data 2026-10-01 17:18:24 +02:00
mathias2784 36eff17046 filedialogs 2026-10-01 17:18:04 +02:00
mathias2784 5d34b8eeaf misc 2026-10-01 17:17:36 +02:00
mathias2784 6696ff900e pyproject update 2026-10-01 17:17:07 +02:00
9 changed files with 228 additions and 4 deletions
+24
View File
@@ -0,0 +1,24 @@
---
name: Tests
on: [push]
jobs:
test_and_lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.14"
- name: Install uv
run: pip install uv
- name: Install dependencies
run: uv sync --frozen
- name: Run pytest
run: uv run pytest .
- name: Check formatting (black)
run: uv run black --check . --extend-exclude .venv
- name: Lint (ruff)
run: uv run ruff check .
+3
View File
@@ -9,6 +9,9 @@ authors = [
requires-python = ">=3.14" requires-python = ">=3.14"
dependencies = [ dependencies = [
"pydantic>=2.13.5", "pydantic>=2.13.5",
"pydantic-settings>=2.15.0",
"pytest>=9.1.1",
"tk>=0.1.0",
"twine>=7.0.0", "twine>=7.0.0",
"uvicorn>=0.54.0", "uvicorn>=0.54.0",
] ]
+44
View File
@@ -0,0 +1,44 @@
import tkinter
import tkinter.filedialog
def get_dir_path_from_dialog(**kwargs):
"""Open a native directory picker and return the selected path.
All ``kwargs`` are passed through unchanged to
:func:`tkinter.filedialog.askdirectory`. The most useful ones:
- ``initialdir`` (str): directory the dialog opens in.
- ``title`` (str): title of the dialog window.
- ``mustexist`` (bool, default ``True``): only return existing directories.
Returns an empty string if the user cancels the dialog.
"""
root = tkinter.Tk()
root.withdraw()
try:
return tkinter.filedialog.askdirectory(**kwargs)
finally:
root.destroy()
def get_file_path_from_dialog(**kwargs):
"""Open a native file picker and return the selected file path.
All ``kwargs`` are passed through unchanged to
:func:`tkinter.filedialog.askopenfilename`. The most useful ones:
- ``initialdir`` (str): directory the dialog opens in.
- ``initialfile`` (str): file pre-selected in the dialog.
- ``filetypes`` (list of (label, pattern) tuples): restrict which files
are shown, e.g. ``[("Text files", "*.txt"), ("All files", "*")]``.
- ``title`` (str): title of the dialog window.
Returns an empty string if the user cancels the dialog.
"""
root = tkinter.Tk()
root.withdraw()
try:
return tkinter.filedialog.askopenfilename(**kwargs)
finally:
root.destroy()
+8
View File
@@ -0,0 +1,8 @@
def readlines(path: str) -> list[str]:
with open(path, "r") as fid:
lines = fid.readlines()
return lines
def read(path: str) -> str:
return "".join(readlines(path))
+3
View File
@@ -0,0 +1,3 @@
This is a test file
with a second line
and a third line
+35
View File
@@ -0,0 +1,35 @@
from unittest import mock
from utils.filedialogs import get_dir_path_from_dialog, get_file_path_from_dialog
def test_get_dir_path_from_dialog_returns_selected_path():
with mock.patch("tkinter.Tk"), mock.patch(
"tkinter.filedialog.askdirectory", return_value="/tmp/somewhere"
) as dialog:
result = get_dir_path_from_dialog(initialdir="/tmp", title="Pick")
assert result == "/tmp/somewhere"
dialog.assert_called_once_with(initialdir="/tmp", title="Pick")
def test_get_dir_path_from_dialog_returns_empty_string_on_cancel():
with mock.patch("tkinter.Tk"), mock.patch(
"tkinter.filedialog.askdirectory", return_value=""
):
assert get_dir_path_from_dialog() == ""
def test_get_file_path_from_dialog_returns_selected_path():
with mock.patch("tkinter.Tk"), mock.patch(
"tkinter.filedialog.askopenfilename", return_value="/tmp/file.txt"
) as dialog:
result = get_file_path_from_dialog(filetypes=[("Text", "*.txt")])
assert result == "/tmp/file.txt"
dialog.assert_called_once_with(filetypes=[("Text", "*.txt")])
def test_get_file_path_from_dialog_returns_empty_string_on_cancel():
with mock.patch("tkinter.Tk"), mock.patch(
"tkinter.filedialog.askopenfilename", return_value=""
):
assert get_file_path_from_dialog() == ""
+3 -3
View File
@@ -7,10 +7,10 @@ from pathlib import Path
from unittest.mock import patch from unittest.mock import patch
import pytest import pytest
from pydantic import ValidationError
from uvicorn.logging import DefaultFormatter from uvicorn.logging import DefaultFormatter
from dataflex_backend_common.logging_config import LoggingSettings from utils.logging_config import LoggingSettings
from pydantic import ValidationError
SECONDS_PER_DAY = 24 * 60 * 60 SECONDS_PER_DAY = 24 * 60 * 60
@@ -41,7 +41,7 @@ def test_sets_valid_log_level(restore_root_logger: None) -> None:
def test_invalid_log_level_falls_back_to_info(restore_root_logger: None) -> None: def test_invalid_log_level_falls_back_to_info(restore_root_logger: None) -> None:
with patch("dataflex_backend_common.logging_config.logger.error") as log_error: with patch("utils.logging_config.logger.error") as log_error:
LoggingSettings(LOG_LEVEL="NOT_A_LEVEL", LOG_TO_FILE=False) LoggingSettings(LOG_LEVEL="NOT_A_LEVEL", LOG_TO_FILE=False)
assert logging.getLogger().level == logging.INFO assert logging.getLogger().level == logging.INFO
+26
View File
@@ -0,0 +1,26 @@
from pathlib import Path
from utils.misc import read, readlines
CWD = Path(__file__).parent.resolve()
TEST_DATA_DIR = CWD / "data"
TEST_FILE_PATH = TEST_DATA_DIR / "text.txt"
EXPECTED_TEST = """This is a test file
with a second line
and a third line
"""
def test_readlines_str():
result = readlines(TEST_FILE_PATH)
assert result
assert isinstance(result, list)
assert all(isinstance(element, str) for element in result)
assert result[1].strip() == "with a second line"
def test_path_str():
result = read(TEST_FILE_PATH)
assert result
assert isinstance(result, str)
assert result == EXPECTED_TEST
Generated
+82 -1
View File
@@ -154,6 +154,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl", hash = "sha256:255bc9599cf7748b4b1a446ccc735421bd08a2ae529a8b88597d3de5664ee360", size = 125251, upload-time = "2026-08-26T13:33:12.928Z" }, { url = "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl", hash = "sha256:255bc9599cf7748b4b1a446ccc735421bd08a2ae529a8b88597d3de5664ee360", size = 125251, upload-time = "2026-08-26T13:33:12.928Z" },
] ]
[[package]]
name = "colorama"
version = "0.4.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
]
[[package]] [[package]]
name = "cryptography" name = "cryptography"
version = "50.0.2" version = "50.0.2"
@@ -240,6 +249,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl", hash = "sha256:ab7ae7122974553370f0bdb919e1a960b2cd1bc1ef0276416d896db81c14582c", size = 69583, upload-time = "2026-09-17T14:11:03.168Z" }, { url = "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl", hash = "sha256:ab7ae7122974553370f0bdb919e1a960b2cd1bc1ef0276416d896db81c14582c", size = 69583, upload-time = "2026-09-17T14:11:03.168Z" },
] ]
[[package]]
name = "iniconfig"
version = "2.3.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
]
[[package]] [[package]]
name = "jaraco-classes" name = "jaraco-classes"
version = "3.4.0" version = "3.4.0"
@@ -372,6 +390,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" }, { url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" },
] ]
[[package]]
name = "pluggy"
version = "1.6.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
]
[[package]] [[package]]
name = "pycparser" name = "pycparser"
version = "3.0" version = "3.0"
@@ -437,6 +464,20 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/63/19/67830dda664e6bdf9285ee2e40f355d0d7d6b92aa0c42e8d217bb8d33d36/pydantic_core-2.46.5-cp314-cp314t-win_arm64.whl", hash = "sha256:acf8a67ba51f4ca9ddbd0e6b3000a65ac51ab734661778b3e7ba64d99a710f2f", size = 1989276, upload-time = "2026-08-28T10:00:16.984Z" }, { url = "https://files.pythonhosted.org/packages/63/19/67830dda664e6bdf9285ee2e40f355d0d7d6b92aa0c42e8d217bb8d33d36/pydantic_core-2.46.5-cp314-cp314t-win_arm64.whl", hash = "sha256:acf8a67ba51f4ca9ddbd0e6b3000a65ac51ab734661778b3e7ba64d99a710f2f", size = 1989276, upload-time = "2026-08-28T10:00:16.984Z" },
] ]
[[package]]
name = "pydantic-settings"
version = "2.15.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pydantic" },
{ name = "python-dotenv" },
{ name = "typing-inspection" },
]
sdist = { url = "https://files.pythonhosted.org/packages/68/ca/31c57507b13119d7d3cfa1576dad2911a4861e3be07b579395f4e9d393f9/pydantic_settings-2.15.0.tar.gz", hash = "sha256:694b793e84f766ba76a90ebdefc01d0a9a045dab0382bee70393da93712ad117", size = 261253, upload-time = "2026-08-07T09:24:57.419Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl", hash = "sha256:0ba092c291c94baceb5eff768aa0d56400a457585bc0175925a5a5510303da42", size = 69413, upload-time = "2026-08-07T09:24:55.839Z" },
]
[[package]] [[package]]
name = "pygments" name = "pygments"
version = "2.21.0" version = "2.21.0"
@@ -446,6 +487,31 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl", hash = "sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9", size = 1250147, upload-time = "2026-08-17T08:02:44.912Z" }, { url = "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl", hash = "sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9", size = 1250147, upload-time = "2026-08-17T08:02:44.912Z" },
] ]
[[package]]
name = "pytest"
version = "9.1.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
{ name = "iniconfig" },
{ name = "packaging" },
{ name = "pluggy" },
{ name = "pygments" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" },
]
[[package]]
name = "python-dotenv"
version = "1.2.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/74/26/2fbeedb218a787a5eea551c7532cac4e009f83d689dd2faa0d0353473f86/python_dotenv-1.2.4.tar.gz", hash = "sha256:f0d53e69935a851c0dcc78f3ab7aaccd8cabef0b92382b576b824212902873c0", size = 60824, upload-time = "2026-10-01T05:36:10Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/60/d1/38f3a3405989a89ac18390803e70c6ad7c7760da4f9b83cbeca0c44a0c72/python_dotenv-1.2.4-py3-none-any.whl", hash = "sha256:42269a8a5b3fd54ffa6f3d84b18abed50064717576b4ecf03dc4a55d8aa04fdc", size = 23266, upload-time = "2026-10-01T05:36:08.633Z" },
]
[[package]] [[package]]
name = "pywin32-ctypes" name = "pywin32-ctypes"
version = "0.2.3" version = "0.2.3"
@@ -531,6 +597,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl", hash = "sha256:0ce65888c0725fcb2c5bc0fdb8e5438eece02c523557ea40ce0703c266248137", size = 15554, upload-time = "2025-11-23T19:02:51.545Z" }, { url = "https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl", hash = "sha256:0ce65888c0725fcb2c5bc0fdb8e5438eece02c523557ea40ce0703c266248137", size = 15554, upload-time = "2025-11-23T19:02:51.545Z" },
] ]
[[package]]
name = "tk"
version = "0.1.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a0/81/742b342fd642e672fbedecde725ba44db44e800dc4c936216c3c6729885a/tk-0.1.0.tar.gz", hash = "sha256:60bc8923d5d35f67f5c6bd93d4f0c49d2048114ec077768f959aef36d4ed97f8", size = 2247, upload-time = "2019-07-08T06:51:58.051Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1e/0b/029cbdb868bb555fed99bf6540fff072d500b3f895873709f25084e85e33/tk-0.1.0-py3-none-any.whl", hash = "sha256:703a69ff0d5ba2bd2f7440582ad10160e4a6561595d33457dc6caa79b9bf4930", size = 3879, upload-time = "2019-07-08T06:51:55.175Z" },
]
[[package]] [[package]]
name = "twine" name = "twine"
version = "7.0.0" version = "7.0.0"
@@ -583,10 +658,13 @@ wheels = [
[[package]] [[package]]
name = "utils" name = "utils"
version = "0.1.0" version = "0.1.1"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "pydantic" }, { name = "pydantic" },
{ name = "pydantic-settings" },
{ name = "pytest" },
{ name = "tk" },
{ name = "twine" }, { name = "twine" },
{ name = "uvicorn" }, { name = "uvicorn" },
] ]
@@ -594,6 +672,9 @@ dependencies = [
[package.metadata] [package.metadata]
requires-dist = [ requires-dist = [
{ name = "pydantic", specifier = ">=2.13.5" }, { name = "pydantic", specifier = ">=2.13.5" },
{ name = "pydantic-settings", specifier = ">=2.15.0" },
{ name = "pytest", specifier = ">=9.1.1" },
{ name = "tk", specifier = ">=0.1.0" },
{ name = "twine", specifier = ">=7.0.0" }, { name = "twine", specifier = ">=7.0.0" },
{ name = "uvicorn", specifier = ">=0.54.0" }, { name = "uvicorn", specifier = ">=0.54.0" },
] ]