libres 0.7.3__py3-none-any.whl → 0.9.0__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 CHANGED
@@ -1,9 +1,11 @@
1
+ from __future__ import annotations
2
+
1
3
  from libres.context.registry import create_default_registry
2
4
  from libres.db import new_scheduler
3
5
 
4
6
  registry = create_default_registry()
5
7
 
6
- __version__ = '0.7.3'
8
+ __version__ = '0.9.0'
7
9
  __all__ = (
8
10
  'new_scheduler',
9
11
  'registry'
libres/context/core.py CHANGED
@@ -1,17 +1,23 @@
1
+ from __future__ import annotations
2
+
1
3
  import enum
2
4
  import libres
3
5
  import threading
4
-
5
6
  from contextlib import contextmanager
6
7
  from functools import cached_property
7
8
 
8
9
  from libres.modules import errors
9
10
 
10
11
 
11
- import typing as _t
12
- if _t.TYPE_CHECKING:
12
+ from typing import Any
13
+ from typing import Literal
14
+ from typing import TYPE_CHECKING
15
+ if TYPE_CHECKING:
16
+ from collections.abc import Callable
17
+ from collections.abc import Iterator
13
18
  from sqlalchemy.orm import Session
14
19
  from sqlalchemy.orm.session import SessionTransaction
20
+ from typing_extensions import TypeAlias
15
21
  from uuid import UUID
16
22
 
17
23
  from libres.context.registry import Registry
@@ -24,8 +30,8 @@ class _Marker(enum.Enum):
24
30
  required = enum.auto()
25
31
 
26
32
 
27
- missing_t = _t.Literal[_Marker.missing]
28
- required_t = _t.Literal[_Marker.required]
33
+ missing_t: TypeAlias = Literal[_Marker.missing] # noqa: PYI042
34
+ required_t: TypeAlias = Literal[_Marker.required] # noqa: PYI042
29
35
  missing: missing_t = _Marker.missing
30
36
  required: required_t = _Marker.required
31
37
 
@@ -51,19 +57,19 @@ class ContextServicesMixin:
51
57
 
52
58
  """
53
59
 
54
- context: 'Context'
60
+ context: Context
55
61
 
56
62
  @cached_property
57
- def is_allocation_exposed(self) -> _t.Callable[['Allocation'], bool]:
58
- return self.context.get_service('exposure').is_allocation_exposed
63
+ def is_allocation_exposed(self) -> Callable[[Allocation], bool]:
64
+ return self.context.get_service('exposure').is_allocation_exposed # type: ignore[no-any-return]
59
65
 
60
66
  @cached_property
61
- def generate_uuid(self) -> _t.Callable[[str], 'UUID']:
62
- return self.context.get_service('uuid_generator')
67
+ def generate_uuid(self) -> Callable[[str], UUID]:
68
+ return self.context.get_service('uuid_generator') # type: ignore[no-any-return]
63
69
 
64
70
  @cached_property
65
- def validate_email(self) -> _t.Callable[[str], bool]:
66
- return self.context.get_service('email_validator')
71
+ def validate_email(self) -> Callable[[str], bool]:
72
+ return self.context.get_service('email_validator') # type: ignore[no-any-return]
67
73
 
68
74
  def clear_cache(self) -> None:
69
75
  """ Clears the cache of the mixin. """
@@ -84,20 +90,20 @@ class ContextServicesMixin:
84
90
  pass
85
91
 
86
92
  @property
87
- def session_provider(self) -> 'SessionProvider':
88
- return self.context.get_service('session_provider')
93
+ def session_provider(self) -> SessionProvider:
94
+ return self.context.get_service('session_provider') # type: ignore[no-any-return]
89
95
 
90
96
  @property
91
- def session(self) -> 'Session':
97
+ def session(self) -> Session:
92
98
  """ Returns the current session. """
93
- return self.session_provider.session()
99
+ return self.session_provider.session() # type: ignore[no-any-return]
94
100
 
95
101
  def close(self) -> None:
96
102
  """ Closes the current session. """
97
103
  self.session.close()
98
104
 
99
105
  @property
100
- def begin_nested(self) -> _t.Callable[[], 'SessionTransaction']:
106
+ def begin_nested(self) -> Callable[[], SessionTransaction]:
101
107
  return self.session.begin_nested
102
108
 
103
109
  def commit(self) -> None:
@@ -143,13 +149,13 @@ class Context:
143
149
  def __init__(
144
150
  self,
145
151
  name: str,
146
- registry: _t.Optional['Registry'] = None,
147
- parent: _t.Optional['Context'] = None,
152
+ registry: Registry | None = None,
153
+ parent: Context | None = None,
148
154
  locked: bool = False
149
155
  ):
150
156
  self.name = name
151
157
  self.registry = registry or libres.registry
152
- self.values: _t.Dict[str, _t.Any] = {}
158
+ self.values: dict[str, Any] = {}
153
159
  self.parent = parent
154
160
  self.locked = False
155
161
  self.thread_lock = threading.RLock()
@@ -158,7 +164,7 @@ class Context:
158
164
  return f"<Libres Context(name='{self.name}')>"
159
165
 
160
166
  @contextmanager
161
- def as_current_context(self) -> _t.Iterator[None]:
167
+ def as_current_context(self) -> Iterator[None]:
162
168
  with self.registry.context(self.name):
163
169
  yield
164
170
 
@@ -173,7 +179,7 @@ class Context:
173
179
  with self.thread_lock:
174
180
  self.locked = False
175
181
 
176
- def get(self, key: str) -> _t.Union[_t.Any, missing_t]:
182
+ def get(self, key: str) -> Any | missing_t:
177
183
  if key in self.values:
178
184
  return self.values[key]
179
185
  elif self.parent:
@@ -181,7 +187,7 @@ class Context:
181
187
  else:
182
188
  return missing
183
189
 
184
- def set(self, key: str, value: _t.Any) -> None:
190
+ def set(self, key: str, value: Any) -> None:
185
191
  if self.locked:
186
192
  raise errors.ContextIsLocked
187
193
 
@@ -195,21 +201,21 @@ class Context:
195
201
 
196
202
  self.values[key] = value
197
203
 
198
- def get_setting(self, name: str) -> _t.Any:
204
+ def get_setting(self, name: str) -> Any:
199
205
  return self.get(f'settings.{name}')
200
206
 
201
- def set_setting(self, name: str, value: _t.Any) -> None:
207
+ def set_setting(self, name: str, value: Any) -> None:
202
208
  with self.thread_lock:
203
209
  self.set(f'settings.{name}', value)
204
210
 
205
- def get_service(self, name: str) -> _t.Any:
206
- service_id = '/'.join(('service', name))
211
+ def get_service(self, name: str) -> Any:
212
+ service_id = f'service/{name}'
207
213
  service = self.get(service_id)
208
214
 
209
215
  if service is missing:
210
216
  raise errors.UnknownService(service_id)
211
217
 
212
- cache_id = '/'.join(('service', name, 'cache'))
218
+ cache_id = f'service/{name}/cache'
213
219
  cache = self.get(cache_id)
214
220
 
215
221
  # no cache
@@ -226,13 +232,13 @@ class Context:
226
232
  def set_service(
227
233
  self,
228
234
  name: str,
229
- factory: _t.Callable[..., _t.Any],
235
+ factory: Callable[..., Any],
230
236
  cache: bool = False
231
237
  ) -> None:
232
238
  with self.thread_lock:
233
- service_id = '/'.join(('service', name))
239
+ service_id = f'service/{name}'
234
240
  self.set(service_id, factory)
235
241
 
236
242
  if cache:
237
- cache_id = '/'.join(('service', name, 'cache'))
243
+ cache_id = f'service/{name}/cache'
238
244
  self.set(cache_id, required)
@@ -1,9 +1,13 @@
1
- import typing as _t
2
- if _t.TYPE_CHECKING:
1
+ from __future__ import annotations
2
+
3
+
4
+ from typing import Literal
5
+ from typing import TYPE_CHECKING
6
+ if TYPE_CHECKING:
3
7
  from libres.db.models import Allocation
4
8
 
5
9
 
6
10
  class Exposure:
7
11
  @staticmethod
8
- def is_allocation_exposed(allocation: 'Allocation') -> _t.Literal[True]:
12
+ def is_allocation_exposed(allocation: Allocation) -> Literal[True]:
9
13
  return True
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import threading
2
4
 
3
5
  from contextlib import contextmanager
@@ -6,12 +8,14 @@ from libres.modules import errors
6
8
  from libres.context.core import Context
7
9
 
8
10
 
9
- import typing as _t
10
- if _t.TYPE_CHECKING:
11
+ from typing import TYPE_CHECKING
12
+ if TYPE_CHECKING:
13
+ from collections.abc import Callable
14
+ from collections.abc import Iterator
11
15
  from uuid import UUID
12
16
 
13
17
 
14
- def create_default_registry() -> 'Registry':
18
+ def create_default_registry() -> Registry:
15
19
  """ Creates the default registry for libres. """
16
20
 
17
21
  import re
@@ -28,7 +32,7 @@ def create_default_registry() -> 'Registry':
28
32
  def session_provider(context: Context) -> SessionProvider:
29
33
  return SessionProvider(context.get_setting('dsn'))
30
34
 
31
- def email_validator_factory(context: Context) -> _t.Callable[[str], bool]:
35
+ def email_validator_factory(context: Context) -> Callable[[str], bool]:
32
36
  # A very simple and stupid email validator. It's way too simple, but
33
37
  # it can be extended to do more powerful checks.
34
38
  def is_valid_email(email: str) -> bool:
@@ -39,11 +43,11 @@ def create_default_registry() -> 'Registry':
39
43
  def exposure_factory(context: Context) -> Exposure:
40
44
  return Exposure()
41
45
 
42
- def uuid_generator_factory(context: Context) -> _t.Callable[[str], 'UUID']:
43
- def uuid_generator(name: str) -> 'UUID':
46
+ def uuid_generator_factory(context: Context) -> Callable[[str], UUID]:
47
+ def uuid_generator(name: str) -> UUID:
44
48
  return new_namespace_uuid(
45
49
  context.get_setting('uuid_namespace'),
46
- '/'.join((context.name, name))
50
+ f'{context.name}/{name}'
47
51
  )
48
52
  return uuid_generator
49
53
 
@@ -77,8 +81,8 @@ class Registry:
77
81
 
78
82
  """
79
83
 
80
- contexts: _t.Dict[str, Context]
81
- master_context: _t.Optional[Context] = None
84
+ contexts: dict[str, Context]
85
+ master_context: Context | None = None
82
86
 
83
87
  def __init__(self) -> None:
84
88
  self.thread_lock = threading.RLock()
@@ -94,7 +98,7 @@ class Registry:
94
98
  if not hasattr(self.local, 'current_context'):
95
99
  self.local.current_context = self.master_context
96
100
 
97
- return self.local.current_context
101
+ return self.local.current_context # type: ignore[no-any-return]
98
102
 
99
103
  def is_existing_context(self, name: str) -> bool:
100
104
  return name in self.contexts
@@ -137,7 +141,7 @@ class Registry:
137
141
  self.local.current_context = self.get_context(name)
138
142
 
139
143
  @contextmanager
140
- def context(self, name: str) -> _t.Iterator[Context]:
144
+ def context(self, name: str) -> Iterator[Context]:
141
145
  previous = self.current_context.name
142
146
  self.switch_context(name)
143
147
  yield self.current_context
libres/context/session.py CHANGED
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from sqlalchemy import create_engine
2
4
  from sqlalchemy.pool import QueuePool
3
5
  from sqlalchemy.orm import scoped_session, sessionmaker
@@ -5,7 +7,7 @@ from sqlalchemy.orm import scoped_session, sessionmaker
5
7
  from libres.context.core import StoppableService
6
8
 
7
9
 
8
- import typing as _t
10
+ from typing import Any
9
11
 
10
12
 
11
13
  SERIALIZABLE = 'SERIALIZABLE'
@@ -24,8 +26,8 @@ class SessionProvider(StoppableService):
24
26
  def __init__(
25
27
  self,
26
28
  dsn: str,
27
- engine_config: _t.Optional[_t.Dict[str, _t.Any]] = None,
28
- session_config: _t.Optional[_t.Dict[str, _t.Any]] = None
29
+ engine_config: dict[str, Any] | None = None,
30
+ session_config: dict[str, Any] | None = None
29
31
  ):
30
32
  self.assert_valid_postgres_version(dsn)
31
33
  self.dsn = dsn
@@ -53,13 +55,13 @@ class SessionProvider(StoppableService):
53
55
  self.engine.raw_connection().invalidate()
54
56
  self.engine.dispose()
55
57
 
56
- def get_postgres_version(self, dsn: str) -> _t.Tuple[str, int]:
58
+ def get_postgres_version(self, dsn: str) -> tuple[str, int]:
57
59
  """ Returns the postgres version as a tuple (string, integer).
58
60
 
59
61
  Uses it's own connection to be independent from any session.
60
62
 
61
63
  """
62
- assert 'postgres' in dsn, "Not a postgres database"
64
+ assert 'postgres' in dsn, 'Not a postgres database'
63
65
 
64
66
  query = """
65
67
  SELECT current_setting('server_version'),
@@ -80,6 +82,6 @@ class SessionProvider(StoppableService):
80
82
  v, n = self.get_postgres_version(dsn)
81
83
 
82
84
  if n < 90100:
83
- raise RuntimeError(f"PostgreSQL 9.1+ is required, got {v}")
85
+ raise RuntimeError(f'PostgreSQL 9.1+ is required, got {v}')
84
86
 
85
87
  return dsn
@@ -1,13 +1,16 @@
1
+ from __future__ import annotations
2
+
1
3
  import textwrap
2
4
  from uuid import UUID
3
5
 
4
6
 
5
- import typing as _t
6
- if _t.TYPE_CHECKING:
7
+ from typing import Any
8
+ from typing import TYPE_CHECKING
9
+ if TYPE_CHECKING:
7
10
  from libres.context.core import Context
8
11
 
9
12
 
10
- _default: _t.Dict[str, _t.Tuple[_t.Any, str]] = {}
13
+ _default: dict[str, tuple[Any, str]] = {}
11
14
 
12
15
  _default['settings.dsn'] = (
13
16
  None,
@@ -31,7 +34,7 @@ _default['settings.uuid_namespace'] = (
31
34
  )
32
35
 
33
36
 
34
- def set_default_settings(context: 'Context') -> None:
37
+ def set_default_settings(context: Context) -> None:
35
38
  for name, (value, _) in _default.items():
36
39
  context.set(name, value)
37
40
 
@@ -42,9 +45,9 @@ doc = []
42
45
  for name, (value, help_str) in _default.items():
43
46
  reference = f'.. _{name}:\n'
44
47
  title = '{name}\n{line}'.format(name=name, line='-' * len(name))
45
- default = f'default: **{repr(value)}**'
48
+ default = f'default: **{value!r}**'
46
49
  help_str = textwrap.dedent(help_str)
47
50
 
48
- doc.append('\n'.join((reference, title, default, help_str)))
51
+ doc.append(f'{reference}\n{title}\n{default}\n{help_str}')
49
52
 
50
53
  __doc__ = '\n'.join(doc)
libres/db/__init__.py CHANGED
@@ -1,4 +1,6 @@
1
- from libres.db.scheduler import Scheduler as new_scheduler
1
+ from __future__ import annotations
2
+
3
+ from libres.db.scheduler import Scheduler as new_scheduler # noqa: N813
2
4
 
3
5
  __all__ = (
4
6
  'new_scheduler',
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from libres.db.models.base import ORMBase
2
4
  from libres.db.models.allocation import Allocation
3
5
  from libres.db.models.reserved_slot import ReservedSlot