Skip to content

Commit

Permalink
Merge pull request #4 from MobilityDB/develop
Browse files Browse the repository at this point in the history
Version 1.1.2 and major changes
  • Loading branch information
estebanzimanyi committed Nov 20, 2022
2 parents d744845 + b05b718 commit 9d84632
Show file tree
Hide file tree
Showing 115 changed files with 168,572 additions and 8,678 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.idea
Pipfile.lock
Pipfile.lock
*-checkpoint.ipynb
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,22 @@ pip install pymeos
## Sample code

> **IMPORTANT** Before using any PyMEOS function, always call `meos_initialize`. Otherwise, the library will
> crash with a `Segmentation Fault` error. You should also always call `meos_finish` at the end of your code.
> **IMPORTANT** Before using any PyMEOS function, always call `pymeos_initialize`. Otherwise, the library will
> crash with a `Segmentation Fault` error. You should also always call `pymeos_finalize` at the end of your code.
````python
from pymeos import meos_initialize, meos_finish, TGeogPointInst, TGeogPointSeq
from pymeos import pymeos_initialize, pymeos_finalize, TGeogPointInst, TGeogPointSeq

# Important: Always initialize MEOS library
meos_initialize()
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)
speed = sequence_from_points.speed
speed = sequence_from_points.speed()
print(f'Speeds: {speed}')

# Call finish at the end of your code
meos_finish()
pymeos_finalize()
````
24 changes: 24 additions & 0 deletions pymeos/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
## 1.1.2

- Add support for `asyncpg`.

### Breaking changes

- `MobilityDB` using `psycopg2` has been moved from `pymeos.db` to `pymeos.db.psycopg` due to the addition of `asyncpg`
support.

## 1.1.1

- All MEOS functions added to PyMEOS.

## 1.1.0

### Breaking changes

- Function `meos_initialize` is now called `pymeos_initialize` and can receive a `str` parameter stating the desired
timezone (e.b. `pymeos_initialize('UTC')`)
- Function `meos_finish` is now called `pymeos_finalize`.

## 1.0.0

Use MEOS as backend.
12 changes: 6 additions & 6 deletions pymeos/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,22 @@ pip install pymeos
## Sample code

> **IMPORTANT** Before using any PyMEOS function, always call `meos_initialize`. Otherwise, the library will
> crash with a `Segmentation Fault` error. You should also always call `meos_finish` at the end of your code.
> **IMPORTANT** Before using any PyMEOS function, always call `pymeos_initialize`. Otherwise, the library will
> crash with a `Segmentation Fault` error. You should also always call `pymeos_finalize` at the end of your code.
````python
from pymeos import meos_initialize, meos_finish, TGeogPointInst, TGeogPointSeq
from pymeos import pymeos_initialize, pymeos_finalize, TGeogPointInst, TGeogPointSeq

# Important: Always initialize MEOS library
meos_initialize()
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)
speed = sequence_from_points.speed
speed = sequence_from_points.speed()
print(f'Speeds: {speed}')

# Call finish at the end of your code
meos_finish()
pymeos_finalize()
````
40 changes: 27 additions & 13 deletions pymeos/pymeos/__init__.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,38 @@
from .aggregators import *
from .boxes import *
from .main import *
from .meos_init import *
from .temporal import *
from .time import *
from pymeos_cffi.functions import meos_initialize, meos_finish

__version__ = '1.1.2'
__all__ = [
#initialization
'meos_initialize', 'meos_finish',
# initialization
'pymeos_initialize', 'pymeos_finalize',
# boxes
'TBox', 'STBox',
'Box', 'TBox', 'STBox',
# main
'TBool', 'TBoolInst', 'TBoolInstSet', 'TBoolSeq', 'TBoolSeqSet',
'TInt', 'TIntInst', 'TIntInstSet', 'TIntSeq', 'TIntSeqSet',
'TFloat', 'TFloatInst', 'TFloatInstSet', 'TFloatSeq', 'TFloatSeqSet',
'TText', 'TTextInst', 'TTextInstSet', 'TTextSeq', 'TTextSeqSet',
'TPointInst', 'TPointInstSet', 'TPointSeq', 'TPointSeqSet',
'TGeomPoint', 'TGeomPointInst', 'TGeomPointInstSet', 'TGeomPointSeq', 'TGeomPointSeqSet',
'TGeogPoint', 'TGeogPointInst', 'TGeogPointInstSet', 'TGeogPointSeq', 'TGeogPointSeqSet',
'TBool', 'TBoolInst', 'TBoolSeq', 'TBoolSeqSet',
'TInt', 'TIntInst', 'TIntSeq', 'TIntSeqSet',
'TFloat', 'TFloatInst', 'TFloatSeq', 'TFloatSeqSet',
'TText', 'TTextInst', 'TTextSeq', 'TTextSeqSet',
'TPointInst', 'TPointSeq', 'TPointSeqSet',
'TGeomPoint', 'TGeomPointInst', 'TGeomPointSeq', 'TGeomPointSeqSet',
'TGeogPoint', 'TGeogPointInst', 'TGeogPointSeq', 'TGeogPointSeqSet',
# temporal
'Temporal', 'TInstant', 'TSequence', 'TSequenceSet',
# time
'Period', 'TimestampSet', 'PeriodSet'
]
'Time', 'Period', 'TimestampSet', 'PeriodSet',
# extras
'TInterpolation',
# aggregators
'TemporalInstantCountAggregator', 'TemporalPeriodCountAggregator', 'TemporalExtentAggregator',
'TemporalAndAggregator', 'TemporalOrAggregator',
'TemporalAverageAggregator',
'TemporalNumberExtentAggregator',
'TemporalIntMaxAggregator', 'TemporalIntMinAggregator', 'TemporalIntSumAggregator',
'TemporalFloatMaxAggregator', 'TemporalFloatMinAggregator', 'TemporalFloatSumAggregator',
'TemporalTextMaxAggregator', 'TemporalTextMinAggregator',
'TemporalPointExtentAggregator',
'TemporalTimestampUnionAggregator', 'TemporalPeriodUnionAggregator',
]
24 changes: 24 additions & 0 deletions pymeos/pymeos/aggregators/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from .bool_aggregators import *
from .general_aggregators import *
from .number_aggregators import *
from .text_aggregators import *
from .point_aggregators import *
from .time_aggregators import *

