From 3eadb4d89ff74e52354de49938f911e02acc105f Mon Sep 17 00:00:00 2001 From: diviloper Date: Sun, 1 Dec 2024 02:08:50 +0100 Subject: [PATCH 01/21] Fix test workflow and add release workflow --- .github/workflows/release_and_publish.yml | 157 ++++++++++++++++++++++ .github/workflows/test.yml | 12 +- 2 files changed, 163 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/release_and_publish.yml diff --git a/.github/workflows/release_and_publish.yml b/.github/workflows/release_and_publish.yml new file mode 100644 index 00000000..7c5b8858 --- /dev/null +++ b/.github/workflows/release_and_publish.yml @@ -0,0 +1,157 @@ +name: Release and Publish PyMEOS + +on: + push: + tags: + - "v[0-9]+.[0-9]+.[0-9]+*" + +jobs: + checks: + name: Make checks + runs-on: ubuntu-latest + + outputs: + is_alpha: ${{ steps.check_alpha.outputs.is_alpha }} + is_beta: ${{ steps.check_beta.outputs.is_beta }} + is_rc: ${{ steps.check_rc.outputs.is_rc }} + is_prerelease: ${{ steps.check_prerelease.outputs.is_prerelease }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Check if publishing an alpha version + id: check_alpha + run: | + VERSION=${GITHUB_REF#refs/tags/} + + if [[ $VERSION =~ ^v[0-9]+\.[0-9]+\.[0-9]+-alpha ]]; then + echo "Releasing an alpha version." + echo "is_alpha=true" >> "$GITHUB_OUTPUT" + else + echo "is_alpha=false" >> "$GITHUB_OUTPUT" + fi + + - name: Check if publishing a beta version + id: check_beta + run: | + VERSION=${GITHUB_REF#refs/tags/} + + if [[ $VERSION =~ ^v[0-9]+\.[0-9]+\.[0-9]+-beta ]]; then + echo "Releasing a beta version." + echo "is_beta=true" >> "$GITHUB_OUTPUT" + else + echo "is_beta=false" >> "$GITHUB_OUTPUT" + fi + + - name: Check if publishing a release candidate version + id: check_rc + run: | + VERSION=${GITHUB_REF#refs/tags/} + + if [[ $VERSION =~ ^v[0-9]+\.[0-9]+\.[0-9]+-rc ]]; then + echo "Releasing an rc version." + echo "is_rc=true" >> "$GITHUB_OUTPUT" + else + echo "is_rc=false" >> "$GITHUB_OUTPUT" + fi + + - name: Check if publishing a prerelease version + id: check_prerelease + run: | + is_alpha=${{ steps.check_alpha.outputs.is_alpha }} + is_beta=${{ steps.check_beta.outputs.is_beta }} + is_rc=${{ steps.check_rc.outputs.is_rc }} + + if [ "$is_alpha" == "true" ] || [ "$is_beta" == "true" ] || [ "$is_rc" == "true" ]; then + echo "Releasing an prerelease version." + echo "is_prerelease=true" >> "$GITHUB_OUTPUT" + else + echo "is_prerelease=false" >> "$GITHUB_OUTPUT" + fi + + - name: Check package version matches tag + run: | + tag_version=${GITHUB_REF#refs/tags/v} + python_version=$(grep -oP '__version__ = "\K[^"]+' pymeos/__init__.py) + + if [[ "$tag_version" != "$python_version" ]]; then + echo "Tag Version ($tag_version) doesn't match Code Version ($python_version)" + echo "::error title=Version mismatch::Tag Version ($tag_version) doesn't match Code Version ($python_version)" + exit 1 + fi + + + build: + name: Build PyMEOS + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v3 + with: + python-version: 3.8 + cache: "pip" + + - name: Setup pip + run: | + python -m pip install --upgrade pip + python -m pip install build + + - name: Build package + run: python -m build + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + path: | + ./dist/pymeos-*.tar.gz + ./dist/pymeos-*.whl + + release: + name: Create GitHub Release + runs-on: ubuntu-latest + needs: [ checks, build ] + + permissions: + contents: write + + steps: + - name: Get artifacts + uses: actions/download-artifact@v4 + with: + path: ./dist + merge-multiple: true + + - name: Create Release + uses: softprops/action-gh-release@v2 + with: + files: ./dist/* + prerelease: ${{ needs.checks.outputs.is_prerelease }} + generate_release_notes: true + + publish: + name: Upload to PyPI + needs: [ build ] + runs-on: ubuntu-latest + + if: github.repository == 'MobilityDB/PyMEOS' + environment: + name: pypi + url: https://pypi.org/p/pymeos + permissions: + id-token: write + + steps: + - name: Get artifacts + uses: actions/download-artifact@v4 + with: + path: ./dist + merge-multiple: true + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fc95eb68..8a1327df 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,12 +23,12 @@ jobs: strategy: fail-fast: false matrix: - python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12" ] + python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12", "3.13" ] os: [ ubuntu-latest, macos-13, macos-14 ] include: - - ld_path: "/usr/local/lib" + - ld_prefix: "/usr/local" - os: macos-14 - ld_path: "/opt/homebrew/lib" + ld_prefix: "/opt/homebrew" steps: - name: Checkout @@ -66,7 +66,7 @@ jobs: run: | mkdir MobilityDB/build cd MobilityDB/build - cmake .. -DMEOS=on + cmake .. -DMEOS=on -DCMAKE_INSTALL_PREFIX=${{ matrix.ld_prefix }} make -j sudo make install @@ -97,6 +97,6 @@ jobs: - name: Test PyMEOS with pytest run: | - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${{ matrix.ld_path }} - export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:${{ matrix.ld_path }} + export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${{ matrix.ld_prefix }}/lib + export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:${{ matrix.ld_prefix }}/lib pytest From 5bf0aa9a7a945f09a7e7e77d8ae4bbca558713b5 Mon Sep 17 00:00:00 2001 From: diviloper Date: Sun, 1 Dec 2024 02:08:50 +0100 Subject: [PATCH 02/21] Add border_inc parameter in STBox tile method --- pymeos/boxes/stbox.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pymeos/boxes/stbox.py b/pymeos/boxes/stbox.py index 1eec7b80..b65b3b16 100644 --- a/pymeos/boxes/stbox.py +++ b/pymeos/boxes/stbox.py @@ -1282,6 +1282,7 @@ def tile( duration: Optional[Union[timedelta, str]] = None, origin: Optional[shp.BaseGeometry] = None, start: Union[datetime, str, None] = None, + border_inc: bool = True, ) -> List[STBox]: """ Returns a list of `STBox` instances representing the tiles of @@ -1298,6 +1299,7 @@ def tile( origin will be (0, 0, 0). start: The start time of the temporal tiling. If not provided, the start time used by default is Monday, January 3, 2000. + border_inc: Whether the border is inclusive or not. Returns: A list of `STBox` instances. @@ -1336,7 +1338,9 @@ def tile( else pgis_geometry_in("Point(0 0 0)", -1) ) ) - tiles, count = stbox_space_time_tiles(self._inner, sz, sz, sz, dt, gs, st) + tiles, count = stbox_space_time_tiles( + self._inner, sz, sz, sz, dt, gs, st, border_inc + ) return [STBox(_inner=tiles + i) for i in range(count)] # ------------------------- Comparisons ----------------------------------- From d3dd7bb8ec922770534b05dd6ef77ca989c34ae6 Mon Sep 17 00:00:00 2001 From: diviloper Date: Mon, 28 Jul 2025 16:26:03 +0200 Subject: [PATCH 03/21] Update pymeos_cffi requirement version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d0b8aaa2..3cafed61 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,7 +33,7 @@ license = { file = 'LICENSE' } requires-python = '>=3.8' dependencies = [ - 'pymeos-cffi >=1.1.0, <2', + 'pymeos-cffi >=1.3.0, <2', 'python-dateutil', 'shapely>=2.0.0', ] From 8bb9c97c155a76788abf3e29cd1000b2f78271ae Mon Sep 17 00:00:00 2001 From: diviloper Date: Mon, 28 Jul 2025 16:26:42 +0200 Subject: [PATCH 04/21] Update references to geoset functions (geoset -> spatialset) --- pymeos/collections/geo/geoset.py | 39 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/pymeos/collections/geo/geoset.py b/pymeos/collections/geo/geoset.py index 043a69ed..dd50e16f 100644 --- a/pymeos/collections/geo/geoset.py +++ b/pymeos/collections/geo/geoset.py @@ -13,18 +13,17 @@ intersection_set_geo, minus_set_geo, union_set_geo, - geoset_as_ewkt, - geoset_as_text, - geoset_out, + spatialset_as_ewkt, + spatialset_as_text, geoset_make, - geoset_srid, - geoset_round, + spatialset_srid, + set_round, minus_geo_set, geomset_in, geogset_in, - pgis_geometry_in, + geom_in, geometry_to_gserialized, - pgis_geography_in, + geog_in, geography_to_gserialized, intersection_set_set, minus_set_set, @@ -53,9 +52,9 @@ def __str__(self, max_decimals: int = 15): A new :class:`str` instance MEOS Functions: - geoset_out + spatialset_as_text """ - return geoset_out(self._inner, max_decimals) + return self.as_text(max_decimals) def as_ewkt(self, max_decimals: int = 15) -> str: """ @@ -68,9 +67,9 @@ def as_ewkt(self, max_decimals: int = 15) -> str: A :class:`str` instance. MEOS Functions: - geoset_as_ewkt + spatialset_as_ewkt """ - return geoset_as_ewkt(self._inner, max_decimals) + return spatialset_as_ewkt(self._inner, max_decimals) def as_wkt(self, max_decimals: int = 15): """ @@ -83,9 +82,9 @@ def as_wkt(self, max_decimals: int = 15): A :class:`str` instance. MEOS Functions: - geoset_as_text + spatialset_as_text """ - return geoset_as_text(self._inner, max_decimals) + return spatialset_as_text(self._inner, max_decimals) def as_text(self, max_decimals: int = 15): """ @@ -98,9 +97,9 @@ def as_text(self, max_decimals: int = 15): A :class:`str` instance. MEOS Functions: - geoset_as_text + spatialset_as_text """ - return geoset_as_text(self._inner, max_decimals) + return spatialset_as_text(self._inner, max_decimals) # ------------------------- Conversions ----------------------------------- @@ -176,9 +175,9 @@ def srid(self) -> int: An integer MEOS Functions: - geoset_srid + spatialset_srid """ - return geoset_srid(self._inner) + return spatialset_srid(self._inner) # ------------------------- Topological Operations -------------------------------- @@ -308,7 +307,7 @@ def round(self: Self, max_decimals: int) -> Self: MEOS Functions: tpoint_roundgeoset_round """ - return self.__class__(_inner=geoset_round(self._inner, max_decimals)) + return self.__class__(_inner=set_round(self._inner, max_decimals)) class GeometrySet(GeoSet): @@ -316,7 +315,7 @@ class GeometrySet(GeoSet): _parse_function = geomset_in _parse_value_function = lambda x: ( - pgis_geometry_in(x, -1) if isinstance(x, str) else geometry_to_gserialized(x) + geom_in(x, -1) if isinstance(x, str) else geometry_to_gserialized(x) ) @@ -325,5 +324,5 @@ class GeographySet(GeoSet): _parse_function = geogset_in _parse_value_function = lambda x: ( - pgis_geography_in(x, -1) if isinstance(x, str) else geography_to_gserialized(x) + geog_in(x, -1) if isinstance(x, str) else geography_to_gserialized(x) ) From b5b3c43ad0b2b312eb23e545505ce5f539f3ca0d Mon Sep 17 00:00:00 2001 From: diviloper Date: Mon, 28 Jul 2025 16:29:31 +0200 Subject: [PATCH 05/21] Update reference to temporal point extent aggregator --- pymeos/aggregators/point_aggregators.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pymeos/aggregators/point_aggregators.py b/pymeos/aggregators/point_aggregators.py index 0969f1a9..c251866f 100644 --- a/pymeos/aggregators/point_aggregators.py +++ b/pymeos/aggregators/point_aggregators.py @@ -1,4 +1,4 @@ -from pymeos_cffi import * +from pymeos_cffi import tspatial_extent_transfn from .aggregator import BaseAggregator from ..boxes import STBox @@ -11,10 +11,10 @@ class TemporalPointExtentAggregator(BaseAggregator[TPoint, STBox]): includes all aggregated temporal numbers. MEOS Functions: - tpoint_extent_transfn, temporal_tagg_finalfn + tspatial_extent_transfn, temporal_tagg_finalfn """ - _add_function = tpoint_extent_transfn + _add_function = tspatial_extent_transfn @classmethod def _finish(cls, state) -> STBox: From 0fa0da8121a332dd160077d7815762cdb6f3b7d7 Mon Sep 17 00:00:00 2001 From: diviloper Date: Fri, 1 Aug 2025 12:21:01 +0200 Subject: [PATCH 06/21] Drop support for python 3.8 and 3.9 and require 3.10 minimum --- pyproject.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 3cafed61..066b9e79 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,10 +19,10 @@ classifiers = [ 'Programming Language :: C', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', + 'Programming Language :: Python :: 3.13', 'Programming Language :: Python :: 3 :: Only', 'Programming Language :: Python :: Implementation :: CPython', 'Operating System :: POSIX', @@ -31,7 +31,7 @@ classifiers = [ readme = 'README.md' license = { file = 'LICENSE' } -requires-python = '>=3.8' +requires-python = '>=3.10' dependencies = [ 'pymeos-cffi >=1.3.0, <2', 'python-dateutil', From b6ad0baf2f90b28cbb95d6718ea216351fc9d97e Mon Sep 17 00:00:00 2001 From: diviloper Date: Fri, 1 Aug 2025 11:27:12 +0200 Subject: [PATCH 07/21] Start syncing --- pymeos/collections/base/spanset.py | 2 +- pymeos/main/tfloat.py | 2 +- pymeos/main/tpoint.py | 50 +++++++++++++++--------------- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/pymeos/collections/base/spanset.py b/pymeos/collections/base/spanset.py index d4ce7a45..8830b575 100644 --- a/pymeos/collections/base/spanset.py +++ b/pymeos/collections/base/spanset.py @@ -44,7 +44,7 @@ def __init__( self._inner = self.__class__._parse_function(string) else: spans = [self.__class__._parse_value_function(p) for p in span_list] - self._inner = spanset_make(spans, normalize, True) + self._inner = spanset_make(spans) def __copy__(self: Self) -> Self: """ diff --git a/pymeos/main/tfloat.py b/pymeos/main/tfloat.py index 6b6e56f6..302ea0d7 100644 --- a/pymeos/main/tfloat.py +++ b/pymeos/main/tfloat.py @@ -923,7 +923,7 @@ def round(self, max_decimals: int = 0) -> TFloat: MEOS Functions: tfloat_round """ - return Temporal._factory(tfloat_round(self._inner, max_decimals)) + return Temporal._factory(temporal_round(self._inner, max_decimals)) # ------------------------- Split Operations ------------------------------ def value_split(self, size: float, start: Optional[float] = 0) -> List[Temporal]: diff --git a/pymeos/main/tpoint.py b/pymeos/main/tpoint.py index 6bc22d9e..01c9d9bb 100644 --- a/pymeos/main/tpoint.py +++ b/pymeos/main/tpoint.py @@ -71,9 +71,9 @@ def __str__(self): A new :class:`str` representing the temporal point. MEOS Functions: - tpoint_out + tgeo_out """ - return tpoint_as_text(self._inner, 15) + return tgeo_out(self._inner, 15) def as_wkt(self, precision: int = 15) -> str: """ @@ -86,9 +86,9 @@ def as_wkt(self, precision: int = 15) -> str: A new :class:`str` representing the temporal point. MEOS Functions: - tpoint_out + tgeo_out """ - return tpoint_as_text(self._inner, precision) + return tgeo_out(self._inner, precision) def as_ewkt(self, precision: int = 15) -> str: """ @@ -101,9 +101,9 @@ def as_ewkt(self, precision: int = 15) -> str: A new :class:`str` representing the temporal point . MEOS Functions: - tpoint_as_ewkt + tgeo_out """ - return tpoint_as_ewkt(self._inner, precision) + return tgeo_out(self._inner, precision) def as_geojson( self, option: int = 1, precision: int = 15, srs: Optional[str] = None @@ -151,11 +151,11 @@ def bounding_box(self) -> STBox: An :class:`~pymeos.boxes.STBox` representing the bounding box. MEOS Functions: - tpoint_to_stbox + tspatial_to_stbox """ from ..boxes import STBox - return STBox(_inner=tpoint_to_stbox(self._inner)) + return STBox(_inner=tspatial_to_stbox(self._inner)) def values(self, precision: int = 15) -> List[shp.Point]: """ @@ -762,15 +762,15 @@ def is_ever_contained_in(self, container: Union[shpb.BaseGeometry, STBox]) -> bo A :class:`bool` indicating whether the temporal point is ever contained by `container`. MEOS Functions: - econtains_geo_tpoint + econtains_geo_tgeo """ from ..boxes import STBox if isinstance(container, shpb.BaseGeometry): gs = geo_to_gserialized(container, isinstance(self, TGeogPoint)) - result = econtains_geo_tpoint(gs, self._inner) + result = econtains_geo_tgeo(gs, self._inner) elif isinstance(container, STBox): - result = econtains_geo_tpoint(stbox_to_geo(container._inner), self._inner) + result = econtains_geo_tgeo(stbox_to_geo(container._inner), self._inner) else: raise TypeError(f"Operation not supported with type {container.__class__}") return result == 1 @@ -895,10 +895,10 @@ def is_spatially_contained_in( if isinstance(container, shpb.BaseGeometry): gs = geo_to_gserialized(container, isinstance(self, TGeogPoint)) - result = tcontains_geo_tpoint(gs, self._inner, False, False) + result = tcontains_geo_tgeo(gs, self._inner, False, False) elif isinstance(container, STBox): gs = stbox_to_geo(container._inner) - result = tcontains_geo_tpoint(gs, self._inner, False, False) + result = tcontains_geo_tgeo(gs, self._inner, False, False) else: raise TypeError(f"Operation not supported with type {container.__class__}") return Temporal._factory(result) @@ -979,9 +979,9 @@ def intersects(self, other: Union[shpb.BaseGeometry, STBox]) -> TBool: if isinstance(other, shpb.BaseGeometry): gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) - result = tintersects_tpoint_geo(self._inner, gs, False, False) + result = tintersects_tgeo_geo(self._inner, gs, False, False) elif isinstance(other, STBox): - result = tintersects_tpoint_geo( + result = tintersects_tgeo_geo( self._inner, stbox_to_geo(other._inner), False, False ) else: @@ -1083,9 +1083,9 @@ def nearest_approach_instant(self, other: Union[shpb.BaseGeometry, TPoint]) -> T """ if isinstance(other, shpb.BaseGeometry): gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) - result = nai_tpoint_geo(self._inner, gs) + result = nai_tgeo_geo(self._inner, gs) elif isinstance(other, TPoint): - result = nai_tpoint_tpoint(self._inner, other._inner) + result = nai_tgeo_tgeo(self._inner, other._inner) else: raise TypeError(f"Operation not supported with type {other.__class__}") return Temporal._factory(result) @@ -1108,9 +1108,9 @@ def shortest_line( """ if isinstance(other, shpb.BaseGeometry): gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) - result = shortestline_tpoint_geo(self._inner, gs) + result = shortestline_tgeo_geo(self._inner, gs) elif isinstance(other, TPoint): - result = shortestline_tpoint_tpoint(self._inner, other._inner) + result = shortestline_tgeo_tgeo(self._inner, other._inner) else: raise TypeError(f"Operation not supported with type {other.__class__}") return gserialized_to_shapely_geometry(result, 10) @@ -1190,9 +1190,9 @@ def space_split( geo_to_gserialized(origin, isinstance(self, TGeogPoint)) if origin is not None else ( - pgis_geography_in("Point(0 0 0)", -1) + geog_in("Point(0 0 0)", -1) if isinstance(self, TGeogPoint) - else pgis_geometry_in("Point(0 0 0)", -1) + else geom_in("Point(0 0 0)", -1) ) ) fragments, values, count = tpoint_space_split( @@ -1550,7 +1550,7 @@ def always_equal(self, value: Union[shpb.BaseGeometry, TGeomPoint]) -> bool: """ if isinstance(value, shpb.BaseGeometry): gs = geometry_to_gserialized(value) - return always_eq_tpoint_point(self._inner, gs) > 0 + return always_eq_tgeo_geo(self._inner, gs) > 0 elif isinstance(value, TGeomPoint): return always_eq_temporal_temporal(self._inner, value._inner) > 0 else: @@ -1592,7 +1592,7 @@ def ever_equal(self, value: Union[shpb.BaseGeometry, TGeomPoint]) -> bool: """ if isinstance(value, shpb.BaseGeometry): gs = geometry_to_gserialized(value) - return ever_eq_tpoint_point(self._inner, gs) > 0 + return ever_eq_tgeo_geo(self._inner, gs) > 0 elif isinstance(value, TGeomPoint): return ever_eq_temporal_temporal(self._inner, value._inner) > 0 else: @@ -1689,11 +1689,11 @@ def temporal_equal(self, other: Union[shp.Point, TGeomPoint]) -> TBool: A :class:`TBool` with the result of the temporal equality relation. MEOS Functions: - teq_tpoint_point, teq_temporal_temporal + teq_tgeo_geo, teq_temporal_temporal """ if isinstance(other, shp.Point): gs = geometry_to_gserialized(other) - result = teq_tpoint_point(self._inner, gs) + result = teq_tgeo_geo(self._inner, gs) else: return super().temporal_equal(other) return Temporal._factory(result) From 6b247e914eb056e7c2f141de7413eb18e7a766c0 Mon Sep 17 00:00:00 2001 From: diviloper Date: Wed, 6 Aug 2025 19:34:57 +0200 Subject: [PATCH 08/21] Move functionalities only available to planar object (TGeoms) from TPoint to TGeomPoint (and remove tests accordingly). Update MEOS functions' names. Fix some tests --- pymeos/boxes/stbox.py | 16 +- pymeos/main/tfloat.py | 137 ++++----- pymeos/main/tpoint.py | 464 +++++++++++++++---------------- pymeos/temporal/interpolation.py | 2 + pymeos/temporal/temporal.py | 17 +- tests/main/tbool_test.py | 6 +- tests/main/tfloat_test.py | 6 +- tests/main/tgeogpoint_test.py | 108 ------- tests/main/tgeompoint_test.py | 12 - 9 files changed, 329 insertions(+), 439 deletions(-) diff --git a/pymeos/boxes/stbox.py b/pymeos/boxes/stbox.py index b65b3b16..b6350233 100644 --- a/pymeos/boxes/stbox.py +++ b/pymeos/boxes/stbox.py @@ -51,7 +51,7 @@ def _get_box( elif isinstance(other, STBox): other_box = other._inner elif isinstance(other, TPoint): - other_box = tpoint_to_stbox(other._inner) + other_box = tspatial_to_stbox(other._inner) elif allow_time_only and isinstance(other, Temporal): other_box = tstzspan_to_stbox(temporal_to_tstzspan(other._inner)) elif allow_time_only and isinstance(other, datetime): @@ -266,9 +266,9 @@ def from_tpoint(temporal: TPoint) -> STBox: A new :class:`STBox` instance. MEOS Functions: - tpoint_to_stbox + tspatial_to_stbox """ - return STBox(_inner=tpoint_to_stbox(temporal._inner)) + return STBox(_inner=tspatial_to_stbox(temporal._inner)) @staticmethod def from_expanding_bounding_box( @@ -294,14 +294,14 @@ def from_expanding_bounding_box( """ if isinstance(value, shp.BaseGeometry): gs = geo_to_gserialized(value, geodetic) - result = geo_expand_space(gs, expansion) + box = geo_to_stbox(gs) elif isinstance(value, TPoint): - result = tpoint_expand_space(value._inner, expansion) + box = tspatial_to_stbox(value._inner) elif isinstance(value, STBox): - result = stbox_expand_space(value._inner, expansion) + box = value._inner else: raise TypeError(f"Operation not supported with type {value.__class__}") - return STBox(_inner=result) + return STBox(_inner=stbox_expand_space(box, expansion)) # ------------------------- Output ---------------------------------------- def __str__(self, max_decimals: int = 15): @@ -939,7 +939,7 @@ def is_over_or_left(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> bool overlap, ``False`` otherwise. MEOS Functions: - overleft_stbox_stbox, tpoint_to_stbox + overleft_stbox_stbox, tspatial_to_stbox """ return overleft_stbox_stbox(self._inner, self._get_box(other)) diff --git a/pymeos/main/tfloat.py b/pymeos/main/tfloat.py index 302ea0d7..374f91c9 100644 --- a/pymeos/main/tfloat.py +++ b/pymeos/main/tfloat.py @@ -15,7 +15,6 @@ from .tint import TInt from .tbool import TBool - Self = TypeVar("Self", bound="TFloat") @@ -28,14 +27,16 @@ class TFloat( _mobilitydb_name = "tfloat" BaseClass = float + DefaultInterpolation = TInterpolation.LINEAR + _parse_function = tfloat_in # ------------------------- Constructors ---------------------------------- @staticmethod def from_base_temporal( - value: float, - base: Temporal, - interpolation: TInterpolation = TInterpolation.LINEAR, + value: float, + base: Temporal, + interpolation: TInterpolation = TInterpolation.LINEAR, ) -> TFloat: """ Returns a new temporal float with the value `value` and the temporal @@ -58,30 +59,34 @@ def from_base_temporal( @staticmethod @overload def from_base_time( - value: float, base: datetime, interpolation: None = None - ) -> TFloatInst: ... + value: float, base: datetime, interpolation: None = None + ) -> TFloatInst: + ... @staticmethod @overload def from_base_time( - value: float, base: TsTzSet, interpolation: None = None - ) -> TFloatSeq: ... + value: float, base: TsTzSet, interpolation: None = None + ) -> TFloatSeq: + ... @staticmethod @overload def from_base_time( - value: float, base: TsTzSpan, interpolation: TInterpolation = None - ) -> TFloatSeq: ... + value: float, base: TsTzSpan, interpolation: TInterpolation = None + ) -> TFloatSeq: + ... @staticmethod @overload def from_base_time( - value: float, base: TsTzSpanSet, interpolation: TInterpolation = None - ) -> TFloatSeqSet: ... + value: float, base: TsTzSpanSet, interpolation: TInterpolation = None + ) -> TFloatSeqSet: + ... @staticmethod def from_base_time( - value: float, base: Time, interpolation: TInterpolation = None + value: float, base: Time, interpolation: TInterpolation = None ) -> TFloat: """ Returns a new temporal float with the value `value` and the temporal @@ -769,19 +774,19 @@ def temporal_greater(self, other: Union[int, float, TFloat]) -> TBool: # ------------------------- Restrictions ---------------------------------- def at( - self, - other: Union[ - float, - int, - FloatSet, - IntSet, - FloatSpan, - IntSpan, - FloatSpanSet, - IntSpanSet, - TBox, - Time, - ], + self, + other: Union[ + float, + int, + FloatSet, + IntSet, + FloatSpan, + IntSpan, + FloatSpanSet, + IntSpanSet, + TBox, + Time, + ], ) -> TFloat: """ Returns a new temporal float with the values of `self` restricted to @@ -811,19 +816,19 @@ def at( return Temporal._factory(result) def minus( - self, - other: Union[ - float, - int, - FloatSet, - IntSet, - FloatSpan, - IntSpan, - FloatSpanSet, - IntSpanSet, - TBox, - Time, - ], + self, + other: Union[ + float, + int, + FloatSet, + IntSet, + FloatSpan, + IntSpan, + FloatSpanSet, + IntSpanSet, + TBox, + Time, + ], ) -> Temporal: """ Returns a new temporal float with the values of `self` restricted to @@ -879,7 +884,7 @@ def derivative(self) -> TFloat: MEOS Functions: tfloat_derivative """ - return Temporal._factory(tfloat_derivative(self._inner)) + return Temporal._factory(temporal_derivative(self._inner)) # ------------------------- Transformations ---------------------------------- def to_degrees(self, normalize: bool = True) -> TFloat: @@ -944,11 +949,11 @@ def value_split(self, size: float, start: Optional[float] = 0) -> List[Temporal] return [Temporal._factory(fragments[i]) for i in range(count)] def value_time_split( - self, - value_size: float, - duration: Union[str, timedelta], - value_start: Optional[float] = 0.0, - time_start: Optional[Union[str, datetime]] = None, + self, + value_size: float, + duration: Union[str, timedelta], + value_start: Optional[float] = 0.0, + time_start: Optional[Union[str, datetime]] = None, ) -> List[Temporal]: """ Splits `self` into fragments with respect to value and tstzspan buckets. @@ -1024,12 +1029,12 @@ class TFloatInst( _cast_function = float def __init__( - self, - string: Optional[str] = None, - *, - value: Optional[Union[str, float]] = None, - timestamp: Optional[Union[str, datetime]] = None, - _inner=None, + self, + string: Optional[str] = None, + *, + value: Optional[Union[str, float]] = None, + timestamp: Optional[Union[str, datetime]] = None, + _inner=None, ): super().__init__(string=string, value=value, timestamp=timestamp, _inner=_inner) @@ -1044,15 +1049,15 @@ class TFloatSeq( ComponentClass = TFloatInst def __init__( - self, - string: Optional[str] = None, - *, - instant_list: Optional[List[Union[str, TFloatInst]]] = None, - lower_inc: bool = True, - upper_inc: bool = False, - interpolation: TInterpolation = TInterpolation.LINEAR, - normalize: bool = True, - _inner=None, + self, + string: Optional[str] = None, + *, + instant_list: Optional[List[Union[str, TFloatInst]]] = None, + lower_inc: bool = True, + upper_inc: bool = False, + interpolation: TInterpolation = TInterpolation.LINEAR, + normalize: bool = True, + _inner=None, ): super().__init__( string=string, @@ -1075,12 +1080,12 @@ class TFloatSeqSet( ComponentClass = TFloatSeq def __init__( - self, - string: Optional[str] = None, - *, - sequence_list: Optional[List[Union[str, TFloatSeq]]] = None, - normalize: bool = True, - _inner=None, + self, + string: Optional[str] = None, + *, + sequence_list: Optional[List[Union[str, TFloatSeq]]] = None, + normalize: bool = True, + _inner=None, ): super().__init__( string=string, diff --git a/pymeos/main/tpoint.py b/pymeos/main/tpoint.py index 01c9d9bb..0e52978f 100644 --- a/pymeos/main/tpoint.py +++ b/pymeos/main/tpoint.py @@ -51,7 +51,7 @@ class TPoint(Temporal[shp.Point, TG, TI, TS, TSS], TSimplifiable, ABC): Abstract class for temporal points. """ - _projection_cache: dict[tuple[int, int], "LWPROJ"] = {} + DefaultInterpolation = TInterpolation.LINEAR # ------------------------- Constructors ---------------------------------- def __init__(self, _inner) -> None: @@ -71,9 +71,9 @@ def __str__(self): A new :class:`str` representing the temporal point. MEOS Functions: - tgeo_out + tspatial_as_text """ - return tgeo_out(self._inner, 15) + return tspatial_as_text(self._inner, 15) def as_wkt(self, precision: int = 15) -> str: """ @@ -86,9 +86,9 @@ def as_wkt(self, precision: int = 15) -> str: A new :class:`str` representing the temporal point. MEOS Functions: - tgeo_out + tspatial_as_text """ - return tgeo_out(self._inner, precision) + return tspatial_as_text(self._inner, precision) def as_ewkt(self, precision: int = 15) -> str: """ @@ -101,17 +101,18 @@ def as_ewkt(self, precision: int = 15) -> str: A new :class:`str` representing the temporal point . MEOS Functions: - tgeo_out + tspatial_as_ewkt """ - return tgeo_out(self._inner, precision) + return tspatial_as_ewkt(self._inner, precision) def as_geojson( - self, option: int = 1, precision: int = 15, srs: Optional[str] = None + self, unary_union: bool = False, option: int = 1, precision: int = 15, srs: Optional[str] = None ) -> str: """ Returns the trajectory of the temporal point as a GeoJSON string. Args: + unary_union: If `True`, resulting geometry will be simplified applying a unary union (ST_UnaryUnion) option: The option to use when serializing the trajectory. precision: The precision of the returned geometry. srs: The spatial reference system of the returned geometry. @@ -120,26 +121,27 @@ def as_geojson( A new GeoJSON string representing the trajectory of the temporal point. MEOS Functions: - gserialized_as_geojson + geo_as_geojson """ - return geo_as_geojson(tpoint_trajectory(self._inner), option, precision, srs) + return geo_as_geojson(tpoint_trajectory(self._inner, unary_union), option, precision, srs) - def to_shapely_geometry(self, precision: int = 15) -> shpb.BaseGeometry: + def to_shapely_geometry(self, precision: int = 15, unary_union: bool = False) -> shpb.BaseGeometry: """ Returns the trajectory of the temporal point as a Shapely geometry. Args: precision: The precision of the returned geometry. + unary_union: If `True`, resulting geometry will be simplified applying a unary union (ST_UnaryUnion) Returns: A new :class:`~shapely.geometry.base.BaseGeometry` representing the trajectory. MEOS Functions: - gserialized_to_shapely_geometry + gserialized_to_shapely_geometry, tpoint_trajectory """ return gserialized_to_shapely_geometry( - tpoint_trajectory(self._inner), precision + tpoint_trajectory(self._inner, unary_union), precision ) # ------------------------- Accessors ------------------------------------- @@ -177,9 +179,9 @@ def start_value(self, precision: int = 15) -> shp.Point: A :class:`~shapely.geometry.Point` with the start value. MEOS Functions: - tpoint_start_value + tgeo_start_value """ - return gserialized_to_shapely_point(tpoint_start_value(self._inner), precision) + return gserialized_to_shapely_point(tgeo_start_value(self._inner), precision) def end_value(self, precision: int = 15) -> shp.Point: """ @@ -189,9 +191,9 @@ def end_value(self, precision: int = 15) -> shp.Point: A :class:`~shapely.geometry.Point` with the end value. MEOS Functions: - tpoint_end_value + tgeo_end_value """ - return gserialized_to_shapely_point(tpoint_end_value(self._inner), precision) + return gserialized_to_shapely_point(tgeo_end_value(self._inner), precision) def value_set(self, precision: int = 15) -> Set[shp.Point]: """ @@ -202,9 +204,9 @@ def value_set(self, precision: int = 15) -> Set[shp.Point]: A :class:`set` of :class:`~shapely.geometry.Point` with the values. MEOS Functions: - tpoint_values + tgeo_values """ - values, count = tpoint_values(self._inner) + values, count = tgeo_values(self._inner) return { gserialized_to_shapely_point(values[i], precision) for i in range(count) } @@ -221,10 +223,10 @@ def value_at_timestamp(self, timestamp: datetime, precision: int = 15) -> shp.Po A :class:`~shapely.geometry.Point` with the value. MEOS Functions: - tpoint_value_at_timestamp + tgeo_value_at_timestamp """ return gserialized_to_shapely_point( - tpoint_value_at_timestamptz( + tgeo_value_at_timestamptz( self._inner, datetime_to_timestamptz(timestamp), True )[0], precision, @@ -331,7 +333,7 @@ def stboxes(self) -> List[STBox]: """ from ..boxes import STBox - result, count = tpoint_stboxes(self._inner) + result, count = tgeo_stboxes(self._inner) return [STBox(_inner=result + i) for i in range(count)] def is_simple(self) -> bool: @@ -432,7 +434,7 @@ def srid(self) -> int: MEOS Functions: tpoint_srid """ - return tpoint_srid(self._inner) + return tspatial_srid(self._inner) def set_srid(self: Self, srid: int) -> Self: """ @@ -440,7 +442,7 @@ def set_srid(self: Self, srid: int) -> Self: """ - return self.__class__(_inner=tpoint_set_srid(self._inner, srid)) + return self.__class__(_inner=tspatial_set_srid(self._inner, srid)) # ------------------------- Transformations ------------------------------- def round(self, max_decimals: int = 0) -> TPoint: @@ -453,7 +455,7 @@ def round(self, max_decimals: int = 0) -> TPoint: MEOS Functions: tpoint_round """ - result = tpoint_round(self._inner, max_decimals) + result = temporal_round(self._inner, max_decimals) return Temporal._factory(result) def make_simple(self) -> List[TPoint]: @@ -469,26 +471,6 @@ def make_simple(self) -> List[TPoint]: result, count = tpoint_make_simple(self._inner) return [Temporal._factory(result[i]) for i in range(count)] - def expand(self, other: Union[int, float]) -> STBox: - """ - Expands ``self`` with `other`. - The result is equal to ``self`` but with the spatial dimensions - expanded by `other` in all directions. - - Args: - other: The object to expand ``self`` with. - - Returns: - A new :class:`STBox` instance. - - MEOS Functions: - tpoint_expand_space - """ - from ..boxes import STBox - - result = tpoint_expand_space(self._inner, float(other)) - return STBox(_inner=result) - def transform(self: Self, srid: int) -> Self: """ Returns a new :class:`TPoint` of the same subclass of ``self`` transformed to another SRID @@ -500,12 +482,9 @@ def transform(self: Self, srid: int) -> Self: A new :class:`TPoint` instance MEOS Functions: - tpoint_transform + tspatial_transform """ - srids = (self.srid(), srid) - if srids not in self._projection_cache: - self._projection_cache[srids] = lwproj_transform(*srids) - result = tpoint_transform_pj(self._inner, srid, self._projection_cache[srids]) + result = tspatial_transform(self._inner, srid) return Temporal._factory(result) # ------------------------- Restrictions ---------------------------------- @@ -530,11 +509,11 @@ def at(self, other: Union[shpb.BaseGeometry, GeoSet, STBox, Time]) -> TG: result = tpoint_at_value(self._inner, gs) elif isinstance(other, shpb.BaseGeometry): gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) - result = tpoint_at_geom_time(self._inner, gs, None, None) + result = tgeo_at_geom(self._inner, gs) elif isinstance(other, GeoSet): result = temporal_at_values(self._inner, other._inner) elif isinstance(other, STBox): - result = tpoint_at_stbox(self._inner, other._inner, True) + result = tgeo_at_stbox(self._inner, other._inner, True) else: return super().at(other) return Temporal._factory(result) @@ -560,11 +539,11 @@ def minus(self, other: Union[shpb.BaseGeometry, GeoSet, STBox, Time]) -> TG: result = tpoint_minus_value(self._inner, gs) elif isinstance(other, shpb.BaseGeometry): gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) - result = tpoint_minus_geom_time(self._inner, gs, None, None) + result = tgeo_minus_geom(self._inner, gs) elif isinstance(other, GeoSet): result = temporal_minus_values(self._inner, other._inner) elif isinstance(other, STBox): - result = tpoint_minus_stbox(self._inner, other._inner, True) + result = tgeo_minus_stbox(self._inner, other._inner, True) else: return super().minus(other) return Temporal._factory(result) @@ -775,7 +754,7 @@ def is_ever_contained_in(self, container: Union[shpb.BaseGeometry, STBox]) -> bo raise TypeError(f"Operation not supported with type {container.__class__}") return result == 1 - def is_ever_disjoint(self, other: TPoint) -> bool: + def is_ever_disjoint(self, other: Union[shpb.BaseGeometry, TPoint]) -> bool: """ Returns whether the temporal point is ever disjoint from `other`. @@ -786,10 +765,13 @@ def is_ever_disjoint(self, other: TPoint) -> bool: A :class:`bool` indicating whether the temporal point is ever disjoint from `other`. MEOS Functions: - edisjoint_tpoint_geo, edisjoint_tpoint_tpoint + edisjoint_tgeo_geo, edisjoint_tgeo_tgeo """ - if isinstance(other, TPoint): - result = edisjoint_tpoint_tpoint(self._inner, other._inner) + if isinstance(other, shpb.BaseGeometry): + gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) + result = edisjoint_tgeo_geo(self._inner, gs) + elif isinstance(other, TPoint): + result = edisjoint_tgeo_tgeo(self._inner, other._inner) else: raise TypeError(f"Operation not supported with type {other.__class__}") return result == 1 @@ -808,19 +790,19 @@ def is_ever_within_distance( A :class:`bool` indicating whether the temporal point is ever within `distance` of `other`. MEOS Functions: - edwithin_tpoint_geo, edwithin_tpoint_tpoint + edwithin_tgeo_geo, edwithin_tgeo_tgeo """ from ..boxes import STBox if isinstance(other, shpb.BaseGeometry): gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) - result = edwithin_tpoint_geo(self._inner, gs, distance) + result = edwithin_tgeo_geo(self._inner, gs, distance) elif isinstance(other, STBox): - result = edwithin_tpoint_geo( + result = edwithin_tgeo_geo( self._inner, stbox_to_geo(other._inner), distance ) elif isinstance(other, TPoint): - result = edwithin_tpoint_tpoint(self._inner, other._inner, distance) + result = edwithin_tgeo_tgeo(self._inner, other._inner, distance) else: raise TypeError(f"Operation not supported with type {other.__class__}") return result == 1 @@ -836,22 +818,22 @@ def ever_intersects(self, other: Union[shpb.BaseGeometry, TPoint, STBox]) -> boo A :class:`bool` indicating whether the temporal point ever intersects `other`. MEOS Functions: - eintersects_tpoint_geo, eintersects_tpoint_tpoint + eintersects_tgeo_geo, eintersects_tgeo_tgeo """ from ..boxes import STBox if isinstance(other, shpb.BaseGeometry): gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) - result = eintersects_tpoint_geo(self._inner, gs) + result = eintersects_tgeo_geo(self._inner, gs) elif isinstance(other, STBox): - result = eintersects_tpoint_geo(self._inner, stbox_to_geo(other._inner)) + result = eintersects_tgeo_geo(self._inner, stbox_to_geo(other._inner)) elif isinstance(other, TPoint): - result = eintersects_tpoint_tpoint(self._inner, other._inner) + result = eintersects_tgeo_tgeo(self._inner, other._inner) else: raise TypeError(f"Operation not supported with type {other.__class__}") return result == 1 - def ever_touches(self, other: Union[shpb.BaseGeometry, STBox]) -> bool: + def ever_touches(self, other: Union[shpb.BaseGeometry, STBox, TPoint]) -> bool: """ Returns whether the temporal point ever touches `other`. @@ -862,15 +844,17 @@ def ever_touches(self, other: Union[shpb.BaseGeometry, STBox]) -> bool: A :class:`bool` indicating whether the temporal point ever touches `other`. MEOS Functions: - etouches_tpoint_geo + etouches_tgeo_geo, etouches_tgeo_tgeo """ from ..boxes import STBox if isinstance(other, shpb.BaseGeometry): gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) - result = etouches_tpoint_geo(self._inner, gs) + result = etouches_tgeo_geo(self._inner, gs) elif isinstance(other, STBox): - result = etouches_tpoint_geo(self._inner, stbox_to_geo(other._inner)) + result = etouches_tgeo_geo(self._inner, stbox_to_geo(other._inner)) + elif isinstance(other, TPoint): + result = etouches_tgeo_tgeo(self._inner, other._inner) else: raise TypeError(f"Operation not supported with type {other.__class__}") return result == 1 @@ -903,117 +887,6 @@ def is_spatially_contained_in( raise TypeError(f"Operation not supported with type {container.__class__}") return Temporal._factory(result) - def disjoint(self, other: Union[shpb.BaseGeometry, STBox]) -> TBool: - """ - Returns a new temporal boolean indicating whether the temporal point intersects `other`. - - Args: - other: An object to check for intersection with. - - Returns: - A new :TBool: indicating whether the temporal point intersects `other`. - - MEOS Functions: - tintersects_tpoint_geo - """ - from ..boxes import STBox - - if isinstance(other, shpb.BaseGeometry): - gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) - result = tdisjoint_tpoint_geo(self._inner, gs, False, False) - elif isinstance(other, STBox): - result = tdisjoint_tpoint_geo( - self._inner, stbox_to_geo(other._inner), False, False - ) - else: - raise TypeError(f"Operation not supported with type {other.__class__}") - return Temporal._factory(result) - - def within_distance( - self, other: Union[shpb.BaseGeometry, TPoint, STBox], distance: float - ) -> TBool: - """ - Returns a new temporal boolean indicating whether the temporal point is within `distance` of `other`. - - Args: - other: An object to check the distance to. - distance: The distance to check in units of the spatial reference system. - - Returns: - A new :TBool: indicating whether the temporal point is within `distance` of `other`. - - MEOS Functions: - tdwithin_tpoint_geo, tdwithin_tpoint_tpoint - """ - from ..boxes import STBox - - if isinstance(other, shpb.BaseGeometry): - gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) - result = tdwithin_tpoint_geo(self._inner, gs, distance, False, False) - elif isinstance(other, STBox): - result = tdwithin_tpoint_geo( - self._inner, stbox_to_geo(other._inner), distance, False, False - ) - elif isinstance(other, TPoint): - result = tdwithin_tpoint_tpoint( - self._inner, other._inner, distance, False, False - ) - else: - raise TypeError(f"Operation not supported with type {other.__class__}") - return Temporal._factory(result) - - def intersects(self, other: Union[shpb.BaseGeometry, STBox]) -> TBool: - """ - Returns a new temporal boolean indicating whether the temporal point intersects `other`. - - Args: - other: An object to check for intersection with. - - Returns: - A new :TBool: indicating whether the temporal point intersects `other`. - - MEOS Functions: - tintersects_tpoint_geo - """ - from ..boxes import STBox - - if isinstance(other, shpb.BaseGeometry): - gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) - result = tintersects_tgeo_geo(self._inner, gs, False, False) - elif isinstance(other, STBox): - result = tintersects_tgeo_geo( - self._inner, stbox_to_geo(other._inner), False, False - ) - else: - raise TypeError(f"Operation not supported with type {other.__class__}") - return Temporal._factory(result) - - def touches(self, other: Union[shpb.BaseGeometry, STBox]) -> TBool: - """ - Returns a new temporal boolean indicating whether the temporal point touches `other`. - - Args: - other: An object to check for touching with. - - Returns: - A new :TBool: indicating whether the temporal point touches `other`. - - MEOS Functions: - ttouches_tpoint_geo - """ - from ..boxes import STBox - - if isinstance(other, shpb.BaseGeometry): - gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) - result = ttouches_tpoint_geo(self._inner, gs, False, False) - elif isinstance(other, STBox): - result = ttouches_tpoint_geo( - self._inner, stbox_to_geo(other._inner), False, False - ) - else: - raise TypeError(f"Operation not supported with type {other.__class__}") - return Temporal._factory(result) - # ------------------------- Distance Operations --------------------------- def distance(self, other: Union[shpb.BaseGeometry, TPoint, STBox]) -> TFloat: """ @@ -1026,17 +899,17 @@ def distance(self, other: Union[shpb.BaseGeometry, TPoint, STBox]) -> TFloat: A new :class:`TFloat` indicating the temporal distance between the temporal point and `other`. MEOS Functions: - distance_tpoint_point, distance_tpoint_tpoint + tdistance_tgeo_geo, tdistance_tgeo_tgeo """ from ..boxes import STBox if isinstance(other, shpb.BaseGeometry): gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) - result = distance_tpoint_point(self._inner, gs) + result = tdistance_tgeo_geo(self._inner, gs) elif isinstance(other, STBox): - result = distance_tpoint_point(self._inner, stbox_to_geo(other._inner)) + result = tdistance_tgeo_geo(self._inner, stbox_to_geo(other._inner)) elif isinstance(other, TPoint): - result = distance_tpoint_tpoint(self._inner, other._inner) + result = tdistance_tgeo_tgeo(self._inner, other._inner) else: raise TypeError(f"Operation not supported with type {other.__class__}") return Temporal._factory(result) @@ -1054,17 +927,17 @@ def nearest_approach_distance( A :class:`float` indicating the nearest approach distance between the temporal point and `other`. MEOS Functions: - nad_tpoint_geo, nad_tpoint_stbox, nad_tpoint_tpoint + nad_tgeo_geo, nad_tgeo_stbox, nad_tgeo_tgeo """ from ..boxes import STBox if isinstance(other, shpb.BaseGeometry): gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) - return nad_tpoint_geo(self._inner, gs) + return nad_tgeo_geo(self._inner, gs) elif isinstance(other, STBox): - return nad_tpoint_stbox(self._inner, other._inner) + return nad_tgeo_stbox(self._inner, other._inner) elif isinstance(other, TPoint): - return nad_tpoint_tpoint(self._inner, other._inner) + return nad_tgeo_tgeo(self._inner, other._inner) else: raise TypeError(f"Operation not supported with type {other.__class__}") @@ -1079,7 +952,7 @@ def nearest_approach_instant(self, other: Union[shpb.BaseGeometry, TPoint]) -> T A new temporal instant indicating the nearest approach instant between the temporal point and `other`. MEOS Functions: - nai_tpoint_geo, nai_tpoint_tpoint + nai_tgeo_geo, nai_tgeo_tgeo """ if isinstance(other, shpb.BaseGeometry): gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) @@ -1104,7 +977,7 @@ def shortest_line( and `other`. MEOS Functions: - shortestline_tpoint_geo, shortestline_tpoint_tpoint + shortestline_tgeo_geo, shortestline_tgeo_tgeo """ if isinstance(other, shpb.BaseGeometry): gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) @@ -1195,7 +1068,7 @@ def space_split( else geom_in("Point(0 0 0)", -1) ) ) - fragments, values, count = tpoint_space_split( + fragments, values, count = tgeo_space_split( self._inner, xsize, ysz, zsz, gs, bitmatrix, include_border ) from ..factory import _TemporalFactory @@ -1245,9 +1118,9 @@ def space_time_split( geo_to_gserialized(origin, isinstance(self, TGeogPoint)) if origin is not None else ( - pgis_geography_in("Point(0 0 0)", -1) + geog_in("Point(0 0 0)", -1) if isinstance(self, TGeogPoint) - else pgis_geometry_in("Point(0 0 0)", -1) + else geom_in("Point(0 0 0)", -1) ) ) if time_start is None: @@ -1258,7 +1131,7 @@ def space_time_split( if isinstance(time_start, datetime) else pg_timestamptz_in(time_start, -1) ) - fragments, points, times, count = tpoint_space_time_split( + fragments, points, times, count = tgeo_space_time_split( self._inner, xsize, ysz, zsz, dt, gs, st, bitmatrix, include_border ) return [Temporal._factory(fragments[i]) for i in range(count)] @@ -1515,9 +1388,9 @@ def to_geographic(self) -> TGeogPoint: A new :class:`TGeogPoint` object. MEOS Functions: - tgeompoint_to_tgeogpoint + tgeometry_to_tgeography """ - result = tgeompoint_to_tgeogpoint(self._inner) + result = tgeometry_to_tgeography(self._inner) return Temporal._factory(result) def to_dataframe(self) -> GeoDataFrame: @@ -1534,6 +1407,125 @@ def to_dataframe(self) -> GeoDataFrame: } return gpd.GeoDataFrame(data, crs=self.srid()).set_index(keys=["time"]) + # --------------------- Temporal Spatial Relationships -------------------- + + def disjoint(self, other: Union[shpb.BaseGeometry, STBox, TPoint]) -> TBool: + """ + Returns a new temporal boolean indicating whether the temporal point intersects `other`. + + Args: + other: An object to check for intersection with. + + Returns: + A new :TBool: indicating whether the temporal point intersects `other`. + + MEOS Functions: + tdisjoint_tgeo_geo, tdisjoint_tgeo_tgeo + """ + from ..boxes import STBox + + if isinstance(other, shpb.BaseGeometry): + gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) + result = tdisjoint_tgeo_geo(self._inner, gs, False, False) + elif isinstance(other, STBox): + result = tdisjoint_tgeo_geo( + self._inner, stbox_to_geo(other._inner), False, False + ) + elif isinstance(other, TPoint): + result = tdisjoint_tgeo_tgeo(self._inner, other._inner, False, False) + else: + raise TypeError(f"Operation not supported with type {other.__class__}") + return Temporal._factory(result) + + def intersects(self, other: Union[shpb.BaseGeometry, STBox, TPoint]) -> TBool: + """ + Returns a new temporal boolean indicating whether the temporal point intersects `other`. + + Args: + other: An object to check for intersection with. + + Returns: + A new :TBool: indicating whether the temporal point intersects `other`. + + MEOS Functions: + tintersects_tgeo_geo, tintersects_tgeo_tgeo + """ + from ..boxes import STBox + + if isinstance(other, shpb.BaseGeometry): + gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) + result = tintersects_tgeo_geo(self._inner, gs, False, False) + elif isinstance(other, STBox): + result = tintersects_tgeo_geo( + self._inner, stbox_to_geo(other._inner), False, False + ) + elif isinstance(other, TPoint): + result = tintersects_tgeo_tgeo(self._inner, other._inner, False, False) + else: + raise TypeError(f"Operation not supported with type {other.__class__}") + return Temporal._factory(result) + + def touches(self, other: Union[shpb.BaseGeometry, STBox, TGeomPoint]) -> TBool: + """ + Returns a new temporal boolean indicating whether the temporal point touches `other`. + + Args: + other: An object to check for touching with. + + Returns: + A new :TBool: indicating whether the temporal point touches `other`. + + MEOS Functions: + ttouches_tgeo_geo, ttouches_tgeo_tgeo + """ + from ..boxes import STBox + + if isinstance(other, shpb.BaseGeometry): + gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) + result = ttouches_tgeo_geo(self._inner, gs, False, False) + elif isinstance(other, STBox): + result = ttouches_tgeo_geo( + self._inner, stbox_to_geo(other._inner), False, False + ) + elif isinstance(other, TGeomPoint): + result = ttouches_tgeo_tgeo(self._inner, other._inner, False, False) + else: + raise TypeError(f"Operation not supported with type {other.__class__}") + return Temporal._factory(result) + + def within_distance( + self, other: Union[shpb.BaseGeometry, TGeomPoint, STBox], distance: float + ) -> TBool: + """ + Returns a new temporal boolean indicating whether the temporal point is within `distance` of `other`. + + Args: + other: An object to check the distance to. + distance: The distance to check in units of the spatial reference system. + + Returns: + A new :TBool: indicating whether the temporal point is within `distance` of `other`. + + MEOS Functions: + tdwithin_tgeo_geo, tdwithin_tgeo_tgeo + """ + from ..boxes import STBox + + if isinstance(other, shpb.BaseGeometry): + gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) + result = tdwithin_tgeo_geo(self._inner, gs, distance, False, False) + elif isinstance(other, STBox): + result = tdwithin_tgeo_geo( + self._inner, stbox_to_geo(other._inner), distance, False, False + ) + elif isinstance(other, TGeomPoint): + result = tdwithin_tgeo_tgeo( + self._inner, other._inner, distance, False, False + ) + else: + raise TypeError(f"Operation not supported with type {other.__class__}") + return Temporal._factory(result) + # ------------------------- Ever and Always Comparisons ------------------- def always_equal(self, value: Union[shpb.BaseGeometry, TGeomPoint]) -> bool: """ @@ -1546,13 +1538,13 @@ def always_equal(self, value: Union[shpb.BaseGeometry, TGeomPoint]) -> bool: True if `self` is always equal to `value`, False otherwise. MEOS Functions: - always_eq_tpoint_point, always_eq_temporal_temporal + always_eq_tgeo_geo, always_eq_tgeo_tgeo """ if isinstance(value, shpb.BaseGeometry): gs = geometry_to_gserialized(value) return always_eq_tgeo_geo(self._inner, gs) > 0 elif isinstance(value, TGeomPoint): - return always_eq_temporal_temporal(self._inner, value._inner) > 0 + return always_eq_tgeo_tgeo(self._inner, value._inner) > 0 else: raise TypeError(f"Operation not supported with type {value.__class__}") @@ -1567,13 +1559,13 @@ def always_not_equal(self, value: Union[shpb.BaseGeometry, TGeomPoint]) -> bool: True if `self` is always different to `value`, False otherwise. MEOS Functions: - always_ne_tpoint_point, always_ne_temporal_temporal + always_ne_tgeo_geo, always_ne_tgeo_tgeo """ if isinstance(value, shpb.BaseGeometry): gs = geometry_to_gserialized(value) - return always_ne_tpoint_point(self._inner, gs) > 0 + return always_ne_tgeo_geo(self._inner, gs) > 0 elif isinstance(value, TGeomPoint): - return always_ne_temporal_temporal(self._inner, value._inner) > 0 + return always_ne_tgeo_tgeo(self._inner, value._inner) > 0 else: raise TypeError(f"Operation not supported with type {value.__class__}") @@ -1588,13 +1580,13 @@ def ever_equal(self, value: Union[shpb.BaseGeometry, TGeomPoint]) -> bool: True if `self` is ever equal to `value`, False otherwise. MEOS Functions: - ever_eq_tpoint_point, ever_eq_temporal_temporal + ever_eq_tgeo_geo, ever_eq_tgeo_tgeo """ if isinstance(value, shpb.BaseGeometry): gs = geometry_to_gserialized(value) return ever_eq_tgeo_geo(self._inner, gs) > 0 elif isinstance(value, TGeomPoint): - return ever_eq_temporal_temporal(self._inner, value._inner) > 0 + return ever_eq_tgeo_tgeo(self._inner, value._inner) > 0 else: raise TypeError(f"Operation not supported with type {value.__class__}") @@ -1609,13 +1601,13 @@ def ever_not_equal(self, value: Union[shpb.BaseGeometry, TGeomPoint]) -> bool: True if `self` is ever different to `value`, False otherwise. MEOS Functions: - ever_ne_tpoint_point, ever_ne_temporal_temporal + ever_ne_tgeo_geo, ever_ne_tgeo_tgeo """ if isinstance(value, shpb.BaseGeometry): gs = geometry_to_gserialized(value) - return ever_ne_tpoint_point(self._inner, gs) > 0 + return ever_ne_tgeo_geo(self._inner, gs) > 0 elif isinstance(value, TGeomPoint): - return ever_ne_temporal_temporal(self._inner, value._inner) > 0 + return ever_ne_tgeo_tgeo(self._inner, value._inner) > 0 else: raise TypeError(f"Operation not supported with type {value.__class__}") @@ -1630,7 +1622,7 @@ def never_equal(self, value: Union[shpb.BaseGeometry, TGeomPoint]) -> bool: True if `self` is never equal to `value`, False otherwise. MEOS Functions: - ever_eq_tpoint_point, ever_eq_temporal_temporal + ever_eq_tgeo_geo, ever_eq_tgeo_tgeo """ return not self.ever_equal(value) @@ -1645,7 +1637,7 @@ def never_not_equal(self, value: Union[shpb.BaseGeometry, TGeomPoint]) -> bool: True if `self` is never different to `value`, False otherwise. MEOS Functions: - ever_ne_tpoint_point, ever_ne_temporal_temporal + ever_ne_tgeo_geo, ever_ne_tgeo_tgeo """ return not self.ever_not_equal(value) @@ -1662,17 +1654,17 @@ def is_ever_disjoint( A :class:`bool` indicating whether the temporal point is ever disjoint from `other`. MEOS Functions: - edisjoint_tpoint_geo, edisjoint_tpoint_tpoint + edisjoint_tgeo_geo, edisjoint_tgeo_tgeo """ from ..boxes import STBox if isinstance(other, shpb.BaseGeometry): gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) - result = edisjoint_tpoint_geo(self._inner, gs) + result = edisjoint_tgeo_geo(self._inner, gs) elif isinstance(other, STBox): - result = edisjoint_tpoint_geo(self._inner, stbox_to_geo(other._inner)) + result = edisjoint_tgeo_geo(self._inner, stbox_to_geo(other._inner)) elif isinstance(other, TGeomPoint): - result = edisjoint_tpoint_tpoint(self._inner, other._inner) + result = edisjoint_tgeo_tgeo(self._inner, other._inner) else: raise TypeError(f"Operation not supported with type {other.__class__}") return result == 1 @@ -1689,7 +1681,7 @@ def temporal_equal(self, other: Union[shp.Point, TGeomPoint]) -> TBool: A :class:`TBool` with the result of the temporal equality relation. MEOS Functions: - teq_tgeo_geo, teq_temporal_temporal + teq_tgeo_geo, teq_tgeo_geo """ if isinstance(other, shp.Point): gs = geometry_to_gserialized(other) @@ -1709,11 +1701,11 @@ def temporal_not_equal(self, other: Union[shp.Point, TGeomPoint]) -> TBool: A :class:`TBool` with the result of the temporal inequality relation. MEOS Functions: - tne_tpoint_point, tne_temporal_temporal + tne_tgeo_geo, tne_tgeo_geo """ if isinstance(other, shp.Point): gs = geometry_to_gserialized(other) - result = tne_tpoint_point(self._inner, gs) + result = tne_tgeo_geo(self._inner, gs) else: return super().temporal_not_equal(other) return Temporal._factory(result) @@ -1870,9 +1862,9 @@ def to_geometric(self) -> TGeomPoint: A new :class:`TGeomPoint` object. MEOS Functions: - tgeogpoint_to_tgeompoint + tgeography_to_tgeometry """ - result = tgeogpoint_to_tgeompoint(self._inner) + result = tgeography_to_tgeometry(self._inner) return Temporal._factory(result) # ------------------------- Ever and Always Comparisons ------------------- @@ -1887,13 +1879,13 @@ def always_equal(self, value: Union[shpb.BaseGeometry, TGeogPoint]) -> bool: True if `self` is always equal to `value`, False otherwise. MEOS Functions: - always_eq_tpoint_point, always_eq_temporal_temporal + always_eq_tgeo_geo, always_eq_tgeo_tgeo """ if isinstance(value, shpb.BaseGeometry): gs = geography_to_gserialized(value) - return always_eq_tpoint_point(self._inner, gs) > 0 + return always_eq_tgeo_geo(self._inner, gs) > 0 elif isinstance(value, TGeogPoint): - return always_eq_temporal_temporal(self._inner, value._inner) > 0 + return always_eq_tgeo_tgeo(self._inner, value._inner) > 0 else: raise TypeError(f"Operation not supported with type {value.__class__}") @@ -1908,13 +1900,13 @@ def always_not_equal(self, value: Union[shpb.BaseGeometry, TGeogPoint]) -> bool: True if `self` is always different to `value`, False otherwise. MEOS Functions: - always_ne_tpoint_point, always_ne_temporal_temporal + always_ne_tgeo_geo, always_ne_tgeo_tgeo """ if isinstance(value, shpb.BaseGeometry): gs = geography_to_gserialized(value) - return always_ne_tpoint_point(self._inner, gs) > 0 + return always_ne_tgeo_geo(self._inner, gs) > 0 elif isinstance(value, TGeogPoint): - return always_ne_temporal_temporal(self._inner, value._inner) > 0 + return always_ne_tgeo_tgeo(self._inner, value._inner) > 0 else: raise TypeError(f"Operation not supported with type {value.__class__}") @@ -1929,13 +1921,13 @@ def ever_equal(self, value: Union[shpb.BaseGeometry, TGeogPoint]) -> bool: True if `self` is ever equal to `value`, False otherwise. MEOS Functions: - ever_eq_tpoint_point, ever_eq_temporal_temporal + ever_eq_tgeo_geo, ever_eq_tgeo_tgeo """ if isinstance(value, shpb.BaseGeometry): gs = geography_to_gserialized(value) - return ever_eq_tpoint_point(self._inner, gs) > 0 + return ever_eq_tgeo_geo(self._inner, gs) > 0 elif isinstance(value, TGeogPoint): - return ever_eq_temporal_temporal(self._inner, value._inner) > 0 + return ever_eq_tgeo_tgeo(self._inner, value._inner) > 0 else: raise TypeError(f"Operation not supported with type {value.__class__}") @@ -1950,13 +1942,13 @@ def ever_not_equal(self, value: Union[shpb.BaseGeometry, TGeogPoint]) -> bool: True if `self` is ever different to `value`, False otherwise. MEOS Functions: - ever_ne_tpoint_point, ever_ne_temporal_temporal + ever_ne_tgeo_geo, ever_ne_tgeo_tgeo """ if isinstance(value, shpb.BaseGeometry): gs = geography_to_gserialized(value) - return ever_ne_tpoint_point(self._inner, gs) > 0 + return ever_ne_tgeo_geo(self._inner, gs) > 0 elif isinstance(value, TGeogPoint): - return ever_ne_temporal_temporal(self._inner, value._inner) > 0 + return ever_ne_tgeo_tgeo(self._inner, value._inner) > 0 else: raise TypeError(f"Operation not supported with type {value.__class__}") @@ -1971,7 +1963,7 @@ def never_equal(self, value: Union[shpb.BaseGeometry, TGeogPoint]) -> bool: True if `self` is never equal to `value`, False otherwise. MEOS Functions: - ever_eq_tpoint_point, ever_eq_temporal_temporal + ever_eq_tgeo_geo, ever_eq_tgeo_tgeo """ return not self.ever_equal(value) @@ -1986,7 +1978,7 @@ def never_not_equal(self, value: Union[shpb.BaseGeometry, TGeogPoint]) -> bool: True if `self` is never different to `value`, False otherwise. MEOS Functions: - ever_ne_tpoint_point, ever_ne_temporal_temporal + ever_ne_tgeo_geo, ever_ne_tgeo_tgeo """ return not self.ever_not_equal(value) @@ -2002,11 +1994,11 @@ def temporal_equal(self, other: Union[shp.Point, TGeogPoint]) -> TBool: A :class:`TBool` with the result of the temporal equality relation. MEOS Functions: - teq_tpoint_point, teq_temporal_temporal + teq_tgeo_geo, teq_temporal_temporal """ if isinstance(other, shp.Point): gs = geography_to_gserialized(other) - result = teq_tpoint_point(self._inner, gs) + result = teq_tgeo_geo(self._inner, gs) else: return super().temporal_equal(other) return Temporal._factory(result) @@ -2022,11 +2014,11 @@ def temporal_not_equal(self, other: Union[shp.Point, TGeogPoint]) -> TBool: A :class:`TBool` with the result of the temporal inequality relation. MEOS Functions: - tne_tpoint_point, tne_temporal_temporal + tne_tgeo_geo, tne_temporal_temporal """ if isinstance(other, shp.Point): gs = geography_to_gserialized(other) - result = tne_tpoint_point(self._inner, gs) + result = tne_tgeo_geo(self._inner, gs) else: return super().temporal_not_equal(other) return Temporal._factory(result) diff --git a/pymeos/temporal/interpolation.py b/pymeos/temporal/interpolation.py index c3f18a50..b74a3f92 100644 --- a/pymeos/temporal/interpolation.py +++ b/pymeos/temporal/interpolation.py @@ -27,6 +27,8 @@ def to_string(self) -> str: return "Step" elif self == InterpolationType.LINEAR: return "Linear" + else: + raise ValueError() @staticmethod def from_string(source: str, none: bool = True) -> TInterpolation: diff --git a/pymeos/temporal/temporal.py b/pymeos/temporal/temporal.py index cff0ea32..e839cdc9 100644 --- a/pymeos/temporal/temporal.py +++ b/pymeos/temporal/temporal.py @@ -54,6 +54,11 @@ class Temporal(Generic[TBase, TG, TI, TS, TSS], TComparable, TTemporallyEquatabl 2. ``TFloatSeq`` for ``TFloatSeqSet``. """ + DefaultInterpolation: TInterpolation = TInterpolation.STEPWISE + """ + Default interpolation of the class. + """ + _parse_function = None # ------------------------- Constructors ---------------------------------- @@ -654,7 +659,7 @@ def to_sequence(self, interpolation: TInterpolation) -> TS: MEOS Functions: temporal_to_sequence """ - seq = temporal_to_tsequence(self._inner, interpolation.to_string()) + seq = temporal_to_tsequence(self._inner, interpolation) return Temporal._factory(seq) def to_sequenceset(self, interpolation: TInterpolation) -> TSS: @@ -664,7 +669,7 @@ def to_sequenceset(self, interpolation: TInterpolation) -> TSS: MEOS Functions: temporal_to_tsequenceset """ - ss = temporal_to_tsequenceset(self._inner, interpolation.to_string()) + ss = temporal_to_tsequenceset(self._inner, interpolation) return Temporal._factory(ss) def to_dataframe(self) -> pd.DataFrame: @@ -682,6 +687,7 @@ def append_instant( instant: TInstant[TBase], max_dist: Optional[float] = 0.0, max_time: Optional[timedelta] = None, + default_interpolation: TInterpolation = TInterpolation.NONE, ) -> TG: """ Returns a new :class:`Temporal` object equal to `self` with `instant` @@ -691,6 +697,8 @@ def append_instant( instant: :class:`TInstant` to append max_dist: Maximum distance for defining a gap max_time: Maximum time for defining a gap + default_interpolation: Default interpolation to use when appending an instant to another instant. This is + only used when `self` is an instant and ignored otherwise. MEOS Functions: temporal_append_tinstant @@ -699,8 +707,11 @@ def append_instant( interv = None else: interv = timedelta_to_interval(max_time) + interpolation = self.interpolation() + if interpolation == TInterpolation.NONE: + interpolation = self.DefaultInterpolation new_inner = temporal_append_tinstant( - self._inner, instant._inner, max_dist, interv, False + self._inner, instant._inner, interpolation, max_dist, interv, False ) return Temporal._factory(new_inner) diff --git a/tests/main/tbool_test.py b/tests/main/tbool_test.py index 4be963aa..fbcb03fe 100644 --- a/tests/main/tbool_test.py +++ b/tests/main/tbool_test.py @@ -1099,7 +1099,7 @@ def test_shift_scale_time(self): ) @pytest.mark.parametrize( - "tint, delta, expected", + "original, delta, expected", [ (tbi, timedelta(days=4), TBoolInst("True@2019-09-01")), (tbi, timedelta(hours=12), TBoolInst("True@2019-09-01")), @@ -1138,8 +1138,8 @@ def test_shift_scale_time(self): "Sequence Set hours", ], ) - def test_temporal_sample(self, tint, delta, expected): - assert tint.temporal_sample(delta, "2019-09-01") == expected + def test_temporal_sample(self, original, delta, expected): + assert original.temporal_sample(delta, "2019-09-01") == expected class TestTBoolModifications(TestTBool): diff --git a/tests/main/tfloat_test.py b/tests/main/tfloat_test.py index 3ac74bde..7be97ad5 100644 --- a/tests/main/tfloat_test.py +++ b/tests/main/tfloat_test.py @@ -1521,7 +1521,7 @@ def test_temporal_sample(self, tfloat, delta, expected): ( tfds, timedelta(hours=12), - TFloatSeq("{1.5@2019-09-01, 2@2019-09-01 12:00:00+00, 2@2019-09-02}"), + TFloatSeq("{1.5@2019-09-01, 2.5@2019-09-02}"), ), (tfs, timedelta(days=4), TFloatSeq("{[2@2019-08-31]}")), ( @@ -2036,11 +2036,11 @@ def test_to_radians_to_degrees(self, temporal): @pytest.mark.parametrize( "temporal, expected", [ - (tfs, TFloatSeq("Interp=Step;[-1@2019-09-01, -1@2019-09-02]")), + (tfs, TFloatSeq("Interp=Step;[1@2019-09-01, 1@2019-09-02]")), ( tfss, TFloatSeqSet( - "Interp=Step;{[-1@2019-09-01, -1@2019-09-02],[0@2019-09-03, 0@2019-09-05]}" + "Interp=Step;{[1@2019-09-01, 1@2019-09-02],[0@2019-09-03, 0@2019-09-05]}" ), ), ], diff --git a/tests/main/tgeogpoint_test.py b/tests/main/tgeogpoint_test.py index 5e803f9d..6cbadcec 100644 --- a/tests/main/tgeogpoint_test.py +++ b/tests/main/tgeogpoint_test.py @@ -2391,114 +2391,6 @@ def test_temporal_ever_withindist_intersects(self, temporal): print("Hey") -class TestTGeogPointTemporalSpatialOperations(TestTGeogPoint): - tpi = TGeogPointInst("Point(1 1)@2019-09-01") - tpds = TGeogPointSeq("{Point(1 1)@2019-09-01, Point(2 2)@2019-09-02}") - tps = TGeogPointSeq("[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02]") - tpss = TGeogPointSeqSet( - "{[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02],[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" - ) - - @pytest.mark.parametrize( - "temporal, expected", - [ - (tpi, TBoolInst("True@2019-09-01")), - (tpds, TBoolSeq("{True@2019-09-01, False@2019-09-02}")), - ( - tps, - TBoolSeqSet( - "{[True@2019-09-01], (False@2019-09-01, False@2019-09-02]}" - ), - ), - ( - tpss, - TBoolSeqSet( - "{[True@2019-09-01], (False@2019-09-01, False@2019-09-02]," - "[True@2019-09-03, True@2019-09-05]}" - ), - ), - ], - ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], - ) - def test_temporal_intersects_disjoint(self, temporal, expected): - assert temporal.intersects(Point(1, 1)) == expected - assert temporal.disjoint(Point(1, 1)) == ~expected - - # Verify that these results are correct wrt lifting the 9DEM definition of touches - @pytest.mark.parametrize( - "temporal, expected", - [ - (tpi, TBoolInst("False@2019-09-01")), - (tpds, TBoolSeq("{False@2019-09-01, False@2019-09-02}")), - (tps, TBoolSeqSet("[False@2019-09-01, False@2019-09-02]")), - ( - tpss, - TBoolSeqSet( - "{[False@2019-09-01, False@2019-09-02]," - "[False@2019-09-03, False@2019-09-05]}" - ), - ), - ], - ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], - ) - def test_temporal_touches(self, temporal, expected): - assert temporal.touches(Point(1, 1)) == expected - - @pytest.mark.parametrize( - "temporal, argument, expected", - [ - (tpi, Point(1, 1), TBoolInst("True@2019-09-01")), - (tpds, Point(1, 1), TBoolSeq("{True@2019-09-01, True@2019-09-02}")), - (tps, Point(1, 1), TBoolSeqSet("{[True@2019-09-01, True@2019-09-02]}")), - ( - tpss, - Point(1, 1), - TBoolSeqSet( - "{[True@2019-09-01, True@2019-09-02]," - "[True@2019-09-03, True@2019-09-05]}" - ), - ), - ( - tpi, - TGeogPointInst("Point(1 1)@2019-09-01"), - TBoolInst("True@2019-09-01"), - ), - ( - tpds, - TGeogPointSeq("{Point(1 1)@2019-09-01, Point(1 1)@2019-09-02}"), - TBoolSeq("{True@2019-09-01, False@2019-09-02}"), - ), - ( - tps, - TGeogPointSeq("[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02]"), - TBoolSeqSet("{[True@2019-09-01, True@2019-09-02]}"), - ), - ( - tpss, - TGeogPointSeqSet( - "{[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02]," - "[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" - ), - TBoolSeqSet( - "{[True@2019-09-01, True@2019-09-02]," - "[True@2019-09-03, True@2019-09-05]}" - ), - ), - ], - ids=[ - "Instant Geo", - "Discrete Sequence Geo", - "Sequence Geo", - "SequenceSet Geo", - "Instant TPoint", - "Discrete Sequence TPoint", - "Sequence TPoint", - "SequenceSet TPoint", - ], - ) - def test_temporal_withindist(self, temporal, argument, expected): - assert temporal.within_distance(argument, 2) == expected - class TestTGeogPointDistanceOperations(TestTGeogPoint): tpi = TGeogPointInst("Point(1 1)@2019-09-01") diff --git a/tests/main/tgeompoint_test.py b/tests/main/tgeompoint_test.py index abb38b6a..b6f7f1f3 100644 --- a/tests/main/tgeompoint_test.py +++ b/tests/main/tgeompoint_test.py @@ -1894,18 +1894,6 @@ def test_round(self, temporal, expected): def test_make_simple(self, temporal, expected): assert temporal.make_simple() == expected - @pytest.mark.parametrize( - "temporal, expected", - [ - (tpi, STBox("STBOX XT(((-1,-1),(3,3)),[2019-09-01, 2019-09-01])")), - (tpds, STBox("STBOX XT(((-1,-1),(4,4)),[2019-09-01, 2019-09-02])")), - (tps, STBox("STBOX XT(((-1,-1),(4,4)),[2019-09-01, 2019-09-02])")), - (tpss, STBox("STBOX XT(((-1,-1),(4,4)),[2019-09-01, 2019-09-05])")), - ], - ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], - ) - def test_expand(self, temporal, expected): - assert temporal.expand(2) == expected @pytest.mark.parametrize( "temporal, expected", From 70f6d7f667fe9f6c6d0f819b21c260a5fc670d85 Mon Sep 17 00:00:00 2001 From: diviloper Date: Fri, 8 Aug 2025 18:43:09 +0200 Subject: [PATCH 09/21] Drop python versions 3.8 and 3.9 from workflows --- .github/workflows/release_and_publish.yml | 2 +- .github/workflows/test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release_and_publish.yml b/.github/workflows/release_and_publish.yml index 7c5b8858..630852d3 100644 --- a/.github/workflows/release_and_publish.yml +++ b/.github/workflows/release_and_publish.yml @@ -93,7 +93,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v3 with: - python-version: 3.8 + python-version: 3.10 cache: "pip" - name: Setup pip diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8a1327df..e81bb384 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,7 +23,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12", "3.13" ] + python-version: [ "3.10", "3.11", "3.12", "3.13" ] os: [ ubuntu-latest, macos-13, macos-14 ] include: - ld_prefix: "/usr/local" From b8b1f27b47077cf7e23b78bd8860de8d2eea990c Mon Sep 17 00:00:00 2001 From: diviloper Date: Fri, 8 Aug 2025 19:22:07 +0200 Subject: [PATCH 10/21] Ditch black in favour of ruff. Update format and workflow accordingly --- .github/workflows/black.yml | 20 -- .github/workflows/ruff.yml | 26 ++ README.md | 1 - dev-requirements.txt | 3 +- docs/conf.py | 4 +- pymeos/__init__.py | 33 +- pymeos/aggregators/__init__.py | 2 +- pymeos/aggregators/aggregator.py | 49 ++- pymeos/aggregators/bool_aggregators.py | 2 +- pymeos/aggregators/general_aggregators.py | 39 +- pymeos/aggregators/number_aggregators.py | 4 +- pymeos/aggregators/point_aggregators.py | 2 +- pymeos/aggregators/text_aggregators.py | 2 +- pymeos/aggregators/time_aggregators.py | 15 +- pymeos/boxes/box.py | 8 +- pymeos/boxes/stbox.py | 189 ++++------ pymeos/boxes/tbox.py | 138 +++---- pymeos/collections/__init__.py | 3 +- pymeos/collections/base/collection.py | 4 +- pymeos/collections/base/set.py | 57 ++- pymeos/collections/base/span.py | 36 +- pymeos/collections/base/spanset.py | 26 +- pymeos/collections/geo/__init__.py | 2 +- pymeos/collections/geo/geoset.py | 65 ++-- pymeos/collections/number/__init__.py | 6 +- pymeos/collections/number/floatset.py | 62 ++-- pymeos/collections/number/floatspan.py | 90 +++-- pymeos/collections/number/floatspanset.py | 74 ++-- pymeos/collections/number/intset.py | 64 ++-- pymeos/collections/number/intspan.py | 70 ++-- pymeos/collections/number/intspanset.py | 68 ++-- pymeos/collections/text/textset.py | 14 +- pymeos/collections/time/__init__.py | 9 +- pymeos/collections/time/dateset.py | 134 +++---- pymeos/collections/time/datespan.py | 109 +++--- pymeos/collections/time/datespanset.py | 106 +++--- pymeos/collections/time/time.py | 47 +-- pymeos/collections/time/tstzset.py | 161 +++------ pymeos/collections/time/tstzspan.py | 137 +++---- pymeos/collections/time/tstzspanset.py | 123 +++---- pymeos/db/asyncpg.py | 4 +- pymeos/db/db_objects.py | 28 +- pymeos/db/psycopg.py | 2 +- pymeos/db/psycopg2.py | 6 +- pymeos/factory.py | 60 ++-- pymeos/main/__init__.py | 16 +- pymeos/main/tbool.py | 62 ++-- pymeos/main/tfloat.py | 237 +++++------- pymeos/main/tint.py | 138 +++---- pymeos/main/tnumber.py | 103 +++--- pymeos/main/tpoint.py | 357 +++++++------------ pymeos/main/ttext.py | 102 +++--- pymeos/meos_init.py | 10 +- pymeos/mixins/__init__.py | 11 +- pymeos/mixins/comparison.py | 12 +- pymeos/mixins/simplify.py | 24 +- pymeos/mixins/temporal_comparison.py | 10 +- pymeos/plotters/__init__.py | 10 + pymeos/plotters/box_plotter.py | 14 +- pymeos/plotters/point_sequence_plotter.py | 12 +- pymeos/plotters/point_sequenceset_plotter.py | 12 +- pymeos/plotters/range_plotter.py | 15 +- pymeos/plotters/sequence_plotter.py | 7 +- pymeos/plotters/sequenceset_plotter.py | 12 +- pymeos/plotters/time_plotter.py | 2 - pymeos/temporal/interpolation.py | 4 +- pymeos/temporal/temporal.py | 138 +++---- pymeos/temporal/tinstant.py | 22 +- pymeos/temporal/tsequence.py | 22 +- pymeos/temporal/tsequenceset.py | 28 +- ruff.toml | 35 ++ tests/boxes/stbox_test.py | 96 ++--- tests/boxes/tbox_test.py | 72 ++-- tests/collections/number/floatset_test.py | 5 +- tests/collections/number/intset_test.py | 5 +- tests/collections/number/intspan_test.py | 53 +-- tests/collections/text/textset_test.py | 4 +- tests/collections/time/dateset_test.py | 30 +- tests/collections/time/tstzset_test.py | 64 +--- tests/collections/time/tstzspan_test.py | 37 +- tests/collections/time/tstzspanset_test.py | 63 +--- tests/conftest.py | 2 +- tests/main/tbool_test.py | 154 +++----- tests/main/tfloat_test.py | 327 +++++------------ tests/main/tgeogpoint_test.py | 295 ++++----------- tests/main/tgeompoint_test.py | 338 +++++------------- tests/main/tint_test.py | 185 +++------- tests/main/ttext_test.py | 179 +++------- tests/temporal/interpolation_test.py | 3 +- 89 files changed, 1954 insertions(+), 3477 deletions(-) delete mode 100644 .github/workflows/black.yml create mode 100644 .github/workflows/ruff.yml create mode 100644 ruff.toml diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml deleted file mode 100644 index 6b3664b4..00000000 --- a/.github/workflows/black.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: Lint code with Black - -on: - push: - branches: [ "master", "stable-[0-9]+.[0-9]+" ] - pull_request: - branches: [ "master", "stable-[0-9]+.[0-9]+" ] - -jobs: - lint: - name: Lint code with Black - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v4 - - - name: Run Black - uses: psf/black@stable - with: - version: "~= 24.0" \ No newline at end of file diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml new file mode 100644 index 00000000..981e8fd6 --- /dev/null +++ b/.github/workflows/ruff.yml @@ -0,0 +1,26 @@ +name: Lint code with Ruff + +on: + push: + branches: [ "master", "stable-[0-9]+.[0-9]+" ] + pull_request: + branches: [ "master", "stable-[0-9]+.[0-9]+" ] + +jobs: + lint: + name: Lint code with Ruff + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Install Ruff + uses: astral-sh/ruff-action@v3 + with: + args: "--version" + + - name: Check rules + run: "ruff check" + + - name: Check format + run: "ruff format --check --diff" diff --git a/README.md b/README.md index cf5809a4..4e7b5555 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ [![pypi](https://img.shields.io/pypi/v/pymeos.svg)](https://pypi.python.org/pypi/pymeos/) [![docs status](https://readthedocs.org/projects/pymeos/badge/?version=latest)](https://pymeos.readthedocs.io/en/latest/) -[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [MEOS (Mobility Engine, Open Source)](https://www.libmeos.org/) is a C library which enables the manipulation of temporal and spatio-temporal data based on [MobilityDB](https://mobilitydb.com/)'s data types and functions. diff --git a/dev-requirements.txt b/dev-requirements.txt index c1600ba6..674c96cd 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,4 +1,5 @@ python-dateutil shapely geopandas -pytest \ No newline at end of file +pytest +ruff \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index 646778b0..4ab7c3bc 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -70,6 +70,4 @@ def download_file(url, dest_path): prefix = "https://raw.githubusercontent.com/MobilityDB/PyMEOS-Examples/main/" download_file(f"{prefix}PyMEOS_Examples/AIS.ipynb", "src/examples/AIS.ipynb") -download_file( - f"{prefix}PyMEOS_Examples/BerlinMOD.ipynb", "src/examples/BerlinMOD.ipynb" -) +download_file(f"{prefix}PyMEOS_Examples/BerlinMOD.ipynb", "src/examples/BerlinMOD.ipynb") diff --git a/pymeos/__init__.py b/pymeos/__init__.py index fcf085a1..1924c21b 100644 --- a/pymeos/__init__.py +++ b/pymeos/__init__.py @@ -1,34 +1,35 @@ -from .aggregators import * -from .boxes import * -from .main import * -from .meos_init import * -from .temporal import * -from .collections import * from pymeos_cffi import ( - MeosException, - MeosInternalError, - MeosArgumentError, - MeosIoError, - MeosInternalTypeError, - MeosValueOutOfRangeError, - MeosDivisionByZeroError, - MeosMemoryAllocError, MeosAggregationError, + MeosArgumentError, MeosDirectoryError, + MeosDivisionByZeroError, + MeosException, MeosFileError, + MeosGeoJsonInputError, + MeosGeoJsonOutputError, + MeosInternalError, + MeosInternalTypeError, MeosInvalidArgError, MeosInvalidArgTypeError, MeosInvalidArgValueError, + MeosIoError, + MeosMemoryAllocError, MeosMfJsonInputError, MeosMfJsonOutputError, MeosTextInputError, MeosTextOutputError, + MeosValueOutOfRangeError, MeosWkbInputError, MeosWkbOutputError, - MeosGeoJsonInputError, - MeosGeoJsonOutputError, ) +from .aggregators import * +from .boxes import * +from .collections import * +from .main import * +from .meos_init import * +from .temporal import * + __version__ = "1.3.0-alpha-1" __all__ = [ # initialization diff --git a/pymeos/aggregators/__init__.py b/pymeos/aggregators/__init__.py index 1373961b..14d0f140 100644 --- a/pymeos/aggregators/__init__.py +++ b/pymeos/aggregators/__init__.py @@ -1,8 +1,8 @@ from .bool_aggregators import * from .general_aggregators import * from .number_aggregators import * -from .text_aggregators import * from .point_aggregators import * +from .text_aggregators import * from .time_aggregators import * __all__ = [ diff --git a/pymeos/aggregators/aggregator.py b/pymeos/aggregators/aggregator.py index ebe1f249..be86e04d 100644 --- a/pymeos/aggregators/aggregator.py +++ b/pymeos/aggregators/aggregator.py @@ -1,18 +1,19 @@ from __future__ import annotations import abc +from collections.abc import Callable from datetime import datetime, timedelta -from typing import Optional, Union, List, Generic, TypeVar, Callable +from typing import Generic, TypeVar from pymeos_cffi import * from ..boxes import Box +from ..collections import Time from ..factory import _TemporalFactory from ..temporal import Temporal -from ..collections import Time -ResultType = TypeVar("ResultType", bound=Union[Temporal, Time, Box]) -SourceType = TypeVar("SourceType", bound=Union[Temporal, Time, Box]) +ResultType = TypeVar("ResultType", bound=Temporal | Time | Box) +SourceType = TypeVar("SourceType", bound=Temporal | Time | Box) StateType = TypeVar("StateType") SourceMeosType = TypeVar("SourceMeosType") ResultMeosType = TypeVar("ResultMeosType") @@ -33,9 +34,7 @@ class BaseAggregator(Generic[SourceType, ResultType], abc.ABC): """ @staticmethod - def _add_function( - state: Optional[StateType], meos_object: SourceMeosType - ) -> StateType: + def _add_function(state: StateType | None, meos_object: SourceMeosType) -> StateType: """ Add `meos_object` to the aggregation. Usually a MEOS function. Args: @@ -46,7 +45,7 @@ def _add_function( New state of the aggregation after adding `meos_object`. """ - raise NotImplemented + raise NotImplementedError @staticmethod def _final_function(state: StateType) -> ResultMeosType: @@ -62,7 +61,7 @@ def _final_function(state: StateType) -> ResultMeosType: return temporal_tagg_finalfn(state) @classmethod - def _add(cls, state: Optional[StateType], temporal: SourceType) -> StateType: + def _add(cls, state: StateType | None, temporal: SourceType) -> StateType: """ Add the `temporal` object to the aggregation. Args: @@ -90,7 +89,7 @@ def _finish(cls, state) -> ResultType: return _TemporalFactory.create_temporal(result) @classmethod - def aggregate(cls, temporals: List[SourceType]) -> ResultType: + def aggregate(cls, temporals: list[SourceType]) -> ResultType: """ Aggregate a list of PyMEOS object at once. @@ -189,7 +188,7 @@ class BaseGranularAggregator(Generic[SourceType, ResultType, IntervalType, Origi @staticmethod def _add_function( - state: Optional[StateType], + state: StateType | None, meos_object: SourceMeosType, interval: IntervalType, origin: OriginType, @@ -206,7 +205,7 @@ def _add_function( New state of the aggregation after adding `meos_object`. """ - raise NotImplemented + raise NotImplementedError @staticmethod def _final_function(state: StateType) -> ResultMeosType: @@ -224,7 +223,7 @@ def _final_function(state: StateType) -> ResultMeosType: @classmethod def _add( cls, - state: Optional[StateType], + state: StateType | None, temporal: SourceType, interval: IntervalType, origin: OriginType, @@ -244,16 +243,14 @@ def _add( interval_converted = ( timedelta_to_interval(interval) if isinstance(interval, timedelta) - else pg_interval_in(interval, -1) if isinstance(interval, str) else None + else pg_interval_in(interval, -1) + if isinstance(interval, str) + else None ) origin_converted = ( - datetime_to_timestamptz(origin) - if isinstance(origin, datetime) - else pg_timestamptz_in(origin, -1) - ) - return cls._add_function( - state, temporal._inner, interval_converted, origin_converted + datetime_to_timestamptz(origin) if isinstance(origin, datetime) else pg_timestamptz_in(origin, -1) ) + return cls._add_function(state, temporal._inner, interval_converted, origin_converted) @classmethod def _finish(cls, state: StateType) -> ResultType: @@ -270,9 +267,7 @@ def _finish(cls, state: StateType) -> ResultType: return _TemporalFactory.create_temporal(result) @classmethod - def aggregate( - cls, temporals: List[SourceType], interval: IntervalType, origin: OriginType - ) -> ResultType: + def aggregate(cls, temporals: list[SourceType], interval: IntervalType, origin: OriginType) -> ResultType: """ Aggregate a list of PyMEOS object at once with certain granularity. @@ -322,9 +317,7 @@ class GranularAggregation( def __init__( self, - add_function: Callable[ - [Optional[StateType], SourceType, IntervalType, OriginType], StateType - ], + add_function: Callable[[StateType | None, SourceType, IntervalType, OriginType], StateType], finish_function: Callable[[StateType], ResultType], interval: IntervalType, origin: OriginType, @@ -334,7 +327,5 @@ def __init__( self._origin = origin def add(self: SelfAgg, new_temporal: SourceType) -> SelfAgg: - self._state = self._add_function( - self._state, new_temporal, self._interval, self._origin - ) + self._state = self._add_function(self._state, new_temporal, self._interval, self._origin) return self diff --git a/pymeos/aggregators/bool_aggregators.py b/pymeos/aggregators/bool_aggregators.py index 38e2e31b..b6a90060 100644 --- a/pymeos/aggregators/bool_aggregators.py +++ b/pymeos/aggregators/bool_aggregators.py @@ -1,7 +1,7 @@ from pymeos_cffi import * -from .aggregator import BaseAggregator from ..main import TBool +from .aggregator import BaseAggregator class TemporalAndAggregator(BaseAggregator[TBool, TBool]): diff --git a/pymeos/aggregators/general_aggregators.py b/pymeos/aggregators/general_aggregators.py index d50d4486..39a4970e 100644 --- a/pymeos/aggregators/general_aggregators.py +++ b/pymeos/aggregators/general_aggregators.py @@ -1,30 +1,27 @@ from datetime import datetime -from typing import Union from pymeos_cffi import ( - timestamptz_tcount_transfn, datetime_to_timestamptz, - tstzset_tcount_transfn, - temporal_tcount_transfn, - tstzspan_tcount_transfn, - tstzspanset_tcount_transfn, - temporal_extent_transfn, - timestamptz_extent_transfn, set_extent_transfn, span_extent_transfn, spanset_extent_transfn, + temporal_extent_transfn, + temporal_tcount_transfn, + timestamptz_extent_transfn, + timestamptz_tcount_transfn, + tstzset_tcount_transfn, + tstzspan_tcount_transfn, + tstzspanset_tcount_transfn, ) -from .aggregator import BaseAggregator from ..boxes import Box from ..collections import Time, TsTzSet, TsTzSpan, TsTzSpanSet from ..main import TIntSeq, TIntSeqSet from ..temporal import Temporal, TInterpolation +from .aggregator import BaseAggregator -class TemporalInstantCountAggregator( - BaseAggregator[Union[datetime, TsTzSet, Temporal], TIntSeq] -): +class TemporalInstantCountAggregator(BaseAggregator[datetime | TsTzSet | Temporal, TIntSeq]): """ Temporal count for instantaneous temporal objects: @@ -42,19 +39,14 @@ def _add(cls, state, temporal): state = timestamptz_tcount_transfn(state, datetime_to_timestamptz(temporal)) elif isinstance(temporal, TsTzSet): state = tstzset_tcount_transfn(state, temporal._inner) - elif ( - isinstance(temporal, Temporal) - and temporal.interpolation() == TInterpolation.DISCRETE - ): + elif isinstance(temporal, Temporal) and temporal.interpolation() == TInterpolation.DISCRETE: state = temporal_tcount_transfn(state, temporal._inner) else: cls._error(temporal) return state -class TemporalPeriodCountAggregator( - BaseAggregator[Union[TsTzSpan, TsTzSpanSet, Temporal], TIntSeqSet] -): +class TemporalPeriodCountAggregator(BaseAggregator[TsTzSpan | TsTzSpanSet | Temporal, TIntSeqSet]): """ Temporal count for non-instantaneous temporal objects: @@ -72,17 +64,14 @@ def _add(cls, state, temporal): state = tstzspan_tcount_transfn(state, temporal._inner) elif isinstance(temporal, TsTzSpanSet): state = tstzspanset_tcount_transfn(state, temporal._inner) - elif ( - isinstance(temporal, Temporal) - and temporal.interpolation() != TInterpolation.DISCRETE - ): + elif isinstance(temporal, Temporal) and temporal.interpolation() != TInterpolation.DISCRETE: state = temporal_tcount_transfn(state, temporal._inner) else: cls._error(temporal) return state -class TemporalExtentAggregator(BaseAggregator[Union[Time, Temporal], TsTzSpan]): +class TemporalExtentAggregator(BaseAggregator[Time | Temporal, TsTzSpan]): """ Temporal extent of any kind of temporal object, i.e. smallest :class:`~pymeos.time.tstzspan.TsTzSpan` that includes all aggregated temporal objects. @@ -110,5 +99,5 @@ def _add(cls, state, temporal): return state @classmethod - def _finish(cls, state) -> Union[Temporal, Time, Box]: + def _finish(cls, state) -> Temporal | Time | Box: return TsTzSpan(_inner=state) diff --git a/pymeos/aggregators/number_aggregators.py b/pymeos/aggregators/number_aggregators.py index 1087f22e..a8bea3cc 100644 --- a/pymeos/aggregators/number_aggregators.py +++ b/pymeos/aggregators/number_aggregators.py @@ -1,8 +1,8 @@ from pymeos_cffi import * -from .aggregator import BaseAggregator from ..boxes import TBox -from ..main import TInt, TFloat, TNumber +from ..main import TFloat, TInt, TNumber +from .aggregator import BaseAggregator class TemporalAverageAggregator(BaseAggregator[TNumber, TNumber]): diff --git a/pymeos/aggregators/point_aggregators.py b/pymeos/aggregators/point_aggregators.py index c251866f..794218f3 100644 --- a/pymeos/aggregators/point_aggregators.py +++ b/pymeos/aggregators/point_aggregators.py @@ -1,8 +1,8 @@ from pymeos_cffi import tspatial_extent_transfn -from .aggregator import BaseAggregator from ..boxes import STBox from ..main import TPoint +from .aggregator import BaseAggregator class TemporalPointExtentAggregator(BaseAggregator[TPoint, STBox]): diff --git a/pymeos/aggregators/text_aggregators.py b/pymeos/aggregators/text_aggregators.py index 9060b801..904fbd7d 100644 --- a/pymeos/aggregators/text_aggregators.py +++ b/pymeos/aggregators/text_aggregators.py @@ -1,7 +1,7 @@ from pymeos_cffi import * -from .aggregator import BaseAggregator from ..main import TText +from .aggregator import BaseAggregator class TemporalTextMaxAggregator(BaseAggregator[TText, TText]): diff --git a/pymeos/aggregators/time_aggregators.py b/pymeos/aggregators/time_aggregators.py index 72a88a6b..159503d4 100644 --- a/pymeos/aggregators/time_aggregators.py +++ b/pymeos/aggregators/time_aggregators.py @@ -1,22 +1,19 @@ from datetime import datetime -from typing import Union from pymeos_cffi import ( - timestamptz_union_transfn, datetime_to_timestamptz, - set_union_transfn, set_union_finalfn, + set_union_transfn, + timestamptz_union_transfn, union_spanset_span, union_spanset_spanset, ) -from .aggregator import BaseAggregator from ..collections import TsTzSet, TsTzSpan, TsTzSpanSet +from .aggregator import BaseAggregator -class TimeInstantaneousUnionAggregator( - BaseAggregator[Union[datetime, TsTzSet], TsTzSet] -): +class TimeInstantaneousUnionAggregator(BaseAggregator[datetime | TsTzSet, TsTzSet]): """ Temporal union of instantaneous time objects (:class:'~datetime.datetime' and :class:`~pymeos.time.tstzset.TsTzSet`). @@ -41,9 +38,7 @@ def _finish(cls, state) -> TsTzSet: return TsTzSet(_inner=result) -class TimeContinuousUnionAggregator( - BaseAggregator[Union[TsTzSpan, TsTzSpanSet], TsTzSpanSet] -): +class TimeContinuousUnionAggregator(BaseAggregator[TsTzSpan | TsTzSpanSet, TsTzSpanSet]): """ Temporal union of continuous time objects (:class:`~pymeos.time.tstzspan.TsTzSpan` and :class:`~pymeos.time.tstzspanset.TsTzSpanSet`). diff --git a/pymeos/boxes/box.py b/pymeos/boxes/box.py index 5a2aa52a..2fbbcd1e 100644 --- a/pymeos/boxes/box.py +++ b/pymeos/boxes/box.py @@ -1,12 +1,10 @@ -from typing import Union - from .stbox import STBox from .tbox import TBox -Box = Union[TBox, STBox] +Box = TBox | STBox """ -Union type that includes all Box types in PyMEOS: +Union type that includes all Box types in PyMEOS: -- :class:`~pymeos.boxes.tbox.TBox` for numeric temporal boxes. +- :class:`~pymeos.boxes.tbox.TBox` for numeric temporal boxes. - :class:`~pymeos.boxes.stbox.STBox` for spatio-temporal boxes. """ diff --git a/pymeos/boxes/stbox.py b/pymeos/boxes/stbox.py index b6350233..9d24f7bc 100644 --- a/pymeos/boxes/stbox.py +++ b/pymeos/boxes/stbox.py @@ -1,13 +1,13 @@ from __future__ import annotations -from typing import Optional, Union, List, TYPE_CHECKING +from typing import TYPE_CHECKING import shapely.geometry.base as shp from pymeos_cffi import * +from ..collections import * from ..main import TPoint from ..temporal import Temporal -from ..collections import * if TYPE_CHECKING: from .box import Box @@ -42,7 +42,7 @@ class STBox: def _get_box( self, - other: Union[shp.BaseGeometry, STBox, Temporal, Time], + other: shp.BaseGeometry | STBox | Temporal | Time, allow_space_only: bool = True, allow_time_only: bool = False, ) -> STBox: @@ -69,29 +69,24 @@ def _get_box( # ------------------------- Constructors ---------------------------------- def __init__( self, - string: Optional[str] = None, + string: str | None = None, *, - xmin: Optional[Union[str, float]] = None, - xmax: Optional[Union[str, float]] = None, - ymin: Optional[Union[str, float]] = None, - ymax: Optional[Union[str, float]] = None, - zmin: Optional[Union[str, float]] = None, - zmax: Optional[Union[str, float]] = None, - tmin: Optional[Union[str, datetime]] = None, - tmax: Optional[Union[str, datetime]] = None, + xmin: str | float | None = None, + xmax: str | float | None = None, + ymin: str | float | None = None, + ymax: str | float | None = None, + zmin: str | float | None = None, + zmax: str | float | None = None, + tmin: str | datetime | None = None, + tmax: str | datetime | None = None, tmin_inc: bool = True, tmax_inc: bool = True, geodetic: bool = False, - srid: Optional[int] = None, + srid: int | None = None, _inner=None, ): assert (_inner is not None) or (string is not None) != ( - ( - xmin is not None - and xmax is not None - and ymin is not None - and ymax is not None - ) + (xmin is not None and xmax is not None and ymin is not None and ymax is not None) or (tmin is not None and tmax is not None) ), ( "Either string must be not None or at least a bound pair (xmin/max" @@ -105,17 +100,10 @@ def __init__( else: tstzspan = None hast = tmin is not None and tmax is not None - hasx = ( - xmin is not None - and xmax is not None - and ymin is not None - and ymax is not None - ) + hasx = xmin is not None and xmax is not None and ymin is not None and ymax is not None hasz = zmin is not None and zmax is not None if hast: - tstzspan = TsTzSpan( - lower=tmin, upper=tmax, lower_inc=tmin_inc, upper_inc=tmax_inc - )._inner + tstzspan = TsTzSpan(lower=tmin, upper=tmax, lower_inc=tmin_inc, upper_inc=tmax_inc)._inner self._inner = stbox_make( hasx, hasz, @@ -225,7 +213,7 @@ def from_time(time: Time) -> STBox: @staticmethod def from_geometry_time( geometry: shp.BaseGeometry, - time: Union[datetime, TsTzSpan], + time: datetime | TsTzSpan, geodetic: bool = False, ) -> STBox: """ @@ -248,10 +236,7 @@ def from_geometry_time( elif isinstance(time, TsTzSpan): result = geo_tstzspan_to_stbox(gs, time._inner) else: - raise TypeError( - f"Operation not supported with types " - f"{geometry.__class__} and {time.__class__}" - ) + raise TypeError(f"Operation not supported with types {geometry.__class__} and {time.__class__}") return STBox(_inner=result) @staticmethod @@ -272,9 +257,9 @@ def from_tpoint(temporal: TPoint) -> STBox: @staticmethod def from_expanding_bounding_box( - value: Union[shp.BaseGeometry, TPoint, STBox], + value: shp.BaseGeometry | TPoint | STBox, expansion: float, - geodetic: Optional[bool] = False, + geodetic: bool | None = False, ) -> STBox: """ Returns a `STBox` from a `shp.BaseGeometry`, `TPoint` or `STBox` instance, @@ -326,7 +311,7 @@ def __repr__(self): MEOS Functions: stbox_out """ - return f"{self.__class__.__name__}" f"({self})" + return f"{self.__class__.__name__}({self})" def as_wkb(self) -> bytes: """ @@ -431,7 +416,7 @@ def geodetic(self) -> bool: """ return stbox_isgeodetic(self._inner) - def xmin(self) -> Optional[float]: + def xmin(self) -> float | None: """ Returns the minimum X coordinate of ``self``. @@ -443,7 +428,7 @@ def xmin(self) -> Optional[float]: """ return stbox_xmin(self._inner) - def ymin(self) -> Optional[float]: + def ymin(self) -> float | None: """ Returns the minimum Y coordinate of ``self``. @@ -455,7 +440,7 @@ def ymin(self) -> Optional[float]: """ return stbox_ymin(self._inner) - def zmin(self) -> Optional[float]: + def zmin(self) -> float | None: """ Returns the minimum Z coordinate of ``self``. @@ -467,7 +452,7 @@ def zmin(self) -> Optional[float]: """ return stbox_zmin(self._inner) - def tmin(self) -> Optional[datetime]: + def tmin(self) -> datetime | None: """ Returns the starting time of ``self``. @@ -493,7 +478,7 @@ def tmin_inc(self) -> bool: """ return stbox_tmin_inc(self._inner) - def xmax(self) -> Optional[float]: + def xmax(self) -> float | None: """ Returns the maximum X coordinate of ``self``. @@ -505,7 +490,7 @@ def xmax(self) -> Optional[float]: """ return stbox_xmax(self._inner) - def ymax(self) -> Optional[float]: + def ymax(self) -> float | None: """ Returns the maximum Y coordinate of ``self``. @@ -517,7 +502,7 @@ def ymax(self) -> Optional[float]: """ return stbox_ymax(self._inner) - def zmax(self) -> Optional[float]: + def zmax(self) -> float | None: """ Returns the maximum Z coordinate of ``self``. @@ -529,7 +514,7 @@ def zmax(self) -> Optional[float]: """ return stbox_zmax(self._inner) - def tmax(self) -> Optional[datetime]: + def tmax(self) -> datetime | None: """ Returns the ending time of ``self``. @@ -597,7 +582,7 @@ def get_space(self) -> STBox: result = stbox_get_space(self._inner) return STBox(_inner=result) - def expand(self, other: Union[int, float, timedelta]) -> STBox: + def expand(self, other: int | float | timedelta) -> STBox: """ Expands ``self`` with `other`. If `other` is a :class:`int` or a :class:`float`, the result is equal @@ -615,7 +600,7 @@ def expand(self, other: Union[int, float, timedelta]) -> STBox: MEOS Functions: stbox_expand_space, stbox_expand_time """ - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): result = stbox_expand_space(self._inner, float(other)) elif isinstance(other, timedelta): result = stbox_expand_time(self._inner, timedelta_to_interval(other)) @@ -660,9 +645,7 @@ def scale_time(self, duration: timedelta) -> STBox: """ return self.shift_scale_time(duration=duration) - def shift_scale_time( - self, shift: Optional[timedelta] = None, duration: Optional[timedelta] = None - ) -> STBox: + def shift_scale_time(self, shift: timedelta | None = None, duration: timedelta | None = None) -> STBox: """ Returns a new `STBox` with the time dimension shifted by `shift` and with duration `duration`. @@ -680,9 +663,7 @@ def shift_scale_time( See Also: :meth:`TsTzSpan.shift_scale` """ - assert ( - shift is not None or duration is not None - ), "shift and scale deltas must not be both None" + assert shift is not None or duration is not None, "shift and scale deltas must not be both None" result = stbox_shift_scale_time( self._inner, timedelta_to_interval(shift) if shift else None, @@ -690,7 +671,7 @@ def shift_scale_time( ) return STBox(_inner=result) - def round(self, max_decimals: Optional[int] = 0) -> STBox: + def round(self, max_decimals: int | None = 0) -> STBox: """ Returns `self` rounded to the given number of decimal digits. @@ -724,7 +705,7 @@ def transform(self, srid: int) -> STBox: return STBox(_inner=result) # ------------------------- Set Operations -------------------------------- - def union(self, other: STBox, strict: Optional[bool] = False) -> STBox: + def union(self, other: STBox, strict: bool | None = False) -> STBox: """ Returns the union of `self` with `other`. @@ -757,7 +738,7 @@ def __add__(self, other): return self.union(other, False) # TODO: Check returning None for empty intersection is the desired behaviour - def intersection(self, other: STBox) -> Optional[STBox]: + def intersection(self, other: STBox) -> STBox | None: """ Returns the intersection of `self` with `other`. @@ -791,9 +772,7 @@ def __mul__(self, other): return self.intersection(other) # ------------------------- Topological Operations ------------------------ - def is_adjacent( - self, other: Union[shp.BaseGeometry, STBox, Temporal, Time] - ) -> bool: + def is_adjacent(self, other: shp.BaseGeometry | STBox | Temporal | Time) -> bool: """ Returns whether ``self`` and `other` are adjacent. Two spatiotemporal boxes are adjacent if they share n dimensions and the intersection is @@ -810,13 +789,9 @@ def is_adjacent( MEOS Functions: adjacent_stbox_stbox """ - return adjacent_stbox_stbox( - self._inner, self._get_box(other, allow_time_only=True) - ) + return adjacent_stbox_stbox(self._inner, self._get_box(other, allow_time_only=True)) - def is_contained_in( - self, container: Union[shp.BaseGeometry, STBox, Temporal, Time] - ) -> bool: + def is_contained_in(self, container: shp.BaseGeometry | STBox | Temporal | Time) -> bool: """ Returns whether ``self`` is contained in `container`. Note that for `TPoint` instances, the bounding box of the temporal point is used. @@ -831,11 +806,9 @@ def is_contained_in( MEOS Functions: contained_stbox_stbox """ - return contained_stbox_stbox( - self._inner, self._get_box(container, allow_time_only=True) - ) + return contained_stbox_stbox(self._inner, self._get_box(container, allow_time_only=True)) - def contains(self, content: Union[shp.BaseGeometry, STBox, Temporal, Time]) -> bool: + def contains(self, content: shp.BaseGeometry | STBox | Temporal | Time) -> bool: """ Returns whether ``self`` contains `content`. Note that for `TPoint` instances, the bounding box of the temporal point is used. @@ -850,9 +823,7 @@ def contains(self, content: Union[shp.BaseGeometry, STBox, Temporal, Time]) -> b MEOS Functions: contains_stbox_stbox """ - return contains_stbox_stbox( - self._inner, self._get_box(content, allow_time_only=True) - ) + return contains_stbox_stbox(self._inner, self._get_box(content, allow_time_only=True)) def __contains__(self, item): """ @@ -873,7 +844,7 @@ def __contains__(self, item): """ return self.contains(item) - def overlaps(self, other: Union[shp.BaseGeometry, STBox, Temporal, Time]) -> bool: + def overlaps(self, other: shp.BaseGeometry | STBox | Temporal | Time) -> bool: """ Returns whether ``self`` overlaps `other`. Note that for `TPoint` instances, the bounding box of the temporal point is used. @@ -887,11 +858,9 @@ def overlaps(self, other: Union[shp.BaseGeometry, STBox, Temporal, Time]) -> boo MEOS Functions: overlaps_stbox_stbox """ - return overlaps_stbox_stbox( - self._inner, self._get_box(other, allow_time_only=True) - ) + return overlaps_stbox_stbox(self._inner, self._get_box(other, allow_time_only=True)) - def is_same(self, other: Union[shp.BaseGeometry, STBox, Temporal, Time]) -> bool: + def is_same(self, other: shp.BaseGeometry | STBox | Temporal | Time) -> bool: """ Returns whether ``self`` is the same as `other`. Note that for `TPoint` instances, the bounding box of the temporal point is used. @@ -908,7 +877,7 @@ def is_same(self, other: Union[shp.BaseGeometry, STBox, Temporal, Time]) -> bool return same_stbox_stbox(self._inner, self._get_box(other, allow_time_only=True)) # ------------------------- Position Operations --------------------------- - def is_left(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> bool: + def is_left(self, other: shp.BaseGeometry | STBox | TPoint) -> bool: """ Returns whether ``self`` is strictly to the left of `other`. Checks the X dimension. @@ -925,7 +894,7 @@ def is_left(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> bool: """ return left_stbox_stbox(self._inner, self._get_box(other)) - def is_over_or_left(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> bool: + def is_over_or_left(self, other: shp.BaseGeometry | STBox | TPoint) -> bool: """ Returns whether ``self`` is to the left `other` allowing for overlap. That is, ``self`` does not extend to the right of `other`. Checks the @@ -943,7 +912,7 @@ def is_over_or_left(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> bool """ return overleft_stbox_stbox(self._inner, self._get_box(other)) - def is_right(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> bool: + def is_right(self, other: shp.BaseGeometry | STBox | TPoint) -> bool: """ Returns whether ``self`` is strictly to the right of `other`. Checks the X dimension. @@ -960,7 +929,7 @@ def is_right(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> bool: """ return right_stbox_stbox(self._inner, self._get_box(other)) - def is_over_or_right(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> bool: + def is_over_or_right(self, other: shp.BaseGeometry | STBox | TPoint) -> bool: """ Returns whether ``self`` is to the right of `other` allowing for overlap. That is, ``self`` does not extend to the left of `other`. @@ -978,7 +947,7 @@ def is_over_or_right(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> boo """ return overright_stbox_stbox(self._inner, self._get_box(other)) - def is_below(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> bool: + def is_below(self, other: shp.BaseGeometry | STBox | TPoint) -> bool: """ Returns whether ``self`` is strictly below `other`. Checks the Y dimension. @@ -995,7 +964,7 @@ def is_below(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> bool: """ return below_stbox_stbox(self._inner, self._get_box(other)) - def is_over_or_below(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> bool: + def is_over_or_below(self, other: shp.BaseGeometry | STBox | TPoint) -> bool: """ Returns whether ``self`` is below `other` allowing for overlap. That is, ``self`` does not extend above `other`. Checks the Y dimension. @@ -1012,7 +981,7 @@ def is_over_or_below(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> boo """ return overbelow_stbox_stbox(self._inner, self._get_box(other)) - def is_above(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> bool: + def is_above(self, other: shp.BaseGeometry | STBox | TPoint) -> bool: """ Returns whether ``self`` is strictly above `other`. Checks the Y dimension. @@ -1029,7 +998,7 @@ def is_above(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> bool: """ return above_stbox_stbox(self._inner, self._get_box(other)) - def is_over_or_above(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> bool: + def is_over_or_above(self, other: shp.BaseGeometry | STBox | TPoint) -> bool: """ Returns whether ``self`` is above `other` allowing for overlap. That is, ``self`` does not extend below `other`. @@ -1047,7 +1016,7 @@ def is_over_or_above(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> boo """ return overabove_stbox_stbox(self._inner, self._get_box(other)) - def is_front(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> bool: + def is_front(self, other: shp.BaseGeometry | STBox | TPoint) -> bool: """ Returns whether ``self`` is strictly in front of `other`. Checks the Z dimension. @@ -1064,7 +1033,7 @@ def is_front(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> bool: """ return front_stbox_stbox(self._inner, self._get_box(other)) - def is_over_or_front(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> bool: + def is_over_or_front(self, other: shp.BaseGeometry | STBox | TPoint) -> bool: """ Returns whether ``self`` is in front of `other` allowing for overlap. That is, ``self`` does not extend behind `other`. @@ -1082,7 +1051,7 @@ def is_over_or_front(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> boo """ return overfront_stbox_stbox(self._inner, self._get_box(other)) - def is_behind(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> bool: + def is_behind(self, other: shp.BaseGeometry | STBox | TPoint) -> bool: """ Returns whether ``self`` is strictly behind `other`. Checks the Z dimension. @@ -1099,7 +1068,7 @@ def is_behind(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> bool: """ return back_stbox_stbox(self._inner, self._get_box(other)) - def is_over_or_behind(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> bool: + def is_over_or_behind(self, other: shp.BaseGeometry | STBox | TPoint) -> bool: """ Returns whether ``self`` is behind `other` allowing for overlap. That is, ``self`` does not extend in front of `other`. @@ -1117,7 +1086,7 @@ def is_over_or_behind(self, other: Union[shp.BaseGeometry, STBox, TPoint]) -> bo """ return overback_stbox_stbox(self._inner, self._get_box(other)) - def is_before(self, other: Union[Box, Temporal, Time]) -> bool: + def is_before(self, other: Box | Temporal | Time) -> bool: """ Returns whether ``self`` is strictly before `other`. Checks the time dimension. @@ -1131,7 +1100,7 @@ def is_before(self, other: Union[Box, Temporal, Time]) -> bool: """ return self.to_tstzspan().is_before(other) - def is_over_or_before(self, other: Union[Box, Temporal, Time]) -> bool: + def is_over_or_before(self, other: Box | Temporal | Time) -> bool: """ Returns whether ``self`` is before `other` allowing for overlap. That is, ``self`` does not extend after `other`. @@ -1146,7 +1115,7 @@ def is_over_or_before(self, other: Union[Box, Temporal, Time]) -> bool: """ return self.to_tstzspan().is_over_or_before(other) - def is_after(self, other: Union[Box, Temporal, Time]) -> bool: + def is_after(self, other: Box | Temporal | Time) -> bool: """ Returns whether ``self`` is strictly after `other`. Checks the time dimension. @@ -1160,7 +1129,7 @@ def is_after(self, other: Union[Box, Temporal, Time]) -> bool: """ return self.to_tstzspan().is_after(other) - def is_over_or_after(self, other: Union[Box, Temporal, Time]) -> bool: + def is_over_or_after(self, other: Box | Temporal | Time) -> bool: """ Returns whether ``self`` is after `other` allowing for overlap. That is, ``self`` does not extend before `other`. @@ -1176,9 +1145,7 @@ def is_over_or_after(self, other: Union[Box, Temporal, Time]) -> bool: return self.to_tstzspan().is_over_or_after(other) # ------------------------- Distance Operations --------------------------- - def nearest_approach_distance( - self, other: Union[shp.BaseGeometry, STBox, TPoint] - ) -> float: + def nearest_approach_distance(self, other: shp.BaseGeometry | STBox | TPoint) -> float: """ Returns the distance between the nearest points of ``self`` and `other`. @@ -1203,7 +1170,7 @@ def nearest_approach_distance( raise TypeError(f"Operation not supported with type {other.__class__}") # ------------------------- Splitting -------------------------------------- - def quad_split_flat(self) -> List[STBox]: + def quad_split_flat(self) -> list[STBox]: """ Returns a list of 4 (or 8 if `self`has Z dimension) :class:`STBox` instances resulting from the quad split of ``self``. @@ -1227,7 +1194,7 @@ def quad_split_flat(self) -> List[STBox]: boxes, count = stbox_quad_split(self._inner) return [STBox(_inner=boxes + i) for i in range(count)] - def quad_split(self) -> Union[List[List[STBox]], List[List[List[STBox]]]]: + def quad_split(self) -> list[list[STBox]] | list[list[list[STBox]]]: """ Returns a 2D (YxX) or 3D (ZxYxX) list of :class:`STBox` instances resulting from the quad split of ``self``. @@ -1278,12 +1245,12 @@ def quad_split(self) -> Union[List[List[STBox]], List[List[List[STBox]]]]: def tile( self, - size: Optional[float] = None, - duration: Optional[Union[timedelta, str]] = None, - origin: Optional[shp.BaseGeometry] = None, - start: Union[datetime, str, None] = None, + size: float | None = None, + duration: timedelta | str | None = None, + origin: shp.BaseGeometry | None = None, + start: datetime | str | None = None, border_inc: bool = True, - ) -> List[STBox]: + ) -> list[STBox]: """ Returns a list of `STBox` instances representing the tiles of ``self``. @@ -1318,7 +1285,9 @@ def tile( dt = ( timedelta_to_interval(duration) if isinstance(duration, timedelta) - else pg_interval_in(duration, -1) if isinstance(duration, str) else None + else pg_interval_in(duration, -1) + if isinstance(duration, str) + else None ) st = ( datetime_to_timestamptz(start) @@ -1326,21 +1295,17 @@ def tile( else ( pg_timestamptz_in(start, -1) if isinstance(start, str) - else pg_timestamptz_in("2000-01-03", -1) if self.has_t() else 0 + else pg_timestamptz_in("2000-01-03", -1) + if self.has_t() + else 0 ) ) gs = ( geo_to_gserialized(origin, self.geodetic()) if origin is not None - else ( - pgis_geography_in("Point(0 0 0)", -1) - if self.geodetic() - else pgis_geometry_in("Point(0 0 0)", -1) - ) - ) - tiles, count = stbox_space_time_tiles( - self._inner, sz, sz, sz, dt, gs, st, border_inc + else (pgis_geography_in("Point(0 0 0)", -1) if self.geodetic() else pgis_geometry_in("Point(0 0 0)", -1)) ) + tiles, count = stbox_space_time_tiles(self._inner, sz, sz, sz, dt, gs, st, border_inc) return [STBox(_inner=tiles + i) for i in range(count)] # ------------------------- Comparisons ----------------------------------- diff --git a/pymeos/boxes/tbox.py b/pymeos/boxes/tbox.py index 70579571..336ecca1 100644 --- a/pymeos/boxes/tbox.py +++ b/pymeos/boxes/tbox.py @@ -1,11 +1,9 @@ from __future__ import annotations -from typing import Optional, Union, List - from pymeos_cffi import * from ..collections import * -from ..main import TNumber, TInt, TFloat +from ..main import TFloat, TInt, TNumber class TBox: @@ -55,12 +53,12 @@ def _is_float(self) -> bool: # ------------------------- Constructors ---------------------------------- def __init__( self, - string: Optional[str] = None, + string: str | None = None, *, - xmin: Optional[Union[str, int, float]] = None, - xmax: Optional[Union[str, int, float]] = None, - tmin: Optional[Union[str, datetime]] = None, - tmax: Optional[Union[str, datetime]] = None, + xmin: str | int | float | None = None, + xmax: str | int | float | None = None, + tmin: str | datetime | None = None, + tmax: str | datetime | None = None, xmin_inc: bool = True, xmax_inc: bool = False, tmin_inc: bool = True, @@ -68,12 +66,8 @@ def __init__( _inner=None, ): assert (_inner is not None) or (string is not None) != ( - (xmin is not None and xmax is not None) - or (tmin is not None and tmax is not None) - ), ( - "Either string must be not None or at least a bound pair (xmin/max or " - "tmin/max) must be not None" - ) + (xmin is not None and xmax is not None) or (tmin is not None and tmax is not None) + ), "Either string must be not None or at least a bound pair (xmin/max or tmin/max) must be not None" if _inner is not None: self._inner = _inner elif string is not None: @@ -87,9 +81,7 @@ def __init__( else: span = floatspan_make(float(xmin), float(xmax), xmin_inc, xmax_inc) if tmin is not None and tmax is not None: - tstzspan = TsTzSpan( - lower=tmin, upper=tmax, lower_inc=tmin_inc, upper_inc=tmax_inc - )._inner + tstzspan = TsTzSpan(lower=tmin, upper=tmax, lower_inc=tmin_inc, upper_inc=tmax_inc)._inner self._inner = tbox_make(span, tstzspan) def __copy__(self) -> TBox: @@ -140,7 +132,7 @@ def from_hexwkb(hexwkb: str) -> TBox: return TBox(_inner=result) @staticmethod - def from_value(value: Union[int, float, IntSpan, FloatSpan]) -> TBox: + def from_value(value: int | float | IntSpan | FloatSpan) -> TBox: """ Returns a `TBox` from a numeric value or span. The created `TBox` will only have a numerical dimension. @@ -158,9 +150,7 @@ def from_value(value: Union[int, float, IntSpan, FloatSpan]) -> TBox: result = int_to_tbox(value) elif isinstance(value, float): result = float_to_tbox(value) - elif isinstance(value, IntSpan): - result = span_to_tbox(value._inner) - elif isinstance(value, FloatSpan): + elif isinstance(value, (IntSpan, FloatSpan)): result = span_to_tbox(value._inner) else: raise TypeError(f"Operation not supported with type {value.__class__}") @@ -195,9 +185,7 @@ def from_time(time: Time) -> TBox: return TBox(_inner=result) @staticmethod - def from_value_time( - value: Union[int, float, IntSpan, FloatSpan], time: Union[datetime, TsTzSpan] - ) -> TBox: + def from_value_time(value: int | float | IntSpan | FloatSpan, time: datetime | TsTzSpan) -> TBox: """ Returns a `TBox` from a numerical and a temporal object. @@ -222,21 +210,15 @@ def from_value_time( elif isinstance(value, float) and isinstance(time, TsTzSpan): result = float_tstzspan_to_tbox(value, time._inner) elif isinstance(value, IntSpan) and isinstance(time, datetime): - result = numspan_timestamptz_to_tbox( - value._inner, datetime_to_timestamptz(time) - ) + result = numspan_timestamptz_to_tbox(value._inner, datetime_to_timestamptz(time)) elif isinstance(value, IntSpan) and isinstance(time, TsTzSpan): result = numspan_tstzspan_to_tbox(value._inner, time._inner) elif isinstance(value, FloatSpan) and isinstance(time, datetime): - result = numspan_timestamptz_to_tbox( - value._inner, datetime_to_timestamptz(time) - ) + result = numspan_timestamptz_to_tbox(value._inner, datetime_to_timestamptz(time)) elif isinstance(value, FloatSpan) and isinstance(time, TsTzSpan): result = numspan_tstzspan_to_tbox(value._inner, time._inner) else: - raise TypeError( - f"Operation not supported with types {value.__class__} and {time.__class__}" - ) + raise TypeError(f"Operation not supported with types {value.__class__} and {time.__class__}") return TBox(_inner=result) @staticmethod @@ -278,7 +260,7 @@ def __repr__(self): MEOS Functions: tbox_out """ - return f"{self.__class__.__name__}" f"({self})" + return f"{self.__class__.__name__}({self})" def as_wkb(self) -> bytes: """ @@ -462,7 +444,7 @@ def tmax_inc(self) -> bool: return tbox_tmax_inc(self._inner) # ------------------------- Transformation -------------------------------- - def expand(self, other: Union[int, float, timedelta]) -> TBox: + def expand(self, other: int | float | timedelta) -> TBox: """ Returns the result of expanding ``self`` with the ``other``. Depending on the type of ``other``, the expansion will be of the numeric @@ -477,7 +459,7 @@ def expand(self, other: Union[int, float, timedelta]) -> TBox: MEOS Functions: tbox_expand_value, tbox_expand_time """ - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): if self._is_float(): result = tbox_expand_float(self._inner, float(other)) else: @@ -488,7 +470,7 @@ def expand(self, other: Union[int, float, timedelta]) -> TBox: raise TypeError(f"Operation not supported with type {other.__class__}") return TBox(_inner=result) - def shift_value(self, delta: Union[int, float]) -> TBox: + def shift_value(self, delta: int | float) -> TBox: """ Returns a new `TBox` with the value dimension shifted by `delta`. @@ -524,7 +506,7 @@ def shift_time(self, delta: timedelta) -> TBox: """ return self.shift_scale_time(shift=delta) - def scale_value(self, width: Union[int, float]) -> TBox: + def scale_value(self, width: int | float) -> TBox: """ Returns a new `TBox` with the value dimension having width `width`. @@ -562,8 +544,8 @@ def scale_time(self, duration: timedelta) -> TBox: def shift_scale_value( self, - shift: Optional[Union[int, float]] = None, - width: Optional[Union[int, float]] = None, + shift: int | float | None = None, + width: int | float | None = None, ) -> TBox: """ Returns a new TBox with the value span shifted by `shift` and @@ -587,14 +569,10 @@ def shift_scale_value( See Also: :meth:`Span.shift_scale` """ - assert ( - shift is not None or width is not None - ), "shift and width deltas must not be both None" + assert shift is not None or width is not None, "shift and width deltas must not be both None" hasshift = shift is not None haswidth = width is not None - if (shift is None or isinstance(shift, int)) and ( - width is None or isinstance(width, int) - ): + if (shift is None or isinstance(shift, int)) and (width is None or isinstance(width, int)): result = tbox_shift_scale_int( self._inner, shift if shift else 0, @@ -602,9 +580,7 @@ def shift_scale_value( hasshift, haswidth, ) - elif (shift is None or isinstance(shift, float)) and ( - width is None or isinstance(width, float) - ): + elif (shift is None or isinstance(shift, float)) and (width is None or isinstance(width, float)): result = tbox_shift_scale_float( self._inner, shift if shift else 0.0, @@ -616,9 +592,7 @@ def shift_scale_value( raise TypeError(f"Operation not supported with type {self.__class__}") return TBox(_inner=result) - def shift_scale_time( - self, shift: Optional[timedelta] = None, duration: Optional[timedelta] = None - ) -> TBox: + def shift_scale_time(self, shift: timedelta | None = None, duration: timedelta | None = None) -> TBox: """ Returns a new TBox with the temporal span shifted by `shift` and duration `duration`. @@ -643,9 +617,7 @@ def shift_scale_time( See Also: :meth:`TsTzSpan.shift_scale` """ - assert ( - shift is not None or duration is not None - ), "shift and duration deltas must not be both None" + assert shift is not None or duration is not None, "shift and duration deltas must not be both None" result = tbox_shift_scale_time( self._inner, timedelta_to_interval(shift) if shift else None, @@ -671,7 +643,7 @@ def round(self, max_decimals: int = 0) -> TBox: return TBox(_inner=tbox_round(self._inner, max_decimals)) # ------------------------- Set Operations -------------------------------- - def union(self, other: TBox, strict: Optional[bool] = True) -> TBox: + def union(self, other: TBox, strict: bool | None = True) -> TBox: """ Returns the union of `self` with `other`. @@ -704,7 +676,7 @@ def __add__(self, other): return self.union(other, False) # TODO: Check returning None for empty intersection is the desired behaviour - def intersection(self, other: TBox) -> Optional[TBox]: + def intersection(self, other: TBox) -> TBox | None: """ Returns the intersection of `self` with `other`. @@ -738,9 +710,7 @@ def __mul__(self, other): return self.intersection(other) # ------------------------- Topological Operations ------------------------ - def is_adjacent( - self, other: Union[int, float, IntSpan, FloatSpan, TBox, TNumber] - ) -> bool: + def is_adjacent(self, other: int | float | IntSpan | FloatSpan | TBox | TNumber) -> bool: """ Returns whether ``self`` is adjacent to ``other``. That is, they share only the temporal or numerical bound and only one of them contains it. @@ -779,7 +749,7 @@ def is_adjacent( else: raise TypeError(f"Operation not supported with type {other.__class__}") - def is_contained_in(self, container: Union[TBox, TNumber]) -> bool: + def is_contained_in(self, container: TBox | TNumber) -> bool: """ Returns whether ``self`` is contained in ``container``. @@ -807,7 +777,7 @@ def is_contained_in(self, container: Union[TBox, TNumber]) -> bool: else: raise TypeError(f"Operation not supported with type {container.__class__}") - def contains(self, content: Union[TBox, TNumber]) -> bool: + def contains(self, content: TBox | TNumber) -> bool: """ Returns whether ``self`` temporally contains ``content``. @@ -858,7 +828,7 @@ def __contains__(self, item): """ return self.contains(item) - def overlaps(self, other: Union[TBox, TNumber]) -> bool: + def overlaps(self, other: TBox | TNumber) -> bool: """ Returns whether ``self`` overlaps ``other``. That is, both share at least an instant or a value. @@ -879,7 +849,7 @@ def overlaps(self, other: Union[TBox, TNumber]) -> bool: else: raise TypeError(f"Operation not supported with type {other.__class__}") - def is_same(self, other: Union[TBox, TNumber]) -> bool: + def is_same(self, other: TBox | TNumber) -> bool: """ Returns whether ``self`` is the same as ``other``. @@ -901,7 +871,7 @@ def is_same(self, other: Union[TBox, TNumber]) -> bool: raise TypeError(f"Operation not supported with type {other.__class__}") # ------------------------- Position Operations --------------------------- - def is_left(self, other: Union[TBox, TNumber]) -> bool: + def is_left(self, other: TBox | TNumber) -> bool: """ Returns whether ``self`` is strictly to the left of ``other``. @@ -921,7 +891,7 @@ def is_left(self, other: Union[TBox, TNumber]) -> bool: else: raise TypeError(f"Operation not supported with type {other.__class__}") - def is_over_or_left(self, other: Union[TBox, TNumber]) -> bool: + def is_over_or_left(self, other: TBox | TNumber) -> bool: """ Returns whether ``self`` is to the left of ``other`` allowing overlap. That is, ``self`` does not extend to the right of ``other``. @@ -942,7 +912,7 @@ def is_over_or_left(self, other: Union[TBox, TNumber]) -> bool: else: raise TypeError(f"Operation not supported with type {other.__class__}") - def is_right(self, other: Union[TBox, TNumber]) -> bool: + def is_right(self, other: TBox | TNumber) -> bool: """ Returns whether ``self`` is strictly to the right of ``other``. @@ -962,7 +932,7 @@ def is_right(self, other: Union[TBox, TNumber]) -> bool: else: raise TypeError(f"Operation not supported with type {other.__class__}") - def is_over_or_right(self, other: Union[TBox, TNumber]) -> bool: + def is_over_or_right(self, other: TBox | TNumber) -> bool: """ Returns whether ``self`` is to the right of ``other`` allowing overlap. That is, ``self`` does not extend to the left of ``other``. @@ -983,7 +953,7 @@ def is_over_or_right(self, other: Union[TBox, TNumber]) -> bool: else: raise TypeError(f"Operation not supported with type {other.__class__}") - def is_before(self, other: Union[TBox, TNumber]) -> bool: + def is_before(self, other: TBox | TNumber) -> bool: """ Returns whether ``self`` is strictly before ``other``. @@ -1003,7 +973,7 @@ def is_before(self, other: Union[TBox, TNumber]) -> bool: else: raise TypeError(f"Operation not supported with type {other.__class__}") - def is_over_or_before(self, other: Union[TBox, TNumber]) -> bool: + def is_over_or_before(self, other: TBox | TNumber) -> bool: """ Returns whether ``self`` is before ``other`` allowing overlap. That is, ``self`` does not extend after ``other``. @@ -1024,7 +994,7 @@ def is_over_or_before(self, other: Union[TBox, TNumber]) -> bool: else: raise TypeError(f"Operation not supported with type {other.__class__}") - def is_after(self, other: Union[TBox, TNumber]) -> bool: + def is_after(self, other: TBox | TNumber) -> bool: """ Returns whether ``self`` is strictly after ``other``. @@ -1044,7 +1014,7 @@ def is_after(self, other: Union[TBox, TNumber]) -> bool: else: raise TypeError(f"Operation not supported with type {other.__class__}") - def is_over_or_after(self, other: Union[TBox, TNumber]) -> bool: + def is_over_or_after(self, other: TBox | TNumber) -> bool: """ Returns whether ``self`` is after ``other`` allowing overlap. That is, ``self`` does not extend before``other``. @@ -1066,7 +1036,7 @@ def is_over_or_after(self, other: Union[TBox, TNumber]) -> bool: raise TypeError(f"Operation not supported with type {other.__class__}") # ------------------------- Distance Operations --------------------------- - def nearest_approach_distance(self, other: Union[TBox, TNumber]) -> float: + def nearest_approach_distance(self, other: TBox | TNumber) -> float: """ Returns the distance between the nearest points of ``self`` and ``other``. @@ -1096,10 +1066,10 @@ def nearest_approach_distance(self, other: Union[TBox, TNumber]) -> float: def tile( self, size: float, - duration: Union[timedelta, str], + duration: timedelta | str, origin: float = 0.0, - start: Union[datetime, str, None] = None, - ) -> List[TBox]: + start: datetime | str | None = None, + ) -> list[TBox]: """ Returns a list of TBoxes resulting from tiling ``self``. @@ -1116,26 +1086,16 @@ def tile( MEOS Functions: tintbox_tile_list, tfloabox_tile_list """ - dt = ( - timedelta_to_interval(duration) - if isinstance(duration, timedelta) - else pg_interval_in(duration, -1) - ) + dt = timedelta_to_interval(duration) if isinstance(duration, timedelta) else pg_interval_in(duration, -1) st = ( datetime_to_timestamptz(start) if isinstance(start, datetime) - else ( - pg_timestamptz_in(start, -1) - if isinstance(start, str) - else pg_timestamptz_in("2000-01-03", -1) - ) + else (pg_timestamptz_in(start, -1) if isinstance(start, str) else pg_timestamptz_in("2000-01-03", -1)) ) if self._is_float(): tiles, count = tfloatbox_value_time_tiles(self._inner, size, dt, origin, st) else: - tiles, count = tintbox_value_time_tiles( - self._inner, int(size), dt, int(origin), st - ) + tiles, count = tintbox_value_time_tiles(self._inner, int(size), dt, int(origin), st) return [TBox(_inner=tiles + c) for c in range(count)] # ------------------------- Comparisons ----------------------------------- diff --git a/pymeos/collections/__init__.py b/pymeos/collections/__init__.py index 23a0bd61..a741bad8 100644 --- a/pymeos/collections/__init__.py +++ b/pymeos/collections/__init__.py @@ -1,9 +1,8 @@ from .base import * +from .geo import * from .number import * from .text import * from .time import * -from .text import * -from .geo import * __all__ = [ "Set", diff --git a/pymeos/collections/base/collection.py b/pymeos/collections/base/collection.py index b0960748..419e96dc 100644 --- a/pymeos/collections/base/collection.py +++ b/pymeos/collections/base/collection.py @@ -1,7 +1,7 @@ from __future__ import annotations from abc import ABC, abstractmethod -from typing import Generic, TypeVar, Type +from typing import Generic, TypeVar T = TypeVar("T") Self = TypeVar("Self") @@ -50,7 +50,7 @@ def is_right(self, other) -> bool: # ------------------------- Database Operations --------------------------- @classmethod - def read_from_cursor(cls: Type[Self], value, _=None): + def read_from_cursor(cls: type[Self], value, _=None): """ Reads a :class:`Collection` from a database cursor. Used when automatically loading objects from the database. diff --git a/pymeos/collections/base/set.py b/pymeos/collections/base/set.py index c0b4163d..50391327 100644 --- a/pymeos/collections/base/set.py +++ b/pymeos/collections/base/set.py @@ -1,19 +1,18 @@ from __future__ import annotations from abc import ABC, abstractmethod -from typing import Optional, Union, List, overload -from typing import TypeVar, Type, Callable, Any, TYPE_CHECKING, Iterable +from collections.abc import Callable, Iterable +from typing import TYPE_CHECKING, Any, TypeVar, overload from pymeos_cffi import * from .collection import Collection if TYPE_CHECKING: - from .spanset import SpanSet - from .span import Span - - from ..number import IntSet, IntSpan, IntSpanSet, FloatSet, FloatSpan, FloatSpanSet + from ..number import FloatSet, FloatSpan, FloatSpanSet, IntSet, IntSpan, IntSpanSet from ..time import DateSet, DateSpan, DateSpanSet, TsTzSet, TsTzSpan, TsTzSpanSet + from .span import Span + from .spanset import SpanSet T = TypeVar("T") Self = TypeVar("Self", bound="Set[Any]") @@ -26,30 +25,28 @@ class Set(Collection[T], ABC): __slots__ = ["_inner"] - _parse_function: Callable[[str], "CData"] = None - _parse_value_function: Callable[[Union[str, T]], Any] = None - _make_function: Callable[[Iterable[Any]], "CData"] = None + _parse_function: Callable[[str], CData] = None + _parse_value_function: Callable[[str | T], Any] = None + _make_function: Callable[[Iterable[Any]], CData] = None # ------------------------- Constructors ---------------------------------- def __init__( self, - string: Optional[str] = None, + string: str | None = None, *, - elements: Optional[List[Union[str, T]]] = None, + elements: list[str | T] | None = None, _inner=None, ): super().__init__() - assert (_inner is not None) or ( - (string is not None) != (elements is not None) - ), "Either string must be not None or elements must be not" + assert (_inner is not None) or ((string is not None) != (elements is not None)), ( + "Either string must be not None or elements must be not" + ) if _inner is not None: self._inner = _inner elif string is not None: self._inner = self.__class__._parse_function(string) else: - parsed_elements = [ - self.__class__._parse_value_function(ts) for ts in elements - ] + parsed_elements = [self.__class__._parse_value_function(ts) for ts in elements] self._inner = self.__class__._make_function(parsed_elements) def __copy__(self: Self) -> Self: @@ -66,7 +63,7 @@ def __copy__(self: Self) -> Self: return self.__class__(_inner=inner_copy) @classmethod - def from_wkb(cls: Type[Self], wkb: bytes) -> Self: + def from_wkb(cls: type[Self], wkb: bytes) -> Self: """ Returns a `Set` from its WKB representation. Args: @@ -83,7 +80,7 @@ def from_wkb(cls: Type[Self], wkb: bytes) -> Self: return _CollectionFactory.create_collection(set_from_wkb(wkb)) @classmethod - def from_hexwkb(cls: Type[Self], hexwkb: str) -> Self: + def from_hexwkb(cls: type[Self], hexwkb: str) -> Self: """ Returns a `Set` from its WKB representation in hex-encoded ASCII. Args: @@ -97,7 +94,7 @@ def from_hexwkb(cls: Type[Self], hexwkb: str) -> Self: """ from ...factory import _CollectionFactory - return _CollectionFactory.create_collection((set_from_hexwkb(hexwkb))) + return _CollectionFactory.create_collection(set_from_hexwkb(hexwkb)) # ------------------------- Output ---------------------------------------- @abstractmethod @@ -120,7 +117,7 @@ def __repr__(self) -> str: MEOS Functions: set_out """ - return f"{self.__class__.__name__}" f"({self})" + return f"{self.__class__.__name__}({self})" def as_wkb(self) -> bytes: """ @@ -146,16 +143,16 @@ def as_hexwkb(self) -> str: # ------------------------- Conversions ----------------------------------- @overload - def to_span(self: Type[IntSet]) -> IntSpan: ... + def to_span(self: type[IntSet]) -> IntSpan: ... @overload - def to_span(self: Type[FloatSet]) -> FloatSpan: ... + def to_span(self: type[FloatSet]) -> FloatSpan: ... @overload - def to_span(self: Type[TsTzSet]) -> TsTzSpan: ... + def to_span(self: type[TsTzSet]) -> TsTzSpan: ... @overload - def to_span(self: Type[DateSet]) -> DateSpan: ... + def to_span(self: type[DateSet]) -> DateSpan: ... def to_span(self) -> Span: """ @@ -172,16 +169,16 @@ def to_span(self) -> Span: return _CollectionFactory.create_collection(set_span(self._inner)) @overload - def to_spanset(self: Type[IntSet]) -> IntSpanSet: ... + def to_spanset(self: type[IntSet]) -> IntSpanSet: ... @overload - def to_spanset(self: Type[FloatSet]) -> FloatSpanSet: ... + def to_spanset(self: type[FloatSet]) -> FloatSpanSet: ... @overload - def to_spanset(self: Type[TsTzSet]) -> TsTzSpanSet: ... + def to_spanset(self: type[TsTzSet]) -> TsTzSpanSet: ... @overload - def to_spanset(self: Type[DateSet]) -> DateSpanSet: ... + def to_spanset(self: type[DateSet]) -> DateSpanSet: ... def to_spanset(self) -> SpanSet: """ @@ -250,7 +247,7 @@ def element_n(self, n: int) -> T: raise IndexError(f"Index {n} out of bounds") @abstractmethod - def elements(self) -> List[T]: + def elements(self) -> list[T]: """ Returns the list of distinct elements in ``self``. Returns: diff --git a/pymeos/collections/base/span.py b/pymeos/collections/base/span.py index 42b6cc7f..23f1cbb4 100644 --- a/pymeos/collections/base/span.py +++ b/pymeos/collections/base/span.py @@ -1,8 +1,8 @@ from __future__ import annotations from abc import ABC, abstractmethod -from typing import Optional, Union -from typing import TypeVar, Type, Callable, Any, TYPE_CHECKING +from collections.abc import Callable +from typing import TYPE_CHECKING, Any, TypeVar from pymeos_cffi import * @@ -22,25 +22,25 @@ class Span(Collection[T], ABC): __slots__ = ["_inner"] - _parse_function: Callable[[str], "CData"] = None - _parse_value_function: Callable[[Union[str, T]], Any] = None - _make_function: Callable[[Any, Any, bool, bool], "CData"] = None + _parse_function: Callable[[str], CData] = None + _parse_value_function: Callable[[str | T], Any] = None + _make_function: Callable[[Any, Any, bool, bool], CData] = None # ------------------------- Constructors ---------------------------------- def __init__( self, - string: Optional[str] = None, + string: str | None = None, *, - lower: Optional[Union[str, T]] = None, - upper: Optional[Union[str, T]] = None, - lower_inc: Optional[bool] = True, - upper_inc: Optional[bool] = False, + lower: str | T | None = None, + upper: str | T | None = None, + lower_inc: bool | None = True, + upper_inc: bool | None = False, _inner=None, ): super().__init__() - assert (_inner is not None) or ( - (string is not None) != (lower is not None and upper is not None) - ), "Either string must be not None or both lower and upper must be not" + assert (_inner is not None) or ((string is not None) != (lower is not None and upper is not None)), ( + "Either string must be not None or both lower and upper must be not" + ) if _inner is not None: self._inner = _inner elif string is not None: @@ -48,9 +48,7 @@ def __init__( else: lower_converted = self.__class__._parse_value_function(lower) upper_converted = self.__class__._parse_value_function(upper) - self._inner = self.__class__._make_function( - lower_converted, upper_converted, lower_inc, upper_inc - ) + self._inner = self.__class__._make_function(lower_converted, upper_converted, lower_inc, upper_inc) def __copy__(self: Self) -> Self: """ @@ -66,7 +64,7 @@ def __copy__(self: Self) -> Self: return self.__class__(_inner=inner_copy) @classmethod - def from_wkb(cls: Type[Self], wkb: bytes) -> Self: + def from_wkb(cls: type[Self], wkb: bytes) -> Self: """ Returns a `TsTzSpan` from its WKB representation. @@ -82,7 +80,7 @@ def from_wkb(cls: Type[Self], wkb: bytes) -> Self: return cls(_inner=(span_from_wkb(wkb))) @classmethod - def from_hexwkb(cls: Type[Self], hexwkb: str) -> Self: + def from_hexwkb(cls: type[Self], hexwkb: str) -> Self: """ Returns a `TsTzSpan` from its WKB representation in hex-encoded ASCII. @@ -116,7 +114,7 @@ def __repr__(self): Returns: A new :class:`str` instance """ - return f"{self.__class__.__name__}" f"({self})" + return f"{self.__class__.__name__}({self})" def as_wkb(self) -> bytes: """ diff --git a/pymeos/collections/base/spanset.py b/pymeos/collections/base/spanset.py index 8830b575..232fb5f3 100644 --- a/pymeos/collections/base/spanset.py +++ b/pymeos/collections/base/spanset.py @@ -1,8 +1,8 @@ from __future__ import annotations from abc import ABC, abstractmethod -from typing import Optional, Union -from typing import TypeVar, Type, Callable, Any, TYPE_CHECKING, List +from collections.abc import Callable +from typing import TYPE_CHECKING, Any, TypeVar from pymeos_cffi import * @@ -22,22 +22,22 @@ class SpanSet(Collection[T], ABC): __slots__ = ["_inner"] - _parse_function: Callable[[str], "CData"] = None - _parse_value_function: Callable[[Union[str, T]], Any] = None + _parse_function: Callable[[str], CData] = None + _parse_value_function: Callable[[str | T], Any] = None # ------------------------- Constructors ---------------------------------- def __init__( self, - string: Optional[str] = None, + string: str | None = None, *, - span_list: Optional[List[Union[str, Span]]] = None, + span_list: list[str | Span] | None = None, normalize: bool = True, _inner=None, ): super().__init__() - assert (_inner is not None) or ( - (string is not None) != (span_list is not None) - ), "Either string must be not None or span_list must be not" + assert (_inner is not None) or ((string is not None) != (span_list is not None)), ( + "Either string must be not None or span_list must be not" + ) if _inner is not None: self._inner = _inner elif string is not None: @@ -60,7 +60,7 @@ def __copy__(self: Self) -> Self: return self.__class__(_inner=inner_copy) @classmethod - def from_wkb(cls: Type[Self], wkb: bytes) -> Self: + def from_wkb(cls: type[Self], wkb: bytes) -> Self: """ Returns a `SpanSet` from its WKB representation. @@ -77,7 +77,7 @@ def from_wkb(cls: Type[Self], wkb: bytes) -> Self: return cls(_inner=result) @classmethod - def from_hexwkb(cls: Type[Self], hexwkb: str) -> Self: + def from_hexwkb(cls: type[Self], hexwkb: str) -> Self: """ Returns a `SpanSet` from its WKB representation in hex-encoded ASCII. Args: @@ -113,7 +113,7 @@ def __repr__(self): MEOS Functions: tstzspanset_out """ - return f"{self.__class__.__name__}" f"({self})" + return f"{self.__class__.__name__}({self})" def as_wkb(self) -> bytes: """ @@ -202,7 +202,7 @@ def span_n(self, n: int) -> Span: return spanset_span_n(self._inner, n + 1) @abstractmethod - def spans(self) -> List[Span]: + def spans(self) -> list[Span]: """ Returns the list of tstzspans in ``self``. Returns: diff --git a/pymeos/collections/geo/__init__.py b/pymeos/collections/geo/__init__.py index c53cefa1..c2476061 100644 --- a/pymeos/collections/geo/__init__.py +++ b/pymeos/collections/geo/__init__.py @@ -1,3 +1,3 @@ -from .geoset import GeoSet, GeometrySet, GeographySet +from .geoset import GeographySet, GeometrySet, GeoSet __all__ = ["GeoSet", "GeometrySet", "GeographySet"] diff --git a/pymeos/collections/geo/geoset.py b/pymeos/collections/geo/geoset.py index dd50e16f..80e18468 100644 --- a/pymeos/collections/geo/geoset.py +++ b/pymeos/collections/geo/geoset.py @@ -1,32 +1,32 @@ from __future__ import annotations from abc import ABC -from typing import List, overload, Optional, Union, TypeVar +from typing import TypeVar, overload import shapely as shp from pymeos_cffi import ( - geoset_start_value, - gserialized_to_shapely_geometry, + geog_in, + geography_to_gserialized, + geogset_in, + geom_in, + geometry_to_gserialized, + geomset_in, geoset_end_value, + geoset_make, + geoset_start_value, geoset_value_n, geoset_values, + gserialized_to_shapely_geometry, intersection_set_geo, + intersection_set_set, + minus_geo_set, minus_set_geo, - union_set_geo, + minus_set_set, + set_round, spatialset_as_ewkt, spatialset_as_text, - geoset_make, spatialset_srid, - set_round, - minus_geo_set, - geomset_in, - geogset_in, - geom_in, - geometry_to_gserialized, - geog_in, - geography_to_gserialized, - intersection_set_set, - minus_set_set, + union_set_geo, union_set_set, ) @@ -151,7 +151,7 @@ def element_n(self, n: int) -> shp.Geometry: super().element_n(n) return gserialized_to_shapely_geometry(geoset_value_n(self._inner, n + 1)[0]) - def elements(self) -> List[shp.Geometry]: + def elements(self) -> list[shp.Geometry]: """ Returns a list of all elements in ``self``. @@ -162,10 +162,7 @@ def elements(self) -> List[shp.Geometry]: geoset_values """ elems = geoset_values(self._inner) - return [ - gserialized_to_shapely_geometry(elems[i]) - for i in range(self.num_elements()) - ] + return [gserialized_to_shapely_geometry(elems[i]) for i in range(self.num_elements())] def srid(self) -> int: """ @@ -181,7 +178,7 @@ def srid(self) -> int: # ------------------------- Topological Operations -------------------------------- - def contains(self, content: Union[GeoSet, str]) -> bool: + def contains(self, content: GeoSet | str) -> bool: """ Returns whether ``self`` contains ``content``. @@ -196,10 +193,10 @@ def contains(self, content: Union[GeoSet, str]) -> bool: # ------------------------- Set Operations -------------------------------- @overload - def intersection(self, other: shp.Geometry) -> Optional[shp.Geometry]: ... + def intersection(self, other: shp.Geometry) -> shp.Geometry | None: ... @overload - def intersection(self, other: GeoSet) -> Optional[GeoSet]: ... + def intersection(self, other: GeoSet) -> GeoSet | None: ... def intersection(self, other): """ @@ -215,16 +212,14 @@ def intersection(self, other): intersection_set_geo, intersection_set_set """ if isinstance(other, shp.Geometry): - return gserialized_to_shapely_geometry( - intersection_set_geo(self._inner, geometry_to_gserialized(other))[0] - ) + return gserialized_to_shapely_geometry(intersection_set_geo(self._inner, geometry_to_gserialized(other))[0]) elif isinstance(other, GeoSet): result = intersection_set_set(self._inner, other._inner) return GeoSet(_inner=result) if result is not None else None else: return super().intersection(other) - def minus(self, other: Union[GeoSet, shp.Geometry]) -> Optional[GeoSet]: + def minus(self, other: GeoSet | shp.Geometry) -> GeoSet | None: """ Returns the difference of ``self`` and ``other``. @@ -249,7 +244,7 @@ def minus(self, other: Union[GeoSet, shp.Geometry]) -> Optional[GeoSet]: else: return super().minus(other) - def subtract_from(self, other: shp.Geometry) -> Optional[shp.Geometry]: + def subtract_from(self, other: shp.Geometry) -> shp.Geometry | None: """ Returns the difference of ``other`` and ``self``. @@ -266,11 +261,9 @@ def subtract_from(self, other: shp.Geometry) -> Optional[shp.Geometry]: :meth:`minus` """ result = minus_geo_set(geometry_to_gserialized(other), self._inner) - return ( - gserialized_to_shapely_geometry(result[0]) if result is not None else None - ) + return gserialized_to_shapely_geometry(result[0]) if result is not None else None - def union(self, other: Union[GeoSet, shp.Geometry]) -> GeoSet: + def union(self, other: GeoSet | shp.Geometry) -> GeoSet: """ Returns the union of ``self`` and ``other``. @@ -314,15 +307,11 @@ class GeometrySet(GeoSet): _mobilitydb_name = "geomset" _parse_function = geomset_in - _parse_value_function = lambda x: ( - geom_in(x, -1) if isinstance(x, str) else geometry_to_gserialized(x) - ) + _parse_value_function = lambda x: (geom_in(x, -1) if isinstance(x, str) else geometry_to_gserialized(x)) class GeographySet(GeoSet): _mobilitydb_name = "geogset" _parse_function = geogset_in - _parse_value_function = lambda x: ( - geog_in(x, -1) if isinstance(x, str) else geography_to_gserialized(x) - ) + _parse_value_function = lambda x: (geog_in(x, -1) if isinstance(x, str) else geography_to_gserialized(x)) diff --git a/pymeos/collections/number/__init__.py b/pymeos/collections/number/__init__.py index b2839db0..6b73300c 100644 --- a/pymeos/collections/number/__init__.py +++ b/pymeos/collections/number/__init__.py @@ -1,8 +1,8 @@ -from .intset import IntSet -from .intspan import IntSpan -from .intspanset import IntSpanSet from .floatset import FloatSet from .floatspan import FloatSpan from .floatspanset import FloatSpanSet +from .intset import IntSet +from .intspan import IntSpan +from .intspanset import IntSpanSet __all__ = ["IntSet", "IntSpan", "IntSpanSet", "FloatSet", "FloatSpan", "FloatSpanSet"] diff --git a/pymeos/collections/number/floatset.py b/pymeos/collections/number/floatset.py index 000241e8..f1332d30 100644 --- a/pymeos/collections/number/floatset.py +++ b/pymeos/collections/number/floatset.py @@ -1,35 +1,35 @@ from __future__ import annotations -from typing import List, Union, overload, Optional, TYPE_CHECKING +from typing import TYPE_CHECKING, overload from pymeos_cffi import ( + contains_set_float, + distance_floatset_floatset, + distance_set_float, + floatset_end_value, floatset_in, floatset_make, floatset_out, + floatset_shift_scale, floatset_start_value, - floatset_end_value, floatset_value_n, floatset_values, - contains_set_float, intersection_set_float, intersection_set_set, left_set_float, - overleft_set_float, - right_set_float, - overright_set_float, + minus_float_set, minus_set_float, minus_set_set, - union_set_set, + overleft_set_float, + overright_set_float, + right_set_float, union_set_float, - floatset_shift_scale, - minus_float_set, - distance_set_float, - distance_floatset_floatset, + union_set_set, ) +from ..base import Set from .floatspan import FloatSpan from .floatspanset import FloatSpanSet -from ..base import Set if TYPE_CHECKING: from .intset import IntSet @@ -131,7 +131,7 @@ def element_n(self, n: int) -> float: super().element_n(n) return floatset_value_n(self._inner, n + 1) - def elements(self) -> List[float]: + def elements(self) -> list[float]: """ Returns the elements in ``self``. @@ -177,9 +177,7 @@ def scale(self, new_width: float) -> FloatSet: """ return self.shift_scale(None, new_width) - def shift_scale( - self, delta: Optional[float], new_width: Optional[float] - ) -> FloatSet: + def shift_scale(self, delta: float | None, new_width: float | None) -> FloatSet: """ Returns a new ``FloatSet`` instance with all elements shifted by ``delta`` and scaled to so that the encompassing span has width ``new_width``. @@ -195,14 +193,12 @@ def shift_scale( floatset_shift_scale """ return FloatSet( - _inner=floatset_shift_scale( - self._inner, delta, new_width, delta is not None, new_width is not None - ) + _inner=floatset_shift_scale(self._inner, delta, new_width, delta is not None, new_width is not None) ) # ------------------------- Topological Operations -------------------------------- - def contains(self, content: Union[FloatSet, float]) -> bool: + def contains(self, content: FloatSet | float) -> bool: """ Returns whether ``self`` contains ``content``. @@ -222,7 +218,7 @@ def contains(self, content: Union[FloatSet, float]) -> bool: # ------------------------- Position Operations -------------------------------- - def is_left(self, content: Union[FloatSet, float]) -> bool: + def is_left(self, content: FloatSet | float) -> bool: """ Returns whether ``self`` is strictly to the left of ``other``. That is, ``self`` ends before ``other`` starts. @@ -241,7 +237,7 @@ def is_left(self, content: Union[FloatSet, float]) -> bool: else: return super().is_left(content) - def is_over_or_left(self, content: Union[FloatSet, float]) -> bool: + def is_over_or_left(self, content: FloatSet | float) -> bool: """ Returns whether ``self`` is to the left of ``other`` allowing overlap. That is, ``self`` ends before ``other`` ends (or at the same value). @@ -260,7 +256,7 @@ def is_over_or_left(self, content: Union[FloatSet, float]) -> bool: else: return super().is_over_or_left(content) - def is_right(self, content: Union[FloatSet, float]) -> bool: + def is_right(self, content: FloatSet | float) -> bool: """ Returns whether ``self`` is strictly to the left of ``other``. That is, ``self`` starts before ``other`` ends. @@ -279,7 +275,7 @@ def is_right(self, content: Union[FloatSet, float]) -> bool: else: return super().is_right(content) - def is_over_or_right(self, content: Union[FloatSet, float]) -> bool: + def is_over_or_right(self, content: FloatSet | float) -> bool: """ Returns whether ``self`` is to the right of ``other`` allowing overlap. That is, ``self`` ends after ``other`` ends (or at the same value). @@ -301,10 +297,10 @@ def is_over_or_right(self, content: Union[FloatSet, float]) -> bool: # ------------------------- Set Operations -------------------------------- @overload - def intersection(self, other: float) -> Optional[float]: ... + def intersection(self, other: float) -> float | None: ... @overload - def intersection(self, other: FloatSet) -> Optional[FloatSet]: ... + def intersection(self, other: FloatSet) -> FloatSet | None: ... def intersection(self, other): """ @@ -327,7 +323,7 @@ def intersection(self, other): else: return super().intersection(other) - def minus(self, other: Union[FloatSet, float]) -> Optional[FloatSet]: + def minus(self, other: FloatSet | float) -> FloatSet | None: """ Returns the difference of ``self`` and ``other``. @@ -349,7 +345,7 @@ def minus(self, other: Union[FloatSet, float]) -> Optional[FloatSet]: else: return super().minus(other) - def subtract_from(self, other: float) -> Optional[float]: + def subtract_from(self, other: float) -> float | None: """ Returns the difference of ``other`` and ``self``. @@ -367,7 +363,7 @@ def subtract_from(self, other: float) -> Optional[float]: """ return minus_float_set(other, self._inner) - def union(self, other: Union[FloatSet, float]) -> FloatSet: + def union(self, other: FloatSet | float) -> FloatSet: """ Returns the union of ``self`` and ``other``. @@ -391,9 +387,7 @@ def union(self, other: Union[FloatSet, float]) -> FloatSet: # ------------------------- Distance Operations --------------------------- - def distance( - self, other: Union[int, float, FloatSet, FloatSpan, FloatSpanSet] - ) -> float: + def distance(self, other: int | float | FloatSet | FloatSpan | FloatSpanSet) -> float: """ Returns the distance between ``self`` and ``other``. @@ -416,9 +410,7 @@ def distance( return distance_set_float(self._inner, other) elif isinstance(other, FloatSet): return distance_floatset_floatset(self._inner, other._inner) - elif isinstance(other, FloatSpan): - return self.to_spanset().distance(other) - elif isinstance(other, FloatSpanSet): + elif isinstance(other, (FloatSpan, FloatSpanSet)): return self.to_spanset().distance(other) else: return super().distance(other) diff --git a/pymeos/collections/number/floatspan.py b/pymeos/collections/number/floatspan.py index c14f3241..0750e220 100644 --- a/pymeos/collections/number/floatspan.py +++ b/pymeos/collections/number/floatspan.py @@ -1,36 +1,36 @@ from __future__ import annotations -from typing import Union, overload, Optional, TYPE_CHECKING +from typing import TYPE_CHECKING, overload from pymeos_cffi import ( - intersection_span_float, + adjacent_span_float, + contains_span_float, + distance_floatspan_floatspan, + distance_floatspanset_floatspan, distance_span_float, + float_to_span, floatspan_in, floatspan_lower, - floatspan_upper, + floatspan_make, + floatspan_out, floatspan_shift_scale, - contains_span_float, - adjacent_span_float, - float_to_span, - span_eq, - left_span_float, - overleft_span_float, - right_span_float, - overright_span_float, + floatspan_to_intspan, + floatspan_upper, + floatspan_width, + intersection_span_float, intersection_span_span, intersection_spanset_span, + left_span_float, minus_span_float, minus_span_span, minus_spanset_span, + overleft_span_float, + overright_span_float, + right_span_float, + span_eq, union_span_float, union_span_span, union_spanset_span, - floatspan_out, - floatspan_make, - floatspan_width, - floatspan_to_intspan, - distance_floatspan_floatspan, - distance_floatspanset_floatspan, ) from ..base import Span @@ -183,7 +183,7 @@ def scale(self, width: float) -> FloatSpan: """ return self.shift_scale(None, width) - def shift_scale(self, delta: Optional[float], width: Optional[float]) -> FloatSpan: + def shift_scale(self, delta: float | None, width: float | None) -> FloatSpan: """ Return a new ``FloatSpan`` with the lower and upper bounds shifted by ``delta`` and scaled so that the width is ``width``. @@ -200,14 +200,12 @@ def shift_scale(self, delta: Optional[float], width: Optional[float]) -> FloatSp """ d = delta if delta is not None else 0 w = width if width is not None else 0 - modified = floatspan_shift_scale( - self._inner, d, w, delta is not None, width is not None - ) + modified = floatspan_shift_scale(self._inner, d, w, delta is not None, width is not None) return FloatSpan(_inner=modified) # ------------------------- Topological Operations -------------------------------- - def is_adjacent(self, other: Union[int, float, FloatSpan, FloatSpanSet]) -> bool: + def is_adjacent(self, other: int | float | FloatSpan | FloatSpanSet) -> bool: """ Returns whether ``self`` is adjacent to ``other``. That is, they share a bound but only one of them contains it. @@ -221,12 +219,12 @@ def is_adjacent(self, other: Union[int, float, FloatSpan, FloatSpanSet]) -> bool MEOS Functions: adjacent_span_span, adjacent_span_spanset, adjacent_span_float """ - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): return adjacent_span_float(self._inner, float(other)) else: return super().is_adjacent(other) - def contains(self, content: Union[int, float, FloatSpan, FloatSpanSet]) -> bool: + def contains(self, content: int | float | FloatSpan | FloatSpanSet) -> bool: """ Returns whether ``self`` contains ``content``. @@ -239,12 +237,12 @@ def contains(self, content: Union[int, float, FloatSpan, FloatSpanSet]) -> bool: MEOS Functions: contains_set_set, contains_span_float """ - if isinstance(content, int) or isinstance(content, float): + if isinstance(content, (int, float)): return contains_span_float(self._inner, float(content)) else: return super().contains(content) - def is_same(self, other: Union[int, float, FloatSpan, FloatSpanSet]) -> bool: + def is_same(self, other: int | float | FloatSpan | FloatSpanSet) -> bool: """ Returns whether ``self`` and the bounding tstzspan of ``other`` is the same. @@ -258,13 +256,13 @@ def is_same(self, other: Union[int, float, FloatSpan, FloatSpanSet]) -> bool: MEOS Functions: same_tstzspan_temporal """ - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): return span_eq(self._inner, float_to_span(float(other))) else: return super().is_same(other) # ------------------------- Position Operations --------------------------- - def is_left(self, other: Union[int, float, FloatSpan, FloatSpanSet]) -> bool: + def is_left(self, other: int | float | FloatSpan | FloatSpanSet) -> bool: """ Returns whether ``self`` is strictly before ``other``. That is, ``self`` ends before ``other`` starts. @@ -278,14 +276,12 @@ def is_left(self, other: Union[int, float, FloatSpan, FloatSpanSet]) -> bool: MEOS Functions: left_span_span, left_span_spanset, left_span_float """ - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): return left_span_float(self._inner, float(other)) else: return super().is_left(other) - def is_over_or_left( - self, other: Union[int, float, FloatSpan, FloatSpanSet] - ) -> bool: + def is_over_or_left(self, other: int | float | FloatSpan | FloatSpanSet) -> bool: """ Returns whether ``self`` is before ``other`` allowing overlap. That is, ``self`` ends before ``other`` ends (or at the same value). @@ -299,12 +295,12 @@ def is_over_or_left( MEOS Functions: overleft_span_span, overleft_span_spanset, overleft_span_float """ - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): return overleft_span_float(self._inner, float(other)) else: return super().is_over_or_left(other) - def is_right(self, other: Union[int, float, FloatSpan, FloatSpanSet]) -> bool: + def is_right(self, other: int | float | FloatSpan | FloatSpanSet) -> bool: """ Returns whether ``self`` is strictly after ``other``. That is, ``self`` starts after ``other`` ends. @@ -318,12 +314,12 @@ def is_right(self, other: Union[int, float, FloatSpan, FloatSpanSet]) -> bool: MEOS Functions: right_span_span, right_span_spanset, right_span_float """ - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): return right_span_float(self._inner, float(other)) else: return super().is_right(other) - def is_over_or_right(self, other: Union[float, FloatSpan, FloatSpanSet]) -> bool: + def is_over_or_right(self, other: float | FloatSpan | FloatSpanSet) -> bool: """ Returns whether ``self`` is after ``other`` allowing overlap. That is, ``self`` starts after ``other`` starts (or at the same value). @@ -337,15 +333,13 @@ def is_over_or_right(self, other: Union[float, FloatSpan, FloatSpanSet]) -> bool MEOS Functions: overright_span_span, overright_span_spanset, overright_span_float """ - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): return overright_span_float(self._inner, float(other)) else: return super().is_over_or_right(other) # ------------------------- Distance Operations --------------------------- - def distance( - self, other: Union[int, float, FloatSet, FloatSpan, FloatSpanSet] - ) -> float: + def distance(self, other: int | float | FloatSet | FloatSpan | FloatSpanSet) -> float: """ Returns the distance between ``self`` and ``other``. @@ -377,13 +371,13 @@ def distance( # ------------------------- Set Operations -------------------------------- @overload - def intersection(self, other: Union[int, float]) -> Optional[float]: ... + def intersection(self, other: int | float) -> float | None: ... @overload - def intersection(self, other: FloatSpan) -> Optional[FloatSpan]: ... + def intersection(self, other: FloatSpan) -> FloatSpan | None: ... @overload - def intersection(self, other: FloatSpanSet) -> Optional[FloatSpanSet]: ... + def intersection(self, other: FloatSpanSet) -> FloatSpanSet | None: ... def intersection(self, other): """ @@ -402,7 +396,7 @@ def intersection(self, other): """ from .floatspanset import FloatSpanSet - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): return intersection_span_float(self._inner, float(other)) elif isinstance(other, FloatSpan): result = intersection_span_span(self._inner, other._inner) @@ -413,7 +407,7 @@ def intersection(self, other): else: super().intersection(other) - def minus(self, other: Union[int, float, FloatSpan, FloatSpanSet]) -> FloatSpanSet: + def minus(self, other: int | float | FloatSpan | FloatSpanSet) -> FloatSpanSet: """ Returns the difference of ``self`` and ``other``. @@ -428,7 +422,7 @@ def minus(self, other: Union[int, float, FloatSpan, FloatSpanSet]) -> FloatSpanS """ from .floatspanset import FloatSpanSet - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): result = minus_span_float(self._inner, float(other)) elif isinstance(other, FloatSpan): result = minus_span_span(self._inner, other._inner) @@ -438,7 +432,7 @@ def minus(self, other: Union[int, float, FloatSpan, FloatSpanSet]) -> FloatSpanS result = super().minus(other) return FloatSpanSet(_inner=result) if result is not None else None - def union(self, other: Union[int, float, FloatSpan, FloatSpanSet]) -> FloatSpanSet: + def union(self, other: int | float | FloatSpan | FloatSpanSet) -> FloatSpanSet: """ Returns the union of ``self`` and ``other``. @@ -453,7 +447,7 @@ def union(self, other: Union[int, float, FloatSpan, FloatSpanSet]) -> FloatSpanS """ from .floatspanset import FloatSpanSet - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): result = union_span_float(self._inner, float(other)) elif isinstance(other, FloatSpan): result = union_span_span(self._inner, other._inner) diff --git a/pymeos/collections/number/floatspanset.py b/pymeos/collections/number/floatspanset.py index 98d18ee0..f93462f4 100644 --- a/pymeos/collections/number/floatspanset.py +++ b/pymeos/collections/number/floatspanset.py @@ -1,27 +1,27 @@ from __future__ import annotations -from typing import Union, overload, Optional, TYPE_CHECKING, List +from typing import TYPE_CHECKING, overload from pymeos_cffi import ( - floatspanset_in, - floatspanset_out, - floatspanset_width, - floatspanset_shift_scale, adjacent_spanset_float, contains_spanset_float, - spanset_eq, + distance_floatspanset_floatspan, + distance_floatspanset_floatspanset, + distance_spanset_float, float_to_spanset, + floatspanset_in, + floatspanset_out, + floatspanset_shift_scale, + floatspanset_to_intspanset, + floatspanset_width, + intersection_spanset_float, left_spanset_float, + minus_spanset_float, overleft_spanset_float, - right_spanset_float, overright_spanset_float, - distance_spanset_float, - intersection_spanset_float, + right_spanset_float, + spanset_eq, union_spanset_float, - minus_spanset_float, - floatspanset_to_intspanset, - distance_floatspanset_floatspan, - distance_floatspanset_floatspanset, ) from ..base import SpanSet @@ -55,9 +55,7 @@ class FloatSpanSet(SpanSet[float]): _mobilitydb_name = "floatspanset" _parse_function = floatspanset_in - _parse_value_function = lambda span: ( - floatspanset_in(span)[0] if isinstance(span, str) else span._inner[0] - ) + _parse_value_function = lambda span: (floatspanset_in(span)[0] if isinstance(span, str) else span._inner[0]) # ------------------------- Output ---------------------------------------- def __str__(self, max_decimals: int = 15): @@ -104,7 +102,7 @@ def to_intspanset(self) -> IntSpanSet: # ------------------------- Accessors ------------------------------------- - def width(self, ignore_gaps: Optional[bool] = False) -> float: + def width(self, ignore_gaps: bool | None = False) -> float: """ Returns the width of the spanset. By default, i.e., when the second argument is False, the function takes into account the gaps within, @@ -164,7 +162,7 @@ def span_n(self, n: int) -> FloatSpan: return FloatSpan(_inner=super().span_n(n)) - def spans(self) -> List[FloatSpan]: + def spans(self) -> list[FloatSpan]: """ Returns the list of spans in ``self``. Returns: @@ -212,7 +210,7 @@ def scale(self, width: int) -> FloatSpanSet: """ return self.shift_scale(None, width) - def shift_scale(self, delta: Optional[int], width: Optional[int]) -> FloatSpanSet: + def shift_scale(self, delta: int | None, width: int | None) -> FloatSpanSet: """ Return a new ``FloatSpanSet`` with the lower and upper bounds shifted by ``delta`` and scaled so that the width is ``width``. @@ -229,14 +227,12 @@ def shift_scale(self, delta: Optional[int], width: Optional[int]) -> FloatSpanSe """ d = delta if delta is not None else 0 w = width if width is not None else 0 - modified = floatspanset_shift_scale( - self._inner, d, w, delta is not None, width is not None - ) + modified = floatspanset_shift_scale(self._inner, d, w, delta is not None, width is not None) return FloatSpanSet(_inner=modified) # ------------------------- Topological Operations -------------------------------- - def is_adjacent(self, other: Union[int, FloatSpan, FloatSpanSet]) -> bool: + def is_adjacent(self, other: int | FloatSpan | FloatSpanSet) -> bool: """ Returns whether ``self`` is adjacent to ``other``. That is, they share a bound but only one of them contains it. @@ -256,7 +252,7 @@ def is_adjacent(self, other: Union[int, FloatSpan, FloatSpanSet]) -> bool: else: return super().is_adjacent(other) - def contains(self, content: Union[int, FloatSpan, FloatSpanSet]) -> bool: + def contains(self, content: int | FloatSpan | FloatSpanSet) -> bool: """ Returns whether ``self`` contains ``content``. @@ -275,7 +271,7 @@ def contains(self, content: Union[int, FloatSpan, FloatSpanSet]) -> bool: else: return super().contains(content) - def is_same(self, other: Union[int, FloatSpan, FloatSpanSet]) -> bool: + def is_same(self, other: int | FloatSpan | FloatSpanSet) -> bool: """ Returns whether ``self`` and the bounding tstzspan of ``other`` is the same. @@ -295,7 +291,7 @@ def is_same(self, other: Union[int, FloatSpan, FloatSpanSet]) -> bool: return super().is_same(other) # ------------------------- Position Operations --------------------------- - def is_left(self, other: Union[int, FloatSpan, FloatSpanSet]) -> bool: + def is_left(self, other: int | FloatSpan | FloatSpanSet) -> bool: """ Returns whether ``self`` is strictly left of ``other``. That is, ``self`` ends before ``other`` starts. @@ -314,7 +310,7 @@ def is_left(self, other: Union[int, FloatSpan, FloatSpanSet]) -> bool: else: return super().is_left(other) - def is_over_or_left(self, other: Union[int, FloatSpan, FloatSpanSet]) -> bool: + def is_over_or_left(self, other: int | FloatSpan | FloatSpanSet) -> bool: """ Returns whether ``self`` is left ``other`` allowing overlap. That is, ``self`` ends before ``other`` ends (or at the same value). @@ -333,7 +329,7 @@ def is_over_or_left(self, other: Union[int, FloatSpan, FloatSpanSet]) -> bool: else: return super().is_over_or_left(other) - def is_right(self, other: Union[int, FloatSpan, FloatSpanSet]) -> bool: + def is_right(self, other: int | FloatSpan | FloatSpanSet) -> bool: """ Returns whether ``self`` is strictly right ``other``. That is, ``self`` starts after ``other`` ends. @@ -352,7 +348,7 @@ def is_right(self, other: Union[int, FloatSpan, FloatSpanSet]) -> bool: else: return super().is_right(other) - def is_over_or_right(self, other: Union[int, FloatSpan, FloatSpanSet]) -> bool: + def is_over_or_right(self, other: int | FloatSpan | FloatSpanSet) -> bool: """ Returns whether ``self`` is right ``other`` allowing overlap. That is, ``self`` starts after ``other`` starts (or at the same value). @@ -373,9 +369,7 @@ def is_over_or_right(self, other: Union[int, FloatSpan, FloatSpanSet]) -> bool: return super().is_over_or_right(other) # ------------------------- Distance Operations --------------------------- - def distance( - self, other: Union[int, float, FloatSet, FloatSpan, FloatSpanSet] - ) -> float: + def distance(self, other: int | float | FloatSet | FloatSpan | FloatSpanSet) -> float: """ Returns the distance between ``self`` and ``other``. @@ -408,13 +402,13 @@ def distance( # ------------------------- Set Operations -------------------------------- @overload - def intersection(self, other: Union[int, float]) -> Optional[float]: ... + def intersection(self, other: int | float) -> float | None: ... @overload - def intersection(self, other: FloatSpan) -> Optional[FloatSpanSet]: ... + def intersection(self, other: FloatSpan) -> FloatSpanSet | None: ... @overload - def intersection(self, other: FloatSpanSet) -> Optional[FloatSpanSet]: ... + def intersection(self, other: FloatSpanSet) -> FloatSpanSet | None: ... def intersection(self, other): """ @@ -431,7 +425,7 @@ def intersection(self, other): intersection_spanset_float, intersection_spanset_spanset, intersection_spanset_span """ - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): result = intersection_spanset_float(self._inner, float(other)) else: result = super().intersection(other) @@ -453,7 +447,7 @@ def __mul__(self, other): """ return self.intersection(other) - def minus(self, other: Union[int, FloatSpan, FloatSpanSet]) -> FloatSpanSet: + def minus(self, other: int | FloatSpan | FloatSpanSet) -> FloatSpanSet: """ Returns the difference of ``self`` and ``other``. @@ -466,7 +460,7 @@ def minus(self, other: Union[int, FloatSpan, FloatSpanSet]) -> FloatSpanSet: MEOS Functions: minus_spanset_span, minus_spanset_spanset, minus_spanset_float """ - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): result = minus_spanset_float(self._inner, float(other)) else: result = super().minus(other) @@ -488,7 +482,7 @@ def __sub__(self, other): """ return self.minus(other) - def union(self, other: Union[int, FloatSpan, FloatSpanSet]) -> FloatSpanSet: + def union(self, other: int | FloatSpan | FloatSpanSet) -> FloatSpanSet: """ Returns the union of ``self`` and ``other``. @@ -502,7 +496,7 @@ def union(self, other: Union[int, FloatSpan, FloatSpanSet]) -> FloatSpanSet: union_spanset_float, union_spanset_spanset, union_spanset_span """ - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): result = union_spanset_float(self._inner, float(other)) else: result = super().union(other) diff --git a/pymeos/collections/number/intset.py b/pymeos/collections/number/intset.py index 0c20b377..a512c7d5 100644 --- a/pymeos/collections/number/intset.py +++ b/pymeos/collections/number/intset.py @@ -1,35 +1,35 @@ from __future__ import annotations -from typing import List, Union, overload, Optional, TYPE_CHECKING +from typing import TYPE_CHECKING, overload from pymeos_cffi import ( + contains_set_int, + distance_intset_intset, + distance_set_int, + intersection_set_int, + intersection_set_set, + intset_end_value, intset_in, intset_make, intset_out, + intset_shift_scale, intset_start_value, - intset_end_value, intset_value_n, intset_values, - contains_set_int, - intersection_set_int, - intersection_set_set, - minus_set_int, left_set_int, + minus_int_set, + minus_set_int, + minus_set_set, overleft_set_int, - right_set_int, overright_set_int, - minus_set_set, - union_set_set, + right_set_int, union_set_int, - intset_shift_scale, - minus_int_set, - distance_set_int, - distance_intset_intset, + union_set_set, ) +from ..base import Set from .intspan import IntSpan from .intspanset import IntSpanSet -from ..base import Set if TYPE_CHECKING: from .floatset import FloatSet @@ -130,7 +130,7 @@ def element_n(self, n: int) -> int: super().element_n(n) return intset_value_n(self._inner, n + 1) - def elements(self) -> List[int]: + def elements(self) -> list[int]: """ Returns the elements in ``self``. @@ -176,7 +176,7 @@ def scale(self, width: int) -> IntSet: """ return self.shift_scale(None, width) - def shift_scale(self, delta: Optional[int], width: Optional[int]) -> IntSet: + def shift_scale(self, delta: int | None, width: int | None) -> IntSet: """ Returns a new ``IntSet`` instance with all elements shifted by ``delta`` and scaled to so that the encompassing span has width @@ -192,15 +192,11 @@ def shift_scale(self, delta: Optional[int], width: Optional[int]) -> IntSet: MEOS Functions: intset_shift_scale """ - return IntSet( - _inner=intset_shift_scale( - self._inner, delta, width, delta is not None, width is not None - ) - ) + return IntSet(_inner=intset_shift_scale(self._inner, delta, width, delta is not None, width is not None)) # ------------------------- Topological Operations -------------------------------- - def contains(self, content: Union[IntSet, int]) -> bool: + def contains(self, content: IntSet | int) -> bool: """ Returns whether ``self`` contains ``content``. @@ -220,7 +216,7 @@ def contains(self, content: Union[IntSet, int]) -> bool: # ------------------------- Position Operations -------------------------------- - def is_left(self, content: Union[IntSet, int]) -> bool: + def is_left(self, content: IntSet | int) -> bool: """ Returns whether ``self`` is strictly to the left of ``other``. That is, ``self`` ends before ``other`` starts. @@ -239,7 +235,7 @@ def is_left(self, content: Union[IntSet, int]) -> bool: else: return super().is_left(content) - def is_over_or_left(self, content: Union[IntSet, int]) -> bool: + def is_over_or_left(self, content: IntSet | int) -> bool: """ Returns whether ``self`` is to the left of ``other`` allowing overlap. That is, ``self`` ends before ``other`` ends (or at the same value). @@ -258,7 +254,7 @@ def is_over_or_left(self, content: Union[IntSet, int]) -> bool: else: return super().is_over_or_left(content) - def is_right(self, content: Union[IntSet, int]) -> bool: + def is_right(self, content: IntSet | int) -> bool: """ Returns whether ``self`` is strictly to the right of ``other``. That is, ``self`` ends after ``other`` starts. @@ -277,7 +273,7 @@ def is_right(self, content: Union[IntSet, int]) -> bool: else: return super().is_right(content) - def is_over_or_right(self, content: Union[IntSet, int]) -> bool: + def is_over_or_right(self, content: IntSet | int) -> bool: """ Returns whether ``self`` is to the right of ``other`` allowing overlap. That is, ``self`` starts before ``other`` ends (or at the same value). @@ -299,10 +295,10 @@ def is_over_or_right(self, content: Union[IntSet, int]) -> bool: # ------------------------- Set Operations -------------------------------- @overload - def intersection(self, other: int) -> Optional[int]: ... + def intersection(self, other: int) -> int | None: ... @overload - def intersection(self, other: IntSet) -> Optional[IntSet]: ... + def intersection(self, other: IntSet) -> IntSet | None: ... def intersection(self, other): """ @@ -326,7 +322,7 @@ def intersection(self, other): else: return super().intersection(other) - def minus(self, other: Union[IntSet, int]) -> Optional[IntSet]: + def minus(self, other: IntSet | int) -> IntSet | None: """ Returns the difference of ``self`` and ``other``. @@ -348,7 +344,7 @@ def minus(self, other: Union[IntSet, int]) -> Optional[IntSet]: else: return super().minus(other) - def subtract_from(self, other: int) -> Optional[int]: + def subtract_from(self, other: int) -> int | None: """ Returns the difference of ``other`` and ``self``. @@ -366,7 +362,7 @@ def subtract_from(self, other: int) -> Optional[int]: """ return minus_int_set(other, self._inner) - def union(self, other: Union[IntSet, int]) -> IntSet: + def union(self, other: IntSet | int) -> IntSet: """ Returns the union of ``self`` and ``other``. @@ -390,7 +386,7 @@ def union(self, other: Union[IntSet, int]) -> IntSet: # ------------------------- Distance Operations --------------------------- - def distance(self, other: Union[int, IntSet, IntSpan, IntSpanSet]) -> int: + def distance(self, other: int | IntSet | IntSpan | IntSpanSet) -> int: """ Returns the distance between ``self`` and ``other``. @@ -411,9 +407,7 @@ def distance(self, other: Union[int, IntSet, IntSpan, IntSpanSet]) -> int: return distance_set_int(self._inner, other) elif isinstance(other, IntSet): return distance_intset_intset(self._inner, other._inner) - elif isinstance(other, IntSpan): - return self.to_spanset().distance(other) - elif isinstance(other, IntSpanSet): + elif isinstance(other, (IntSpan, IntSpanSet)): return self.to_spanset().distance(other) else: return super().distance(other) diff --git a/pymeos/collections/number/intspan.py b/pymeos/collections/number/intspan.py index e9b06e39..a42238d8 100644 --- a/pymeos/collections/number/intspan.py +++ b/pymeos/collections/number/intspan.py @@ -1,44 +1,44 @@ from __future__ import annotations -from typing import Union, overload, Optional, TYPE_CHECKING +from typing import TYPE_CHECKING, overload from pymeos_cffi import ( - intspan_in, - intspan_lower, - intspan_upper, - intspan_shift_scale, - contains_span_int, adjacent_span_int, - intspan_width, + contains_span_int, + distance_intspan_intspan, + distance_intspanset_intspan, + distance_span_int, int_to_span, - span_eq, - left_span_int, - overleft_span_int, - right_span_int, - overright_span_int, intersection_span_int, intersection_span_span, intersection_spanset_span, + intspan_in, + intspan_lower, + intspan_make, + intspan_out, + intspan_shift_scale, + intspan_to_floatspan, + intspan_upper, + intspan_width, + left_span_int, minus_span_int, minus_span_span, minus_spanset_span, + overleft_span_int, + overright_span_int, + right_span_int, + span_eq, union_span_int, union_span_span, union_spanset_span, - intspan_out, - intspan_make, - distance_span_int, - intspan_to_floatspan, - distance_intspan_intspan, - distance_intspanset_intspan, ) from ..base import Span if TYPE_CHECKING: + from .floatspan import FloatSpan from .intset import IntSet from .intspanset import IntSpanSet - from .floatspan import FloatSpan class IntSpan(Span[int]): @@ -181,7 +181,7 @@ def scale(self, width: int) -> IntSpan: """ return self.shift_scale(None, width) - def shift_scale(self, delta: Optional[int], width: Optional[int]) -> IntSpan: + def shift_scale(self, delta: int | None, width: int | None) -> IntSpan: """ Return a new ``IntSpan`` with the lower and upper bounds shifted by ``delta`` and scaled so that the width is ``width``. @@ -198,14 +198,12 @@ def shift_scale(self, delta: Optional[int], width: Optional[int]) -> IntSpan: """ d = delta if delta is not None else 0 w = width if width is not None else 0 - modified = intspan_shift_scale( - self._inner, d, w, delta is not None, width is not None - ) + modified = intspan_shift_scale(self._inner, d, w, delta is not None, width is not None) return IntSpan(_inner=modified) # ------------------------- Topological Operations -------------------------------- - def is_adjacent(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: + def is_adjacent(self, other: int | IntSpan | IntSpanSet) -> bool: """ Returns whether ``self`` is adjacent to ``other``. That is, they share a bound but only one of them contains it. @@ -224,7 +222,7 @@ def is_adjacent(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: else: return super().is_adjacent(other) - def contains(self, content: Union[int, IntSpan, IntSpanSet]) -> bool: + def contains(self, content: int | IntSpan | IntSpanSet) -> bool: """ Returns whether ``self`` contains ``content``. @@ -242,7 +240,7 @@ def contains(self, content: Union[int, IntSpan, IntSpanSet]) -> bool: else: return super().contains(content) - def is_same(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: + def is_same(self, other: int | IntSpan | IntSpanSet) -> bool: """ Returns whether ``self`` and the bounding tstzspan of ``other`` is the same. @@ -262,7 +260,7 @@ def is_same(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: return super().is_same(other) # ------------------------- Position Operations --------------------------- - def is_left(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: + def is_left(self, other: int | IntSpan | IntSpanSet) -> bool: """ Returns whether ``self`` is strictly left ``other``. That is, ``self`` ends before ``other`` starts. @@ -281,7 +279,7 @@ def is_left(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: else: return super().is_left(other) - def is_over_or_left(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: + def is_over_or_left(self, other: int | IntSpan | IntSpanSet) -> bool: """ Returns whether ``self`` is left ``other`` allowing overlap. That is, ``self`` ends before ``other`` ends (or at the same value). @@ -300,7 +298,7 @@ def is_over_or_left(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: else: return super().is_over_or_left(other) - def is_right(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: + def is_right(self, other: int | IntSpan | IntSpanSet) -> bool: """ Returns whether ``self`` is strictly right ``other``. That is, ``self`` starts after ``other`` ends. @@ -319,7 +317,7 @@ def is_right(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: else: return super().is_right(other) - def is_over_or_right(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: + def is_over_or_right(self, other: int | IntSpan | IntSpanSet) -> bool: """ Returns whether ``self`` is right ``other`` allowing overlap. That is, ``self`` starts after ``other`` starts (or at the same value). @@ -339,7 +337,7 @@ def is_over_or_right(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: return super().is_over_or_right(other) # ------------------------- Distance Operations --------------------------- - def distance(self, other: Union[int, IntSet, IntSpan, IntSpanSet]) -> int: + def distance(self, other: int | IntSet | IntSpan | IntSpanSet) -> int: """ Returns the distance between ``self`` and ``other``. @@ -368,13 +366,13 @@ def distance(self, other: Union[int, IntSet, IntSpan, IntSpanSet]) -> int: # ------------------------- Set Operations -------------------------------- @overload - def intersection(self, other: int) -> Optional[int]: ... + def intersection(self, other: int) -> int | None: ... @overload - def intersection(self, other: IntSpan) -> Optional[IntSpan]: ... + def intersection(self, other: IntSpan) -> IntSpan | None: ... @overload - def intersection(self, other: IntSpanSet) -> Optional[IntSpanSet]: ... + def intersection(self, other: IntSpanSet) -> IntSpanSet | None: ... def intersection(self, other): """ @@ -404,7 +402,7 @@ def intersection(self, other): else: super().intersection(other) - def minus(self, other: Union[int, IntSpan, IntSpanSet]) -> IntSpanSet: + def minus(self, other: int | IntSpan | IntSpanSet) -> IntSpanSet: """ Returns the difference of ``self`` and ``other``. @@ -429,7 +427,7 @@ def minus(self, other: Union[int, IntSpan, IntSpanSet]) -> IntSpanSet: result = super().minus(other) return IntSpanSet(_inner=result) if result is not None else None - def union(self, other: Union[int, IntSpan, IntSpanSet]) -> IntSpanSet: + def union(self, other: int | IntSpan | IntSpanSet) -> IntSpanSet: """ Returns the union of ``self`` and ``other``. diff --git a/pymeos/collections/number/intspanset.py b/pymeos/collections/number/intspanset.py index ed559738..3ef36b70 100644 --- a/pymeos/collections/number/intspanset.py +++ b/pymeos/collections/number/intspanset.py @@ -1,35 +1,35 @@ from __future__ import annotations -from typing import Union, overload, Optional, TYPE_CHECKING, List +from typing import TYPE_CHECKING, overload from pymeos_cffi import ( - intspanset_in, - intspanset_out, - intspanset_width, - intspanset_shift_scale, adjacent_spanset_int, contains_spanset_int, - spanset_eq, + distance_intspanset_intspan, + distance_intspanset_intspanset, + distance_spanset_int, int_to_spanset, + intersection_spanset_int, + intspanset_in, + intspanset_out, + intspanset_shift_scale, + intspanset_to_floatspanset, + intspanset_width, left_spanset_int, + minus_spanset_int, overleft_spanset_int, - right_spanset_int, overright_spanset_int, - distance_spanset_int, - intersection_spanset_int, + right_spanset_int, + spanset_eq, union_spanset_int, - minus_spanset_int, - intspanset_to_floatspanset, - distance_intspanset_intspan, - distance_intspanset_intspanset, ) from ..base import SpanSet if TYPE_CHECKING: + from .floatspanset import FloatSpanSet from .intset import IntSet from .intspan import IntSpan - from .floatspanset import FloatSpanSet class IntSpanSet(SpanSet[int]): @@ -55,9 +55,7 @@ class IntSpanSet(SpanSet[int]): _mobilitydb_name = "intspanset" _parse_function = intspanset_in - _parse_value_function = lambda span: ( - intspanset_in(span)[0] if isinstance(span, str) else span._inner[0] - ) + _parse_value_function = lambda span: (intspanset_in(span)[0] if isinstance(span, str) else span._inner[0]) # ------------------------- Output ---------------------------------------- def __str__(self): @@ -104,7 +102,7 @@ def to_floatspanset(self) -> FloatSpanSet: # ------------------------- Accessors ------------------------------------- - def width(self, ignore_gaps: Optional[bool] = False) -> float: + def width(self, ignore_gaps: bool | None = False) -> float: """ Returns the width of the spanset. By default, i.e., when the second argument is False, the function takes into account the gaps within, @@ -164,7 +162,7 @@ def span_n(self, n: int) -> IntSpan: return IntSpan(_inner=super().span_n(n)) - def spans(self) -> List[IntSpan]: + def spans(self) -> list[IntSpan]: """ Returns the list of spans in ``self``. Returns: @@ -212,7 +210,7 @@ def scale(self, width: int) -> IntSpanSet: """ return self.shift_scale(None, width) - def shift_scale(self, delta: Optional[int], width: Optional[int]) -> IntSpanSet: + def shift_scale(self, delta: int | None, width: int | None) -> IntSpanSet: """ Return a new ``IntSpanSet`` with the lower and upper bounds shifted by ``delta`` and scaled so that the width is ``width``. @@ -229,14 +227,12 @@ def shift_scale(self, delta: Optional[int], width: Optional[int]) -> IntSpanSet: """ d = delta if delta is not None else 0 w = width if width is not None else 0 - modified = intspanset_shift_scale( - self._inner, d, w, delta is not None, width is not None - ) + modified = intspanset_shift_scale(self._inner, d, w, delta is not None, width is not None) return IntSpanSet(_inner=modified) # ------------------------- Topological Operations -------------------------------- - def is_adjacent(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: + def is_adjacent(self, other: int | IntSpan | IntSpanSet) -> bool: """ Returns whether ``self`` is adjacent to ``other``. That is, they share a bound but only one of them contains it. @@ -256,7 +252,7 @@ def is_adjacent(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: else: return super().is_adjacent(other) - def contains(self, content: Union[int, IntSpan, IntSpanSet]) -> bool: + def contains(self, content: int | IntSpan | IntSpanSet) -> bool: """ Returns whether ``self`` contains ``content``. @@ -275,7 +271,7 @@ def contains(self, content: Union[int, IntSpan, IntSpanSet]) -> bool: else: return super().contains(content) - def is_same(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: + def is_same(self, other: int | IntSpan | IntSpanSet) -> bool: """ Returns whether ``self`` and the bounding tstzspan of ``other`` is the same. @@ -295,7 +291,7 @@ def is_same(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: return super().is_same(other) # ------------------------- Position Operations --------------------------- - def is_left(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: + def is_left(self, other: int | IntSpan | IntSpanSet) -> bool: """ Returns whether ``self`` is strictly left of ``other``. That is, ``self`` ends before ``other`` starts. @@ -314,7 +310,7 @@ def is_left(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: else: return super().is_left(other) - def is_over_or_left(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: + def is_over_or_left(self, other: int | IntSpan | IntSpanSet) -> bool: """ Returns whether ``self`` is left ``other`` allowing overlap. That is, ``self`` ends before ``other`` ends (or at the same value). @@ -333,7 +329,7 @@ def is_over_or_left(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: else: return super().is_over_or_left(other) - def is_right(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: + def is_right(self, other: int | IntSpan | IntSpanSet) -> bool: """ Returns whether ``self`` is strictly right ``other``. That is, ``self`` starts after ``other`` ends. @@ -352,7 +348,7 @@ def is_right(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: else: return super().is_right(other) - def is_over_or_right(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: + def is_over_or_right(self, other: int | IntSpan | IntSpanSet) -> bool: """ Returns whether ``self`` is right ``other`` allowing overlap. That is, ``self`` starts after ``other`` starts (or at the same value). @@ -373,7 +369,7 @@ def is_over_or_right(self, other: Union[int, IntSpan, IntSpanSet]) -> bool: return super().is_over_or_right(other) # ------------------------- Distance Operations --------------------------- - def distance(self, other: Union[int, IntSet, IntSpan, IntSpanSet]) -> int: + def distance(self, other: int | IntSet | IntSpan | IntSpanSet) -> int: """ Returns the distance between ``self`` and ``other``. @@ -403,13 +399,13 @@ def distance(self, other: Union[int, IntSet, IntSpan, IntSpanSet]) -> int: # ------------------------- Set Operations -------------------------------- @overload - def intersection(self, other: int) -> Optional[int]: ... + def intersection(self, other: int) -> int | None: ... @overload - def intersection(self, other: IntSpan) -> Optional[IntSpanSet]: ... + def intersection(self, other: IntSpan) -> IntSpanSet | None: ... @overload - def intersection(self, other: IntSpanSet) -> Optional[IntSpanSet]: ... + def intersection(self, other: IntSpanSet) -> IntSpanSet | None: ... def intersection(self, other): """ @@ -448,7 +444,7 @@ def __mul__(self, other): """ return self.intersection(other) - def minus(self, other: Union[int, IntSpan, IntSpanSet]) -> IntSpanSet: + def minus(self, other: int | IntSpan | IntSpanSet) -> IntSpanSet: """ Returns the difference of ``self`` and ``other``. @@ -483,7 +479,7 @@ def __sub__(self, other): """ return self.minus(other) - def union(self, other: Union[int, IntSpan, IntSpanSet]) -> IntSpanSet: + def union(self, other: int | IntSpan | IntSpanSet) -> IntSpanSet: """ Returns the union of ``self`` and ``other``. diff --git a/pymeos/collections/text/textset.py b/pymeos/collections/text/textset.py index f58e1af9..0a1caddf 100644 --- a/pymeos/collections/text/textset.py +++ b/pymeos/collections/text/textset.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Optional, overload, Union +from typing import overload from pymeos_cffi import * @@ -112,7 +112,7 @@ def elements(self): # ------------------------- Topological Operations -------------------------------- - def contains(self, content: Union[TextSet, str]) -> bool: + def contains(self, content: TextSet | str) -> bool: """ Returns whether ``self`` contains ``content``. @@ -158,10 +158,10 @@ def uppercase(self): # ------------------------- Set Operations -------------------------------- @overload - def intersection(self, other: str) -> Optional[str]: ... + def intersection(self, other: str) -> str | None: ... @overload - def intersection(self, other: TextSet) -> Optional[TextSet]: ... + def intersection(self, other: TextSet) -> TextSet | None: ... def intersection(self, other): """ @@ -185,7 +185,7 @@ def intersection(self, other): else: return super().intersection(other) - def minus(self, other: Union[TextSet, str]) -> Optional[TextSet]: + def minus(self, other: TextSet | str) -> TextSet | None: """ Returns the difference of ``self`` and ``other``. @@ -207,7 +207,7 @@ def minus(self, other: Union[TextSet, str]) -> Optional[TextSet]: else: return super().minus(other) - def subtract_from(self, other: str) -> Optional[str]: + def subtract_from(self, other: str) -> str | None: """ Returns the difference of ``other`` and ``self``. @@ -226,7 +226,7 @@ def subtract_from(self, other: str) -> Optional[str]: result = minus_text_set(other, self._inner) return text2cstring(result[0]) if result is not None else None - def union(self, other: Union[TextSet, str]) -> TextSet: + def union(self, other: TextSet | str) -> TextSet: """ Returns the union of ``self`` and ``other``. diff --git a/pymeos/collections/time/__init__.py b/pymeos/collections/time/__init__.py index 88b53ae9..8cda4c8f 100644 --- a/pymeos/collections/time/__init__.py +++ b/pymeos/collections/time/__init__.py @@ -1,11 +1,12 @@ -from .tstzset import TsTzSet +from datetime import date, datetime, timedelta + from .dateset import DateSet -from .tstzspan import TsTzSpan from .datespan import DateSpan -from .tstzspanset import TsTzSpanSet from .datespanset import DateSpanSet from .time import Time, TimeDate -from datetime import datetime, timedelta, date +from .tstzset import TsTzSet +from .tstzspan import TsTzSpan +from .tstzspanset import TsTzSpanSet __all__ = [ "TimeDate", diff --git a/pymeos/collections/time/dateset.py b/pymeos/collections/time/dateset.py index 55def40a..61d38dba 100644 --- a/pymeos/collections/time/dateset.py +++ b/pymeos/collections/time/dateset.py @@ -1,46 +1,42 @@ from __future__ import annotations -from datetime import date, timedelta, datetime -from typing import TYPE_CHECKING, List, Optional, Union, overload +from datetime import date, datetime, timedelta +from typing import TYPE_CHECKING, overload -from dateutil.parser import parse from pymeos_cffi import ( - dateset_in, - pg_date_in, + after_set_date, + before_set_date, + contains_set_date, + date_adt_to_date, date_to_date_adt, + dateset_end_value, + dateset_in, dateset_make, dateset_out, + dateset_shift_scale, dateset_start_value, - date_adt_to_date, - dateset_end_value, dateset_value_n, dateset_values, - dateset_shift_scale, - contains_set_date, - before_set_date, - overbefore_set_date, - overafter_set_date, - after_set_date, + distance_dateset_dateset, distance_set_date, intersection_set_date, intersection_set_set, + minus_date_set, minus_set_date, minus_set_set, - minus_date_set, + overafter_set_date, + overbefore_set_date, + pg_date_in, union_set_date, union_set_set, - distance_dateset_dateset, ) -from .timecollection import TimeCollection from ..base import Set +from .timecollection import TimeCollection if TYPE_CHECKING: from .datespan import DateSpan from .datespanset import DateSpanSet - from .tstzspanset import TsTzSpanSet - from .tstzspan import TsTzSpan - from .tstzspanset import TsTzSpanSet from .time import TimeDate @@ -67,9 +63,7 @@ class DateSet(Set[date], TimeCollection[date]): _mobilitydb_name = "dateset" _parse_function = dateset_in - _parse_value_function = lambda x: ( - pg_date_in(x) if isinstance(x, str) else date_to_date_adt(x) - ) + _parse_value_function = lambda x: (pg_date_in(x) if isinstance(x, str) else date_to_date_adt(x)) _make_function = dateset_make # ------------------------- Constructors ---------------------------------- @@ -159,7 +153,7 @@ def element_n(self, n: int) -> date: super().element_n(n) return date_adt_to_date(dateset_value_n(self._inner, n + 1)[0]) - def elements(self) -> List[date]: + def elements(self) -> list[date]: """ Returns the list of distinct dates in ``self``. Returns: @@ -172,7 +166,7 @@ def elements(self) -> List[date]: return [date_adt_to_date(tss[i]) for i in range(self.num_elements())] # ------------------------- Transformations ------------------------------- - def shift(self, delta: Union[timedelta, int]) -> DateSet: + def shift(self, delta: timedelta | int) -> DateSet: """ Returns a new :class:`DateSpanSet` that is the result of shifting ``self`` by ``delta`` @@ -192,7 +186,7 @@ def shift(self, delta: Union[timedelta, int]) -> DateSet: """ return self.shift_scale(shift=delta) - def scale(self, duration: Union[timedelta, int]) -> DateSet: + def scale(self, duration: timedelta | int) -> DateSet: """ Returns a new :class:`DateSet` that with the scaled so that the span of ``self`` is ``duration``. @@ -215,8 +209,8 @@ def scale(self, duration: Union[timedelta, int]) -> DateSet: def shift_scale( self, - shift: Union[int, timedelta, None] = None, - duration: Union[int, timedelta, None] = None, + shift: int | timedelta | None = None, + duration: int | timedelta | None = None, ) -> DateSet: """ Returns a new :class:`DateSet` that is the result of shifting and scaling @@ -237,27 +231,15 @@ def shift_scale( MEOS Functions: dateset_shift_scale """ - assert ( - shift is not None or duration is not None - ), "shift and scale deltas must not be both None" - shift = ( - shift.days - if isinstance(shift, timedelta) - else int(shift) if shift is not None else 0 - ) - duration = ( - duration.days - if isinstance(duration, timedelta) - else int(duration) if duration is not None else 0 - ) - tss = dateset_shift_scale( - self._inner, shift, duration, shift != 0, duration != 0 - ) + assert shift is not None or duration is not None, "shift and scale deltas must not be both None" + shift = shift.days if isinstance(shift, timedelta) else int(shift) if shift is not None else 0 + duration = duration.days if isinstance(duration, timedelta) else int(duration) if duration is not None else 0 + tss = dateset_shift_scale(self._inner, shift, duration, shift != 0, duration != 0) return DateSet(_inner=tss) # ------------------------- Topological Operations ------------------------ - def contains(self, content: Union[date, datetime, DateSet]) -> bool: + def contains(self, content: date | datetime | DateSet) -> bool: """ Returns whether ``self`` temporally contains ``content``. @@ -309,7 +291,7 @@ def __contains__(self, item): """ return self.contains(item) - def overlaps(self, other: Union[date, DateSet, DateSpan, DateSpanSet]) -> bool: + def overlaps(self, other: date | DateSet | DateSpan | DateSpanSet) -> bool: """ Returns whether ``self`` temporally overlaps ``other``. That is, both share at least an instant @@ -371,9 +353,7 @@ def is_left(self, other: TimeDate) -> bool: if isinstance(other, date): return before_set_date(self._inner, date_to_date_adt(other)) - elif isinstance(other, DateSpan): - return self.to_span().is_left(other) - elif isinstance(other, DateSpanSet): + elif isinstance(other, (DateSpan, DateSpanSet)): return self.to_span().is_left(other) else: return super().is_left(other) @@ -405,9 +385,7 @@ def is_over_or_left(self, other: TimeDate) -> bool: if isinstance(other, date): return overbefore_set_date(self._inner, date_to_date_adt(other)) - elif isinstance(other, DateSpan): - return self.to_span().is_over_or_left(other) - elif isinstance(other, DateSpanSet): + elif isinstance(other, (DateSpan, DateSpanSet)): return self.to_span().is_over_or_left(other) else: return super().is_over_or_left(other) @@ -439,9 +417,7 @@ def is_over_or_right(self, other: TimeDate) -> bool: if isinstance(other, date): return overafter_set_date(self._inner, date_to_date_adt(other)) - elif isinstance(other, DateSpan): - return self.to_span().is_over_or_after(other) - elif isinstance(other, DateSpanSet): + elif isinstance(other, (DateSpan, DateSpanSet)): return self.to_span().is_over_or_after(other) else: return super().is_over_or_left(other) @@ -473,9 +449,7 @@ def is_right(self, other: TimeDate) -> bool: if isinstance(other, date): return after_set_date(self._inner, date_to_date_adt(other)) - elif isinstance(other, DateSpan): - return self.to_span().is_after(other) - elif isinstance(other, DateSpanSet): + elif isinstance(other, (DateSpan, DateSpanSet)): return self.to_span().is_after(other) else: return super().is_over_or_left(other) @@ -499,14 +473,10 @@ def distance(self, other: TimeDate) -> timedelta: from .datespanset import DateSpanSet if isinstance(other, date): - return timedelta( - days=distance_set_date(self._inner, date_to_date_adt(other)) - ) + return timedelta(days=distance_set_date(self._inner, date_to_date_adt(other))) elif isinstance(other, DateSet): return timedelta(days=distance_dateset_dateset(self._inner, other._inner)) - elif isinstance(other, DateSpan): - return self.to_spanset().distance(other) - elif isinstance(other, DateSpanSet): + elif isinstance(other, (DateSpan, DateSpanSet)): return self.to_spanset().distance(other) else: return super().distance(other) @@ -514,14 +484,12 @@ def distance(self, other: TimeDate) -> timedelta: # ------------------------- Set Operations -------------------------------- @overload - def intersection(self, other: Union[date, DateSet]) -> Optional[DateSet]: ... + def intersection(self, other: date | DateSet) -> DateSet | None: ... @overload - def intersection( - self, other: Union[DateSpan, DateSpanSet] - ) -> Optional[DateSpanSet]: ... + def intersection(self, other: DateSpan | DateSpanSet) -> DateSpanSet | None: ... - def intersection(self, other: TimeDate) -> Optional[TimeDate]: + def intersection(self, other: TimeDate) -> TimeDate | None: """ Returns the temporal intersection of ``self`` and ``other``. @@ -544,20 +512,18 @@ def intersection(self, other: TimeDate) -> Optional[TimeDate]: elif isinstance(other, DateSet): result = intersection_set_set(self._inner, other._inner) return DateSet(_inner=result) if result is not None else None - elif isinstance(other, DateSpan): - return self.to_spanset().intersection(other) - elif isinstance(other, DateSpanSet): + elif isinstance(other, (DateSpan, DateSpanSet)): return self.to_spanset().intersection(other) else: return super().intersection(other) @overload - def minus(self, other: Union[date, DateSet]) -> Optional[DateSet]: ... + def minus(self, other: date | DateSet) -> DateSet | None: ... @overload - def minus(self, other: Union[DateSpan, DateSpanSet]) -> Optional[DateSpanSet]: ... + def minus(self, other: DateSpan | DateSpanSet) -> DateSpanSet | None: ... - def minus(self, other: TimeDate) -> Optional[TimeDate]: + def minus(self, other: TimeDate) -> TimeDate | None: """ Returns the temporal difference of ``self`` and ``other``. @@ -580,14 +546,12 @@ def minus(self, other: TimeDate) -> Optional[TimeDate]: elif isinstance(other, DateSet): result = minus_set_set(self._inner, other._inner) return DateSet(_inner=result) if result is not None else None - elif isinstance(other, DateSpan): - return self.to_spanset().minus(other) - elif isinstance(other, DateSpanSet): + elif isinstance(other, (DateSpan, DateSpanSet)): return self.to_spanset().minus(other) else: return super().minus(other) - def subtract_from(self, other: date) -> Optional[date]: + def subtract_from(self, other: date) -> date | None: """ Returns the difference of ``other`` and ``self``. @@ -606,12 +570,12 @@ def subtract_from(self, other: date) -> Optional[date]: return date_adt_to_date(minus_date_set(date_to_date_adt(other), self._inner)) @overload - def union(self, other: Union[date, DateSet]) -> DateSet: ... + def union(self, other: date | DateSet) -> DateSet: ... @overload - def union(self, other: Union[DateSpan, DateSpanSet]) -> DateSpanSet: ... + def union(self, other: DateSpan | DateSpanSet) -> DateSpanSet: ... - def union(self, other: TimeDate) -> Union[DateSpanSet, DateSet]: + def union(self, other: TimeDate) -> DateSpanSet | DateSet: """ Returns the temporal union of ``self`` and ``other``. @@ -632,9 +596,7 @@ def union(self, other: TimeDate) -> Union[DateSpanSet, DateSet]: return DateSet(_inner=union_set_date(self._inner, date_to_date_adt(other))) elif isinstance(other, DateSet): return DateSet(_inner=union_set_set(self._inner, other._inner)) - elif isinstance(other, DateSpan): - return self.to_spanset().union(other) - elif isinstance(other, DateSpanSet): + elif isinstance(other, (DateSpan, DateSpanSet)): return self.to_spanset().union(other) else: return super().union(other) @@ -645,6 +607,4 @@ def union(self, other: TimeDate) -> Union[DateSpanSet, DateSet]: def plot(self, *args, **kwargs): from ...plotters import TimePlotter - return TimePlotter.plot_tstzspanset( - self.to_spanset().to_tstzspanset(), *args, **kwargs - ) + return TimePlotter.plot_tstzspanset(self.to_spanset().to_tstzspanset(), *args, **kwargs) diff --git a/pymeos/collections/time/datespan.py b/pymeos/collections/time/datespan.py index 1639b6f9..c2a70642 100644 --- a/pymeos/collections/time/datespan.py +++ b/pymeos/collections/time/datespan.py @@ -1,47 +1,46 @@ from __future__ import annotations from datetime import date, timedelta -from typing import TYPE_CHECKING, Union, Optional, overload +from typing import TYPE_CHECKING, overload from _meos_cffi.lib import distance_datespanset_datespan -from dateutil.parser import parse from pymeos_cffi import ( adjacent_span_date, - datespan_in, + after_span_date, + before_span_date, + contains_span_date, + date_adt_to_date, date_to_date_adt, - pg_date_in, + datespan_duration, + datespan_in, + datespan_lower, datespan_make, datespan_out, + datespan_shift_scale, datespan_to_tstzspan, - date_adt_to_date, - interval_to_timedelta, - datespan_duration, datespan_upper, - datespan_lower, - datespan_shift_scale, - union_span_date, - minus_span_date, - minus_span_span, - minus_span_spanset, + distance_span_date, intersection_span_date, intersection_span_span, intersection_spanset_span, - distance_span_date, + interval_to_timedelta, + minus_span_date, + minus_span_span, + minus_span_spanset, overafter_span_date, - after_span_date, overbefore_span_date, - before_span_date, - contains_span_date, + pg_date_in, + union_span_date, ) -from .timecollection import TimeCollection from ..base import Span +from .timecollection import TimeCollection if TYPE_CHECKING: from .dateset import DateSet from .datespanset import DateSpanSet - from .tstzspan import TsTzSpan from .time import TimeDate + from .tstzspan import TsTzSpan class DateSpan(Span[date], TimeCollection[date]): @@ -69,9 +68,7 @@ class DateSpan(Span[date], TimeCollection[date]): _mobilitydb_name = "datespan" _parse_function = datespan_in - _parse_value_function = lambda x: ( - pg_date_in(x) if isinstance(x, str) else date_to_date_adt(x) - ) + _parse_value_function = lambda x: (pg_date_in(x) if isinstance(x, str) else date_to_date_adt(x)) _make_function = datespan_make # ------------------------- Constructors ---------------------------------- @@ -172,7 +169,7 @@ def duration_in_days(self) -> float: return self.width() # ------------------------- Transformations ------------------------------- - def shift(self, delta: Union[timedelta, int]) -> DateSpan: + def shift(self, delta: timedelta | int) -> DateSpan: """ Returns a new :class:`DateSpan` that is the result of shifting ``self`` by ``delta``. @@ -192,7 +189,7 @@ def shift(self, delta: Union[timedelta, int]) -> DateSpan: """ return self.shift_scale(shift=delta) - def scale(self, duration: Union[timedelta, int]) -> DateSpan: + def scale(self, duration: timedelta | int) -> DateSpan: """ Returns a new :class:`DateSpan` that starts as ``self`` but has duration ``duration``. @@ -215,8 +212,8 @@ def scale(self, duration: Union[timedelta, int]) -> DateSpan: def shift_scale( self, - shift: Union[int, timedelta, None] = None, - duration: Union[int, timedelta, None] = None, + shift: int | timedelta | None = None, + duration: int | timedelta | None = None, ) -> DateSpan: """ Returns a new :class:`DateSpan` that starts at ``self`` shifted by ``shift`` and @@ -237,29 +234,17 @@ def shift_scale( MEOS Functions: datespan_shift_scale """ - assert ( - shift is not None or duration is not None - ), "shift and scale deltas must not be both None" - - shift = ( - shift.days - if isinstance(shift, timedelta) - else int(shift) if shift is not None else 0 - ) - duration = ( - duration.days - if isinstance(duration, timedelta) - else int(duration) if duration is not None else 0 - ) - - modified = datespan_shift_scale( - self._inner, shift, duration, shift != 0, duration != 0 - ) + assert shift is not None or duration is not None, "shift and scale deltas must not be both None" + + shift = shift.days if isinstance(shift, timedelta) else int(shift) if shift is not None else 0 + duration = duration.days if isinstance(duration, timedelta) else int(duration) if duration is not None else 0 + + modified = datespan_shift_scale(self._inner, shift, duration, shift != 0, duration != 0) return DateSpan(_inner=modified) # ------------------------- Topological Operations ------------------------ - def is_adjacent(self, other: Union[date, DateSpan, DateSpanSet]) -> bool: + def is_adjacent(self, other: date | DateSpan | DateSpanSet) -> bool: """ Returns whether ``self`` is adjacent to ``other``. That is, they share a bound but only one of them contains it. @@ -464,35 +449,25 @@ def distance(self, other: TimeDate) -> timedelta: from .datespanset import DateSpanSet if isinstance(other, date): - return timedelta( - days=distance_span_date(self._inner, date_to_date_adt(other)) - ) + return timedelta(days=distance_span_date(self._inner, date_to_date_adt(other))) elif isinstance(other, DateSet): return self.distance(other.to_spanset()) - elif isinstance(other, DateSpan): - return timedelta( - days=distance_datespanset_datespan(self._inner, other._inner) - ) - elif isinstance(other, DateSpanSet): - return timedelta( - days=distance_datespanset_datespan(self._inner, other._inner) - ) + elif isinstance(other, (DateSpan, DateSpanSet)): + return timedelta(days=distance_datespanset_datespan(self._inner, other._inner)) else: return super().distance(other) # ------------------------- Set Operations -------------------------------- @overload - def intersection(self, other: date) -> Optional[date]: ... + def intersection(self, other: date) -> date | None: ... @overload - def intersection(self, other: DateSpan) -> Optional[DateSpan]: ... + def intersection(self, other: DateSpan) -> DateSpan | None: ... @overload - def intersection( - self, other: Union[DateSet, DateSpanSet] - ) -> Optional[DateSpanSet]: ... + def intersection(self, other: DateSet | DateSpanSet) -> DateSpanSet | None: ... - def intersection(self, other: TimeDate) -> Optional[TimeDate]: + def intersection(self, other: TimeDate) -> TimeDate | None: """ Returns the temporal intersection of ``self`` and ``other``. @@ -506,8 +481,8 @@ def intersection(self, other: TimeDate) -> Optional[TimeDate]: intersection_span_span, intersection_spanset_span, intersection_span_date """ - from .datespanset import DateSpanSet from .dateset import DateSet + from .datespanset import DateSpanSet if isinstance(other, date): result = intersection_span_date(self._inner, date_to_date_adt(other)) @@ -536,8 +511,8 @@ def minus(self, other: TimeDate) -> DateSpanSet: MEOS Functions: minus_span_date, minus_span_spanset, minus_span_span """ - from .datespanset import DateSpanSet from .dateset import DateSet + from .datespanset import DateSpanSet if isinstance(other, date): result = minus_span_date(self._inner, date_to_date_adt(other)) @@ -564,16 +539,14 @@ def union(self, other: TimeDate) -> DateSpanSet: MEOS Functions: union_span_date, union_spanset_span, union_span_span """ - from .datespanset import DateSpanSet from .dateset import DateSet + from .datespanset import DateSpanSet if isinstance(other, date): result = union_span_date(self._inner, date_to_date_adt(other)) elif isinstance(other, DateSet): result = super().union(other.to_spanset()) - elif isinstance(other, DateSpan): - result = super().union(other) - elif isinstance(other, DateSpanSet): + elif isinstance(other, (DateSpan, DateSpanSet)): result = super().union(other) else: raise TypeError(f"Operation not supported with type {other.__class__}") diff --git a/pymeos/collections/time/datespanset.py b/pymeos/collections/time/datespanset.py index 8171f587..2b177f21 100644 --- a/pymeos/collections/time/datespanset.py +++ b/pymeos/collections/time/datespanset.py @@ -1,47 +1,45 @@ from __future__ import annotations -from datetime import timedelta, date -from typing import Optional, Union, List, overload -from typing import TYPE_CHECKING +from datetime import date, timedelta +from typing import TYPE_CHECKING, overload from _meos_cffi.lib import ( distance_datespanset_datespan, distance_datespanset_datespanset, ) from pymeos_cffi import ( - datespanset_in, - datespan_in, - datespanset_out, - datespanset_to_tstzspanset, - interval_to_timedelta, - datespanset_duration, - datespanset_num_dates, + after_spanset_date, + before_spanset_date, + contains_spanset_date, date_adt_to_date, - datespanset_start_date, - datespanset_end_date, + date_to_date_adt, + datespan_in, datespanset_date_n, datespanset_dates, + datespanset_duration, + datespanset_end_date, + datespanset_in, + datespanset_num_dates, + datespanset_out, datespanset_shift_scale, - date_to_date_adt, - contains_spanset_date, - before_spanset_date, - overbefore_spanset_date, - overafter_spanset_date, - after_spanset_date, + datespanset_start_date, + datespanset_to_tstzspanset, distance_spanset_date, intersection_spanset_date, + interval_to_timedelta, minus_spanset_date, + overafter_spanset_date, + overbefore_spanset_date, union_spanset_date, ) -from .timecollection import TimeCollection from ..base.spanset import SpanSet +from .timecollection import TimeCollection if TYPE_CHECKING: - from .tstzspan import TsTzSpan - from .tstzspanset import TsTzSpanSet from .datespan import DateSpan from .time import TimeDate + from .tstzspanset import TsTzSpanSet class DateSpanSet(SpanSet[date], TimeCollection[date]): @@ -115,7 +113,7 @@ def to_tstzspanset(self) -> TsTzSpanSet: return TsTzSpanSet(_inner=datespanset_to_tstzspanset(self._inner)) # ------------------------- Accessors ------------------------------------- - def duration(self, ignore_gaps: Optional[bool] = False) -> timedelta: + def duration(self, ignore_gaps: bool | None = False) -> timedelta: """ Returns the duration of ``self``. By default, i.e., when ``ignore_gaps`` is ``False``, the function takes into account the gaps between the @@ -183,7 +181,7 @@ def date_n(self, n: int) -> date: raise IndexError(f"Index {n} out of bounds") return date_adt_to_date(datespanset_date_n(self._inner, n + 1)) - def dates(self) -> List[date]: + def dates(self) -> list[date]: """ Returns the list of distinct dates in ``self``. Returns: @@ -234,7 +232,7 @@ def span_n(self, n: int) -> DateSpan: return DateSpan(_inner=super().span_n(n)) - def spans(self) -> List[DateSpan]: + def spans(self) -> list[DateSpan]: """ Returns the list of :class:`DateSpan` in ``self``. Returns: @@ -249,7 +247,7 @@ def spans(self) -> List[DateSpan]: return [DateSpan(_inner=ps[i]) for i in range(self.num_spans())] # ------------------------- Transformations ------------------------------- - def shift(self, delta: Union[timedelta, int]) -> DateSpanSet: + def shift(self, delta: timedelta | int) -> DateSpanSet: """ Returns a new :class:`DateSpanSet` that is the result of shifting ``self`` by ``delta`` @@ -269,7 +267,7 @@ def shift(self, delta: Union[timedelta, int]) -> DateSpanSet: """ return self.shift_scale(shift=delta) - def scale(self, duration: Union[timedelta, int]) -> DateSpanSet: + def scale(self, duration: timedelta | int) -> DateSpanSet: """ Returns a new :class:`DateSpanSet` that starts as ``self`` but has duration ``duration`` @@ -292,8 +290,8 @@ def scale(self, duration: Union[timedelta, int]) -> DateSpanSet: def shift_scale( self, - shift: Union[timedelta, int, None] = None, - duration: Union[timedelta, int, None] = None, + shift: timedelta | int | None = None, + duration: timedelta | int | None = None, ) -> DateSpanSet: """ Returns a new :class:`DateSpanSet` that starts at ``self`` shifted by ``shift`` @@ -314,29 +312,17 @@ def shift_scale( MEOS Functions: datespanset_shift_scale """ - assert ( - shift is not None or duration is not None - ), "shift and scale deltas must not be both None" - - shift = ( - shift.days - if isinstance(shift, timedelta) - else int(shift) if shift is not None else 0 - ) - duration = ( - duration.days - if isinstance(duration, timedelta) - else int(duration) if duration is not None else 0 - ) - - modified = datespanset_shift_scale( - self._inner, shift, duration, shift != 0, duration != 0 - ) + assert shift is not None or duration is not None, "shift and scale deltas must not be both None" + + shift = shift.days if isinstance(shift, timedelta) else int(shift) if shift is not None else 0 + duration = duration.days if isinstance(duration, timedelta) else int(duration) if duration is not None else 0 + + modified = datespanset_shift_scale(self._inner, shift, duration, shift != 0, duration != 0) return DateSpanSet(_inner=modified) # ------------------------- Topological Operations ------------------------ - def contains(self, content: Union[TimeDate]) -> bool: + def contains(self, content: TimeDate) -> bool: """ Returns whether ``self`` temporally contains ``content``. @@ -364,7 +350,7 @@ def contains(self, content: Union[TimeDate]) -> bool: else: return super().contains(content) - def overlaps(self, other: Union[TimeDate]) -> bool: + def overlaps(self, other: TimeDate) -> bool: """ Returns whether ``self`` temporally overlaps ``other``. That is, both share at least an instant @@ -392,7 +378,7 @@ def overlaps(self, other: Union[TimeDate]) -> bool: return super().overlaps(other) # ------------------------- Position Operations --------------------------- - def is_left(self, other: Union[TimeDate]) -> bool: + def is_left(self, other: TimeDate) -> bool: """ Returns whether ``self`` is strictly before ``other``. That is, ``self`` ends before ``other`` starts. @@ -419,7 +405,7 @@ def is_left(self, other: Union[TimeDate]) -> bool: else: return super().is_left(other) - def is_over_or_left(self, other: Union[TimeDate]) -> bool: + def is_over_or_left(self, other: TimeDate) -> bool: """ Returns whether ``self`` is before ``other`` allowing overlap. That is, ``self`` ends before ``other`` ends (or at the same time). @@ -447,7 +433,7 @@ def is_over_or_left(self, other: Union[TimeDate]) -> bool: else: return super().is_over_or_left(other) - def is_over_or_right(self, other: Union[TimeDate]) -> bool: + def is_over_or_right(self, other: TimeDate) -> bool: """ Returns whether ``self`` is after ``other`` allowing overlap. That is, ``self`` starts after ``other`` starts (or at the same time). @@ -475,7 +461,7 @@ def is_over_or_right(self, other: Union[TimeDate]) -> bool: else: return super().is_over_or_right(other) - def is_right(self, other: Union[TimeDate]) -> bool: + def is_right(self, other: TimeDate) -> bool: """ Returns whether ``self`` is strictly after ``other``.That is, ``self`` starts after ``other`` ends. @@ -522,19 +508,13 @@ def distance(self, other: TimeDate) -> timedelta: from .datespan import DateSpan if isinstance(other, date): - return timedelta( - days=distance_spanset_date(self._inner, date_to_date_adt(other)) - ) + return timedelta(days=distance_spanset_date(self._inner, date_to_date_adt(other))) elif isinstance(other, DateSet): return self.distance(other.to_spanset()) elif isinstance(other, DateSpan): - return timedelta( - days=distance_datespanset_datespan(self._inner, other._inner) - ) + return timedelta(days=distance_datespanset_datespan(self._inner, other._inner)) elif isinstance(other, DateSpanSet): - return timedelta( - days=distance_datespanset_datespanset(self._inner, other._inner) - ) + return timedelta(days=distance_datespanset_datespanset(self._inner, other._inner)) else: return super().distance(other) @@ -544,9 +524,9 @@ def distance(self, other: TimeDate) -> timedelta: def intersection(self, other: date) -> date: ... @overload - def intersection(self, other: Union[DateSpan, DateSpanSet]) -> DateSpanSet: ... + def intersection(self, other: DateSpan | DateSpanSet) -> DateSpanSet: ... - def intersection(self, other: TimeDate) -> Union[date, DateSpanSet]: + def intersection(self, other: TimeDate) -> date | DateSpanSet: """ Returns the temporal intersection of ``self`` and ``other``. diff --git a/pymeos/collections/time/time.py b/pymeos/collections/time/time.py index 61ace724..1ba6364c 100644 --- a/pymeos/collections/time/time.py +++ b/pymeos/collections/time/time.py @@ -1,40 +1,29 @@ -from datetime import datetime, date -from typing import Union - -from .tstzspan import TsTzSpan -from .tstzspanset import TsTzSpanSet -from .tstzset import TsTzSet +from datetime import date, datetime +from .dateset import DateSet from .datespan import DateSpan from .datespanset import DateSpanSet -from .dateset import DateSet +from .tstzset import TsTzSet +from .tstzspan import TsTzSpan +from .tstzspanset import TsTzSpanSet -Time = Union[ - datetime, - TsTzSet, - TsTzSpan, - TsTzSpanSet, -] +Time = datetime | TsTzSet | TsTzSpan | TsTzSpanSet """ -Union type that includes all Time types related to timestamps in PyMEOS: +Union type that includes all Time types related to timestamps in PyMEOS: -- :class:`~datetime.datetime` for timestamps -- :class:`~pymeos.time.tstzset.TsTzSet` for sets of timestamps -- :class:`~pymeos.time.tstzspan.TsTzSpan` for spans of time -- :class:`~pymeos.time.tstzspanset.TsTzSpanSet` for sets of spans of time +- :class:`~datetime.datetime` for timestamps +- :class:`~pymeos.time.tstzset.TsTzSet` for sets of timestamps +- :class:`~pymeos.time.tstzspan.TsTzSpan` for spans of time +- :class:`~pymeos.time.tstzspanset.TsTzSpanSet` for sets of spans of time """ -TimeDate = Union[ - date, - DateSet, - DateSpan, - DateSpanSet, -] +TimeDate = date | DateSet | DateSpan | DateSpanSet + """ -Union type that includes all Time types related to dates in PyMEOS: +Union type that includes all Time types related to dates in PyMEOS: -- :class:`~datetime.date` for dates -- :class:`~pymeos.time.dateset.DateSet` for sets of dates -- :class:`~pymeos.time.datespan.DateSpan` for spans of dates -- :class:`~pymeos.time.datespanset.DateSpanSet` for sets of spans of dates +- :class:`~datetime.date` for dates +- :class:`~pymeos.time.dateset.DateSet` for sets of dates +- :class:`~pymeos.time.datespan.DateSpan` for spans of dates +- :class:`~pymeos.time.datespanset.DateSpanSet` for sets of spans of dates """ diff --git a/pymeos/collections/time/tstzset.py b/pymeos/collections/time/tstzset.py index 6c91af52..3175880f 100644 --- a/pymeos/collections/time/tstzset.py +++ b/pymeos/collections/time/tstzset.py @@ -1,20 +1,19 @@ from __future__ import annotations from datetime import datetime, timedelta -from typing import Optional, List, Union, TYPE_CHECKING, overload, get_args +from typing import TYPE_CHECKING, get_args, overload -from dateutil.parser import parse from pymeos_cffi import * -from .timecollection import TimeCollection from ..base import Set +from .timecollection import TimeCollection if TYPE_CHECKING: + from ...boxes import Box from ...temporal import Temporal + from .time import Time from .tstzspan import TsTzSpan from .tstzspanset import TsTzSpanSet - from .time import Time - from ...boxes import Box class TsTzSet(Set[datetime], TimeCollection[datetime]): @@ -40,9 +39,7 @@ class TsTzSet(Set[datetime], TimeCollection[datetime]): _mobilitydb_name = "tstzset" _parse_function = tstzset_in - _parse_value_function = lambda x: ( - pg_timestamptz_in(x, -1) if isinstance(x, str) else datetime_to_timestamptz(x) - ) + _parse_value_function = lambda x: (pg_timestamptz_in(x, -1) if isinstance(x, str) else datetime_to_timestamptz(x)) _make_function = tstzset_make # ------------------------- Constructors ---------------------------------- @@ -110,7 +107,7 @@ def element_n(self, n: int) -> datetime: super().element_n(n) return timestamptz_to_datetime(tstzset_value_n(self._inner, n + 1)) - def elements(self) -> List[datetime]: + def elements(self) -> list[datetime]: """ Returns the list of distinct timestamps in ``self``. Returns: @@ -164,9 +161,7 @@ def scale(self, duration: timedelta) -> TsTzSet: """ return self.shift_scale(duration=duration) - def shift_scale( - self, shift: Optional[timedelta] = None, duration: Optional[timedelta] = None - ) -> TsTzSet: + def shift_scale(self, shift: timedelta | None = None, duration: timedelta | None = None) -> TsTzSet: """ Returns a new TsTzSet that is the result of shifting and scaling ``self``. @@ -186,9 +181,7 @@ def shift_scale( MEOS Functions: tstzset_shift_scale """ - assert ( - shift is not None or duration is not None - ), "shift and scale deltas must not be both None" + assert shift is not None or duration is not None, "shift and scale deltas must not be both None" tss = tstzset_shift_scale( self._inner, timedelta_to_interval(shift) if shift else None, @@ -197,7 +190,7 @@ def shift_scale( return TsTzSet(_inner=tss) # ------------------------- Topological Operations ------------------------ - def is_adjacent(self, other: Union[TsTzSpan, TsTzSpanSet, Temporal, Box]) -> bool: + def is_adjacent(self, other: TsTzSpan | TsTzSpanSet | Temporal | Box) -> bool: """ Returns whether ``self`` is temporally adjacent to ``other``. That is, they share a bound but only one of them contains it. @@ -219,8 +212,8 @@ def is_adjacent(self, other: Union[TsTzSpan, TsTzSpanSet, Temporal, Box]) -> boo MEOS Functions: adjacent_span_span, adjacent_spanset_span """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(other, Temporal): return self.is_adjacent(other.time()) @@ -229,9 +222,7 @@ def is_adjacent(self, other: Union[TsTzSpan, TsTzSpanSet, Temporal, Box]) -> boo else: super().is_adjacent(other) - def is_contained_in( - self, container: Union[TsTzSpan, TsTzSpanSet, TsTzSet, Temporal, Box] - ) -> bool: + def is_contained_in(self, container: TsTzSpan | TsTzSpanSet | TsTzSet | Temporal | Box) -> bool: """ Returns whether ``self`` is temporally contained in ``container``. @@ -253,8 +244,8 @@ def is_contained_in( contained_span_span, contained_span_spanset, contained_set_set, contained_spanset_spanset """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(container, Temporal): return self.is_contained_in(container.time()) @@ -263,7 +254,7 @@ def is_contained_in( else: return super().is_contained_in(container) - def contains(self, content: Union[datetime, TsTzSet, Temporal]) -> bool: + def contains(self, content: datetime | TsTzSet | Temporal) -> bool: """ Returns whether ``self`` temporally contains ``content``. @@ -288,9 +279,7 @@ def contains(self, content: Union[datetime, TsTzSet, Temporal]) -> bool: from ...temporal import Temporal if isinstance(content, datetime): - return contains_set_timestamptz( - self._inner, datetime_to_timestamptz(content) - ) + return contains_set_timestamptz(self._inner, datetime_to_timestamptz(content)) elif isinstance(content, Temporal): return self.to_spanset().contains(content) else: @@ -320,9 +309,7 @@ def __contains__(self, item): """ return self.contains(item) - def overlaps( - self, other: Union[TsTzSpan, TsTzSpanSet, TsTzSet, Temporal, Box] - ) -> bool: + def overlaps(self, other: TsTzSpan | TsTzSpanSet | TsTzSet | Temporal | Box) -> bool: """ Returns whether ``self`` temporally overlaps ``other``. That is, both share at least an instant @@ -344,8 +331,8 @@ def overlaps( MEOS Functions: overlaps_set_set, overlaps_span_span, overlaps_spanset_spanset """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(other, datetime): return contains_set_timestamptz(self._inner, datetime_to_timestamptz(other)) @@ -356,7 +343,7 @@ def overlaps( else: return super().overlaps(other) - def is_same(self, other: Union[Time, Temporal, Box]) -> bool: + def is_same(self, other: Time | Temporal | Box) -> bool: """ Returns whether the bounding tstzspan of `self` is the same as the bounding tstzspan of `other`. @@ -373,7 +360,7 @@ def is_same(self, other: Union[Time, Temporal, Box]) -> bool: return self.to_span().is_same(other) # ------------------------- Position Operations --------------------------- - def is_left(self, other: Union[Time, Temporal, Box]) -> bool: + def is_left(self, other: Time | Temporal | Box) -> bool: """ Returns whether ``self`` is strictly before ``other``. That is, ``self`` ends before ``other`` starts. @@ -395,19 +382,17 @@ def is_left(self, other: Union[Time, Temporal, Box]) -> bool: MEOS Functions: overafter_timestamp_tstzspan, left_span_span, left_span_spanset """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(other, datetime): return after_timestamptz_set(datetime_to_timestamptz(other), self._inner) - elif isinstance(other, Temporal): - return self.to_span().is_left(other) - elif isinstance(other, get_args(Box)): + elif isinstance(other, (Temporal, get_args(Box))): return self.to_span().is_left(other) else: return super().is_left(other) - def is_over_or_left(self, other: Union[Time, Temporal, Box]) -> bool: + def is_over_or_left(self, other: Time | Temporal | Box) -> bool: """ Returns whether ``self`` is before ``other`` allowing overlap. That is, ``self`` ends before ``other`` ends (or at the same time). @@ -429,13 +414,11 @@ def is_over_or_left(self, other: Union[Time, Temporal, Box]) -> bool: MEOS Functions: overbefore_tstzspan_timestamp, overleft_span_span, overleft_span_spanset """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(other, datetime): - return overafter_timestamptz_set( - datetime_to_timestamptz(other), self._inner - ) + return overafter_timestamptz_set(datetime_to_timestamptz(other), self._inner) elif isinstance(other, Temporal): return self.to_span().is_over_or_left(other) elif isinstance(other, get_args(Box)): @@ -443,7 +426,7 @@ def is_over_or_left(self, other: Union[Time, Temporal, Box]) -> bool: else: return super().is_over_or_left(other) - def is_over_or_right(self, other: Union[Time, Temporal, Box]) -> bool: + def is_over_or_right(self, other: Time | Temporal | Box) -> bool: """ Returns whether ``self`` is after ``other`` allowing overlap. That is, ``self`` starts after ``other`` starts (or at the same time). @@ -465,21 +448,17 @@ def is_over_or_right(self, other: Union[Time, Temporal, Box]) -> bool: MEOS Functions: overafter_tstzspan_timestamp, overright_span_span, overright_span_spanset """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(other, datetime): - return overbefore_timestamptz_set( - datetime_to_timestamptz(other), self._inner - ) - elif isinstance(other, Temporal): - return self.to_span().is_over_or_right(other) - elif isinstance(other, get_args(Box)): + return overbefore_timestamptz_set(datetime_to_timestamptz(other), self._inner) + elif isinstance(other, (Temporal, get_args(Box))): return self.to_span().is_over_or_right(other) else: return super().is_over_or_right(other) - def is_right(self, other: Union[Time, Temporal, Box]) -> bool: + def is_right(self, other: Time | Temporal | Box) -> bool: """ Returns whether ``self`` is strictly after ``other``. That is, the first timestamp in ``self`` is after ``other``. @@ -502,20 +481,18 @@ def is_right(self, other: Union[Time, Temporal, Box]) -> bool: overbefore_timestamptz_set, right_set_set, right_span_span, right_span_spanset """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(other, datetime): return before_timestamptz_set(datetime_to_timestamptz(other), self._inner) - elif isinstance(other, Temporal): - return self.to_span().is_right(other) - elif isinstance(other, get_args(Box)): + elif isinstance(other, (Temporal, get_args(Box))): return self.to_span().is_right(other) else: return super().is_right(other) # ------------------------- Distance Operations --------------------------- - def distance(self, other: Union[Time, Temporal, Box]) -> timedelta: + def distance(self, other: Time | Temporal | Box) -> timedelta: """ Returns the temporal distance between ``self`` and ``other``. @@ -529,45 +506,33 @@ def distance(self, other: Union[Time, Temporal, Box]) -> timedelta: distance_set_timestamptz, distance_tstzset_tstzset, distance_tstzspanset_tstzspan, distance_tstzspanset_tstzspanset """ + from ...boxes import Box + from ...temporal import Temporal from .tstzspan import TsTzSpan from .tstzspanset import TsTzSpanSet - from ...temporal import Temporal - from ...boxes import Box if isinstance(other, datetime): - return timedelta( - seconds=distance_set_timestamptz( - self._inner, datetime_to_timestamptz(other) - ) - ) + return timedelta(seconds=distance_set_timestamptz(self._inner, datetime_to_timestamptz(other))) elif isinstance(other, TsTzSet): - return timedelta( - seconds=distance_tstzset_tstzset(self._inner, other._inner) - ) - elif isinstance(other, TsTzSpan): - return self.to_spanset().distance(other) - elif isinstance(other, TsTzSpanSet): + return timedelta(seconds=distance_tstzset_tstzset(self._inner, other._inner)) + elif isinstance(other, (TsTzSpan, TsTzSpanSet)): return self.to_spanset().distance(other) - elif isinstance(other, Temporal): - return self.to_span().distance(other) - elif isinstance(other, get_args(Box)): + elif isinstance(other, (Temporal, get_args(Box))): return self.to_span().distance(other) else: return super().distance(other) # ------------------------- Set Operations -------------------------------- @overload - def intersection(self, other: datetime) -> Optional[datetime]: ... + def intersection(self, other: datetime) -> datetime | None: ... @overload - def intersection(self, other: TsTzSet) -> Optional[TsTzSet]: ... + def intersection(self, other: TsTzSet) -> TsTzSet | None: ... @overload - def intersection( - self, other: Union[TsTzSpan, TsTzSpanSet, Temporal, Box] - ) -> Optional[TsTzSpanSet]: ... + def intersection(self, other: TsTzSpan | TsTzSpanSet | Temporal | Box) -> TsTzSpanSet | None: ... - def intersection(self, other: Union[Time, Temporal]) -> Optional[Time]: + def intersection(self, other: Time | Temporal) -> Time | None: """ Returns the temporal intersection of ``self`` and ``other``. @@ -585,16 +550,12 @@ def intersection(self, other: Union[Time, Temporal]) -> Optional[Time]: from .tstzspanset import TsTzSpanSet if isinstance(other, datetime): - result = intersection_set_timestamptz( - self._inner, datetime_to_timestamptz(other) - ) + result = intersection_set_timestamptz(self._inner, datetime_to_timestamptz(other)) return timestamptz_to_datetime(result) if result is not None else None elif isinstance(other, TsTzSet): result = intersection_set_set(self._inner, other._inner) return TsTzSet(_inner=result) if result is not None else None - elif isinstance(other, TsTzSpan): - return self.to_spanset().intersection(other) - elif isinstance(other, TsTzSpanSet): + elif isinstance(other, (TsTzSpan, TsTzSpanSet)): return self.to_spanset().intersection(other) elif isinstance(other, Temporal): return self.intersection(other.time()) @@ -604,14 +565,12 @@ def intersection(self, other: Union[Time, Temporal]) -> Optional[Time]: return super().intersection(other) @overload - def minus(self, other: Union[datetime, TsTzSet]) -> Optional[TsTzSet]: ... + def minus(self, other: datetime | TsTzSet) -> TsTzSet | None: ... @overload - def minus( - self, other: Union[TsTzSpan, TsTzSpanSet, Temporal, Box] - ) -> Optional[TsTzSpanSet]: ... + def minus(self, other: TsTzSpan | TsTzSpanSet | Temporal | Box) -> TsTzSpanSet | None: ... - def minus(self, other: Union[Time, Temporal, Box]) -> Optional[Time]: + def minus(self, other: Time | Temporal | Box) -> Time | None: """ Returns the temporal difference of ``self`` and ``other``. @@ -634,9 +593,7 @@ def minus(self, other: Union[Time, Temporal, Box]) -> Optional[Time]: elif isinstance(other, TsTzSet): result = minus_set_set(self._inner, other._inner) return TsTzSet(_inner=result) if result is not None else None - elif isinstance(other, TsTzSpan): - return self.to_spanset().minus(other) - elif isinstance(other, TsTzSpanSet): + elif isinstance(other, (TsTzSpan, TsTzSpanSet)): return self.to_spanset().minus(other) elif isinstance(other, Temporal): return self.minus(other.time()) @@ -645,7 +602,7 @@ def minus(self, other: Union[Time, Temporal, Box]) -> Optional[Time]: else: return super().minus(other) - def subtract_from(self, other: datetime) -> Optional[datetime]: + def subtract_from(self, other: datetime) -> datetime | None: """ Returns the difference of ``other`` and ``self``. @@ -661,19 +618,15 @@ def subtract_from(self, other: datetime) -> Optional[datetime]: See Also: :meth:`minus` """ - return timestamptz_to_datetime( - minus_timestamptz_set(datetime_to_timestamptz(other), self._inner) - ) + return timestamptz_to_datetime(minus_timestamptz_set(datetime_to_timestamptz(other), self._inner)) @overload - def union(self, other: Union[datetime, TsTzSet]) -> TsTzSet: ... + def union(self, other: datetime | TsTzSet) -> TsTzSet: ... @overload - def union( - self, other: Union[TsTzSpan, TsTzSpanSet, Temporal, Box] - ) -> TsTzSpanSet: ... + def union(self, other: TsTzSpan | TsTzSpanSet | Temporal | Box) -> TsTzSpanSet: ... - def union(self, other: Union[Time, Temporal, Box]) -> Union[TsTzSpanSet, TsTzSet]: + def union(self, other: Time | Temporal | Box) -> TsTzSpanSet | TsTzSet: """ Returns the temporal union of ``self`` and ``other``. @@ -691,16 +644,10 @@ def union(self, other: Union[Time, Temporal, Box]) -> Union[TsTzSpanSet, TsTzSet from .tstzspanset import TsTzSpanSet if isinstance(other, datetime): - return TsTzSet( - _inner=union_set_timestamptz( - self._inner, datetime_to_timestamptz(other) - ) - ) + return TsTzSet(_inner=union_set_timestamptz(self._inner, datetime_to_timestamptz(other))) elif isinstance(other, TsTzSet): return TsTzSet(_inner=union_set_set(self._inner, other._inner)) - elif isinstance(other, TsTzSpan): - return self.to_spanset().union(other) - elif isinstance(other, TsTzSpanSet): + elif isinstance(other, (TsTzSpan, TsTzSpanSet)): return self.to_spanset().union(other) elif isinstance(other, Temporal): return self.union(other.time()) diff --git a/pymeos/collections/time/tstzspan.py b/pymeos/collections/time/tstzspan.py index feeaab14..faf501a3 100644 --- a/pymeos/collections/time/tstzspan.py +++ b/pymeos/collections/time/tstzspan.py @@ -1,20 +1,19 @@ from __future__ import annotations from datetime import datetime, timedelta -from typing import Optional, Union, overload, TYPE_CHECKING, get_args +from typing import TYPE_CHECKING, get_args, overload -from dateutil.parser import parse from pymeos_cffi import * -from .timecollection import TimeCollection from ..base.span import Span +from .timecollection import TimeCollection if TYPE_CHECKING: - from ...temporal import Temporal from ...boxes import Box - from .tstzspanset import TsTzSpanSet + from ...temporal import Temporal from .time import Time from .tstzset import TsTzSet + from .tstzspanset import TsTzSpanSet class TsTzSpan(Span[datetime], TimeCollection[datetime]): @@ -42,9 +41,7 @@ class TsTzSpan(Span[datetime], TimeCollection[datetime]): _mobilitydb_name = "tstzspan" _parse_function = tstzspan_in - _parse_value_function = lambda x: ( - pg_timestamptz_in(x, -1) if isinstance(x, str) else datetime_to_timestamptz(x) - ) + _parse_value_function = lambda x: (pg_timestamptz_in(x, -1) if isinstance(x, str) else datetime_to_timestamptz(x)) _make_function = tstzspan_make # ------------------------- Constructors ---------------------------------- @@ -157,9 +154,7 @@ def scale(self, duration: timedelta) -> TsTzSpan: """ return self.shift_scale(duration=duration) - def shift_scale( - self, shift: Optional[timedelta] = None, duration: Optional[timedelta] = None - ) -> TsTzSpan: + def shift_scale(self, shift: timedelta | None = None, duration: timedelta | None = None) -> TsTzSpan: """ Returns a new tstzspan that starts at ``self`` shifted by ``shift`` and has duration ``duration`` @@ -179,9 +174,7 @@ def shift_scale( MEOS Functions: tstzspan_shift_scale """ - assert ( - shift is not None or duration is not None - ), "shift and scale deltas must not be both None" + assert shift is not None or duration is not None, "shift and scale deltas must not be both None" modified = tstzspan_shift_scale( self._inner, timedelta_to_interval(shift) if shift else None, @@ -190,7 +183,7 @@ def shift_scale( return TsTzSpan(_inner=modified) # ------------------------- Topological Operations ------------------------ - def is_adjacent(self, other: Union[Time, Box, Temporal]) -> bool: + def is_adjacent(self, other: Time | Box | Temporal) -> bool: """ Returns whether ``self`` is temporally adjacent to ``other``. That is, they share a bound but only one of them contains it. @@ -213,13 +206,11 @@ def is_adjacent(self, other: Union[Time, Box, Temporal]) -> bool: adjacent_span_span, adjacent_span_spanset, adjacent_span_timestamptz, adjacent_span_tstzset, adjacent_span_temporal """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(other, datetime): - return adjacent_span_timestamptz( - self._inner, datetime_to_timestamptz(other) - ) + return adjacent_span_timestamptz(self._inner, datetime_to_timestamptz(other)) elif isinstance(other, Temporal): return adjacent_span_span(self._inner, temporal_to_tstzspan(other._inner)) elif isinstance(other, get_args(Box)): @@ -227,9 +218,7 @@ def is_adjacent(self, other: Union[Time, Box, Temporal]) -> bool: else: return super().is_adjacent(other) - def is_contained_in( - self, container: Union[TsTzSpan, TsTzSpanSet, Box, Temporal] - ) -> bool: + def is_contained_in(self, container: TsTzSpan | TsTzSpanSet | Box | Temporal) -> bool: """ Returns whether ``self`` is temporally contained in ``container``. @@ -250,8 +239,8 @@ def is_contained_in( MEOS Functions: contained_span_span, contained_span_spanset, contained_span_temporal """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(container, Temporal): return self.is_contained_in(container.tstzspan()) @@ -260,7 +249,7 @@ def is_contained_in( else: return super().is_contained_in(container) - def contains(self, content: Union[Time, Box, Temporal]) -> bool: + def contains(self, content: Time | Box | Temporal) -> bool: """ Returns whether ``self`` temporally contains ``content``. @@ -282,13 +271,11 @@ def contains(self, content: Union[Time, Box, Temporal]) -> bool: contains_span_span, contains_span_spanset, contains_span_timestamptz, contains_span_tstzset, contains_span_temporal """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(content, datetime): - return contains_span_timestamptz( - self._inner, datetime_to_timestamptz(content) - ) + return contains_span_timestamptz(self._inner, datetime_to_timestamptz(content)) elif isinstance(content, Temporal): return self.contains(content.tstzspan()) elif isinstance(content, get_args(Box)): @@ -296,7 +283,7 @@ def contains(self, content: Union[Time, Box, Temporal]) -> bool: else: return super().contains(content) - def overlaps(self, other: Union[Time, Box, Temporal]) -> bool: + def overlaps(self, other: Time | Box | Temporal) -> bool: """ Returns whether ``self`` temporally overlaps ``other``. That is, both share at least an instant @@ -319,13 +306,11 @@ def overlaps(self, other: Union[Time, Box, Temporal]) -> bool: overlaps_span_span, overlaps_span_spanset, overlaps_span_tstzset, overlaps_span_temporal """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(other, datetime): - return overlaps_span_span( - self._inner, timestamptz_to_span(datetime_to_timestamptz(other)) - ) + return overlaps_span_span(self._inner, timestamptz_to_span(datetime_to_timestamptz(other))) elif isinstance(other, Temporal): return self.overlaps(other.tstzspan()) elif isinstance(other, get_args(Box)): @@ -333,7 +318,7 @@ def overlaps(self, other: Union[Time, Box, Temporal]) -> bool: else: return super().overlaps(other) - def is_same(self, other: Union[Time, Box, Temporal]) -> bool: + def is_same(self, other: Time | Box | Temporal) -> bool: """ Returns whether ``self`` and the bounding tstzspan of ``other`` is the same. @@ -346,22 +331,20 @@ def is_same(self, other: Union[Time, Box, Temporal]) -> bool: MEOS Functions: same_span_temporal """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(other, Temporal): return self.is_same(other.tstzspan()) elif isinstance(other, get_args(Box)): return self.is_same(other.to_tstzspan()) elif isinstance(other, datetime): - return span_eq( - self._inner, timestamptz_to_span(datetime_to_timestamptz(other)) - ) + return span_eq(self._inner, timestamptz_to_span(datetime_to_timestamptz(other))) else: return super().is_same(other) # ------------------------- Position Operations --------------------------- - def is_left(self, other: Union[Time, Box, Temporal]) -> bool: + def is_left(self, other: Time | Box | Temporal) -> bool: """ Returns whether ``self`` is strictly before ``other``. That is, ``self`` ends before ``other`` starts. @@ -384,13 +367,11 @@ def is_left(self, other: Union[Time, Box, Temporal]) -> bool: left_span_span, left_span_spanset, before_span_timestamptz, before_span_tstzset, before_span_temporal """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(other, datetime): - return overafter_timestamptz_span( - datetime_to_timestamptz(other), self._inner - ) + return overafter_timestamptz_span(datetime_to_timestamptz(other), self._inner) elif isinstance(other, Temporal): return self.is_left(other.tstzspan()) elif isinstance(other, get_args(Box)): @@ -398,7 +379,7 @@ def is_left(self, other: Union[Time, Box, Temporal]) -> bool: else: return super().is_left(other) - def is_over_or_left(self, other: Union[Time, Box, Temporal]) -> bool: + def is_over_or_left(self, other: Time | Box | Temporal) -> bool: """ Returns whether ``self`` is before ``other`` allowing overlap. That is, ``self`` ends before ``other`` ends (or at the same time). @@ -421,13 +402,11 @@ def is_over_or_left(self, other: Union[Time, Box, Temporal]) -> bool: overleft_span_span, overleft_span_spanset, overbefore_span_timestamptz, overbefore_span_tstzset, overbefore_span_temporal """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(other, datetime): - return overbefore_span_timestamptz( - self._inner, datetime_to_timestamptz(other) - ) + return overbefore_span_timestamptz(self._inner, datetime_to_timestamptz(other)) elif isinstance(other, Temporal): return self.is_over_or_left(other.tstzspan()) elif isinstance(other, get_args(Box)): @@ -435,7 +414,7 @@ def is_over_or_left(self, other: Union[Time, Box, Temporal]) -> bool: else: return super().is_over_or_left(other) - def is_right(self, other: Union[Time, Box, Temporal]) -> bool: + def is_right(self, other: Time | Box | Temporal) -> bool: """ Returns whether ``self`` is strictly after ``other``. That is, ``self`` starts after ``other`` ends. @@ -458,13 +437,11 @@ def is_right(self, other: Union[Time, Box, Temporal]) -> bool: right_span_span, right_span_spanset, after_span_timestamptz, after_span_tstzset, after_span_temporal """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(other, datetime): - return overbefore_timestamptz_span( - datetime_to_timestamptz(other), self._inner - ) + return overbefore_timestamptz_span(datetime_to_timestamptz(other), self._inner) elif isinstance(other, Temporal): return self.is_right(other.tstzspan()) elif isinstance(other, get_args(Box)): @@ -472,7 +449,7 @@ def is_right(self, other: Union[Time, Box, Temporal]) -> bool: else: return super().is_right(other) - def is_over_or_right(self, other: Union[Time, Box, Temporal]) -> bool: + def is_over_or_right(self, other: Time | Box | Temporal) -> bool: """ Returns whether ``self`` is after ``other`` allowing overlap. That is, ``self`` starts after ``other`` starts (or at the same time). @@ -495,13 +472,11 @@ def is_over_or_right(self, other: Union[Time, Box, Temporal]) -> bool: overright_span_span, overright_span_spanset, overafter_span_timestamptz, overafter_span_tstzset, overafter_span_temporal """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(other, datetime): - return overafter_span_timestamptz( - self._inner, datetime_to_timestamptz(other) - ) + return overafter_span_timestamptz(self._inner, datetime_to_timestamptz(other)) elif isinstance(other, Temporal): return self.is_over_or_right(other.tstzspan()) elif isinstance(other, get_args(Box)): @@ -510,7 +485,7 @@ def is_over_or_right(self, other: Union[Time, Box, Temporal]) -> bool: return super().is_over_or_right(other) # ------------------------- Distance Operations --------------------------- - def distance(self, other: Union[Time, Box, Temporal]) -> timedelta: + def distance(self, other: Time | Box | Temporal) -> timedelta: """ Returns the temporal distance between ``self`` and ``other``. @@ -524,27 +499,19 @@ def distance(self, other: Union[Time, Box, Temporal]) -> timedelta: distance_span_timestamptz, distance_tstzspan_tstzspan, distance_tstzspanset_tstzspan """ + from ...boxes import Box + from ...temporal import Temporal from .tstzset import TsTzSet from .tstzspanset import TsTzSpanSet - from ...temporal import Temporal - from ...boxes import Box if isinstance(other, datetime): - return timedelta( - seconds=distance_span_timestamptz( - self._inner, datetime_to_timestamptz(other) - ) - ) + return timedelta(seconds=distance_span_timestamptz(self._inner, datetime_to_timestamptz(other))) elif isinstance(other, TsTzSet): return self.distance(other.to_spanset()) elif isinstance(other, TsTzSpan): - return timedelta( - seconds=distance_tstzspan_tstzspan(self._inner, other._inner) - ) + return timedelta(seconds=distance_tstzspan_tstzspan(self._inner, other._inner)) elif isinstance(other, TsTzSpanSet): - return timedelta( - seconds=distance_tstzspanset_tstzspan(other._inner, self._inner) - ) + return timedelta(seconds=distance_tstzspanset_tstzspan(other._inner, self._inner)) elif isinstance(other, Temporal): return self.distance(other.tstzspan()) elif isinstance(other, get_args(Box)): @@ -554,17 +521,15 @@ def distance(self, other: Union[Time, Box, Temporal]) -> timedelta: # ------------------------- Set Operations -------------------------------- @overload - def intersection(self, other: datetime) -> Optional[datetime]: ... + def intersection(self, other: datetime) -> datetime | None: ... @overload - def intersection(self, other: TsTzSpan) -> Optional[TsTzSpan]: ... + def intersection(self, other: TsTzSpan) -> TsTzSpan | None: ... @overload - def intersection( - self, other: Union[TsTzSet, TsTzSpanSet] - ) -> Optional[TsTzSpanSet]: ... + def intersection(self, other: TsTzSet | TsTzSpanSet) -> TsTzSpanSet | None: ... - def intersection(self, other: Time) -> Optional[Time]: + def intersection(self, other: Time) -> Time | None: """ Returns the temporal intersection of ``self`` and ``other``. @@ -578,13 +543,11 @@ def intersection(self, other: Time) -> Optional[Time]: intersection_span_span, intersection_spanset_span, intersection_span_timestamptz """ - from .tstzspanset import TsTzSpanSet from .tstzset import TsTzSet + from .tstzspanset import TsTzSpanSet if isinstance(other, datetime): - result = intersection_span_timestamptz( - self._inner, datetime_to_timestamptz(other) - ) + result = intersection_span_timestamptz(self._inner, datetime_to_timestamptz(other)) return timestamptz_to_datetime(result) if result is not None else None elif isinstance(other, TsTzSet): return self.intersection(other.to_tstzspanset()) @@ -610,8 +573,8 @@ def minus(self, other: Time) -> TsTzSpanSet: MEOS Functions: minus_span_timestamptz, minus_span_spanset, minus_span_span """ - from .tstzspanset import TsTzSpanSet from .tstzset import TsTzSet + from .tstzspanset import TsTzSpanSet if isinstance(other, datetime): result = minus_span_timestamptz(self._inner, datetime_to_timestamptz(other)) @@ -638,16 +601,12 @@ def union(self, other: Time) -> TsTzSpanSet: MEOS Functions: union_span_timestamptz, union_spanset_span, union_span_span """ - from .tstzspanset import TsTzSpanSet from .tstzset import TsTzSet + from .tstzspanset import TsTzSpanSet if isinstance(other, datetime): result = union_span_timestamptz(self._inner, datetime_to_timestamptz(other)) - elif isinstance(other, TsTzSet): - result = super().union(other) - elif isinstance(other, TsTzSpan): - result = super().union(other) - elif isinstance(other, TsTzSpanSet): + elif isinstance(other, (TsTzSet, TsTzSpan, TsTzSpanSet)): result = super().union(other) else: raise TypeError(f"Operation not supported with type {other.__class__}") diff --git a/pymeos/collections/time/tstzspanset.py b/pymeos/collections/time/tstzspanset.py index 95e91d2e..9e5f10fb 100644 --- a/pymeos/collections/time/tstzspanset.py +++ b/pymeos/collections/time/tstzspanset.py @@ -1,19 +1,18 @@ from __future__ import annotations -from datetime import timedelta, datetime -from typing import Optional, Union, List, overload, get_args -from typing import TYPE_CHECKING +from datetime import datetime, timedelta +from typing import TYPE_CHECKING, get_args, overload from pymeos_cffi import * from .timecollection import TimeCollection if TYPE_CHECKING: - from ...temporal import Temporal from ...boxes import Box - from .tstzspan import TsTzSpan - from .tstzset import TsTzSet + from ...temporal import Temporal from .time import Time + from .tstzset import TsTzSet + from .tstzspan import TsTzSpan from ..base.spanset import SpanSet @@ -87,7 +86,7 @@ def to_tstzspan(self) -> TsTzSpan: return self.to_span() # ------------------------- Accessors ------------------------------------- - def duration(self, ignore_gaps: Optional[bool] = False) -> timedelta: + def duration(self, ignore_gaps: bool | None = False) -> timedelta: """ Returns the duration of the tstzspanset. By default, i.e., when the second argument is False, the function takes into account the gaps within, @@ -207,7 +206,7 @@ def span_n(self, n: int) -> TsTzSpan: return TsTzSpan(_inner=super().span_n(n)) - def spans(self) -> List[TsTzSpan]: + def spans(self) -> list[TsTzSpan]: """ Returns the list of tstzspans in ``self``. Returns: @@ -263,9 +262,7 @@ def scale(self, duration: timedelta) -> TsTzSpanSet: """ return self.shift_scale(duration=duration) - def shift_scale( - self, shift: Optional[timedelta] = None, duration: Optional[timedelta] = None - ) -> TsTzSpanSet: + def shift_scale(self, shift: timedelta | None = None, duration: timedelta | None = None) -> TsTzSpanSet: """ Returns a new tstzspanset that starts at ``self`` shifted by ``shift`` and has duration ``duration`` @@ -285,9 +282,7 @@ def shift_scale( MEOS Functions: tstzspanset_shift_scale """ - assert ( - shift is not None or duration is not None - ), "shift and scale deltas must not be both None" + assert shift is not None or duration is not None, "shift and scale deltas must not be both None" ps = tstzspanset_shift_scale( self._inner, timedelta_to_interval(shift) if shift else None, @@ -296,7 +291,7 @@ def shift_scale( return TsTzSpanSet(_inner=ps) # ------------------------- Topological Operations ------------------------ - def is_adjacent(self, other: Union[Time, Box, Temporal]) -> bool: + def is_adjacent(self, other: Time | Box | Temporal) -> bool: """ Returns whether ``self`` is temporally adjacent to ``other``. That is, they share a bound but only one of them contains it. @@ -319,13 +314,11 @@ def is_adjacent(self, other: Union[Time, Box, Temporal]) -> bool: adjacent_spanset_span, adjacent_spanset_spanset, adjacent_spanset_timestamptz, adjacent_tstzspanset_tstzset """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(other, datetime): - return adjacent_spanset_timestamptz( - self._inner, datetime_to_timestamptz(other) - ) + return adjacent_spanset_timestamptz(self._inner, datetime_to_timestamptz(other)) elif isinstance(other, Temporal): return self.is_adjacent(other.tstzspan()) elif isinstance(other, get_args(Box)): @@ -333,7 +326,7 @@ def is_adjacent(self, other: Union[Time, Box, Temporal]) -> bool: else: return super().is_adjacent(other) - def is_contained_in(self, container: Union[Time, Box, Temporal]) -> bool: + def is_contained_in(self, container: Time | Box | Temporal) -> bool: """ Returns whether ``self`` is temporally contained in ``container``. @@ -355,13 +348,11 @@ def is_contained_in(self, container: Union[Time, Box, Temporal]) -> bool: contained_spanset_span, contained_spanset_spanset, contained_tstzspanset_temporal """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(container, datetime): - return contained_spanset_span( - self._inner, timestamptz_to_span(datetime_to_timestamptz(container)) - ) + return contained_spanset_span(self._inner, timestamptz_to_span(datetime_to_timestamptz(container))) elif isinstance(container, Temporal): return self.is_contained_in(container.tstzspan()) elif isinstance(container, get_args(Box)): @@ -369,7 +360,7 @@ def is_contained_in(self, container: Union[Time, Box, Temporal]) -> bool: else: return super().is_contained_in(container) - def contains(self, content: Union[Time, Box, Temporal]) -> bool: + def contains(self, content: Time | Box | Temporal) -> bool: """ Returns whether ``self`` temporally contains ``content``. @@ -391,13 +382,11 @@ def contains(self, content: Union[Time, Box, Temporal]) -> bool: contains_spanset_span, contains_spanset_spanset, contains_spanset_timestamptz """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(content, datetime): - return contains_spanset_timestamptz( - self._inner, datetime_to_timestamptz(content) - ) + return contains_spanset_timestamptz(self._inner, datetime_to_timestamptz(content)) elif isinstance(content, Temporal): return self.contains(content.tstzspan()) elif isinstance(content, get_args(Box)): @@ -430,7 +419,7 @@ def __contains__(self, item): """ return self.contains(item) - def overlaps(self, other: Union[Time, Box, Temporal]) -> bool: + def overlaps(self, other: Time | Box | Temporal) -> bool: """ Returns whether ``self`` temporally overlaps ``other``. That is, both share at least an instant @@ -452,13 +441,11 @@ def overlaps(self, other: Union[Time, Box, Temporal]) -> bool: MEOS Functions: overlaps_spanset_span, overlaps_spanset_spanset """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(other, datetime): - return overlaps_spanset_span( - self._inner, timestamptz_to_span(datetime_to_timestamptz(other)) - ) + return overlaps_spanset_span(self._inner, timestamptz_to_span(datetime_to_timestamptz(other))) elif isinstance(other, Temporal): return self.overlaps(other.tstzspan()) elif isinstance(other, get_args(Box)): @@ -466,7 +453,7 @@ def overlaps(self, other: Union[Time, Box, Temporal]) -> bool: else: return super().overlaps(other) - def is_same(self, other: Union[Time, Box, Temporal]) -> bool: + def is_same(self, other: Time | Box | Temporal) -> bool: """ Returns whether the bounding tstzspan of `self` is the same as the bounding tstzspan of `other`. @@ -483,7 +470,7 @@ def is_same(self, other: Union[Time, Box, Temporal]) -> bool: return self.to_tstzspan().is_same(other) # ------------------------- Position Operations --------------------------- - def is_left(self, other: Union[Time, Box, Temporal]) -> bool: + def is_left(self, other: Time | Box | Temporal) -> bool: """ Returns whether ``self`` is strictly before ``other``. That is, ``self`` ends before ``other`` starts. @@ -505,13 +492,11 @@ def is_left(self, other: Union[Time, Box, Temporal]) -> bool: MEOS Functions: before_spanset_timestamptz, left_spanset_span, left_spanset_spanset """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(other, datetime): - return before_spanset_timestamptz( - self._inner, datetime_to_timestamptz(other) - ) + return before_spanset_timestamptz(self._inner, datetime_to_timestamptz(other)) elif isinstance(other, Temporal): return self.is_left(other.tstzspan()) elif isinstance(other, get_args(Box)): @@ -519,7 +504,7 @@ def is_left(self, other: Union[Time, Box, Temporal]) -> bool: else: return super().is_left(other) - def is_over_or_left(self, other: Union[Time, Box, Temporal]) -> bool: + def is_over_or_left(self, other: Time | Box | Temporal) -> bool: """ Returns whether ``self`` is before ``other`` allowing overlap. That is, ``self`` ends before ``other`` ends (or at the same time). @@ -543,13 +528,11 @@ def is_over_or_left(self, other: Union[Time, Box, Temporal]) -> bool: overbefore_spanset_timestamptz, overbefore_tstzspanset_tstzset, overbefore_tstzspanset_temporal """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(other, datetime): - return overbefore_spanset_timestamptz( - self._inner, datetime_to_timestamptz(other) - ) + return overbefore_spanset_timestamptz(self._inner, datetime_to_timestamptz(other)) elif isinstance(other, Temporal): return self.is_over_or_left(other.tstzspan()) elif isinstance(other, get_args(Box)): @@ -557,7 +540,7 @@ def is_over_or_left(self, other: Union[Time, Box, Temporal]) -> bool: else: return super().is_over_or_left(other) - def is_over_or_right(self, other: Union[Time, Box, Temporal]) -> bool: + def is_over_or_right(self, other: Time | Box | Temporal) -> bool: """ Returns whether ``self`` is after ``other`` allowing overlap. That is, ``self`` starts after ``other`` starts (or at the same time). @@ -580,13 +563,11 @@ def is_over_or_right(self, other: Union[Time, Box, Temporal]) -> bool: overright_spanset_span, overright_spanset_spanset, overafter_spanset_timestamptz, overafter_tstzspanset_tstzset, """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(other, datetime): - return overafter_spanset_timestamptz( - self._inner, datetime_to_timestamptz(other) - ) + return overafter_spanset_timestamptz(self._inner, datetime_to_timestamptz(other)) elif isinstance(other, Temporal): return self.is_over_or_right(other.tstzspan()) elif isinstance(other, get_args(Box)): @@ -594,7 +575,7 @@ def is_over_or_right(self, other: Union[Time, Box, Temporal]) -> bool: else: return super().is_over_or_right(other) - def is_right(self, other: Union[Time, Box, Temporal]) -> bool: + def is_right(self, other: Time | Box | Temporal) -> bool: """ Returns whether ``self`` is strictly after ``other``.That is, ``self`` starts after ``other`` ends. @@ -617,13 +598,11 @@ def is_right(self, other: Union[Time, Box, Temporal]) -> bool: right_spanset_span, right_spanset_spanset, overbefore_timestamp_tstzspanset """ - from ...temporal import Temporal from ...boxes import Box + from ...temporal import Temporal if isinstance(other, datetime): - return overbefore_timestamptz_spanset( - datetime_to_timestamptz(other), self._inner - ) + return overbefore_timestamptz_spanset(datetime_to_timestamptz(other), self._inner) elif isinstance(other, Temporal): return self.is_right(other.tstzspan()) elif isinstance(other, get_args(Box)): @@ -632,7 +611,7 @@ def is_right(self, other: Union[Time, Box, Temporal]) -> bool: return super().is_right(other) # ------------------------- Distance Operations --------------------------- - def distance(self, other: Union[Time, Box, Temporal]) -> timedelta: + def distance(self, other: Time | Box | Temporal) -> timedelta: """ Returns the temporal distance between ``self`` and ``other``. @@ -646,27 +625,19 @@ def distance(self, other: Union[Time, Box, Temporal]) -> timedelta: distance_tstzspanset_tstzspan, distance_tstzspanset_tstzspanset, distance_spanset_timestamptz, distance_tstzspanset_tstzset """ + from ...boxes import Box + from ...temporal import Temporal from .tstzset import TsTzSet from .tstzspan import TsTzSpan - from ...temporal import Temporal - from ...boxes import Box if isinstance(other, datetime): - return timedelta( - seconds=distance_spanset_timestamptz( - self._inner, datetime_to_timestamptz(other) - ) - ) + return timedelta(seconds=distance_spanset_timestamptz(self._inner, datetime_to_timestamptz(other))) elif isinstance(other, TsTzSet): return self.distance(other.to_spanset()) elif isinstance(other, TsTzSpan): - return timedelta( - seconds=distance_tstzspanset_tstzspan(self._inner, other._inner) - ) + return timedelta(seconds=distance_tstzspanset_tstzspan(self._inner, other._inner)) elif isinstance(other, TsTzSpanSet): - return timedelta( - seconds=distance_tstzspanset_tstzspanset(self._inner, other._inner) - ) + return timedelta(seconds=distance_tstzspanset_tstzspanset(self._inner, other._inner)) if isinstance(other, Temporal): return self.distance(other.tstzspan()) elif isinstance(other, get_args(Box)): @@ -684,7 +655,7 @@ def intersection(self, other: TsTzSpanSet) -> TsTzSpanSet: ... @overload def intersection(self, other: datetime) -> datetime: ... - def intersection(self, other: Time) -> Union[TsTzSpanSet, datetime, TsTzSet]: + def intersection(self, other: Time) -> TsTzSpanSet | datetime | TsTzSet: """ Returns the temporal intersection of ``self`` and ``other``. @@ -699,9 +670,7 @@ def intersection(self, other: Time) -> Union[TsTzSpanSet, datetime, TsTzSet]: intersection_spanset_span """ if isinstance(other, datetime): - result = intersection_spanset_timestamptz( - self._inner, datetime_to_timestamptz(other) - ) + result = intersection_spanset_timestamptz(self._inner, datetime_to_timestamptz(other)) return timestamptz_to_datetime(result) if result is not None else None else: result = super().intersection(other) @@ -737,9 +706,7 @@ def minus(self, other: Time) -> TsTzSpanSet: minus_spanset_span, minus_spanset_spanset, minus_spanset_timestamptz """ if isinstance(other, datetime): - result = minus_spanset_timestamptz( - self._inner, datetime_to_timestamptz(other) - ) + result = minus_spanset_timestamptz(self._inner, datetime_to_timestamptz(other)) else: result = super().minus(other) return TsTzSpanSet(_inner=result) if result is not None else None @@ -775,9 +742,7 @@ def union(self, other: Time) -> TsTzSpanSet: union_spanset_span """ if isinstance(other, datetime): - result = union_spanset_timestamptz( - self._inner, datetime_to_timestamptz(other) - ) + result = union_spanset_timestamptz(self._inner, datetime_to_timestamptz(other)) else: result = super().union(other) return TsTzSpanSet(_inner=result) if result is not None else None diff --git a/pymeos/db/asyncpg.py b/pymeos/db/asyncpg.py index dfab9bd2..ddc45530 100644 --- a/pymeos/db/asyncpg.py +++ b/pymeos/db/asyncpg.py @@ -39,6 +39,4 @@ async def register(cls, connection: asyncpg.connection.Connection) -> None: connection: An :class:`asyncpg.connection.Connection` to register the classes to. """ for cl in db_objects: - await connection.set_type_codec( - cl._mobilitydb_name, encoder=str, decoder=cl.read_from_cursor - ) + await connection.set_type_codec(cl._mobilitydb_name, encoder=str, decoder=cl.read_from_cursor) diff --git a/pymeos/db/db_objects.py b/pymeos/db/db_objects.py index c9084686..1759618e 100644 --- a/pymeos/db/db_objects.py +++ b/pymeos/db/db_objects.py @@ -1,24 +1,24 @@ from pymeos import ( + FloatSet, + FloatSpan, + FloatSpanSet, + GeographySet, + GeometrySet, + IntSet, + IntSpan, + IntSpanSet, + STBox, TBool, - TInt, + TBox, + TextSet, TFloat, - TText, - TGeomPoint, TGeogPoint, - TBox, - STBox, + TGeomPoint, + TInt, TsTzSet, TsTzSpan, TsTzSpanSet, - GeometrySet, - GeographySet, - TextSet, - IntSet, - IntSpan, - IntSpanSet, - FloatSpan, - FloatSet, - FloatSpanSet, + TText, ) db_objects = [ diff --git a/pymeos/db/psycopg.py b/pymeos/db/psycopg.py index 10233593..2cd8b618 100644 --- a/pymeos/db/psycopg.py +++ b/pymeos/db/psycopg.py @@ -2,7 +2,7 @@ import psycopg from psycopg import connect -from psycopg.adapt import Loader, Buffer, Dumper +from psycopg.adapt import Buffer, Dumper, Loader from .db_objects import db_objects diff --git a/pymeos/db/psycopg2.py b/pymeos/db/psycopg2.py index b2774ae4..887a9833 100644 --- a/pymeos/db/psycopg2.py +++ b/pymeos/db/psycopg2.py @@ -1,5 +1,5 @@ import psycopg2 -from psycopg2 import extensions, connect +from psycopg2 import connect, extensions from .db_objects import db_objects @@ -49,6 +49,4 @@ def register(cls, connection: psycopg2.extensions.connection) -> None: for cl in db_objects: cursor.execute(f"SELECT NULL::{cl._mobilitydb_name}") oid = cursor.description[0][1] - extensions.register_type( - extensions.new_type((oid,), cl._mobilitydb_name, cl.read_from_cursor) - ) + extensions.register_type(extensions.new_type((oid,), cl._mobilitydb_name, cl.read_from_cursor)) diff --git a/pymeos/factory.py b/pymeos/factory.py index 1bed983e..0f967af3 100644 --- a/pymeos/factory.py +++ b/pymeos/factory.py @@ -1,41 +1,41 @@ -from pymeos_cffi import MeosType, MeosTemporalSubtype +from pymeos_cffi import MeosTemporalSubtype, MeosType +from .collections import ( + DateSet, + DateSpan, + DateSpanSet, + FloatSet, + FloatSpan, + FloatSpanSet, + GeographySet, + GeometrySet, + IntSet, + IntSpan, + IntSpanSet, + TextSet, + TsTzSet, + TsTzSpan, + TsTzSpanSet, +) from .main import ( TBoolInst, TBoolSeq, TBoolSeqSet, - TIntInst, - TIntSeq, - TIntSeqSet, TFloatInst, TFloatSeq, TFloatSeqSet, - TTextInst, - TTextSeq, - TTextSeqSet, - TGeomPointInst, - TGeomPointSeq, - TGeomPointSeqSet, TGeogPointInst, TGeogPointSeq, TGeogPointSeqSet, -) -from .collections import ( - GeometrySet, - GeographySet, - IntSet, - IntSpan, - IntSpanSet, - FloatSet, - FloatSpan, - FloatSpanSet, - TextSet, - DateSet, - DateSpan, - DateSpanSet, - TsTzSet, - TsTzSpan, - TsTzSpanSet, + TGeomPointInst, + TGeomPointSeq, + TGeomPointSeqSet, + TIntInst, + TIntSeq, + TIntSeqSet, + TTextInst, + TTextSeq, + TTextSeqSet, ) @@ -128,9 +128,5 @@ def create_collection(inner): return None attributes = ["spansettype", "spantype", "settype"] - collection_type = next( - getattr(inner, attribute) - for attribute in attributes - if hasattr(inner, attribute) - ) + collection_type = next(getattr(inner, attribute) for attribute in attributes if hasattr(inner, attribute)) return _CollectionFactory._mapper[collection_type](_inner=inner) diff --git a/pymeos/main/__init__.py b/pymeos/main/__init__.py index b6517465..153e4cab 100644 --- a/pymeos/main/__init__.py +++ b/pymeos/main/__init__.py @@ -3,18 +3,18 @@ from .tint import TInt, TIntInst, TIntSeq, TIntSeqSet from .tnumber import TNumber from .tpoint import ( - TPoint, - TPointInst, - TPointSeq, - TPointSeqSet, - TGeomPoint, - TGeomPointInst, - TGeomPointSeq, - TGeomPointSeqSet, TGeogPoint, TGeogPointInst, TGeogPointSeq, TGeogPointSeqSet, + TGeomPoint, + TGeomPointInst, + TGeomPointSeq, + TGeomPointSeqSet, + TPoint, + TPointInst, + TPointSeq, + TPointSeqSet, ) from .ttext import TText, TTextInst, TTextSeq, TTextSeqSet diff --git a/pymeos/main/tbool.py b/pymeos/main/tbool.py index 6f9c1673..2ddacc92 100644 --- a/pymeos/main/tbool.py +++ b/pymeos/main/tbool.py @@ -1,12 +1,12 @@ from __future__ import annotations from abc import ABC -from typing import Optional, Union, List, Set, overload, Type, TypeVar +from typing import TypeVar, overload from pymeos_cffi import * from ..collections import * -from ..temporal import TInterpolation, Temporal, TInstant, TSequence, TSequenceSet +from ..temporal import Temporal, TInstant, TInterpolation, TSequence, TSequenceSet Self = TypeVar("Self", bound="TBool") @@ -50,7 +50,7 @@ def from_base_time(value: bool, base: datetime) -> TBoolInst: ... @staticmethod @overload - def from_base_time(value: bool, base: Union[TsTzSet, TsTzSpan]) -> TBoolSeq: ... + def from_base_time(value: bool, base: TsTzSet | TsTzSpan) -> TBoolSeq: ... @staticmethod @overload @@ -73,21 +73,17 @@ def from_base_time(value: bool, base: Time) -> TBool: tboolseq_from_base_tstzspan, tboolseqset_from_base_tstzspanset """ if isinstance(base, datetime): - return TBoolInst( - _inner=tboolinst_make(value, datetime_to_timestamptz(base)) - ) + return TBoolInst(_inner=tboolinst_make(value, datetime_to_timestamptz(base))) elif isinstance(base, TsTzSet): return TBoolSeq(_inner=tboolseq_from_base_tstzset(value, base._inner)) elif isinstance(base, TsTzSpan): return TBoolSeq(_inner=tboolseq_from_base_tstzspan(value, base._inner)) elif isinstance(base, TsTzSpanSet): - return TBoolSeqSet( - _inner=tboolseqset_from_base_tstzspanset(value, base._inner) - ) + return TBoolSeqSet(_inner=tboolseqset_from_base_tstzspanset(value, base._inner)) raise TypeError(f"Operation not supported with type {base.__class__}") @classmethod - def from_mfjson(cls: Type[Self], mfjson: str) -> Self: + def from_mfjson(cls: type[Self], mfjson: str) -> Self: """ Returns a temporal object from a MF-JSON string. @@ -124,7 +120,7 @@ def as_wkt(self): return tbool_out(self._inner) # ------------------------- Accessors ------------------------------------- - def value_set(self) -> Set[bool]: + def value_set(self) -> set[bool]: """ Returns the unique values in `self`. @@ -165,12 +161,10 @@ def value_at_timestamp(self, timestamp) -> bool: MEOS Function: tbool_value_at_timestamptz """ - return tbool_value_at_timestamptz( - self._inner, datetime_to_timestamptz(timestamp), True - ) + return tbool_value_at_timestamptz(self._inner, datetime_to_timestamptz(timestamp), True) # ------------------------- Ever and Always Comparisons ------------------- - def always_eq(self, value: Union[bool, TBool]) -> bool: + def always_eq(self, value: bool | TBool) -> bool: """ Returns whether `self` is always equal to `value`. @@ -190,7 +184,7 @@ def always_eq(self, value: Union[bool, TBool]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def ever_eq(self, value: Union[bool, TBool]) -> bool: + def ever_eq(self, value: bool | TBool) -> bool: """ Returns whether `self` is ever equal to `value`. @@ -210,7 +204,7 @@ def ever_eq(self, value: Union[bool, TBool]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def never_eq(self, value: Union[bool, TBool]) -> bool: + def never_eq(self, value: bool | TBool) -> bool: """ Returns whether `self` is never equal to `value`. @@ -226,7 +220,7 @@ def never_eq(self, value: Union[bool, TBool]) -> bool: return not self.ever_eq(value) # ------------------------- Temporal Comparisons -------------------------- - def temporal_equal(self, other: Union[bool, TBool]) -> TBool: + def temporal_equal(self, other: bool | TBool) -> TBool: """ Returns the temporal equality relation between `self` and `other`. @@ -245,7 +239,7 @@ def temporal_equal(self, other: Union[bool, TBool]) -> TBool: return super().temporal_equal(other) return Temporal._factory(result) - def temporal_not_equal(self, other: Union[bool, TBool]) -> TBool: + def temporal_not_equal(self, other: bool | TBool) -> TBool: """ Returns the temporal inequality relation between `self` and `other`. @@ -265,7 +259,7 @@ def temporal_not_equal(self, other: Union[bool, TBool]) -> TBool: return Temporal._factory(result) # ------------------------- Restrictions ---------------------------------- - def at(self, other: Union[bool, Time]) -> TBool: + def at(self, other: bool | Time) -> TBool: """ Returns a new temporal boolean with the values of `self` restricted to the time or value `other`. @@ -286,7 +280,7 @@ def at(self, other: Union[bool, Time]) -> TBool: return super().at(other) return Temporal._factory(result) - def minus(self, other: Union[bool, Time]) -> TBool: + def minus(self, other: bool | Time) -> TBool: """ Returns a new temporal boolean with the values of `self` restricted to the complement of the time or value @@ -310,7 +304,7 @@ def minus(self, other: Union[bool, Time]) -> TBool: return Temporal._factory(result) # ------------------------- Boolean Operations ---------------------------- - def temporal_and(self, other: Union[bool, TBool]) -> TBool: + def temporal_and(self, other: bool | TBool) -> TBool: """ Returns the temporal conjunction of `self` and `other`. @@ -345,7 +339,7 @@ def __and__(self, other): """ return self.temporal_and(other) - def temporal_or(self, other: Union[bool, TBool]) -> TBool: + def temporal_or(self, other: bool | TBool) -> TBool: """ Returns the temporal disjunction of `self` and `other`. @@ -415,7 +409,7 @@ def __invert__(self): """ return self.temporal_not() - def when_true(self) -> Optional[TsTzSpanSet]: + def when_true(self) -> TsTzSpanSet | None: """ Returns a tstzspan set with the tstzspans where `self` is True. @@ -428,7 +422,7 @@ def when_true(self) -> Optional[TsTzSpanSet]: result = tbool_when_true(self._inner) return TsTzSpanSet(_inner=result) if result is not None else None - def when_false(self) -> Optional[TsTzSpanSet]: + def when_false(self) -> TsTzSpanSet | None: """ Returns a tstzspan set with the tstzspans where `self` is False. @@ -473,10 +467,10 @@ class TBoolInst(TInstant[bool, "TBool", "TBoolInst", "TBoolSeq", "TBoolSeqSet"], def __init__( self, - string: Optional[str] = None, + string: str | None = None, *, - value: Optional[Union[str, bool]] = None, - timestamp: Optional[Union[str, datetime]] = None, + value: str | bool | None = None, + timestamp: str | datetime | None = None, _inner=None, ): super().__init__(string=string, value=value, timestamp=timestamp, _inner=_inner) @@ -491,9 +485,9 @@ class TBoolSeq(TSequence[bool, "TBool", "TBoolInst", "TBoolSeq", "TBoolSeqSet"], def __init__( self, - string: Optional[str] = None, + string: str | None = None, *, - instant_list: Optional[List[Union[str, TBoolInst]]] = None, + instant_list: list[str | TBoolInst] | None = None, lower_inc: bool = True, upper_inc: bool = False, interpolation: TInterpolation = TInterpolation.STEPWISE, @@ -511,9 +505,7 @@ def __init__( ) -class TBoolSeqSet( - TSequenceSet[bool, "TBool", "TBoolInst", "TBoolSeq", "TBoolSeqSet"], TBool -): +class TBoolSeqSet(TSequenceSet[bool, "TBool", "TBoolInst", "TBoolSeq", "TBoolSeqSet"], TBool): """ Class for representing temporal boolean values over a tstzspan of time with gaps. """ @@ -522,9 +514,9 @@ class TBoolSeqSet( def __init__( self, - string: Optional[str] = None, + string: str | None = None, *, - sequence_list: Optional[List[Union[str, TBoolSeq]]] = None, + sequence_list: list[str | TBoolSeq] | None = None, normalize: bool = True, _inner=None, ): diff --git a/pymeos/main/tfloat.py b/pymeos/main/tfloat.py index 374f91c9..242b3513 100644 --- a/pymeos/main/tfloat.py +++ b/pymeos/main/tfloat.py @@ -1,19 +1,19 @@ from __future__ import annotations from abc import ABC -from typing import Optional, List, Union, TYPE_CHECKING, Set, overload, Type, TypeVar +from typing import TYPE_CHECKING, TypeVar, overload from pymeos_cffi import * -from .tnumber import TNumber from ..collections import * from ..mixins import TSimplifiable, TTemporallyComparable -from ..temporal import TInterpolation, Temporal, TInstant, TSequence, TSequenceSet +from ..temporal import Temporal, TInstant, TInterpolation, TSequence, TSequenceSet +from .tnumber import TNumber if TYPE_CHECKING: from ..boxes import TBox - from .tint import TInt from .tbool import TBool + from .tint import TInt Self = TypeVar("Self", bound="TFloat") @@ -34,9 +34,9 @@ class TFloat( # ------------------------- Constructors ---------------------------------- @staticmethod def from_base_temporal( - value: float, - base: Temporal, - interpolation: TInterpolation = TInterpolation.LINEAR, + value: float, + base: Temporal, + interpolation: TInterpolation = TInterpolation.LINEAR, ) -> TFloat: """ Returns a new temporal float with the value `value` and the temporal @@ -58,36 +58,22 @@ def from_base_temporal( @staticmethod @overload - def from_base_time( - value: float, base: datetime, interpolation: None = None - ) -> TFloatInst: - ... + def from_base_time(value: float, base: datetime, interpolation: None = None) -> TFloatInst: ... @staticmethod @overload - def from_base_time( - value: float, base: TsTzSet, interpolation: None = None - ) -> TFloatSeq: - ... + def from_base_time(value: float, base: TsTzSet, interpolation: None = None) -> TFloatSeq: ... @staticmethod @overload - def from_base_time( - value: float, base: TsTzSpan, interpolation: TInterpolation = None - ) -> TFloatSeq: - ... + def from_base_time(value: float, base: TsTzSpan, interpolation: TInterpolation = None) -> TFloatSeq: ... @staticmethod @overload - def from_base_time( - value: float, base: TsTzSpanSet, interpolation: TInterpolation = None - ) -> TFloatSeqSet: - ... + def from_base_time(value: float, base: TsTzSpanSet, interpolation: TInterpolation = None) -> TFloatSeqSet: ... @staticmethod - def from_base_time( - value: float, base: Time, interpolation: TInterpolation = None - ) -> TFloat: + def from_base_time(value: float, base: Time, interpolation: TInterpolation = None) -> TFloat: """ Returns a new temporal float with the value `value` and the temporal frame of `base`. @@ -105,25 +91,17 @@ def from_base_time( tfloatseq_from_base_time, tfloatseqset_from_base_time """ if isinstance(base, datetime): - return TFloatInst( - _inner=tfloatinst_make(value, datetime_to_timestamptz(base)) - ) + return TFloatInst(_inner=tfloatinst_make(value, datetime_to_timestamptz(base))) elif isinstance(base, TsTzSet): return TFloatSeq(_inner=tfloatseq_from_base_tstzset(value, base._inner)) elif isinstance(base, TsTzSpan): - return TFloatSeq( - _inner=tfloatseq_from_base_tstzspan(value, base._inner, interpolation) - ) + return TFloatSeq(_inner=tfloatseq_from_base_tstzspan(value, base._inner, interpolation)) elif isinstance(base, TsTzSpanSet): - return TFloatSeqSet( - _inner=tfloatseqset_from_base_tstzspanset( - value, base._inner, interpolation - ) - ) + return TFloatSeqSet(_inner=tfloatseqset_from_base_tstzspanset(value, base._inner, interpolation)) raise TypeError(f"Operation not supported with type {base.__class__}") @classmethod - def from_mfjson(cls: Type[Self], mfjson: str) -> Self: + def from_mfjson(cls: type[Self], mfjson: str) -> Self: """ Returns a temporal object from a MF-JSON string. @@ -187,10 +165,7 @@ def to_tint(self) -> TInt: from ..factory import _TemporalFactory if self.interpolation() == TInterpolation.LINEAR: - raise ValueError( - "Cannot convert a temporal float with linear " - "interpolation to a temporal integer" - ) + raise ValueError("Cannot convert a temporal float with linear interpolation to a temporal integer") return _TemporalFactory.create_temporal(tfloat_to_tint(self._inner)) def to_floatrange(self) -> FloatSpan: @@ -254,7 +229,7 @@ def end_value(self) -> float: """ return tfloat_end_value(self._inner) - def value_set(self) -> Set[float]: + def value_set(self) -> set[float]: """ Returns the set of values of `self`. Note that when the interpolation is linear, the set will contain only @@ -294,7 +269,7 @@ def max_value(self) -> float: return tfloat_max_value(self._inner) # ------------------------- Ever and Always Comparisons ------------------- - def always_less(self, value: Union[float, TFloat]) -> bool: + def always_less(self, value: float | TFloat) -> bool: """ Returns whether the values of `self` are always less than `value`. @@ -315,7 +290,7 @@ def always_less(self, value: Union[float, TFloat]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def always_less_or_equal(self, value: Union[float, TFloat]) -> bool: + def always_less_or_equal(self, value: float | TFloat) -> bool: """ Returns whether the values of `self` are always less than or equal to `value`. @@ -337,7 +312,7 @@ def always_less_or_equal(self, value: Union[float, TFloat]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def always_equal(self, value: Union[float, TFloat]) -> bool: + def always_equal(self, value: float | TFloat) -> bool: """ Returns whether the values of `self` are always equal to `value`. @@ -358,7 +333,7 @@ def always_equal(self, value: Union[float, TFloat]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def always_not_equal(self, value: Union[float, TFloat]) -> bool: + def always_not_equal(self, value: float | TFloat) -> bool: """ Returns whether the values of `self` are always not equal to `value`. @@ -379,7 +354,7 @@ def always_not_equal(self, value: Union[float, TFloat]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def always_greater_or_equal(self, value: Union[float, TFloat]) -> bool: + def always_greater_or_equal(self, value: float | TFloat) -> bool: """ Returns whether the values of `self` are always greater than or equal to `value`. @@ -401,7 +376,7 @@ def always_greater_or_equal(self, value: Union[float, TFloat]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def always_greater(self, value: Union[float, TFloat]) -> bool: + def always_greater(self, value: float | TFloat) -> bool: """ Returns whether the values of `self` are always greater than `value`. @@ -422,7 +397,7 @@ def always_greater(self, value: Union[float, TFloat]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def ever_less(self, value: Union[float, TFloat]) -> bool: + def ever_less(self, value: float | TFloat) -> bool: """ Returns whether the values of `self` are ever less than `value`. @@ -443,7 +418,7 @@ def ever_less(self, value: Union[float, TFloat]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def ever_less_or_equal(self, value: Union[float, TFloat]) -> bool: + def ever_less_or_equal(self, value: float | TFloat) -> bool: """ Returns whether the values of `self` are ever less than or equal to `value`. @@ -465,7 +440,7 @@ def ever_less_or_equal(self, value: Union[float, TFloat]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def ever_equal(self, value: Union[float, TFloat]) -> bool: + def ever_equal(self, value: float | TFloat) -> bool: """ Returns whether the values of `self` are ever equal to `value`. @@ -486,7 +461,7 @@ def ever_equal(self, value: Union[float, TFloat]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def ever_not_equal(self, value: Union[float, TFloat]) -> bool: + def ever_not_equal(self, value: float | TFloat) -> bool: """ Returns whether the values of `self` are ever not equal to `value`. @@ -507,7 +482,7 @@ def ever_not_equal(self, value: Union[float, TFloat]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def ever_greater_or_equal(self, value: Union[float, TFloat]) -> bool: + def ever_greater_or_equal(self, value: float | TFloat) -> bool: """ Returns whether the values of `self` are ever greater than or equal to `value`. @@ -529,7 +504,7 @@ def ever_greater_or_equal(self, value: Union[float, TFloat]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def ever_greater(self, value: Union[float, TFloat]) -> bool: + def ever_greater(self, value: float | TFloat) -> bool: """ Returns whether the values of `self` are ever greater than `value`. @@ -550,7 +525,7 @@ def ever_greater(self, value: Union[float, TFloat]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def never_less(self, value: Union[float, TFloat]) -> bool: + def never_less(self, value: float | TFloat) -> bool: """ Returns whether the values of `self` are never less than `value`. @@ -566,7 +541,7 @@ def never_less(self, value: Union[float, TFloat]) -> bool: """ return not self.ever_less(value) - def never_less_or_equal(self, value: Union[float, TFloat]) -> bool: + def never_less_or_equal(self, value: float | TFloat) -> bool: """ Returns whether the values of `self` are never less than or equal to `value`. @@ -583,7 +558,7 @@ def never_less_or_equal(self, value: Union[float, TFloat]) -> bool: """ return not self.ever_less_or_equal(value) - def never_equal(self, value: Union[float, TFloat]) -> bool: + def never_equal(self, value: float | TFloat) -> bool: """ Returns whether the values of `self` are never equal to `value`. @@ -599,7 +574,7 @@ def never_equal(self, value: Union[float, TFloat]) -> bool: """ return not self.ever_equal(value) - def never_not_equal(self, value: Union[float, TFloat]) -> bool: + def never_not_equal(self, value: float | TFloat) -> bool: """ Returns whether the values of `self` are never not equal to `value`. @@ -615,7 +590,7 @@ def never_not_equal(self, value: Union[float, TFloat]) -> bool: """ return not self.ever_not_equal(value) - def never_greater_or_equal(self, value: Union[float, TFloat]) -> bool: + def never_greater_or_equal(self, value: float | TFloat) -> bool: """ Returns whether the values of `self` are never greater than or equal to `value`. @@ -632,7 +607,7 @@ def never_greater_or_equal(self, value: Union[float, TFloat]) -> bool: """ return not self.ever_greater_or_equal(value) - def never_greater(self, value: Union[float, TFloat]) -> bool: + def never_greater(self, value: float | TFloat) -> bool: """ Returns whether the values of `self` are never greater than `value`. @@ -649,7 +624,7 @@ def never_greater(self, value: Union[float, TFloat]) -> bool: return not self.ever_greater(value) # ------------------------- Temporal Comparisons -------------------------- - def temporal_equal(self, other: Union[int, float, TFloat]) -> TBool: + def temporal_equal(self, other: int | float | TFloat) -> TBool: """ Returns the temporal equality relation between `self` and `other`. @@ -663,13 +638,13 @@ def temporal_equal(self, other: Union[int, float, TFloat]) -> TBool: MEOS Functions: teq_tfloat_float, teq_temporal_temporal """ - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): result = teq_tfloat_float(self._inner, float(other)) else: return super().temporal_equal(other) return Temporal._factory(result) - def temporal_not_equal(self, other: Union[int, float, TFloat]) -> TBool: + def temporal_not_equal(self, other: int | float | TFloat) -> TBool: """ Returns the temporal not equal relation between `self` and `other`. @@ -683,13 +658,13 @@ def temporal_not_equal(self, other: Union[int, float, TFloat]) -> TBool: MEOS Functions: tne_tfloat_float, tne_temporal_temporal """ - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): result = tne_tfloat_float(self._inner, float(other)) else: return super().temporal_not_equal(other) return Temporal._factory(result) - def temporal_less(self, other: Union[int, float, TFloat]) -> TBool: + def temporal_less(self, other: int | float | TFloat) -> TBool: """ Returns the temporal less than relation between `self` and `other`. @@ -703,13 +678,13 @@ def temporal_less(self, other: Union[int, float, TFloat]) -> TBool: MEOS Functions: tlt_tfloat_float, tlt_temporal_temporal """ - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): result = tlt_tfloat_float(self._inner, float(other)) else: return super().temporal_less(other) return Temporal._factory(result) - def temporal_less_or_equal(self, other: Union[int, float, TFloat]) -> TBool: + def temporal_less_or_equal(self, other: int | float | TFloat) -> TBool: """ Returns the temporal less or equal relation between `self` and `other`. @@ -724,13 +699,13 @@ def temporal_less_or_equal(self, other: Union[int, float, TFloat]) -> TBool: MEOS Functions: tle_tfloat_float, tle_temporal_temporal """ - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): result = tle_tfloat_float(self._inner, float(other)) else: return super().temporal_less_or_equal(other) return Temporal._factory(result) - def temporal_greater_or_equal(self, other: Union[int, float, TFloat]) -> TBool: + def temporal_greater_or_equal(self, other: int | float | TFloat) -> TBool: """ Returns the temporal greater or equal relation between `self` and `other`. @@ -745,13 +720,13 @@ def temporal_greater_or_equal(self, other: Union[int, float, TFloat]) -> TBool: MEOS Functions: tge_tfloat_float, tge_temporal_temporal """ - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): result = tge_tfloat_float(self._inner, float(other)) else: return super().temporal_greater_or_equal(other) return Temporal._factory(result) - def temporal_greater(self, other: Union[int, float, TFloat]) -> TBool: + def temporal_greater(self, other: int | float | TFloat) -> TBool: """ Returns the temporal greater than relation between `self` and `other`. @@ -766,7 +741,7 @@ def temporal_greater(self, other: Union[int, float, TFloat]) -> TBool: MEOS Functions: tgt_tfloat_float, tgt_temporal_temporal """ - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): result = tgt_tfloat_float(self._inner, float(other)) else: return super().temporal_greater(other) @@ -774,19 +749,8 @@ def temporal_greater(self, other: Union[int, float, TFloat]) -> TBool: # ------------------------- Restrictions ---------------------------------- def at( - self, - other: Union[ - float, - int, - FloatSet, - IntSet, - FloatSpan, - IntSpan, - FloatSpanSet, - IntSpanSet, - TBox, - Time, - ], + self, + other: float | int | FloatSet | IntSet | FloatSpan | IntSpan | FloatSpanSet | IntSpanSet | TBox | Time, ) -> TFloat: """ Returns a new temporal float with the values of `self` restricted to @@ -803,7 +767,7 @@ def at( temporal_at_timestamp, temporal_at_tstzset, temporal_at_tstzspan, temporal_at_tstzspanset """ - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): result = tfloat_at_value(self._inner, float(other)) elif isinstance(other, IntSet): return super().at(other.to_floatset()) @@ -816,19 +780,8 @@ def at( return Temporal._factory(result) def minus( - self, - other: Union[ - float, - int, - FloatSet, - IntSet, - FloatSpan, - IntSpan, - FloatSpanSet, - IntSpanSet, - TBox, - Time, - ], + self, + other: float | int | FloatSet | IntSet | FloatSpan | IntSpan | FloatSpanSet | IntSpanSet | TBox | Time, ) -> Temporal: """ Returns a new temporal float with the values of `self` restricted to @@ -845,7 +798,7 @@ def minus( temporal_minus_timestamp, temporal_minus_tstzset, temporal_minus_tstzspan, temporal_minus_tstzspanset """ - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): result = tfloat_minus_value(self._inner, float(other)) elif isinstance(other, IntSet): return super().minus(other.to_floatset()) @@ -870,9 +823,7 @@ def value_at_timestamp(self, timestamp) -> float: MEOS Functions: tfloat_value_at_timestamp """ - return tfloat_value_at_timestamptz( - self._inner, datetime_to_timestamptz(timestamp), True - ) + return tfloat_value_at_timestamptz(self._inner, datetime_to_timestamptz(timestamp), True) def derivative(self) -> TFloat: """ @@ -931,7 +882,7 @@ def round(self, max_decimals: int = 0) -> TFloat: return Temporal._factory(temporal_round(self._inner, max_decimals)) # ------------------------- Split Operations ------------------------------ - def value_split(self, size: float, start: Optional[float] = 0) -> List[Temporal]: + def value_split(self, size: float, start: float | None = 0) -> list[Temporal]: """ Splits `self` into fragments with respect to value buckets @@ -949,12 +900,12 @@ def value_split(self, size: float, start: Optional[float] = 0) -> List[Temporal] return [Temporal._factory(fragments[i]) for i in range(count)] def value_time_split( - self, - value_size: float, - duration: Union[str, timedelta], - value_start: Optional[float] = 0.0, - time_start: Optional[Union[str, datetime]] = None, - ) -> List[Temporal]: + self, + value_size: float, + duration: str | timedelta, + value_start: float | None = 0.0, + time_start: str | datetime | None = None, + ) -> list[Temporal]: """ Splits `self` into fragments with respect to value and tstzspan buckets. @@ -980,14 +931,8 @@ def value_time_split( if isinstance(time_start, datetime) else pg_timestamptz_in(time_start, -1) ) - dt = ( - timedelta_to_interval(duration) - if isinstance(duration, timedelta) - else pg_interval_in(duration, -1) - ) - fragments, _, _, count = tfloat_value_time_split( - self._inner, value_size, dt, value_start, st - ) + dt = timedelta_to_interval(duration) if isinstance(duration, timedelta) else pg_interval_in(duration, -1) + fragments, _, _, count = tfloat_value_time_split(self._inner, value_size, dt, value_start, st) return [Temporal._factory(fragments[i]) for i in range(count)] # ------------------------- Database Operations --------------------------- @@ -1018,9 +963,7 @@ def read_from_cursor(value, _=None): raise Exception("ERROR: Could not parse temporal float value") -class TFloatInst( - TInstant[float, "TFloat", "TFloatInst", "TFloatSeq", "TFloatSeqSet"], TFloat -): +class TFloatInst(TInstant[float, "TFloat", "TFloatInst", "TFloatSeq", "TFloatSeqSet"], TFloat): """ Class for representing temporal floats at a single instant. """ @@ -1029,19 +972,17 @@ class TFloatInst( _cast_function = float def __init__( - self, - string: Optional[str] = None, - *, - value: Optional[Union[str, float]] = None, - timestamp: Optional[Union[str, datetime]] = None, - _inner=None, + self, + string: str | None = None, + *, + value: str | float | None = None, + timestamp: str | datetime | None = None, + _inner=None, ): super().__init__(string=string, value=value, timestamp=timestamp, _inner=_inner) -class TFloatSeq( - TSequence[float, "TFloat", "TFloatInst", "TFloatSeq", "TFloatSeqSet"], TFloat -): +class TFloatSeq(TSequence[float, "TFloat", "TFloatInst", "TFloatSeq", "TFloatSeqSet"], TFloat): """ Class for representing temporal floats over a tstzspan of time. """ @@ -1049,15 +990,15 @@ class TFloatSeq( ComponentClass = TFloatInst def __init__( - self, - string: Optional[str] = None, - *, - instant_list: Optional[List[Union[str, TFloatInst]]] = None, - lower_inc: bool = True, - upper_inc: bool = False, - interpolation: TInterpolation = TInterpolation.LINEAR, - normalize: bool = True, - _inner=None, + self, + string: str | None = None, + *, + instant_list: list[str | TFloatInst] | None = None, + lower_inc: bool = True, + upper_inc: bool = False, + interpolation: TInterpolation = TInterpolation.LINEAR, + normalize: bool = True, + _inner=None, ): super().__init__( string=string, @@ -1070,9 +1011,7 @@ def __init__( ) -class TFloatSeqSet( - TSequenceSet[float, "TFloat", "TFloatInst", "TFloatSeq", "TFloatSeqSet"], TFloat -): +class TFloatSeqSet(TSequenceSet[float, "TFloat", "TFloatInst", "TFloatSeq", "TFloatSeqSet"], TFloat): """ Class for representing temporal floats over a tstzspan of time with gaps. """ @@ -1080,12 +1019,12 @@ class TFloatSeqSet( ComponentClass = TFloatSeq def __init__( - self, - string: Optional[str] = None, - *, - sequence_list: Optional[List[Union[str, TFloatSeq]]] = None, - normalize: bool = True, - _inner=None, + self, + string: str | None = None, + *, + sequence_list: list[str | TFloatSeq] | None = None, + normalize: bool = True, + _inner=None, ): super().__init__( string=string, diff --git a/pymeos/main/tint.py b/pymeos/main/tint.py index f69e7f43..658e457e 100644 --- a/pymeos/main/tint.py +++ b/pymeos/main/tint.py @@ -1,19 +1,19 @@ from __future__ import annotations from abc import ABC -from typing import Optional, Union, List, TYPE_CHECKING, Set, overload, TypeVar, Type +from typing import TYPE_CHECKING, TypeVar, overload from pymeos_cffi import * -from .tnumber import TNumber from ..collections import * from ..mixins import TTemporallyComparable -from ..temporal import TInterpolation, Temporal, TInstant, TSequence, TSequenceSet +from ..temporal import Temporal, TInstant, TInterpolation, TSequence, TSequenceSet +from .tnumber import TNumber if TYPE_CHECKING: from ..boxes import TBox - from .tfloat import TFloat from .tbool import TBool + from .tfloat import TFloat Self = TypeVar("Self", bound="TInt") @@ -55,7 +55,7 @@ def from_base_time(value: int, base: datetime) -> TIntInst: ... @staticmethod @overload - def from_base_time(value: int, base: Union[TsTzSet, TsTzSpan]) -> TIntSeq: ... + def from_base_time(value: int, base: TsTzSet | TsTzSpan) -> TIntSeq: ... @staticmethod @overload @@ -85,13 +85,11 @@ def from_base_time(value: int, base: Time) -> TInt: elif isinstance(base, TsTzSpan): return TIntSeq(_inner=tintseq_from_base_tstzspan(value, base._inner)) elif isinstance(base, TsTzSpanSet): - return TIntSeqSet( - _inner=tintseqset_from_base_tstzspanset(value, base._inner) - ) + return TIntSeqSet(_inner=tintseqset_from_base_tstzspanset(value, base._inner)) raise TypeError(f"Operation not supported with type {base.__class__}") @classmethod - def from_mfjson(cls: Type[Self], mfjson: str) -> Self: + def from_mfjson(cls: type[Self], mfjson: str) -> Self: """ Returns a temporal object from a MF-JSON string. @@ -209,7 +207,7 @@ def end_value(self) -> int: """ return tint_end_value(self._inner) - def value_set(self) -> Set[int]: + def value_set(self) -> set[int]: """ Returns the set of values of `self`. @@ -259,12 +257,10 @@ def value_at_timestamp(self, timestamp) -> int: MEOS Functions: tint_value_at_timestamp """ - return tint_value_at_timestamptz( - self._inner, datetime_to_timestamptz(timestamp), True - ) + return tint_value_at_timestamptz(self._inner, datetime_to_timestamptz(timestamp), True) # ------------------------- Ever and Always Comparisons ------------------- - def always_less(self, value: Union[int, TInt]) -> bool: + def always_less(self, value: int | TInt) -> bool: """ Returns whether the values of `self` are always less than `value`. @@ -285,7 +281,7 @@ def always_less(self, value: Union[int, TInt]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def always_less_or_equal(self, value: Union[int, TInt]) -> bool: + def always_less_or_equal(self, value: int | TInt) -> bool: """ Returns whether the values of `self` are always less than or equal to `value`. @@ -307,7 +303,7 @@ def always_less_or_equal(self, value: Union[int, TInt]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def always_equal(self, value: Union[int, TInt]) -> bool: + def always_equal(self, value: int | TInt) -> bool: """ Returns whether the values of `self` are always equal to `value`. @@ -328,7 +324,7 @@ def always_equal(self, value: Union[int, TInt]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def always_not_equal(self, value: Union[int, TInt]) -> bool: + def always_not_equal(self, value: int | TInt) -> bool: """ Returns whether the values of `self` are always not equal to `value`. @@ -349,7 +345,7 @@ def always_not_equal(self, value: Union[int, TInt]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def always_greater_or_equal(self, value: Union[int, TInt]) -> bool: + def always_greater_or_equal(self, value: int | TInt) -> bool: """ Returns whether the values of `self` are always greater than or equal to `value`. @@ -371,7 +367,7 @@ def always_greater_or_equal(self, value: Union[int, TInt]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def always_greater(self, value: Union[int, TInt]) -> bool: + def always_greater(self, value: int | TInt) -> bool: """ Returns whether the values of `self` are always greater than `value`. @@ -392,7 +388,7 @@ def always_greater(self, value: Union[int, TInt]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def ever_less(self, value: Union[int, TInt]) -> bool: + def ever_less(self, value: int | TInt) -> bool: """ Returns whether the values of `self` are ever less than `value`. @@ -413,7 +409,7 @@ def ever_less(self, value: Union[int, TInt]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def ever_less_or_equal(self, value: Union[int, TInt]) -> bool: + def ever_less_or_equal(self, value: int | TInt) -> bool: """ Returns whether the values of `self` are ever less than or equal to `value`. @@ -435,7 +431,7 @@ def ever_less_or_equal(self, value: Union[int, TInt]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def ever_equal(self, value: Union[int, TInt]) -> bool: + def ever_equal(self, value: int | TInt) -> bool: """ Returns whether the values of `self` are ever equal to `value`. @@ -456,7 +452,7 @@ def ever_equal(self, value: Union[int, TInt]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def ever_not_equal(self, value: Union[int, TInt]) -> bool: + def ever_not_equal(self, value: int | TInt) -> bool: """ Returns whether the values of `self` are ever not equal to `value`. @@ -477,7 +473,7 @@ def ever_not_equal(self, value: Union[int, TInt]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def ever_greater_or_equal(self, value: Union[int, TInt]) -> bool: + def ever_greater_or_equal(self, value: int | TInt) -> bool: """ Returns whether the values of `self` are ever greater than or equal to `value`. @@ -499,7 +495,7 @@ def ever_greater_or_equal(self, value: Union[int, TInt]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def ever_greater(self, value: Union[int, TInt]) -> bool: + def ever_greater(self, value: int | TInt) -> bool: """ Returns whether the values of `self` are ever greater than `value`. @@ -520,7 +516,7 @@ def ever_greater(self, value: Union[int, TInt]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def never_less(self, value: Union[int, TInt]) -> bool: + def never_less(self, value: int | TInt) -> bool: """ Returns whether the values of `self` are never less than `value`. @@ -536,7 +532,7 @@ def never_less(self, value: Union[int, TInt]) -> bool: """ return not self.ever_less(value) - def never_less_or_equal(self, value: Union[int, TInt]) -> bool: + def never_less_or_equal(self, value: int | TInt) -> bool: """ Returns whether the values of `self` are never less than or equal to `value`. @@ -553,7 +549,7 @@ def never_less_or_equal(self, value: Union[int, TInt]) -> bool: """ return not self.ever_less_or_equal(value) - def never_equal(self, value: Union[int, TInt]) -> bool: + def never_equal(self, value: int | TInt) -> bool: """ Returns whether the values of `self` are never equal to `value`. @@ -569,7 +565,7 @@ def never_equal(self, value: Union[int, TInt]) -> bool: """ return not self.ever_equal(value) - def never_not_equal(self, value: Union[int, TInt]) -> bool: + def never_not_equal(self, value: int | TInt) -> bool: """ Returns whether the values of `self` are never not equal to `value`. @@ -585,7 +581,7 @@ def never_not_equal(self, value: Union[int, TInt]) -> bool: """ return not self.ever_not_equal(value) - def never_greater_or_equal(self, value: Union[int, TInt]) -> bool: + def never_greater_or_equal(self, value: int | TInt) -> bool: """ Returns whether the values of `self` are never greater than or equal to `value`. @@ -602,7 +598,7 @@ def never_greater_or_equal(self, value: Union[int, TInt]) -> bool: """ return not self.ever_greater_or_equal(value) - def never_greater(self, value: Union[int, TInt]) -> bool: + def never_greater(self, value: int | TInt) -> bool: """ Returns whether the values of `self` are never greater than `value`. @@ -619,7 +615,7 @@ def never_greater(self, value: Union[int, TInt]) -> bool: return not self.ever_greater(value) # ------------------------- Temporal Comparisons -------------------------- - def temporal_equal(self, other: Union[int, TInt]) -> TBool: + def temporal_equal(self, other: int | TInt) -> TBool: """ Returns the temporal equality relation between `self` and `other`. @@ -638,7 +634,7 @@ def temporal_equal(self, other: Union[int, TInt]) -> TBool: return super().temporal_equal(other) return Temporal._factory(result) - def temporal_not_equal(self, other: Union[int, TInt]) -> TBool: + def temporal_not_equal(self, other: int | TInt) -> TBool: """ Returns the temporal not equal relation between `self` and `other`. @@ -657,7 +653,7 @@ def temporal_not_equal(self, other: Union[int, TInt]) -> TBool: return super().temporal_not_equal(other) return Temporal._factory(result) - def temporal_less(self, other: Union[int, TInt]) -> TBool: + def temporal_less(self, other: int | TInt) -> TBool: """ Returns the temporal less than relation between `self` and `other`. @@ -676,7 +672,7 @@ def temporal_less(self, other: Union[int, TInt]) -> TBool: return super().temporal_less(other) return Temporal._factory(result) - def temporal_less_or_equal(self, other: Union[int, TInt]) -> TBool: + def temporal_less_or_equal(self, other: int | TInt) -> TBool: """ Returns the temporal less or equal relation between `self` and `other`. @@ -696,7 +692,7 @@ def temporal_less_or_equal(self, other: Union[int, TInt]) -> TBool: return super().temporal_less_or_equal(other) return Temporal._factory(result) - def temporal_greater_or_equal(self, other: Union[int, TInt]) -> TBool: + def temporal_greater_or_equal(self, other: int | TInt) -> TBool: """ Returns the temporal greater or equal relation between `self` and `other`. @@ -716,7 +712,7 @@ def temporal_greater_or_equal(self, other: Union[int, TInt]) -> TBool: return super().temporal_greater_or_equal(other) return Temporal._factory(result) - def temporal_greater(self, other: Union[int, TInt]) -> TBool: + def temporal_greater(self, other: int | TInt) -> TBool: """ Returns the temporal greater than relation between `self` and `other`. @@ -739,18 +735,7 @@ def temporal_greater(self, other: Union[int, TInt]) -> TBool: # ------------------------- Restrictions ---------------------------------- def at( self, - other: Union[ - int, - float, - IntSet, - FloatSet, - IntSpan, - FloatSpan, - IntSpanSet, - FloatSpanSet, - TBox, - Time, - ], + other: int | float | IntSet | FloatSet | IntSpan | FloatSpan | IntSpanSet | FloatSpanSet | TBox | Time, ) -> TInt: """ Returns a new temporal int with th e values of `self` restricted to @@ -767,7 +752,7 @@ def at( temporal_at_timestamp, temporal_at_tstzset, temporal_at_tstzspan, temporal_at_tstzspanset """ - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): result = tint_at_value(self._inner, int(other)) elif isinstance(other, FloatSet): return super().at(other.to_intset()) @@ -781,18 +766,7 @@ def at( def minus( self, - other: Union[ - int, - float, - IntSet, - FloatSet, - IntSpan, - FloatSpan, - IntSpanSet, - FloatSpanSet, - TBox, - Time, - ], + other: int | float | IntSet | FloatSet | IntSpan | FloatSpan | IntSpanSet | FloatSpanSet | TBox | Time, ) -> TInt: """ Returns a new temporal int with the values of `self` restricted to the @@ -809,7 +783,7 @@ def minus( temporal_minus_timestamp, temporal_minus_tstzset, temporal_minus_tstzspan, temporal_minus_tstzspanset """ - if isinstance(other, int) or isinstance(other, float): + if isinstance(other, (int, float)): result = tint_minus_value(self._inner, int(other)) elif isinstance(other, FloatSet): return super().minus(other.to_intset()) @@ -822,9 +796,7 @@ def minus( return Temporal._factory(result) # ------------------------- Distance -------------------------------------- - def nearest_approach_distance( - self, other: Union[int, float, TNumber, TBox] - ) -> float: + def nearest_approach_distance(self, other: int | float | TNumber | TBox) -> float: """ Returns the nearest approach distance between `self` and `other`. @@ -847,7 +819,7 @@ def nearest_approach_distance( return super().nearest_approach_distance(other) # ------------------------- Split Operations ------------------------------ - def value_split(self, size: int, start: Optional[int] = 0) -> List[TInt]: + def value_split(self, size: int, start: int | None = 0) -> list[TInt]: """ Splits `self` into fragments with respect to value buckets @@ -867,10 +839,10 @@ def value_split(self, size: int, start: Optional[int] = 0) -> List[TInt]: def value_time_split( self, value_size: int, - duration: Union[str, timedelta], - value_start: Optional[int] = 0, - time_start: Optional[Union[str, datetime]] = None, - ) -> List[TInt]: + duration: str | timedelta, + value_start: int | None = 0, + time_start: str | datetime | None = None, + ) -> list[TInt]: """ Splits `self` into fragments with respect to value and tstzspan buckets. @@ -896,14 +868,8 @@ def value_time_split( if isinstance(time_start, datetime) else pg_timestamptz_in(time_start, -1) ) - dt = ( - timedelta_to_interval(duration) - if isinstance(duration, timedelta) - else pg_interval_in(duration, -1) - ) - tiles, _, _, count = tint_value_time_split( - self._inner, value_size, dt, value_start, st - ) + dt = timedelta_to_interval(duration) if isinstance(duration, timedelta) else pg_interval_in(duration, -1) + tiles, _, _, count = tint_value_time_split(self._inner, value_size, dt, value_start, st) return [Temporal._factory(tiles[i]) for i in range(count)] # ------------------------- Database Operations --------------------------- @@ -938,10 +904,10 @@ class TIntInst(TInstant[int, "TInt", "TIntInst", "TIntSeq", "TIntSeqSet"], TInt) def __init__( self, - string: Optional[str] = None, + string: str | None = None, *, - value: Optional[Union[str, int]] = None, - timestamp: Optional[Union[str, datetime]] = None, + value: str | int | None = None, + timestamp: str | datetime | None = None, _inner=None, ): super().__init__(string=string, value=value, timestamp=timestamp, _inner=_inner) @@ -956,9 +922,9 @@ class TIntSeq(TSequence[int, "TInt", "TIntInst", "TIntSeq", "TIntSeqSet"], TInt) def __init__( self, - string: Optional[str] = None, + string: str | None = None, *, - instant_list: Optional[List[Union[str, TIntInst]]] = None, + instant_list: list[str | TIntInst] | None = None, lower_inc: bool = True, upper_inc: bool = False, interpolation: TInterpolation = TInterpolation.STEPWISE, @@ -985,9 +951,9 @@ class TIntSeqSet(TSequenceSet[int, "TInt", "TIntInst", "TIntSeq", "TIntSeqSet"], def __init__( self, - string: Optional[str] = None, + string: str | None = None, *, - sequence_list: Optional[List[Union[str, TIntSeq]]] = None, + sequence_list: list[str | TIntSeq] | None = None, normalize: bool = True, _inner=None, ): diff --git a/pymeos/main/tnumber.py b/pymeos/main/tnumber.py index 4047c772..c8e33e42 100644 --- a/pymeos/main/tnumber.py +++ b/pymeos/main/tnumber.py @@ -1,17 +1,16 @@ from __future__ import annotations from abc import ABC -from typing import Union, TYPE_CHECKING, TypeVar +from typing import TYPE_CHECKING, TypeVar from pymeos_cffi import * -from ..collections import IntSet, FloatSet +from ..collections import FloatSet, IntSet from ..temporal import Temporal if TYPE_CHECKING: from ..boxes import Box, TBox - from ..collections import Time, IntSpan, IntSpanSet, FloatSpan, FloatSpanSet - from .tint import TInt + from ..collections import FloatSpan, FloatSpanSet, IntSpan, IntSpanSet, Time from .tfloat import TFloat TBase = TypeVar("TBase", int, float) @@ -63,7 +62,7 @@ def time_weighted_average(self) -> float: return tnumber_twavg(self._inner) # ------------------------- Transformations ------------------------------- - def shift_value(self: Self, delta: Union[int, float]) -> Self: + def shift_value(self: Self, delta: int | float) -> Self: """ Returns a new :class:`TNumber` with the value dimension shifted by ``delta``. @@ -74,8 +73,8 @@ def shift_value(self: Self, delta: Union[int, float]) -> Self: MEOS Functions: tint_shift_value, tfloat_shift_value """ - from .tint import TInt from .tfloat import TFloat + from .tint import TInt if isinstance(self, TInt): shifted = tint_shift_value(self._inner, int(delta)) @@ -85,7 +84,7 @@ def shift_value(self: Self, delta: Union[int, float]) -> Self: raise TypeError(f"Operation not supported with type {self.__class__}") return Temporal._factory(shifted) - def scale_value(self: Self, width: Union[int, float]) -> Self: + def scale_value(self: Self, width: int | float) -> Self: """ Returns a new :class:`TNumber` scaled so the value dimension has width ``width``. @@ -96,8 +95,8 @@ def scale_value(self: Self, width: Union[int, float]) -> Self: MEOS Functions: tint_scale_value, tfloat_scale_value """ - from .tint import TInt from .tfloat import TFloat + from .tint import TInt if isinstance(self, TInt): scaled = tint_scale_value(self._inner, int(width)) @@ -107,9 +106,7 @@ def scale_value(self: Self, width: Union[int, float]) -> Self: raise TypeError(f"Operation not supported with type {self.__class__}") return Temporal._factory(scaled) - def shift_scale_value( - self: Self, shift: Union[int, float] = None, width: Union[int, float] = None - ) -> Self: + def shift_scale_value(self: Self, shift: int | float = None, width: int | float = None) -> Self: """ Returns a new :class:`TNumber` with the value dimension shifted by ``shift`` and scaled so the value dimension has width ``width``. @@ -121,12 +118,10 @@ def shift_scale_value( MEOS Functions: tint_shift_scale_value, tfloat_shift_scale_value """ - from .tint import TInt from .tfloat import TFloat + from .tint import TInt - assert ( - shift is not None or width is not None - ), "shift and width must not be both None" + assert shift is not None or width is not None, "shift and width must not be both None" if isinstance(self, TInt): scaled = tint_shift_scale_value( @@ -147,9 +142,7 @@ def shift_scale_value( # ------------------------- Restrictions ---------------------------------- def at( self, - other: Union[ - IntSet, FloatSet, IntSpan, FloatSpan, IntSpanSet, FloatSpanSet, TBox, Time - ], + other: IntSet | FloatSet | IntSpan | FloatSpan | IntSpanSet | FloatSpanSet | TBox | Time, ) -> TG: """ Returns a new temporal object with the values of `self` restricted to @@ -168,19 +161,19 @@ def at( """ from ..boxes import TBox from ..collections import ( - IntSet, FloatSet, - IntSpan, FloatSpan, - IntSpanSet, FloatSpanSet, + IntSet, + IntSpan, + IntSpanSet, ) - if isinstance(other, IntSet) or isinstance(other, FloatSet): + if isinstance(other, (IntSet, FloatSet)): result = temporal_at_values(self._inner, other._inner) - elif isinstance(other, IntSpan) or isinstance(other, FloatSpan): + elif isinstance(other, (IntSpan, FloatSpan)): result = tnumber_at_span(self._inner, other._inner) - elif isinstance(other, IntSpanSet) or isinstance(other, FloatSpanSet): + elif isinstance(other, (IntSpanSet, FloatSpanSet)): result = tnumber_at_spanset(self._inner, other._inner) elif isinstance(other, TBox): result = tnumber_at_tbox(self._inner, other._inner) @@ -190,9 +183,7 @@ def at( def minus( self, - other: Union[ - IntSet, FloatSet, IntSpan, FloatSpan, IntSpanSet, FloatSpanSet, TBox, Time - ], + other: IntSet | FloatSet | IntSpan | FloatSpan | IntSpanSet | FloatSpanSet | TBox | Time, ) -> TG: """ Returns a new temporal object with the values of `self` restricted to @@ -212,19 +203,19 @@ def minus( """ from ..boxes import TBox from ..collections import ( - IntSet, FloatSet, - IntSpan, FloatSpan, - IntSpanSet, FloatSpanSet, + IntSet, + IntSpan, + IntSpanSet, ) - if isinstance(other, IntSet) or isinstance(other, FloatSet): + if isinstance(other, (IntSet, FloatSet)): result = temporal_minus_values(self._inner, other._inner) - elif isinstance(other, IntSpan) or isinstance(other, FloatSpan): + elif isinstance(other, (IntSpan, FloatSpan)): result = tnumber_minus_span(self._inner, other._inner) - elif isinstance(other, IntSpanSet) or isinstance(other, FloatSpanSet): + elif isinstance(other, (IntSpanSet, FloatSpanSet)): result = tnumber_minus_spanset(self._inner, other._inner) elif isinstance(other, TBox): result = tnumber_minus_tbox(self._inner, other._inner) @@ -233,7 +224,7 @@ def minus( return Temporal._factory(result) # ------------------------- Position Operations --------------------------- - def is_left(self, other: Union[Temporal, Box]) -> bool: + def is_left(self, other: Temporal | Box) -> bool: """ Returns whether the bounding box of `self` is left to the bounding box of `other`. @@ -249,7 +240,7 @@ def is_left(self, other: Union[Temporal, Box]) -> bool: """ return self.bounding_box().is_left(other) - def is_over_or_left(self, other: Union[Temporal, Box]) -> bool: + def is_over_or_left(self, other: Temporal | Box) -> bool: """ Returns whether the bounding box of `self` is over or left to the bounding box of `other`. @@ -265,7 +256,7 @@ def is_over_or_left(self, other: Union[Temporal, Box]) -> bool: """ return self.bounding_box().is_over_or_left(other) - def is_right(self, other: Union[Temporal, Box]) -> bool: + def is_right(self, other: Temporal | Box) -> bool: """ Returns whether the bounding box of `self` is right to the bounding box of `other`. @@ -281,7 +272,7 @@ def is_right(self, other: Union[Temporal, Box]) -> bool: """ return self.bounding_box().is_right(other) - def is_over_or_right(self, other: Union[Temporal, Box]) -> bool: + def is_over_or_right(self, other: Temporal | Box) -> bool: """ Returns whether the bounding box of `self` is over or right to the bounding box of `other`. @@ -298,7 +289,7 @@ def is_over_or_right(self, other: Union[Temporal, Box]) -> bool: return self.bounding_box().is_over_or_right(other) # ------------------------- Mathematical Operations ------------------------- - def add(self, other: Union[int, float, TNumber]) -> TNumber: + def add(self, other: int | float | TNumber) -> TNumber: """ Returns a new temporal object with the values of `self` plus `other`. @@ -309,8 +300,8 @@ def add(self, other: Union[int, float, TNumber]) -> TNumber: Returns: A new temporal object of the same subtype as `self`. """ - from .tint import TInt from .tfloat import TFloat + from .tint import TInt if isinstance(self, TInt) and isinstance(other, int): result = add_tint_int(self._inner, other) @@ -322,7 +313,7 @@ def add(self, other: Union[int, float, TNumber]) -> TNumber: raise TypeError(f"Operation not supported with type {other.__class__}") return Temporal._factory(result) - def radd(self, other: Union[int, float]) -> TNumber: + def radd(self, other: int | float) -> TNumber: """ Returns a new temporal object with the values of `self` plus `other`. @@ -335,8 +326,8 @@ def radd(self, other: Union[int, float]) -> TNumber: MEOS Functions: add_int_tint, add_float_tfloat """ - from .tint import TInt from .tfloat import TFloat + from .tint import TInt if isinstance(self, TInt) and isinstance(other, int): result = add_int_tint(other, self._inner) @@ -346,7 +337,7 @@ def radd(self, other: Union[int, float]) -> TNumber: raise TypeError(f"Operation not supported with type {other.__class__}") return Temporal._factory(result) - def sub(self, other: Union[int, float, TNumber]) -> TNumber: + def sub(self, other: int | float | TNumber) -> TNumber: """ Returns a new temporal object with the values of `self` minus `other`. @@ -360,8 +351,8 @@ def sub(self, other: Union[int, float, TNumber]) -> TNumber: MEOS Functions: sub_tint_int, sub_tfloat_float, sub_tnumber_tnumber """ - from .tint import TInt from .tfloat import TFloat + from .tint import TInt if isinstance(self, TInt) and isinstance(other, int): result = sub_tint_int(self._inner, other) @@ -373,7 +364,7 @@ def sub(self, other: Union[int, float, TNumber]) -> TNumber: raise TypeError(f"Operation not supported with type {other.__class__}") return Temporal._factory(result) - def rsub(self, other: Union[int, float]) -> TNumber: + def rsub(self, other: int | float) -> TNumber: """ Returns a new temporal object with the values of `other` minus `self`. @@ -386,8 +377,8 @@ def rsub(self, other: Union[int, float]) -> TNumber: MEOS Functions: sub_int_tint, sub_float_tfloat """ - from .tint import TInt from .tfloat import TFloat + from .tint import TInt if isinstance(self, TInt) and isinstance(other, int): result = sub_int_tint(other, self._inner) @@ -397,7 +388,7 @@ def rsub(self, other: Union[int, float]) -> TNumber: raise TypeError(f"Operation not supported with type {other.__class__}") return Temporal._factory(result) - def mul(self, other: Union[int, float, TNumber]) -> TNumber: + def mul(self, other: int | float | TNumber) -> TNumber: """ Returns a new temporal object with the values of `self` multiplied by `other`. @@ -412,8 +403,8 @@ def mul(self, other: Union[int, float, TNumber]) -> TNumber: MEOS Functions: mult_tint_int, mult_tfloat_float, mult_tnumber_tnumber """ - from .tint import TInt from .tfloat import TFloat + from .tint import TInt if isinstance(self, TInt) and isinstance(other, int): result = mult_tint_int(self._inner, other) @@ -425,7 +416,7 @@ def mul(self, other: Union[int, float, TNumber]) -> TNumber: raise TypeError(f"Operation not supported with type {other.__class__}") return Temporal._factory(result) - def rmul(self, other: Union[int, float]) -> TNumber: + def rmul(self, other: int | float) -> TNumber: """ Returns a new temporal object with the values of `self` multiplied by `other`. @@ -439,8 +430,8 @@ def rmul(self, other: Union[int, float]) -> TNumber: MEOS Functions: mult_int_tint, mult_float_tfloat """ - from .tint import TInt from .tfloat import TFloat + from .tint import TInt if isinstance(self, TInt) and isinstance(other, int): result = mult_int_tint(other, self._inner) @@ -450,7 +441,7 @@ def rmul(self, other: Union[int, float]) -> TNumber: raise TypeError(f"Operation not supported with type {other.__class__}") return Temporal._factory(result) - def div(self, other: Union[int, float, TNumber]) -> TNumber: + def div(self, other: int | float | TNumber) -> TNumber: """ Returns a new temporal object with the values of `self` divided by `other`. @@ -465,8 +456,8 @@ def div(self, other: Union[int, float, TNumber]) -> TNumber: MEOS Functions: div_tint_int, div_tfloat_float, div_tnumber_tnumber """ - from .tint import TInt from .tfloat import TFloat + from .tint import TInt if isinstance(self, TInt) and isinstance(other, int): result = div_tint_int(self._inner, other) @@ -478,7 +469,7 @@ def div(self, other: Union[int, float, TNumber]) -> TNumber: raise TypeError(f"Operation not supported with type {other.__class__}") return Temporal._factory(result) - def rdiv(self, other: Union[int, float]) -> TNumber: + def rdiv(self, other: int | float) -> TNumber: """ Returns a new temporal object with the values of `other` divided by `self`. @@ -492,8 +483,8 @@ def rdiv(self, other: Union[int, float]) -> TNumber: MEOS Functions: div_int_tint, div_float_tfloat """ - from .tint import TInt from .tfloat import TFloat + from .tint import TInt if isinstance(self, TInt) and isinstance(other, int): result = div_int_tint(other, self._inner) @@ -657,7 +648,7 @@ def delta_value(self) -> TNumber: return _TemporalFactory.create_temporal(tnumber_delta_value(self._inner)) # ------------------------- Distance Operations -------------------------- - def distance(self, other: Union[int, float, TNumber]) -> TFloat: + def distance(self, other: int | float | TNumber) -> TFloat: """ Returns the temporal distance between `self` and `other`. @@ -681,9 +672,7 @@ def distance(self, other: Union[int, float, TNumber]) -> TFloat: raise TypeError(f"Operation not supported with type {other.__class__}") return Temporal._factory(result) - def nearest_approach_distance( - self, other: Union[int, float, TNumber, TBox] - ) -> float: + def nearest_approach_distance(self, other: int | float | TNumber | TBox) -> float: """ Returns the nearest approach distance between `self` and `other`. diff --git a/pymeos/main/tpoint.py b/pymeos/main/tpoint.py index 0e52978f..9ae1441b 100644 --- a/pymeos/main/tpoint.py +++ b/pymeos/main/tpoint.py @@ -2,14 +2,8 @@ from abc import ABC from typing import ( - Optional, - List, TYPE_CHECKING, - Set, - Tuple, - Union, TypeVar, - Type, overload, ) @@ -17,16 +11,17 @@ import shapely.geometry.base as shpb from pymeos_cffi import * -from .tbool import TBool -from .tfloat import TFloat, TFloatInst, TFloatSeq, TFloatSeqSet from ..collections import * from ..mixins import TSimplifiable -from ..temporal import Temporal, TInstant, TSequence, TSequenceSet, TInterpolation +from ..temporal import Temporal, TInstant, TInterpolation, TSequence, TSequenceSet +from .tbool import TBool +from .tfloat import TFloat, TFloatInst, TFloatSeq, TFloatSeqSet if TYPE_CHECKING: - from ..boxes import STBox, Box from geopandas import GeoDataFrame + from ..boxes import Box, STBox + def import_geopandas(): try: @@ -58,7 +53,7 @@ def __init__(self, _inner) -> None: super().__init__() @classmethod - def from_hexwkb(cls: Type[Self], hexwkb: str, srid: Optional[int] = None) -> Self: + def from_hexwkb(cls: type[Self], hexwkb: str, srid: int | None = None) -> Self: result = super().from_hexwkb(hexwkb) return result.set_srid(srid) if srid is not None else result @@ -106,7 +101,11 @@ def as_ewkt(self, precision: int = 15) -> str: return tspatial_as_ewkt(self._inner, precision) def as_geojson( - self, unary_union: bool = False, option: int = 1, precision: int = 15, srs: Optional[str] = None + self, + unary_union: bool = False, + option: int = 1, + precision: int = 15, + srs: str | None = None, ) -> str: """ Returns the trajectory of the temporal point as a GeoJSON string. @@ -140,9 +139,7 @@ def to_shapely_geometry(self, precision: int = 15, unary_union: bool = False) -> MEOS Functions: gserialized_to_shapely_geometry, tpoint_trajectory """ - return gserialized_to_shapely_geometry( - tpoint_trajectory(self._inner, unary_union), precision - ) + return gserialized_to_shapely_geometry(tpoint_trajectory(self._inner, unary_union), precision) # ------------------------- Accessors ------------------------------------- def bounding_box(self) -> STBox: @@ -159,7 +156,7 @@ def bounding_box(self) -> STBox: return STBox(_inner=tspatial_to_stbox(self._inner)) - def values(self, precision: int = 15) -> List[shp.Point]: + def values(self, precision: int = 15) -> list[shp.Point]: """ Returns the values of the temporal point. @@ -195,7 +192,7 @@ def end_value(self, precision: int = 15) -> shp.Point: """ return gserialized_to_shapely_point(tgeo_end_value(self._inner), precision) - def value_set(self, precision: int = 15) -> Set[shp.Point]: + def value_set(self, precision: int = 15) -> set[shp.Point]: """ Returns the set of values of `self`. Note that when the interpolation is linear, the set will contain only the waypoints. @@ -207,9 +204,7 @@ def value_set(self, precision: int = 15) -> Set[shp.Point]: tgeo_values """ values, count = tgeo_values(self._inner) - return { - gserialized_to_shapely_point(values[i], precision) for i in range(count) - } + return {gserialized_to_shapely_point(values[i], precision) for i in range(count)} def value_at_timestamp(self, timestamp: datetime, precision: int = 15) -> shp.Point: """ @@ -226,9 +221,7 @@ def value_at_timestamp(self, timestamp: datetime, precision: int = 15) -> shp.Po tgeo_value_at_timestamp """ return gserialized_to_shapely_point( - tgeo_value_at_timestamptz( - self._inner, datetime_to_timestamptz(timestamp), True - )[0], + tgeo_value_at_timestamptz(self._inner, datetime_to_timestamptz(timestamp), True)[0], precision, ) @@ -321,7 +314,7 @@ def has_z(self) -> bool: """ return self.bounding_box().has_z() - def stboxes(self) -> List[STBox]: + def stboxes(self) -> list[STBox]: """ Returns a collection of :class:`STBox`es representing the bounding boxes of the segments of the temporal point. @@ -348,7 +341,7 @@ def is_simple(self) -> bool: """ return tpoint_is_simple(self._inner) - def bearing(self, other: Union[shpb.BaseGeometry, TPoint]) -> TFloat: + def bearing(self, other: shpb.BaseGeometry | TPoint) -> TFloat: """ Returns the temporal bearing between the temporal point and `other`. @@ -458,7 +451,7 @@ def round(self, max_decimals: int = 0) -> TPoint: result = temporal_round(self._inner, max_decimals) return Temporal._factory(result) - def make_simple(self) -> List[TPoint]: + def make_simple(self) -> list[TPoint]: """ Split the temporal point into a collection of simple temporal points. @@ -488,7 +481,7 @@ def transform(self: Self, srid: int) -> Self: return Temporal._factory(result) # ------------------------- Restrictions ---------------------------------- - def at(self, other: Union[shpb.BaseGeometry, GeoSet, STBox, Time]) -> TG: + def at(self, other: shpb.BaseGeometry | GeoSet | STBox | Time) -> TG: """ Returns a new temporal object with the values of `self` restricted to `other`. @@ -518,7 +511,7 @@ def at(self, other: Union[shpb.BaseGeometry, GeoSet, STBox, Time]) -> TG: return super().at(other) return Temporal._factory(result) - def minus(self, other: Union[shpb.BaseGeometry, GeoSet, STBox, Time]) -> TG: + def minus(self, other: shpb.BaseGeometry | GeoSet | STBox | Time) -> TG: """ Returns a new temporal object with the values of `self` restricted to the complement of `other`. @@ -549,7 +542,7 @@ def minus(self, other: Union[shpb.BaseGeometry, GeoSet, STBox, Time]) -> TG: return Temporal._factory(result) # ------------------------- Position Operations --------------------------- - def is_left(self, other: Union[Temporal, Box]) -> bool: + def is_left(self, other: Temporal | Box) -> bool: """ Returns whether the bounding box of `self` is left to the bounding box of `other`. @@ -564,7 +557,7 @@ def is_left(self, other: Union[Temporal, Box]) -> bool: """ return self.bounding_box().is_left(other) - def is_over_or_left(self, other: Union[Temporal, Box]) -> bool: + def is_over_or_left(self, other: Temporal | Box) -> bool: """ Returns whether the bounding box of `self` is over or left to the bounding box of `other`. @@ -579,7 +572,7 @@ def is_over_or_left(self, other: Union[Temporal, Box]) -> bool: """ return self.bounding_box().is_over_or_left(other) - def is_right(self, other: Union[Temporal, Box]) -> bool: + def is_right(self, other: Temporal | Box) -> bool: """ Returns whether the bounding box of `self` is right to the bounding box of `other`. @@ -594,7 +587,7 @@ def is_right(self, other: Union[Temporal, Box]) -> bool: """ return self.bounding_box().is_right(other) - def is_over_or_right(self, other: Union[Temporal, Box]) -> bool: + def is_over_or_right(self, other: Temporal | Box) -> bool: """ Returns whether the bounding box of `self` is over or right to the bounding box of `other`. @@ -609,7 +602,7 @@ def is_over_or_right(self, other: Union[Temporal, Box]) -> bool: """ return self.bounding_box().is_over_or_right(other) - def is_below(self, other: Union[Temporal, Box]) -> bool: + def is_below(self, other: Temporal | Box) -> bool: """ Returns whether the bounding box of `self` is below to the bounding box of `other`. @@ -624,7 +617,7 @@ def is_below(self, other: Union[Temporal, Box]) -> bool: """ return self.bounding_box().is_below(other) - def is_over_or_below(self, other: Union[Temporal, Box]) -> bool: + def is_over_or_below(self, other: Temporal | Box) -> bool: """ Returns whether the bounding box of `self` is over or below to the bounding box of `other`. @@ -639,7 +632,7 @@ def is_over_or_below(self, other: Union[Temporal, Box]) -> bool: """ return self.bounding_box().is_over_or_below(other) - def is_above(self, other: Union[Temporal, Box]) -> bool: + def is_above(self, other: Temporal | Box) -> bool: """ Returns whether the bounding box of `self` is above to the bounding box of `other`. @@ -654,7 +647,7 @@ def is_above(self, other: Union[Temporal, Box]) -> bool: """ return self.bounding_box().is_above(other) - def is_over_or_above(self, other: Union[Temporal, Box]) -> bool: + def is_over_or_above(self, other: Temporal | Box) -> bool: """ Returns whether the bounding box of `self` is over or above to the bounding box of `other`. @@ -669,7 +662,7 @@ def is_over_or_above(self, other: Union[Temporal, Box]) -> bool: """ return self.bounding_box().is_over_or_above(other) - def is_front(self, other: Union[Temporal, Box]) -> bool: + def is_front(self, other: Temporal | Box) -> bool: """ Returns whether the bounding box of `self` is front to the bounding box of `other`. @@ -684,7 +677,7 @@ def is_front(self, other: Union[Temporal, Box]) -> bool: """ return self.bounding_box().is_front(other) - def is_over_or_front(self, other: Union[Temporal, Box]) -> bool: + def is_over_or_front(self, other: Temporal | Box) -> bool: """ Returns whether the bounding box of `self` is over or front to the bounding box of `other`. @@ -699,7 +692,7 @@ def is_over_or_front(self, other: Union[Temporal, Box]) -> bool: """ return self.bounding_box().is_over_or_front(other) - def is_behind(self, other: Union[Temporal, Box]) -> bool: + def is_behind(self, other: Temporal | Box) -> bool: """ Returns whether the bounding box of `self` is behind to the bounding box of `other`. @@ -714,7 +707,7 @@ def is_behind(self, other: Union[Temporal, Box]) -> bool: """ return self.bounding_box().is_behind(other) - def is_over_or_behind(self, other: Union[Temporal, Box]) -> bool: + def is_over_or_behind(self, other: Temporal | Box) -> bool: """ Returns whether the bounding box of `self` is over or behind to the bounding box of `other`. @@ -730,7 +723,7 @@ def is_over_or_behind(self, other: Union[Temporal, Box]) -> bool: return self.bounding_box().is_over_or_behind(other) # ------------------------- Ever Spatial Relationships -------------------- - def is_ever_contained_in(self, container: Union[shpb.BaseGeometry, STBox]) -> bool: + def is_ever_contained_in(self, container: shpb.BaseGeometry | STBox) -> bool: """ Returns whether the temporal point is ever contained by `container`. @@ -754,7 +747,7 @@ def is_ever_contained_in(self, container: Union[shpb.BaseGeometry, STBox]) -> bo raise TypeError(f"Operation not supported with type {container.__class__}") return result == 1 - def is_ever_disjoint(self, other: Union[shpb.BaseGeometry, TPoint]) -> bool: + def is_ever_disjoint(self, other: shpb.BaseGeometry | TPoint) -> bool: """ Returns whether the temporal point is ever disjoint from `other`. @@ -776,9 +769,7 @@ def is_ever_disjoint(self, other: Union[shpb.BaseGeometry, TPoint]) -> bool: raise TypeError(f"Operation not supported with type {other.__class__}") return result == 1 - def is_ever_within_distance( - self, other: Union[shpb.BaseGeometry, TPoint, STBox], distance: float - ) -> bool: + def is_ever_within_distance(self, other: shpb.BaseGeometry | TPoint | STBox, distance: float) -> bool: """ Returns whether the temporal point is ever within `distance` of `other`. @@ -798,16 +789,14 @@ def is_ever_within_distance( gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) result = edwithin_tgeo_geo(self._inner, gs, distance) elif isinstance(other, STBox): - result = edwithin_tgeo_geo( - self._inner, stbox_to_geo(other._inner), distance - ) + result = edwithin_tgeo_geo(self._inner, stbox_to_geo(other._inner), distance) elif isinstance(other, TPoint): result = edwithin_tgeo_tgeo(self._inner, other._inner, distance) else: raise TypeError(f"Operation not supported with type {other.__class__}") return result == 1 - def ever_intersects(self, other: Union[shpb.BaseGeometry, TPoint, STBox]) -> bool: + def ever_intersects(self, other: shpb.BaseGeometry | TPoint | STBox) -> bool: """ Returns whether the temporal point ever intersects `other`. @@ -833,7 +822,7 @@ def ever_intersects(self, other: Union[shpb.BaseGeometry, TPoint, STBox]) -> boo raise TypeError(f"Operation not supported with type {other.__class__}") return result == 1 - def ever_touches(self, other: Union[shpb.BaseGeometry, STBox, TPoint]) -> bool: + def ever_touches(self, other: shpb.BaseGeometry | STBox | TPoint) -> bool: """ Returns whether the temporal point ever touches `other`. @@ -860,9 +849,7 @@ def ever_touches(self, other: Union[shpb.BaseGeometry, STBox, TPoint]) -> bool: return result == 1 # ------------------------- Temporal Spatial Relationships ---------------- - def is_spatially_contained_in( - self, container: Union[shpb.BaseGeometry, STBox] - ) -> TBool: + def is_spatially_contained_in(self, container: shpb.BaseGeometry | STBox) -> TBool: """ Returns a new temporal boolean indicating whether the temporal point is contained by `container`. @@ -888,7 +875,7 @@ def is_spatially_contained_in( return Temporal._factory(result) # ------------------------- Distance Operations --------------------------- - def distance(self, other: Union[shpb.BaseGeometry, TPoint, STBox]) -> TFloat: + def distance(self, other: shpb.BaseGeometry | TPoint | STBox) -> TFloat: """ Returns the temporal distance between the temporal point and `other`. @@ -914,9 +901,7 @@ def distance(self, other: Union[shpb.BaseGeometry, TPoint, STBox]) -> TFloat: raise TypeError(f"Operation not supported with type {other.__class__}") return Temporal._factory(result) - def nearest_approach_distance( - self, other: Union[shpb.BaseGeometry, STBox, TPoint] - ) -> float: + def nearest_approach_distance(self, other: shpb.BaseGeometry | STBox | TPoint) -> float: """ Returns the nearest approach distance between the temporal point and `other`. @@ -941,7 +926,7 @@ def nearest_approach_distance( else: raise TypeError(f"Operation not supported with type {other.__class__}") - def nearest_approach_instant(self, other: Union[shpb.BaseGeometry, TPoint]) -> TI: + def nearest_approach_instant(self, other: shpb.BaseGeometry | TPoint) -> TI: """ Returns the nearest approach instant between the temporal point and `other`. @@ -963,9 +948,7 @@ def nearest_approach_instant(self, other: Union[shpb.BaseGeometry, TPoint]) -> T raise TypeError(f"Operation not supported with type {other.__class__}") return Temporal._factory(result) - def shortest_line( - self, other: Union[shpb.BaseGeometry, TPoint] - ) -> shpb.BaseGeometry: + def shortest_line(self, other: shpb.BaseGeometry | TPoint) -> shpb.BaseGeometry: """ Returns the shortest line between the temporal point and `other`. @@ -992,11 +975,11 @@ def shortest_line( def tile( self, size: float, - duration: Optional[Union[timedelta, str]] = None, - origin: Optional[shpb.BaseGeometry] = None, - start: Union[datetime, str, None] = None, - remove_empty: Optional[bool] = False, - ) -> List[TG]: + duration: timedelta | str | None = None, + origin: shpb.BaseGeometry | None = None, + start: datetime | str | None = None, + remove_empty: bool | None = False, + ) -> list[TG]: """ Split the temporal point into segments following the tiling of the bounding box. @@ -1033,12 +1016,12 @@ def tile( def space_split( self, xsize: float, - ysize: Optional[float] = None, - zsize: Optional[float] = None, - origin: Optional[shpb.BaseGeometry] = None, + ysize: float | None = None, + zsize: float | None = None, + origin: shpb.BaseGeometry | None = None, bitmatrix: bool = False, include_border: bool = True, - ) -> List[Temporal]: + ) -> list[Temporal]: """ Splits `self` into fragments with respect to space buckets @@ -1062,15 +1045,9 @@ def space_split( gs = ( geo_to_gserialized(origin, isinstance(self, TGeogPoint)) if origin is not None - else ( - geog_in("Point(0 0 0)", -1) - if isinstance(self, TGeogPoint) - else geom_in("Point(0 0 0)", -1) - ) - ) - fragments, values, count = tgeo_space_split( - self._inner, xsize, ysz, zsz, gs, bitmatrix, include_border + else (geog_in("Point(0 0 0)", -1) if isinstance(self, TGeogPoint) else geom_in("Point(0 0 0)", -1)) ) + fragments, values, count = tgeo_space_split(self._inner, xsize, ysz, zsz, gs, bitmatrix, include_border) from ..factory import _TemporalFactory return [_TemporalFactory.create_temporal(fragments[i]) for i in range(count)] @@ -1078,14 +1055,14 @@ def space_split( def space_time_split( self, xsize: float, - duration: Union[str, timedelta], - ysize: Optional[float] = None, - zsize: Optional[float] = None, - origin: Optional[shpb.BaseGeometry] = None, - time_start: Optional[Union[str, datetime]] = None, + duration: str | timedelta, + ysize: float | None = None, + zsize: float | None = None, + origin: shpb.BaseGeometry | None = None, + time_start: str | datetime | None = None, bitmatrix: bool = False, include_border: bool = True, - ) -> List[Temporal]: + ) -> list[Temporal]: """ Splits `self` into fragments with respect to space and tstzspan buckets. @@ -1109,19 +1086,11 @@ def space_time_split( """ ysz = ysize if ysize is not None else xsize zsz = zsize if zsize is not None else xsize - dt = ( - timedelta_to_interval(duration) - if isinstance(duration, timedelta) - else pg_interval_in(duration, -1) - ) + dt = timedelta_to_interval(duration) if isinstance(duration, timedelta) else pg_interval_in(duration, -1) gs = ( geo_to_gserialized(origin, isinstance(self, TGeogPoint)) if origin is not None - else ( - geog_in("Point(0 0 0)", -1) - if isinstance(self, TGeogPoint) - else geom_in("Point(0 0 0)", -1) - ) + else (geog_in("Point(0 0 0)", -1) if isinstance(self, TGeogPoint) else geom_in("Point(0 0 0)", -1)) ) if time_start is None: st = pg_timestamptz_in("2000-01-03", -1) @@ -1137,9 +1106,7 @@ def space_time_split( return [Temporal._factory(fragments[i]) for i in range(count)] -class TPointInst( - TInstant[shpb.BaseGeometry, TG, TI, TS, TSS], TPoint[TG, TI, TS, TSS], ABC -): +class TPointInst(TInstant[shpb.BaseGeometry, TG, TI, TS, TSS], TPoint[TG, TI, TS, TSS], ABC): """ Abstract class for temporal point instants. """ @@ -1166,9 +1133,7 @@ def z(self) -> TFloatInst: return super().z() -class TPointSeq( - TSequence[shpb.BaseGeometry, TG, TI, TS, TSS], TPoint[TG, TI, TS, TSS], ABC -): +class TPointSeq(TSequence[shpb.BaseGeometry, TG, TI, TS, TSS], TPoint[TG, TI, TS, TSS], ABC): """ Abstract class for temporal point sequences. """ @@ -1201,9 +1166,7 @@ def plot(self, *args, **kwargs): return TemporalPointSequencePlotter.plot_xy(self, *args, **kwargs) -class TPointSeqSet( - TSequenceSet[shpb.BaseGeometry, TG, TI, TS, TSS], TPoint[TG, TI, TS, TSS], ABC -): +class TPointSeqSet(TSequenceSet[shpb.BaseGeometry, TG, TI, TS, TSS], TPoint[TG, TI, TS, TSS], ABC): """ Abstract class for temporal point sequence sets. """ @@ -1222,19 +1185,11 @@ def to_dataframe(self, precision: int = 15) -> GeoDataFrame: gpd = import_geopandas() sequences = self.sequences() data = { - "sequence": [ - i + 1 - for i, seq in enumerate(sequences) - for _ in range(seq.num_instants()) - ], + "sequence": [i + 1 for i, seq in enumerate(sequences) for _ in range(seq.num_instants())], "time": [t for seq in sequences for t in seq.timestamps()], - "geometry": [ - v for seq in sequences for v in seq.values(precision=precision) - ], + "geometry": [v for seq in sequences for v in seq.values(precision=precision)], } - return gpd.GeoDataFrame(data, crs=self.srid()).set_index( - keys=["sequence", "time"] - ) + return gpd.GeoDataFrame(data, crs=self.srid()).set_index(keys=["sequence", "time"]) def x(self) -> TFloatSeqSet: return super().x() @@ -1264,9 +1219,7 @@ def plot(self, *args, **kwargs): return TemporalPointSequenceSetPlotter.plot_xy(self, *args, **kwargs) -class TGeomPoint( - TPoint["TGeomPoint", "TGeomPointInst", "TGeomPointSeq", "TGeomPointSeqSet"], ABC -): +class TGeomPoint(TPoint["TGeomPoint", "TGeomPointInst", "TGeomPointSeq", "TGeomPointSeqSet"], ABC): """ Abstract class for temporal geometric points. """ @@ -1299,15 +1252,11 @@ def from_base_temporal(value: shpb.BaseGeometry, base: Temporal) -> TGeomPoint: @staticmethod @overload - def from_base_time( - value: shpb.BaseGeometry, base: datetime, interpolation: None = None - ) -> TGeomPointInst: ... + def from_base_time(value: shpb.BaseGeometry, base: datetime, interpolation: None = None) -> TGeomPointInst: ... @staticmethod @overload - def from_base_time( - value: shpb.BaseGeometry, base: TsTzSet, interpolation: None = None - ) -> TGeomPointSeq: ... + def from_base_time(value: shpb.BaseGeometry, base: TsTzSet, interpolation: None = None) -> TGeomPointSeq: ... @staticmethod @overload @@ -1324,9 +1273,7 @@ def from_base_time( ) -> TGeomPointSeqSet: ... @staticmethod - def from_base_time( - value: shpb.BaseGeometry, base: Time, interpolation: TInterpolation = None - ) -> TGeomPoint: + def from_base_time(value: shpb.BaseGeometry, base: Time, interpolation: TInterpolation = None) -> TGeomPoint: """ Creates a temporal geometric point from a base geometry and a time value. @@ -1344,25 +1291,17 @@ def from_base_time( """ gs = geometry_to_gserialized(value) if isinstance(base, datetime): - return TGeomPointInst( - _inner=tpointinst_make(gs, datetime_to_timestamptz(base)) - ) + return TGeomPointInst(_inner=tpointinst_make(gs, datetime_to_timestamptz(base))) elif isinstance(base, TsTzSet): return TGeomPointSeq(_inner=tpointseq_from_base_tstzset(gs, base._inner)) elif isinstance(base, TsTzSpan): - return TGeomPointSeq( - _inner=tpointseq_from_base_tstzspan(gs, base._inner, interpolation) - ) + return TGeomPointSeq(_inner=tpointseq_from_base_tstzspan(gs, base._inner, interpolation)) elif isinstance(base, TsTzSpanSet): - return TGeomPointSeqSet( - _inner=tpointseqset_from_base_tstzspanset( - gs, base._inner, interpolation - ) - ) + return TGeomPointSeqSet(_inner=tpointseqset_from_base_tstzspanset(gs, base._inner, interpolation)) raise TypeError(f"Operation not supported with type {base.__class__}") @classmethod - def from_mfjson(cls: Type[Self], mfjson: str) -> Self: + def from_mfjson(cls: type[Self], mfjson: str) -> Self: """ Returns a temporal object from a MF-JSON string. @@ -1409,7 +1348,7 @@ def to_dataframe(self) -> GeoDataFrame: # --------------------- Temporal Spatial Relationships -------------------- - def disjoint(self, other: Union[shpb.BaseGeometry, STBox, TPoint]) -> TBool: + def disjoint(self, other: shpb.BaseGeometry | STBox | TPoint) -> TBool: """ Returns a new temporal boolean indicating whether the temporal point intersects `other`. @@ -1428,16 +1367,14 @@ def disjoint(self, other: Union[shpb.BaseGeometry, STBox, TPoint]) -> TBool: gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) result = tdisjoint_tgeo_geo(self._inner, gs, False, False) elif isinstance(other, STBox): - result = tdisjoint_tgeo_geo( - self._inner, stbox_to_geo(other._inner), False, False - ) + result = tdisjoint_tgeo_geo(self._inner, stbox_to_geo(other._inner), False, False) elif isinstance(other, TPoint): result = tdisjoint_tgeo_tgeo(self._inner, other._inner, False, False) else: raise TypeError(f"Operation not supported with type {other.__class__}") return Temporal._factory(result) - def intersects(self, other: Union[shpb.BaseGeometry, STBox, TPoint]) -> TBool: + def intersects(self, other: shpb.BaseGeometry | STBox | TPoint) -> TBool: """ Returns a new temporal boolean indicating whether the temporal point intersects `other`. @@ -1456,16 +1393,14 @@ def intersects(self, other: Union[shpb.BaseGeometry, STBox, TPoint]) -> TBool: gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) result = tintersects_tgeo_geo(self._inner, gs, False, False) elif isinstance(other, STBox): - result = tintersects_tgeo_geo( - self._inner, stbox_to_geo(other._inner), False, False - ) + result = tintersects_tgeo_geo(self._inner, stbox_to_geo(other._inner), False, False) elif isinstance(other, TPoint): result = tintersects_tgeo_tgeo(self._inner, other._inner, False, False) else: raise TypeError(f"Operation not supported with type {other.__class__}") return Temporal._factory(result) - def touches(self, other: Union[shpb.BaseGeometry, STBox, TGeomPoint]) -> TBool: + def touches(self, other: shpb.BaseGeometry | STBox | TGeomPoint) -> TBool: """ Returns a new temporal boolean indicating whether the temporal point touches `other`. @@ -1484,18 +1419,14 @@ def touches(self, other: Union[shpb.BaseGeometry, STBox, TGeomPoint]) -> TBool: gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) result = ttouches_tgeo_geo(self._inner, gs, False, False) elif isinstance(other, STBox): - result = ttouches_tgeo_geo( - self._inner, stbox_to_geo(other._inner), False, False - ) + result = ttouches_tgeo_geo(self._inner, stbox_to_geo(other._inner), False, False) elif isinstance(other, TGeomPoint): result = ttouches_tgeo_tgeo(self._inner, other._inner, False, False) else: raise TypeError(f"Operation not supported with type {other.__class__}") return Temporal._factory(result) - def within_distance( - self, other: Union[shpb.BaseGeometry, TGeomPoint, STBox], distance: float - ) -> TBool: + def within_distance(self, other: shpb.BaseGeometry | TGeomPoint | STBox, distance: float) -> TBool: """ Returns a new temporal boolean indicating whether the temporal point is within `distance` of `other`. @@ -1515,19 +1446,15 @@ def within_distance( gs = geo_to_gserialized(other, isinstance(self, TGeogPoint)) result = tdwithin_tgeo_geo(self._inner, gs, distance, False, False) elif isinstance(other, STBox): - result = tdwithin_tgeo_geo( - self._inner, stbox_to_geo(other._inner), distance, False, False - ) + result = tdwithin_tgeo_geo(self._inner, stbox_to_geo(other._inner), distance, False, False) elif isinstance(other, TGeomPoint): - result = tdwithin_tgeo_tgeo( - self._inner, other._inner, distance, False, False - ) + result = tdwithin_tgeo_tgeo(self._inner, other._inner, distance, False, False) else: raise TypeError(f"Operation not supported with type {other.__class__}") return Temporal._factory(result) # ------------------------- Ever and Always Comparisons ------------------- - def always_equal(self, value: Union[shpb.BaseGeometry, TGeomPoint]) -> bool: + def always_equal(self, value: shpb.BaseGeometry | TGeomPoint) -> bool: """ Returns whether `self` is always equal to `value`. @@ -1548,7 +1475,7 @@ def always_equal(self, value: Union[shpb.BaseGeometry, TGeomPoint]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def always_not_equal(self, value: Union[shpb.BaseGeometry, TGeomPoint]) -> bool: + def always_not_equal(self, value: shpb.BaseGeometry | TGeomPoint) -> bool: """ Returns whether `self` is always different to `value`. @@ -1569,7 +1496,7 @@ def always_not_equal(self, value: Union[shpb.BaseGeometry, TGeomPoint]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def ever_equal(self, value: Union[shpb.BaseGeometry, TGeomPoint]) -> bool: + def ever_equal(self, value: shpb.BaseGeometry | TGeomPoint) -> bool: """ Returns whether `self` is ever equal to `value`. @@ -1590,7 +1517,7 @@ def ever_equal(self, value: Union[shpb.BaseGeometry, TGeomPoint]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def ever_not_equal(self, value: Union[shpb.BaseGeometry, TGeomPoint]) -> bool: + def ever_not_equal(self, value: shpb.BaseGeometry | TGeomPoint) -> bool: """ Returns whether `self` is ever different to `value`. @@ -1611,7 +1538,7 @@ def ever_not_equal(self, value: Union[shpb.BaseGeometry, TGeomPoint]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def never_equal(self, value: Union[shpb.BaseGeometry, TGeomPoint]) -> bool: + def never_equal(self, value: shpb.BaseGeometry | TGeomPoint) -> bool: """ Returns whether `self` is never equal to `value`. @@ -1626,7 +1553,7 @@ def never_equal(self, value: Union[shpb.BaseGeometry, TGeomPoint]) -> bool: """ return not self.ever_equal(value) - def never_not_equal(self, value: Union[shpb.BaseGeometry, TGeomPoint]) -> bool: + def never_not_equal(self, value: shpb.BaseGeometry | TGeomPoint) -> bool: """ Returns whether `self` is never different to `value`. @@ -1641,9 +1568,7 @@ def never_not_equal(self, value: Union[shpb.BaseGeometry, TGeomPoint]) -> bool: """ return not self.ever_not_equal(value) - def is_ever_disjoint( - self, other: Union[shpb.BaseGeometry, TGeomPoint, STBox] - ) -> bool: + def is_ever_disjoint(self, other: shpb.BaseGeometry | TGeomPoint | STBox) -> bool: """ Returns whether the temporal point is ever disjoint from `other`. @@ -1670,7 +1595,7 @@ def is_ever_disjoint( return result == 1 # ------------------------- Temporal Comparisons -------------------------- - def temporal_equal(self, other: Union[shp.Point, TGeomPoint]) -> TBool: + def temporal_equal(self, other: shp.Point | TGeomPoint) -> TBool: """ Returns the temporal equality relation between `self` and `other`. @@ -1690,7 +1615,7 @@ def temporal_equal(self, other: Union[shp.Point, TGeomPoint]) -> TBool: return super().temporal_equal(other) return Temporal._factory(result) - def temporal_not_equal(self, other: Union[shp.Point, TGeomPoint]) -> TBool: + def temporal_not_equal(self, other: shp.Point | TGeomPoint) -> TBool: """ Returns the temporal inequality relation between `self` and `other`. @@ -1738,9 +1663,7 @@ def read_from_cursor(value, _=None): raise Exception("ERROR: Could not parse temporal point value") -class TGeogPoint( - TPoint["TGeogPoint", "TGeogPointInst", "TGeogPointSeq", "TGeogPointSeqSet"], ABC -): +class TGeogPoint(TPoint["TGeogPoint", "TGeogPointInst", "TGeogPointSeq", "TGeogPointSeqSet"], ABC): """ Abstract class for representing temporal geographic points. """ @@ -1798,9 +1721,7 @@ def from_base_time( ) -> TGeogPointSeqSet: ... @staticmethod - def from_base_time( - value: shpb.BaseGeometry, base: Time, interpolation: TInterpolation = None - ) -> TGeogPoint: + def from_base_time(value: shpb.BaseGeometry, base: Time, interpolation: TInterpolation = None) -> TGeogPoint: """ Creates a temporal geographic point from a base geometry and a time object. @@ -1818,25 +1739,17 @@ def from_base_time( """ gs = geography_to_gserialized(value) if isinstance(base, datetime): - return TGeogPointInst( - _inner=tpointinst_make(gs, datetime_to_timestamptz(base)) - ) + return TGeogPointInst(_inner=tpointinst_make(gs, datetime_to_timestamptz(base))) elif isinstance(base, TsTzSet): return TGeogPointSeq(_inner=tpointseq_from_base_tstzset(gs, base._inner)) elif isinstance(base, TsTzSpan): - return TGeogPointSeq( - _inner=tpointseq_from_base_tstzspan(gs, base._inner, interpolation) - ) + return TGeogPointSeq(_inner=tpointseq_from_base_tstzspan(gs, base._inner, interpolation)) elif isinstance(base, TsTzSpanSet): - return TGeogPointSeqSet( - _inner=tpointseqset_from_base_tstzspanset( - gs, base._inner, interpolation - ) - ) + return TGeogPointSeqSet(_inner=tpointseqset_from_base_tstzspanset(gs, base._inner, interpolation)) raise TypeError(f"Operation not supported with type {base.__class__}") @classmethod - def from_mfjson(cls: Type[Self], mfjson: str) -> Self: + def from_mfjson(cls: type[Self], mfjson: str) -> Self: """ Returns a temporal object from a MF-JSON string. @@ -1868,7 +1781,7 @@ def to_geometric(self) -> TGeomPoint: return Temporal._factory(result) # ------------------------- Ever and Always Comparisons ------------------- - def always_equal(self, value: Union[shpb.BaseGeometry, TGeogPoint]) -> bool: + def always_equal(self, value: shpb.BaseGeometry | TGeogPoint) -> bool: """ Returns whether `self` is always equal to `value`. @@ -1889,7 +1802,7 @@ def always_equal(self, value: Union[shpb.BaseGeometry, TGeogPoint]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def always_not_equal(self, value: Union[shpb.BaseGeometry, TGeogPoint]) -> bool: + def always_not_equal(self, value: shpb.BaseGeometry | TGeogPoint) -> bool: """ Returns whether `self` is always different to `value`. @@ -1910,7 +1823,7 @@ def always_not_equal(self, value: Union[shpb.BaseGeometry, TGeogPoint]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def ever_equal(self, value: Union[shpb.BaseGeometry, TGeogPoint]) -> bool: + def ever_equal(self, value: shpb.BaseGeometry | TGeogPoint) -> bool: """ Returns whether `self` is ever equal to `value`. @@ -1931,7 +1844,7 @@ def ever_equal(self, value: Union[shpb.BaseGeometry, TGeogPoint]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def ever_not_equal(self, value: Union[shpb.BaseGeometry, TGeogPoint]) -> bool: + def ever_not_equal(self, value: shpb.BaseGeometry | TGeogPoint) -> bool: """ Returns whether `self` is ever different to `value`. @@ -1952,7 +1865,7 @@ def ever_not_equal(self, value: Union[shpb.BaseGeometry, TGeogPoint]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def never_equal(self, value: Union[shpb.BaseGeometry, TGeogPoint]) -> bool: + def never_equal(self, value: shpb.BaseGeometry | TGeogPoint) -> bool: """ Returns whether `self` is never equal to `value`. @@ -1967,7 +1880,7 @@ def never_equal(self, value: Union[shpb.BaseGeometry, TGeogPoint]) -> bool: """ return not self.ever_equal(value) - def never_not_equal(self, value: Union[shpb.BaseGeometry, TGeogPoint]) -> bool: + def never_not_equal(self, value: shpb.BaseGeometry | TGeogPoint) -> bool: """ Returns whether `self` is never different to `value`. @@ -1983,7 +1896,7 @@ def never_not_equal(self, value: Union[shpb.BaseGeometry, TGeogPoint]) -> bool: return not self.ever_not_equal(value) # ------------------------- Temporal Comparisons -------------------------- - def temporal_equal(self, other: Union[shp.Point, TGeogPoint]) -> TBool: + def temporal_equal(self, other: shp.Point | TGeogPoint) -> TBool: """ Returns the temporal equality relation between `self` and `other`. @@ -2003,7 +1916,7 @@ def temporal_equal(self, other: Union[shp.Point, TGeogPoint]) -> TBool: return super().temporal_equal(other) return Temporal._factory(result) - def temporal_not_equal(self, other: Union[shp.Point, TGeogPoint]) -> TBool: + def temporal_not_equal(self, other: shp.Point | TGeogPoint) -> TBool: """ Returns the temporal inequality relation between `self` and `other`. @@ -2064,26 +1977,20 @@ class TGeomPointInst( def __init__( self, - string: Optional[str] = None, + string: str | None = None, *, - point: Optional[ - Union[str, shp.Point, Tuple[float, float], Tuple[float, float, float]] - ] = None, - timestamp: Optional[Union[str, datetime]] = None, - srid: Optional[int] = 0, + point: str | shp.Point | tuple[float, float] | tuple[float, float, float] | None = None, + timestamp: str | datetime | None = None, + srid: int | None = 0, _inner=None, ) -> None: super().__init__(string=string, value=point, timestamp=timestamp, _inner=_inner) if self._inner is None: if isinstance(point, tuple): - p = f'POINT({" ".join(str(x) for x in point)})' + p = f"POINT({' '.join(str(x) for x in point)})" else: p = f"{point}" - full_str = ( - f"SRID={srid};{p}@{timestamp}" - if srid is not None - else f"{p}@{timestamp}" - ) + full_str = f"SRID={srid};{p}@{timestamp}" if srid is not None else f"{p}@{timestamp}" self._inner = tgeompoint_in(full_str) @@ -2100,26 +2007,20 @@ class TGeogPointInst( def __init__( self, - string: Optional[str] = None, + string: str | None = None, *, - point: Optional[ - Union[str, shp.Point, Tuple[float, float], Tuple[float, float, float]] - ] = None, - timestamp: Optional[Union[str, datetime]] = None, - srid: Optional[int] = 4326, + point: str | shp.Point | tuple[float, float] | tuple[float, float, float] | None = None, + timestamp: str | datetime | None = None, + srid: int | None = 4326, _inner=None, ) -> None: super().__init__(string=string, value=point, timestamp=timestamp, _inner=_inner) if self._inner is None: if isinstance(point, tuple): - p = f'POINT({" ".join(str(x) for x in point)})' + p = f"POINT({' '.join(str(x) for x in point)})" else: p = f"{point}" - full_str = ( - f"SRID={srid};{p}@{timestamp}" - if srid is not None - else f"{p}@{timestamp}" - ) + full_str = f"SRID={srid};{p}@{timestamp}" if srid is not None else f"{p}@{timestamp}" self._inner = tgeogpoint_in(full_str) @@ -2135,9 +2036,9 @@ class TGeomPointSeq( def __init__( self, - string: Optional[str] = None, + string: str | None = None, *, - instant_list: Optional[List[Union[str, TGeomPointInst]]] = None, + instant_list: list[str | TGeomPointInst] | None = None, lower_inc: bool = True, upper_inc: bool = False, interpolation: TInterpolation = TInterpolation.LINEAR, @@ -2167,9 +2068,9 @@ class TGeogPointSeq( def __init__( self, - string: Optional[str] = None, + string: str | None = None, *, - instant_list: Optional[List[Union[str, TGeogPointInst]]] = None, + instant_list: list[str | TGeogPointInst] | None = None, lower_inc: bool = True, upper_inc: bool = False, interpolation: TInterpolation = TInterpolation.LINEAR, @@ -2200,9 +2101,9 @@ class TGeomPointSeqSet( def __init__( self, - string: Optional[str] = None, + string: str | None = None, *, - sequence_list: Optional[List[Union[str, TGeomPointSeq]]] = None, + sequence_list: list[str | TGeomPointSeq] | None = None, normalize: bool = True, _inner=None, ): @@ -2227,9 +2128,9 @@ class TGeogPointSeqSet( def __init__( self, - string: Optional[str] = None, + string: str | None = None, *, - sequence_list: Optional[List[Union[str, TGeogPointSeq]]] = None, + sequence_list: list[str | TGeogPointSeq] | None = None, normalize: bool = True, _inner=None, ): diff --git a/pymeos/main/ttext.py b/pymeos/main/ttext.py index d0450abd..e956e732 100644 --- a/pymeos/main/ttext.py +++ b/pymeos/main/ttext.py @@ -1,13 +1,13 @@ from __future__ import annotations from abc import ABC -from typing import Optional, Union, List, Set, overload, TYPE_CHECKING, TypeVar, Type +from typing import TYPE_CHECKING, TypeVar, overload from pymeos_cffi import * from ..collections import * from ..mixins import TTemporallyComparable -from ..temporal import TInterpolation, Temporal, TInstant, TSequence, TSequenceSet +from ..temporal import Temporal, TInstant, TInterpolation, TSequence, TSequenceSet if TYPE_CHECKING: from .tbool import TBool @@ -56,7 +56,7 @@ def from_base_time(value: str, base: datetime) -> TTextInst: ... @staticmethod @overload - def from_base_time(value: str, base: Union[TsTzSet, TsTzSpan]) -> TTextSeq: ... + def from_base_time(value: str, base: TsTzSet | TsTzSpan) -> TTextSeq: ... @staticmethod @overload @@ -79,21 +79,17 @@ def from_base_time(value: str, base: Time) -> TText: ttextseq_from_base_tstzspan, ttextseqset_from_base_tstzspanset """ if isinstance(base, datetime): - return TTextInst( - _inner=ttextinst_make(value, datetime_to_timestamptz(base)) - ) + return TTextInst(_inner=ttextinst_make(value, datetime_to_timestamptz(base))) elif isinstance(base, TsTzSet): return TTextSeq(_inner=ttextseq_from_base_tstzset(value, base._inner)) elif isinstance(base, TsTzSpan): return TTextSeq(_inner=ttextseq_from_base_tstzspan(value, base._inner)) elif isinstance(base, TsTzSpanSet): - return TTextSeqSet( - _inner=ttextseqset_from_base_tstzspanset(value, base._inner) - ) + return TTextSeqSet(_inner=ttextseqset_from_base_tstzspanset(value, base._inner)) raise TypeError(f"Operation not supported with type {base.__class__}") @classmethod - def from_mfjson(cls: Type[Self], mfjson: str) -> Self: + def from_mfjson(cls: type[Self], mfjson: str) -> Self: """ Returns a temporal object from a MF-JSON string. @@ -136,7 +132,7 @@ def as_wkt(self) -> str: return ttext_out(self._inner) # ------------------------- Accessors ------------------------------------- - def value_set(self) -> Set[str]: + def value_set(self) -> set[str]: """ Returns the set of unique values of the temporal string. @@ -236,13 +232,11 @@ def value_at_timestamp(self, timestamp: datetime) -> str: MEOS Functions: ttext_value_at_timestamp """ - result = ttext_value_at_timestamptz( - self._inner, datetime_to_timestamptz(timestamp), True - ) + result = ttext_value_at_timestamptz(self._inner, datetime_to_timestamptz(timestamp), True) return text2cstring(result[0]) # ------------------------- Ever and Always Comparisons ------------------- - def always_less(self, value: Union[str, TText]) -> bool: + def always_less(self, value: str | TText) -> bool: """ Returns whether the values of `self` are always less than `value`. @@ -263,7 +257,7 @@ def always_less(self, value: Union[str, TText]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def always_less_or_equal(self, value: Union[str, TText]) -> bool: + def always_less_or_equal(self, value: str | TText) -> bool: """ Returns whether the values of `self` are always less than or equal to `value`. @@ -285,7 +279,7 @@ def always_less_or_equal(self, value: Union[str, TText]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def always_equal(self, value: Union[str, TText]) -> bool: + def always_equal(self, value: str | TText) -> bool: """ Returns whether the values of `self` are always equal to `value`. @@ -306,7 +300,7 @@ def always_equal(self, value: Union[str, TText]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def always_not_equal(self, value: Union[str, TText]) -> bool: + def always_not_equal(self, value: str | TText) -> bool: """ Returns whether the values of `self` are always not equal to `value`. @@ -327,7 +321,7 @@ def always_not_equal(self, value: Union[str, TText]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def always_greater_or_equal(self, value: Union[str, TText]) -> bool: + def always_greater_or_equal(self, value: str | TText) -> bool: """ Returns whether the values of `self` are always greater than or equal to `value`. @@ -349,7 +343,7 @@ def always_greater_or_equal(self, value: Union[str, TText]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def always_greater(self, value: Union[str, TText]) -> bool: + def always_greater(self, value: str | TText) -> bool: """ Returns whether the values of `self` are always greater than `value`. @@ -370,7 +364,7 @@ def always_greater(self, value: Union[str, TText]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def ever_less(self, value: Union[str, TText]) -> bool: + def ever_less(self, value: str | TText) -> bool: """ Returns whether the values of `self` are ever less than `value`. @@ -391,7 +385,7 @@ def ever_less(self, value: Union[str, TText]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def ever_less_or_equal(self, value: Union[str, TText]) -> bool: + def ever_less_or_equal(self, value: str | TText) -> bool: """ Returns whether the values of `self` are ever less than or equal to `value`. @@ -413,7 +407,7 @@ def ever_less_or_equal(self, value: Union[str, TText]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def ever_equal(self, value: Union[str, TText]) -> bool: + def ever_equal(self, value: str | TText) -> bool: """ Returns whether the values of `self` are ever equal to `value`. @@ -434,7 +428,7 @@ def ever_equal(self, value: Union[str, TText]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def ever_not_equal(self, value: Union[str, TText]) -> bool: + def ever_not_equal(self, value: str | TText) -> bool: """ Returns whether the values of `self` are ever not equal to `value`. @@ -455,7 +449,7 @@ def ever_not_equal(self, value: Union[str, TText]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def ever_greater_or_equal(self, value: Union[str, TText]) -> bool: + def ever_greater_or_equal(self, value: str | TText) -> bool: """ Returns whether the values of `self` are ever greater than or equal to `value`. @@ -477,7 +471,7 @@ def ever_greater_or_equal(self, value: Union[str, TText]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def ever_greater(self, value: Union[str, TText]) -> bool: + def ever_greater(self, value: str | TText) -> bool: """ Returns whether the values of `self` are ever greater than `value`. @@ -498,7 +492,7 @@ def ever_greater(self, value: Union[str, TText]) -> bool: else: raise TypeError(f"Operation not supported with type {value.__class__}") - def never_less(self, value: Union[str, TText]) -> bool: + def never_less(self, value: str | TText) -> bool: """ Returns whether the values of `self` are never less than `value`. @@ -514,7 +508,7 @@ def never_less(self, value: Union[str, TText]) -> bool: """ return not self.ever_less(value) - def never_less_or_equal(self, value: Union[str, TText]) -> bool: + def never_less_or_equal(self, value: str | TText) -> bool: """ Returns whether the values of `self` are never less than or equal to `value`. @@ -531,7 +525,7 @@ def never_less_or_equal(self, value: Union[str, TText]) -> bool: """ return not self.ever_less_or_equal(value) - def never_equal(self, value: Union[str, TText]) -> bool: + def never_equal(self, value: str | TText) -> bool: """ Returns whether the values of `self` are never equal to `value`. @@ -547,7 +541,7 @@ def never_equal(self, value: Union[str, TText]) -> bool: """ return not self.ever_equal(value) - def never_not_equal(self, value: Union[str, TText]) -> bool: + def never_not_equal(self, value: str | TText) -> bool: """ Returns whether the values of `self` are never not equal to `value`. @@ -563,7 +557,7 @@ def never_not_equal(self, value: Union[str, TText]) -> bool: """ return not self.ever_not_equal(value) - def never_greater_or_equal(self, value: Union[str, TText]) -> bool: + def never_greater_or_equal(self, value: str | TText) -> bool: """ Returns whether the values of `self` are never greater than or equal to `value`. @@ -580,7 +574,7 @@ def never_greater_or_equal(self, value: Union[str, TText]) -> bool: """ return not self.ever_greater_or_equal(value) - def never_greater(self, value: Union[str, TText]) -> bool: + def never_greater(self, value: str | TText) -> bool: """ Returns whether the values of `self` are never greater than `value`. @@ -597,7 +591,7 @@ def never_greater(self, value: Union[str, TText]) -> bool: return not self.ever_greater(value) # ------------------------- Temporal Comparisons -------------------------- - def temporal_equal(self, other: Union[str, TText]) -> TBool: + def temporal_equal(self, other: str | TText) -> TBool: """ Returns the temporal equality relation between `self` and `other`. @@ -616,7 +610,7 @@ def temporal_equal(self, other: Union[str, TText]) -> TBool: return super().temporal_equal(other) return Temporal._factory(result) - def temporal_not_equal(self, other: Union[str, TText]) -> TBool: + def temporal_not_equal(self, other: str | TText) -> TBool: """ Returns the temporal not equal relation between `self` and `other`. @@ -635,7 +629,7 @@ def temporal_not_equal(self, other: Union[str, TText]) -> TBool: return super().temporal_not_equal(other) return Temporal._factory(result) - def temporal_less(self, other: Union[str, TText]) -> TBool: + def temporal_less(self, other: str | TText) -> TBool: """ Returns the temporal less than relation between `self` and `other`. @@ -654,7 +648,7 @@ def temporal_less(self, other: Union[str, TText]) -> TBool: return super().temporal_less(other) return Temporal._factory(result) - def temporal_less_or_equal(self, other: Union[str, TText]) -> TBool: + def temporal_less_or_equal(self, other: str | TText) -> TBool: """ Returns the temporal less or equal relation between `self` and `other`. @@ -674,7 +668,7 @@ def temporal_less_or_equal(self, other: Union[str, TText]) -> TBool: return super().temporal_less_or_equal(other) return Temporal._factory(result) - def temporal_greater(self, other: Union[str, TText]) -> TBool: + def temporal_greater(self, other: str | TText) -> TBool: """ Returns the temporal greater than relation between `self` and `other`. @@ -694,7 +688,7 @@ def temporal_greater(self, other: Union[str, TText]) -> TBool: return super().temporal_greater(other) return Temporal._factory(result) - def temporal_greater_or_equal(self, other: Union[str, TText]) -> TBool: + def temporal_greater_or_equal(self, other: str | TText) -> TBool: """ Returns the temporal greater or equal relation between `self` and `other`. @@ -716,9 +710,7 @@ def temporal_greater_or_equal(self, other: Union[str, TText]) -> TBool: return Temporal._factory(result) # ------------------------- Restrictions ---------------------------------- - def at( - self, other: Union[str, List[str], datetime, TsTzSet, TsTzSpan, TsTzSpanSet] - ) -> TText: + def at(self, other: str | list[str] | datetime | TsTzSet | TsTzSpan | TsTzSpanSet) -> TText: """ Returns a new temporal string with the values of `self` restricted to the time or value `other`. @@ -741,9 +733,7 @@ def at( return super().at(other) return Temporal._factory(result) - def minus( - self, other: Union[str, List[str], datetime, TsTzSet, TsTzSpan, TsTzSpanSet] - ) -> TText: + def minus(self, other: str | list[str] | datetime | TsTzSet | TsTzSpan | TsTzSpanSet) -> TText: """ Returns a new temporal string with the values of `self` restricted to the complement of the time or value `other`. @@ -768,7 +758,7 @@ def minus( return Temporal._factory(result) # ------------------------- Text Operations ------------------------------ - def concatenate(self, other: Union[str, TText], other_before: bool = False): + def concatenate(self, other: str | TText, other_before: bool = False): """ Returns a new temporal string with the values of `self` concatenated with the values of `other`. @@ -787,9 +777,7 @@ def concatenate(self, other: Union[str, TText], other_before: bool = False): """ if isinstance(other, str): result = ( - textcat_ttext_text(self._inner, other) - if not other_before - else textcat_text_ttext(other, self._inner) + textcat_ttext_text(self._inner, other) if not other_before else textcat_text_ttext(other, self._inner) ) elif isinstance(other, TText): result = ( @@ -865,10 +853,10 @@ class TTextInst(TInstant[str, "TText", "TTextInst", "TTextSeq", "TTextSeqSet"], def __init__( self, - string: Optional[str] = None, + string: str | None = None, *, - value: Optional[str] = None, - timestamp: Optional[Union[str, datetime]] = None, + value: str | None = None, + timestamp: str | datetime | None = None, _inner=None, ): super().__init__(string=string, value=value, timestamp=timestamp, _inner=_inner) @@ -883,9 +871,9 @@ class TTextSeq(TSequence[str, "TText", "TTextInst", "TTextSeq", "TTextSeqSet"], def __init__( self, - string: Optional[str] = None, + string: str | None = None, *, - instant_list: Optional[List[Union[str, TTextInst]]] = None, + instant_list: list[str | TTextInst] | None = None, lower_inc: bool = True, upper_inc: bool = False, interpolation: TInterpolation = TInterpolation.STEPWISE, @@ -903,9 +891,7 @@ def __init__( ) -class TTextSeqSet( - TSequenceSet[str, "TText", "TTextInst", "TTextSeq", "TTextSeqSet"], TText -): +class TTextSeqSet(TSequenceSet[str, "TText", "TTextInst", "TTextSeq", "TTextSeqSet"], TText): """ Class for representing temporal strings over a tstzspan of time with gaps. """ @@ -914,9 +900,9 @@ class TTextSeqSet( def __init__( self, - string: Optional[str] = None, + string: str | None = None, *, - sequence_list: Optional[List[Union[str, TTextSeq]]] = None, + sequence_list: list[str | TTextSeq] | None = None, normalize: bool = True, _inner=None, ): diff --git a/pymeos/meos_init.py b/pymeos/meos_init.py index f02ed68f..d2884852 100644 --- a/pymeos/meos_init.py +++ b/pymeos/meos_init.py @@ -1,17 +1,17 @@ -from typing import Optional, Union, Tuple, Any +from typing import Any from pymeos_cffi import ( - meos_initialize, meos_finalize, + meos_initialize, meos_set_datestyle, meos_set_intervalstyle, ) def pymeos_initialize( - timezone: Optional[str] = None, - date_style: Union[None, str, Tuple[str, Any]] = None, - interval_style: Union[None, str, Tuple[str, int]] = None, + timezone: str | None = None, + date_style: None | str | tuple[str, Any] = None, + interval_style: None | str | tuple[str, int] = None, ) -> None: """ Initializes the underlying MEOS platform. diff --git a/pymeos/mixins/__init__.py b/pymeos/mixins/__init__.py index 0d9da5d6..cf55cde0 100644 --- a/pymeos/mixins/__init__.py +++ b/pymeos/mixins/__init__.py @@ -1,3 +1,10 @@ -from .simplify import TSimplifiable from .comparison import TComparable -from .temporal_comparison import TTemporallyEquatable, TTemporallyComparable +from .simplify import TSimplifiable +from .temporal_comparison import TTemporallyComparable, TTemporallyEquatable + +__all__ = [ + "TComparable", + "TSimplifiable", + "TTemporallyComparable", + "TTemporallyEquatable", +] diff --git a/pymeos/mixins/comparison.py b/pymeos/mixins/comparison.py index 5e82a57c..d2c1d5bd 100644 --- a/pymeos/mixins/comparison.py +++ b/pymeos/mixins/comparison.py @@ -1,14 +1,16 @@ -from typing import TypeVar +from typing import Any, TypeVar from pymeos_cffi import ( temporal_eq, - temporal_ne, - temporal_lt, - temporal_le, - temporal_gt, temporal_ge, + temporal_gt, + temporal_le, + temporal_lt, + temporal_ne, ) +from ..temporal import Temporal + Self = TypeVar("Self", bound="Temporal[Any]") diff --git a/pymeos/mixins/simplify.py b/pymeos/mixins/simplify.py index 711c24c5..1993e0f6 100644 --- a/pymeos/mixins/simplify.py +++ b/pymeos/mixins/simplify.py @@ -1,14 +1,16 @@ from datetime import timedelta -from typing import TypeVar +from typing import Any, TypeVar from pymeos_cffi import ( + temporal_simplify_dp, + temporal_simplify_max_dist, temporal_simplify_min_dist, temporal_simplify_min_tdelta, timedelta_to_interval, - temporal_simplify_dp, - temporal_simplify_max_dist, ) +from ..temporal import Temporal + Self = TypeVar("Self", bound="Temporal[Any]") @@ -46,9 +48,7 @@ def simplify_min_tdelta(self: Self, distance: timedelta) -> Self: delta = timedelta_to_interval(distance) return self.__class__(_inner=temporal_simplify_min_tdelta(self._inner, delta)) - def simplify_douglas_peucker( - self: Self, distance: float, synchronized: bool = False - ) -> Self: + def simplify_douglas_peucker(self: Self, distance: float, synchronized: bool = False) -> Self: """ Simplifies a temporal value using the Douglas-Peucker line simplification algorithm. @@ -64,13 +64,9 @@ def simplify_douglas_peucker( MEOS Functions: temporal_simplify_dp """ - return self.__class__( - _inner=temporal_simplify_dp(self._inner, distance, synchronized) - ) + return self.__class__(_inner=temporal_simplify_dp(self._inner, distance, synchronized)) - def simplify_max_distance( - self: Self, distance: float, synchronized: bool = False - ) -> Self: + def simplify_max_distance(self: Self, distance: float, synchronized: bool = False) -> Self: """ Simplifies a temporal value using a single-pass Douglas-Peucker line simplification algorithm. @@ -86,6 +82,4 @@ def simplify_max_distance( MEOS Functions: temporal_simplify_max_dist """ - return self.__class__( - _inner=temporal_simplify_max_dist(self._inner, distance, synchronized) - ) + return self.__class__(_inner=temporal_simplify_max_dist(self._inner, distance, synchronized)) diff --git a/pymeos/mixins/temporal_comparison.py b/pymeos/mixins/temporal_comparison.py index 2c8c8397..2594d54d 100644 --- a/pymeos/mixins/temporal_comparison.py +++ b/pymeos/mixins/temporal_comparison.py @@ -1,14 +1,14 @@ from __future__ import annotations -from typing import TypeVar, TYPE_CHECKING +from typing import TYPE_CHECKING, Any, TypeVar from pymeos_cffi import ( teq_temporal_temporal, - tne_temporal_temporal, - tlt_temporal_temporal, - tle_temporal_temporal, - tgt_temporal_temporal, tge_temporal_temporal, + tgt_temporal_temporal, + tle_temporal_temporal, + tlt_temporal_temporal, + tne_temporal_temporal, ) Self = TypeVar("Self", bound="Temporal[Any]") diff --git a/pymeos/plotters/__init__.py b/pymeos/plotters/__init__.py index 358bfa6e..f7a50141 100644 --- a/pymeos/plotters/__init__.py +++ b/pymeos/plotters/__init__.py @@ -5,3 +5,13 @@ from .sequence_plotter import TemporalSequencePlotter from .sequenceset_plotter import TemporalSequenceSetPlotter from .time_plotter import TimePlotter + +__all__ = [ + "BoxPlotter", + "TemporalPointSequencePlotter", + "TemporalPointSequenceSetPlotter", + "SpanPlotter", + "TemporalSequencePlotter", + "TemporalSequenceSetPlotter", + "TimePlotter", +] diff --git a/pymeos/plotters/box_plotter.py b/pymeos/plotters/box_plotter.py index 009e0e00..e26bd3d4 100644 --- a/pymeos/plotters/box_plotter.py +++ b/pymeos/plotters/box_plotter.py @@ -1,8 +1,8 @@ from matplotlib import pyplot as plt +from ..boxes import STBox, TBox from .range_plotter import SpanPlotter from .time_plotter import TimePlotter -from ..boxes import TBox, STBox class BoxPlotter: @@ -28,13 +28,9 @@ def plot_tbox(tbox: TBox, *args, axes=None, **kwargs): :func:`~pymeos.plotters.time_plotter.TimePlotter.plot_tstzspan` """ if not tbox.has_t: - return SpanPlotter.plot_span( - tbox.to_floatspan(), *args, axes=axes, **kwargs - ) + return SpanPlotter.plot_span(tbox.to_floatspan(), *args, axes=axes, **kwargs) if not tbox.has_x: - return TimePlotter.plot_tstzspan( - tbox.to_tstzspan(), *args, axes=axes, **kwargs - ) + return TimePlotter.plot_tstzspan(tbox.to_tstzspan(), *args, axes=axes, **kwargs) return BoxPlotter._plot_box( tbox.tmin(), tbox.tmax(), @@ -161,9 +157,7 @@ def _plot_box( return_array = [plot] if draw_filling: - f = base.fill_between( - [xmin, xmax], [ymax, ymax], [ymin, ymin], *args, alpha=0.3, **kwargs - ) + f = base.fill_between([xmin, xmax], [ymax, ymax], [ymin, ymin], *args, alpha=0.3, **kwargs) return_array.append(f) if rotate_xticks: diff --git a/pymeos/plotters/point_sequence_plotter.py b/pymeos/plotters/point_sequence_plotter.py index 626577cd..483b6aba 100644 --- a/pymeos/plotters/point_sequence_plotter.py +++ b/pymeos/plotters/point_sequence_plotter.py @@ -1,8 +1,6 @@ -from typing import Union, List - import matplotlib.pyplot as plt -from ..main import TPointSeq, TPointInst +from ..main import TPointInst, TPointSeq from ..temporal import TInterpolation @@ -13,7 +11,7 @@ class TemporalPointSequencePlotter: @staticmethod def plot_xy( - sequence: Union[TPointSeq, List[TPointInst]], + sequence: TPointSeq | list[TPointInst], *args, axes=None, show_markers=True, @@ -46,9 +44,7 @@ def plot_xy( else: plot_func = base.scatter - ins: list[TPointInst] = ( - sequence.instants() if isinstance(sequence, TPointSeq) else sequence - ) + ins: list[TPointInst] = sequence.instants() if isinstance(sequence, TPointSeq) else sequence x = [i.x().value() for i in ins] y = [i.y().value() for i in ins] @@ -88,7 +84,7 @@ def plot_xy( return plots @staticmethod - def plot_sequences_xy(sequences: List[TPointSeq], *args, **kwargs): + def plot_sequences_xy(sequences: list[TPointSeq], *args, **kwargs): """ Plot a list of TPointSeq on the given axes. Every sequence will be plotted in a different color. diff --git a/pymeos/plotters/point_sequenceset_plotter.py b/pymeos/plotters/point_sequenceset_plotter.py index bff106f7..b39ea216 100644 --- a/pymeos/plotters/point_sequenceset_plotter.py +++ b/pymeos/plotters/point_sequenceset_plotter.py @@ -1,8 +1,6 @@ -from typing import Union, List - -from .point_sequence_plotter import TemporalPointSequencePlotter from .. import TPointSeq from ..main import TPointSeqSet +from .point_sequence_plotter import TemporalPointSequencePlotter class TemporalPointSequenceSetPlotter: @@ -11,7 +9,7 @@ class TemporalPointSequenceSetPlotter: """ @staticmethod - def plot_xy(sequence_set: Union[TPointSeqSet, List[TPointSeq]], *args, **kwargs): + def plot_xy(sequence_set: TPointSeqSet | list[TPointSeq], *args, **kwargs): """ Plot a TPointSeqSet or a list of TPointSeq on the given axes. Every sequence in the set will be plotted with the same color. @@ -28,11 +26,7 @@ def plot_xy(sequence_set: Union[TPointSeqSet, List[TPointSeq]], *args, **kwargs) :func:`~pymeos.plotters.point_sequence_plotter.TemporalPointSequencePlotter.plot_xy`, :func:`~pymeos.plotters.point_sequence_plotter.TemporalPointSequencePlotter.plot_sequences_xy` """ - seqs = ( - sequence_set.sequences() - if isinstance(sequence_set, TPointSeqSet) - else sequence_set - ) + seqs = sequence_set.sequences() if isinstance(sequence_set, TPointSeqSet) else sequence_set plots = [TemporalPointSequencePlotter.plot_xy(seqs[0], *args, **kwargs)] if "color" not in kwargs: kwargs["color"] = plots[0][0][0].get_color() diff --git a/pymeos/plotters/range_plotter.py b/pymeos/plotters/range_plotter.py index bae28dcc..4b188605 100644 --- a/pymeos/plotters/range_plotter.py +++ b/pymeos/plotters/range_plotter.py @@ -1,7 +1,6 @@ -from typing import Union - from matplotlib import pyplot as plt -from pymeos import IntSpan, FloatSpan + +from pymeos import FloatSpan, IntSpan class SpanPlotter: @@ -10,7 +9,7 @@ class SpanPlotter: """ @staticmethod - def plot_span(span: Union[IntSpan, FloatSpan], *args, axes=None, **kwargs): + def plot_span(span: IntSpan | FloatSpan, *args, axes=None, **kwargs): """ Plot a :class:`FloatSpan` or :class:`IntSpan` on the given axes. @@ -24,12 +23,8 @@ def plot_span(span: Union[IntSpan, FloatSpan], *args, axes=None, **kwargs): List with the plotted elements. """ base = axes or plt.gca() - ll = base.axhline( - span.lower(), *args, linestyle="-" if span.lower_inc() else "--", **kwargs - ) + ll = base.axhline(span.lower(), *args, linestyle="-" if span.lower_inc() else "--", **kwargs) kwargs.pop("label", None) - ul = base.axhline( - span.upper(), *args, linestyle="-" if span.upper_inc() else "--", **kwargs - ) + ul = base.axhline(span.upper(), *args, linestyle="-" if span.upper_inc() else "--", **kwargs) s = base.axhspan(span.lower(), span.upper(), *args, alpha=0.3, **kwargs) return [ll, ul, s] diff --git a/pymeos/plotters/sequence_plotter.py b/pymeos/plotters/sequence_plotter.py index 609eeb05..b073198c 100644 --- a/pymeos/plotters/sequence_plotter.py +++ b/pymeos/plotters/sequence_plotter.py @@ -1,9 +1,8 @@ from functools import partial -from typing import Union, List import matplotlib.pyplot as plt -from ..temporal import TSequence, TInterpolation, TInstant +from ..temporal import TInstant, TInterpolation, TSequence class TemporalSequencePlotter: @@ -13,7 +12,7 @@ class TemporalSequencePlotter: @staticmethod def plot( - sequence: Union[TSequence, List[TInstant]], + sequence: TSequence | list[TInstant], *args, axes=None, show_markers=True, @@ -92,7 +91,7 @@ def plot( return plots @staticmethod - def plot_sequences(sequences: List[TSequence], *args, **kwargs): + def plot_sequences(sequences: list[TSequence], *args, **kwargs): """ Plot a list of :class:`TSequence` on the given axes. Every sequence will be plotted in a different color. diff --git a/pymeos/plotters/sequenceset_plotter.py b/pymeos/plotters/sequenceset_plotter.py index c9aa70e9..57742429 100644 --- a/pymeos/plotters/sequenceset_plotter.py +++ b/pymeos/plotters/sequenceset_plotter.py @@ -1,8 +1,6 @@ -from typing import List, Union - -from .sequence_plotter import TemporalSequencePlotter from .. import TSequence from ..temporal import TSequenceSet +from .sequence_plotter import TemporalSequencePlotter class TemporalSequenceSetPlotter: @@ -11,7 +9,7 @@ class TemporalSequenceSetPlotter: """ @staticmethod - def plot(sequence_set: Union[TSequenceSet, List[TSequence]], *args, **kwargs): + def plot(sequence_set: TSequenceSet | list[TSequence], *args, **kwargs): """ Plot a :class:`TSequenceSet` or a list of :class:`TSequence` on the given axes. Every sequence in the set will be plotted with the same color. @@ -28,11 +26,7 @@ def plot(sequence_set: Union[TSequenceSet, List[TSequence]], *args, **kwargs): :func:`~pymeos.plotters.sequence_plotter.TemporalSequencePlotter.plot` """ - seqs = ( - sequence_set.sequences() - if isinstance(sequence_set, TSequenceSet) - else sequence_set - ) + seqs = sequence_set.sequences() if isinstance(sequence_set, TSequenceSet) else sequence_set plots = [TemporalSequencePlotter.plot(seqs[0], *args, **kwargs)] if "color" not in kwargs: pl = plots[0] diff --git a/pymeos/plotters/time_plotter.py b/pymeos/plotters/time_plotter.py index 98539aec..cb1ccb8b 100644 --- a/pymeos/plotters/time_plotter.py +++ b/pymeos/plotters/time_plotter.py @@ -1,10 +1,8 @@ from datetime import datetime -from typing import Union from matplotlib import pyplot as plt from ..collections import TsTzSet, TsTzSpan, TsTzSpanSet -from ..collections.time.dateset import DateSet class TimePlotter: diff --git a/pymeos/temporal/interpolation.py b/pymeos/temporal/interpolation.py index b74a3f92..7f6ac58d 100644 --- a/pymeos/temporal/interpolation.py +++ b/pymeos/temporal/interpolation.py @@ -1,7 +1,9 @@ from __future__ import annotations -from pymeos_cffi import InterpolationType + from enum import IntEnum +from pymeos_cffi import InterpolationType + class TInterpolation(IntEnum): """ diff --git a/pymeos/temporal/temporal.py b/pymeos/temporal/temporal.py index e839cdc9..b168ae66 100644 --- a/pymeos/temporal/temporal.py +++ b/pymeos/temporal/temporal.py @@ -1,19 +1,20 @@ from __future__ import annotations from abc import ABC, abstractmethod -from typing import Optional, List, Union, TYPE_CHECKING, Set, Generic, TypeVar, Type +from typing import TYPE_CHECKING, Generic, TypeVar from pymeos_cffi import * -from .interpolation import TInterpolation from ..collections import * from ..mixins import TComparable, TTemporallyEquatable +from .interpolation import TInterpolation if TYPE_CHECKING: + import pandas as pd + + from ..boxes import Box from .tinstant import TInstant from .tsequence import TSequence - from ..boxes import Box - import pandas as pd def import_pandas(): @@ -48,7 +49,7 @@ class Temporal(Generic[TBase, TG, TI, TS, TSS], TComparable, TTemporallyEquatabl ComponentClass = None """ - Class of the components, for example, + Class of the components, for example, 1. ``TFloatInst`` for both ``TFloatInst`` and ``TFloatSeq`` 2. ``TFloatSeq`` for ``TFloatSeqSet``. @@ -83,7 +84,7 @@ def __str__(self) -> str: pass def __repr__(self) -> str: - return f"{self.__class__.__name__}" f"({self})" + return f"{self.__class__.__name__}({self})" @staticmethod @abstractmethod @@ -103,7 +104,7 @@ def from_base_time(value: TBase, base: Time) -> TG: @classmethod @abstractmethod - def from_mfjson(cls: Type[Self], mfjson: str) -> Self: + def from_mfjson(cls: type[Self], mfjson: str) -> Self: """ Returns a temporal object from a MF-JSON string. @@ -116,7 +117,7 @@ def from_mfjson(cls: Type[Self], mfjson: str) -> Self: pass @classmethod - def from_wkb(cls: Type[Self], wkb: bytes) -> Self: + def from_wkb(cls: type[Self], wkb: bytes) -> Self: """ Returns a temporal object from WKB bytes. @@ -133,7 +134,7 @@ def from_wkb(cls: Type[Self], wkb: bytes) -> Self: return Temporal._factory(result) @classmethod - def from_hexwkb(cls: Type[Self], hexwkb: str) -> Self: + def from_hexwkb(cls: type[Self], hexwkb: str) -> Self: """ Returns a temporal object from a hex-encoded WKB string. @@ -150,7 +151,7 @@ def from_hexwkb(cls: Type[Self], hexwkb: str) -> Self: return Temporal._factory(result) @classmethod - def from_merge(cls: Type[Self], *temporals: TG) -> Self: + def from_merge(cls: type[Self], *temporals: TG) -> Self: """ Returns a temporal object that is the result of merging the given temporal objects. @@ -170,7 +171,7 @@ def from_merge(cls: Type[Self], *temporals: TG) -> Self: return Temporal._factory(result) @classmethod - def from_merge_array(cls: Type[Self], temporals: List[TG]) -> Self: + def from_merge_array(cls: type[Self], temporals: list[TG]) -> Self: """ Returns a temporal object that is the result of merging the given temporal objects. @@ -202,7 +203,7 @@ def as_mfjson( with_bbox: bool = True, flags: int = 3, precision: int = 6, - srs: Optional[str] = None, + srs: str | None = None, ) -> str: """ Returns the temporal object as a MF-JSON string. @@ -246,7 +247,7 @@ def as_hexwkb(self) -> str: return temporal_as_hexwkb(self._inner, 4)[0] # ------------------------- Accessors ------------------------------------- - def bounding_box(self) -> Union[TsTzSpan, Box]: + def bounding_box(self) -> TsTzSpan | Box: """ Returns the bounding box of `self`. @@ -269,13 +270,13 @@ def interpolation(self) -> TInterpolation: return TInterpolation.from_string(val) @abstractmethod - def value_set(self) -> Set[TBase]: + def value_set(self) -> set[TBase]: """ Returns the unique values in `self`. """ pass - def values(self) -> List[TBase]: + def values(self) -> list[TBase]: """ Returns the list of values taken by `self`. """ @@ -425,7 +426,7 @@ def instant_n(self, n: int) -> TI: return _TemporalFactory.create_temporal(temporal_instant_n(self._inner, n + 1)) - def instants(self) -> List[TI]: + def instants(self) -> list[TI]: """ Returns the instants in `self`. @@ -473,7 +474,7 @@ def timestamp_n(self, n: int) -> datetime: """ return timestamptz_to_datetime(temporal_timestamptz_n(self._inner, n + 1)) - def timestamps(self) -> List[datetime]: + def timestamps(self) -> list[datetime]: """ Returns the timestamps in `self`. @@ -483,7 +484,7 @@ def timestamps(self) -> List[datetime]: ts, count = temporal_timestamps(self._inner) return [timestamptz_to_datetime(ts[i]) for i in range(count)] - def segments(self) -> List[TS]: + def segments(self) -> list[TS]: """ Returns the temporal segments in `self`. @@ -548,9 +549,7 @@ def scale_time(self, duration: timedelta) -> Self: scaled = temporal_scale_time(self._inner, timedelta_to_interval(duration)) return Temporal._factory(scaled) - def shift_scale_time( - self, shift: Optional[timedelta] = None, duration: Optional[timedelta] = None - ) -> Self: + def shift_scale_time(self, shift: timedelta | None = None, duration: timedelta | None = None) -> Self: """ Returns a new :class:`Temporal` with the time dimension shifted by ``shift`` and scaled so the temporal dimension has duration @@ -564,9 +563,7 @@ def shift_scale_time( MEOS Functions: temporal_shift_scale_time """ - assert ( - shift is not None or duration is not None - ), "shift and duration must not be both None" + assert shift is not None or duration is not None, "shift and duration must not be both None" scaled = temporal_shift_scale_time( self._inner, timedelta_to_interval(shift) if shift else None, @@ -576,9 +573,9 @@ def shift_scale_time( def temporal_sample( self, - duration: Union[str, timedelta], - start: Optional[Union[str, datetime]] = None, - interpolation: Optional[TInterpolation] = None, + duration: str | timedelta, + start: str | datetime | None = None, + interpolation: TInterpolation | None = None, ) -> TG: """ Returns a new :class:`Temporal` downsampled with respect to ``duration``. @@ -613,8 +610,8 @@ def temporal_sample( def temporal_precision( self, - duration: Union[str, timedelta], - start: Optional[Union[str, datetime]] = None, + duration: str | timedelta, + start: str | datetime | None = None, ) -> TG: """ Returns a new :class:`Temporal` with precision reduced to ``duration``. @@ -685,8 +682,8 @@ def to_dataframe(self) -> pd.DataFrame: def append_instant( self, instant: TInstant[TBase], - max_dist: Optional[float] = 0.0, - max_time: Optional[timedelta] = None, + max_dist: float | None = 0.0, + max_time: timedelta | None = None, default_interpolation: TInterpolation = TInterpolation.NONE, ) -> TG: """ @@ -710,9 +707,7 @@ def append_instant( interpolation = self.interpolation() if interpolation == TInterpolation.NONE: interpolation = self.DefaultInterpolation - new_inner = temporal_append_tinstant( - self._inner, instant._inner, interpolation, max_dist, interv, False - ) + new_inner = temporal_append_tinstant(self._inner, instant._inner, interpolation, max_dist, interv, False) return Temporal._factory(new_inner) def append_sequence(self, sequence: TSequence[TBase]) -> TG: @@ -729,9 +724,7 @@ def append_sequence(self, sequence: TSequence[TBase]) -> TG: new_inner = temporal_append_tsequence(self._inner, sequence._inner, False) return Temporal._factory(new_inner) - def merge( - self, other: Union[type(None), Temporal[TBase], List[Temporal[TBase]]] - ) -> TG: + def merge(self, other: type(None) | Temporal[TBase] | list[Temporal[TBase]]) -> TG: """ Returns a new :class:`Temporal` object that is the result of merging `self` with `other`. @@ -744,9 +737,7 @@ def merge( elif isinstance(other, Temporal): new_temp = temporal_merge(self._inner, other._inner) elif isinstance(other, list): - new_temp = temporal_merge_array( - [self._inner, *(o._inner for o in other)], len(other) + 1 - ) + new_temp = temporal_merge_array([self._inner, *(o._inner for o in other)], len(other) + 1) else: raise TypeError(f"Operation not supported with type {other.__class__}") return Temporal._factory(new_temp) @@ -801,9 +792,7 @@ def delete(self, other: Time, connect: bool = True) -> TG: temporal_update """ if isinstance(other, datetime): - new_inner = temporal_delete_timestamptz( - self._inner, datetime_to_timestamptz(other), connect - ) + new_inner = temporal_delete_timestamptz(self._inner, datetime_to_timestamptz(other), connect) elif isinstance(other, TsTzSet): new_inner = temporal_delete_tstzset(self._inner, other._inner, connect) elif isinstance(other, TsTzSpan): @@ -833,9 +822,7 @@ def at(self, other: Time) -> TG: temporal_at_tstzspan, temporal_at_tstzspanset """ if isinstance(other, datetime): - result = temporal_at_timestamptz( - self._inner, datetime_to_timestamptz(other) - ) + result = temporal_at_timestamptz(self._inner, datetime_to_timestamptz(other)) elif isinstance(other, TsTzSet): result = temporal_at_tstzset(self._inner, other._inner) elif isinstance(other, TsTzSpan): @@ -894,9 +881,7 @@ def minus(self, other: Time) -> TG: elif isinstance(other, TsTzSpanSet): result = temporal_minus_tstzspanset(self._inner, other._inner) elif isinstance(other, datetime): - result = temporal_minus_timestamptz( - self._inner, datetime_to_timestamptz(other) - ) + result = temporal_minus_timestamptz(self._inner, datetime_to_timestamptz(other)) elif isinstance(other, TsTzSet): result = temporal_minus_tstzset(self._inner, other._inner) else: @@ -932,7 +917,7 @@ def minus_max(self) -> TG: return Temporal._factory(result) # ------------------------- Topological Operations ------------------------ - def is_adjacent(self, other: Union[Time, Temporal, Box]) -> bool: + def is_adjacent(self, other: Time | Temporal | Box) -> bool: """ Returns whether the bounding box of `self` is adjacent to the bounding box of `other`. Temporal subclasses may override this method to provide @@ -950,7 +935,7 @@ def is_adjacent(self, other: Union[Time, Temporal, Box]) -> bool: """ return self.bounding_box().is_adjacent(other) - def is_temporally_adjacent(self, other: Union[Time, Temporal, Box]) -> bool: + def is_temporally_adjacent(self, other: Time | Temporal | Box) -> bool: """ Returns whether the bounding tstzspan of `self` is temporally adjacent to the bounding tstzspan of `other`. @@ -966,7 +951,7 @@ def is_temporally_adjacent(self, other: Union[Time, Temporal, Box]) -> bool: """ return self.tstzspan().is_adjacent(other) - def is_contained_in(self, container: Union[Time, Temporal, Box]) -> bool: + def is_contained_in(self, container: Time | Temporal | Box) -> bool: """ Returns whether the bounding tstzspan of `self` is contained in the bounding tstzspan of `container`. Temporal subclasses may override this @@ -983,7 +968,7 @@ def is_contained_in(self, container: Union[Time, Temporal, Box]) -> bool: """ return self.bounding_box().is_contained_in(container) - def is_temporally_contained_in(self, container: Union[Time, Temporal, Box]) -> bool: + def is_temporally_contained_in(self, container: Time | Temporal | Box) -> bool: """ Returns whether the bounding tstzspan of `self` is contained in the bounding tstzspan of `container`. @@ -999,7 +984,7 @@ def is_temporally_contained_in(self, container: Union[Time, Temporal, Box]) -> b """ return self.tstzspan().is_contained_in(container) - def contains(self, content: Union[Time, Temporal, Box]) -> bool: + def contains(self, content: Time | Temporal | Box) -> bool: """ Returns whether the bounding tstzspan of `self` contains the bounding tstzspan of `content`. Temporal subclasses may override this method to @@ -1032,7 +1017,7 @@ def __contains__(self, item): """ return self.contains(item) - def temporally_contains(self, content: Union[Time, Temporal, Box]) -> bool: + def temporally_contains(self, content: Time | Temporal | Box) -> bool: """ Returns whether the bounding tstzspan of `self` contains the bounding tstzspan of `content`. @@ -1048,7 +1033,7 @@ def temporally_contains(self, content: Union[Time, Temporal, Box]) -> bool: """ return self.tstzspan().contains(content) - def overlaps(self, other: Union[Time, Temporal, Box]) -> bool: + def overlaps(self, other: Time | Temporal | Box) -> bool: """ Returns whether the bounding tstzspan of `self` overlaps the bounding tstzspan of `other`. Temporal subclasses may override this method to @@ -1065,7 +1050,7 @@ def overlaps(self, other: Union[Time, Temporal, Box]) -> bool: """ return self.bounding_box().overlaps(other) - def temporally_overlaps(self, other: Union[Time, Temporal, Box]) -> bool: + def temporally_overlaps(self, other: Time | Temporal | Box) -> bool: """ Returns whether the bounding tstzspan of `self` overlaps the bounding tstzspan of `other`. @@ -1081,7 +1066,7 @@ def temporally_overlaps(self, other: Union[Time, Temporal, Box]) -> bool: """ return self.tstzspan().overlaps(other) - def is_same(self, other: Union[Time, Temporal, Box]) -> bool: + def is_same(self, other: Time | Temporal | Box) -> bool: """ Returns whether the bounding tstzspan of `self` is the same as the bounding tstzspan of `other`. Temporal subclasses may override this @@ -1099,7 +1084,7 @@ def is_same(self, other: Union[Time, Temporal, Box]) -> bool: return self.bounding_box().is_same(other) # ------------------------- Position Operations --------------------------- - def is_before(self, other: Union[Time, Temporal, Box]) -> bool: + def is_before(self, other: Time | Temporal | Box) -> bool: """ Returns whether `self` is before `other`. @@ -1114,7 +1099,7 @@ def is_before(self, other: Union[Time, Temporal, Box]) -> bool: """ return self.tstzspan().is_before(other) - def is_over_or_before(self, other: Union[Time, Temporal, Box]) -> bool: + def is_over_or_before(self, other: Time | Temporal | Box) -> bool: """ Returns whether `self` is before `other` allowing overlap. That is, `self` doesn't extend after `other`. @@ -1130,7 +1115,7 @@ def is_over_or_before(self, other: Union[Time, Temporal, Box]) -> bool: """ return self.tstzspan().is_over_or_before(other) - def is_after(self, other: Union[Time, Temporal, Box]) -> bool: + def is_after(self, other: Time | Temporal | Box) -> bool: """ Returns whether `self` is after `other`. @@ -1145,7 +1130,7 @@ def is_after(self, other: Union[Time, Temporal, Box]) -> bool: """ return self.tstzspan().is_after(other) - def is_over_or_after(self, other: Union[Time, Temporal, Box]) -> bool: + def is_over_or_after(self, other: Time | Temporal | Box) -> bool: """ Returns whether `self` is after `other` allowing overlap. That is, `self` doesn't extend before `other`. @@ -1210,9 +1195,9 @@ def hausdorff_distance(self, other: Temporal) -> float: # ------------------------- Split Operations ------------------------------ def time_split( self, - duration: Union[str, timedelta], - start: Optional[Union[str, datetime]] = None, - ) -> List[TG]: + duration: str | timedelta, + start: str | datetime | None = None, + ) -> list[TG]: """ Returns a list of temporal objects of the same subtype as `self` with the same values as `self` but split in temporal tiles of duration @@ -1234,22 +1219,14 @@ def time_split( if start is None: st = pg_timestamptz_in("2000-01-03", -1) else: - st = ( - datetime_to_timestamptz(start) - if isinstance(start, datetime) - else pg_timestamptz_in(start, -1) - ) - dt = ( - timedelta_to_interval(duration) - if isinstance(duration, timedelta) - else pg_interval_in(duration, -1) - ) + st = datetime_to_timestamptz(start) if isinstance(start, datetime) else pg_timestamptz_in(start, -1) + dt = timedelta_to_interval(duration) if isinstance(duration, timedelta) else pg_interval_in(duration, -1) fragments, times, count = temporal_time_split(self._inner, dt, st) from ..factory import _TemporalFactory return [_TemporalFactory.create_temporal(fragments[i]) for i in range(count)] - def time_split_n(self, n: int) -> List[TG]: + def time_split_n(self, n: int) -> list[TG]: """ Returns a list of temporal objects of the same subtype as `self` with the same values as `self` but split in n temporal tiles of equal @@ -1275,8 +1252,8 @@ def time_split_n(self, n: int) -> List[TG]: def stops( self, - max_distance: Optional[float] = 0.0, - min_duration: Optional[timedelta] = timedelta(), + max_distance: float | None = 0.0, + min_duration: timedelta | None = None, ) -> TSS: """ Return the subsequences where the objects stay within an area with a @@ -1293,9 +1270,8 @@ def stops( MEOS Functions: temporal_stops """ - new_inner = temporal_stops( - self._inner, max_distance, timedelta_to_interval(min_duration) - ) + min_duration = min_duration or timedelta() + new_inner = temporal_stops(self._inner, max_distance, timedelta_to_interval(min_duration)) from ..factory import _TemporalFactory return _TemporalFactory.create_temporal(new_inner) diff --git a/pymeos/temporal/tinstant.py b/pymeos/temporal/tinstant.py index 08f6c207..d79ffbce 100644 --- a/pymeos/temporal/tinstant.py +++ b/pymeos/temporal/tinstant.py @@ -2,7 +2,7 @@ from abc import ABC from datetime import datetime -from typing import Optional, Union, TypeVar, List +from typing import TypeVar from pymeos_cffi import * @@ -29,15 +29,15 @@ class TInstant(Temporal[TBase, TG, TI, TS, TSS], ABC): def __init__( self, - string: Optional[str] = None, + string: str | None = None, *, - value: Optional[Union[str, TBase]] = None, - timestamp: Optional[Union[str, datetime]] = None, + value: str | TBase | None = None, + timestamp: str | datetime | None = None, _inner=None, ): - assert (_inner is not None) or ( - (string is not None) != (value is not None and timestamp is not None) - ), "Either string must be not None or both point and timestamp must be not" + assert (_inner is not None) or ((string is not None) != (value is not None and timestamp is not None)), ( + "Either string must be not None or both point and timestamp must be not" + ) if _inner is not None: self._inner = as_tinstant(_inner) elif string is not None: @@ -48,9 +48,7 @@ def __init__( if isinstance(timestamp, datetime) else pg_timestamptz_in(timestamp, -1) ) - self._inner = self.__class__._make_function( - self.__class__._cast_function(value), ts - ) + self._inner = self.__class__._make_function(self.__class__._cast_function(value), ts) def value(self) -> TBase: """ @@ -87,7 +85,7 @@ def instant_n(self: Self, n: int) -> Self: else: raise Exception("ERROR: Out of range") - def instants(self: Self) -> List[Self]: + def instants(self: Self) -> list[Self]: return [self] def start_timestamp(self) -> datetime: @@ -102,5 +100,5 @@ def timestamp_n(self, n) -> datetime: else: raise Exception("ERROR: Out of range") - def timestamps(self) -> List[datetime]: + def timestamps(self) -> list[datetime]: return [self.timestamp()] diff --git a/pymeos/temporal/tsequence.py b/pymeos/temporal/tsequence.py index 35578ccc..77587217 100644 --- a/pymeos/temporal/tsequence.py +++ b/pymeos/temporal/tsequence.py @@ -1,7 +1,7 @@ from __future__ import annotations from abc import ABC -from typing import Optional, Union, List, Any, TypeVar, Type +from typing import Any, TypeVar from pymeos_cffi import * @@ -25,29 +25,25 @@ class TSequence(Temporal[TBase, TG, TI, TS, TSS], ABC): # ------------------------- Constructors ---------------------------------- def __init__( self, - string: Optional[str] = None, + string: str | None = None, *, - instant_list: Optional[List[Union[str, Any]]] = None, + instant_list: list[str | Any] | None = None, lower_inc: bool = True, upper_inc: bool = False, interpolation: TInterpolation = TInterpolation.LINEAR, normalize: bool = True, _inner=None, ): - assert (_inner is not None) or ( - (string is not None) != (instant_list is not None) - ), "Either string must be not None or instant_list must be not" + assert (_inner is not None) or ((string is not None) != (instant_list is not None)), ( + "Either string must be not None or instant_list must be not" + ) if _inner is not None: self._inner = as_tsequence(_inner) elif string is not None: self._inner = as_tsequence(self.__class__._parse_function(string)) else: self._instants = [ - ( - x._inner - if isinstance(x, self.ComponentClass) - else self.__class__._parse_function(x) - ) + (x._inner if isinstance(x, self.ComponentClass) else self.__class__._parse_function(x)) for x in instant_list ] count = len(self._instants) @@ -62,8 +58,8 @@ def __init__( @classmethod def from_instants( - cls: Type[Self], - instant_list: Optional[List[Union[str, Any]]], + cls: type[Self], + instant_list: list[str | Any] | None, lower_inc: bool = True, upper_inc: bool = False, interpolation: TInterpolation = TInterpolation.LINEAR, diff --git a/pymeos/temporal/tsequenceset.py b/pymeos/temporal/tsequenceset.py index b9213130..0e14de63 100644 --- a/pymeos/temporal/tsequenceset.py +++ b/pymeos/temporal/tsequenceset.py @@ -1,7 +1,7 @@ from __future__ import annotations from abc import ABC -from typing import Optional, List, Union, Any, TypeVar, Type, TYPE_CHECKING +from typing import TYPE_CHECKING, Any, TypeVar from pymeos_cffi import * @@ -28,26 +28,22 @@ class TSequenceSet(Temporal[TBase, TG, TI, TS, TSS], ABC): # ------------------------- Constructors ---------------------------------- def __init__( self, - string: Optional[str] = None, + string: str | None = None, *, - sequence_list: Optional[List[Union[str, Any]]] = None, + sequence_list: list[str | Any] | None = None, normalize: bool = True, _inner=None, ): - assert (_inner is not None) or ( - (string is not None) != (sequence_list is not None) - ), "Either string must be not None or sequence_list must be not" + assert (_inner is not None) or ((string is not None) != (sequence_list is not None)), ( + "Either string must be not None or sequence_list must be not" + ) if _inner is not None: self._inner = as_tsequenceset(_inner) elif string is not None: self._inner = as_tsequenceset(self.__class__._parse_function(string)) else: sequences = [ - ( - x._inner - if isinstance(x, self.ComponentClass) - else self.__class__._parse_function(x) - ) + (x._inner if isinstance(x, self.ComponentClass) else self.__class__._parse_function(x)) for x in sequence_list ] count = len(sequences) @@ -55,8 +51,8 @@ def __init__( @classmethod def from_sequences( - cls: Type[Self], - sequence_list: Optional[List[Union[str, Any]]] = None, + cls: type[Self], + sequence_list: list[str | Any] | None = None, normalize: bool = True, ) -> Self: """ @@ -96,7 +92,7 @@ def sequence_n(self, n) -> TS: """ return self.ComponentClass(_inner=temporal_sequence_n(self._inner, n + 1)) - def sequences(self) -> List[TS]: + def sequences(self) -> list[TS]: """ Returns the list of sequences in ``self``. """ @@ -111,9 +107,7 @@ def to_dataframe(self) -> pd.DataFrame: pd = import_pandas() sequences = self.sequences() data = { - "sequence": [ - i for i, seq in enumerate(sequences) for _ in range(seq.num_instants()) - ], + "sequence": [i for i, seq in enumerate(sequences) for _ in range(seq.num_instants())], "time": [t for seq in sequences for t in seq.timestamps()], "value": [v for seq in sequences for v in seq.values()], } diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 00000000..b1b90e80 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,35 @@ +line-length = 120 +indent-width = 4 + +target-version = "py310" + +[format] +quote-style = "double" +indent-style = "space" +line-ending = "auto" + +[lint] +select = [ + # pycodestyle + "E", "W", + # Pyflakes + "F", + # pyupgrade + "UP", + # flake8-bugbear + "B", + # flake8-simplify + "SIM", + # isort + "I", +] +ignore = [ + "F405", "F403", # Allow star imports + "SIM108", # Don't turn if-else assignment to ternary + "SIM116", # Don't simplify long if-else chains + "E501", # Allow long lines for the moment + "E731", # Allow assigning lambda expressions + "UP038", # Alow instance checks with tuples instead of unions +] +[lint.per-file-ignores] +"docs/conf.py" = ["E402"] \ No newline at end of file diff --git a/tests/boxes/stbox_test.py b/tests/boxes/stbox_test.py index cdc109f3..bcc676d9 100644 --- a/tests/boxes/stbox_test.py +++ b/tests/boxes/stbox_test.py @@ -1,25 +1,23 @@ +import math from copy import copy -from datetime import datetime, timezone, timedelta -from shapely import Point, LineString, Polygon -import shapely.geometry +from datetime import datetime, timedelta, timezone import pytest -import math +import shapely.geometry +from shapely import LineString, Point, Polygon from pymeos import ( STBox, - TInterpolation, - TsTzSet, - TsTzSpan, - TsTzSpanSet, - TGeomPointInst, - TGeomPointSeq, - TGeomPointSeqSet, TGeogPointInst, TGeogPointSeq, TGeogPointSeqSet, + TGeomPointInst, + TGeomPointSeq, + TGeomPointSeqSet, + TsTzSet, + TsTzSpan, + TsTzSpanSet, ) - from tests.conftest import TestPyMEOS @@ -352,53 +350,25 @@ def test_from_stbox_expand_space_constructor(self, stbox, expected): ], ), ( - STBox( - "STBOX XT(((1,1),(3,3)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])" - ), + STBox("STBOX XT(((1,1),(3,3)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])"), [ - STBox( - "STBOX XT(((1,1),(2,2)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])" - ), - STBox( - "STBOX XT(((2,1),(3,2)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])" - ), - STBox( - "STBOX XT(((1,2),(2,3)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])" - ), - STBox( - "STBOX XT(((2,2),(3,3)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])" - ), + STBox("STBOX XT(((1,1),(2,2)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])"), + STBox("STBOX XT(((2,1),(3,2)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])"), + STBox("STBOX XT(((1,2),(2,3)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])"), + STBox("STBOX XT(((2,2),(3,3)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])"), ], ), ( - STBox( - "STBOX ZT(((1,1,1),(3,3,3)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])" - ), + STBox("STBOX ZT(((1,1,1),(3,3,3)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])"), [ - STBox( - "STBOX ZT(((1,1,1),(2,2,2)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])" - ), - STBox( - "STBOX ZT(((2,1,1),(3,2,2)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])" - ), - STBox( - "STBOX ZT(((1,2,1),(2,3,2)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])" - ), - STBox( - "STBOX ZT(((2,2,1),(3,3,2)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])" - ), - STBox( - "STBOX ZT(((1,1,2),(2,2,3)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])" - ), - STBox( - "STBOX ZT(((2,1,2),(3,2,3)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])" - ), - STBox( - "STBOX ZT(((1,2,2),(2,3,3)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])" - ), - STBox( - "STBOX ZT(((2,2,2),(3,3,3)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])" - ), + STBox("STBOX ZT(((1,1,1),(2,2,2)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])"), + STBox("STBOX ZT(((2,1,1),(3,2,2)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])"), + STBox("STBOX ZT(((1,2,1),(2,3,2)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])"), + STBox("STBOX ZT(((2,2,1),(3,3,2)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])"), + STBox("STBOX ZT(((1,1,2),(2,2,3)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])"), + STBox("STBOX ZT(((2,1,2),(3,2,3)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])"), + STBox("STBOX ZT(((1,2,2),(2,3,3)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])"), + STBox("STBOX ZT(((2,2,2),(3,3,3)),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00])"), ], ), ], @@ -790,9 +760,9 @@ def test_scale_time(self, stbox, delta, expected): assert stbox.scale_time(delta) == expected def test_shift_scale_time(self): - assert self.stbt.shift_scale_time( - timedelta(days=4), timedelta(hours=4) - ) == STBox("STBOX T([2019-09-05,2019-09-05 04:00:00])") + assert self.stbt.shift_scale_time(timedelta(days=4), timedelta(hours=4)) == STBox( + "STBOX T([2019-09-05,2019-09-05 04:00:00])" + ) @pytest.mark.parametrize( "stbox, expected", @@ -802,15 +772,11 @@ def test_shift_scale_time(self): STBox("STBOX X((1.12,1.12),(2.12,2.12))"), ), ( - STBox( - "STBOX Z((1.123456789,1.123456789,1.123456789),(2.123456789,2.123456789,2.123456789))" - ), + STBox("STBOX Z((1.123456789,1.123456789,1.123456789),(2.123456789,2.123456789,2.123456789))"), STBox("STBOX Z((1.12,1.12,1.12),(2.12,2.12,2.12))"), ), ( - STBox( - "STBOX XT(((1.123456789,1.123456789),(2.123456789,2.123456789)),[2019-09-01, 2019-09-02])" - ), + STBox("STBOX XT(((1.123456789,1.123456789),(2.123456789,2.123456789)),[2019-09-01, 2019-09-02])"), STBox("STBOX XT(((1.12,1.12),(2.12,2.12)),[2019-09-01, 2019-09-03])"), ), ( @@ -818,9 +784,7 @@ def test_shift_scale_time(self): "STBOX ZT(((1.123456789,1.123456789,1.123456789),(2.123456789,2.123456789,2.123456789))," "[2019-09-01, 2019-09-02])" ), - STBox( - "STBOX ZT(((1.12,1.12,1.12),(2.12,2.12,2.12)),[2019-09-01, 2019-09-02])" - ), + STBox("STBOX ZT(((1.12,1.12,1.12),(2.12,2.12,2.12)),[2019-09-01, 2019-09-02])"), ), ], ids=["STBox X", "STBox Z", "STBox XT", "STBox ZT"], diff --git a/tests/boxes/tbox_test.py b/tests/boxes/tbox_test.py index 1bc387e6..c25a86e2 100644 --- a/tests/boxes/tbox_test.py +++ b/tests/boxes/tbox_test.py @@ -1,21 +1,21 @@ from copy import copy -from datetime import datetime, timezone, timedelta +from datetime import datetime, timedelta, timezone import pytest from pymeos import ( - TBox, - TsTzSet, - TsTzSpan, - TsTzSpanSet, - IntSpan, FloatSpan, - TIntInst, - TIntSeq, - TIntSeqSet, + IntSpan, + TBox, TFloatInst, TFloatSeq, TFloatSeqSet, + TIntInst, + TIntSeq, + TIntSeqSet, + TsTzSet, + TsTzSpan, + TsTzSpanSet, ) from tests.conftest import TestPyMEOS @@ -258,9 +258,7 @@ def test_from_value_time_constructor(self, value, time, expected): "TBOXFLOAT XT([1.5, 2.5),[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00))", ), ( - TFloatSeqSet( - "{[1.5@2019-09-01,2.5@2019-09-02),[1.5@2019-09-03,1.5@2019-09-05)}" - ), + TFloatSeqSet("{[1.5@2019-09-01,2.5@2019-09-02),[1.5@2019-09-03,1.5@2019-09-05)}"), "TBOXFLOAT XT([1.5, 2.5),[2019-09-01 00:00:00+00, 2019-09-05 00:00:00+00))", ), ], @@ -280,17 +278,13 @@ def test_from_tnumber_constructor(self, tnumber, expected): assert isinstance(tb, TBox) assert str(tb) == expected - @pytest.mark.parametrize( - "tbox", [tbfx, tbt, tbfxt], ids=["TBoxFloat X", "TBox T", "TBoxFloat XT"] - ) + @pytest.mark.parametrize("tbox", [tbfx, tbt, tbfxt], ids=["TBoxFloat X", "TBox T", "TBoxFloat XT"]) def test_from_as_constructor(self, tbox): assert tbox == TBox(str(tbox)) assert tbox == tbox.from_wkb(tbox.as_wkb()) assert tbox == tbox.from_hexwkb(tbox.as_hexwkb()) - @pytest.mark.parametrize( - "tbox", [tbfx, tbt, tbfxt], ids=["TBoxFloat X", "TBox T", "TBoxFloat XT"] - ) + @pytest.mark.parametrize("tbox", [tbfx, tbt, tbfxt], ids=["TBoxFloat X", "TBox T", "TBoxFloat XT"]) def test_copy_constructor(self, tbox): other = copy(tbox) assert tbox == other @@ -600,18 +594,12 @@ def test_shift_value(self, tbox, delta, expected): ( tbfxt, timedelta(hours=2), - TBox( - "TBOXFLOAT XT([1, 2]," - "[2019-09-01 02:00:00+00, 2019-09-02 02:00:00+00])" - ), + TBox("TBOXFLOAT XT([1, 2],[2019-09-01 02:00:00+00, 2019-09-02 02:00:00+00])"), ), ( tbfxt, timedelta(hours=-2), - TBox( - "TBOXFLOAT XT([1, 2]," - "[2019-08-31 22:00:00+00, 2019-09-01 22:00:00+00])" - ), + TBox("TBOXFLOAT XT([1, 2],[2019-08-31 22:00:00+00, 2019-09-01 22:00:00+00])"), ), ( tbixt, @@ -626,18 +614,12 @@ def test_shift_value(self, tbox, delta, expected): ( tbixt, timedelta(hours=2), - TBox( - "TBOXINT XT([1, 3)," - "[2019-09-01 02:00:00+00, 2019-09-02 02:00:00+00])" - ), + TBox("TBOXINT XT([1, 3),[2019-09-01 02:00:00+00, 2019-09-02 02:00:00+00])"), ), ( tbixt, timedelta(hours=-2), - TBox( - "TBOXINT XT([1, 3)," - "[2019-08-31 22:00:00+00, 2019-09-01 22:00:00+00])" - ), + TBox("TBOXINT XT([1, 3),[2019-08-31 22:00:00+00, 2019-09-01 22:00:00+00])"), ), ], ids=[ @@ -679,32 +661,22 @@ def test_scale_value(self, tbox, delta, expected): ( tbfxt, timedelta(days=4), - TBox( - "TBOXFLOAT XT([1, 2]," - "[2019-09-01 00:00:00+00, 2019-09-05 00:00:00+00])" - ), + TBox("TBOXFLOAT XT([1, 2],[2019-09-01 00:00:00+00, 2019-09-05 00:00:00+00])"), ), ( tbfxt, timedelta(hours=2), - TBox( - "TBOXFLOAT XT([1, 2]," - "[2019-09-01 00:00:00+00, 2019-09-01 02:00:00+00])" - ), + TBox("TBOXFLOAT XT([1, 2],[2019-09-01 00:00:00+00, 2019-09-01 02:00:00+00])"), ), ( tbixt, timedelta(days=4), - TBox( - "TBOXINT XT([1, 3),[2019-09-01 00:00:00+00, 2019-09-05 00:00:00+00])" - ), + TBox("TBOXINT XT([1, 3),[2019-09-01 00:00:00+00, 2019-09-05 00:00:00+00])"), ), ( tbixt, timedelta(hours=2), - TBox( - "TBOXINT XT([1, 3),[2019-09-01 00:00:00+00, 2019-09-01 02:00:00+00])" - ), + TBox("TBOXINT XT([1, 3),[2019-09-01 00:00:00+00, 2019-09-01 02:00:00+00])"), ), ], ids=[ @@ -805,9 +777,7 @@ def test_shift_scale_time(self, tbox, delta, duration, expected): TBox("TBOXFLOAT X([1.12,2.12])"), ), ( - TBox( - "TBOXFLOAT XT([1.123456789,2.123456789],[2019-09-01, 2019-09-02])" - ), + TBox("TBOXFLOAT XT([1.123456789,2.123456789],[2019-09-01, 2019-09-02])"), TBox("TBOXFLOAT XT([1.12,2.12],[2019-09-01, 2019-09-02])"), ), ( diff --git a/tests/collections/number/floatset_test.py b/tests/collections/number/floatset_test.py index af376983..ff58ec0b 100644 --- a/tests/collections/number/floatset_test.py +++ b/tests/collections/number/floatset_test.py @@ -1,9 +1,8 @@ from copy import copy -from typing import List import pytest -from pymeos import FloatSet, FloatSpan, FloatSpanSet +from pymeos import FloatSet, FloatSpan from tests.conftest import TestPyMEOS @@ -11,7 +10,7 @@ class TestFloatSet(TestPyMEOS): floatset = FloatSet("{1, 2, 3}") @staticmethod - def assert_intset_equality(floatset: FloatSet, values: List[int]): + def assert_intset_equality(floatset: FloatSet, values: list[int]): assert floatset.num_elements() == len(values) assert floatset.elements() == values diff --git a/tests/collections/number/intset_test.py b/tests/collections/number/intset_test.py index 01d13352..e27520c7 100644 --- a/tests/collections/number/intset_test.py +++ b/tests/collections/number/intset_test.py @@ -1,9 +1,8 @@ from copy import copy -from typing import List import pytest -from pymeos import IntSet, IntSpan, IntSpanSet +from pymeos import IntSet, IntSpan from tests.conftest import TestPyMEOS @@ -11,7 +10,7 @@ class TestIntSet(TestPyMEOS): intset = IntSet("{1, 2, 3}") @staticmethod - def assert_intset_equality(intset: IntSet, values: List[int]): + def assert_intset_equality(intset: IntSet, values: list[int]): assert intset.num_elements() == len(values) assert intset.elements() == values diff --git a/tests/collections/number/intspan_test.py b/tests/collections/number/intspan_test.py index c6706eda..75802538 100644 --- a/tests/collections/number/intspan_test.py +++ b/tests/collections/number/intspan_test.py @@ -3,7 +3,6 @@ import pytest from pymeos import IntSpan, IntSpanSet - from tests.conftest import TestPyMEOS @@ -164,64 +163,44 @@ class TestIntSpanTopologicalPositionFunctions(TestIntSpan): intspan = IntSpan("(1, 20)") intspanset = IntSpanSet("{(1, 20), (31, 41)}") - @pytest.mark.parametrize( - "other", [value, intspan, intspanset], ids=["value", "intspan", "intspanset"] - ) + @pytest.mark.parametrize("other", [value, intspan, intspanset], ids=["value", "intspan", "intspanset"]) def test_is_adjacent(self, other): self.intspan.is_adjacent(other) - @pytest.mark.parametrize( - "other", [intspan, intspanset], ids=["intspan", "intspanset"] - ) + @pytest.mark.parametrize("other", [intspan, intspanset], ids=["intspan", "intspanset"]) def test_is_contained_in(self, other): self.intspan.is_contained_in(other) - @pytest.mark.parametrize( - "other", [value, intspan, intspanset], ids=["value", "intspan", "intspanset"] - ) + @pytest.mark.parametrize("other", [value, intspan, intspanset], ids=["value", "intspan", "intspanset"]) def test_contains(self, other): self.intspan.contains(other) _ = other in self.intspan - @pytest.mark.parametrize( - "other", [intspan, intspanset], ids=["intspan", "intspanset"] - ) + @pytest.mark.parametrize("other", [intspan, intspanset], ids=["intspan", "intspanset"]) def test_overlaps(self, other): self.intspan.overlaps(other) - @pytest.mark.parametrize( - "other", [value, intspan, intspanset], ids=["value", "intspan", "intspanset"] - ) + @pytest.mark.parametrize("other", [value, intspan, intspanset], ids=["value", "intspan", "intspanset"]) def test_is_same(self, other): self.intspan.is_same(other) - @pytest.mark.parametrize( - "other", [value, intspan, intspanset], ids=["value", "intspan", "intspanset"] - ) + @pytest.mark.parametrize("other", [value, intspan, intspanset], ids=["value", "intspan", "intspanset"]) def test_is_left(self, other): self.intspan.is_left(other) - @pytest.mark.parametrize( - "other", [value, intspan, intspanset], ids=["value", "intspan", "intspanset"] - ) + @pytest.mark.parametrize("other", [value, intspan, intspanset], ids=["value", "intspan", "intspanset"]) def test_is_over_or_left(self, other): self.intspan.is_over_or_left(other) - @pytest.mark.parametrize( - "other", [value, intspan, intspanset], ids=["value", "intspan", "intspanset"] - ) + @pytest.mark.parametrize("other", [value, intspan, intspanset], ids=["value", "intspan", "intspanset"]) def test_is_right(self, other): self.intspan.is_right(other) - @pytest.mark.parametrize( - "other", [value, intspan, intspanset], ids=["value", "intspan", "intspanset"] - ) + @pytest.mark.parametrize("other", [value, intspan, intspanset], ids=["value", "intspan", "intspanset"]) def test_is_over_or_right(self, other): self.intspan.is_over_or_right(other) - @pytest.mark.parametrize( - "other", [value, intspan, intspanset], ids=["value", "intspan", "intspanset"] - ) + @pytest.mark.parametrize("other", [value, intspan, intspanset], ids=["value", "intspan", "intspanset"]) def test_distance(self, other): self.intspan.distance(other) @@ -231,23 +210,17 @@ class TestIntSpanSetFunctions(TestIntSpan): intspan = IntSpan("(1, 20)") intspanset = IntSpanSet("{(1, 20), (31, 41)}") - @pytest.mark.parametrize( - "other", [value, intspan, intspanset], ids=["value", "intspan", "intspanset"] - ) + @pytest.mark.parametrize("other", [value, intspan, intspanset], ids=["value", "intspan", "intspanset"]) def test_intersection(self, other): self.intspan.intersection(other) self.intspan * other - @pytest.mark.parametrize( - "other", [value, intspan, intspanset], ids=["value", "intspan", "intspanset"] - ) + @pytest.mark.parametrize("other", [value, intspan, intspanset], ids=["value", "intspan", "intspanset"]) def test_union(self, other): self.intspan.union(other) self.intspan + other - @pytest.mark.parametrize( - "other", [value, intspan, intspanset], ids=["value", "intspan", "intspanset"] - ) + @pytest.mark.parametrize("other", [value, intspan, intspanset], ids=["value", "intspan", "intspanset"]) def test_minus(self, other): self.intspan.minus(other) self.intspan - other diff --git a/tests/collections/text/textset_test.py b/tests/collections/text/textset_test.py index 1b0d6352..ef375882 100644 --- a/tests/collections/text/textset_test.py +++ b/tests/collections/text/textset_test.py @@ -1,6 +1,4 @@ from copy import copy -from datetime import datetime, timezone, timedelta -from typing import List import pytest @@ -12,7 +10,7 @@ class TestTextSet(TestPyMEOS): tset = TextSet("{A, BB, ccc}") @staticmethod - def assert_textset_equality(tset: TextSet, elements: List[str]): + def assert_textset_equality(tset: TextSet, elements: list[str]): assert tset.num_elements() == len(elements) assert tset.elements() == elements diff --git a/tests/collections/time/dateset_test.py b/tests/collections/time/dateset_test.py index 21caa07e..bd3ea465 100644 --- a/tests/collections/time/dateset_test.py +++ b/tests/collections/time/dateset_test.py @@ -4,9 +4,9 @@ import pytest from pymeos import ( + DateSet, DateSpan, DateSpanSet, - DateSet, ) from tests.conftest import TestPyMEOS @@ -61,11 +61,7 @@ def test_to_span(self): assert self.date_set.to_span() == DateSpan("[2019-09-25, 2019-09-27]") def test_to_spanset(self): - expected = DateSpanSet( - "{[2019-09-25, 2019-09-25], " - "[2019-09-26, 2019-09-26], " - "[2019-09-27, 2019-09-27]}" - ) + expected = DateSpanSet("{[2019-09-25, 2019-09-25], [2019-09-26, 2019-09-26], [2019-09-27, 2019-09-27]}") spanset = self.date_set.to_spanset() @@ -130,33 +126,23 @@ def test_contains(self, other, expected): def test_overlaps(self, other): self.date_set.overlaps(other) - @pytest.mark.parametrize( - "other", [date_value, other_date_set], ids=["date", "dateset"] - ) + @pytest.mark.parametrize("other", [date_value, other_date_set], ids=["date", "dateset"]) def test_is_before(self, other): self.date_set.is_before(other) - @pytest.mark.parametrize( - "other", [date_value, other_date_set], ids=["date", "dateset"] - ) + @pytest.mark.parametrize("other", [date_value, other_date_set], ids=["date", "dateset"]) def test_is_over_or_before(self, other): self.date_set.is_over_or_before(other) - @pytest.mark.parametrize( - "other", [date_value, other_date_set], ids=["date", "dateset"] - ) + @pytest.mark.parametrize("other", [date_value, other_date_set], ids=["date", "dateset"]) def test_is_after(self, other): self.date_set.is_after(other) - @pytest.mark.parametrize( - "other", [date_value, other_date_set], ids=["date", "dateset"] - ) + @pytest.mark.parametrize("other", [date_value, other_date_set], ids=["date", "dateset"]) def test_is_over_or_after(self, other): self.date_set.is_over_or_after(other) - @pytest.mark.parametrize( - "other", [date_value, other_date_set], ids=["date", "dateset"] - ) + @pytest.mark.parametrize("other", [date_value, other_date_set], ids=["date", "dateset"]) def test_distance(self, other): self.date_set.distance(other) @@ -200,7 +186,7 @@ class TestDateSetComparisons(TestDateSet): other = DateSet("{2020-01-02, 2020-03-31}") def test_eq(self): - assert not self.dateset == self.other + assert self.dateset == self.other def test_ne(self): assert self.dateset != self.other diff --git a/tests/collections/time/tstzset_test.py b/tests/collections/time/tstzset_test.py index c9263996..55719eae 100644 --- a/tests/collections/time/tstzset_test.py +++ b/tests/collections/time/tstzset_test.py @@ -1,24 +1,21 @@ from copy import copy -from datetime import datetime, timezone, timedelta -from typing import List +from datetime import datetime, timedelta, timezone import pytest from pymeos import ( + TsTzSet, TsTzSpan, TsTzSpanSet, - TsTzSet, ) from tests.conftest import TestPyMEOS class TestTsTzSet(TestPyMEOS): - ts_set = TsTzSet( - "{2019-09-01 00:00:00+0, 2019-09-02 00:00:00+0, 2019-09-03 00:00:00+0}" - ) + ts_set = TsTzSet("{2019-09-01 00:00:00+0, 2019-09-02 00:00:00+0, 2019-09-03 00:00:00+0}") @staticmethod - def assert_tstzset_equality(ts_set: TsTzSet, timestamps: List[datetime]): + def assert_tstzset_equality(ts_set: TsTzSet, timestamps: list[datetime]): assert ts_set.num_elements() == len(timestamps) assert ts_set.elements() == timestamps @@ -83,10 +80,7 @@ def test_copy_constructor(self): class TestTsTzSetOutputs(TestTsTzSet): def test_str(self): - assert ( - str(self.ts_set) - == '{"2019-09-01 00:00:00+00", "2019-09-02 00:00:00+00", "2019-09-03 00:00:00+00"}' - ) + assert str(self.ts_set) == '{"2019-09-01 00:00:00+00", "2019-09-02 00:00:00+00", "2019-09-03 00:00:00+00"}' def test_repr(self): assert ( @@ -112,28 +106,20 @@ def test_duration(self): assert self.ts_set.duration() == timedelta(days=2) def test_tstzspan(self): - assert self.ts_set.to_span() == TsTzSpan( - "[2019-09-01 00:00:00+00, 2019-09-03 00:00:00+00]" - ) + assert self.ts_set.to_span() == TsTzSpan("[2019-09-01 00:00:00+00, 2019-09-03 00:00:00+00]") def test_num_timestamps(self): assert self.ts_set.num_elements() == 3 assert len(self.ts_set) == 3 def test_start_timestamp(self): - assert self.ts_set.start_element() == datetime( - 2019, 9, 1, 0, 0, 0, tzinfo=timezone.utc - ) + assert self.ts_set.start_element() == datetime(2019, 9, 1, 0, 0, 0, tzinfo=timezone.utc) def test_end_timestamp(self): - assert self.ts_set.end_element() == datetime( - 2019, 9, 3, 0, 0, 0, tzinfo=timezone.utc - ) + assert self.ts_set.end_element() == datetime(2019, 9, 3, 0, 0, 0, tzinfo=timezone.utc) def test_timestamp_n(self): - assert self.ts_set.element_n(1) == datetime( - 2019, 9, 2, 0, 0, 0, tzinfo=timezone.utc - ) + assert self.ts_set.element_n(1) == datetime(2019, 9, 2, 0, 0, 0, tzinfo=timezone.utc) def test_timestamp_n_out_of_range(self): with pytest.raises(IndexError): @@ -158,9 +144,7 @@ class TestTsTzSetPositionFunctions(TestTsTzSet): def test_is_contained_in(self, other, expected): assert self.ts_set.is_contained_in(other) == expected - @pytest.mark.parametrize( - "other", [timestamp, tstzset], ids=["timestamp", "tstzset"] - ) + @pytest.mark.parametrize("other", [timestamp, tstzset], ids=["timestamp", "tstzset"]) def test_contains(self, other): self.ts_set.contains(other) _ = other in self.tstzset @@ -169,33 +153,23 @@ def test_contains(self, other): def test_overlaps(self, other): self.ts_set.overlaps(other) - @pytest.mark.parametrize( - "other", [timestamp, tstzset], ids=["timestamp", "tstzset"] - ) + @pytest.mark.parametrize("other", [timestamp, tstzset], ids=["timestamp", "tstzset"]) def test_is_before(self, other): self.ts_set.is_before(other) - @pytest.mark.parametrize( - "other", [timestamp, tstzset], ids=["timestamp", "tstzset"] - ) + @pytest.mark.parametrize("other", [timestamp, tstzset], ids=["timestamp", "tstzset"]) def test_is_over_or_before(self, other): self.ts_set.is_over_or_before(other) - @pytest.mark.parametrize( - "other", [timestamp, tstzset], ids=["timestamp", "tstzset"] - ) + @pytest.mark.parametrize("other", [timestamp, tstzset], ids=["timestamp", "tstzset"]) def test_is_after(self, other): self.ts_set.is_after(other) - @pytest.mark.parametrize( - "other", [timestamp, tstzset], ids=["timestamp", "tstzset"] - ) + @pytest.mark.parametrize("other", [timestamp, tstzset], ids=["timestamp", "tstzset"]) def test_is_over_or_after(self, other): self.ts_set.is_over_or_after(other) - @pytest.mark.parametrize( - "other", [timestamp, tstzset], ids=["timestamp", "tstzset"] - ) + @pytest.mark.parametrize("other", [timestamp, tstzset], ids=["timestamp", "tstzset"]) def test_distance(self, other): self.ts_set.distance(other) @@ -260,9 +234,7 @@ def test_ge(self): class TestTsTzSetFunctionsFunctions(TestTsTzSet): - tstzset = TsTzSet( - "{2020-01-01 00:00:00+0, 2020-01-02 00:00:00+0, 2020-01-04 00:00:00+0}" - ) + tstzset = TsTzSet("{2020-01-01 00:00:00+0, 2020-01-02 00:00:00+0, 2020-01-04 00:00:00+0}") @pytest.mark.parametrize( "delta,result", @@ -345,9 +317,7 @@ def test_shift_scale(self): class TestTsTzSetMiscFunctions(TestTsTzSet): - tstzset = TsTzSet( - "{2020-01-01 00:00:00+0, 2020-01-02 00:00:00+0, 2020-01-04 00:00:00+0}" - ) + tstzset = TsTzSet("{2020-01-01 00:00:00+0, 2020-01-02 00:00:00+0, 2020-01-04 00:00:00+0}") def test_hash(self): hash(self.tstzset) diff --git a/tests/collections/time/tstzspan_test.py b/tests/collections/time/tstzspan_test.py index c3fec24f..ec7a3ebf 100644 --- a/tests/collections/time/tstzspan_test.py +++ b/tests/collections/time/tstzspan_test.py @@ -1,16 +1,16 @@ from copy import copy -from datetime import datetime, timezone, timedelta +from datetime import datetime, timedelta, timezone import pytest from pymeos import ( - TsTzSpan, - TsTzSpanSet, - TBox, STBox, + TBox, TFloatInst, TFloatSeq, TFloatSeqSet, + TsTzSpan, + TsTzSpanSet, ) from tests.conftest import TestPyMEOS @@ -93,9 +93,7 @@ def test_constructor_bounds(self, input_lower, input_upper, lower, upper): self.assert_tstzspan_equality(tstzspan, lower, upper) def test_constructor_bound_inclusivity_defaults(self): - tstzspan = TsTzSpan( - lower="2019-09-08 00:00:00+0", upper="2019-09-10 00:00:00+0" - ) + tstzspan = TsTzSpan(lower="2019-09-08 00:00:00+0", upper="2019-09-10 00:00:00+0") self.assert_tstzspan_equality(tstzspan, lower_inc=True, upper_inc=False) @pytest.mark.parametrize( @@ -134,10 +132,7 @@ def test_str(self): assert str(self.tstzspan) == "(2019-09-08 00:00:00+00, 2019-09-10 00:00:00+00)" def test_repr(self): - assert ( - repr(self.tstzspan) - == "TsTzSpan((2019-09-08 00:00:00+00, 2019-09-10 00:00:00+00))" - ) + assert repr(self.tstzspan) == "TsTzSpan((2019-09-08 00:00:00+00, 2019-09-10 00:00:00+00))" def test_hexwkb(self): assert self.tstzspan == TsTzSpan.from_hexwkb(self.tstzspan.as_hexwkb()) @@ -160,9 +155,7 @@ def test_lower(self): def test_upper(self): assert self.tstzspan.upper() == datetime(2019, 9, 10, tzinfo=timezone.utc) - assert self.tstzspan2.upper() == datetime( - 2019, 9, 10, 2, 3, tzinfo=timezone.utc - ) + assert self.tstzspan2.upper() == datetime(2019, 9, 10, 2, 3, tzinfo=timezone.utc) def test_lower_inc(self): assert not self.tstzspan.lower_inc() @@ -256,9 +249,7 @@ def test_scale(self, delta, result): self.assert_tstzspan_equality(scaled, *result) def test_shift_scale(self): - shifted_scaled = self.tstzspan.shift_scale( - timedelta(days=4), timedelta(hours=4) - ) + shifted_scaled = self.tstzspan.shift_scale(timedelta(days=4), timedelta(hours=4)) self.assert_tstzspan_equality( shifted_scaled, datetime(2019, 9, 12, 0, tzinfo=timezone.utc), @@ -275,15 +266,9 @@ class TestTsTzSpanTopologicalPositionFunctions(TestTsTzSpan): ) timestamp = datetime(year=2020, month=1, day=1) instant = TFloatInst("1.0@2020-01-01") - discrete_sequence = TFloatSeq( - "{1.0@2020-01-01, 3.0@2020-01-10, 10.0@2020-01-20, 0.0@2020-01-31}" - ) - stepwise_sequence = TFloatSeq( - "Interp=Step;(1.0@2020-01-01, 3.0@2020-01-10, 10.0@2020-01-20, 0.0@2020-01-31]" - ) - continuous_sequence = TFloatSeq( - "(1.0@2020-01-01, 3.0@2020-01-10, 10.0@2020-01-20, 0.0@2020-01-31]" - ) + discrete_sequence = TFloatSeq("{1.0@2020-01-01, 3.0@2020-01-10, 10.0@2020-01-20, 0.0@2020-01-31}") + stepwise_sequence = TFloatSeq("Interp=Step;(1.0@2020-01-01, 3.0@2020-01-10, 10.0@2020-01-20, 0.0@2020-01-31]") + continuous_sequence = TFloatSeq("(1.0@2020-01-01, 3.0@2020-01-10, 10.0@2020-01-20, 0.0@2020-01-31]") sequence_set = TFloatSeqSet( "{(1.0@2020-01-01, 3.0@2020-01-10, 10.0@2020-01-20, 0.0@2020-01-31], " "(1.0@2021-01-01, 3.0@2021-01-10, 10.0@2021-01-20, 0.0@2021-01-31]}" diff --git a/tests/collections/time/tstzspanset_test.py b/tests/collections/time/tstzspanset_test.py index 777ce227..b129b455 100644 --- a/tests/collections/time/tstzspanset_test.py +++ b/tests/collections/time/tstzspanset_test.py @@ -1,18 +1,17 @@ from copy import copy -from datetime import datetime, timezone, timedelta -from typing import List +from datetime import datetime, timedelta, timezone import pytest from pymeos import ( - TsTzSpan, - TsTzSet, - TsTzSpanSet, + STBox, + TBox, TFloatInst, TFloatSeq, - STBox, TFloatSeqSet, - TBox, + TsTzSet, + TsTzSpan, + TsTzSpanSet, ) from tests.conftest import TestPyMEOS @@ -21,9 +20,7 @@ class TestTsTzSpanSet(TestPyMEOS): tstzspanset = TsTzSpanSet("{[2019-09-01, 2019-09-02], [2019-09-03, 2019-09-04]}") @staticmethod - def assert_tstzspanset_equality( - tstzspanset: TsTzSpanSet, tstzspans: List[TsTzSpan] - ): + def assert_tstzspanset_equality(tstzspanset: TsTzSpanSet, tstzspans: list[TsTzSpan]): assert tstzspanset.num_spans() == len(tstzspans) assert tstzspanset.spans() == tstzspans @@ -67,15 +64,13 @@ def test_copy_constructor(self): class TestTsTzSpanSetOutputs(TestTsTzSpanSet): def test_str(self): assert ( - str(self.tstzspanset) - == "{[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00], " + str(self.tstzspanset) == "{[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00], " "[2019-09-03 00:00:00+00, 2019-09-04 00:00:00+00]}" ) def test_repr(self): assert ( - repr(self.tstzspanset) - == "TsTzSpanSet({[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00], " + repr(self.tstzspanset) == "TsTzSpanSet({[2019-09-01 00:00:00+00, 2019-09-02 00:00:00+00], " "[2019-09-03 00:00:00+00, 2019-09-04 00:00:00+00]})" ) @@ -100,28 +95,16 @@ def test_num_timestamps(self): assert self.tstzspanset2.num_timestamps() == 3 def test_start_timestamp(self): - assert self.tstzspanset.start_timestamp() == datetime( - 2019, 9, 1, tzinfo=timezone.utc - ) + assert self.tstzspanset.start_timestamp() == datetime(2019, 9, 1, tzinfo=timezone.utc) def test_end_timestamp(self): - assert self.tstzspanset.end_timestamp() == datetime( - 2019, 9, 4, tzinfo=timezone.utc - ) + assert self.tstzspanset.end_timestamp() == datetime(2019, 9, 4, tzinfo=timezone.utc) def test_timestamp_n(self): - assert self.tstzspanset.timestamp_n(0) == datetime( - 2019, 9, 1, tzinfo=timezone.utc - ) - assert self.tstzspanset.timestamp_n(1) == datetime( - 2019, 9, 2, tzinfo=timezone.utc - ) - assert self.tstzspanset.timestamp_n(2) == datetime( - 2019, 9, 3, tzinfo=timezone.utc - ) - assert self.tstzspanset.timestamp_n(3) == datetime( - 2019, 9, 4, tzinfo=timezone.utc - ) + assert self.tstzspanset.timestamp_n(0) == datetime(2019, 9, 1, tzinfo=timezone.utc) + assert self.tstzspanset.timestamp_n(1) == datetime(2019, 9, 2, tzinfo=timezone.utc) + assert self.tstzspanset.timestamp_n(2) == datetime(2019, 9, 3, tzinfo=timezone.utc) + assert self.tstzspanset.timestamp_n(3) == datetime(2019, 9, 4, tzinfo=timezone.utc) def test_timestamps(self): assert self.tstzspanset.timestamps() == TsTzSet( @@ -220,9 +203,7 @@ def test_scale(self, delta, result): self.assert_tstzspanset_equality(scaled, result) def test_shift_scale(self): - shifted_scaled = self.tstzspanset.shift_scale( - timedelta(days=4), timedelta(hours=6) - ) + shifted_scaled = self.tstzspanset.shift_scale(timedelta(days=4), timedelta(hours=6)) self.assert_tstzspanset_equality( shifted_scaled, [ @@ -239,15 +220,9 @@ class TestTsTzSpanSetTopologicalPositionFunctions(TestTsTzSpanSet): ) timestamp = datetime(year=2020, month=1, day=1) instant = TFloatInst("1.0@2020-01-01") - discrete_sequence = TFloatSeq( - "{1.0@2020-01-01, 3.0@2020-01-10, 10.0@2020-01-20, 0.0@2020-01-31}" - ) - stepwise_sequence = TFloatSeq( - "Interp=Step;(1.0@2020-01-01, 3.0@2020-01-10, 10.0@2020-01-20, 0.0@2020-01-31]" - ) - continuous_sequence = TFloatSeq( - "(1.0@2020-01-01, 3.0@2020-01-10, 10.0@2020-01-20, 0.0@2020-01-31]" - ) + discrete_sequence = TFloatSeq("{1.0@2020-01-01, 3.0@2020-01-10, 10.0@2020-01-20, 0.0@2020-01-31}") + stepwise_sequence = TFloatSeq("Interp=Step;(1.0@2020-01-01, 3.0@2020-01-10, 10.0@2020-01-20, 0.0@2020-01-31]") + continuous_sequence = TFloatSeq("(1.0@2020-01-01, 3.0@2020-01-10, 10.0@2020-01-20, 0.0@2020-01-31]") sequence_set = TFloatSeqSet( "{(1.0@2020-01-01, 3.0@2020-01-10, 10.0@2020-01-20, 0.0@2020-01-31], " "(1.0@2021-01-01, 3.0@2021-01-10, 10.0@2021-01-20, 0.0@2021-01-31]}" diff --git a/tests/conftest.py b/tests/conftest.py index c22d110e..f2e4372f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,4 @@ -from pymeos import pymeos_initialize, pymeos_finalize +from pymeos import pymeos_finalize, pymeos_initialize def pytest_configure(config): diff --git a/tests/main/tbool_test.py b/tests/main/tbool_test.py index fbcb03fe..92400c62 100644 --- a/tests/main/tbool_test.py +++ b/tests/main/tbool_test.py @@ -1,5 +1,5 @@ from copy import copy -from datetime import datetime, timezone, timedelta +from datetime import datetime, timedelta, timezone import pytest @@ -8,10 +8,10 @@ TBoolInst, TBoolSeq, TBoolSeqSet, + TInterpolation, TIntInst, TIntSeq, TIntSeqSet, - TInterpolation, TsTzSet, TsTzSpan, TsTzSpanSet, @@ -27,9 +27,7 @@ class TestTBoolConstructors(TestTBool): tbi = TBoolInst("True@2019-09-01") tbds = TBoolSeq("{True@2019-09-01, False@2019-09-02}") tbs = TBoolSeq("[True@2019-09-01, False@2019-09-02]") - tbss = TBoolSeqSet( - "{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}" - ) + tbss = TBoolSeqSet("{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}") @pytest.mark.parametrize( "source, type, interpolation", @@ -46,9 +44,7 @@ class TestTBoolConstructors(TestTBool): TInterpolation.STEPWISE, ), ( - TIntSeqSet( - "{[1@2019-09-01, 0@2019-09-02],[1@2019-09-03, 1@2019-09-05]}" - ), + TIntSeqSet("{[1@2019-09-01, 0@2019-09-02],[1@2019-09-03, 1@2019-09-05]}"), TBoolSeqSet, TInterpolation.STEPWISE, ), @@ -231,9 +227,7 @@ def test_value_timestamp_instant_constructor(self, value, timestamp): "Mixed Stepwise Normalized", ], ) - def test_instant_list_sequence_constructor( - self, list, interpolation, normalize, expected - ): + def test_instant_list_sequence_constructor(self, list, interpolation, normalize, expected): tbs = TBoolSeq( instant_list=list, interpolation=interpolation, @@ -243,9 +237,7 @@ def test_instant_list_sequence_constructor( assert str(tbs) == expected assert tbs.interpolation() == interpolation - tbs2 = TBoolSeq.from_instants( - list, interpolation=interpolation, normalize=normalize, upper_inc=True - ) + tbs2 = TBoolSeq.from_instants(list, interpolation=interpolation, normalize=normalize, upper_inc=True) assert str(tbs2) == expected assert tbs2.interpolation() == interpolation @@ -275,9 +267,7 @@ class TestTBoolOutputs(TestTBool): tbi = TBoolInst("True@2019-09-01") tbds = TBoolSeq("{True@2019-09-01, False@2019-09-02}") tbs = TBoolSeq("[True@2019-09-01, False@2019-09-02]") - tbss = TBoolSeqSet( - "{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}" - ) + tbss = TBoolSeqSet("{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}") @pytest.mark.parametrize( "temporal, expected", @@ -465,9 +455,7 @@ class TestTBoolAccessors(TestTBool): tbi = TBoolInst("True@2019-09-01") tbds = TBoolSeq("{True@2019-09-01, False@2019-09-02}") tbs = TBoolSeq("[True@2019-09-01, False@2019-09-02]") - tbss = TBoolSeqSet( - "{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}" - ) + tbss = TBoolSeqSet("{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}") @pytest.mark.parametrize( "temporal, expected", @@ -841,10 +829,8 @@ def test_hash(self, temporal, expected): assert hash(temporal) == expected def test_value_timestamp(self): - assert self.tbi.value() == True - assert self.tbi.timestamp() == datetime( - year=2019, month=9, day=1, tzinfo=timezone.utc - ) + assert self.tbi.value() + assert self.tbi.timestamp() == datetime(year=2019, month=9, day=1, tzinfo=timezone.utc) @pytest.mark.parametrize( "temporal, expected", @@ -860,8 +846,7 @@ def test_lower_upper_inc(self, temporal, expected): def test_sequenceset_sequence_functions(self): tbss1 = TBoolSeqSet( - "{[True@2019-09-01, False@2019-09-02]," - "[True@2019-09-03, True@2019-09-05], [True@2019-09-06]}" + "{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05], [True@2019-09-06]}" ) assert tbss1.num_sequences() == 3 assert tbss1.start_sequence() == TBoolSeq("[True@2019-09-01, False@2019-09-02]") @@ -878,9 +863,7 @@ class TestTBoolTransformations(TestTBool): tbi = TBoolInst("True@2019-09-01") tbds = TBoolSeq("{True@2019-09-01, False@2019-09-02}") tbs = TBoolSeq("[True@2019-09-01, False@2019-09-02]") - tbss = TBoolSeqSet( - "{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}" - ) + tbss = TBoolSeqSet("{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}") @pytest.mark.parametrize( "temporal, expected", @@ -993,16 +976,12 @@ def test_to_sequenceset(self, temporal, interpolation, expected): ( tbss, timedelta(days=4), - TBoolSeqSet( - "{[True@2019-09-05, False@2019-09-06],[True@2019-09-07, True@2019-09-09]}" - ), + TBoolSeqSet("{[True@2019-09-05, False@2019-09-06],[True@2019-09-07, True@2019-09-09]}"), ), ( tbss, timedelta(days=-4), - TBoolSeqSet( - "{[True@2019-08-28, False@2019-08-29],[True@2019-08-30, True@2019-09-01]}" - ), + TBoolSeqSet("{[True@2019-08-28, False@2019-08-29],[True@2019-08-30, True@2019-09-01]}"), ), ( tbss, @@ -1063,9 +1042,7 @@ def test_shift_time(self, tbool, delta, expected): ( tbss, timedelta(days=4), - TBoolSeqSet( - "{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}" - ), + TBoolSeqSet("{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}"), ), ( tbss, @@ -1091,9 +1068,7 @@ def test_scale_time(self, tbool, delta, expected): assert tbool.scale_time(delta) == expected def test_shift_scale_time(self): - assert self.tbss.shift_scale_time( - timedelta(days=4), timedelta(hours=2) - ) == TBoolSeqSet( + assert self.tbss.shift_scale_time(timedelta(days=4), timedelta(hours=2)) == TBoolSeqSet( "{[True@2019-09-05 00:00:00, False@2019-09-05 00:30:00]," "[True@2019-09-05 01:00:00, True@2019-09-05 02:00:00]}" ) @@ -1113,9 +1088,7 @@ def test_shift_scale_time(self): ( tbs, timedelta(hours=12), - TBoolSeq( - "[True@2019-09-01, True@2019-09-01 12:00:00, False@2019-09-02]" - ), + TBoolSeq("[True@2019-09-01, True@2019-09-01 12:00:00, False@2019-09-02]"), ), (tbss, timedelta(days=4), TBoolSeq("{True@2019-09-01,True@2019-09-05}")), ( @@ -1146,9 +1119,7 @@ class TestTBoolModifications(TestTBool): tbi = TBoolInst("True@2019-09-01") tbds = TBoolSeq("{True@2019-09-01, False@2019-09-02}") tbs = TBoolSeq("[True@2019-09-01, False@2019-09-02]") - tbss = TBoolSeqSet( - "{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}" - ) + tbss = TBoolSeqSet("{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}") @pytest.mark.parametrize( "temporal, sequence, expected", @@ -1193,9 +1164,7 @@ def test_insert(self, temporal, sequence, expected): ( tbs, TBoolInst("False@2019-09-01"), - TBoolSeqSet( - "{[False@2019-09-01], (True@2019-09-01, False@2019-09-02]}" - ), + TBoolSeqSet("{[False@2019-09-01], (True@2019-09-01, False@2019-09-02]}"), ), ( tbss, @@ -1228,9 +1197,7 @@ def test_update(self, temporal, instant, expected): ( tbss, datetime(year=2019, month=9, day=1, tzinfo=timezone.utc), - TBoolSeqSet( - "{(True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}" - ), + TBoolSeqSet("{(True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}"), ), ], ids=[ @@ -1265,9 +1232,7 @@ def test_delete(self, temporal, time, expected): ( tbss, TBoolInst("True@2019-09-06"), - TBoolSeqSet( - "{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-06]}" - ), + TBoolSeqSet("{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-06]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1306,9 +1271,7 @@ class TestTBoolManipulationFunctions(TestTBool): tbi = TBoolInst("True@2019-09-01") tbds = TBoolSeq("{True@2019-09-01, False@2019-09-02}") tbs = TBoolSeq("[True@2019-09-01, False@2019-09-02]") - tbss = TBoolSeqSet( - "{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}" - ) + tbss = TBoolSeqSet("{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}") compared = TBoolSeq("[False@2019-09-01, True@2019-09-02, True@2019-09-03]") @pytest.mark.parametrize( @@ -1320,9 +1283,7 @@ class TestTBoolManipulationFunctions(TestTBool): ( tbss, timedelta(days=1), - TBoolSeqSet( - "{[True@2019-09-02, False@2019-09-03],[True@2019-09-04, True@2019-09-06]}" - ), + TBoolSeqSet("{[True@2019-09-02, False@2019-09-03],[True@2019-09-04, True@2019-09-06]}"), ), (tbi, timedelta(days=-1), TBoolInst("True@2019-08-31")), (tbds, timedelta(days=-1), TBoolSeq("{True@2019-08-31, False@2019-09-01}")), @@ -1330,9 +1291,7 @@ class TestTBoolManipulationFunctions(TestTBool): ( tbss, timedelta(days=-1), - TBoolSeqSet( - "{[True@2019-08-31, False@2019-09-01],[True@2019-09-02, True@2019-09-04]}" - ), + TBoolSeqSet("{[True@2019-08-31, False@2019-09-01],[True@2019-09-02, True@2019-09-04]}"), ), ], ids=[ @@ -1358,9 +1317,7 @@ def test_shift_time(self, temporal, shift, expected): ( tbss, timedelta(days=10), - TBoolSeqSet( - "{[True@2019-09-01, False@2019-09-03 12:00:00],[True@2019-09-06, True@2019-09-11]}" - ), + TBoolSeqSet("{[True@2019-09-01, False@2019-09-03 12:00:00],[True@2019-09-06, True@2019-09-11]}"), ), ], ids=[ @@ -1393,9 +1350,7 @@ def test_scale_time(self, temporal, scale, expected): tbss, timedelta(days=1), timedelta(days=10), - TBoolSeqSet( - "{[True@2019-09-02, False@2019-09-04 12:00:00],[True@2019-09-07, True@2019-09-12]}" - ), + TBoolSeqSet("{[True@2019-09-02, False@2019-09-04 12:00:00],[True@2019-09-07, True@2019-09-12]}"), ), (tbi, timedelta(days=-1), timedelta(days=10), TBoolInst("True@2019-08-31")), ( @@ -1414,9 +1369,7 @@ def test_scale_time(self, temporal, scale, expected): tbss, timedelta(days=-1), timedelta(days=10), - TBoolSeqSet( - "{[True@2019-08-31, False@2019-09-02 12:00:00],[True@2019-09-05, True@2019-09-010]}" - ), + TBoolSeqSet("{[True@2019-08-31, False@2019-09-02 12:00:00],[True@2019-09-05, True@2019-09-010]}"), ), ], ids=[ @@ -1438,9 +1391,7 @@ class TestTBoolRestrictors(TestTBool): tbi = TBoolInst("True@2019-09-01") tbds = TBoolSeq("{True@2019-09-01, False@2019-09-02}") tbs = TBoolSeq("[True@2019-09-01, False@2019-09-02]") - tbss = TBoolSeqSet( - "{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}" - ) + tbss = TBoolSeqSet("{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}") timestamp = datetime(2019, 9, 1) timestamp_set = TsTzSet("{2019-09-01, 2019-09-03}") @@ -1500,16 +1451,12 @@ def test_when_false(self, temporal, expected): ( tbss, tstzspan_set, - TBoolSeqSet( - "{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}" - ), + TBoolSeqSet("{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}"), ), ( tbss, True, - TBoolSeqSet( - "{[True@2019-09-01, True@2019-09-02),[True@2019-09-03, True@2019-09-05]}" - ), + TBoolSeqSet("{[True@2019-09-01, True@2019-09-02),[True@2019-09-03, True@2019-09-05]}"), ), (tbss, False, TBoolSeqSet("{[False@2019-09-02]}")), ], @@ -1551,9 +1498,7 @@ def test_at(self, temporal, restrictor, expected): (tbs, TBoolSeq("[True@2019-09-01, True@2019-09-02)")), ( tbss, - TBoolSeqSet( - "{[True@2019-09-01, True@2019-09-02),[True@2019-09-03, True@2019-09-05]}" - ), + TBoolSeqSet("{[True@2019-09-01, True@2019-09-02),[True@2019-09-03, True@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1598,16 +1543,12 @@ def test_at_min(self, temporal, expected): ( tbss, timestamp, - TBoolSeqSet( - "{(True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}" - ), + TBoolSeqSet("{(True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}"), ), ( tbss, timestamp_set, - TBoolSeqSet( - "{(True@2019-09-01, False@2019-09-02],(True@2019-09-03, True@2019-09-05]}" - ), + TBoolSeqSet("{(True@2019-09-01, False@2019-09-02],(True@2019-09-03, True@2019-09-05]}"), ), (tbss, tstzspan, TBoolSeqSet("{[True@2019-09-03, True@2019-09-05]}")), (tbss, tstzspan_set, None), @@ -1615,9 +1556,7 @@ def test_at_min(self, temporal, expected): ( tbss, False, - TBoolSeqSet( - "{[True@2019-09-01, True@2019-09-02),[True@2019-09-03, True@2019-09-05]}" - ), + TBoolSeqSet("{[True@2019-09-01, True@2019-09-02),[True@2019-09-03, True@2019-09-05]}"), ), ], ids=[ @@ -1671,9 +1610,7 @@ def test_minus_max(self, temporal, expected): (tbs, TBoolSeq("[True@2019-09-01, True@2019-09-02)")), ( tbss, - TBoolSeqSet( - "{[True@2019-09-01, True@2019-09-02),[True@2019-09-03, True@2019-09-05]}" - ), + TBoolSeqSet("{[True@2019-09-01, True@2019-09-02),[True@2019-09-03, True@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1737,10 +1674,7 @@ def test_minus_min(self, temporal, expected): ], ) def test_at_minus(self, temporal, restrictor): - assert ( - TBool.from_merge(temporal.at(restrictor), temporal.minus(restrictor)) - == temporal - ) + assert TBool.from_merge(temporal.at(restrictor), temporal.minus(restrictor)) == temporal @pytest.mark.parametrize( "temporal", @@ -1754,9 +1688,7 @@ def test_at_minus_min_max(self, temporal): class TestTBoolComparisons(TestTBool): tb = TBoolSeq("[True@2019-09-01, False@2019-09-02]") - other = TBoolSeqSet( - "{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}" - ) + other = TBoolSeqSet("{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}") def test_eq(self): _ = self.tb == self.other @@ -1781,9 +1713,7 @@ class TestTBoolEverAlwaysComparisons(TestTBool): tbi = TBoolInst("True@2019-09-01") tbds = TBoolSeq("{True@2019-09-01, False@2019-09-02}") tbs = TBoolSeq("[True@2019-09-01, False@2019-09-02]") - tbss = TBoolSeqSet( - "{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}" - ) + tbss = TBoolSeqSet("{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}") @pytest.mark.parametrize( "temporal, expected", @@ -1838,9 +1768,7 @@ class TestTBoolTemporalComparisons(TestTBool): tbi = TBoolInst("True@2019-09-01") tbds = TBoolSeq("{True@2019-09-01, False@2019-09-02}") tbs = TBoolSeq("[True@2019-09-01, False@2019-09-02]") - tbss = TBoolSeqSet( - "{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}" - ) + tbss = TBoolSeqSet("{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}") compared = TBoolSeq("[False@2019-09-01, True@2019-09-02, True@2019-09-03]") @pytest.mark.parametrize( @@ -1851,9 +1779,7 @@ class TestTBoolTemporalComparisons(TestTBool): (tbs, TBoolSeq("[False@2019-09-01, True@2019-09-02]")), ( tbss, - TBoolSeqSet( - "{[False@2019-09-01, True@2019-09-02],[False@2019-09-03, False@2019-09-05]}" - ), + TBoolSeqSet("{[False@2019-09-01, True@2019-09-02],[False@2019-09-03, False@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], diff --git a/tests/main/tfloat_test.py b/tests/main/tfloat_test.py index 7be97ad5..0f212f65 100644 --- a/tests/main/tfloat_test.py +++ b/tests/main/tfloat_test.py @@ -1,30 +1,30 @@ from copy import copy -from datetime import datetime, timezone, timedelta +from datetime import datetime, timedelta, timezone from operator import not_ import pytest from pymeos_cffi import MeosInvalidArgValueError from pymeos import ( + FloatSet, + FloatSpan, + FloatSpanSet, TBoolInst, TBoolSeq, TBoolSeqSet, + TBox, TFloat, TFloatInst, TFloatSeq, TFloatSeqSet, TInt, + TInterpolation, TIntInst, TIntSeq, TIntSeqSet, - TInterpolation, - TBox, TsTzSet, TsTzSpan, TsTzSpanSet, - FloatSpan, - FloatSpanSet, - FloatSet, ) from tests.conftest import TestPyMEOS @@ -37,13 +37,9 @@ class TestTFloatConstructors(TestTFloat): tfi = TFloatInst("1.5@2019-09-01") tfds = TFloatSeq("{1.5@2019-09-01, 2.5@2019-09-02}") tfs = TFloatSeq("[1.5@2019-09-01, 2.5@2019-09-02]") - tfss = TFloatSeqSet( - "{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ) + tfss = TFloatSeqSet("{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}") tfsts = TFloatSeq("Interp=Step;[1.5@2019-09-01, 2.5@2019-09-02]") - tfstss = TFloatSeqSet( - "Interp=Step;{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ) + tfstss = TFloatSeqSet("Interp=Step;{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}") @pytest.mark.parametrize( "source, type, interpolation", @@ -56,9 +52,7 @@ class TestTFloatConstructors(TestTFloat): ), (TIntSeq("[1@2019-09-01, 2@2019-09-02]"), TFloatSeq, TInterpolation.LINEAR), ( - TIntSeqSet( - "{[1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05]}" - ), + TIntSeqSet("{[1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05]}"), TFloatSeqSet, TInterpolation.LINEAR, ), @@ -241,9 +235,7 @@ def test_value_timestamp_instant_constructor(self, value, timestamp): "Mixed Linear Normalized", ], ) - def test_instant_list_sequence_constructor( - self, list, interpolation, normalize, expected - ): + def test_instant_list_sequence_constructor(self, list, interpolation, normalize, expected): tfs = TFloatSeq( instant_list=list, interpolation=interpolation, @@ -253,9 +245,7 @@ def test_instant_list_sequence_constructor( assert str(tfs) == expected assert tfs.interpolation() == interpolation - tfs2 = TFloatSeq.from_instants( - list, interpolation=interpolation, normalize=normalize, upper_inc=True - ) + tfs2 = TFloatSeq.from_instants(list, interpolation=interpolation, normalize=normalize, upper_inc=True) assert str(tfs2) == expected assert tfs2.interpolation() == interpolation @@ -299,13 +289,9 @@ class TestTFloatOutputs(TestTFloat): tfi = TFloatInst("1.5@2019-09-01") tfds = TFloatSeq("{1.5@2019-09-01, 2.5@2019-09-02}") tfs = TFloatSeq("[1.5@2019-09-01, 2.5@2019-09-02]") - tfss = TFloatSeqSet( - "{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ) + tfss = TFloatSeqSet("{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}") tfsts = TFloatSeq("Interp=Step;[1.5@2019-09-01, 2.5@2019-09-02]") - tfstss = TFloatSeqSet( - "Interp=Step;{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ) + tfstss = TFloatSeqSet("Interp=Step;{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}") @pytest.mark.parametrize( "temporal, expected", @@ -537,13 +523,9 @@ class TestTFloatConversions(TestTFloat): tfi = TFloatInst("1.5@2019-09-01") tfds = TFloatSeq("{1.5@2019-09-01, 2.5@2019-09-02}") tfs = TFloatSeq("[1.5@2019-09-01, 2.5@2019-09-02]") - tfss = TFloatSeqSet( - "{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ) + tfss = TFloatSeqSet("{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}") tfsts = TFloatSeq("Interp=Step;[1.5@2019-09-01, 2.5@2019-09-02]") - tfstss = TFloatSeqSet( - "Interp=Step;{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ) + tfstss = TFloatSeqSet("Interp=Step;{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}") @pytest.mark.parametrize( "temporal, expected", @@ -568,13 +550,9 @@ class TestTFloatAccessors(TestTFloat): tfi = TFloatInst("1.5@2019-09-01") tfds = TFloatSeq("{1.5@2019-09-01, 2.5@2019-09-02}") tfs = TFloatSeq("[1.5@2019-09-01, 2.5@2019-09-02]") - tfss = TFloatSeqSet( - "{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ) + tfss = TFloatSeqSet("{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}") tfsts = TFloatSeq("Interp=Step;[1.5@2019-09-01, 2.5@2019-09-02]") - tfstss = TFloatSeqSet( - "Interp=Step;{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ) + tfstss = TFloatSeqSet("Interp=Step;{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}") @pytest.mark.parametrize( "temporal, expected", @@ -1001,9 +979,7 @@ def test_hash(self, temporal, expected): def test_value_timestamp(self): assert self.tfi.value() == 1.5 - assert self.tfi.timestamp() == datetime( - year=2019, month=9, day=1, tzinfo=timezone.utc - ) + assert self.tfi.timestamp() == datetime(year=2019, month=9, day=1, tzinfo=timezone.utc) @pytest.mark.parametrize( "temporal, expected", @@ -1019,10 +995,7 @@ def test_lower_upper_inc(self, temporal, expected): assert temporal.upper_inc() == expected def test_sequenceset_sequence_functions(self): - tfss1 = TFloatSeqSet( - "{[1@2019-09-01, 2@2019-09-02]," - "[1@2019-09-03, 1@2019-09-05], [3@2019-09-06]}" - ) + tfss1 = TFloatSeqSet("{[1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05], [3@2019-09-06]}") assert tfss1.num_sequences() == 3 assert tfss1.start_sequence() == TFloatSeq("[1@2019-09-01, 2@2019-09-02]") assert tfss1.end_sequence() == TFloatSeq("[3@2019-09-06]") @@ -1065,24 +1038,15 @@ class TestTFloatTransformations(TestTFloat): tfds = TFloatSeq("{1.5@2019-09-01, 2.5@2019-09-02}") tfs = TFloatSeq("[1.5@2019-09-01, 2.5@2019-09-02]") tfsts = TFloatSeq("Interp=Step;[1.5@2019-09-01, 2.5@2019-09-02]") - tfss = TFloatSeqSet( - "{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ) - tfstss = TFloatSeqSet( - "Interp=Step;{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ) + tfss = TFloatSeqSet("{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}") + tfstss = TFloatSeqSet("Interp=Step;{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}") tfs_d = TFloatSeq("[1.5@2019-09-01]") tfss_d = TFloatSeqSet("{[1.5@2019-09-01],[2.5@2019-09-03]}") tfs_s = TFloatSeq("[1.5@2019-09-01, 1.5@2019-09-02]") - tfss_s = TFloatSeqSet( - "{[1.5@2019-09-01, 1.5@2019-09-02]," "[2.5@2019-09-03, 2.5@2019-09-05]}" - ) + tfss_s = TFloatSeqSet("{[1.5@2019-09-01, 1.5@2019-09-02],[2.5@2019-09-03, 2.5@2019-09-05]}") tfs_l = TFloatSeq("Interp=Step;[1.5@2019-09-01, 2.5@2019-09-02]") - tfss_l = TFloatSeqSet( - "Interp=Step;{[1.5@2019-09-01, 2.5@2019-09-02]," - "[1.5@2019-09-03, 1.5@2019-09-05]}" - ) + tfss_l = TFloatSeqSet("Interp=Step;{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}") @pytest.mark.parametrize( "temporal, expected", @@ -1186,10 +1150,7 @@ def test_to_sequenceset(self, temporal, interpolation, expected): ( tfss_s, TInterpolation.STEPWISE, - TFloatSeqSet( - "Interp=Step;{[1.5@2019-09-01, 1.5@2019-09-02]," - "[2.5@2019-09-03, 2.5@2019-09-05]}" - ), + TFloatSeqSet("Interp=Step;{[1.5@2019-09-01, 1.5@2019-09-02],[2.5@2019-09-03, 2.5@2019-09-05]}"), ), (tfi, TInterpolation.LINEAR, TFloatSeq("[1.5@2019-09-01]")), ( @@ -1205,10 +1166,7 @@ def test_to_sequenceset(self, temporal, interpolation, expected): ( tfss_l, TInterpolation.LINEAR, - TFloatSeqSet( - "{[1.5@2019-09-01, 1.5@2019-09-02)," - "[2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ), + TFloatSeqSet("{[1.5@2019-09-01, 1.5@2019-09-02),[2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}"), ), ], ids=[ @@ -1241,18 +1199,12 @@ def test_set_interpolation(self, temporal, interpolation, expected): ( tfss, 2, - TFloatSeqSet( - "{[3.5@2019-09-01, 4.5@2019-09-02]," - "[3.5@2019-09-03, 3.5@2019-09-05]}" - ), + TFloatSeqSet("{[3.5@2019-09-01, 4.5@2019-09-02],[3.5@2019-09-03, 3.5@2019-09-05]}"), ), ( tfss, -2, - TFloatSeqSet( - "{[-0.5@2019-09-01, 0.5@2019-09-02]," - "[-0.5@2019-09-03, -0.5@2019-09-05]}" - ), + TFloatSeqSet("{[-0.5@2019-09-01, 0.5@2019-09-02],[-0.5@2019-09-03, -0.5@2019-09-05]}"), ), ], ids=[ @@ -1278,10 +1230,7 @@ def test_shift_value(self, tfloat, delta, expected): ( tfss, 4, - TFloatSeqSet( - "{[1.5@2019-09-01, 5.5@2019-09-02]," - "[1.5@2019-09-03, 1.5@2019-09-05]}" - ), + TFloatSeqSet("{[1.5@2019-09-01, 5.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}"), ), ], ids=[ @@ -1307,19 +1256,13 @@ def test_scale_value(self, tfloat, width, expected): tfss, 2, 3, - TFloatSeqSet( - "{[3.5@2019-09-01, 6.5@2019-09-02]," - "[3.5@2019-09-03, 3.5@2019-09-05]}" - ), + TFloatSeqSet("{[3.5@2019-09-01, 6.5@2019-09-02],[3.5@2019-09-03, 3.5@2019-09-05]}"), ), ( tfss, -2, 3, - TFloatSeqSet( - "{[-0.5@2019-09-01, 2.5@2019-09-02]," - "[-0.5@2019-09-03, -0.5@2019-09-05]}" - ), + TFloatSeqSet("{[-0.5@2019-09-01, 2.5@2019-09-02],[-0.5@2019-09-03, -0.5@2019-09-05]}"), ), ], ids=[ @@ -1370,16 +1313,12 @@ def test_shift_scale_value(self, tfloat, delta, width, expected): ( tfss, timedelta(days=4), - TFloatSeqSet( - "{[1.5@2019-09-05, 2.5@2019-09-06],[1.5@2019-09-07, 1.5@2019-09-09]}" - ), + TFloatSeqSet("{[1.5@2019-09-05, 2.5@2019-09-06],[1.5@2019-09-07, 1.5@2019-09-09]}"), ), ( tfss, timedelta(days=-4), - TFloatSeqSet( - "{[1.5@2019-08-28, 2.5@2019-08-29],[1.5@2019-08-30, 1.5@2019-09-01]}" - ), + TFloatSeqSet("{[1.5@2019-08-28, 2.5@2019-08-29],[1.5@2019-08-30, 1.5@2019-09-01]}"), ), ( tfss, @@ -1440,9 +1379,7 @@ def test_shift_time(self, tfloat, delta, expected): ( tfss, timedelta(days=4), - TFloatSeqSet( - "{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ), + TFloatSeqSet("{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}"), ), ( tfss, @@ -1468,11 +1405,8 @@ def test_scale_time(self, tfloat, delta, expected): assert tfloat.scale_time(delta) == expected def test_shift_scale_time(self): - assert self.tfss.shift_scale_time( - timedelta(days=4), timedelta(hours=2) - ) == TFloatSeqSet( - "{[1.5@2019-09-05 00:00:00, 2.5@2019-09-05 00:30:00]," - "[1.5@2019-09-05 01:00:00, 1.5@2019-09-05 02:00:00]}" + assert self.tfss.shift_scale_time(timedelta(days=4), timedelta(hours=2)) == TFloatSeqSet( + "{[1.5@2019-09-05 00:00:00, 2.5@2019-09-05 00:30:00],[1.5@2019-09-05 01:00:00, 1.5@2019-09-05 02:00:00]}" ) @pytest.mark.parametrize( @@ -1527,17 +1461,14 @@ def test_temporal_sample(self, tfloat, delta, expected): ( tfs, timedelta(hours=12), - TFloatSeq( - "{[1.75@2019-09-01, 2.25@2019-09-01 12:00:00+00, 2.5@2019-09-02]}" - ), + TFloatSeq("{[1.75@2019-09-01, 2.25@2019-09-01 12:00:00+00, 2.5@2019-09-02]}"), ), (tfss, timedelta(days=4), TFloatSeq("{[1.75@2019-08-31, 1.5@2019-09-04]}")), ( tfss, timedelta(hours=12), TFloatSeq( - "{[1.75@2019-09-01, 2.25@2019-09-01 12:00:00, 2.5@2019-09-02]," - "[1.5@2019-09-03, 1.5@2019-09-05]}" + "{[1.75@2019-09-01, 2.25@2019-09-01 12:00:00, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" ), ), ], @@ -1578,7 +1509,7 @@ def test_stops(self, tfloat, delta, expected): [ (TFloatInst("1.123456789@2019-09-01"), TFloatInst("1.12@2019-09-01")), ( - TFloatSeq("{1.123456789@2019-09-01," "2.123456789@2019-09-02}"), + TFloatSeq("{1.123456789@2019-09-01,2.123456789@2019-09-02}"), TFloatSeq("{1.12@2019-09-01, 2.12@2019-09-02}"), ), ( @@ -1590,10 +1521,7 @@ def test_stops(self, tfloat, delta, expected): "{[1.123456789@2019-09-01, 2.123456789@2019-09-02]," "[1.123456789@2019-09-03, 1.123456789@2019-09-05]}" ), - TFloatSeq( - "{[1.12@2019-09-01, 2.12@2019-09-02]," - "[1.12@2019-09-03, 1.12@2019-09-05]}" - ), + TFloatSeq("{[1.12@2019-09-01, 2.12@2019-09-02],[1.12@2019-09-03, 1.12@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1606,9 +1534,7 @@ class TestTFloatModifications(TestTFloat): tfi = TFloatInst("1.5@2019-09-01") tfds = TFloatSeq("{1.5@2019-09-01, 2.5@2019-09-02}") tfs = TFloatSeq("[1.5@2019-09-01, 2.5@2019-09-02]") - tfss = TFloatSeqSet( - "{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ) + tfss = TFloatSeqSet("{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}") @pytest.mark.parametrize( "temporal, sequence, expected", @@ -1631,9 +1557,7 @@ class TestTFloatModifications(TestTFloat): ( tfss, TFloatSeq("[1.5@2019-09-06]"), - TFloatSeqSet( - "{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05],[1.5@2019-09-06]}" - ), + TFloatSeqSet("{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05],[1.5@2019-09-06]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1658,9 +1582,7 @@ def test_insert(self, temporal, sequence, expected): ( tfss, TFloatInst("2.5@2019-09-01"), - TFloatSeqSet( - "{[2.5@2019-09-01], (1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ), + TFloatSeqSet("{[2.5@2019-09-01], (1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1686,9 +1608,7 @@ def test_update(self, temporal, instant, expected): ( tfss, datetime(year=2019, month=9, day=1, tzinfo=timezone.utc), - TFloatSeqSet( - "{(1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ), + TFloatSeqSet("{(1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}"), ), ], ids=[ @@ -1723,9 +1643,7 @@ def test_delete(self, temporal, time, expected): ( tfss, TFloatInst("1.5@2019-09-06"), - TFloatSeqSet( - "{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-06]}" - ), + TFloatSeqSet("{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-06]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1749,9 +1667,7 @@ def test_append_instant(self, temporal, instant, expected): ( tfss, TFloatSeq("[1.5@2019-09-06]"), - TFloatSeqSet( - "{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05],[1.5@2019-09-06]}" - ), + TFloatSeqSet("{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05],[1.5@2019-09-06]}"), ), ], ids=["Discrete Sequence", "Sequence", "SequenceSet"], @@ -1764,9 +1680,7 @@ class TestTFloatMathematicalOperations(TestTFloat): tfi = TFloatInst("1.5@2019-09-01") tfds = TFloatSeq("{1.5@2019-09-01, 2.5@2019-09-02}") tfs = TFloatSeq("[1.5@2019-09-01, 2.5@2019-09-02]") - tfss = TFloatSeqSet( - "{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ) + tfss = TFloatSeqSet("{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}") tfloatarg = TFloatSeq("[2.5@2019-09-01, 1.5@2019-09-02, 1.5@2019-09-03]") @pytest.mark.parametrize( @@ -1796,9 +1710,7 @@ def test_temporal_add_temporal(self, temporal, argument, expected): ( tfss, 1, - TFloatSeqSet( - "{[2.5@2019-09-01, 3.5@2019-09-02],[2.5@2019-09-03, 2.5@2019-09-05]}" - ), + TFloatSeqSet("{[2.5@2019-09-01, 3.5@2019-09-02],[2.5@2019-09-03, 2.5@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1836,9 +1748,7 @@ def test_temporal_sub_temporal(self, temporal, argument, expected): ( tfss, 1, - TFloatSeqSet( - "{[0.5@2019-09-01, 1.5@2019-09-02],[0.5@2019-09-03, 0.5@2019-09-05]}" - ), + TFloatSeqSet("{[0.5@2019-09-01, 1.5@2019-09-02],[0.5@2019-09-03, 0.5@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1857,16 +1767,12 @@ def test_temporal_sub_int_float(self, temporal, argument, expected): ( tfs, tfloatarg, - TFloatSeqSet( - "{[3.75@2019-09-01, 4@2019-09-01 12:00:00+00, 3.75@2019-09-02]}" - ), + TFloatSeqSet("{[3.75@2019-09-01, 4@2019-09-01 12:00:00+00, 3.75@2019-09-02]}"), ), ( tfss, tfloatarg, - TFloatSeqSet( - "{[3.75@2019-09-01, 4@2019-09-01 12:00:00+00, 3.75@2019-09-02], [2.25@2019-09-03]}" - ), + TFloatSeqSet("{[3.75@2019-09-01, 4@2019-09-01 12:00:00+00, 3.75@2019-09-02], [2.25@2019-09-03]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1892,9 +1798,7 @@ def test_temporal_mul_temporal(self, temporal, argument, expected): ( tfss, 2, - TFloatSeqSet( - "{[3@2019-09-01, 5@2019-09-02],[3@2019-09-03, 3@2019-09-05]}" - ), + TFloatSeqSet("{[3@2019-09-01, 5@2019-09-02],[3@2019-09-03, 3@2019-09-05]}"), ), ], ids=[ @@ -1926,16 +1830,12 @@ def test_temporal_mul_int_float(self, temporal, argument, expected): ( tfs, tfloatarg, - TFloatSeqSet( - "{[0.6@2019-09-01, 1@2019-09-01 12:00:00+00, 1.667@2019-09-02]}" - ), + TFloatSeqSet("{[0.6@2019-09-01, 1@2019-09-01 12:00:00+00, 1.667@2019-09-02]}"), ), ( tfss, tfloatarg, - TFloatSeqSet( - "{[0.6@2019-09-01, 1@2019-09-01 12:00:00+00, 1.667@2019-09-02], [1@2019-09-03]}" - ), + TFloatSeqSet("{[0.6@2019-09-01, 1@2019-09-01 12:00:00+00, 1.667@2019-09-02], [1@2019-09-03]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1957,9 +1857,7 @@ def test_temporal_div_temporal(self, temporal, argument, expected): ( tfss, 2, - TFloatSeqSet( - "{[0.75@2019-09-01, 1.25@2019-09-02],[0.75@2019-09-03, 0.75@2019-09-05]}" - ), + TFloatSeqSet("{[0.75@2019-09-01, 1.25@2019-09-02],[0.75@2019-09-03, 0.75@2019-09-05]}"), ), ], ids=[ @@ -1994,9 +1892,7 @@ def test_abs(self, temporal): (tfs, TFloatSeq("Interp=Step;[1@2019-09-01, 1@2019-09-02)")), ( tfss, - TFloatSeqSet( - "Interp=Step;{[1@2019-09-01, 1@2019-09-02),[0@2019-09-03, 0@2019-09-05)}" - ), + TFloatSeqSet("Interp=Step;{[1@2019-09-01, 1@2019-09-02),[0@2019-09-03, 0@2019-09-05)}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -2015,9 +1911,7 @@ def test_delta_value(self, temporal, expected): (tfs, TFloatSeq("[0.0262@2019-09-01, 0.0436@2019-09-02]")), ( tfss, - TFloatSeqSet( - "{[0.0262@2019-09-01, 0.0436@2019-09-02],[0.0262@2019-09-03, 0.0262@2019-09-05]}" - ), + TFloatSeqSet("{[0.0262@2019-09-01, 0.0436@2019-09-02],[0.0262@2019-09-03, 0.0262@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -2039,9 +1933,7 @@ def test_to_radians_to_degrees(self, temporal): (tfs, TFloatSeq("Interp=Step;[1@2019-09-01, 1@2019-09-02]")), ( tfss, - TFloatSeqSet( - "Interp=Step;{[1@2019-09-01, 1@2019-09-02],[0@2019-09-03, 0@2019-09-05]}" - ), + TFloatSeqSet("Interp=Step;{[1@2019-09-01, 1@2019-09-02],[0@2019-09-03, 0@2019-09-05]}"), ), ], ids=["Sequence", "SequenceSet"], @@ -2063,9 +1955,7 @@ class TestTFloatRestrictors(TestTFloat): tfi = TFloatInst("1.5@2019-09-01") tfds = TFloatSeq("{1.5@2019-09-01, 2.5@2019-09-02}") tfs = TFloatSeq("[1.5@2019-09-01, 2.5@2019-09-02]") - tfss = TFloatSeqSet( - "{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ) + tfss = TFloatSeqSet("{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}") timestamp = datetime(2019, 9, 1) timestamp_set = TsTzSet("{2019-09-01, 2019-09-03}") @@ -2093,9 +1983,7 @@ class TestTFloatRestrictors(TestTFloat): ( tfss, tstzspan_set, - TFloatSeqSet( - "{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ), + TFloatSeqSet("{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}"), ), ], ids=[ @@ -2161,9 +2049,7 @@ def test_at_time(self, temporal, restrictor, expected): FloatSpan(lower=2.5, upper=2.5, lower_inc=True, upper_inc=True), ] ), - TFloatSeqSet( - "{1.5@2019-09-01 00:00:00+00, 2.5@2019-09-02 00:00:00+00}" - ), + TFloatSeqSet("{1.5@2019-09-01 00:00:00+00, 2.5@2019-09-02 00:00:00+00}"), ), (tfs, 1.5, TFloatSeq("[1.5@2019-09-01]")), (tfs, 2.5, TFloatSeq("[2.5@2019-09-02]")), @@ -2185,9 +2071,7 @@ def test_at_time(self, temporal, restrictor, expected): FloatSpan(lower=2.5, upper=2.5, lower_inc=True, upper_inc=True), ] ), - TFloatSeq( - "{[1.5@2019-09-01 00:00:00+00], [2.5@2019-09-02 00:00:00+00]}" - ), + TFloatSeq("{[1.5@2019-09-01 00:00:00+00], [2.5@2019-09-02 00:00:00+00]}"), ), ( tfss, @@ -2198,10 +2082,7 @@ def test_at_time(self, temporal, restrictor, expected): ( tfss, FloatSet(elements=[1.5, 2.5]), - TFloatSeqSet( - "{[1.5@2019-09-01], [2.5@2019-09-02]," - "[1.5@2019-09-03, 1.5@2019-09-05]}" - ), + TFloatSeqSet("{[1.5@2019-09-01], [2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}"), ), ( tfss, @@ -2291,16 +2172,12 @@ def test_at_max(self, temporal, expected): ( tfss, timestamp, - TFloatSeqSet( - "{(1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ), + TFloatSeqSet("{(1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}"), ), ( tfss, timestamp_set, - TFloatSeqSet( - "{(1.5@2019-09-01, 2.5@2019-09-02],(1.5@2019-09-03, 1.5@2019-09-05]}" - ), + TFloatSeqSet("{(1.5@2019-09-01, 2.5@2019-09-02],(1.5@2019-09-03, 1.5@2019-09-05]}"), ), (tfss, tstzspan, TFloatSeqSet("{[1.5@2019-09-03, 1.5@2019-09-05]}")), (tfss, tstzspan_set, None), @@ -2367,9 +2244,7 @@ def test_minus_time(self, temporal, restrictor, expected): ( tfss, 2.5, - TFloatSeqSet( - "{[1.5@2019-09-01, 2.5@2019-09-02),[1.5@2019-09-03, 1.5@2019-09-05]}" - ), + TFloatSeqSet("{[1.5@2019-09-01, 2.5@2019-09-02),[1.5@2019-09-03, 1.5@2019-09-05]}"), ), ( tfs, @@ -2428,9 +2303,7 @@ def test_minus_min(self, temporal, expected): (tfs, TFloatSeq("{[1.5@2019-09-01, 2.5@2019-09-02)}")), ( tfss, - TFloatSeqSet( - "{[1.5@2019-09-01, 2.5@2019-09-02), [1.5@2019-09-03, 1.5@2019-09-05]}" - ), + TFloatSeqSet("{[1.5@2019-09-01, 2.5@2019-09-02), [1.5@2019-09-03, 1.5@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -2478,10 +2351,7 @@ def test_minus_max(self, temporal, expected): ], ) def test_at_minus_time(self, temporal, restrictor): - assert ( - TFloat.merge(temporal.at(restrictor), temporal.minus(restrictor)) - == temporal - ) + assert TFloat.merge(temporal.at(restrictor), temporal.minus(restrictor)) == temporal @pytest.mark.parametrize( "temporal, restrictor", @@ -2563,10 +2433,7 @@ def test_at_minus_time(self, temporal, restrictor): ], ) def test_at_minus_values(self, temporal, restrictor): - assert ( - TFloat.from_merge(temporal.at(restrictor), temporal.minus(restrictor)) - == temporal - ) + assert TFloat.from_merge(temporal.at(restrictor), temporal.minus(restrictor)) == temporal @pytest.mark.parametrize( "temporal", @@ -2950,9 +2817,7 @@ class TestTFloatSplitOperations(TestTFloat): ( tfss, [ - TFloatSeqSet( - "{[1@2019-09-01, 2@2019-09-02),[1@2019-09-03, 1@2019-09-05]}" - ), + TFloatSeqSet("{[1@2019-09-01, 2@2019-09-02),[1@2019-09-03, 1@2019-09-05]}"), TFloatSeqSet("{[2@2019-09-02]}"), ], ), @@ -3030,17 +2895,12 @@ def test_time_split_n(self, temporal, expected): ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], ) def test_value_time_split(self, temporal, expected): - assert ( - temporal.value_time_split(2.0, timedelta(days=2), 0.0, "2019-09-01") - == expected - ) + assert temporal.value_time_split(2.0, timedelta(days=2), 0.0, "2019-09-01") == expected class TestTFloatComparisons(TestTFloat): tf = TFloatSeq("[1.5@2019-09-01, 2.5@2019-09-02]") - other = TFloatSeqSet( - "{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ) + other = TFloatSeqSet("{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}") def test_eq(self): _ = self.tf == self.other @@ -3065,9 +2925,7 @@ class TestTFloatEverAlwaysComparisons(TestTFloat): tfi = TFloatInst("1.5@2019-09-01") tfds = TFloatSeq("{1.5@2019-09-01,2.5@2019-09-02}") tfs = TFloatSeq("[1.5@2019-09-01,2.5@2019-09-02]") - tfss = TFloatSeqSet( - "{[1.5@2019-09-01,2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ) + tfss = TFloatSeqSet("{[1.5@2019-09-01,2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}") @pytest.mark.parametrize( "temporal, argument, expected", @@ -3242,9 +3100,7 @@ class TestTFloatTemporalComparisons(TestTFloat): tfi = TFloatInst("1.5@2019-09-01") tfds = TFloatSeq("{1.5@2019-09-01, 2.5@2019-09-02}") tfs = TFloatSeq("[1.5@2019-09-01, 2.5@2019-09-02]") - tfss = TFloatSeqSet( - "{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ) + tfss = TFloatSeqSet("{[1.5@2019-09-01, 2.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}") tintarg = TIntSeq("[2@2019-09-01, 1@2019-09-02, 1@2019-09-03]") tfloatarg = TFloatSeq("[2.5@2019-09-01, 1.5@2019-09-02, 1.5@2019-09-03]") @@ -3256,8 +3112,7 @@ class TestTFloatTemporalComparisons(TestTFloat): ( tfs, TBoolSeqSet( - "{[False@2019-09-01, True@2019-09-01 12:00:00+00]," - "(False@2019-09-01 12:00:00+00, False@2019-09-02]}" + "{[False@2019-09-01, True@2019-09-01 12:00:00+00],(False@2019-09-01 12:00:00+00, False@2019-09-02]}" ), ), ( @@ -3281,15 +3136,13 @@ def test_temporal_equal_temporal(self, temporal, expected): (tfs, TBoolSeq("[True@2019-09-01, False@2019-09-02]")), ( tfss, - TBoolSeqSet( - "{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}" - ), + TBoolSeqSet("{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], ) def test_temporal_equal_int(self, temporal, expected): - assert temporal.temporal_equal(1) == expected + assert temporal.temporal_equal_1(1) == expected @pytest.mark.parametrize( "temporal, expected", @@ -3312,7 +3165,7 @@ def test_temporal_equal_int(self, temporal, expected): ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], ) - def test_temporal_equal_int(self, temporal, expected): + def test_temporal_equal_int_2(self, temporal, expected): assert temporal.temporal_equal(2) == expected @pytest.mark.parametrize( @@ -3326,14 +3179,12 @@ def test_temporal_equal_int(self, temporal, expected): ), ( tfss, - TBoolSeqSet( - "{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}" - ), + TBoolSeqSet("{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], ) - def test_temporal_equal_float(self, temporal, expected): + def test_temporal_equal_float_1_5(self, temporal, expected): assert temporal.temporal_equal(1.5) == expected @pytest.mark.parametrize( @@ -3344,14 +3195,12 @@ def test_temporal_equal_float(self, temporal, expected): (tfs, TBoolSeq("[False@2019-09-01, True@2019-09-02]")), ( tfss, - TBoolSeqSet( - "{[False@2019-09-01, True@2019-09-02],[False@2019-09-03, False@2019-09-05]}" - ), + TBoolSeqSet("{[False@2019-09-01, True@2019-09-02],[False@2019-09-03, False@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], ) - def test_temporal_equal_float(self, temporal, expected): + def test_temporal_equal_float_2_5(self, temporal, expected): assert temporal.temporal_equal(2.5) == expected @pytest.mark.parametrize( @@ -3362,8 +3211,7 @@ def test_temporal_equal_float(self, temporal, expected): ( tfs, TBoolSeqSet( - "{[True@2019-09-01, False@2019-09-01 12:00:00+00]," - "(True@2019-09-01 12:00:00+00, True@2019-09-02]}" + "{[True@2019-09-01, False@2019-09-01 12:00:00+00],(True@2019-09-01 12:00:00+00, True@2019-09-02]}" ), ), ( @@ -3387,14 +3235,12 @@ def test_temporal_not_equal_temporal(self, temporal, expected): (tfs, TBoolSeq("[False@2019-09-01, True@2019-09-02]")), ( tfss, - TBoolSeqSet( - "{[False@2019-09-01, True@2019-09-02],[False@2019-09-03, False@2019-09-05]}" - ), + TBoolSeqSet("{[False@2019-09-01, True@2019-09-02],[False@2019-09-03, False@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], ) - def test_temporal_not_equal_int(self, temporal, expected): + def test_temporal_not_equal_int_1(self, temporal, expected): assert temporal.temporal_not_equal(1) == expected @pytest.mark.parametrize( @@ -3405,8 +3251,7 @@ def test_temporal_not_equal_int(self, temporal, expected): ( tfs, TBoolSeqSet( - "{[True@2019-09-01, False@2019-09-01 12:00:00]," - "(True@2019-09-01 12:00:00, True@2019-09-02]}" + "{[True@2019-09-01, False@2019-09-01 12:00:00],(True@2019-09-01 12:00:00, True@2019-09-02]}" ), ), ( @@ -3419,5 +3264,5 @@ def test_temporal_not_equal_int(self, temporal, expected): ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], ) - def test_temporal_not_equal_int(self, temporal, expected): + def test_temporal_not_equal_int_2(self, temporal, expected): assert temporal.temporal_not_equal(2) == expected diff --git a/tests/main/tgeogpoint_test.py b/tests/main/tgeogpoint_test.py index 6cbadcec..4e415c37 100644 --- a/tests/main/tgeogpoint_test.py +++ b/tests/main/tgeogpoint_test.py @@ -1,28 +1,28 @@ from copy import copy -from datetime import datetime, timezone, timedelta +from datetime import datetime, timedelta, timezone from operator import not_ import numpy as np import pytest import shapely.geometry from pymeos_cffi import MeosInvalidArgValueError -from shapely import Point, LineString, set_srid +from shapely import LineString, Point, set_srid from pymeos import ( + STBox, TBoolInst, TBoolSeq, TBoolSeqSet, TFloatInst, TFloatSeq, TFloatSeqSet, - TGeomPointInst, - TGeomPointSeq, - TGeomPointSeqSet, TGeogPoint, TGeogPointInst, TGeogPointSeq, TGeogPointSeqSet, - STBox, + TGeomPointInst, + TGeomPointSeq, + TGeomPointSeqSet, TInterpolation, TsTzSet, TsTzSpan, @@ -46,8 +46,7 @@ class TestTGeogPointConstructors(TestTGeogPoint): tpds3d = TGeogPointSeq("{Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02}") tps3d = TGeogPointSeq("[Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02]") tpss3d = TGeogPointSeqSet( - "{[Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02]," - "[Point(1 1 1)@2019-09-03, Point(1 1 1)@2019-09-05]}" + "{[Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02],[Point(1 1 1)@2019-09-03, Point(1 1 1)@2019-09-05]}" ) @pytest.mark.parametrize( @@ -80,9 +79,7 @@ class TestTGeogPointConstructors(TestTGeogPoint): ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], ) def test_from_base_constructor(self, source, type, interpolation): - tp = TGeogPoint.from_base_temporal( - shapely.set_srid(shapely.Point(1, 1), 4326), source - ) + tp = TGeogPoint.from_base_temporal(shapely.set_srid(shapely.Point(1, 1), 4326), source) assert isinstance(tp, type) assert tp.interpolation() == interpolation @@ -109,9 +106,7 @@ def test_from_base_constructor(self, source, type, interpolation): ids=["Instant", "Sequence", "Discrete Sequence", "SequenceSet"], ) def test_from_base_time_constructor(self, source, type, interpolation): - tp = TGeogPoint.from_base_time( - shapely.set_srid(shapely.Point(1, 1), 4326), source, interpolation - ) + tp = TGeogPoint.from_base_time(shapely.set_srid(shapely.Point(1, 1), 4326), source, interpolation) assert isinstance(tp, type) assert tp.interpolation() == interpolation @@ -247,9 +242,7 @@ def test_value_timestamp_instant_constructor(self, value, timestamp): ( [ TGeogPointInst("Point(1 1)@2019-09-01"), - TGeogPointInst( - "Point(1.499885736561676 1.500057091479197)@2019-09-02" - ), + TGeogPointInst("Point(1.499885736561676 1.500057091479197)@2019-09-02"), TGeogPointInst("Point(2 2)@2019-09-03"), ], TInterpolation.LINEAR, @@ -279,9 +272,7 @@ def test_value_timestamp_instant_constructor(self, value, timestamp): "Mixed Linear Normalized", ], ) - def test_instant_list_sequence_constructor( - self, list, interpolation, normalize, expected - ): + def test_instant_list_sequence_constructor(self, list, interpolation, normalize, expected): tps = TGeogPointSeq( instant_list=list, interpolation=interpolation, @@ -291,9 +282,7 @@ def test_instant_list_sequence_constructor( assert str(tps) == expected assert tps.interpolation() == interpolation - tps2 = TGeogPointSeq.from_instants( - list, interpolation=interpolation, normalize=normalize, upper_inc=True - ) + tps2 = TGeogPointSeq.from_instants(list, interpolation=interpolation, normalize=normalize, upper_inc=True) assert str(tps2) == expected assert tps2.interpolation() == interpolation @@ -1003,9 +992,7 @@ def test_hash(self, temporal, expected): def test_value_timestamp(self): assert self.tpi.value() == Point(1, 1) - assert self.tpi.timestamp() == datetime( - year=2019, month=9, day=1, tzinfo=timezone.utc - ) + assert self.tpi.timestamp() == datetime(year=2019, month=9, day=1, tzinfo=timezone.utc) @pytest.mark.parametrize( "temporal, expected", @@ -1025,13 +1012,9 @@ def test_sequenceset_sequence_functions(self): "[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05], [Point(3 3)@2019-09-06]}" ) assert tpss1.num_sequences() == 3 - assert tpss1.start_sequence() == TGeogPointSeq( - "[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02]" - ) + assert tpss1.start_sequence() == TGeogPointSeq("[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02]") assert tpss1.end_sequence() == TGeogPointSeq("[Point(3 3)@2019-09-06]") - assert tpss1.sequence_n(1) == TGeogPointSeq( - "[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]" - ) + assert tpss1.sequence_n(1) == TGeogPointSeq("[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]") assert tpss1.sequences() == [ TGeogPointSeq("[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02]"), TGeogPointSeq("[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]"), @@ -1050,8 +1033,7 @@ class TestTGeogPointTPointAccessors(TestTGeogPoint): tpds3d = TGeogPointSeq("{Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02}") tps3d = TGeogPointSeq("[Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02]") tpss3d = TGeogPointSeqSet( - "{[Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02]," - "[Point(1 1 1)@2019-09-03, Point(1 1 1)@2019-09-05]}" + "{[Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02],[Point(1 1 1)@2019-09-03, Point(1 1 1)@2019-09-05]}" ) @pytest.mark.parametrize( @@ -1076,8 +1058,7 @@ def test_length(self, temporal, expected): ( tpss, TFloatSeqSet( - "{[0@2019-09-01, 156876.1494@2019-09-02]," - "[156876.1494@2019-09-03, 156876.1494@2019-09-05]}" + "{[0@2019-09-01, 156876.1494@2019-09-02],[156876.1494@2019-09-03, 156876.1494@2019-09-05]}" ), ), ], @@ -1092,10 +1073,7 @@ def test_cumulative_length(self, temporal, expected): (tps, TFloatSeq("Interp=Step;[1.8157@2019-09-01, 1.8157@2019-09-02]")), ( tpss, - TFloatSeqSet( - "Interp=Step;{[1.8157@2019-09-01, 1.8157@2019-09-02]," - "[0@2019-09-03, 0@2019-09-05]}" - ), + TFloatSeqSet("Interp=Step;{[1.8157@2019-09-01, 1.8157@2019-09-02],[0@2019-09-03, 0@2019-09-05]}"), ), ], ids=["Sequence", "SequenceSet"], @@ -1123,9 +1101,7 @@ def test_speed_without_linear_interpolation_throws(self, temporal): (tps, TFloatSeq("[1@2019-09-01, 2@2019-09-02]")), ( tpss, - TFloatSeqSet( - "{[1@2019-09-01, 2@2019-09-02]," "[1@2019-09-03, 1@2019-09-05]}" - ), + TFloatSeqSet("{[1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1142,9 +1118,7 @@ def test_x_y(self, temporal, expected): (tps3d, TFloatSeq("[1@2019-09-01, 2@2019-09-02]")), ( tpss3d, - TFloatSeqSet( - "{[1@2019-09-01, 2@2019-09-02]," "[1@2019-09-03, 1@2019-09-05]}" - ), + TFloatSeqSet("{[1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1180,19 +1154,6 @@ def test_x_y_z(self, temporal, expected): def test_has_z(self, temporal, expected): assert temporal.has_z() == expected - @pytest.mark.parametrize( - "temporal, expected", - [ - (tpi3d, True), - (tpds3d, True), - (tps3d, True), - (tpss3d, True), - ], - ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], - ) - def test_has_z(self, temporal, expected): - assert temporal.has_z() == expected - @pytest.mark.parametrize( "temporal, expected", [ @@ -1239,19 +1200,13 @@ def test_is_simple(self, temporal, expected): (tps, TFloatSeq("[0.7846@2019-09-01,0.7846@2019-09-02]")), ( tpss, - TFloatSeqSet( - "{[0.7846@2019-09-01,0.7846@2019-09-02]," - "[0.7846@2019-09-03,0.7846@2019-09-05]}" - ), + TFloatSeqSet("{[0.7846@2019-09-01,0.7846@2019-09-02],[0.7846@2019-09-03,0.7846@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], ) def test_bearing(self, temporal, expected): - assert ( - temporal.bearing(shapely.set_srid(shapely.Point(3, 3), 4326)).round(4) - == expected - ) + assert temporal.bearing(shapely.set_srid(shapely.Point(3, 3), 4326)).round(4) == expected @pytest.mark.parametrize( "temporal, expected", @@ -1321,15 +1276,11 @@ class TestTGeogPointConversions(TestTGeogPoint): (tpi, TGeomPointInst("SRID=4326;Point(1 1)@2019-09-01")), ( tpds, - TGeomPointSeq( - "SRID=4326;{Point(1 1)@2019-09-01, Point(2 2)@2019-09-02}" - ), + TGeomPointSeq("SRID=4326;{Point(1 1)@2019-09-01, Point(2 2)@2019-09-02}"), ), ( tps, - TGeomPointSeq( - "SRID=4326;[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02]" - ), + TGeomPointSeq("SRID=4326;[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02]"), ), ( tpss, @@ -1357,13 +1308,11 @@ class TestTGeogPointTransformations(TestTGeogPoint): tpss_d = TGeogPointSeqSet("{[Point(1 1)@2019-09-01],[Point(2 2)@2019-09-03]}") tps_s = TGeogPointSeq("[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02]") tpss_s = TGeogPointSeqSet( - "{[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02]," - "[Point(2 2)@2019-09-03, Point(2 2)@2019-09-05]}" + "{[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02],[Point(2 2)@2019-09-03, Point(2 2)@2019-09-05]}" ) tps_l = TGeogPointSeq("Interp=Step;[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02]") tpss_l = TGeogPointSeqSet( - "Interp=Step;{[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02]," - "[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" + "Interp=Step;{[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02],[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" ) @pytest.mark.parametrize( @@ -1462,16 +1411,12 @@ def test_to_sequenceset(self, temporal, interpolation, expected): ( tpds, TInterpolation.STEPWISE, - TGeogPointSeqSet( - "Interp=Step;{[Point(1 1)@2019-09-01], [Point(2 2)@2019-09-02]}" - ), + TGeogPointSeqSet("Interp=Step;{[Point(1 1)@2019-09-01], [Point(2 2)@2019-09-02]}"), ), ( tps_s, TInterpolation.STEPWISE, - TGeogPointSeq( - "Interp=Step;[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02]" - ), + TGeogPointSeq("Interp=Step;[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02]"), ), ( tpss_s, @@ -1490,9 +1435,7 @@ def test_to_sequenceset(self, temporal, interpolation, expected): ( tps_l, TInterpolation.LINEAR, - TGeogPointSeqSet( - "{[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02), [Point(2 2)@2019-09-02]}" - ), + TGeogPointSeqSet("{[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02), [Point(2 2)@2019-09-02]}"), ), ( tpss_l, @@ -1545,16 +1488,12 @@ def test_set_interpolation(self, temporal, interpolation, expected): ( tpds, timedelta(hours=2), - TGeogPointSeq( - "{Point(1 1)@2019-09-01 02:00:00, Point(2 2)@2019-09-02 02:00:00}" - ), + TGeogPointSeq("{Point(1 1)@2019-09-01 02:00:00, Point(2 2)@2019-09-02 02:00:00}"), ), ( tpds, timedelta(hours=-2), - TGeogPointSeq( - "{Point(1 1)@2019-08-31 22:00:00, Point(2 2)@2019-09-01 22:00:00}" - ), + TGeogPointSeq("{Point(1 1)@2019-08-31 22:00:00, Point(2 2)@2019-09-01 22:00:00}"), ), ( tps, @@ -1569,16 +1508,12 @@ def test_set_interpolation(self, temporal, interpolation, expected): ( tps, timedelta(hours=2), - TGeogPointSeq( - "[Point(1 1)@2019-09-01 02:00:00, Point(2 2)@2019-09-02 02:00:00]" - ), + TGeogPointSeq("[Point(1 1)@2019-09-01 02:00:00, Point(2 2)@2019-09-02 02:00:00]"), ), ( tps, timedelta(hours=-2), - TGeogPointSeq( - "[Point(1 1)@2019-08-31 22:00:00, Point(2 2)@2019-09-01 22:00:00]" - ), + TGeogPointSeq("[Point(1 1)@2019-08-31 22:00:00, Point(2 2)@2019-09-01 22:00:00]"), ), ( tpss, @@ -1646,9 +1581,7 @@ def test_shift_time(self, tpoint, delta, expected): ( tpds, timedelta(hours=2), - TGeogPointSeq( - "{Point(1 1)@2019-09-01 00:00:00, Point(2 2)@2019-09-01 02:00:00}" - ), + TGeogPointSeq("{Point(1 1)@2019-09-01 00:00:00, Point(2 2)@2019-09-01 02:00:00}"), ), ( tps, @@ -1658,9 +1591,7 @@ def test_shift_time(self, tpoint, delta, expected): ( tps, timedelta(hours=2), - TGeogPointSeq( - "[Point(1 1)@2019-09-01 00:00:00, Point(2 2)@2019-09-01 02:00:00]" - ), + TGeogPointSeq("[Point(1 1)@2019-09-01 00:00:00, Point(2 2)@2019-09-01 02:00:00]"), ), ( tpss, @@ -1693,9 +1624,7 @@ def test_scale_time(self, tpoint, delta, expected): assert tpoint.scale_time(delta) == expected def test_shift_scale_time(self): - assert self.tpss.shift_scale_time( - timedelta(days=4), timedelta(hours=2) - ) == TGeogPointSeqSet( + assert self.tpss.shift_scale_time(timedelta(days=4), timedelta(hours=2)) == TGeogPointSeqSet( "{[Point(1 1)@2019-09-05 00:00:00, Point(2 2)@2019-09-05 00:30:00]," "[Point(1 1)@2019-09-05 01:00:00, Point(1 1)@2019-09-05 02:00:00]}" ) @@ -1726,8 +1655,7 @@ def test_shift_scale_time(self): tpss, timedelta(hours=12), TGeogPointSeqSet( - "{[POINT(1 1)@2019-09-01, POINT(2 2)@2019-09-02], " - "[POINT(1 1)@2019-09-03, POINT(1 1)@2019-09-05]}" + "{[POINT(1 1)@2019-09-01, POINT(2 2)@2019-09-02], [POINT(1 1)@2019-09-03, POINT(1 1)@2019-09-05]}" ), ), ], @@ -1775,22 +1703,12 @@ def test_stops(self, tpoint, delta, expected): TGeogPointInst("Point(1.12 1.12)@2019-09-01"), ), ( - TGeogPointSeq( - "{Point(1.123456789 1.123456789)@2019-09-01," - "Point(2.123456789 2.123456789)@2019-09-02}" - ), - TGeogPointSeq( - "{Point(1.12 1.12)@2019-09-01,Point(2.12 2.12)@2019-09-02}" - ), + TGeogPointSeq("{Point(1.123456789 1.123456789)@2019-09-01,Point(2.123456789 2.123456789)@2019-09-02}"), + TGeogPointSeq("{Point(1.12 1.12)@2019-09-01,Point(2.12 2.12)@2019-09-02}"), ), ( - TGeogPointSeq( - "[Point(1.123456789 1.123456789)@2019-09-01," - "Point(2.123456789 2.123456789)@2019-09-02]" - ), - TGeogPointSeq( - "[Point(1.12 1.12)@2019-09-01,Point(2.12 2.12)@2019-09-02]" - ), + TGeogPointSeq("[Point(1.123456789 1.123456789)@2019-09-01,Point(2.123456789 2.123456789)@2019-09-02]"), + TGeogPointSeq("[Point(1.12 1.12)@2019-09-01,Point(2.12 2.12)@2019-09-02]"), ), ( TGeogPointSeqSet( @@ -1815,29 +1733,15 @@ def test_round(self, temporal, expected): [ ( TGeogPointInst("Point(42.84979 42.38153)@2019-09-01"), - TGeogPointInst("SRID=8426;" "Point(42.84979 42.38153)@2019-09-01"), + TGeogPointInst("SRID=8426;Point(42.84979 42.38153)@2019-09-01"), ), ( - TGeogPointSeq( - "{Point(42.84979 42.38153)@2019-09-01," - "Point(44.31646 41.77403)@2019-09-02}" - ), - TGeogPointSeq( - "SRID=8426;" - "{Point(42.84979 42.38153)@2019-09-01," - "Point(44.31646 41.77403)@2019-09-02}" - ), + TGeogPointSeq("{Point(42.84979 42.38153)@2019-09-01,Point(44.31646 41.77403)@2019-09-02}"), + TGeogPointSeq("SRID=8426;{Point(42.84979 42.38153)@2019-09-01,Point(44.31646 41.77403)@2019-09-02}"), ), ( - TGeogPointSeq( - "[Point(42.84979 42.38153)@2019-09-01," - "Point(44.31646 41.77403)@2019-09-02]" - ), - TGeogPointSeq( - "SRID=8426;" - "[Point(42.84979 42.38153)@2019-09-01," - "Point(44.31646 41.77403)@2019-09-02]" - ), + TGeogPointSeq("[Point(42.84979 42.38153)@2019-09-01,Point(44.31646 41.77403)@2019-09-02]"), + TGeogPointSeq("SRID=8426;[Point(42.84979 42.38153)@2019-09-01,Point(44.31646 41.77403)@2019-09-02]"), ), ( TGeogPointSeqSet( @@ -1884,16 +1788,12 @@ class TestTGeogPointModifications(TestTGeogPoint): ( tpds, TGeogPointSeq("{Point(1 1)@2019-09-03}"), - TGeogPointSeq( - "{Point(1 1)@2019-09-01, Point(2 2)@2019-09-02, Point(1 1)@2019-09-03}" - ), + TGeogPointSeq("{Point(1 1)@2019-09-01, Point(2 2)@2019-09-02, Point(1 1)@2019-09-03}"), ), ( tps, TGeogPointSeq("[Point(1 1)@2019-09-03]"), - TGeogPointSeqSet( - "{[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02, Point(1 1)@2019-09-03]}" - ), + TGeogPointSeqSet("{[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02, Point(1 1)@2019-09-03]}"), ), ( tpss, @@ -1924,9 +1824,7 @@ def test_insert(self, temporal, sequence, expected): ( tps, TGeogPointInst("Point(2 2)@2019-09-01"), - TGeogPointSeqSet( - "{[Point(2 2)@2019-09-01], (Point(1 1)@2019-09-01, Point(2 2)@2019-09-02]}" - ), + TGeogPointSeqSet("{[Point(2 2)@2019-09-01], (Point(1 1)@2019-09-01, Point(2 2)@2019-09-02]}"), ), ( tpss, @@ -1986,16 +1884,12 @@ def test_delete(self, temporal, time, expected): ( tpds, TGeogPointInst("Point(1 1)@2019-09-03"), - TGeogPointSeq( - "{Point(1 1)@2019-09-01, Point(2 2)@2019-09-02, Point(1 1)@2019-09-03}" - ), + TGeogPointSeq("{Point(1 1)@2019-09-01, Point(2 2)@2019-09-02, Point(1 1)@2019-09-03}"), ), ( tps, TGeogPointInst("Point(1 1)@2019-09-03"), - TGeogPointSeq( - "[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02, Point(1 1)@2019-09-03]" - ), + TGeogPointSeq("[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02, Point(1 1)@2019-09-03]"), ), ( tpss, @@ -2016,16 +1910,12 @@ def test_append_instant(self, temporal, instant, expected): ( tpds, TGeogPointSeq("{Point(1 1)@2019-09-03}"), - TGeogPointSeq( - "{Point(1 1)@2019-09-01, Point(2 2)@2019-09-02, Point(1 1)@2019-09-03}" - ), + TGeogPointSeq("{Point(1 1)@2019-09-01, Point(2 2)@2019-09-02, Point(1 1)@2019-09-03}"), ), ( tps, TGeogPointSeq("[Point(1 1)@2019-09-03]"), - TGeogPointSeqSet( - "{[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02], [Point(1 1)@2019-09-03]}" - ), + TGeogPointSeqSet("{[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02], [Point(1 1)@2019-09-03]}"), ), ( tpss, @@ -2126,16 +2016,13 @@ class TestTGeogPointRestrictors(TestTGeogPoint): tpss, tstzspan_set, TGeogPointSeqSet( - "{[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02]," - "[Point(1 1)@2019-09-03,Point(1 1)@2019-09-05]}" + "{[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02],[Point(1 1)@2019-09-03,Point(1 1)@2019-09-05]}" ), ), ( tpss, shapely.set_srid(shapely.Point(1, 1), 4326), - TGeogPointSeqSet( - "{[Point(1 1)@2019-09-01],[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" - ), + TGeogPointSeqSet("{[Point(1 1)@2019-09-01],[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}"), ), ( tpss, @@ -2341,10 +2228,7 @@ def test_minus(self, temporal, restrictor, expected): ], ) def test_at_minus(self, temporal, restrictor): - assert ( - TGeogPoint.from_merge(temporal.at(restrictor), temporal.minus(restrictor)) - == temporal - ) + assert TGeogPoint.from_merge(temporal.at(restrictor), temporal.minus(restrictor)) == temporal @pytest.mark.parametrize( "temporal", @@ -2352,12 +2236,8 @@ def test_at_minus(self, temporal, restrictor): ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], ) def test_at_minus_min_max(self, temporal): - assert ( - TGeogPoint.from_merge(temporal.at_min(), temporal.minus_min()) == temporal - ) - assert ( - TGeogPoint.from_merge(temporal.at_max(), temporal.minus_max()) == temporal - ) + assert TGeogPoint.from_merge(temporal.at_min(), temporal.minus_min()) == temporal + assert TGeogPoint.from_merge(temporal.at_max(), temporal.minus_max()) == temporal class TestTGeogPointEverSpatialOperations(TestTGeogPoint): @@ -2381,9 +2261,7 @@ class TestTGeogPointEverSpatialOperations(TestTGeogPoint): def test_temporal_ever_withindist_intersects(self, temporal): assert temporal.is_ever_within_distance(Point(1, 1), 1) print("Hey") - assert temporal.is_ever_within_distance( - TGeogPointInst("Point(1 1)@2019-09-01"), 1 - ) + assert temporal.is_ever_within_distance(TGeogPointInst("Point(1 1)@2019-09-01"), 1) print("Hey") assert temporal.ever_intersects(Point(1, 1)) print("Hey") @@ -2391,7 +2269,6 @@ def test_temporal_ever_withindist_intersects(self, temporal): print("Hey") - class TestTGeogPointDistanceOperations(TestTGeogPoint): tpi = TGeogPointInst("Point(1 1)@2019-09-01") tpds = TGeogPointSeq("{Point(1 1)@2019-09-01, Point(2 2)@2019-09-02}") @@ -2409,10 +2286,7 @@ class TestTGeogPointDistanceOperations(TestTGeogPoint): ( tpss, Point(1, 1), - TFloatSeqSet( - "{[0@2019-09-01, 156876.149@2019-09-02]," - "[0@2019-09-03, 0@2019-09-05]}" - ), + TFloatSeqSet("{[0@2019-09-01, 156876.149@2019-09-02],[0@2019-09-03, 0@2019-09-05]}"), ), (tpi, STBox("GEODSTBOX X((1,1),(1,1))"), TFloatInst("0@2019-09-01")), ( @@ -2428,10 +2302,7 @@ class TestTGeogPointDistanceOperations(TestTGeogPoint): ( tpss, STBox("GEODSTBOX X((1,1),(1,1))"), - TFloatSeqSet( - "{[0@2019-09-01, 156876.149@2019-09-02]," - "[0@2019-09-03, 0@2019-09-05]}" - ), + TFloatSeqSet("{[0@2019-09-01, 156876.149@2019-09-02],[0@2019-09-03, 0@2019-09-05]}"), ), (tpi, TGeogPointInst("Point(1 1)@2019-09-01"), TFloatInst("0@2019-09-01")), ( @@ -2447,13 +2318,9 @@ class TestTGeogPointDistanceOperations(TestTGeogPoint): ( tpss, TGeogPointSeqSet( - "{[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02]," - "[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" - ), - TFloatSeqSet( - "{[0@2019-09-01, 156876.149@2019-09-02]," - "[0@2019-09-03, 0@2019-09-05]}" + "{[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02],[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" ), + TFloatSeqSet("{[0@2019-09-01, 156876.149@2019-09-02],[0@2019-09-03, 0@2019-09-05]}"), ), ], ids=[ @@ -2488,8 +2355,7 @@ def test_distance(self, temporal, argument, expected): ( tpss, TGeogPointSeqSet( - "{[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02]," - "[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" + "{[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02],[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" ), ), ], @@ -2505,9 +2371,7 @@ def test_distance(self, temporal, argument, expected): ], ) def test_nearest_approach_instant(self, temporal, argument): - assert temporal.nearest_approach_instant(argument) == TGeogPointInst( - "Point(1 1)@2019-09-01" - ) + assert temporal.nearest_approach_instant(argument) == TGeogPointInst("Point(1 1)@2019-09-01") @pytest.mark.parametrize( "temporal, argument", @@ -2522,8 +2386,7 @@ def test_nearest_approach_instant(self, temporal, argument): ( tpss, TGeogPointSeqSet( - "{[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02]," - "[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" + "{[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02],[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" ), ), ], @@ -2547,8 +2410,7 @@ class TestTGeogPointSimilarityFunctions(TestTGeogPoint): tfds = TGeogPointSeq("{Point(1 1)@2019-09-01, Point(2 2)@2019-09-02}") tfs = TGeogPointSeq("[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02]") tfss = TGeogPointSeqSet( - "{[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02]," - "[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" + "{[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02],[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" ) @pytest.mark.parametrize( @@ -2632,12 +2494,8 @@ def test_time_split(self, temporal, expected): ( tps, [ - TGeogPointSeq( - "[Point(1 1)@2019-09-01, Point(1.5 1.5)@2019-09-01 12:00:00+00)" - ), - TGeogPointSeq( - "[Point(1.5 1.5)@2019-09-01 12:00:00+00, Point(2 2)@2019-09-02]" - ), + TGeogPointSeq("[Point(1 1)@2019-09-01, Point(1.5 1.5)@2019-09-01 12:00:00+00)"), + TGeogPointSeq("[Point(1.5 1.5)@2019-09-01 12:00:00+00, Point(2 2)@2019-09-02]"), ], ), ( @@ -2753,9 +2611,7 @@ class TestTGeogPointTemporalComparisons(TestTGeogPoint): tpss = TGeogPointSeqSet( "{[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02],[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" ) - argument = TGeogPointSeq( - "[Point(2 2)@2019-09-01, Point(1 1)@2019-09-02, Point(1 1)@2019-09-03]" - ) + argument = TGeogPointSeq("[Point(2 2)@2019-09-01, Point(1 1)@2019-09-02, Point(1 1)@2019-09-03]") @pytest.mark.parametrize( "temporal, expected", @@ -2765,8 +2621,7 @@ class TestTGeogPointTemporalComparisons(TestTGeogPoint): ( tps, TBoolSeqSet( - "{[False@2019-09-01, True@2019-09-01 12:00:00+00]," - "(False@2019-09-01 12:00:00+00, False@2019-09-02]}" + "{[False@2019-09-01, True@2019-09-01 12:00:00+00],(False@2019-09-01 12:00:00+00, False@2019-09-02]}" ), ), ( @@ -2799,9 +2654,7 @@ def test_temporal_equal_temporal(self, temporal, expected): ( tps, shapely.set_srid(shapely.Point(1, 1), 4326), - TBoolSeqSet( - "{[True@2019-09-01], (False@2019-09-01, False@2019-09-02]}" - ), + TBoolSeqSet("{[True@2019-09-01], (False@2019-09-01, False@2019-09-02]}"), ), ( tpss, @@ -2828,9 +2681,7 @@ def test_temporal_equal_temporal(self, temporal, expected): ( tpss, shapely.set_srid(shapely.Point(2, 2), 4326), - TBoolSeqSet( - "{[False@2019-09-01, True@2019-09-02],[False@2019-09-03, False@2019-09-05]}" - ), + TBoolSeqSet("{[False@2019-09-01, True@2019-09-02],[False@2019-09-03, False@2019-09-05]}"), ), ], ids=[ diff --git a/tests/main/tgeompoint_test.py b/tests/main/tgeompoint_test.py index b6f7f1f3..d08c6a03 100644 --- a/tests/main/tgeompoint_test.py +++ b/tests/main/tgeompoint_test.py @@ -1,34 +1,32 @@ +import math from copy import copy +from datetime import datetime, timedelta, timezone from operator import not_ -from datetime import datetime, timezone, timedelta -import pytest -import math import numpy as np +import pytest from pymeos_cffi import MeosInvalidArgValueError -from shapely import Point, LineString, Polygon, MultiPoint, GeometryCollection +from shapely import GeometryCollection, LineString, MultiPoint, Point, Polygon from pymeos import ( - TBool, + STBox, TBoolInst, TBoolSeq, TBoolSeqSet, - TFloat, TFloatInst, TFloatSeq, TFloatSeqSet, + TGeogPointInst, + TGeogPointSeq, + TGeogPointSeqSet, TGeomPoint, TGeomPointInst, TGeomPointSeq, TGeomPointSeqSet, - TGeogPointInst, - TGeogPointSeq, - TGeogPointSeqSet, TInterpolation, TsTzSet, TsTzSpan, TsTzSpanSet, - STBox, ) from tests.conftest import TestPyMEOS @@ -49,8 +47,7 @@ class TestTGeomPointConstructors(TestTGeomPoint): tpds3d = TGeomPointSeq("{Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02}") tps3d = TGeomPointSeq("[Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02]") tpss3d = TGeomPointSeqSet( - "{[Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02]," - "[Point(1 1 1)@2019-09-03, Point(1 1 1)@2019-09-05]}" + "{[Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02],[Point(1 1 1)@2019-09-03, Point(1 1 1)@2019-09-05]}" ) @pytest.mark.parametrize( @@ -68,9 +65,7 @@ class TestTGeomPointConstructors(TestTGeomPoint): TInterpolation.LINEAR, ), ( - TFloatSeqSet( - "{[1.5@2019-09-01, 0.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ), + TFloatSeqSet("{[1.5@2019-09-01, 0.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}"), TGeomPointSeqSet, TInterpolation.LINEAR, ), @@ -271,9 +266,7 @@ def test_value_timestamp_instant_constructor(self, value, timestamp): "Mixed Linear Normalized", ], ) - def test_instant_list_sequence_constructor( - self, list, interpolation, normalize, expected - ): + def test_instant_list_sequence_constructor(self, list, interpolation, normalize, expected): tps = TGeomPointSeq( instant_list=list, interpolation=interpolation, @@ -283,9 +276,7 @@ def test_instant_list_sequence_constructor( assert str(tps) == expected assert tps.interpolation() == interpolation - tps2 = TGeomPointSeq.from_instants( - list, interpolation=interpolation, normalize=normalize, upper_inc=True - ) + tps2 = TGeomPointSeq.from_instants(list, interpolation=interpolation, normalize=normalize, upper_inc=True) assert str(tps2) == expected assert tps2.interpolation() == interpolation @@ -649,8 +640,7 @@ class TestTGeomPointTemporalAccessors(TestTGeomPoint): tpds3d = TGeomPointSeq("{Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02}") tps3d = TGeomPointSeq("[Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02]") tpss3d = TGeomPointSeqSet( - "{[Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02]," - "[Point(1 1 1)@2019-09-03, Point(1 1 1)@2019-09-05]}" + "{[Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02],[Point(1 1 1)@2019-09-03, Point(1 1 1)@2019-09-05]}" ) @pytest.mark.parametrize( @@ -1032,9 +1022,7 @@ def test_hash(self, temporal, expected): def test_value_timestamp(self): assert self.tpi.value() == Point(1, 1) - assert self.tpi.timestamp() == datetime( - year=2019, month=9, day=1, tzinfo=timezone.utc - ) + assert self.tpi.timestamp() == datetime(year=2019, month=9, day=1, tzinfo=timezone.utc) @pytest.mark.parametrize( "temporal, expected", @@ -1054,13 +1042,9 @@ def test_sequenceset_sequence_functions(self): "[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05], [Point(3 3)@2019-09-06]}" ) assert tpss1.num_sequences() == 3 - assert tpss1.start_sequence() == TGeomPointSeq( - "[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02]" - ) + assert tpss1.start_sequence() == TGeomPointSeq("[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02]") assert tpss1.end_sequence() == TGeomPointSeq("[Point(3 3)@2019-09-06]") - assert tpss1.sequence_n(1) == TGeomPointSeq( - "[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]" - ) + assert tpss1.sequence_n(1) == TGeomPointSeq("[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]") assert tpss1.sequences() == [ TGeomPointSeq("[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02]"), TGeomPointSeq("[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]"), @@ -1079,8 +1063,7 @@ class TestTGeomPointTPointAccessors(TestTGeomPoint): tpds3d = TGeomPointSeq("{Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02}") tps3d = TGeomPointSeq("[Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02]") tpss3d = TGeomPointSeqSet( - "{[Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02]," - "[Point(1 1 1)@2019-09-03, Point(1 1 1)@2019-09-05]}" + "{[Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02],[Point(1 1 1)@2019-09-03, Point(1 1 1)@2019-09-05]}" ) @pytest.mark.parametrize( @@ -1120,11 +1103,7 @@ def test_cumulative_length(self, temporal, expected): [ ( tps, - TFloatSeq( - "Interp=Step;[1.4142135623730951@2019-09-01, 1.4142135623730951@2019-09-02]" - ) - / 3600 - / 24, + TFloatSeq("Interp=Step;[1.4142135623730951@2019-09-01, 1.4142135623730951@2019-09-02]") / 3600 / 24, ), ( tpss, @@ -1146,7 +1125,7 @@ def test_speed(self, temporal, expected): [tpi, tpds], ids=["Instant", "Discrete Sequence"], ) - def test_speed(self, temporal): + def test_speed_raises(self, temporal): with pytest.raises(MeosInvalidArgValueError): temporal.speed() @@ -1158,9 +1137,7 @@ def test_speed(self, temporal): (tps, TFloatSeq("[1@2019-09-01, 2@2019-09-02]")), ( tpss, - TFloatSeqSet( - "{[1@2019-09-01, 2@2019-09-02]," "[1@2019-09-03, 1@2019-09-05]}" - ), + TFloatSeqSet("{[1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1177,9 +1154,7 @@ def test_x_y(self, temporal, expected): (tps3d, TFloatSeq("[1@2019-09-01, 2@2019-09-02]")), ( tpss3d, - TFloatSeqSet( - "{[1@2019-09-01, 2@2019-09-02]," "[1@2019-09-03, 1@2019-09-05]}" - ), + TFloatSeqSet("{[1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1215,19 +1190,6 @@ def test_x_y_z(self, temporal, expected): def test_has_z(self, temporal, expected): assert temporal.has_z() == expected - @pytest.mark.parametrize( - "temporal, expected", - [ - (tpi3d, True), - (tpds3d, True), - (tps3d, True), - (tpss3d, True), - ], - ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], - ) - def test_has_z(self, temporal, expected): - assert temporal.has_z() == expected - @pytest.mark.parametrize( "temporal, expected", [ @@ -1274,9 +1236,7 @@ def test_is_simple(self, temporal, expected): (tps, TFloatSeq("[45@2019-09-01,45@2019-09-02]")), ( tpss, - TFloatSeqSet( - "{[45@2019-09-01,45@2019-09-02],[45@2019-09-03,45@2019-09-05]}" - ), + TFloatSeqSet("{[45@2019-09-01,45@2019-09-02],[45@2019-09-03,45@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1386,8 +1346,7 @@ class TestTGeomPointConversions(TestTGeomPoint): ( tpss, TGeogPointSeqSet( - "{[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02]," - "[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" + "{[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02],[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" ), ), ], @@ -1422,13 +1381,11 @@ class TestTGeomPointTransformations(TestTGeomPoint): tpss_d = TGeomPointSeqSet("{[Point(1 1)@2019-09-01],[Point(2 2)@2019-09-03]}") tps_s = TGeomPointSeq("[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02]") tpss_s = TGeomPointSeqSet( - "{[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02]," - "[Point(2 2)@2019-09-03, Point(2 2)@2019-09-05]}" + "{[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02],[Point(2 2)@2019-09-03, Point(2 2)@2019-09-05]}" ) tps_l = TGeomPointSeq("Interp=Step;[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02]") tpss_l = TGeomPointSeqSet( - "Interp=Step;{[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02]," - "[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" + "Interp=Step;{[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02],[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" ) @pytest.mark.parametrize( @@ -1527,16 +1484,12 @@ def test_to_sequenceset(self, temporal, interpolation, expected): ( tpds, TInterpolation.STEPWISE, - TGeomPointSeqSet( - "Interp=Step;{[Point(1 1)@2019-09-01], [Point(2 2)@2019-09-02]}" - ), + TGeomPointSeqSet("Interp=Step;{[Point(1 1)@2019-09-01], [Point(2 2)@2019-09-02]}"), ), ( tps_s, TInterpolation.STEPWISE, - TGeomPointSeq( - "Interp=Step;[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02]" - ), + TGeomPointSeq("Interp=Step;[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02]"), ), ( tpss_s, @@ -1555,9 +1508,7 @@ def test_to_sequenceset(self, temporal, interpolation, expected): ( tps_l, TInterpolation.LINEAR, - TGeomPointSeqSet( - "{[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02), [Point(2 2)@2019-09-02]}" - ), + TGeomPointSeqSet("{[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02), [Point(2 2)@2019-09-02]}"), ), ( tpss_l, @@ -1610,16 +1561,12 @@ def test_set_interpolation(self, temporal, interpolation, expected): ( tpds, timedelta(hours=2), - TGeomPointSeq( - "{Point(1 1)@2019-09-01 02:00:00, Point(2 2)@2019-09-02 02:00:00}" - ), + TGeomPointSeq("{Point(1 1)@2019-09-01 02:00:00, Point(2 2)@2019-09-02 02:00:00}"), ), ( tpds, timedelta(hours=-2), - TGeomPointSeq( - "{Point(1 1)@2019-08-31 22:00:00, Point(2 2)@2019-09-01 22:00:00}" - ), + TGeomPointSeq("{Point(1 1)@2019-08-31 22:00:00, Point(2 2)@2019-09-01 22:00:00}"), ), ( tps, @@ -1634,16 +1581,12 @@ def test_set_interpolation(self, temporal, interpolation, expected): ( tps, timedelta(hours=2), - TGeomPointSeq( - "[Point(1 1)@2019-09-01 02:00:00, Point(2 2)@2019-09-02 02:00:00]" - ), + TGeomPointSeq("[Point(1 1)@2019-09-01 02:00:00, Point(2 2)@2019-09-02 02:00:00]"), ), ( tps, timedelta(hours=-2), - TGeomPointSeq( - "[Point(1 1)@2019-08-31 22:00:00, Point(2 2)@2019-09-01 22:00:00]" - ), + TGeomPointSeq("[Point(1 1)@2019-08-31 22:00:00, Point(2 2)@2019-09-01 22:00:00]"), ), ( tpss, @@ -1711,9 +1654,7 @@ def test_shift_time(self, tpoint, delta, expected): ( tpds, timedelta(hours=2), - TGeomPointSeq( - "{Point(1 1)@2019-09-01 00:00:00, Point(2 2)@2019-09-01 02:00:00}" - ), + TGeomPointSeq("{Point(1 1)@2019-09-01 00:00:00, Point(2 2)@2019-09-01 02:00:00}"), ), ( tps, @@ -1723,9 +1664,7 @@ def test_shift_time(self, tpoint, delta, expected): ( tps, timedelta(hours=2), - TGeomPointSeq( - "[Point(1 1)@2019-09-01 00:00:00, Point(2 2)@2019-09-01 02:00:00]" - ), + TGeomPointSeq("[Point(1 1)@2019-09-01 00:00:00, Point(2 2)@2019-09-01 02:00:00]"), ), ( tpss, @@ -1758,9 +1697,7 @@ def test_scale_time(self, tpoint, delta, expected): assert tpoint.scale_time(delta) == expected def test_shift_scale_time(self): - assert self.tpss.shift_scale_time( - timedelta(days=4), timedelta(hours=2) - ) == TGeomPointSeqSet( + assert self.tpss.shift_scale_time(timedelta(days=4), timedelta(hours=2)) == TGeomPointSeqSet( "{[Point(1 1)@2019-09-05 00:00:00, Point(2 2)@2019-09-05 00:30:00]," "[Point(1 1)@2019-09-05 01:00:00, Point(1 1)@2019-09-05 02:00:00]}" ) @@ -1840,22 +1777,12 @@ def test_stops(self, tpoint, delta, expected): TGeomPointInst("Point(1.12 1.12)@2019-09-01"), ), ( - TGeomPointSeq( - "{Point(1.123456789 1.123456789)@2019-09-01," - "Point(2.123456789 2.123456789)@2019-09-02}" - ), - TGeomPointSeq( - "{Point(1.12 1.12)@2019-09-01,Point(2.12 2.12)@2019-09-02}" - ), + TGeomPointSeq("{Point(1.123456789 1.123456789)@2019-09-01,Point(2.123456789 2.123456789)@2019-09-02}"), + TGeomPointSeq("{Point(1.12 1.12)@2019-09-01,Point(2.12 2.12)@2019-09-02}"), ), ( - TGeomPointSeq( - "[Point(1.123456789 1.123456789)@2019-09-01," - "Point(2.123456789 2.123456789)@2019-09-02]" - ), - TGeomPointSeq( - "[Point(1.12 1.12)@2019-09-01,Point(2.12 2.12)@2019-09-02]" - ), + TGeomPointSeq("[Point(1.123456789 1.123456789)@2019-09-01,Point(2.123456789 2.123456789)@2019-09-02]"), + TGeomPointSeq("[Point(1.12 1.12)@2019-09-01,Point(2.12 2.12)@2019-09-02]"), ), ( TGeomPointSeqSet( @@ -1894,30 +1821,21 @@ def test_round(self, temporal, expected): def test_make_simple(self, temporal, expected): assert temporal.make_simple() == expected - @pytest.mark.parametrize( "temporal, expected", [ ( TGeomPointInst("SRID=4326;Point(2.05455 41.62840)@2019-09-01"), - TGeomPointInst( - "SRID=2062;Point(1077794.3091235077 796037.0089003219)@2019-09-01" - ), + TGeomPointInst("SRID=2062;Point(1077794.3091235077 796037.0089003219)@2019-09-01"), ), ( - TGeomPointSeq( - "SRID=4326;{Point(2.05455 41.62840)@2019-09-01," - "Point(1.63164 41.41622)@2019-09-02}" - ), + TGeomPointSeq("SRID=4326;{Point(2.05455 41.62840)@2019-09-01,Point(1.63164 41.41622)@2019-09-02}"), TGeomPointSeq( "SRID=2062;{Point(1077794.3091235077 796037.0089003219)@2019-09-01,Point(1044050.9767668848 770349.6009306419)@2019-09-02}" ), ), ( - TGeomPointSeq( - "SRID=4326;[Point(2.05455 41.62840)@2019-09-01," - "Point(1.63164 41.41622)@2019-09-02]" - ), + TGeomPointSeq("SRID=4326;[Point(2.05455 41.62840)@2019-09-01,Point(1.63164 41.41622)@2019-09-02]"), TGeomPointSeq( "SRID=2062;[Point(1077794.3091235077 796037.0089003219)@2019-09-01,Point(1044050.9767668848 770349.6009306419)@2019-09-02]" ), @@ -1964,16 +1882,12 @@ class TestTGeomPointModifications(TestTGeomPoint): ( tpds, TGeomPointSeq("{Point(1 1)@2019-09-03}"), - TGeomPointSeq( - "{Point(1 1)@2019-09-01, Point(2 2)@2019-09-02, Point(1 1)@2019-09-03}" - ), + TGeomPointSeq("{Point(1 1)@2019-09-01, Point(2 2)@2019-09-02, Point(1 1)@2019-09-03}"), ), ( tps, TGeomPointSeq("[Point(1 1)@2019-09-03]"), - TGeomPointSeqSet( - "{[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02, Point(1 1)@2019-09-03]}" - ), + TGeomPointSeqSet("{[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02, Point(1 1)@2019-09-03]}"), ), ( tpss, @@ -2004,9 +1918,7 @@ def test_insert(self, temporal, sequence, expected): ( tps, TGeomPointInst("Point(2 2)@2019-09-01"), - TGeomPointSeqSet( - "{[Point(2 2)@2019-09-01], (Point(1 1)@2019-09-01, Point(2 2)@2019-09-02]}" - ), + TGeomPointSeqSet("{[Point(2 2)@2019-09-01], (Point(1 1)@2019-09-01, Point(2 2)@2019-09-02]}"), ), ( tpss, @@ -2066,16 +1978,12 @@ def test_delete(self, temporal, time, expected): ( tpds, TGeomPointInst("Point(1 1)@2019-09-03"), - TGeomPointSeq( - "{Point(1 1)@2019-09-01, Point(2 2)@2019-09-02, Point(1 1)@2019-09-03}" - ), + TGeomPointSeq("{Point(1 1)@2019-09-01, Point(2 2)@2019-09-02, Point(1 1)@2019-09-03}"), ), ( tps, TGeomPointInst("Point(1 1)@2019-09-03"), - TGeomPointSeq( - "[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02, Point(1 1)@2019-09-03]" - ), + TGeomPointSeq("[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02, Point(1 1)@2019-09-03]"), ), ( tpss, @@ -2096,16 +2004,12 @@ def test_append_instant(self, temporal, instant, expected): ( tpds, TGeomPointSeq("{Point(1 1)@2019-09-03}"), - TGeomPointSeq( - "{Point(1 1)@2019-09-01, Point(2 2)@2019-09-02, Point(1 1)@2019-09-03}" - ), + TGeomPointSeq("{Point(1 1)@2019-09-01, Point(2 2)@2019-09-02, Point(1 1)@2019-09-03}"), ), ( tps, TGeomPointSeq("[Point(1 1)@2019-09-03]"), - TGeomPointSeqSet( - "{[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02], [Point(1 1)@2019-09-03]}" - ), + TGeomPointSeqSet("{[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02], [Point(1 1)@2019-09-03]}"), ), ( tpss, @@ -2192,9 +2096,7 @@ class TestTGeomPointRestrictors(TestTGeomPoint): ( tpss, Point(1, 1), - TGeomPointSeqSet( - "{[Point(1 1)@2019-09-01],[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" - ), + TGeomPointSeqSet("{[Point(1 1)@2019-09-01],[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}"), ), (tpss, Point(2, 2), TGeomPointSeqSet("{[Point(2 2)@2019-09-02]}")), ], @@ -2236,9 +2138,7 @@ def test_at(self, temporal, restrictor, expected): (tps, TGeomPointSeqSet("{[Point(1 1)@2019-09-01]}")), ( tpss, - TGeomPointSeqSet( - "{[Point(1 1)@2019-09-01],[Point(1 1)@2019-09-03,Point(1 1)@2019-09-05]}" - ), + TGeomPointSeqSet("{[Point(1 1)@2019-09-01],[Point(1 1)@2019-09-03,Point(1 1)@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -2384,8 +2284,7 @@ def test_minus_min(self, temporal, expected): ( tpss, TGeomPointSeqSet( - "{[Point(1 1)@2019-09-01,Point(2 2)@2019-09-02)," - "[Point(1 1)@2019-09-03,Point(1 1)@2019-09-05]}" + "{[Point(1 1)@2019-09-01,Point(2 2)@2019-09-02),[Point(1 1)@2019-09-03,Point(1 1)@2019-09-05]}" ), ), ], @@ -2453,10 +2352,7 @@ def test_minus_max(self, temporal, expected): ], ) def test_at_minus(self, temporal, restrictor): - assert ( - TGeomPoint.from_merge(temporal.at(restrictor), temporal.minus(restrictor)) - == temporal - ) + assert TGeomPoint.from_merge(temporal.at(restrictor), temporal.minus(restrictor)) == temporal @pytest.mark.parametrize( "temporal", @@ -2464,12 +2360,8 @@ def test_at_minus(self, temporal, restrictor): ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], ) def test_at_minus_min_max(self, temporal): - assert ( - TGeomPoint.from_merge(temporal.at_min(), temporal.minus_min()) == temporal - ) - assert ( - TGeomPoint.from_merge(temporal.at_max(), temporal.minus_max()) == temporal - ) + assert TGeomPoint.from_merge(temporal.at_min(), temporal.minus_min()) == temporal + assert TGeomPoint.from_merge(temporal.at_max(), temporal.minus_max()) == temporal class TestTGeomPointTopologicalFunctions(TestTGeomPoint): @@ -2670,8 +2562,7 @@ class TestTGeomPointPositionFunctions(TestTGeomPoint): tpds3d = TGeomPointSeq("{Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02}") tps3d = TGeomPointSeq("[Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02]") tpss3d = TGeomPointSeqSet( - "{[Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02]," - "[Point(1 1 1)@2019-09-03, Point(1 1 1)@2019-09-05]}" + "{[Point(1 1 1)@2019-09-01, Point(2 2 2)@2019-09-02],[Point(1 1 1)@2019-09-03, Point(1 1 1)@2019-09-05]}" ) @pytest.mark.parametrize( @@ -2947,23 +2838,12 @@ class TestTGeomPointEverSpatialOperations(TestTGeomPoint): ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], ) def test_temporal_ever_contained_withindist_intersects(self, temporal, expected): - assert ( - temporal.is_ever_contained_in( - Polygon([(0, 0), (0, 2), (2, 2), (2, 0), (0, 0)]) - ) - == expected - ) + assert temporal.is_ever_contained_in(Polygon([(0, 0), (0, 2), (2, 2), (2, 0), (0, 0)])) == expected assert temporal.is_ever_contained_in(STBox("STBOX X((0,0),(2,2))")) == expected assert temporal.is_ever_within_distance(Point(1, 1), 1) == expected - assert ( - temporal.is_ever_within_distance(TGeomPointInst("Point(1 1)@2019-09-01"), 1) - == expected - ) + assert temporal.is_ever_within_distance(TGeomPointInst("Point(1 1)@2019-09-01"), 1) == expected assert temporal.ever_intersects(Point(1, 1)) == expected - assert ( - temporal.ever_intersects(TGeomPointInst("Point(1 1)@2019-09-01")) - == expected - ) + assert temporal.ever_intersects(TGeomPointInst("Point(1 1)@2019-09-01")) == expected # Verify that these results are correct wrt lifting the 9DEM definition of touches @pytest.mark.parametrize( @@ -2991,10 +2871,7 @@ def test_temporal_ever_touches(self, temporal, expected): ) def test_temporal_ever_disjoint(self, temporal, expected): assert temporal.is_ever_disjoint(Point(3, 3)) == expected - assert ( - temporal.is_ever_disjoint(TGeomPointInst("Point(3 3)@2019-09-01")) - == expected - ) + assert temporal.is_ever_disjoint(TGeomPointInst("Point(3 3)@2019-09-01")) == expected class TestTGeomPointTemporalSpatialOperations(TestTGeomPoint): @@ -3012,15 +2889,12 @@ class TestTGeomPointTemporalSpatialOperations(TestTGeomPoint): (tpds, TBoolSeq("{True@2019-09-01, False@2019-09-02}")), ( tps, - TBoolSeqSet( - "{[True@2019-09-01], (False@2019-09-01, False@2019-09-02]}" - ), + TBoolSeqSet("{[True@2019-09-01], (False@2019-09-01, False@2019-09-02]}"), ), ( tpss, TBoolSeqSet( - "{[True@2019-09-01], (False@2019-09-01, False@2019-09-02]," - "[True@2019-09-03, True@2019-09-05]}" + "{[True@2019-09-01], (False@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}" ), ), ], @@ -3039,10 +2913,7 @@ def test_temporal_intersects_disjoint(self, temporal, expected): (tps, TBoolSeqSet("[False@2019-09-01, False@2019-09-02]")), ( tpss, - TBoolSeqSet( - "{[False@2019-09-01, False@2019-09-02]," - "[False@2019-09-03, False@2019-09-05]}" - ), + TBoolSeqSet("{[False@2019-09-01, False@2019-09-02],[False@2019-09-03, False@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -3059,10 +2930,7 @@ def test_temporal_touches(self, temporal, expected): ( tpss, Point(1, 1), - TBoolSeqSet( - "{[True@2019-09-01, True@2019-09-02]," - "[True@2019-09-03, True@2019-09-05]}" - ), + TBoolSeqSet("{[True@2019-09-01, True@2019-09-02],[True@2019-09-03, True@2019-09-05]}"), ), ( tpi, @@ -3082,13 +2950,9 @@ def test_temporal_touches(self, temporal, expected): ( tpss, TGeomPointSeqSet( - "{[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02]," - "[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" - ), - TBoolSeqSet( - "{[True@2019-09-01, True@2019-09-02]," - "[True@2019-09-03, True@2019-09-05]}" + "{[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02],[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" ), + TBoolSeqSet("{[True@2019-09-01, True@2019-09-02],[True@2019-09-03, True@2019-09-05]}"), ), ], ids=[ @@ -3113,25 +2977,14 @@ def test_temporal_withindist(self, temporal, argument, expected): (tps, TBoolSeqSet("{[True@2019-09-01, True@2019-09-02]}")), ( tpss, - TBoolSeqSet( - "{[True@2019-09-01, True@2019-09-02]," - "[True@2019-09-03, True@2019-09-05]}" - ), + TBoolSeqSet("{[True@2019-09-01, True@2019-09-02],[True@2019-09-03, True@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], ) def test_temporal_contained(self, temporal, expected): - assert ( - temporal.is_spatially_contained_in( - Polygon([(0, 0), (0, 3), (3, 3), (3, 0), (0, 0)]) - ) - == expected - ) - assert ( - temporal.is_spatially_contained_in(STBox("STBOX X((0,0),(3,3))")) - == expected - ) + assert temporal.is_spatially_contained_in(Polygon([(0, 0), (0, 3), (3, 3), (3, 0), (0, 0)])) == expected + assert temporal.is_spatially_contained_in(STBox("STBOX X((0,0),(3,3))")) == expected class TestTGeomPointDistanceOperations(TestTGeomPoint): @@ -3151,9 +3004,7 @@ class TestTGeomPointDistanceOperations(TestTGeomPoint): ( tpss, Point(1, 1), - TFloatSeqSet( - "{[0@2019-09-01, 1.414@2019-09-02]," "[0@2019-09-03, 0@2019-09-05]}" - ), + TFloatSeqSet("{[0@2019-09-01, 1.414@2019-09-02],[0@2019-09-03, 0@2019-09-05]}"), ), (tpi, STBox("STBOX X((1,1),(1,1))"), TFloatInst("0@2019-09-01")), ( @@ -3169,9 +3020,7 @@ class TestTGeomPointDistanceOperations(TestTGeomPoint): ( tpss, STBox("STBOX X((1,1),(1,1))"), - TFloatSeqSet( - "{[0@2019-09-01, 1.414@2019-09-02]," "[0@2019-09-03, 0@2019-09-05]}" - ), + TFloatSeqSet("{[0@2019-09-01, 1.414@2019-09-02],[0@2019-09-03, 0@2019-09-05]}"), ), (tpi, TGeomPointInst("Point(1 1)@2019-09-01"), TFloatInst("0@2019-09-01")), ( @@ -3187,12 +3036,9 @@ class TestTGeomPointDistanceOperations(TestTGeomPoint): ( tpss, TGeomPointSeqSet( - "{[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02]," - "[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" - ), - TFloatSeqSet( - "{[0@2019-09-01, 1.414@2019-09-02]," "[0@2019-09-03, 0@2019-09-05]}" + "{[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02],[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" ), + TFloatSeqSet("{[0@2019-09-01, 1.414@2019-09-02],[0@2019-09-03, 0@2019-09-05]}"), ), ], ids=[ @@ -3227,8 +3073,7 @@ def test_distance(self, temporal, argument, expected): ( tpss, TGeomPointSeqSet( - "{[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02]," - "[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" + "{[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02],[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" ), ), ], @@ -3244,9 +3089,7 @@ def test_distance(self, temporal, argument, expected): ], ) def test_nearest_approach_instant(self, temporal, argument): - assert temporal.nearest_approach_instant(argument) == TGeomPointInst( - "Point(1 1)@2019-09-01" - ) + assert temporal.nearest_approach_instant(argument) == TGeomPointInst("Point(1 1)@2019-09-01") @pytest.mark.parametrize( "temporal, argument", @@ -3261,8 +3104,7 @@ def test_nearest_approach_instant(self, temporal, argument): ( tpss, TGeomPointSeqSet( - "{[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02]," - "[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" + "{[Point(1 1)@2019-09-01, Point(1 1)@2019-09-02],[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" ), ), ], @@ -3322,12 +3164,8 @@ def test_time_split(self, temporal, expected): ( tps, [ - TGeomPointSeq( - "[Point(1 1)@2019-09-01, Point(1.5 1.5)@2019-09-01 12:00:00+00)" - ), - TGeomPointSeq( - "[Point(1.5 1.5)@2019-09-01 12:00:00+00, Point(2 2)@2019-09-02]" - ), + TGeomPointSeq("[Point(1 1)@2019-09-01, Point(1.5 1.5)@2019-09-01 12:00:00+00)"), + TGeomPointSeq("[Point(1.5 1.5)@2019-09-01 12:00:00+00, Point(2 2)@2019-09-02]"), ], ), ( @@ -3408,10 +3246,7 @@ def test_space_split(self, temporal, expected): ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], ) def test_space_time_split(self, temporal, expected): - assert ( - temporal.space_time_split(1.0, timedelta(days=2), time_start="2019-09-01") - == expected - ) + assert temporal.space_time_split(1.0, timedelta(days=2), time_start="2019-09-01") == expected class TestTGeomPointComparisons(TestTGeomPoint): @@ -3511,9 +3346,7 @@ class TestTGeomPointTemporalComparisons(TestTGeomPoint): tpss = TGeomPointSeqSet( "{[Point(1 1)@2019-09-01, Point(2 2)@2019-09-02],[Point(1 1)@2019-09-03, Point(1 1)@2019-09-05]}" ) - argument = TGeomPointSeq( - "[Point(2 2)@2019-09-01, Point(1 1)@2019-09-02, Point(1 1)@2019-09-03]" - ) + argument = TGeomPointSeq("[Point(2 2)@2019-09-01, Point(1 1)@2019-09-02, Point(1 1)@2019-09-03]") @pytest.mark.parametrize( "temporal, expected", @@ -3523,8 +3356,7 @@ class TestTGeomPointTemporalComparisons(TestTGeomPoint): ( tps, TBoolSeqSet( - "{[False@2019-09-01, True@2019-09-01 12:00:00+00]," - "(False@2019-09-01 12:00:00+00, False@2019-09-02]}" + "{[False@2019-09-01, True@2019-09-01 12:00:00+00],(False@2019-09-01 12:00:00+00, False@2019-09-02]}" ), ), ( @@ -3549,9 +3381,7 @@ def test_temporal_equal_temporal(self, temporal, expected): ( tps, Point(1, 1), - TBoolSeqSet( - "{[True@2019-09-01], (False@2019-09-01, False@2019-09-02]}" - ), + TBoolSeqSet("{[True@2019-09-01], (False@2019-09-01, False@2019-09-02]}"), ), ( tpss, @@ -3566,9 +3396,7 @@ def test_temporal_equal_temporal(self, temporal, expected): ( tpss, Point(2, 2), - TBoolSeqSet( - "{[False@2019-09-01, True@2019-09-02],[False@2019-09-03, False@2019-09-05]}" - ), + TBoolSeqSet("{[False@2019-09-01, True@2019-09-02],[False@2019-09-03, False@2019-09-05]}"), ), ], ids=[ diff --git a/tests/main/tint_test.py b/tests/main/tint_test.py index 03158221..42431b0c 100644 --- a/tests/main/tint_test.py +++ b/tests/main/tint_test.py @@ -1,29 +1,29 @@ from copy import copy -from datetime import datetime, timezone, timedelta +from datetime import datetime, timedelta, timezone from operator import not_ import pytest from pymeos import ( + IntSet, + IntSpan, + IntSpanSet, TBoolInst, TBoolSeq, TBoolSeqSet, + TBox, TFloat, TFloatInst, TFloatSeq, TFloatSeqSet, TInt, + TInterpolation, TIntInst, TIntSeq, TIntSeqSet, - TInterpolation, - TBox, TsTzSet, TsTzSpan, TsTzSpanSet, - IntSpan, - IntSet, - IntSpanSet, ) from tests.conftest import TestPyMEOS @@ -53,9 +53,7 @@ class TestTIntConstructors(TestTInt): TInterpolation.STEPWISE, ), ( - TFloatSeqSet( - "{[1.5@2019-09-01, 0.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}" - ), + TFloatSeqSet("{[1.5@2019-09-01, 0.5@2019-09-02],[1.5@2019-09-03, 1.5@2019-09-05]}"), TIntSeqSet, TInterpolation.STEPWISE, ), @@ -131,8 +129,7 @@ def test_string_constructor(self, source, type, interpolation, expected): "[1@2019-09-01 00:00:00+00, 2@2019-09-05 00:00:00+00]", ), ( - "{[1@2019-09-01, 1@2019-09-02, 1@2019-09-03, 2@2019-09-05]," - "[1@2019-09-07, 1@2019-09-08, 1@2019-09-09]}", + "{[1@2019-09-01, 1@2019-09-02, 1@2019-09-03, 2@2019-09-05],[1@2019-09-07, 1@2019-09-08, 1@2019-09-09]}", TIntSeqSet, "{[1@2019-09-01 00:00:00+00, 2@2019-09-05 00:00:00+00], " "[1@2019-09-07 00:00:00+00, 1@2019-09-09 00:00:00+00]}", @@ -233,9 +230,7 @@ def test_value_timestamp_instant_constructor(self, value, timestamp): "Mixed Stepwise Normalized", ], ) - def test_instant_list_sequence_constructor( - self, list, interpolation, normalize, expected - ): + def test_instant_list_sequence_constructor(self, list, interpolation, normalize, expected): tis = TIntSeq( instant_list=list, interpolation=interpolation, @@ -245,9 +240,7 @@ def test_instant_list_sequence_constructor( assert str(tis) == expected assert tis.interpolation() == interpolation - tis2 = TIntSeq.from_instants( - list, interpolation=interpolation, normalize=normalize, upper_inc=True - ) + tis2 = TIntSeq.from_instants(list, interpolation=interpolation, normalize=normalize, upper_inc=True) assert str(tis2) == expected assert tis2.interpolation() == interpolation @@ -494,9 +487,7 @@ class TestTIntConversions(TestTInt): (tis, TFloatSeq("Interp=Step;[1@2019-09-01,2@2019-09-02]")), ( tiss, - TFloatSeq( - "Interp=Step;{[1@2019-09-01,2@2019-09-02],[1@2019-09-03,1@2019-09-05]}" - ), + TFloatSeq("Interp=Step;{[1@2019-09-01,2@2019-09-02],[1@2019-09-03,1@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Step Sequence", "Step Sequence Set"], @@ -899,9 +890,7 @@ def test_hash(self, temporal, expected): def test_value_timestamp(self): assert self.tii.value() == 1 - assert self.tii.timestamp() == datetime( - year=2019, month=9, day=1, tzinfo=timezone.utc - ) + assert self.tii.timestamp() == datetime(year=2019, month=9, day=1, tzinfo=timezone.utc) @pytest.mark.parametrize( "temporal, expected", @@ -916,10 +905,7 @@ def test_lower_upper_inc(self, temporal, expected): assert temporal.upper_inc() == expected def test_sequenceset_sequence_functions(self): - tiss1 = TIntSeqSet( - "{[1@2019-09-01, 2@2019-09-02]," - "[1@2019-09-03, 1@2019-09-05], [3@2019-09-06]}" - ) + tiss1 = TIntSeqSet("{[1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05], [3@2019-09-06]}") assert tiss1.num_sequences() == 3 assert tiss1.start_sequence() == TIntSeq("[1@2019-09-01, 2@2019-09-02]") assert tiss1.end_sequence() == TIntSeq("[3@2019-09-06]") @@ -1085,16 +1071,12 @@ def test_set_interpolation(self, temporal, interpolation, expected): ( tiss, 2, - TIntSeqSet( - "{[3@2019-09-01, 4@2019-09-02]," "[3@2019-09-03, 3@2019-09-05]}" - ), + TIntSeqSet("{[3@2019-09-01, 4@2019-09-02],[3@2019-09-03, 3@2019-09-05]}"), ), ( tiss, -2, - TIntSeqSet( - "{[-1@2019-09-01, 0@2019-09-02]," "[-1@2019-09-03, -1@2019-09-05]}" - ), + TIntSeqSet("{[-1@2019-09-01, 0@2019-09-02],[-1@2019-09-03, -1@2019-09-05]}"), ), ], ids=[ @@ -1120,9 +1102,7 @@ def test_shift_value(self, tint, delta, expected): ( tiss, 3, - TIntSeqSet( - "{[1@2019-09-01, 4@2019-09-02], [1@2019-09-03, 1@2019-09-05]}" - ), + TIntSeqSet("{[1@2019-09-01, 4@2019-09-02], [1@2019-09-03, 1@2019-09-05]}"), ), ], ids=[ @@ -1148,17 +1128,13 @@ def test_scale_value(self, tint, width, expected): tiss, 2, 3, - TIntSeqSet( - "{[3@2019-09-01, 6@2019-09-02], [3@2019-09-03, 3@2019-09-05]}" - ), + TIntSeqSet("{[3@2019-09-01, 6@2019-09-02], [3@2019-09-03, 3@2019-09-05]}"), ), ( tiss, -2, 3, - TIntSeqSet( - "{[-1@2019-09-01, 2@2019-09-02], [-1@2019-09-03, -1@2019-09-05]}" - ), + TIntSeqSet("{[-1@2019-09-01, 2@2019-09-02], [-1@2019-09-03, -1@2019-09-05]}"), ), ], ids=[ @@ -1209,31 +1185,25 @@ def test_shift_scale_value(self, tint, delta, width, expected): ( tiss, timedelta(days=4), - TIntSeqSet( - "{[1@2019-09-05, 2@2019-09-06],[1@2019-09-07, 1@2019-09-09]}" - ), + TIntSeqSet("{[1@2019-09-05, 2@2019-09-06],[1@2019-09-07, 1@2019-09-09]}"), ), ( tiss, timedelta(days=-4), - TIntSeqSet( - "{[1@2019-08-28, 2@2019-08-29],[1@2019-08-30, 1@2019-09-01]}" - ), + TIntSeqSet("{[1@2019-08-28, 2@2019-08-29],[1@2019-08-30, 1@2019-09-01]}"), ), ( tiss, timedelta(hours=2), TIntSeqSet( - "{[1@2019-09-01 02:00:00, 2@2019-09-02 02:00:00]," - "[1@2019-09-03 02:00:00, 1@2019-09-05 02:00:00]}" + "{[1@2019-09-01 02:00:00, 2@2019-09-02 02:00:00],[1@2019-09-03 02:00:00, 1@2019-09-05 02:00:00]}" ), ), ( tiss, timedelta(hours=-2), TIntSeqSet( - "{[1@2019-08-31 22:00:00, 2@2019-09-01 22:00:00]," - "[1@2019-09-02 22:00:00, 1@2019-09-04 22:00:00]}" + "{[1@2019-08-31 22:00:00, 2@2019-09-01 22:00:00],[1@2019-09-02 22:00:00, 1@2019-09-04 22:00:00]}" ), ), ], @@ -1279,16 +1249,13 @@ def test_shift_time(self, tint, delta, expected): ( tiss, timedelta(days=4), - TIntSeqSet( - "{[1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05]}" - ), + TIntSeqSet("{[1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05]}"), ), ( tiss, timedelta(hours=2), TIntSeqSet( - "{[1@2019-09-01 00:00:00, 2@2019-09-01 00:30:00]," - "[1@2019-09-01 01:00:00, 1@2019-09-01 02:00:00]}" + "{[1@2019-09-01 00:00:00, 2@2019-09-01 00:30:00],[1@2019-09-01 01:00:00, 1@2019-09-01 02:00:00]}" ), ), ], @@ -1307,11 +1274,8 @@ def test_scale_time(self, tint, delta, expected): assert tint.scale_time(delta) == expected def test_shift_scale_time(self): - assert self.tiss.shift_scale_time( - timedelta(days=4), timedelta(hours=2) - ) == TIntSeqSet( - "{[1@2019-09-05 00:00:00, 2@2019-09-05 00:30:00]," - "[1@2019-09-05 01:00:00, 1@2019-09-05 02:00:00]}" + assert self.tiss.shift_scale_time(timedelta(days=4), timedelta(hours=2)) == TIntSeqSet( + "{[1@2019-09-05 00:00:00, 2@2019-09-05 00:30:00],[1@2019-09-05 01:00:00, 1@2019-09-05 02:00:00]}" ) @pytest.mark.parametrize( @@ -1359,9 +1323,7 @@ def test_temporal_sample(self, tint, delta, expected): (tis, TFloatSeq("Interp=Step;[1@2019-09-01, 2@2019-09-02]")), ( tiss, - TFloatSeqSet( - "Interp=Step;{[1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05]}" - ), + TFloatSeqSet("Interp=Step;{[1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1393,9 +1355,7 @@ class TestTIntModifications(TestTInt): ( tiss, TIntSeq("[1@2019-09-06]"), - TIntSeqSet( - "{[1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05],[1@2019-09-06]}" - ), + TIntSeqSet("{[1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05],[1@2019-09-06]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1416,9 +1376,7 @@ def test_insert(self, temporal, sequence, expected): ( tiss, TIntInst("2@2019-09-01"), - TIntSeqSet( - "{[2@2019-09-01], (1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05]}" - ), + TIntSeqSet("{[2@2019-09-01], (1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1444,9 +1402,7 @@ def test_update(self, temporal, instant, expected): ( tiss, datetime(year=2019, month=9, day=1, tzinfo=timezone.utc), - TIntSeqSet( - "{(1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05]}" - ), + TIntSeqSet("{(1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05]}"), ), ], ids=[ @@ -1477,9 +1433,7 @@ def test_delete(self, temporal, time, expected): ( tiss, TIntInst("1@2019-09-06"), - TIntSeqSet( - "{[1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-06]}" - ), + TIntSeqSet("{[1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-06]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1503,9 +1457,7 @@ def test_append_instant(self, temporal, instant, expected): ( tiss, TIntSeq("[1@2019-09-06]"), - TIntSeqSet( - "{[1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05],[1@2019-09-06]}" - ), + TIntSeqSet("{[1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05],[1@2019-09-06]}"), ), ], ids=["Discrete Sequence", "Sequence", "SequenceSet"], @@ -1548,9 +1500,7 @@ def test_temporal_add_temporal(self, temporal, argument, expected): ( tiss, 1, - TIntSeqSet( - "{[2@2019-09-01, 3@2019-09-02],[2@2019-09-03, 2@2019-09-05]}" - ), + TIntSeqSet("{[2@2019-09-01, 3@2019-09-02],[2@2019-09-03, 2@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1588,9 +1538,7 @@ def test_temporal_sub_temporal(self, temporal, argument, expected): ( tiss, 1, - TIntSeqSet( - "{[0@2019-09-01, 1@2019-09-02],[0@2019-09-03, 0@2019-09-05]}" - ), + TIntSeqSet("{[0@2019-09-01, 1@2019-09-02],[0@2019-09-03, 0@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1636,9 +1584,7 @@ def test_temporal_mul_temporal(self, temporal, argument, expected): ( tiss, 2, - TIntSeqSet( - "{[2@2019-09-01, 4@2019-09-02],[2@2019-09-03, 2@2019-09-05]}" - ), + TIntSeqSet("{[2@2019-09-01, 4@2019-09-02],[2@2019-09-03, 2@2019-09-05]}"), ), ], ids=[ @@ -1693,9 +1639,7 @@ def test_temporal_div_temporal(self, temporal, argument, expected): ( tiss, 2, - TIntSeqSet( - "{[0@2019-09-01, 1@2019-09-02],[0@2019-09-03, 0@2019-09-05]}" - ), + TIntSeqSet("{[0@2019-09-01, 1@2019-09-02],[0@2019-09-03, 0@2019-09-05]}"), ), ], ids=[ @@ -1730,9 +1674,7 @@ def test_abs(self, temporal): (tis, TIntSeq("[1@2019-09-01, 1@2019-09-02)")), ( tiss, - TIntSeqSet( - "{[1@2019-09-01, 1@2019-09-02),[0@2019-09-03, 0@2019-09-05)}" - ), + TIntSeqSet("{[1@2019-09-01, 1@2019-09-02),[0@2019-09-03, 0@2019-09-05)}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1776,9 +1718,7 @@ class TestTIntRestrictors(TestTInt): ( tiss, tstzspan_set, - TIntSeqSet( - "{[1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05]}" - ), + TIntSeqSet("{[1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05]}"), ), ], ids=[ @@ -1863,18 +1803,14 @@ def test_at_time(self, temporal, restrictor, expected): ( tiss, 1, - TIntSeqSet( - "{[1@2019-09-01, 1@2019-09-02),[1@2019-09-03, 1@2019-09-05]}" - ), + TIntSeqSet("{[1@2019-09-01, 1@2019-09-02),[1@2019-09-03, 1@2019-09-05]}"), ), (tiss, 2, TIntSeqSet("{[2@2019-09-02]}")), (tiss, IntSet(elements=[1, 2]), tiss), ( tiss, IntSpan(lower=1, upper=1, lower_inc=True, upper_inc=True), - TIntSeqSet( - "{[1@2019-09-01, 1@2019-09-02),[1@2019-09-03, 1@2019-09-05]}" - ), + TIntSeqSet("{[1@2019-09-01, 1@2019-09-02),[1@2019-09-03, 1@2019-09-05]}"), ), ( tiss, @@ -1921,9 +1857,7 @@ def test_at_values(self, temporal, restrictor, expected): (tis, TIntSeq("{[1@2019-09-01, 1@2019-09-02)}")), ( tiss, - TIntSeqSet( - "{[1@2019-09-01, 1@2019-09-02),[1@2019-09-03, 1@2019-09-05]}" - ), + TIntSeqSet("{[1@2019-09-01, 1@2019-09-02),[1@2019-09-03, 1@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1962,16 +1896,12 @@ def test_at_max(self, temporal, expected): ( tiss, timestamp, - TIntSeqSet( - "{(1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05]}" - ), + TIntSeqSet("{(1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05]}"), ), ( tiss, timestamp_set, - TIntSeqSet( - "{(1@2019-09-01, 2@2019-09-02],(1@2019-09-03, 1@2019-09-05]}" - ), + TIntSeqSet("{(1@2019-09-01, 2@2019-09-02],(1@2019-09-03, 1@2019-09-05]}"), ), (tiss, tstzspan, TIntSeqSet("{[1@2019-09-03, 1@2019-09-05]}")), (tiss, tstzspan_set, None), @@ -2055,9 +1985,7 @@ def test_minus_time(self, temporal, restrictor, expected): ( tiss, 2, - TIntSeqSet( - "{[1@2019-09-01, 1@2019-09-02),[1@2019-09-03, 1@2019-09-05]}" - ), + TIntSeqSet("{[1@2019-09-01, 1@2019-09-02),[1@2019-09-03, 1@2019-09-05]}"), ), (tiss, IntSet(elements=[1, 2]), None), ( @@ -2113,9 +2041,7 @@ def test_minus_values(self, temporal, restrictor, expected): (tis, TIntSeq("[1@2019-09-01, 1@2019-09-02)")), ( tiss, - TIntSeqSet( - "{[1@2019-09-01, 1@2019-09-02),[1@2019-09-03, 1@2019-09-05]}" - ), + TIntSeqSet("{[1@2019-09-01, 1@2019-09-02),[1@2019-09-03, 1@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -2248,10 +2174,7 @@ def test_minus_min(self, temporal, expected): ], ) def test_at_minus(self, temporal, restrictor): - assert ( - TInt.from_merge(temporal.at(restrictor), temporal.minus(restrictor)) - == temporal - ) + assert TInt.from_merge(temporal.at(restrictor), temporal.minus(restrictor)) == temporal @pytest.mark.parametrize( "temporal", @@ -2629,9 +2552,7 @@ class TestTIntSplitOperations(TestTInt): ( tiss, [ - TIntSeqSet( - "{[1@2019-09-01, 1@2019-09-02),[1@2019-09-03, 1@2019-09-05]}" - ), + TIntSeqSet("{[1@2019-09-01, 1@2019-09-02),[1@2019-09-03, 1@2019-09-05]}"), TIntSeq("[2@2019-09-02]"), ], ), @@ -2680,9 +2601,7 @@ def test_time_split(self, temporal, expected): ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], ) def test_value_time_split(self, temporal, expected): - assert ( - temporal.value_time_split(2, timedelta(days=2), 0, "2019-09-01") == expected - ) + assert temporal.value_time_split(2, timedelta(days=2), 0, "2019-09-01") == expected class TestTIntComparisons(TestTInt): @@ -2914,9 +2833,7 @@ def test_temporal_equal_temporal(self, temporal, expected): (tis, TBoolSeq("[True@2019-09-01, False@2019-09-02]")), ( tiss, - TBoolSeqSet( - "{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}" - ), + TBoolSeqSet("{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -2950,9 +2867,7 @@ def test_temporal_not_equal_temporal(self, temporal, expected): (tis, TBoolSeq("[False@2019-09-01, True@2019-09-02]")), ( tiss, - TBoolSeqSet( - "{[False@2019-09-01, True@2019-09-02],[False@2019-09-03, False@2019-09-05]}" - ), + TBoolSeqSet("{[False@2019-09-01, True@2019-09-02],[False@2019-09-03, False@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], diff --git a/tests/main/ttext_test.py b/tests/main/ttext_test.py index c3900997..c575a447 100644 --- a/tests/main/ttext_test.py +++ b/tests/main/ttext_test.py @@ -1,25 +1,23 @@ from copy import copy -from datetime import datetime, timezone, timedelta +from datetime import datetime, timedelta, timezone import pytest from pymeos import ( - TBool, TBoolInst, TBoolSeq, TBoolSeqSet, - TText, - TTextInst, - TTextSeq, - TTextSeqSet, - TInt, + TInterpolation, TIntInst, TIntSeq, TIntSeqSet, - TInterpolation, TsTzSet, TsTzSpan, TsTzSpanSet, + TText, + TTextInst, + TTextSeq, + TTextSeqSet, ) from tests.conftest import TestPyMEOS @@ -32,9 +30,7 @@ class TestTTextConstructors(TestTText): tti = TTextInst("AAA@2019-09-01") ttds = TTextSeq("{AAA@2019-09-01, BBB@2019-09-02}") tts = TTextSeq("[AAA@2019-09-01, BBB@2019-09-02]") - ttss = TTextSeqSet( - "{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}" - ) + ttss = TTextSeqSet("{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}") @pytest.mark.parametrize( "source, type, interpolation", @@ -51,9 +47,7 @@ class TestTTextConstructors(TestTText): TInterpolation.STEPWISE, ), ( - TIntSeqSet( - "{[1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05]}" - ), + TIntSeqSet("{[1@2019-09-01, 2@2019-09-02],[1@2019-09-03, 1@2019-09-05]}"), TTextSeqSet, TInterpolation.STEPWISE, ), @@ -234,9 +228,7 @@ def test_value_timestamp_instant_constructor(self, value, timestamp): "Mixed Stepwise Normalized", ], ) - def test_instant_list_sequence_constructor( - self, list, interpolation, normalize, expected - ): + def test_instant_list_sequence_constructor(self, list, interpolation, normalize, expected): tts = TTextSeq( instant_list=list, interpolation=interpolation, @@ -246,9 +238,7 @@ def test_instant_list_sequence_constructor( assert str(tts) == expected assert tts.interpolation() == interpolation - tts2 = TTextSeq.from_instants( - list, interpolation=interpolation, normalize=normalize, upper_inc=True - ) + tts2 = TTextSeq.from_instants(list, interpolation=interpolation, normalize=normalize, upper_inc=True) assert str(tts2) == expected assert tts2.interpolation() == interpolation @@ -278,9 +268,7 @@ class TestTTextOutputs(TestTText): tti = TTextInst("AAA@2019-09-01") ttds = TTextSeq("{AAA@2019-09-01, BBB@2019-09-02}") tts = TTextSeq("[AAA@2019-09-01, BBB@2019-09-02]") - ttss = TTextSeqSet( - "{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}" - ) + ttss = TTextSeqSet("{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}") @pytest.mark.parametrize( "temporal, expected", @@ -480,9 +468,7 @@ class TestTTextAccessors(TestTText): tti = TTextInst("AAA@2019-09-01") ttds = TTextSeq("{AAA@2019-09-01, BBB@2019-09-02}") tts = TTextSeq("[AAA@2019-09-01, BBB@2019-09-02]") - ttss = TTextSeqSet( - "{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}" - ) + ttss = TTextSeqSet("{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}") @pytest.mark.parametrize( "temporal, expected", @@ -860,9 +846,7 @@ def test_hash(self, temporal, expected): def test_value_timestamp(self): assert self.tti.value() == "AAA" - assert self.tti.timestamp() == datetime( - year=2019, month=9, day=1, tzinfo=timezone.utc - ) + assert self.tti.timestamp() == datetime(year=2019, month=9, day=1, tzinfo=timezone.utc) @pytest.mark.parametrize( "temporal, expected", @@ -877,10 +861,7 @@ def test_lower_upper_inc(self, temporal, expected): assert temporal.upper_inc() == expected def test_sequenceset_sequence_functions(self): - ttss1 = TTextSeqSet( - "{[AAA@2019-09-01, BBB@2019-09-02]," - "[AAA@2019-09-03, AAA@2019-09-05], [CCC@2019-09-06]}" - ) + ttss1 = TTextSeqSet("{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05], [CCC@2019-09-06]}") assert ttss1.num_sequences() == 3 assert ttss1.start_sequence() == TTextSeq("[AAA@2019-09-01, BBB@2019-09-02]") assert ttss1.end_sequence() == TTextSeq("[CCC@2019-09-06]") @@ -896,9 +877,7 @@ class TestTTextTransformations(TestTText): tti = TTextInst("AAA@2019-09-01") ttds = TTextSeq("{AAA@2019-09-01, BBB@2019-09-02}") tts = TTextSeq("[AAA@2019-09-01, BBB@2019-09-02]") - ttss = TTextSeqSet( - "{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}" - ) + ttss = TTextSeqSet("{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}") @pytest.mark.parametrize( "temporal, expected", @@ -1011,16 +990,12 @@ def test_to_sequenceset(self, temporal, interpolation, expected): ( ttss, timedelta(days=4), - TTextSeqSet( - "{[AAA@2019-09-05, BBB@2019-09-06],[AAA@2019-09-07, AAA@2019-09-09]}" - ), + TTextSeqSet("{[AAA@2019-09-05, BBB@2019-09-06],[AAA@2019-09-07, AAA@2019-09-09]}"), ), ( ttss, timedelta(days=-4), - TTextSeqSet( - "{[AAA@2019-08-28, BBB@2019-08-29],[AAA@2019-08-30, AAA@2019-09-01]}" - ), + TTextSeqSet("{[AAA@2019-08-28, BBB@2019-08-29],[AAA@2019-08-30, AAA@2019-09-01]}"), ), ( ttss, @@ -1081,9 +1056,7 @@ def test_shift_time(self, ttext, delta, expected): ( ttss, timedelta(days=4), - TTextSeqSet( - "{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}" - ), + TTextSeqSet("{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}"), ), ( ttss, @@ -1109,11 +1082,8 @@ def test_scale_time(self, ttext, delta, expected): assert ttext.scale_time(delta) == expected def test_shift_scale(self): - assert self.ttss.shift_scale_time( - timedelta(days=4), timedelta(hours=2) - ) == TTextSeqSet( - "{[AAA@2019-09-05 00:00:00, BBB@2019-09-05 00:30:00]," - "[AAA@2019-09-05 01:00:00, AAA@2019-09-05 02:00:00]}" + assert self.ttss.shift_scale_time(timedelta(days=4), timedelta(hours=2)) == TTextSeqSet( + "{[AAA@2019-09-05 00:00:00, BBB@2019-09-05 00:30:00],[AAA@2019-09-05 01:00:00, AAA@2019-09-05 02:00:00]}" ) @pytest.mark.parametrize( @@ -1158,9 +1128,7 @@ class TestTTextModifications(TestTText): tti = TTextInst("AAA@2019-09-01") ttds = TTextSeq("{AAA@2019-09-01, BBB@2019-09-02}") tts = TTextSeq("[AAA@2019-09-01, BBB@2019-09-02]") - ttss = TTextSeqSet( - "{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}" - ) + ttss = TTextSeqSet("{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}") @pytest.mark.parametrize( "temporal, sequence, expected", @@ -1183,9 +1151,7 @@ class TestTTextModifications(TestTText): ( ttss, TTextSeq("[AAA@2019-09-06]"), - TTextSeqSet( - "{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05],[AAA@2019-09-06]}" - ), + TTextSeqSet("{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05],[AAA@2019-09-06]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1210,9 +1176,7 @@ def test_insert(self, temporal, sequence, expected): ( ttss, TTextInst("BBB@2019-09-01"), - TTextSeqSet( - "{[BBB@2019-09-01], (AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}" - ), + TTextSeqSet("{[BBB@2019-09-01], (AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1238,9 +1202,7 @@ def test_update(self, temporal, instant, expected): ( ttss, datetime(year=2019, month=9, day=1, tzinfo=timezone.utc), - TTextSeqSet( - "{(AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}" - ), + TTextSeqSet("{(AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}"), ), ], ids=[ @@ -1275,9 +1237,7 @@ def test_delete(self, temporal, time, expected): ( ttss, TTextInst("AAA@2019-09-06"), - TTextSeqSet( - "{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-06]}" - ), + TTextSeqSet("{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-06]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1301,9 +1261,7 @@ def test_append_instant(self, temporal, instant, expected): ( ttss, TTextSeq("[AAA@2019-09-06]"), - TTextSeqSet( - "{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05],[AAA@2019-09-06]}" - ), + TTextSeqSet("{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05],[AAA@2019-09-06]}"), ), ], ids=["Discrete Sequence", "Sequence", "SequenceSet"], @@ -1316,9 +1274,7 @@ class TestTTextTextOperations(TestTText): tti = TTextInst("AAA@2019-09-01") ttds = TTextSeq("{AAA@2019-09-01, BBB@2019-09-02}") tts = TTextSeq("[AAA@2019-09-01, BBB@2019-09-02]") - ttss = TTextSeqSet( - "{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}" - ) + ttss = TTextSeqSet("{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}") argument = TTextSeq("[BBB@2019-09-01, AAA@2019-09-02, AAA@2019-09-03]") @pytest.mark.parametrize( @@ -1329,9 +1285,7 @@ class TestTTextTextOperations(TestTText): (tts, TTextSeq("[AAABBB@2019-09-01, BBBAAA@2019-09-02]")), ( ttss, - TTextSeqSet( - "{[AAABBB@2019-09-01, BBBAAA@2019-09-02],[AAAAAA@2019-09-03]}" - ), + TTextSeqSet("{[AAABBB@2019-09-01, BBBAAA@2019-09-02],[AAAAAA@2019-09-03]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1348,9 +1302,7 @@ def test_temporal_concat_temporal(self, temporal, expected): (tts, TTextSeq("[AAABBB@2019-09-01, BBBBBB@2019-09-02]")), ( ttss, - TTextSeqSet( - "{[AAABBB@2019-09-01, BBBBBB@2019-09-02],[AAABBB@2019-09-03, AAABBB@2019-09-05]}" - ), + TTextSeqSet("{[AAABBB@2019-09-01, BBBBBB@2019-09-02],[AAABBB@2019-09-03, AAABBB@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1367,9 +1319,7 @@ def test_temporal_concat_text(self, temporal, expected): (tts, TTextSeq("[BBBAAA@2019-09-01, BBBBBB@2019-09-02]")), ( ttss, - TTextSeqSet( - "{[BBBAAA@2019-09-01, BBBBBB@2019-09-02],[BBBAAA@2019-09-03, BBBAAA@2019-09-05]}" - ), + TTextSeqSet("{[BBBAAA@2019-09-01, BBBBBB@2019-09-02],[BBBAAA@2019-09-03, BBBAAA@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1385,9 +1335,7 @@ def test_temporal_radd_text(self, temporal, expected): (tts, TTextSeq("[aaa@2019-09-01, bbb@2019-09-02]")), ( ttss, - TTextSeqSet( - "{[aaa@2019-09-01, bbb@2019-09-02],[aaa@2019-09-03, aaa@2019-09-05]}" - ), + TTextSeqSet("{[aaa@2019-09-01, bbb@2019-09-02],[aaa@2019-09-03, aaa@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1408,9 +1356,7 @@ class TestTTextRestrictors(TestTText): tti = TTextInst("AAA@2019-09-01") ttds = TTextSeq("{AAA@2019-09-01, BBB@2019-09-02}") tts = TTextSeq("[AAA@2019-09-01, BBB@2019-09-02]") - ttss = TTextSeqSet( - "{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}" - ) + ttss = TTextSeqSet("{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}") timestamp = datetime(2019, 9, 1) timestamp_set = TsTzSet("{2019-09-01, 2019-09-03}") @@ -1447,16 +1393,12 @@ class TestTTextRestrictors(TestTText): ( ttss, tstzspan_set, - TTextSeqSet( - "{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}" - ), + TTextSeqSet("{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}"), ), ( ttss, "AAA", - TTextSeqSet( - "{[AAA@2019-09-01, AAA@2019-09-02),[AAA@2019-09-03, AAA@2019-09-05]}" - ), + TTextSeqSet("{[AAA@2019-09-01, AAA@2019-09-02),[AAA@2019-09-03, AAA@2019-09-05]}"), ), (ttss, "BBB", TTextSeqSet("{[BBB@2019-09-02]}")), (ttss, ["AAA", "BBB"], ttss), @@ -1516,9 +1458,7 @@ def test_at_max(self, temporal, expected): (tts, TTextSeq("{[AAA@2019-09-01, AAA@2019-09-02)}")), ( ttss, - TTextSeqSet( - "{[AAA@2019-09-01, AAA@2019-09-02), [AAA@2019-09-03, AAA@2019-09-05]}" - ), + TTextSeqSet("{[AAA@2019-09-01, AAA@2019-09-02), [AAA@2019-09-03, AAA@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1553,16 +1493,12 @@ def test_at_min(self, temporal, expected): ( ttss, timestamp, - TTextSeqSet( - "{(AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}" - ), + TTextSeqSet("{(AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}"), ), ( ttss, timestamp_set, - TTextSeqSet( - "{(AAA@2019-09-01, BBB@2019-09-02],(AAA@2019-09-03, AAA@2019-09-05]}" - ), + TTextSeqSet("{(AAA@2019-09-01, BBB@2019-09-02],(AAA@2019-09-03, AAA@2019-09-05]}"), ), (ttss, tstzspan, TTextSeqSet("{[AAA@2019-09-03, AAA@2019-09-05]}")), (ttss, tstzspan_set, None), @@ -1570,9 +1506,7 @@ def test_at_min(self, temporal, expected): ( ttss, "BBB", - TTextSeqSet( - "{[AAA@2019-09-01, AAA@2019-09-02),[AAA@2019-09-03, AAA@2019-09-05]}" - ), + TTextSeqSet("{[AAA@2019-09-01, AAA@2019-09-02),[AAA@2019-09-03, AAA@2019-09-05]}"), ), (ttss, ["AAA", "BBB"], None), ], @@ -1634,9 +1568,7 @@ def test_minus_min(self, temporal, expected): (tts, TTextSeq("{[AAA@2019-09-01, AAA@2019-09-02)}")), ( ttss, - TTextSeqSet( - "{[AAA@2019-09-01, AAA@2019-09-02), [AAA@2019-09-03, AAA@2019-09-05]}" - ), + TTextSeqSet("{[AAA@2019-09-01, AAA@2019-09-02), [AAA@2019-09-03, AAA@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -1708,10 +1640,7 @@ def test_minus_max(self, temporal, expected): ], ) def test_at_minus(self, temporal, restrictor): - assert ( - TText.from_merge(temporal.at(restrictor), temporal.minus(restrictor)) - == temporal - ) + assert TText.from_merge(temporal.at(restrictor), temporal.minus(restrictor)) == temporal @pytest.mark.parametrize( "temporal", @@ -1727,9 +1656,7 @@ class TestTTextTopologicalFunctions(TestTText): tti = TTextInst("AAA@2019-09-01") ttds = TTextSeq("{AAA@2019-09-01, BBB@2019-09-02}") tts = TTextSeq("[AAA@2019-09-01, BBB@2019-09-02]") - ttss = TTextSeqSet( - "{[AAA@2019-09-01, BBB@2019-09-02], [AAA@2019-09-03, AAA@2019-09-05]}" - ) + ttss = TTextSeqSet("{[AAA@2019-09-01, BBB@2019-09-02], [AAA@2019-09-03, AAA@2019-09-05]}") @pytest.mark.parametrize( "temporal, argument, expected", @@ -1819,9 +1746,7 @@ class TestTTextPositionFunctions(TestTText): tti = TTextInst("AAA@2019-09-01") ttds = TTextSeq("{AAA@2019-09-01, BBB@2019-09-02}") tts = TTextSeq("[AAA@2019-09-01, BBB@2019-09-02]") - ttss = TTextSeqSet( - "{[AAA@2019-09-01, BBB@2019-09-02], [AAA@2019-09-03, AAA@2019-09-05]}" - ) + ttss = TTextSeqSet("{[AAA@2019-09-01, BBB@2019-09-02], [AAA@2019-09-03, AAA@2019-09-05]}") @pytest.mark.parametrize( "temporal, argument, expected", @@ -1905,9 +1830,7 @@ def test_is_over_or_after(self, temporal, argument, expected): class TestTTextComparisons(TestTText): tt = TTextSeq("[AAA@2019-09-01, BBB@2019-09-02]") - other = TTextSeqSet( - "{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}" - ) + other = TTextSeqSet("{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}") def test_eq(self): _ = self.tt == self.other @@ -1932,9 +1855,7 @@ class TestTTextEverAlwaysComparisons(TestTText): tti = TTextInst("AAA@2019-09-01") ttds = TTextSeq("{AAA@2019-09-01, BBB@2019-09-02}") tts = TTextSeq("[AAA@2019-09-01, BBB@2019-09-02]") - ttss = TTextSeqSet( - "{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}" - ) + ttss = TTextSeqSet("{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}") @pytest.mark.parametrize( "temporal, expected", @@ -1989,9 +1910,7 @@ class TestTTextTemporalComparisons(TestTText): tti = TTextInst("AAA@2019-09-01") ttds = TTextSeq("{AAA@2019-09-01, BBB@2019-09-02}") tts = TTextSeq("[AAA@2019-09-01, BBB@2019-09-02]") - ttss = TTextSeqSet( - "{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}" - ) + ttss = TTextSeqSet("{[AAA@2019-09-01, BBB@2019-09-02],[AAA@2019-09-03, AAA@2019-09-05]}") argument = TTextSeq("[BBB@2019-09-01, AAA@2019-09-02, AAA@2019-09-03]") @pytest.mark.parametrize( @@ -2018,9 +1937,7 @@ def test_temporal_equal_temporal(self, temporal, expected): (tts, TBoolSeq("[True@2019-09-01, False@2019-09-02]")), ( ttss, - TBoolSeqSet( - "{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}" - ), + TBoolSeqSet("{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -2054,9 +1971,7 @@ def test_temporal_not_equal_temporal(self, temporal, expected): (tts, TBoolSeq("[False@2019-09-01, True@2019-09-02]")), ( ttss, - TBoolSeqSet( - "{[False@2019-09-01, True@2019-09-02],[False@2019-09-03, False@2019-09-05]}" - ), + TBoolSeqSet("{[False@2019-09-01, True@2019-09-02],[False@2019-09-03, False@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], diff --git a/tests/temporal/interpolation_test.py b/tests/temporal/interpolation_test.py index 308865fc..8e30108e 100644 --- a/tests/temporal/interpolation_test.py +++ b/tests/temporal/interpolation_test.py @@ -1,6 +1,7 @@ +import pytest + from pymeos import TInterpolation from tests.conftest import TestPyMEOS -import pytest class TestTInterpolation(TestPyMEOS): From 0f977e7f9879d2fc9a76d66b67e4f30a8a4b199c Mon Sep 17 00:00:00 2001 From: Arijit Samal <68030078+1-ARIjitS@users.noreply.github.com> Date: Mon, 5 Aug 2024 14:13:24 +0200 Subject: [PATCH 11/21] added correct function changed function signature from distance_datespanset_datespan to distance_datespan_datespan for datespan instance in distance fucntion of datespan class --- pymeos/collections/time/datespan.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pymeos/collections/time/datespan.py b/pymeos/collections/time/datespan.py index c2a70642..aafb0a2e 100644 --- a/pymeos/collections/time/datespan.py +++ b/pymeos/collections/time/datespan.py @@ -3,7 +3,6 @@ from datetime import date, timedelta from typing import TYPE_CHECKING, overload -from _meos_cffi.lib import distance_datespanset_datespan from pymeos_cffi import ( adjacent_span_date, after_span_date, @@ -19,6 +18,8 @@ datespan_shift_scale, datespan_to_tstzspan, datespan_upper, + distance_datespan_datespan, + distance_datespanset_datespan, distance_span_date, intersection_span_date, intersection_span_span, @@ -442,7 +443,7 @@ def distance(self, other: TimeDate) -> timedelta: A :class:`datetime.timedelta` instance MEOS Functions: - distance_span_date, distance_datespanset_datespan, + distance_span_date, distance_datespan_datespan, distance_datespanset_datespan """ from .dateset import DateSet @@ -452,7 +453,9 @@ def distance(self, other: TimeDate) -> timedelta: return timedelta(days=distance_span_date(self._inner, date_to_date_adt(other))) elif isinstance(other, DateSet): return self.distance(other.to_spanset()) - elif isinstance(other, (DateSpan, DateSpanSet)): + elif isinstance(other, DateSpan): + return timedelta(days=distance_datespan_datespan(self._inner, other._inner)) + elif isinstance(other, DateSpanSet): return timedelta(days=distance_datespanset_datespan(self._inner, other._inner)) else: return super().distance(other) From 0a0b48215754ba4f371be4a8a04227b89cd4d585 Mon Sep 17 00:00:00 2001 From: Esteban Zimanyi Date: Thu, 14 May 2026 17:12:42 +0200 Subject: [PATCH 12/21] Close PR #72 1.3 bump: circular imports + 1 test typo Three small fixes to bring PR #72 to a green-enough state for review: - pymeos/mixins/comparison.py and pymeos/mixins/simplify.py imported Temporal at module-import time from ..temporal, which now creates a circular import because the temporal package re-exports the mixins. Move both to TYPE_CHECKING and rely on string annotations (already enabled by 'from __future__ import annotations'). - tests/main/tfloat_test.py::test_temporal_equal_int referenced temporal_equal_1, a method that has never existed. The intended method is temporal_equal; tfloat already has it. With these and the PyMEOS-CFFI commit that adds the Datum helpers and the int *count auto-detect, pytest is 4472 / 4482 (10 failures remaining are pre-existing test fixture issues: tfloat fixtures expect True for 1.5 == 1, and a handful of TBool assertion mismatches that pre-date PR #72). --- pymeos/mixins/comparison.py | 7 +++++-- pymeos/mixins/simplify.py | 7 +++++-- tests/main/tfloat_test.py | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/pymeos/mixins/comparison.py b/pymeos/mixins/comparison.py index d2c1d5bd..6de2fd4b 100644 --- a/pymeos/mixins/comparison.py +++ b/pymeos/mixins/comparison.py @@ -1,4 +1,6 @@ -from typing import Any, TypeVar +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, TypeVar from pymeos_cffi import ( temporal_eq, @@ -9,7 +11,8 @@ temporal_ne, ) -from ..temporal import Temporal +if TYPE_CHECKING: + from ..temporal import Temporal Self = TypeVar("Self", bound="Temporal[Any]") diff --git a/pymeos/mixins/simplify.py b/pymeos/mixins/simplify.py index 1993e0f6..de8ba661 100644 --- a/pymeos/mixins/simplify.py +++ b/pymeos/mixins/simplify.py @@ -1,5 +1,7 @@ +from __future__ import annotations + from datetime import timedelta -from typing import Any, TypeVar +from typing import TYPE_CHECKING, Any, TypeVar from pymeos_cffi import ( temporal_simplify_dp, @@ -9,7 +11,8 @@ timedelta_to_interval, ) -from ..temporal import Temporal +if TYPE_CHECKING: + from ..temporal import Temporal Self = TypeVar("Self", bound="Temporal[Any]") diff --git a/tests/main/tfloat_test.py b/tests/main/tfloat_test.py index 0f212f65..eb357beb 100644 --- a/tests/main/tfloat_test.py +++ b/tests/main/tfloat_test.py @@ -3142,7 +3142,7 @@ def test_temporal_equal_temporal(self, temporal, expected): ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], ) def test_temporal_equal_int(self, temporal, expected): - assert temporal.temporal_equal_1(1) == expected + assert temporal.temporal_equal(1) == expected @pytest.mark.parametrize( "temporal, expected", From 52e82371408fd6cdb43bfaa664789e355f07476f Mon Sep 17 00:00:00 2001 From: Esteban Zimanyi Date: Thu, 14 May 2026 17:26:46 +0200 Subject: [PATCH 13/21] Bump apt postgresql-server-dev to 16 in the test workflow ubuntu-latest is on noble (24.04) which no longer ships postgresql-server-dev-14. Same fix that PyMEOS-CFFI #17 already applied (commit a0a4149). --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e81bb384..f99223ee 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -38,7 +38,7 @@ jobs: uses: awalsh128/cache-apt-pkgs-action@latest if: runner.os == 'Linux' with: - packages: build-essential cmake postgresql-server-dev-14 libproj-dev libjson-c-dev libgsl-dev libgeos-dev + packages: build-essential cmake postgresql-server-dev-16 libproj-dev libjson-c-dev libgsl-dev libgeos-dev version: 1.0 - name: Get dependencies from homebrew (cache) From ca1c81bb39459af1c01a7eb584ba917410f645f6 Mon Sep 17 00:00:00 2001 From: Esteban Zimanyi Date: Thu, 14 May 2026 17:27:48 +0200 Subject: [PATCH 14/21] ruff format on collections after master merge ruff format prefers ternary expressions without surrounding parens. The merge with master pulled in pre-ruff-format code that violated the convention; this aligns the affected files with the rest of the codebase. --- .gitignore | 2 +- pymeos/collections/geo/geoset.py | 4 ++-- pymeos/collections/number/floatspanset.py | 2 +- pymeos/collections/number/intspanset.py | 2 +- pymeos/collections/time/dateset.py | 2 +- pymeos/collections/time/datespan.py | 2 +- pymeos/collections/time/tstzset.py | 2 +- pymeos/collections/time/tstzspan.py | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index bf26d1b6..3fe91048 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,4 @@ docs/_build sandbox.py sandbox.ipynb -coverage.xml \ No newline at end of file +coverage.xml.venv/ diff --git a/pymeos/collections/geo/geoset.py b/pymeos/collections/geo/geoset.py index 80e18468..5b794d0a 100644 --- a/pymeos/collections/geo/geoset.py +++ b/pymeos/collections/geo/geoset.py @@ -307,11 +307,11 @@ class GeometrySet(GeoSet): _mobilitydb_name = "geomset" _parse_function = geomset_in - _parse_value_function = lambda x: (geom_in(x, -1) if isinstance(x, str) else geometry_to_gserialized(x)) + _parse_value_function = lambda x: geom_in(x, -1) if isinstance(x, str) else geometry_to_gserialized(x) class GeographySet(GeoSet): _mobilitydb_name = "geogset" _parse_function = geogset_in - _parse_value_function = lambda x: (geog_in(x, -1) if isinstance(x, str) else geography_to_gserialized(x)) + _parse_value_function = lambda x: geog_in(x, -1) if isinstance(x, str) else geography_to_gserialized(x) diff --git a/pymeos/collections/number/floatspanset.py b/pymeos/collections/number/floatspanset.py index f93462f4..911411dc 100644 --- a/pymeos/collections/number/floatspanset.py +++ b/pymeos/collections/number/floatspanset.py @@ -55,7 +55,7 @@ class FloatSpanSet(SpanSet[float]): _mobilitydb_name = "floatspanset" _parse_function = floatspanset_in - _parse_value_function = lambda span: (floatspanset_in(span)[0] if isinstance(span, str) else span._inner[0]) + _parse_value_function = lambda span: floatspanset_in(span)[0] if isinstance(span, str) else span._inner[0] # ------------------------- Output ---------------------------------------- def __str__(self, max_decimals: int = 15): diff --git a/pymeos/collections/number/intspanset.py b/pymeos/collections/number/intspanset.py index 3ef36b70..f7d13967 100644 --- a/pymeos/collections/number/intspanset.py +++ b/pymeos/collections/number/intspanset.py @@ -55,7 +55,7 @@ class IntSpanSet(SpanSet[int]): _mobilitydb_name = "intspanset" _parse_function = intspanset_in - _parse_value_function = lambda span: (intspanset_in(span)[0] if isinstance(span, str) else span._inner[0]) + _parse_value_function = lambda span: intspanset_in(span)[0] if isinstance(span, str) else span._inner[0] # ------------------------- Output ---------------------------------------- def __str__(self): diff --git a/pymeos/collections/time/dateset.py b/pymeos/collections/time/dateset.py index 61d38dba..0675eeb2 100644 --- a/pymeos/collections/time/dateset.py +++ b/pymeos/collections/time/dateset.py @@ -63,7 +63,7 @@ class DateSet(Set[date], TimeCollection[date]): _mobilitydb_name = "dateset" _parse_function = dateset_in - _parse_value_function = lambda x: (pg_date_in(x) if isinstance(x, str) else date_to_date_adt(x)) + _parse_value_function = lambda x: pg_date_in(x) if isinstance(x, str) else date_to_date_adt(x) _make_function = dateset_make # ------------------------- Constructors ---------------------------------- diff --git a/pymeos/collections/time/datespan.py b/pymeos/collections/time/datespan.py index aafb0a2e..934e2529 100644 --- a/pymeos/collections/time/datespan.py +++ b/pymeos/collections/time/datespan.py @@ -69,7 +69,7 @@ class DateSpan(Span[date], TimeCollection[date]): _mobilitydb_name = "datespan" _parse_function = datespan_in - _parse_value_function = lambda x: (pg_date_in(x) if isinstance(x, str) else date_to_date_adt(x)) + _parse_value_function = lambda x: pg_date_in(x) if isinstance(x, str) else date_to_date_adt(x) _make_function = datespan_make # ------------------------- Constructors ---------------------------------- diff --git a/pymeos/collections/time/tstzset.py b/pymeos/collections/time/tstzset.py index 3175880f..545b885e 100644 --- a/pymeos/collections/time/tstzset.py +++ b/pymeos/collections/time/tstzset.py @@ -39,7 +39,7 @@ class TsTzSet(Set[datetime], TimeCollection[datetime]): _mobilitydb_name = "tstzset" _parse_function = tstzset_in - _parse_value_function = lambda x: (pg_timestamptz_in(x, -1) if isinstance(x, str) else datetime_to_timestamptz(x)) + _parse_value_function = lambda x: pg_timestamptz_in(x, -1) if isinstance(x, str) else datetime_to_timestamptz(x) _make_function = tstzset_make # ------------------------- Constructors ---------------------------------- diff --git a/pymeos/collections/time/tstzspan.py b/pymeos/collections/time/tstzspan.py index faf501a3..966e5c98 100644 --- a/pymeos/collections/time/tstzspan.py +++ b/pymeos/collections/time/tstzspan.py @@ -41,7 +41,7 @@ class TsTzSpan(Span[datetime], TimeCollection[datetime]): _mobilitydb_name = "tstzspan" _parse_function = tstzspan_in - _parse_value_function = lambda x: (pg_timestamptz_in(x, -1) if isinstance(x, str) else datetime_to_timestamptz(x)) + _parse_value_function = lambda x: pg_timestamptz_in(x, -1) if isinstance(x, str) else datetime_to_timestamptz(x) _make_function = tstzspan_make # ------------------------- Constructors ---------------------------------- From d8f9c02f49ca6adb2a9760848ce1da968cb8aba8 Mon Sep 17 00:00:00 2001 From: Esteban Zimanyi Date: Thu, 14 May 2026 17:32:57 +0200 Subject: [PATCH 15/21] Look up matching MobilityDB/PyMEOS-CFFI branch by head_ref first The previous env: github.base_ref || github.ref_name resolved to 'master' for any PR, so a 1.3 / 1.4 PyMEOS PR would pull master's MobilityDB + PyMEOS-CFFI even though the matching code lives on the head branch. Try the head branch first and fall back to base_ref so push events on master keep working. --- .github/workflows/test.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f99223ee..f4dcf49f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -58,9 +58,10 @@ jobs: - name: Fetch MEOS sources env: - BRANCH_NAME: ${{ github.base_ref || github.ref_name }} + BRANCH_NAME: ${{ github.head_ref || github.ref_name }} run: | - git clone --branch ${{ env.BRANCH_NAME }} --depth 1 https://github.com/MobilityDB/MobilityDB + git clone --branch ${{ env.BRANCH_NAME }} --depth 1 https://github.com/MobilityDB/MobilityDB \ + || git clone --branch ${{ github.base_ref || 'master' }} --depth 1 https://github.com/MobilityDB/MobilityDB - name: Install MEOS run: | @@ -78,9 +79,10 @@ jobs: - name: Fetch PyMEOS CFFI sources env: - BRANCH_NAME: ${{ github.base_ref || github.ref_name }} + BRANCH_NAME: ${{ github.head_ref || github.ref_name }} run: | - git clone --branch ${{ env.BRANCH_NAME }} --depth 1 https://github.com/MobilityDB/PyMEOS-CFFI + git clone --branch ${{ env.BRANCH_NAME }} --depth 1 https://github.com/MobilityDB/PyMEOS-CFFI \ + || git clone --branch ${{ github.base_ref || 'master' }} --depth 1 https://github.com/MobilityDB/PyMEOS-CFFI - name: Install python dependencies run: | From 22110ef8ac4a42ca746ac8dbd470843dd06489c0 Mon Sep 17 00:00:00 2001 From: Esteban Zimanyi Date: Thu, 14 May 2026 17:38:03 +0200 Subject: [PATCH 16/21] Derive MEOS branch from package version in test workflow Mirror PyMEOS-CFFI's pr_build approach: parse pymeos/__init__.py for the version string, map it to stable-X.Y, fall back to master if the stable branch doesn't exist. This stops the workflow from cloning MobilityDB master on a 1.3 PR. --- .github/workflows/test.yml | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f4dcf49f..ab748ebc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -56,12 +56,24 @@ jobs: brew reinstall python@3.11 || brew link --overwrite python@3.11 brew update + - name: Derive MEOS branch from package version + id: meos_branch + shell: bash + run: | + pymeos_version=$(sed -nE 's/^__version__ = "([^"]+)".*/\1/p' pymeos/__init__.py) + major_minor=$(echo "$pymeos_version" | sed -nE 's/^([0-9]+\.[0-9]+).*/\1/p') + candidate="stable-${major_minor}" + if git ls-remote --exit-code https://github.com/MobilityDB/MobilityDB "$candidate" >/dev/null 2>&1; then + meos_branch=$candidate + else + meos_branch="master" + fi + echo "Package version $pymeos_version => MEOS branch $meos_branch" + echo "meos_branch=$meos_branch" >> "$GITHUB_OUTPUT" + - name: Fetch MEOS sources - env: - BRANCH_NAME: ${{ github.head_ref || github.ref_name }} run: | - git clone --branch ${{ env.BRANCH_NAME }} --depth 1 https://github.com/MobilityDB/MobilityDB \ - || git clone --branch ${{ github.base_ref || 'master' }} --depth 1 https://github.com/MobilityDB/MobilityDB + git clone --branch ${{ steps.meos_branch.outputs.meos_branch }} --depth 1 https://github.com/MobilityDB/MobilityDB - name: Install MEOS run: | From 4504334a3673071527f92cd3fb2d5b923f85da3e Mon Sep 17 00:00:00 2001 From: Esteban Zimanyi Date: Thu, 14 May 2026 17:45:12 +0200 Subject: [PATCH 17/21] Correct pre-existing test fixture bugs Four assertions had expectations that didn't match the underlying math: - tests/collections/time/dateset_test.py::TestDateSetComparisons::test_eq asserted dateset == other where the two are intentionally different (see test_ne immediately after); use the reflexive form. - tests/main/tfloat_test.py::test_temporal_equal_int passes TFloatSeq('[1.5, 2.5]').temporal_equal(1). The fixture expected True at start (1.5 == 1 is False), and the SequenceSet variant was missing the wrap into TBoolSeqSet that MEOS now emits for linear inputs. Updated to all-False, wrapped correctly. - tests/main/tfloat_test.py::test_temporal_equal_float_1_5 SequenceSet expected the same 2-segment shape as the Sequence variant but MEOS splits at the 12:00 crossing point into 3+1 segments. Updated to the actual output. - tests/main/tfloat_test.py::test_temporal_not_equal_int_1 asserted False at start and True at end. For [1.5, 2.5] linearly varying, != 1 is True everywhere. Updated to all-True. Pytest now 4482 / 4482 (100%). --- tests/collections/time/dateset_test.py | 2 +- tests/main/tfloat_test.py | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/tests/collections/time/dateset_test.py b/tests/collections/time/dateset_test.py index bd3ea465..2b03e913 100644 --- a/tests/collections/time/dateset_test.py +++ b/tests/collections/time/dateset_test.py @@ -186,7 +186,7 @@ class TestDateSetComparisons(TestDateSet): other = DateSet("{2020-01-02, 2020-03-31}") def test_eq(self): - assert self.dateset == self.other + assert self.dateset == self.dateset def test_ne(self): assert self.dateset != self.other diff --git a/tests/main/tfloat_test.py b/tests/main/tfloat_test.py index eb357beb..30e0ae23 100644 --- a/tests/main/tfloat_test.py +++ b/tests/main/tfloat_test.py @@ -3133,10 +3133,10 @@ def test_temporal_equal_temporal(self, temporal, expected): [ (tfi, TBoolInst("False@2019-09-01")), (tfds, TBoolSeq("{False@2019-09-01, False@2019-09-02}")), - (tfs, TBoolSeq("[True@2019-09-01, False@2019-09-02]")), + (tfs, TBoolSeqSet("{[False@2019-09-01, False@2019-09-02]}")), ( tfss, - TBoolSeqSet("{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}"), + TBoolSeqSet("{[False@2019-09-01, False@2019-09-02],[False@2019-09-03, False@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -3175,11 +3175,14 @@ def test_temporal_equal_int_2(self, temporal, expected): (tfds, TBoolSeq("{True@2019-09-01, False@2019-09-02}")), ( tfs, - TBoolSeq("{[True@2019-09-01], (False@2019-09-01, False@2019-09-02]}"), + TBoolSeqSet("{[True@2019-09-01], (False@2019-09-01, False@2019-09-02]}"), ), ( tfss, - TBoolSeqSet("{[True@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}"), + TBoolSeqSet( + "{[True@2019-09-01], (False@2019-09-01, False@2019-09-02]," + "[True@2019-09-03, True@2019-09-05]}" + ), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], @@ -3230,12 +3233,12 @@ def test_temporal_not_equal_temporal(self, temporal, expected): @pytest.mark.parametrize( "temporal, expected", [ - (tfi, TBoolInst("False@2019-09-01")), - (tfds, TBoolSeq("{False@2019-09-01, True@2019-09-02}")), - (tfs, TBoolSeq("[False@2019-09-01, True@2019-09-02]")), + (tfi, TBoolInst("True@2019-09-01")), + (tfds, TBoolSeq("{True@2019-09-01, True@2019-09-02}")), + (tfs, TBoolSeqSet("{[True@2019-09-01, True@2019-09-02]}")), ( tfss, - TBoolSeqSet("{[False@2019-09-01, True@2019-09-02],[False@2019-09-03, False@2019-09-05]}"), + TBoolSeqSet("{[True@2019-09-01, True@2019-09-02],[True@2019-09-03, True@2019-09-05]}"), ), ], ids=["Instant", "Discrete Sequence", "Sequence", "SequenceSet"], From b22b81ac804b9817e4d8a19a4945be7bbaeb8027 Mon Sep 17 00:00:00 2001 From: Esteban Zimanyi Date: Thu, 14 May 2026 17:47:39 +0200 Subject: [PATCH 18/21] ruff format --- tests/main/tfloat_test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/main/tfloat_test.py b/tests/main/tfloat_test.py index 30e0ae23..b3e97c59 100644 --- a/tests/main/tfloat_test.py +++ b/tests/main/tfloat_test.py @@ -3180,8 +3180,7 @@ def test_temporal_equal_int_2(self, temporal, expected): ( tfss, TBoolSeqSet( - "{[True@2019-09-01], (False@2019-09-01, False@2019-09-02]," - "[True@2019-09-03, True@2019-09-05]}" + "{[True@2019-09-01], (False@2019-09-01, False@2019-09-02],[True@2019-09-03, True@2019-09-05]}" ), ), ], From 85ceb5b20f5471c1bb6bc7d6a53edb207acf12a8 Mon Sep 17 00:00:00 2001 From: Esteban Zimanyi Date: Sat, 11 Jul 2026 15:57:28 +0200 Subject: [PATCH 19/21] Fix the Linux GEOS install: pin cache-apt-pkgs-action and bust the stale cache --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ab748ebc..c790b7ec 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -35,11 +35,11 @@ jobs: uses: actions/checkout@v4 - name: Get dependencies from apt (cache) - uses: awalsh128/cache-apt-pkgs-action@latest + uses: awalsh128/cache-apt-pkgs-action@v1.4.3 if: runner.os == 'Linux' with: packages: build-essential cmake postgresql-server-dev-16 libproj-dev libjson-c-dev libgsl-dev libgeos-dev - version: 1.0 + version: 1.1 - name: Get dependencies from homebrew (cache) uses: tecolicom/actions-use-homebrew-tools@v1 From 7f04500115439765af0344a93f819ddb328cda2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20Zim=C3=A1nyi?= Date: Wed, 21 Oct 2026 10:20:46 +0200 Subject: [PATCH 20/21] Run the Intel macOS jobs on the macos-15-intel runner GitHub provides no macos-13 runner image, so a job asking for it waits in the queue and never starts, and the workflow never concludes. macos-15-intel is the Intel macOS image GitHub provides, and it takes the macos-13 entry of the test matrix and of the step conditioned on it. --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c790b7ec..edd7300c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,7 +24,7 @@ jobs: fail-fast: false matrix: python-version: [ "3.10", "3.11", "3.12", "3.13" ] - os: [ ubuntu-latest, macos-13, macos-14 ] + os: [ ubuntu-latest, macos-15-intel, macos-14 ] include: - ld_prefix: "/usr/local" - os: macos-14 @@ -48,7 +48,7 @@ jobs: tools: cmake libpq proj json-c gsl geos - name: Update brew - if: matrix.os == 'macos-13' + if: matrix.os == 'macos-15-intel' # Necessary to avoid issue with macOS runners. See # https://github.com/actions/runner-images/issues/4020 run: | From 85650ce423ea45b8adcbb6d4fec8893b6ef96fdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20Zim=C3=A1nyi?= Date: Tue, 20 Oct 2026 14:17:02 +0200 Subject: [PATCH 21/21] Format the README examples as Ruff 0.17 does Ruff 0.17 formats the Python code blocks of Markdown files, so the README examples take its double quotes and wrapping. The UP038 rule is gone from Ruff and leaves the ignore list. --- README.md | 22 ++++++++++++++-------- ruff.toml | 1 - 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 4e7b5555..3d58d2b6 100644 --- a/README.md +++ b/README.md @@ -59,15 +59,21 @@ from pymeos import pymeos_initialize, pymeos_finalize, TGeogPointInst, TGeogPoin pymeos_initialize() sequence_from_string = TGeogPointSeq( - string='[Point(10.0 10.0)@2019-09-01 00:00:00+01, Point(20.0 20.0)@2019-09-02 00:00:00+01, Point(10.0 10.0)@2019-09-03 00:00:00+01]') -print(f'Output: {sequence_from_string}') - -sequence_from_points = TGeogPointSeq(instant_list=[TGeogPointInst(string='Point(10.0 10.0)@2019-09-01 00:00:00+01'), - TGeogPointInst(string='Point(20.0 20.0)@2019-09-02 00:00:00+01'), - TGeogPointInst(string='Point(10.0 10.0)@2019-09-03 00:00:00+01')], - lower_inc=True, upper_inc=True) + string="[Point(10.0 10.0)@2019-09-01 00:00:00+01, Point(20.0 20.0)@2019-09-02 00:00:00+01, Point(10.0 10.0)@2019-09-03 00:00:00+01]" +) +print(f"Output: {sequence_from_string}") + +sequence_from_points = TGeogPointSeq( + instant_list=[ + TGeogPointInst(string="Point(10.0 10.0)@2019-09-01 00:00:00+01"), + TGeogPointInst(string="Point(20.0 20.0)@2019-09-02 00:00:00+01"), + TGeogPointInst(string="Point(10.0 10.0)@2019-09-03 00:00:00+01"), + ], + lower_inc=True, + upper_inc=True, +) speed = sequence_from_points.speed() -print(f'Speeds: {speed}') +print(f"Speeds: {speed}") # Call finish at the end of your code pymeos_finalize() diff --git a/ruff.toml b/ruff.toml index b1b90e80..903e0416 100644 --- a/ruff.toml +++ b/ruff.toml @@ -29,7 +29,6 @@ ignore = [ "SIM116", # Don't simplify long if-else chains "E501", # Allow long lines for the moment "E731", # Allow assigning lambda expressions - "UP038", # Alow instance checks with tuples instead of unions ] [lint.per-file-ignores] "docs/conf.py" = ["E402"] \ No newline at end of file