diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..85f1302 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: Bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..bbcbbe7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/spec-request.md b/.github/ISSUE_TEMPLATE/spec-request.md new file mode 100644 index 0000000..2c366e0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/spec-request.md @@ -0,0 +1,20 @@ +--- +name: Spec Request +about: Suggest an idea for this project +title: '' +labels: spec request +assignees: AidanJohnston + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml new file mode 100644 index 0000000..ec3b395 --- /dev/null +++ b/.github/workflows/github-actions.yml @@ -0,0 +1,186 @@ +name: build +on: [push, pull_request] +jobs: + test: + name: ${{ matrix.name }} + runs-on: ${{ matrix.os }} + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + include: + - name: 'check' + python: '3.11' + toxpython: 'python3.11' + tox_env: 'check' + os: 'ubuntu-latest' + - name: 'docs' + python: '3.11' + toxpython: 'python3.11' + tox_env: 'docs' + os: 'ubuntu-latest' + - name: 'py38 (ubuntu)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38' + os: 'ubuntu-latest' + - name: 'py38 (windows)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38' + os: 'windows-latest' + - name: 'py38 (macos)' + python: '3.8' + toxpython: 'python3.8' + python_arch: 'x64' + tox_env: 'py38' + os: 'macos-latest' + - name: 'py39 (ubuntu)' + python: '3.9' + toxpython: 'python3.9' + python_arch: 'x64' + tox_env: 'py39' + os: 'ubuntu-latest' + - name: 'py39 (windows)' + python: '3.9' + toxpython: 'python3.9' + python_arch: 'x64' + tox_env: 'py39' + os: 'windows-latest' + - name: 'py39 (macos)' + python: '3.9' + toxpython: 'python3.9' + python_arch: 'x64' + tox_env: 'py39' + os: 'macos-latest' + - name: 'py310 (ubuntu)' + python: '3.10' + toxpython: 'python3.10' + python_arch: 'x64' + tox_env: 'py310' + os: 'ubuntu-latest' + - name: 'py310 (windows)' + python: '3.10' + toxpython: 'python3.10' + python_arch: 'x64' + tox_env: 'py310' + os: 'windows-latest' + - name: 'py310 (macos)' + python: '3.10' + toxpython: 'python3.10' + python_arch: 'x64' + tox_env: 'py310' + os: 'macos-latest' + - name: 'py311 (ubuntu)' + python: '3.11' + toxpython: 'python3.11' + python_arch: 'x64' + tox_env: 'py311' + os: 'ubuntu-latest' + - name: 'py311 (windows)' + python: '3.11' + toxpython: 'python3.11' + python_arch: 'x64' + tox_env: 'py311' + os: 'windows-latest' + - name: 'py311 (macos)' + python: '3.11' + toxpython: 'python3.11' + python_arch: 'x64' + tox_env: 'py311' + os: 'macos-latest' + - name: 'py312 (ubuntu)' + python: '3.12' + toxpython: 'python3.12' + python_arch: 'x64' + tox_env: 'py312' + os: 'ubuntu-latest' + - name: 'py312 (windows)' + python: '3.12' + toxpython: 'python3.12' + python_arch: 'x64' + tox_env: 'py312' + os: 'windows-latest' + - name: 'py312 (macos)' + python: '3.12' + toxpython: 'python3.12' + python_arch: 'x64' + tox_env: 'py312' + os: 'macos-latest' + - name: 'pypy38 (ubuntu)' + python: 'pypy-3.8' + toxpython: 'pypy3.8' + python_arch: 'x64' + tox_env: 'pypy38' + os: 'ubuntu-latest' + - name: 'pypy38 (windows)' + python: 'pypy-3.8' + toxpython: 'pypy3.8' + python_arch: 'x64' + tox_env: 'pypy38' + os: 'windows-latest' + - name: 'pypy38 (macos)' + python: 'pypy-3.8' + toxpython: 'pypy3.8' + python_arch: 'x64' + tox_env: 'pypy38' + os: 'macos-latest' + - name: 'pypy39 (ubuntu)' + python: 'pypy-3.9' + toxpython: 'pypy3.9' + python_arch: 'x64' + tox_env: 'pypy39' + os: 'ubuntu-latest' + - name: 'pypy39 (windows)' + python: 'pypy-3.9' + toxpython: 'pypy3.9' + python_arch: 'x64' + tox_env: 'pypy39' + os: 'windows-latest' + - name: 'pypy39 (macos)' + python: 'pypy-3.9' + toxpython: 'pypy3.9' + python_arch: 'x64' + tox_env: 'pypy39' + os: 'macos-latest' + - name: 'pypy310 (ubuntu)' + python: 'pypy-3.10' + toxpython: 'pypy3.10' + python_arch: 'x64' + tox_env: 'pypy310' + os: 'ubuntu-latest' + - name: 'pypy310 (windows)' + python: 'pypy-3.10' + toxpython: 'pypy3.10' + python_arch: 'x64' + tox_env: 'pypy310' + os: 'windows-latest' + - name: 'pypy310 (macos)' + python: 'pypy-3.10' + toxpython: 'pypy3.10' + python_arch: 'x64' + tox_env: 'pypy310' + os: 'macos-latest' + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: recursive + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python }} + architecture: ${{ matrix.python_arch }} + - name: install dependencies + run: | + python -mpip install --progress-bar=off -r ci/requirements.txt + virtualenv --version + pip --version + tox --version + pip list --format=freeze + - name: test + env: + TOXPYTHON: '${{ matrix.toxpython }}' + run: > + tox -e ${{ matrix.tox_env }} -v diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 248fb42..0000000 --- a/.gitmodules +++ /dev/null @@ -1,7 +0,0 @@ -[submodule "extern/pybind11"] - path = extern/pybind11 - url = ../../pybind/pybind11 - branch = stable -[submodule "extern/json"] - path = extern/json - url = https://github.com/nlohmann/json diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 166d498..82076f3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,11 @@ Changelog ========= +0.1.0 (2024-05-21) +------------------ + +* Initial dataclasses for sensor and resolution. + 0.0.0 (2024-01-08) ------------------ diff --git a/MANIFEST.in b/MANIFEST.in index d0dac9c..93152ec 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -4,12 +4,11 @@ graft ci graft tests include .bumpversion.cfg -include .cookiecutterrc -include .coveragerc +include CMakeLists.txt include .editorconfig include .github/workflows/github-actions.yml include .pre-commit-config.yaml -include .readthedocs.yml +include .readthedocs.yaml include pytest.ini include tox.ini diff --git a/README.rst b/README.rst index 5705f62..f17d71b 100644 --- a/README.rst +++ b/README.rst @@ -2,33 +2,36 @@ RASAL ===== + Resolution and Sensors and Lens. -.. class:: center +.. start-badges + +.. image:: https://readthedocs.org/projects/rasal/badge/?version=latest&style=flat-square + :target: https://rasal.readthedocs.io/en/latest/?badge=latest + :alt: Documentation Status + +.. image:: https://img.shields.io/pypi/v/rasal.svg?style=flat-square + :alt: PyPI Package latest release + :target: https://pypi.org/project/rasal - .. image:: https://readthedocs.org/projects/rasal/badge/?version=latest&style=flat-square - :target: https://rasal.readthedocs.io/en/latest/?badge=latest - :alt: Documentation Status +.. image:: https://img.shields.io/pypi/dm/rasal?style=flat-square + :alt: PyPi Package Downloads + :target: https://pypi.org/project/rasal - .. image:: https://img.shields.io/pypi/v/rasal.svg?style=flat-square - :alt: PyPI Package latest release - :target: https://pypi.org/project/rasal +.. image:: https://img.shields.io/pypi/wheel/rasal.svg?style=flat-square + :alt: PyPI Wheel + :target: https://pypi.org/project/rasal - .. image:: https://img.shields.io/pypi/dm/rasal?style=flat-square - :alt: PyPi Package Downloads - :target: https://pypi.org/project/rasal - - .. image:: https://img.shields.io/pypi/wheel/rasal.svg?style=flat-square - :alt: PyPI Wheel - :target: https://pypi.org/project/rasal +.. image:: https://img.shields.io/pypi/pyversions/rasal.svg?style=flat-square + :alt: Supported versions + :target: https://pypi.org/project/rasal - .. image:: https://img.shields.io/pypi/pyversions/rasal.svg?style=flat-square - :alt: Supported versions - :target: https://pypi.org/project/rasal +.. image:: https://img.shields.io/pypi/implementation/rasal.svg?style=flat-square + :alt: Supported implementations + :target: https://pypi.org/project/rasal - .. image:: https://img.shields.io/pypi/implementation/rasal.svg?style=flat-square - :alt: Supported implementations - :target: https://pypi.org/project/rasal +.. end-badges Installation ============ diff --git a/ci/templates/.github/workflows/github-actions.yml b/ci/templates/.github/workflows/github-actions.yml index d6b9e77..bc2748d 100644 --- a/ci/templates/.github/workflows/github-actions.yml +++ b/ci/templates/.github/workflows/github-actions.yml @@ -47,6 +47,7 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 + submodules: recursive - uses: actions/setup-python@v5 with: python-version: {{ '${{ matrix.python }}' }} diff --git a/docs/conf.py b/docs/conf.py index c357990..81c0bbd 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,4 +1,3 @@ -import furo extensions = [ "sphinx.ext.autodoc", diff --git a/extern/json b/extern/json deleted file mode 160000 index 7efe875..0000000 --- a/extern/json +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7efe875495a3ed7d805ddbb01af0c7725f50c88b diff --git a/extern/pybind11 b/extern/pybind11 deleted file mode 160000 index 8b03ffa..0000000 --- a/extern/pybind11 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8b03ffa7c06cd9c8a38297b1c8923695d1ff1b07 diff --git a/pyproject.toml b/pyproject.toml index f704ae4..702454e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,11 +16,11 @@ test-skip = ["*universal2:arm64"] before-build = "rm -rf {project}/build" -[tool.ruff.per-file-ignores] +[tool.ruff.lint.per-file-ignores] "ci/*" = ["S"] [tool.ruff] -extend-exclude = ["static", "ci/templates"] +extend-exclude = ["static", "ci/templates", "extern"] ignore = [ "RUF001", # ruff-specific rules ambiguous-unicode-character-string "S101", # flake8-bandit assert @@ -51,11 +51,11 @@ select = [ src = ["src", "tests"] target-version = "py38" -[tool.ruff.flake8-pytest-style] +[tool.ruff.lint.flake8-pytest-style] fixture-parentheses = false mark-parentheses = false -[tool.ruff.isort] +[tool.ruff.lint.isort] forced-separate = ["conftest"] force-single-line = true diff --git a/setup.py b/setup.py index 9c39272..c545ba9 100755 --- a/setup.py +++ b/setup.py @@ -1,14 +1,8 @@ #!/usr/bin/env python -import os import re -import subprocess -import sys from pathlib import Path -from setuptools import Extension, setup -from setuptools.command.build_ext import build_ext - -from pybind11.setup_helpers import Pybind11Extension, build_ext +from setuptools import find_packages, setup def read(*names, **kwargs): @@ -19,149 +13,14 @@ def read(*names, **kwargs): __name__ = "rasal" -__version__ = "0.0.1" - -# The main interface is through Pybind11Extension. -# * You can add cxx_std=11/14/17, and then build_ext can be removed. -# * You can set include_pybind11=false to add the include directory yourself, -# say from a submodule. -# - -# Convert distutils Windows platform specifiers to CMake -A arguments -PLAT_TO_CMAKE = { - "win32": "Win32", - "win-amd64": "x64", - "win-arm32": "ARM", - "win-arm64": "ARM64", -} - - -# A CMakeExtension needs a sourcedir instead of a file list. -# The name must be the _single_ output extension from the CMake build. -# If you need multiple extensions, see scikit-build. -class CMakeExtension(Extension): - def __init__(self, name: str, sourcedir: str = "") -> None: - super().__init__(name, sources=[]) - self.sourcedir = os.fspath(Path(sourcedir).resolve()) - - -class CMakeBuild(build_ext): - def build_extension(self, ext: CMakeExtension) -> None: - # Must be in this form due to bug in .resolve() only fixed in Python 3.10+ - ext_fullpath = Path.cwd() / self.get_ext_fullpath(ext.name) - extdir = ext_fullpath.parent.resolve() - - # Using this requires trailing slash for auto-detection & inclusion of - # auxiliary "native" libs - - debug = ( - int(os.environ.get("DEBUG", 0)) - if self.debug is None - else self.debug - ) - cfg = "Debug" if debug else "Release" - - # CMake lets you override the generator - we need to check this. - # Can be set with Conda-Build, for example. - cmake_generator = os.environ.get("CMAKE_GENERATOR", "") - - # Set Python_EXECUTABLE instead if you use PYBIND11_FINDPYTHON - # EXAMPLE_VERSION_INFO shows you how to pass a value into the C++ code - # from Python. - cmake_args = [ - f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={extdir}{os.sep}", - f"-DPYTHON_EXECUTABLE={sys.executable}", - f"-DCMAKE_BUILD_TYPE={cfg}", # not used on MSVC, but no harm - ] - build_args = [] - # Adding CMake arguments set as environment variable - # (needed e.g. to build for ARM OSx on conda-forge) - if "CMAKE_ARGS" in os.environ: - cmake_args += [ - item for item in os.environ["CMAKE_ARGS"].split(" ") if item - ] - - # In this example, we pass in the version to C++. You might not need to. - cmake_args += [ - f"-DEXAMPLE_VERSION_INFO={self.distribution.get_version()}" - ] - - if self.compiler.compiler_type != "msvc": - # Using Ninja-build since it a) is available as a wheel and b) - # multithreads automatically. MSVC would require all variables be - # exported for Ninja to pick it up, which is a little tricky to do. - # Users can override the generator with CMAKE_GENERATOR in CMake - # 3.15+. - if not cmake_generator or cmake_generator == "Ninja": - try: - import ninja - - ninja_executable_path = Path(ninja.BIN_DIR) / "ninja" - cmake_args += [ - "-GNinja", - f"-DCMAKE_MAKE_PROGRAM:FILEPATH={ninja_executable_path}", - ] - except ImportError: - pass - - else: - # Single config generators are handled "normally" - single_config = any( - x in cmake_generator for x in {"NMake", "Ninja"} - ) - - # CMake allows an arch-in-generator style for backward compatibility - contains_arch = any(x in cmake_generator for x in {"ARM", "Win64"}) - - # Specify the arch if using MSVC generator, but only if it doesn't - # contain a backward-compatibility arch spec already in the - # generator name. - if not single_config and not contains_arch: - cmake_args += ["-A", PLAT_TO_CMAKE[self.plat_name]] - - # Multi-config generators have a different way to specify configs - if not single_config: - cmake_args += [ - f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{cfg.upper()}={extdir}" - ] - build_args += ["--config", cfg] - - if sys.platform.startswith("darwin"): - # Cross-compile support for macOS - respect ARCHFLAGS if set - archs = re.findall(r"-arch (\S+)", os.environ.get("ARCHFLAGS", "")) - if archs: - cmake_args += [ - "-DCMAKE_OSX_ARCHITECTURES={}".format(";".join(archs)) - ] - - # Set CMAKE_BUILD_PARALLEL_LEVEL to control the parallel build level - # across all generators. - if "CMAKE_BUILD_PARALLEL_LEVEL" not in os.environ: - # self.parallel is a Python 3 only way to set parallel jobs by hand - # using -j in the build_ext call, not supported by pip or PyPA-build. - if hasattr(self, "parallel") and self.parallel: - # CMake 3.12+ only. - build_args += [f"-j{self.parallel}"] - - build_temp = Path(self.build_temp) / ext.name - if not build_temp.exists(): - build_temp.mkdir(parents=True) - - subprocess.run( - ["cmake", ext.sourcedir, *cmake_args], cwd=build_temp, check=True - ) - subprocess.run( - ["cmake", "--build", ".", *build_args], cwd=build_temp, check=True - ) - -ext_modules=[ - CMakeExtension("rasal", "./src/"), -] +__version__ = "0.1.0" setup( name=__name__, version=__version__, + package_dir={'': 'src'}, + packages=find_packages(where='src'), license="MIT", description="Resolution and Sensors and Lens.", long_description="{}\n{}".format( @@ -173,12 +32,7 @@ def build_extension(self, ext: CMakeExtension) -> None: author="Aidan Johnston", author_email="contact@aidanjohnston.ca", url="https://github.com/AidanJohnston/rasal", - # py_modules=[path.stem for path in Path("src").glob("*.py")], include_package_data=True, - ext_modules=ext_modules, - cmdclass={"build_ext": CMakeBuild}, - # Currently, build_ext only provides an optional "highest supported C++ - # level" feature, but in the future it may provide more features. zip_safe=False, classifiers=[ # complete classifier list: http://pypi.python.org/pypi?%3Aaction=list_classifiers @@ -195,27 +49,22 @@ def build_extension(self, ext: CMakeExtension) -> None: "Programming Language :: Python :: 3.12", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", - # uncomment if you test on these interpreters: - # "Programming Language :: Python :: Implementation :: IronPython", - # "Programming Language :: Python :: Implementation :: Jython", - # "Programming Language :: Python :: Implementation :: Stackless", "Topic :: Utilities", ], project_urls={ - "Documentation": "https://rasal.readthedocs.io/", + "Documentation": "https://rasal.readthedocs.io/en/latest", "Changelog": "https://rasal.readthedocs.io/en/latest/changelog.html", "Issue Tracker": "https://github.com/AidanJohnston/rasal/issues", }, keywords=[ - # eg: "keyword1", "keyword2", "keyword3", + "resolution", "sensor" "lens", ], python_requires=">=3.8", install_requires=[ # eg: "aspectlib==1.1.1", "six>=1.7", ], extras_require={ - # eg: - # "rst": ["docutils>=0.11"], - # ":python_version=="2.6"": ["argparse"], + "test": [ + ] }, ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt deleted file mode 100644 index 87aebb0..0000000 --- a/src/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -cmake_minimum_required(VERSION 3.4...3.18) -project(rasal) - -add_subdirectory(../extern/pybind11 ./extern/pybind11) -pybind11_add_module(rasal rasal/rasal.cpp) - -target_compile_definitions( - rasal - PRIVATE VERSION_INFO=${VERSION_INFO} -) diff --git a/src/rasal/CMakeLists.txt b/src/rasal/CMakeLists.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/rasal/__init__.py b/src/rasal/__init__.py new file mode 100644 index 0000000..889374b --- /dev/null +++ b/src/rasal/__init__.py @@ -0,0 +1,9 @@ +from ._sensor import Sensor +from ._resolution import Resolution +from ._lens import Lens + +__all__ = ( + "Sensor", + "Resolution", + "Lens", +) diff --git a/src/rasal/_lens.py b/src/rasal/_lens.py new file mode 100644 index 0000000..27470a0 --- /dev/null +++ b/src/rasal/_lens.py @@ -0,0 +1,2 @@ +class Lens(): + pass diff --git a/src/rasal/_resolution.py b/src/rasal/_resolution.py new file mode 100644 index 0000000..53a1e67 --- /dev/null +++ b/src/rasal/_resolution.py @@ -0,0 +1,40 @@ +"""Resolution classes and methods.""" + +class Resolution(): + """Data class for storing resolution.""" + + def __init__(self, width: int, height: int) -> None: + """Initialize the resolution. + + Args: + width (int): The pixel width of the resolution. + height (int): The pixel height of the resolution. + """ + self.width = width + self.height = height + + @property + def width(self) -> int: + """Pixel width of the resolution. + + Returns: + int: The width. + """ + return self._width + + @width.setter + def width(self, value: int): + self._width = int + + @property + def height(self) -> int: + """Pixel height of the resolution. + + Returns: + int: The height. + """ + return self._height + + @height.setter + def height(self, value: int): + self._height = value diff --git a/src/rasal/_sensor.py b/src/rasal/_sensor.py new file mode 100644 index 0000000..06c747c --- /dev/null +++ b/src/rasal/_sensor.py @@ -0,0 +1,98 @@ +from .units import Length + + +class Sensor(): + + def __init__( + self, + name: str, + width: Length, + height: Length, + squeeze: float + ) -> None: + """Initialize the sensor. + + Args: + name (str): The name of the sensor. + width (Length): The width of the sensor. + height (Length): The height of the sensors. + squeeze (float): Any squeeze applied to the sensor. + """ + self.width = width + self.height = height + self.squeeze = squeeze + self.name = name + + @property + def width(self) -> Length: + """The width of the sensor. + + Returns: + Length: The width. + """ + return self._width + + @width.setter + def width(self, value: Length): + self._width = value + + @property + def height(self) -> Length: + """The height of the sensor. + + Returns: + Length: The height. + """ + return self._height + + @width.setter + def height(self, value: Length): + self._height = value + + @property + def squeeze(self) -> float: + """The squeeze of the sensor. + + Returns: + float: The squeeze. + """ + return self._squeeze + + @squeeze.setter + def squeeze(self, value: float): + self._squeeze = value + + @property + def name(self) -> str: + """The name of the sensor. + + Returns: + str: The name. + """ + return self._name + + @name.setter + def name(self, value): + self._name = value + + def squeezed_width(self) -> Length: + """The "true" squeezed width of the sensor. + + Effectively just: + sensor.width * sensor.squeeze + + Returns: + Length: The resulting squeezed width. + """ + return self.width * self.squeeze + + def squeezed_height(self) -> Length: + """The "true" squeezed height of the sensor. + + Effectively just: + sensor.height * sensor.squeeze + + Returns: + Length: The resulting squeezed height. + """ + return self.height * self.squeeze diff --git a/src/rasal/_version.py b/src/rasal/_version.py new file mode 100644 index 0000000..b229178 --- /dev/null +++ b/src/rasal/_version.py @@ -0,0 +1,19 @@ +import logging +import importlib.metadata + + + +LOGGER = logging.getLogger(__name__) + +package_name = "rasal" + +# try: +__version__ = importlib.metadata.version(package_name) + +# except pkg_resources.DistributionNotFound: +# LOGGER.warning("Failed to find distribution of package %s.", package_name) +# __version__ = "unknown" + +__all__ = ( + "__version__", +) diff --git a/src/rasal/filmback.cpp b/src/rasal/filmback.cpp deleted file mode 100644 index e95f2e1..0000000 --- a/src/rasal/filmback.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "filmback.h" -#include "rasal.h" - - -RASAL_NAMESPACE_OPEN_SCOPE - -Filmback::Filmback() -{ - -} - -Filmback::~Filmback() -{ - -} - -RASAL_NAMESPACE_CLOSE_SCOPE diff --git a/src/rasal/filmback.h b/src/rasal/filmback.h deleted file mode 100644 index 0e2fd55..0000000 --- a/src/rasal/filmback.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef RASAL_FILMBACK_H -#define RASAL_FILMBACK_H - -#include "rasal.h" - -RASAL_NAMESPACE_OPEN_SCOPE - -class Filmback { - -}; - - -RASAL_NAMESPACE_CLOSE_SCOPE - - -#endif // RASAL_FILMBACK_H \ No newline at end of file diff --git a/src/rasal/lens/CMakeLists.txt b/src/rasal/lens/CMakeLists.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/rasal/lens/lens.cpp b/src/rasal/lens/lens.cpp deleted file mode 100644 index 0c78691..0000000 --- a/src/rasal/lens/lens.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "rasal.h" -#include "lens.h" - -RASAL_NAMESPACE_OPEN_SCOPE - -Lens::Lens() -{ - -} - -Lens::~Lens() -{ -} - -RASAL_NAMESPACE_CLOSE_SCOPE \ No newline at end of file diff --git a/src/rasal/lens/lens.h b/src/rasal/lens/lens.h deleted file mode 100644 index 1be27f0..0000000 --- a/src/rasal/lens/lens.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef RASAL_LENS_H -#define RASAL_LENS_H - -#include "rasal.h" - -RASAL_NAMESPACE_OPEN_SCOPE - -class Lens { - - private: - - public: - Lens(); - ~Lens(); -}; - -RASAL_NAMESPACE_CLOSE_SCOPE - -#endif // RASAl_LENS_H diff --git a/src/rasal/rasal.cpp b/src/rasal/rasal.cpp deleted file mode 100644 index cc06f96..0000000 --- a/src/rasal/rasal.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include - -#define STRINGIFY(x) #x -#define MACRO_STRINGIFY(x) STRINGIFY(x) - -/* - * _____ _____ _ - * | __ \ /\ / ____| /\ | | - * | |__) | / \ | (___ / \ | | - * | _ / / /\ \ \___ \ / /\ \ | | - * | | \ \ / ____ \ ____) / ____ \| |____ - * |_| \_\/_/ \_\_____/_/ \_\______| - * - */ - -int add(int i, int j) { - return i + j; -} - -namespace py = pybind11; - -PYBIND11_MODULE(rasal, m) { - m.doc() = R"pbdoc( - Resolution and Sensors and Lens. - - _____ _____ _ - | __ \ /\ / ____| /\ | | - | |__) | / \ | (___ / \ | | - | _ / / /\ \ \___ \ / /\ \ | | - | | \ \ / ____ \ ____) / ____ \| |____ - |_| \_\/_/ \_\_____/_/ \_\______| - )pbdoc"; - - m.def("add", &add, R"pbdoc( - Add two numbers - - Some other explanation about the add function. - )pbdoc"); - - m.def("subtract", [](int i, int j) { return i - j; }, R"pbdoc( - Subtract two numbers - - Some other explanation about the subtract function. - )pbdoc"); - -#ifdef VERSION_INFO - m.attr("__version__") = MACRO_STRINGIFY(VERSION_INFO); -#else - m.attr("__version__") = "dev"; -#endif -} \ No newline at end of file diff --git a/src/rasal/rasal.h b/src/rasal/rasal.h deleted file mode 100644 index be87b14..0000000 --- a/src/rasal/rasal.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef RASAL_H -#define RASAL_H - -#define RASAL_NS rasal - -#define RASAL_NAMESPACE_OPEN_SCOPE namespace RASAL_NS { -#define RASAL_NAMESPACE_CLOSE_SCOPE } - -RASAL_NAMESPACE_OPEN_SCOPE - -RASAL_NAMESPACE_CLOSE_SCOPE - -#endif // RASAL_H diff --git a/src/rasal/resolution.cpp b/src/rasal/resolution.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/rasal/resolution.h b/src/rasal/resolution.h deleted file mode 100644 index b48baa8..0000000 --- a/src/rasal/resolution.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef RASAL_RESOLUTION_H -#define RASAL_RESOLUTION_H - -#include "rasal.h" - -RASAL_NAMESPACE_OPEN_SCOPE - -RASAL_NAMESPACE_CLOSE_SCOPE - -#endif // RASAL_RESOLUTION_H diff --git a/src/rasal/sensor.cpp b/src/rasal/sensor.cpp deleted file mode 100644 index 4c64a68..0000000 --- a/src/rasal/sensor.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "rasal.h" -#include "sensor.h" - -RASAL_NAMESPACE_OPEN_SCOPE - -Sensor::Sensor (int width, int height) { - width = width; - height = height; -} - -float -Sensor::get_aspect_ratio() { - float ratio = width / height; - return ratio; -} - -RASAL_NAMESPACE_CLOSE_SCOPE diff --git a/src/rasal/sensor.h b/src/rasal/sensor.h deleted file mode 100644 index be82036..0000000 --- a/src/rasal/sensor.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef RASAL_SENSOR_H -#define RASAL_SENSOR_H - -#include "rasal.h" -#include "" - -RASAL_NAMESPACE_OPEN_SCOPE - -class Sensor -{ - private: - int width; - int height; - public: - Sensor(int width, int height); - float get_aspect_ratio(); - ~Sensor(); -}; - -RASAL_NAMESPACE_CLOSE_SCOPE - -PYBIND11_MODULE(RASAL_NS, m) { - pybind11::class_(m, "Sensor") - .def("get_aspect_ratio", &Sensor::get_aspect_ratio); -} - -#endif // RASAL_SENSOR_H diff --git a/src/rasal/units.py b/src/rasal/units.py new file mode 100644 index 0000000..d20fad3 --- /dev/null +++ b/src/rasal/units.py @@ -0,0 +1,237 @@ +from typing import Union + + +class Unit(type): + def __new__(cls, name: str, bases: tuple, **kwargs): + return super(Unit, cls).__new__(cls, name, bases, kwargs) + +class LengthUnit(Unit): + def __new__(cls, name: str, short_name: str, conversion_value: float): + bases = (Length, ) + return super().__new__( + cls, + name, + bases, + short_name=short_name, + conversion_value=conversion_value + ) + +class TimeUnit(Unit): + def __new__(cls, name: str, short_name: str, conversion_value: float): + bases = (Time, ) + return super().__new__( + cls, + name, + bases, + short_name=short_name, + conversion_value=conversion_value + ) + +class Measurement(): + def __init__(self, value: Union[int, float, complex]): + self._value = float(value) + + def to(self, unit): + return unit(self._value * distance_unit.conversion_value) + + def __str__(self): + return f"{self._value} {self.short_name}" + + def __neg__(self): + return self.__class__(-self._value) + + def __pos__(self): + raise NotImplementedError + + def __abs__(self): + return self.__class__(abs(self.value)) + + def __invert__(self): + raise NotImplementedError + + # Binary arithmetic operators + def __add__(self, other): + return self.__class__(self._value + other._value) + + def __sub__(self, other): + return self.__class__(self._value - other._value) + + def __mul__(self, other): + return self.__class__(self._value * other._value) + + def __matmul__(self, other): + raise NotImplementedError + + def __truediv__(self, other): + raise NotImplementedError + + def __floordiv__(self, other): + raise NotImplementedError + + def __mod__(self, other): + raise NotImplementedError + + def __divmod__(self, other): + raise NotImplementedError + + def __pow__(self, other, modulo=None): + raise NotImplementedError + + def __lshift__(self, other): + raise NotImplementedError + + def __rshift__(self, other): + raise NotImplementedError + + def __and__(self, other): + raise NotImplementedError + + def __xor__(self, other): + raise NotImplementedError + + def __or__(self, other): + raise NotImplementedError + + # Reflected binary arithmetic operators + def __radd__(self, other): + raise NotImplementedError + + def __rsub__(self, other): + raise NotImplementedError + + def __rmul__(self, other): + raise NotImplementedError + + def __rmatmul__(self, other): + raise NotImplementedError + + def __rtruediv__(self, other): + raise NotImplementedError + + def __rfloordiv__(self, other): + raise NotImplementedError + + def __rmod__(self, other): + raise NotImplementedError + + def __rdivmod__(self, other): + raise NotImplementedError + + def __rpow__(self, other, modulo=None): + raise NotImplementedError + + def __rlshift__(self, other): + raise NotImplementedError + + def __rrshift__(self, other): + raise NotImplementedError + + def __rand__(self, other): + raise NotImplementedError + + def __rxor__(self, other): + raise NotImplementedError + + def __ror__(self, other): + raise NotImplementedError + + # Augmented assignment operators + def __iadd__(self, other): + raise NotImplementedError + + def __isub__(self, other): + raise NotImplementedError + + def __imul__(self, other): + raise NotImplementedError + + def __imatmul__(self, other): + raise NotImplementedError + + def __itruediv__(self, other): + raise NotImplementedError + + def __ifloordiv__(self, other): + raise NotImplementedError + + def __imod__(self, other): + raise NotImplementedError + + def __ipow__(self, other, modulo=None): + raise NotImplementedError + + def __ilshift__(self, other): + raise NotImplementedError + + def __irshift__(self, other): + raise NotImplementedError + + def __iand__(self, other): + raise NotImplementedError + + def __ixor__(self, other): + raise NotImplementedError + + def __ior__(self, other): + raise NotImplementedError + + # Type conversion methods + def __int__(self): + raise NotImplementedError + + def __float__(self): + raise NotImplementedError + + def __complex__(self): + raise NotImplementedError + + def __index__(self): + raise NotImplementedError + + def __round__(self, ndigits=None): + raise NotImplementedError + + def __trunc__(self): + raise NotImplementedError + + def __floor__(self): + raise NotImplementedError + + def __ceil__(self): + raise NotImplementedError + +class Length(Measurement): + pass + +class Time(Measurement): + pass + + +Kilometer = LengthUnit("Kilometer", "km", 1000.0) +Meter = LengthUnit("Meter", "m", 1.0) +Centimeter = LengthUnit("Centimeter", "cm", 0.01) +Millimeter = LengthUnit("Millimeter", "mm", 0.001) + +Second = TimeUnit("Second", "s", 1.0) +Minute = TimeUnit("Minute", "m", 60.0) +Hour = TimeUnit("Hour", "h", 3600.0) +Day = TimeUnit("Day", "D", 86400.0) + +__all__ = ( + # Type Classes + "Unit", + "DistanceUnit", + "TimeUnit" + + # Distance Units + "Meter", + "Kilometer", + "Centimeter", + "Millimeter", + + # Time Units + "Second", + "Minute", + "Hour", + "Day", +) diff --git a/tests/test_import.py b/tests/test_import.py new file mode 100644 index 0000000..cfd8135 --- /dev/null +++ b/tests/test_import.py @@ -0,0 +1,15 @@ +"""Tests for importing the package.""" + +import importlib +import pkgutil + + +def test_import_rasal(): + """Test import of whole rasal package. + + Walks the package and imports each submodule. + """ + package_name = "rasal" + package = importlib.import_module(package_name) + for _, name, _ in pkgutil.walk_packages(package.__path__, package.__name__ + '.'): + importlib.import_module(name) diff --git a/tests/test_rasal.py b/tests/test_rasal.py deleted file mode 100644 index 54ee15e..0000000 --- a/tests/test_rasal.py +++ /dev/null @@ -1,6 +0,0 @@ - -import rasal - - -def test_rasal(): - assert rasal.add(1, 1) == 2 diff --git a/tox.ini b/tox.ini index 7d6a38e..afe8a53 100644 --- a/tox.ini +++ b/tox.ini @@ -34,7 +34,6 @@ setenv = PYTHONUNBUFFERED=yes passenv = * -usedevelop = false deps = pytest pytest-cov @@ -45,18 +44,15 @@ commands = deps = docutils check-manifest - pre-commit readme-renderer pygments isort -skip_install = true + pybind11 commands = python setup.py check --strict --metadata --restructuredtext check-manifest . - pre-commit run --all-files --show-diff-on-failure [testenv:docs] -usedevelop = true deps = -r{toxinidir}/docs/requirements.txt commands =