__all__ = [
# General
'TemporalInstantCountAggregator', 'TemporalPeriodCountAggregator', 'TemporalExtentAggregator',
# Bool
'TemporalAndAggregator', 'TemporalOrAggregator',
# Number
'TemporalAverageAggregator',
'TemporalNumberExtentAggregator',
'TemporalIntMaxAggregator', 'TemporalIntMinAggregator', 'TemporalIntSumAggregator',
'TemporalFloatMaxAggregator', 'TemporalFloatMinAggregator', 'TemporalFloatSumAggregator',
# Text
'TemporalTextMaxAggregator', 'TemporalTextMinAggregator',
# Point
'TemporalPointExtentAggregator',
# Time
'TemporalTimestampUnionAggregator', 'TemporalPeriodUnionAggregator',
]
97 changes: 97 additions & 0 deletions pymeos/pymeos/aggregators/aggregator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
from __future__ import annotations

import abc
from datetime import datetime, timedelta
from typing import Optional, Union, List, Generic, TypeVar

from pymeos_cffi import *

from ..boxes import Box
from ..factory import _TemporalFactory
from ..temporal import Temporal
from ..time import Time

ResultType = TypeVar('ResultType', bound=Union[Temporal, Time, Box])
SourceType = TypeVar('SourceType', bound=Union[Temporal, Time, Box])
SelfAgg = TypeVar('SelfAgg', bound='Aggregation')


class BaseAggregator(Generic[SourceType, ResultType], abc.ABC):
_add_function = None
_final_function = temporal_tagg_finalfn

@classmethod
def aggregate(cls, temporals: List[SourceType]) -> ResultType:
state = None
for t in temporals:
state = cls._add(state, t)
return cls._finish(state)

@classmethod
def _add(cls, state, temporal: SourceType):
return cls._add_function(state, temporal._inner)

@classmethod
def _finish(cls, state) -> SourceType:
result = cls._final_function(state)
return _TemporalFactory.create_temporal(result)

@classmethod
def start_aggregation(cls) -> Aggregation:
return Aggregation(cls._add, cls._finish)

@classmethod
def _error(cls, element):
raise TypeError(f'Cannot perform aggregation ({cls.__name__}) with the following element: '
f'{element} (Class: {element.__class__})')


class Aggregation(Generic[SourceType, ResultType]):

def __init__(self, add_function, finish_function) -> None:
super().__init__()
self._add_function = add_function
self._finish_function = finish_function
self._state = None

def add(self: SelfAgg, new_temporal: SourceType) -> SelfAgg:
self._state = self._add_function(self._state, new_temporal)
return self

def aggregation(self) -> ResultType:
return self._finish_function(self._state)


class BaseGranularityAggregator(BaseAggregator[SourceType, ResultType]):

@classmethod
def aggregate(cls, temporals: List[SourceType], interval: Optional[Union[str, timedelta]] = None,
origin: Union['str', datetime] = '1970-01-01') -> ResultType:
state = None
for t in temporals:
state = cls._add(state, t, interval, origin)
return cls._finish(state)

@classmethod
def _add(cls, state, temporal: SourceType, interval=None, origin='1970-01-01'):
interval_converted = timedelta_to_interval(interval) if isinstance(interval, timedelta) 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)

@classmethod
def start_aggregation(cls, interval: Optional[Union[str, timedelta]] = None,
origin: Union['str', datetime] = '1970-01-01') -> GranularAggregation[SourceType, ResultType]:
return GranularAggregation(cls._add, cls._finish, interval, origin)


class GranularAggregation(Aggregation[SourceType, ResultType]):
def __init__(self, add_function, finish_function, interval, origin) -> None:
super().__init__(add_function, finish_function)
self._interval = interval
self._origin = origin

