Commit 77ffd94d authored by Tanguy Le Carrour's avatar Tanguy Le Carrour
Browse files

First version of the library

parents
[flake8]
ignore = E203,E231,W503
max-line-length = 89
__pycache__/
.envrc
This diff is collapsed.
allen-s-interval-algebra --- Implementation of the Allen's interval algebra
Copyright © 2021 Tanguy Le Carrour <tanguy@bioneland.org>
This file is part of allen-s-interval-algebra.
allen-s-interval-algebra is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
allen-s-interval-algebra is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar. If not, see <https://www.gnu.org/licenses/>.
#
# allen-s-interval-algebra --- Implementation of the Allen's interval algebra
# Copyright © 2021 Tanguy Le Carrour <tanguy@bioneland.org>
#
# This file is part of allen-s-interval-algebra.
#
# allen-s-interval-algebra is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# allen-s-interval-algebra is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Foobar. If not, see <https://www.gnu.org/licenses/>.
#
from __future__ import annotations # allows `-> Interval`
from datetime import datetime as DateTime
from pytz import utc
class Interval:
"""Implements interval algebra as defined by Allen
@see https://en.wikipedia.org/wiki/Allen%27s_interval_algebra
"""
@classmethod
def from_datetimes(cls, start: DateTime, end: DateTime) -> Interval:
return cls(start.timestamp(), end.timestamp())
def __init__(self, start: float, end: float) -> None:
if start < end:
self.__start = start
self.__end = end
else:
self.__start = end
self.__end = start
def __str__(self) -> str:
return f"<Interval {self.__start} {self.__end}>"
@property
def start_as_datetime(self) -> DateTime:
return DateTime.fromtimestamp(self.__start, tz=utc)
@property
def end_as_datetime(self) -> DateTime:
return DateTime.fromtimestamp(self.__end, tz=utc)
def precedes(self, an_interval: "Interval") -> bool:
return self.__end < an_interval.__start
def preceded_by(self, an_interval: "Interval") -> bool:
return an_interval.precedes(self)
def meets(self, an_interval: "Interval") -> bool:
return self.__end == an_interval.__start
def met_by(self, an_interval: "Interval") -> bool:
return an_interval.meets(self)
def overlaps(self, an_interval: "Interval") -> bool:
return (
self.__start < an_interval.__start
and self.__end < an_interval.__end
and self.__end > an_interval.__start
)
def overlaped_by(self, an_interval: "Interval") -> bool:
return an_interval.overlaps(self)
def finishes(self, an_interval: "Interval") -> bool:
return self.__end == an_interval.__end and self.__start > an_interval.__start
def finished_by(self, an_interval: "Interval") -> bool:
return an_interval.finishes(self)
def during(self, an_interval: "Interval") -> bool:
return an_interval.__start < self.__start and self.__end < an_interval.__end
def contains(self, an_interval: "Interval") -> bool:
return an_interval.during(self)
def starts(self, an_interval: "Interval") -> bool:
return self.__start == an_interval.__start and self.__end < an_interval.__end
def started_by(self, an_interval: "Interval") -> bool:
return an_interval.starts(self)
def equals(self, an_interval: "Interval") -> bool:
return an_interval.__start == self.__start and an_interval.__end == self.__end
#
# allen-s-interval-algebra --- Implementation of the Allen's interval algebra
# Copyright © 2021 Tanguy Le Carrour <tanguy@bioneland.org>
#
# This file is part of allen-s-interval-algebra.
#
# allen-s-interval-algebra is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# allen-s-interval-algebra is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Foobar. If not, see <https://www.gnu.org/licenses/>.
#
from datetime import datetime as DateTime
from mamba import before, describe, it # type: ignore
from pytz import utc
from robber import expect # type: ignore
from allen_s_interval_algebra import Interval
def utc_datetime(*args: int) -> DateTime:
return DateTime(*args, tzinfo=utc) # type: ignore
with describe("Interval") as self:
with before.all:
a = utc_datetime(2000, 1, 1)
b = utc_datetime(2000, 1, 2)
c = utc_datetime(2000, 1, 3)
d = utc_datetime(2000, 1, 4)
e = utc_datetime(2000, 1, 5)
self.a = a
self.b = b
# ###################################### # | A B C D E |
self.ab = Interval.from_datetimes(a, b) # | *-* |
self.bc = Interval.from_datetimes(b, c) # | *-* |
self.cd = Interval.from_datetimes(c, d) # | *-* |
self.ad = Interval.from_datetimes(a, d) # | *-----* |
self.ce = Interval.from_datetimes(c, e) # | *---* |
# ###################################### # | A B C D E |
with it("builds from datetimes"):
start = utc_datetime(2019, 5, 20, 11, 16)
end = utc_datetime(2019, 5, 21, 11, 17)
expect(lambda: Interval.from_datetimes(start, end)).not_to.throw(Exception)
with it("returns its start as datetime"):
expect(self.ab.start_as_datetime).to.eq(self.a)
with it("returns its end as datetime"):
expect(self.ab.end_as_datetime).to.eq(self.b)
with it("handles equals"):
expect(self.ab.equals(self.ab)).to.be.true()
expect(self.ab.equals(self.bc)).to.be.false()
with it("handles precedes/preceded_by"):
expect(self.ab.precedes(self.cd)).to.be.true()
expect(self.cd.preceded_by(self.ab)).to.be.true()
expect(self.ab.preceded_by(self.cd)).to.be.false()
expect(self.cd.precedes(self.ab)).to.be.false()
with it("handles meets/met_by"):
expect(self.ab.meets(self.bc)).to.be.true()
expect(self.bc.met_by(self.ab)).to.be.true()
expect(self.ab.met_by(self.bc)).to.be.false()
expect(self.bc.meets(self.ab)).to.be.false()
with it("handles overlaps/overlaped_by"):
expect(self.ad.overlaps(self.ce)).to.be.true()
expect(self.ce.overlaped_by(self.ad)).to.be.true()
expect(self.ad.overlaped_by(self.ce)).to.be.false()
expect(self.ce.overlaps(self.ad)).to.be.false()
with it("handles finishes/finished_by"):
expect(self.cd.finishes(self.ad)).to.be.true()
expect(self.ad.finished_by(self.cd)).to.be.true()
expect(self.cd.finished_by(self.ad)).to.be.false()
expect(self.ad.finishes(self.cd)).to.be.false()
with it("handles contains/during"):
expect(self.ad.contains(self.bc)).to.be.true()
expect(self.bc.during(self.ad)).to.be.true()
expect(self.ad.during(self.bc)).to.be.false()
expect(self.bc.contains(self.ad)).to.be.false()
with it("handles starts/started_by"):
expect(self.ab.starts(self.ad)).to.be.true()
expect(self.ad.started_by(self.ab)).to.be.true()
expect(self.ab.started_by(self.ad)).to.be.false()
expect(self.ad.starts(self.ab)).to.be.false()
This diff is collapsed.
[tool.poetry]
name = "allen-s-interval-algebra"
version = "0.1.0"
description = "Implementation of the Allen's interval algebra"
authors = ["Tanguy Le Carrour <tanguy@bioneland.org>"]
license = "GPL-3.0+"
[tool.poetry.dependencies]
python = "^3.8"
pytz = "^2021.1"
[tool.poetry.dev-dependencies]
mamba = "^0.11.2"
robber = "^1.1.5"
mypy = "^0.800"
invoke = "^1.5.0"
flake8 = "^3.8.4"
black = "^20.8b1"
isort = "^5.7.0"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
#
# allen-s-interval-algebra --- Implementation of the Allen's interval algebra
# Copyright © 2021 Tanguy Le Carrour <tanguy@bioneland.org>
#
# This file is part of allen-s-interval-algebra.
#
# allen-s-interval-algebra is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# allen-s-interval-algebra is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Foobar. If not, see <https://www.gnu.org/licenses/>.
#
from invoke import Collection, task
import tasks.test
from tasks.helpers import title
@task()
def format(c):
"""Format code"""
title(format.__doc__)
c.run("isort allen_s_interval_algebra tasks")
c.run("black allen_s_interval_algebra tasks")
ns = Collection()
ns.add_task(format)
ns.add_collection(tasks.test)
#
# allen-s-interval-algebra --- Implementation of the Allen's interval algebra
# Copyright © 2021 Tanguy Le Carrour <tanguy@bioneland.org>
#
# This file is part of allen-s-interval-algebra.
#
# allen-s-interval-algebra is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# allen-s-interval-algebra is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Foobar. If not, see <https://www.gnu.org/licenses/>.
#
from termcolor import cprint
def title(message: str) -> None:
cprint("\n* {}".format(message), "blue")
#
# allen-s-interval-algebra --- Implementation of the Allen"s interval algebra
# Copyright © 2021 Tanguy Le Carrour <tanguy@bioneland.org>
#
# This file is part of allen-s-interval-algebra.
#
# allen-s-interval-algebra is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# allen-s-interval-algebra is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Foobar. If not, see <https://www.gnu.org/licenses/>.
#
from invoke import task
from tasks.helpers import title
@task
def syntax(c):
"""Run code syntax analyser."""
title(syntax.__doc__)
c.run("flake8 allen_s_interval_algebra tasks", pty=True)
@task
def types(c):
"""Run static type analyser."""
title(types.__doc__)
c.run("mypy --strict allen_s_interval_algebra", pty=True)
@task
def specs(c):
"""Run specifications."""
title(specs.__doc__)
c.run("mamba --format documentation allen_s_interval_algebra", pty=True)
@task(syntax, types, specs, default=True)
def all(c):
"""Run the test suite."""
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment