diff --git a/doc/changelog.d/160.added.md b/doc/changelog.d/160.added.md new file mode 100644 index 00000000..9521f2bc --- /dev/null +++ b/doc/changelog.d/160.added.md @@ -0,0 +1 @@ +Use typeguard to check types at runtime \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index 578e31a4..e06621e6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3060,6 +3060,24 @@ files = [ docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.2)", "pytest-mock", "pytest-mypy-testing"] +[[package]] +name = "typeguard" +version = "4.4.1" +description = "Run-time type checker for Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "typeguard-4.4.1-py3-none-any.whl", hash = "sha256:9324ec07a27ec67fc54a9c063020ca4c0ae6abad5e9f0f9804ca59aee68c6e21"}, + {file = "typeguard-4.4.1.tar.gz", hash = "sha256:0d22a89d00b453b47c49875f42b6601b961757541a2e1e0ef517b6e24213c21b"}, +] + +[package.dependencies] +typing-extensions = ">=4.10.0" + +[package.extras] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.3.0)"] +test = ["coverage[toml] (>=7)", "mypy (>=1.2.0)", "pytest (>=7)"] + [[package]] name = "typing-extensions" version = "4.12.2" @@ -3152,4 +3170,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<4.0" -content-hash = "eb3c7989aed9f9ebd32fe7451a03d115e0bd5983abc57147538faa2d7e7bcca8" +content-hash = "6098f169ddd1f4fafe8660999753cbdc0e3a83b9e51ac6b42fff565f72fb8edf" diff --git a/pyproject.toml b/pyproject.toml index 7a45c871..4eb686aa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,8 +32,8 @@ python = ">=3.10,<4.0" ansys-openapi-common = "^2.0.0" # Ensure PIP_INDEX_URL is not set in CI when reverting to a public version of the package. ansys-grantami-serverapi-openapi = "^4.0.0" +typeguard = "^4.4.1" -# Optional documentation dependencies [tool.poetry.group.doc] optional = true diff --git a/src/ansys/grantami/jobqueue/_models.py b/src/ansys/grantami/jobqueue/_models.py index d3cf582e..3b4d9b7a 100644 --- a/src/ansys/grantami/jobqueue/_models.py +++ b/src/ansys/grantami/jobqueue/_models.py @@ -32,6 +32,7 @@ from ansys.grantami.serverapi_openapi import api, models from ansys.openapi.common import UndefinedObjectWarning, Unset +from typeguard import typechecked class _DocumentedEnum(Enum): @@ -169,6 +170,7 @@ class JobFile: >>> attachment_file = JobFile(pathlib.Path(r"C:\test_results\pictures\sample_001\panel_front.png"), "./assets/panel_front.png") """ + @typechecked() def __init__(self, path: Union[str, pathlib.Path], virtual_path: Union[str, pathlib.Path]): self._path: pathlib.Path = pathlib.Path(path) virtual_path = pathlib.Path(virtual_path) @@ -665,6 +667,7 @@ class ExcelExportJobRequest(JobRequest): """ + @typechecked() def __init__( self, name: str, @@ -816,6 +819,7 @@ class ExcelImportJobRequest(ImportJobRequest): """ + @typechecked() def __init__( self, name: str, @@ -926,6 +930,7 @@ class TextImportJobRequest(ImportJobRequest): """ + @typechecked() def __init__( self, name: str, diff --git a/tests/test_job_requests.py b/tests/test_job_requests.py index a1e4fd54..ba8aa23b 100644 --- a/tests/test_job_requests.py +++ b/tests/test_job_requests.py @@ -24,6 +24,7 @@ import sys import pytest +from typeguard import TypeCheckError from ansys.grantami.jobqueue import ExcelImportJobRequest, JobFile, TextImportJobRequest from common import ( @@ -232,3 +233,28 @@ def test_identical_paths_raise_exception( def test_virtual_path_validation(virtual_path, expectation): with expectation: JobFile._validate_virtual_path(virtual_path) + + +class TestInvalidArgumentTypes: + def test_data_file(self): + with pytest.raises( + TypeCheckError, + match='argument "data_files" (.*) did not match any element in the union', + ): + ExcelImportJobRequest( + name="Test name", + description=None, + data_files=Path("file.data"), + ) + + def test_date(self): + with pytest.raises( + TypeCheckError, + match='argument "scheduled_execution_date" (.*) did not match any element in the union', + ): + ExcelImportJobRequest( + name="Test name", + description=None, + data_files=[Path("file.data")], + scheduled_execution_date="2024-11-15T20:50:20+00:00", + )