def add(self: SelfAgg, new_temporal: SourceType) -> SelfAgg:
self._state = self._add_function(self._state, new_temporal, self._interval, self._origin)
return self
12 changes: 12 additions & 0 deletions pymeos/pymeos/aggregators/bool_aggregators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from pymeos_cffi import *

from .aggregator import BaseAggregator
from ..main import TBool


class TemporalAndAggregator(BaseAggregator[TBool, TBool]):
_add_function = tbool_tand_transfn


class TemporalOrAggregator(BaseAggregator[TBool, TBool]):
_add_function = tbool_tor_transfn
71 changes: 71 additions & 0 deletions pymeos/pymeos/aggregators/general_aggregators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
from datetime import datetime, timedelta
from typing import Union

from pymeos_cffi import *

from .aggregator import BaseAggregator, BaseGranularityAggregator
from ..boxes import Box
from ..main import TIntSeq, TIntSeqSet
from ..temporal import Temporal, TInterpolation
from ..time import Time, TimestampSet, Period, PeriodSet


class TemporalInstantCountAggregator(BaseGranularityAggregator[Union[Time, Temporal], TIntSeq]):
@classmethod
def _add(cls, state, temporal, interval=None, origin='1970-01-01'):
interval_converted = timedelta_to_interval(interval) if isinstance(interval, timedelta) 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)
if isinstance(temporal, datetime):
state = timestamp_tcount_transfn(state, datetime_to_timestamptz(temporal), interval_converted,
origin_converted)
elif isinstance(temporal, TimestampSet):
state = timestampset_tcount_transfn(state, temporal._inner, interval_converted, origin_converted)
elif isinstance(temporal, Temporal) and temporal.interpolation == TInterpolation.DISCRETE:
state = temporal_tcount_transfn(state, temporal._inner, interval_converted, origin_converted)
else:
cls._error(temporal)
return state


class TemporalPeriodCountAggregator(BaseGranularityAggregator[Union[Time, Temporal], TIntSeqSet]):
@classmethod
def _add(cls, state, temporal, interval=None, origin='1970-01-01'):
interval_converted = timedelta_to_interval(interval) if isinstance(interval, timedelta) 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)
if isinstance(temporal, Period):
state = period_tcount_transfn(state, temporal._inner, interval_converted, origin_converted)
elif isinstance(temporal, PeriodSet):
state = periodset_tcount_transfn(state, temporal._inner, interval_converted, origin_converted)
elif isinstance(temporal, Temporal) and temporal.interpolation != TInterpolation.DISCRETE:
state = temporal_tcount_transfn(state, temporal._inner, interval_converted, origin_converted)
else:
cls._error(temporal)
return state


class TemporalExtentAggregator(BaseAggregator[Union[Time, Temporal], Period]):

@classmethod
def _add(cls, state, temporal):
if isinstance(temporal, Temporal):
state = temporal_extent_transfn(state, temporal._inner)
elif isinstance(temporal, datetime):
state = timestamp_extent_transfn(state, datetime_to_timestamptz(temporal))
elif isinstance(temporal, TimestampSet):
state = timestampset_extent_transfn(state, temporal._inner)
elif isinstance(temporal, Period):
state = span_extent_transfn(state, temporal._inner)
pass
elif isinstance(temporal, PeriodSet):
state = periodset_extent_transfn(state, temporal._inner)
else:
cls._error(temporal)
return state

@classmethod
def _finish(cls, state) -> Union[Temporal, Time, Box]:
return Period(_inner=state)
42 changes: 42 additions & 0 deletions pymeos/pymeos/aggregators/number_aggregators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from pymeos_cffi import *

from .aggregator import BaseAggregator
from ..boxes import TBox
from ..main import TInt, TFloat, TNumber


class TemporalAverageAggregator(BaseAggregator[TNumber, TNumber]):
_add_function = tnumber_tavg_transfn
_final_function = tnumber_tavg_finalfn


class TemporalNumberExtentAggregator(BaseAggregator[TNumber, TBox]):
_add_function = tnumber_extent_transfn

@classmethod
def _finish(cls, state) -> TBox:
return TBox(_inner=state)


class TemporalIntMaxAggregator(BaseAggregator[TNumber, TBox]):
_add_function = tint_tmax_transfn


class TemporalIntMinAggregator(BaseAggregator[TInt, TInt]):
_add_function = tint_tmin_transfn


class TemporalIntSumAggregator(BaseAggregator[TInt, TInt]):
_add_function = tint_tsum_transfn


class TemporalFloatMaxAggregator(BaseAggregator[TFloat, TFloat]):
_add_function = tfloat_tmax_transfn


class TemporalFloatMinAggregator(BaseAggregator[TFloat, TFloat]):
_add_function = tfloat_tmin_transfn


class TemporalFloatSumAggregator(BaseAggregator[TFloat, TFloat]):
_add_function = tfloat_tsum_transfn
Loading

0 comments on commit 9d84632

Please sign in to comment.