libres 0.8.0__py3-none-any.whl → 0.9.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- libres/__init__.py +1 -1
- libres/context/core.py +5 -5
- libres/context/registry.py +3 -1
- libres/db/models/allocation.py +14 -5
- libres/db/models/reservation.py +3 -3
- libres/db/models/types/json_type.py +19 -24
- libres/db/scheduler.py +23 -15
- {libres-0.8.0.dist-info → libres-0.9.1.dist-info}/METADATA +27 -4
- {libres-0.8.0.dist-info → libres-0.9.1.dist-info}/RECORD +12 -12
- {libres-0.8.0.dist-info → libres-0.9.1.dist-info}/WHEEL +1 -1
- {libres-0.8.0.dist-info → libres-0.9.1.dist-info/licenses}/LICENSE +0 -0
- {libres-0.8.0.dist-info → libres-0.9.1.dist-info}/top_level.txt +0 -0
libres/__init__.py
CHANGED
libres/context/core.py
CHANGED
|
@@ -61,15 +61,15 @@ class ContextServicesMixin:
|
|
|
61
61
|
|
|
62
62
|
@cached_property
|
|
63
63
|
def is_allocation_exposed(self) -> Callable[[Allocation], bool]:
|
|
64
|
-
return self.context.get_service('exposure').is_allocation_exposed
|
|
64
|
+
return self.context.get_service('exposure').is_allocation_exposed # type: ignore[no-any-return]
|
|
65
65
|
|
|
66
66
|
@cached_property
|
|
67
67
|
def generate_uuid(self) -> Callable[[str], UUID]:
|
|
68
|
-
return self.context.get_service('uuid_generator')
|
|
68
|
+
return self.context.get_service('uuid_generator') # type: ignore[no-any-return]
|
|
69
69
|
|
|
70
70
|
@cached_property
|
|
71
71
|
def validate_email(self) -> Callable[[str], bool]:
|
|
72
|
-
return self.context.get_service('email_validator')
|
|
72
|
+
return self.context.get_service('email_validator') # type: ignore[no-any-return]
|
|
73
73
|
|
|
74
74
|
def clear_cache(self) -> None:
|
|
75
75
|
""" Clears the cache of the mixin. """
|
|
@@ -91,12 +91,12 @@ class ContextServicesMixin:
|
|
|
91
91
|
|
|
92
92
|
@property
|
|
93
93
|
def session_provider(self) -> SessionProvider:
|
|
94
|
-
return self.context.get_service('session_provider')
|
|
94
|
+
return self.context.get_service('session_provider') # type: ignore[no-any-return]
|
|
95
95
|
|
|
96
96
|
@property
|
|
97
97
|
def session(self) -> Session:
|
|
98
98
|
""" Returns the current session. """
|
|
99
|
-
return self.session_provider.session()
|
|
99
|
+
return self.session_provider.session() # type: ignore[no-any-return]
|
|
100
100
|
|
|
101
101
|
def close(self) -> None:
|
|
102
102
|
""" Closes the current session. """
|
libres/context/registry.py
CHANGED
|
@@ -82,6 +82,8 @@ class Registry:
|
|
|
82
82
|
"""
|
|
83
83
|
|
|
84
84
|
contexts: dict[str, Context]
|
|
85
|
+
# FIXME: Why do we allow this to be None? Do we make use
|
|
86
|
+
# of this anywhere?
|
|
85
87
|
master_context: Context | None = None
|
|
86
88
|
|
|
87
89
|
def __init__(self) -> None:
|
|
@@ -98,7 +100,7 @@ class Registry:
|
|
|
98
100
|
if not hasattr(self.local, 'current_context'):
|
|
99
101
|
self.local.current_context = self.master_context
|
|
100
102
|
|
|
101
|
-
return self.local.current_context
|
|
103
|
+
return self.local.current_context # type: ignore[no-any-return]
|
|
102
104
|
|
|
103
105
|
def is_existing_context(self, name: str) -> bool:
|
|
104
106
|
return name in self.contexts
|
libres/db/models/allocation.py
CHANGED
|
@@ -34,14 +34,18 @@ if TYPE_CHECKING:
|
|
|
34
34
|
from collections.abc import Iterator
|
|
35
35
|
from sedate.types import TzInfoOrName
|
|
36
36
|
from sqlalchemy.orm import Query
|
|
37
|
+
from typing import NamedTuple
|
|
37
38
|
from typing_extensions import Self
|
|
38
39
|
|
|
39
|
-
from libres.db.models import
|
|
40
|
+
from libres.db.models import ReservedSlot
|
|
40
41
|
from libres.modules.rasterizer import Raster
|
|
41
42
|
|
|
42
43
|
_OptDT1 = TypeVar('_OptDT1', 'datetime | None', datetime, None)
|
|
43
44
|
_OptDT2 = TypeVar('_OptDT2', 'datetime | None', datetime, None)
|
|
44
45
|
|
|
46
|
+
class _ReservationIdRow(NamedTuple):
|
|
47
|
+
id: int
|
|
48
|
+
|
|
45
49
|
|
|
46
50
|
class Allocation(TimestampMixin, ORMBase, OtherModels):
|
|
47
51
|
"""Describes a timespan within which one or many timeslots can be
|
|
@@ -114,7 +118,7 @@ class Allocation(TimestampMixin, ORMBase, OtherModels):
|
|
|
114
118
|
timezone: Column[str | None] = Column(types.String())
|
|
115
119
|
|
|
116
120
|
#: Custom data reserved for the user
|
|
117
|
-
data: Column[Any | None] = Column(
|
|
121
|
+
data: Column[dict[str, Any] | None] = Column(
|
|
118
122
|
JSON(),
|
|
119
123
|
nullable=True
|
|
120
124
|
)
|
|
@@ -470,7 +474,7 @@ class Allocation(TimestampMixin, ORMBase, OtherModels):
|
|
|
470
474
|
return self.display_start(timezone), self.display_end(timezone)
|
|
471
475
|
|
|
472
476
|
@property
|
|
473
|
-
def pending_reservations(self) -> Query[
|
|
477
|
+
def pending_reservations(self) -> Query[_ReservationIdRow]:
|
|
474
478
|
""" Returns the pending reservations query for this allocation.
|
|
475
479
|
As the pending reservations target the group and not a specific
|
|
476
480
|
allocation this function returns the same value for masters and
|
|
@@ -482,6 +486,7 @@ class Allocation(TimestampMixin, ORMBase, OtherModels):
|
|
|
482
486
|
)
|
|
483
487
|
|
|
484
488
|
Reservation = self.models.Reservation # noqa: N806
|
|
489
|
+
query: Query[_ReservationIdRow]
|
|
485
490
|
query = object_session(self).query(Reservation.id)
|
|
486
491
|
query = query.filter(Reservation.target == self.group)
|
|
487
492
|
query = query.filter(Reservation.status == 'pending')
|
|
@@ -794,7 +799,9 @@ class Allocation(TimestampMixin, ORMBase, OtherModels):
|
|
|
794
799
|
if self.is_master:
|
|
795
800
|
return self
|
|
796
801
|
else:
|
|
797
|
-
query
|
|
802
|
+
# FIXME: This should either query `self.__class__` or
|
|
803
|
+
# we need to return `Allocation` rather than `Self`
|
|
804
|
+
query: Query[Self] = object_session(self).query(Allocation)
|
|
798
805
|
query = query.filter(Allocation._start == self._start)
|
|
799
806
|
query = query.filter(Allocation.resource == self.mirror_of)
|
|
800
807
|
|
|
@@ -818,7 +825,9 @@ class Allocation(TimestampMixin, ORMBase, OtherModels):
|
|
|
818
825
|
assert self.is_master
|
|
819
826
|
return [self]
|
|
820
827
|
|
|
821
|
-
query
|
|
828
|
+
# FIXME: This should either query `self.__class__` or
|
|
829
|
+
# we need to return `Allocation` rather than `Self`
|
|
830
|
+
query: Query[Self] = object_session(self).query(Allocation)
|
|
822
831
|
query = query.filter(Allocation.mirror_of == self.mirror_of)
|
|
823
832
|
query = query.filter(Allocation._start == self._start)
|
|
824
833
|
|
libres/db/models/reservation.py
CHANGED
|
@@ -96,7 +96,7 @@ class Reservation(TimestampMixin, ORMBase, OtherModels):
|
|
|
96
96
|
nullable=False
|
|
97
97
|
)
|
|
98
98
|
|
|
99
|
-
data: Column[Any | None] = deferred(
|
|
99
|
+
data: Column[dict[str, Any] | None] = deferred(
|
|
100
100
|
Column(
|
|
101
101
|
JSON(),
|
|
102
102
|
nullable=True
|
|
@@ -148,7 +148,7 @@ class Reservation(TimestampMixin, ORMBase, OtherModels):
|
|
|
148
148
|
# order by date
|
|
149
149
|
query = query.order_by(Allocation._start)
|
|
150
150
|
|
|
151
|
-
return query
|
|
151
|
+
return query # type: ignore[no-any-return]
|
|
152
152
|
|
|
153
153
|
def display_start(
|
|
154
154
|
self,
|
|
@@ -212,4 +212,4 @@ class Reservation(TimestampMixin, ORMBase, OtherModels):
|
|
|
212
212
|
# A reservation is deemed autoapprovable if no allocation
|
|
213
213
|
# requires explicit approval
|
|
214
214
|
|
|
215
|
-
return object_session(self).query(~query.exists()).scalar()
|
|
215
|
+
return object_session(self).query(~query.exists()).scalar() # type: ignore[no-any-return]
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
from sqlalchemy.types import TypeDecorator
|
|
3
|
+
from sqlalchemy.ext.mutable import MutableDict
|
|
4
|
+
from sqlalchemy.types import TypeDecorator
|
|
5
|
+
from sqlalchemy.dialects.postgresql import JSONB
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
from typing import Any
|
|
@@ -9,43 +10,37 @@ from typing import TYPE_CHECKING
|
|
|
9
10
|
if TYPE_CHECKING:
|
|
10
11
|
from sqlalchemy.engine import Dialect
|
|
11
12
|
|
|
12
|
-
_Base = TypeDecorator[Any]
|
|
13
|
+
_Base = TypeDecorator[dict[str, Any]]
|
|
13
14
|
else:
|
|
14
15
|
_Base = TypeDecorator
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
class JSON(_Base):
|
|
18
|
-
"""
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
""" A JSONB based type that coerces None's to empty dictionaries.
|
|
20
|
+
|
|
21
|
+
That is, this JSONB column cannot be `'null'::jsonb`. It could
|
|
22
|
+
still be `NULL` though, if it's nullable and never explicitly
|
|
23
|
+
set. But on the Python end you should always see a dictionary.
|
|
22
24
|
|
|
23
25
|
"""
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
# this will be replaced by JSON (or JSONB) though that requires that we
|
|
27
|
-
# require a later Postgres release. For now we stay backwards compatible
|
|
28
|
-
# with a version that's still widely used (9.1).
|
|
29
|
-
impl = TEXT
|
|
27
|
+
impl = JSONB
|
|
30
28
|
|
|
31
|
-
def process_bind_param(
|
|
29
|
+
def process_bind_param( # type:ignore[override]
|
|
32
30
|
self,
|
|
33
|
-
value: Any,
|
|
31
|
+
value: dict[str, Any] | None,
|
|
34
32
|
dialect: Dialect
|
|
35
|
-
) -> str
|
|
36
|
-
|
|
37
|
-
if value is not None:
|
|
38
|
-
value = (dialect._json_serializer or dumps)(value) # type:ignore
|
|
33
|
+
) -> dict[str, Any]:
|
|
39
34
|
|
|
40
|
-
return value
|
|
35
|
+
return {} if value is None else value
|
|
41
36
|
|
|
42
37
|
def process_result_value(
|
|
43
38
|
self,
|
|
44
|
-
value: str | None,
|
|
39
|
+
value: dict[str, Any] | None,
|
|
45
40
|
dialect: Dialect
|
|
46
|
-
) -> Any
|
|
41
|
+
) -> dict[str, Any]:
|
|
42
|
+
|
|
43
|
+
return {} if value is None else value
|
|
47
44
|
|
|
48
|
-
if value is not None:
|
|
49
|
-
value = (dialect._json_deserializer or loads)(value) # type:ignore
|
|
50
45
|
|
|
51
|
-
|
|
46
|
+
MutableDict.associate_with(JSON) # type:ignore[no-untyped-call]
|
libres/db/scheduler.py
CHANGED
|
@@ -269,7 +269,7 @@ class Scheduler(ContextServicesMixin):
|
|
|
269
269
|
allocations = allocations.with_entities(Allocation.id)
|
|
270
270
|
allocations = allocations.filter(Allocation.group.in_(groups))
|
|
271
271
|
|
|
272
|
-
query = self.managed_allocations()
|
|
272
|
+
query: Query[Allocation] = self.managed_allocations()
|
|
273
273
|
query = query.join(ReservedSlot)
|
|
274
274
|
query = query.filter(
|
|
275
275
|
ReservedSlot.reservation_token == token
|
|
@@ -306,7 +306,10 @@ class Scheduler(ContextServicesMixin):
|
|
|
306
306
|
) -> list[tuple[datetime, datetime]]:
|
|
307
307
|
|
|
308
308
|
query = self.allocations_by_group(group)
|
|
309
|
-
dates_query = query.with_entities(
|
|
309
|
+
dates_query: Query[tuple[datetime, datetime]] = query.with_entities(
|
|
310
|
+
Allocation._start,
|
|
311
|
+
Allocation._end
|
|
312
|
+
)
|
|
310
313
|
return dates_query.all()
|
|
311
314
|
|
|
312
315
|
def allocation_mirrors_by_master(
|
|
@@ -336,7 +339,7 @@ class Scheduler(ContextServicesMixin):
|
|
|
336
339
|
query = self.allocations_by_ids(ids)
|
|
337
340
|
query = query.filter(Allocation.approve_manually == True)
|
|
338
341
|
|
|
339
|
-
return self.session.query(query.exists()).scalar()
|
|
342
|
+
return self.session.query(query.exists()).scalar() # type: ignore[no-any-return]
|
|
340
343
|
|
|
341
344
|
def allocate(
|
|
342
345
|
self,
|
|
@@ -1273,8 +1276,9 @@ class Scheduler(ContextServicesMixin):
|
|
|
1273
1276
|
# reservation twice on a single session
|
|
1274
1277
|
if session_id:
|
|
1275
1278
|
found = self.queries.reservations_by_session(session_id)
|
|
1276
|
-
|
|
1277
|
-
|
|
1279
|
+
found_set: set[tuple[UUID, datetime | None]] = set(
|
|
1280
|
+
found.with_entities(Reservation.target, Reservation.start)
|
|
1281
|
+
)
|
|
1278
1282
|
|
|
1279
1283
|
for reservation in reservations:
|
|
1280
1284
|
if (reservation.target, reservation.start) in found_set:
|
|
@@ -1625,8 +1629,6 @@ class Scheduler(ContextServicesMixin):
|
|
|
1625
1629
|
assert start
|
|
1626
1630
|
assert end
|
|
1627
1631
|
|
|
1628
|
-
start, end = self._prepare_range(start, end)
|
|
1629
|
-
|
|
1630
1632
|
assert whole_day in ('yes', 'no', 'any')
|
|
1631
1633
|
assert groups in ('yes', 'no', 'any')
|
|
1632
1634
|
|
|
@@ -1641,7 +1643,7 @@ class Scheduler(ContextServicesMixin):
|
|
|
1641
1643
|
else:
|
|
1642
1644
|
day_numbers = None
|
|
1643
1645
|
|
|
1644
|
-
query = self.allocations_in_range(start, end)
|
|
1646
|
+
query = self.allocations_in_range(*self._prepare_range(start, end))
|
|
1645
1647
|
query = query.order_by(Allocation._start)
|
|
1646
1648
|
|
|
1647
1649
|
allocations = []
|
|
@@ -1653,13 +1655,19 @@ class Scheduler(ContextServicesMixin):
|
|
|
1653
1655
|
|
|
1654
1656
|
if not self.is_allocation_exposed(allocation):
|
|
1655
1657
|
continue
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
s = sedate.
|
|
1662
|
-
|
|
1658
|
+
allocation_start = allocation.display_start()
|
|
1659
|
+
# NOTE: We want the correct timezone, but we don't want the
|
|
1660
|
+
# date to be on the next day for a full-day reservation
|
|
1661
|
+
# so we skip the microsecond addition
|
|
1662
|
+
allocation_end = sedate.to_timezone(allocation.end, self.timezone)
|
|
1663
|
+
s = sedate.standardize_date(datetime.combine(
|
|
1664
|
+
allocation_start.date(),
|
|
1665
|
+
start.time()
|
|
1666
|
+
), self.timezone)
|
|
1667
|
+
e = sedate.standardize_date(datetime.combine(
|
|
1668
|
+
allocation_end.date(),
|
|
1669
|
+
end.time()
|
|
1670
|
+
), self.timezone)
|
|
1663
1671
|
|
|
1664
1672
|
if not allocation.overlaps(s, e):
|
|
1665
1673
|
continue
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: libres
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.1
|
|
4
4
|
Summary: A library to reserve things
|
|
5
5
|
Home-page: http://github.com/seantis/libres/
|
|
6
6
|
Author: Denis Krienbühl
|
|
@@ -51,13 +51,14 @@ Requires-Dist: types-psycopg2; extra == "mypy"
|
|
|
51
51
|
Requires-Dist: types-python-dateutil; extra == "mypy"
|
|
52
52
|
Requires-Dist: types-pytz; extra == "mypy"
|
|
53
53
|
Requires-Dist: typing-extensions; extra == "mypy"
|
|
54
|
+
Dynamic: license-file
|
|
54
55
|
|
|
55
56
|
Libres
|
|
56
57
|
======
|
|
57
58
|
|
|
58
59
|
Libres is a reservations management library to reserve things like tables at
|
|
59
|
-
a restaurant or tickets at an event. It works with Python 3.
|
|
60
|
-
and requires Postgresql 9.
|
|
60
|
+
a restaurant or tickets at an event. It works with Python 3.9+
|
|
61
|
+
and requires Postgresql 9.2+.
|
|
61
62
|
|
|
62
63
|
`Documentation <http://libres.readthedocs.org/en/latest/>`_ | `Source <http://github.com/seantis/libres/>`_ | `Bugs <http://github.com/seantis/libres/issues>`_
|
|
63
64
|
|
|
@@ -141,6 +142,28 @@ After this, create a new release on Github.
|
|
|
141
142
|
Changelog
|
|
142
143
|
---------
|
|
143
144
|
|
|
145
|
+
0.9.1 (05.08.2025)
|
|
146
|
+
~~~~~~~~~~~~~~~~~~~
|
|
147
|
+
|
|
148
|
+
- Fixes bug in `Scheduler.search_allocations` when the searched
|
|
149
|
+
time range contains multiple DST <-> ST transitions.
|
|
150
|
+
[Daverball]
|
|
151
|
+
|
|
152
|
+
0.9.0 (23.05.2025)
|
|
153
|
+
~~~~~~~~~~~~~~~~~~~
|
|
154
|
+
|
|
155
|
+
- Replaces `JSON` database type with `JSONB`, this means
|
|
156
|
+
Postgres as a backend is not required. You will also need
|
|
157
|
+
to write a migration for existing JSON columns. You may use
|
|
158
|
+
the following recipe using an alembic `Operations` object::
|
|
159
|
+
|
|
160
|
+
operations.alter_column(
|
|
161
|
+
'table_name',
|
|
162
|
+
'column_name',
|
|
163
|
+
type_=JSON,
|
|
164
|
+
postgresql_using='"column_name"::jsonb'
|
|
165
|
+
)
|
|
166
|
+
|
|
144
167
|
0.8.0 (15.01.2025)
|
|
145
168
|
~~~~~~~~~~~~~~~~~~~
|
|
146
169
|
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
libres/.gitignore,sha256=tyWYoDW7-zMdsfiJIVONRWJ5JmqJCTHzBOsi_rkIYZg,49
|
|
2
|
-
libres/__init__.py,sha256=
|
|
2
|
+
libres/__init__.py,sha256=d2iNp33yOxIx7AAvW064M_9oiCtEl9Zxr1WVwK8Vl1U,243
|
|
3
3
|
libres/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
libres/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
-
libres/context/core.py,sha256=
|
|
5
|
+
libres/context/core.py,sha256=AZMmFVqTVSkK3pomhoamLWOeqynY23g_uf32yjhgrRQ,7353
|
|
6
6
|
libres/context/exposure.py,sha256=0krsky3XYplG7Uf5oLlQgdXp6XuEDjN2JGe3ljgLM14,287
|
|
7
|
-
libres/context/registry.py,sha256=
|
|
7
|
+
libres/context/registry.py,sha256=JfV-QccpDbAEq154aHu7_-hznr5kXYY58czZ-0-m8vA,4986
|
|
8
8
|
libres/context/session.py,sha256=bVvZ7cvSKffGrzxpDM7vKrGgwAPWRoS4No6HK1--xlg,2488
|
|
9
9
|
libres/context/settings.py,sha256=IkdG67QUUuk_sQMXiwsJgelrsbx6M-7f72uJBA2JoJA,1374
|
|
10
10
|
libres/db/__init__.py,sha256=Fks6T8aEacYVvXB9U1v182zKX7SuEUAkC5hTK50AuQk,145
|
|
11
11
|
libres/db/queries.py,sha256=mVLMcFh7tbAOOp8fveB1T-ZBt0X3hQiaN5Krt5Mmhhs,10917
|
|
12
|
-
libres/db/scheduler.py,sha256=
|
|
12
|
+
libres/db/scheduler.py,sha256=Pg-bgyrMgCE54K7sXxChNw_NTIdviCZSO7_X0LG0o34,64711
|
|
13
13
|
libres/db/models/__init__.py,sha256=IL52K-0tg_v6zuiiE2k4UQNqneeb8CLUUVo_t_OBU-g,325
|
|
14
|
-
libres/db/models/allocation.py,sha256=
|
|
14
|
+
libres/db/models/allocation.py,sha256=Zi-H3HGz4Xt9VhwUZmoUMc8xGr8rPBNiHGumnYcjlwI,29005
|
|
15
15
|
libres/db/models/base.py,sha256=Y2Lc60vJ1Du73D0sLozVNi1TfhtrQ3i_64NV7hsnc4g,117
|
|
16
16
|
libres/db/models/other.py,sha256=REg6GlJo58eAubu4MzJqNtWqoEJrq_hTGeOs7XYU5BQ,791
|
|
17
|
-
libres/db/models/reservation.py,sha256=
|
|
17
|
+
libres/db/models/reservation.py,sha256=GmDf9r_Sr0ZOQG2q-GbOtDTeJkOa8FJSi2tpWYk_hEA,5865
|
|
18
18
|
libres/db/models/reserved_slot.py,sha256=_r8RUHlaQHDgo14oO5mPUyfS8pI4jmrP-_l5HzuCPwA,3090
|
|
19
19
|
libres/db/models/timestamp.py,sha256=EsuxdQSUsPCkHb1F7HdrDevWZ5wDWerDFRIhqfhefNw,1301
|
|
20
20
|
libres/db/models/types/__init__.py,sha256=8fx7ecDasCKsCJxGjt4qP5BbDJCG88dJRa0nzD6IetY,186
|
|
21
|
-
libres/db/models/types/json_type.py,sha256=
|
|
21
|
+
libres/db/models/types/json_type.py,sha256=ko6K4YRWERWCpg0wYzuwJ_u-VLJ4K3j3ksJ7cGyiMzw,1137
|
|
22
22
|
libres/db/models/types/utcdatetime.py,sha256=4Wlk0Yc6e3PljOjngUGuYvo8jps76RYVkCEwmPygzsY,1285
|
|
23
23
|
libres/db/models/types/uuid_type.py,sha256=sesgyF65JV0Zh2ty7rSeALpZxKjVg1Y68_Pv7gJAuAo,1675
|
|
24
24
|
libres/modules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -26,8 +26,8 @@ libres/modules/errors.py,sha256=afcvKDfu7XYnGt6CfTG1gpmCaoMTPgtxwmTe2Cyz9qc,2146
|
|
|
26
26
|
libres/modules/events.py,sha256=-YHwFJKory8RSIRTths5LBn92sodEPkhARH_a1Xml3c,5299
|
|
27
27
|
libres/modules/rasterizer.py,sha256=-KYG03YkaPNnyohl_HrEJZqdHrhmGesbLgxxPahNTCc,3155
|
|
28
28
|
libres/modules/utils.py,sha256=W5Kuu9LhhUWZMKLAhw7DmQEuNYb9aXWpW_HXCn62lhU,1871
|
|
29
|
-
libres-0.
|
|
30
|
-
libres-0.
|
|
31
|
-
libres-0.
|
|
32
|
-
libres-0.
|
|
33
|
-
libres-0.
|
|
29
|
+
libres-0.9.1.dist-info/licenses/LICENSE,sha256=w1rojULT3naueSnr4r62MSQipL4VPtsfEcTFmSKpVuI,1069
|
|
30
|
+
libres-0.9.1.dist-info/METADATA,sha256=e-7a5dHP6OCJ5ob5wsH1-Wk4pr0qVMMZDU3wtzd4Y98,10222
|
|
31
|
+
libres-0.9.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
32
|
+
libres-0.9.1.dist-info/top_level.txt,sha256=Exs6AnhZc0UTcsD5Ylyx1P89j19hJ4Dy13jxQyZwi3k,7
|
|
33
|
+
libres-0.9.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|