sqlalchemy-events-lib 0.3.0__tar.gz → 0.3.1__tar.gz
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.
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/PKG-INFO +18 -9
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/README.md +17 -8
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/pyproject.toml +1 -1
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events/__init__.py +1 -1
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events/core.py +1 -2
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events/decorators.py +7 -0
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events/default_logger.py +1 -1
- sqlalchemy_events_lib-0.3.1/src/sqlalchemy_events/discovery.py +44 -0
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events/handlers.py +1 -1
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events_lib.egg-info/PKG-INFO +18 -9
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events_lib.egg-info/SOURCES.txt +4 -1
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/tests/conftest.py +2 -3
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/tests/test_autodiscover.py +19 -0
- sqlalchemy_events_lib-0.3.1/src/tests/test_handlers.py +17 -0
- sqlalchemy_events_lib-0.3.1/src/tests/test_sa_events.py +27 -0
- sqlalchemy_events_lib-0.3.1/src/tests/test_with_events_deco.py +45 -0
- sqlalchemy_events_lib-0.3.0/src/sqlalchemy_events/discovery.py +0 -30
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/LICENSE +0 -0
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/setup.cfg +0 -0
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events/callbacks_strategies/__init__.py +0 -0
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events/callbacks_strategies/base.py +0 -0
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events/callbacks_strategies/postgres_callback.py +0 -0
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events/events.py +0 -0
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events/exceptions.py +0 -0
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events/init_triggers_strategies/__init__.py +0 -0
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events/init_triggers_strategies/base.py +0 -0
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events/init_triggers_strategies/postgres_init_triggers.py +0 -0
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events/registry.py +0 -0
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events/types.py +0 -0
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events/utils.py +0 -0
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events_lib.egg-info/dependency_links.txt +0 -0
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events_lib.egg-info/requires.txt +0 -0
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events_lib.egg-info/top_level.txt +0 -0
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/tests/test_is_created_triggers.py +0 -0
- {sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/tests/test_models.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlalchemy-events-lib
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Event-driven extension for SQLAlchemy that enables listening to database CUD events. This library allows you to react to database changes in real time using a clean, declarative API.
|
|
5
5
|
Author-email: Alexey Kostarev <normjkeeewm@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -96,7 +96,6 @@ ___
|
|
|
96
96
|
session.py
|
|
97
97
|
```python
|
|
98
98
|
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
|
|
99
|
-
|
|
100
99
|
from config import DATABASE_URL
|
|
101
100
|
|
|
102
101
|
engine = create_async_engine(DATABASE_URL)
|
|
@@ -114,10 +113,11 @@ from session import engine
|
|
|
114
113
|
|
|
115
114
|
|
|
116
115
|
async def main():
|
|
117
|
-
SQLAlchemyEvents(
|
|
116
|
+
sa_events = SQLAlchemyEvents(
|
|
118
117
|
engine=engine,
|
|
119
118
|
autodiscover_paths=['services']
|
|
120
119
|
)
|
|
120
|
+
await sa_events()
|
|
121
121
|
while True:
|
|
122
122
|
await asyncio.sleep(9999)
|
|
123
123
|
|
|
@@ -165,16 +165,25 @@ If provided, the library will log internal lifecycle events such as:
|
|
|
165
165
|
**Example:**
|
|
166
166
|
```python
|
|
167
167
|
import logging
|
|
168
|
+
import asyncio
|
|
169
|
+
from sqlalchemy_events import SQLAlchemyEvents
|
|
170
|
+
from session import engine
|
|
168
171
|
|
|
169
172
|
logger = logging.getLogger('sqlalchemy_events')
|
|
170
173
|
logger.setLevel(logging.INFO)
|
|
171
174
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
)
|
|
175
|
+
async def main():
|
|
176
|
+
sa_events = SQLAlchemyEvents(
|
|
177
|
+
engine=engine,
|
|
178
|
+
autodiscover_paths=['services'],
|
|
179
|
+
logger=logger
|
|
180
|
+
)
|
|
181
|
+
await sa_events()
|
|
182
|
+
while True:
|
|
183
|
+
await asyncio.sleep(9999)
|
|
184
|
+
|
|
185
|
+
if __name__ == '__main__':
|
|
186
|
+
asyncio.run(main())
|
|
178
187
|
```
|
|
179
188
|
|
|
180
189
|
## How it works
|
|
@@ -74,7 +74,6 @@ ___
|
|
|
74
74
|
session.py
|
|
75
75
|
```python
|
|
76
76
|
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
|
|
77
|
-
|
|
78
77
|
from config import DATABASE_URL
|
|
79
78
|
|
|
80
79
|
engine = create_async_engine(DATABASE_URL)
|
|
@@ -92,10 +91,11 @@ from session import engine
|
|
|
92
91
|
|
|
93
92
|
|
|
94
93
|
async def main():
|
|
95
|
-
SQLAlchemyEvents(
|
|
94
|
+
sa_events = SQLAlchemyEvents(
|
|
96
95
|
engine=engine,
|
|
97
96
|
autodiscover_paths=['services']
|
|
98
97
|
)
|
|
98
|
+
await sa_events()
|
|
99
99
|
while True:
|
|
100
100
|
await asyncio.sleep(9999)
|
|
101
101
|
|
|
@@ -143,16 +143,25 @@ If provided, the library will log internal lifecycle events such as:
|
|
|
143
143
|
**Example:**
|
|
144
144
|
```python
|
|
145
145
|
import logging
|
|
146
|
+
import asyncio
|
|
147
|
+
from sqlalchemy_events import SQLAlchemyEvents
|
|
148
|
+
from session import engine
|
|
146
149
|
|
|
147
150
|
logger = logging.getLogger('sqlalchemy_events')
|
|
148
151
|
logger.setLevel(logging.INFO)
|
|
149
152
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
)
|
|
153
|
+
async def main():
|
|
154
|
+
sa_events = SQLAlchemyEvents(
|
|
155
|
+
engine=engine,
|
|
156
|
+
autodiscover_paths=['services'],
|
|
157
|
+
logger=logger
|
|
158
|
+
)
|
|
159
|
+
await sa_events()
|
|
160
|
+
while True:
|
|
161
|
+
await asyncio.sleep(9999)
|
|
162
|
+
|
|
163
|
+
if __name__ == '__main__':
|
|
164
|
+
asyncio.run(main())
|
|
156
165
|
```
|
|
157
166
|
|
|
158
167
|
## How it works
|
|
@@ -10,7 +10,7 @@ where = ["src"]
|
|
|
10
10
|
|
|
11
11
|
[project]
|
|
12
12
|
name = "sqlalchemy-events-lib"
|
|
13
|
-
version = "0.3.
|
|
13
|
+
version = "0.3.1"
|
|
14
14
|
description = "Event-driven extension for SQLAlchemy that enables listening to database CUD events. This library allows you to react to database changes in real time using a clean, declarative API."
|
|
15
15
|
requires-python = ">=3.12"
|
|
16
16
|
authors = [
|
|
@@ -30,9 +30,8 @@ class SQLAlchemyEvents:
|
|
|
30
30
|
self.autodiscover_paths = autodiscover_paths
|
|
31
31
|
self.logger = logger or DefaultLogger() if verbose else None
|
|
32
32
|
self.verbose = verbose
|
|
33
|
-
asyncio.create_task(self.__init())
|
|
34
33
|
|
|
35
|
-
async def
|
|
34
|
+
async def __call__(self) -> None:
|
|
36
35
|
if not isinstance(self.engine, (AsyncEngine, Engine)):
|
|
37
36
|
raise RuntimeError(
|
|
38
37
|
'[SQLAlchemyEvents] \'engine\' must be an instance of '
|
{sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events/decorators.py
RENAMED
|
@@ -1,12 +1,19 @@
|
|
|
1
|
+
from sqlalchemy.orm import DeclarativeBase
|
|
2
|
+
|
|
1
3
|
from .types import SaEvent
|
|
2
4
|
|
|
3
5
|
|
|
4
6
|
def with_events(events: list[SaEvent]):
|
|
7
|
+
if not isinstance(events, list) or not events:
|
|
8
|
+
raise RuntimeError('Events must be a list with at least one SeEvent element')
|
|
9
|
+
|
|
5
10
|
for e in events:
|
|
6
11
|
if not isinstance(e, SaEvent):
|
|
7
12
|
raise RuntimeError(f'Event must be a SaEvent instance, not {type(e)}')
|
|
8
13
|
|
|
9
14
|
def wrapper(cls):
|
|
15
|
+
if not issubclass(cls, DeclarativeBase):
|
|
16
|
+
raise RuntimeError('Model must inherit from DeclarativeBase')
|
|
10
17
|
cls.__events__ = set(events)
|
|
11
18
|
|
|
12
19
|
class Events:
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
import pkgutil
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from types import ModuleType
|
|
5
|
+
from typing import Iterable, List
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def autodiscover(paths: Iterable[str | Path]) -> List[ModuleType]:
|
|
9
|
+
modules: List[ModuleType] = []
|
|
10
|
+
seen: set[str] = set()
|
|
11
|
+
|
|
12
|
+
def add_module(module: ModuleType):
|
|
13
|
+
if module.__name__ in seen:
|
|
14
|
+
return
|
|
15
|
+
seen.add(module.__name__)
|
|
16
|
+
modules.append(module)
|
|
17
|
+
|
|
18
|
+
for path in paths:
|
|
19
|
+
is_file = False
|
|
20
|
+
|
|
21
|
+
if isinstance(path, Path):
|
|
22
|
+
is_file = path.suffix == '.py'
|
|
23
|
+
path = str(path)
|
|
24
|
+
|
|
25
|
+
if isinstance(path, str) and path.endswith('.py'):
|
|
26
|
+
is_file = True
|
|
27
|
+
path = path[:-3]
|
|
28
|
+
|
|
29
|
+
path = path.replace('\\', '.').replace('/', '.').lstrip('.')
|
|
30
|
+
|
|
31
|
+
module = importlib.import_module(path)
|
|
32
|
+
add_module(module)
|
|
33
|
+
|
|
34
|
+
if is_file or not hasattr(module, '__path__'):
|
|
35
|
+
continue
|
|
36
|
+
|
|
37
|
+
for _, module_name, _ in pkgutil.walk_packages(
|
|
38
|
+
module.__path__,
|
|
39
|
+
module.__name__ + '.',
|
|
40
|
+
):
|
|
41
|
+
submodule = importlib.import_module(module_name)
|
|
42
|
+
add_module(submodule)
|
|
43
|
+
|
|
44
|
+
return modules
|
{sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events/handlers.py
RENAMED
|
@@ -10,7 +10,7 @@ from .types import Handler
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def __inner(func: Callable, sa_event: SaEvent, model: Type[DeclarativeBase]):
|
|
13
|
-
if not
|
|
13
|
+
if not issubclass(model, DeclarativeBase):
|
|
14
14
|
raise RuntimeError('Model must inherit from DeclarativeBase')
|
|
15
15
|
|
|
16
16
|
event_handlers = get_event_handlers()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlalchemy-events-lib
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Event-driven extension for SQLAlchemy that enables listening to database CUD events. This library allows you to react to database changes in real time using a clean, declarative API.
|
|
5
5
|
Author-email: Alexey Kostarev <normjkeeewm@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -96,7 +96,6 @@ ___
|
|
|
96
96
|
session.py
|
|
97
97
|
```python
|
|
98
98
|
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
|
|
99
|
-
|
|
100
99
|
from config import DATABASE_URL
|
|
101
100
|
|
|
102
101
|
engine = create_async_engine(DATABASE_URL)
|
|
@@ -114,10 +113,11 @@ from session import engine
|
|
|
114
113
|
|
|
115
114
|
|
|
116
115
|
async def main():
|
|
117
|
-
SQLAlchemyEvents(
|
|
116
|
+
sa_events = SQLAlchemyEvents(
|
|
118
117
|
engine=engine,
|
|
119
118
|
autodiscover_paths=['services']
|
|
120
119
|
)
|
|
120
|
+
await sa_events()
|
|
121
121
|
while True:
|
|
122
122
|
await asyncio.sleep(9999)
|
|
123
123
|
|
|
@@ -165,16 +165,25 @@ If provided, the library will log internal lifecycle events such as:
|
|
|
165
165
|
**Example:**
|
|
166
166
|
```python
|
|
167
167
|
import logging
|
|
168
|
+
import asyncio
|
|
169
|
+
from sqlalchemy_events import SQLAlchemyEvents
|
|
170
|
+
from session import engine
|
|
168
171
|
|
|
169
172
|
logger = logging.getLogger('sqlalchemy_events')
|
|
170
173
|
logger.setLevel(logging.INFO)
|
|
171
174
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
)
|
|
175
|
+
async def main():
|
|
176
|
+
sa_events = SQLAlchemyEvents(
|
|
177
|
+
engine=engine,
|
|
178
|
+
autodiscover_paths=['services'],
|
|
179
|
+
logger=logger
|
|
180
|
+
)
|
|
181
|
+
await sa_events()
|
|
182
|
+
while True:
|
|
183
|
+
await asyncio.sleep(9999)
|
|
184
|
+
|
|
185
|
+
if __name__ == '__main__':
|
|
186
|
+
asyncio.run(main())
|
|
178
187
|
```
|
|
179
188
|
|
|
180
189
|
## How it works
|
|
@@ -25,5 +25,8 @@ src/sqlalchemy_events_lib.egg-info/requires.txt
|
|
|
25
25
|
src/sqlalchemy_events_lib.egg-info/top_level.txt
|
|
26
26
|
src/tests/conftest.py
|
|
27
27
|
src/tests/test_autodiscover.py
|
|
28
|
+
src/tests/test_handlers.py
|
|
28
29
|
src/tests/test_is_created_triggers.py
|
|
29
|
-
src/tests/test_models.py
|
|
30
|
+
src/tests/test_models.py
|
|
31
|
+
src/tests/test_sa_events.py
|
|
32
|
+
src/tests/test_with_events_deco.py
|
|
@@ -32,11 +32,10 @@ async def prepared_db(engine):
|
|
|
32
32
|
await conn.execute(text('CREATE SCHEMA public'))
|
|
33
33
|
await conn.run_sync(Base.metadata.create_all)
|
|
34
34
|
|
|
35
|
-
SQLAlchemyEvents(
|
|
35
|
+
await SQLAlchemyEvents(
|
|
36
36
|
engine=engine,
|
|
37
37
|
autodiscover_paths=['tests']
|
|
38
|
-
)
|
|
39
|
-
await asyncio.sleep(0.1)
|
|
38
|
+
)()
|
|
40
39
|
IS_DB = True
|
|
41
40
|
|
|
42
41
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
import types
|
|
3
3
|
|
|
4
|
+
import pytest
|
|
5
|
+
|
|
4
6
|
from sqlalchemy_events.discovery import autodiscover
|
|
5
7
|
from sqlalchemy_events import sa_insert_handler, sa_update_handler, sa_delete_handler
|
|
6
8
|
from sqlalchemy_events.registry import get_event_handlers
|
|
@@ -127,3 +129,20 @@ async def test_discover_handlers():
|
|
|
127
129
|
result_handlers.extend(handler_list)
|
|
128
130
|
|
|
129
131
|
assert len(result_handlers) == len(handlers)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def test_invalid_autodiscover_path():
|
|
135
|
+
with pytest.raises(ModuleNotFoundError):
|
|
136
|
+
autodiscover(['not.existing.module'])
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def test_autodiscover_no_duplicates():
|
|
140
|
+
modules = autodiscover(['tests', 'tests.test_autodiscover.py'])
|
|
141
|
+
|
|
142
|
+
names = [m.__name__ for m in modules]
|
|
143
|
+
assert len(names) == len(set(names))
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def test_autodiscover_import_error_is_handled():
|
|
147
|
+
with pytest.raises(Exception):
|
|
148
|
+
autodiscover(['app.broken_module'])
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from sqlalchemy_events import sa_insert_handler
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_invalid_model_in_handler():
|
|
7
|
+
with pytest.raises(RuntimeError):
|
|
8
|
+
@sa_insert_handler(object)
|
|
9
|
+
def test_func():
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_handler_signature():
|
|
14
|
+
with pytest.raises(TypeError):
|
|
15
|
+
@sa_insert_handler()
|
|
16
|
+
def test_func():
|
|
17
|
+
pass
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from sqlalchemy_events import SQLAlchemyEvents
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async def test_invalid_engine_type():
|
|
9
|
+
with pytest.raises(RuntimeError):
|
|
10
|
+
await SQLAlchemyEvents(engine='not_engine', autodiscover_paths=[])()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
async def test_empty_autodiscover_paths_logs_warning(caplog, engine):
|
|
14
|
+
caplog.set_level('WARNING', logger='SQLAlchemyEvents')
|
|
15
|
+
await SQLAlchemyEvents(engine=engine, autodiscover_paths=[], verbose=True)()
|
|
16
|
+
assert 'No autodiscover paths' in caplog.text
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
async def test_no_logs_when_verbose_disabled(caplog, engine):
|
|
20
|
+
await SQLAlchemyEvents(engine=engine, autodiscover_paths=[], verbose=False)()
|
|
21
|
+
assert caplog.text == ''
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
async def test_custom_logger_used(caplog, engine):
|
|
25
|
+
logger = logging.getLogger('test')
|
|
26
|
+
await SQLAlchemyEvents(engine=engine, autodiscover_paths=[], logger=logger)()
|
|
27
|
+
assert 'SQLAlchemyEvents' in caplog.text
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from sqlalchemy import Column, Integer, String
|
|
3
|
+
|
|
4
|
+
from sqlalchemy_events import SaEvent, with_events
|
|
5
|
+
from tests.test_models import Base, UserModel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_with_events_on_incorrect_class_type():
|
|
9
|
+
with pytest.raises(RuntimeError):
|
|
10
|
+
@with_events([SaEvent.INSERT])
|
|
11
|
+
class Test: ...
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_incorrect_event_type():
|
|
15
|
+
with pytest.raises(RuntimeError):
|
|
16
|
+
@with_events(['incorrect_event_type'])
|
|
17
|
+
class UserModel(Base):
|
|
18
|
+
__tablename__ = 'test_model'
|
|
19
|
+
|
|
20
|
+
id = Column(Integer, primary_key=True)
|
|
21
|
+
name = Column(String)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_empty_events():
|
|
25
|
+
with pytest.raises(TypeError):
|
|
26
|
+
@with_events()
|
|
27
|
+
class UserModel(Base):
|
|
28
|
+
__tablename__ = 'test_model'
|
|
29
|
+
|
|
30
|
+
id = Column(Integer, primary_key=True)
|
|
31
|
+
name = Column(String)
|
|
32
|
+
|
|
33
|
+
with pytest.raises(RuntimeError):
|
|
34
|
+
@with_events([])
|
|
35
|
+
class UserModel(Base):
|
|
36
|
+
__tablename__ = 'test_model'
|
|
37
|
+
|
|
38
|
+
id = Column(Integer, primary_key=True)
|
|
39
|
+
name = Column(String)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_events_in_model():
|
|
43
|
+
assert UserModel.events.INSERT
|
|
44
|
+
assert UserModel.events.UPDATE
|
|
45
|
+
assert UserModel.events.DELETE
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import importlib
|
|
2
|
-
import pkgutil
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
from types import ModuleType
|
|
5
|
-
from typing import Iterable, List
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def autodiscover(paths: Iterable[str]) -> List[ModuleType]:
|
|
9
|
-
modules: List[ModuleType] = []
|
|
10
|
-
|
|
11
|
-
for path in paths:
|
|
12
|
-
if isinstance(path, Path):
|
|
13
|
-
path = str(path)
|
|
14
|
-
path = path.replace('\\', '.')
|
|
15
|
-
|
|
16
|
-
path = path.strip('/').replace('/', '.').lstrip('.')
|
|
17
|
-
module = importlib.import_module(path)
|
|
18
|
-
modules.append(module)
|
|
19
|
-
|
|
20
|
-
if not hasattr(module, '__path__'):
|
|
21
|
-
continue
|
|
22
|
-
|
|
23
|
-
for _, module_name, _ in pkgutil.walk_packages(
|
|
24
|
-
module.__path__,
|
|
25
|
-
module.__name__ + '.',
|
|
26
|
-
):
|
|
27
|
-
submodule = importlib.import_module(module_name)
|
|
28
|
-
modules.append(submodule)
|
|
29
|
-
|
|
30
|
-
return modules
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events/exceptions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/sqlalchemy_events/registry.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sqlalchemy_events_lib-0.3.0 → sqlalchemy_events_lib-0.3.1}/src/tests/test_is_created_triggers.py
RENAMED
|
File without changes
|
|
File without changes
|