sqlalchemy-events-lib 0.3.4__tar.gz → 0.4.0__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.
Files changed (36) hide show
  1. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/LICENSE +4 -4
  2. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/PKG-INFO +210 -208
  3. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/README.md +187 -185
  4. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/pyproject.toml +45 -45
  5. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/setup.cfg +4 -4
  6. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/sqlalchemy_events/__init__.py +14 -14
  7. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/sqlalchemy_events/callbacks_strategies/base.py +7 -7
  8. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/sqlalchemy_events/callbacks_strategies/postgres_callback.py +63 -68
  9. sqlalchemy_events_lib-0.4.0/src/sqlalchemy_events/core.py +333 -0
  10. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/sqlalchemy_events/decorators.py +25 -25
  11. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/sqlalchemy_events/default_logger.py +24 -24
  12. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/sqlalchemy_events/discovery.py +43 -43
  13. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/sqlalchemy_events/events.py +34 -34
  14. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/sqlalchemy_events/handlers.py +49 -49
  15. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/sqlalchemy_events/init_triggers_strategies/base.py +13 -13
  16. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/sqlalchemy_events/init_triggers_strategies/postgres_init_triggers.py +114 -114
  17. sqlalchemy_events_lib-0.4.0/src/sqlalchemy_events/py.typed +0 -0
  18. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/sqlalchemy_events/registry.py +14 -14
  19. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/sqlalchemy_events/types.py +40 -40
  20. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/sqlalchemy_events/utils.py +35 -35
  21. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/sqlalchemy_events_lib.egg-info/PKG-INFO +210 -208
  22. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/sqlalchemy_events_lib.egg-info/SOURCES.txt +1 -0
  23. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/tests/conftest.py +55 -55
  24. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/tests/test_autodiscover.py +146 -146
  25. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/tests/test_handlers.py +78 -78
  26. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/tests/test_is_created_triggers.py +48 -48
  27. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/tests/test_models.py +15 -15
  28. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/tests/test_sa_events.py +26 -26
  29. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/tests/test_with_events_deco.py +44 -44
  30. sqlalchemy_events_lib-0.3.4/src/sqlalchemy_events/core.py +0 -163
  31. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/sqlalchemy_events/callbacks_strategies/__init__.py +0 -0
  32. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/sqlalchemy_events/exceptions.py +0 -0
  33. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/sqlalchemy_events/init_triggers_strategies/__init__.py +0 -0
  34. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/sqlalchemy_events_lib.egg-info/dependency_links.txt +0 -0
  35. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/sqlalchemy_events_lib.egg-info/requires.txt +0 -0
  36. {sqlalchemy_events_lib-0.3.4 → sqlalchemy_events_lib-0.4.0}/src/sqlalchemy_events_lib.egg-info/top_level.txt +0 -0
@@ -1,5 +1,5 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Alexey Kostarev
4
-
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alexey Kostarev
4
+
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy...
@@ -1,208 +1,210 @@
1
- Metadata-Version: 2.4
2
- Name: sqlalchemy-events-lib
3
- Version: 0.3.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
- Author-email: Alexey Kostarev <normjkeeewm@gmail.com>
6
- License: MIT
7
- Project-URL: Homepage, https://github.com/NormanwOw/SQLAlchemy-Events
8
- Project-URL: Repository, https://github.com/NormanwOw/SQLAlchemy-Events
9
- Project-URL: Issues, https://github.com/NormanwOw/SQLAlchemy-Events/issues
10
- Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 3.12
12
- Classifier: License :: OSI Approved :: MIT License
13
- Classifier: Operating System :: OS Independent
14
- Requires-Python: >=3.12
15
- Description-Content-Type: text/markdown
16
- License-File: LICENSE
17
- Requires-Dist: sqlalchemy>=2.0.49
18
- Provides-Extra: test
19
- Requires-Dist: pytest; extra == "test"
20
- Requires-Dist: pytest-asyncio; extra == "test"
21
- Dynamic: license-file
22
-
23
- # SQLAlchemy Events
24
-
25
- ## About
26
- Event-driven extension for SQLAlchemy that enables listening to database CUD events.
27
- This library allows you to react to database changes in real time using a clean, declarative API.
28
- * **Currently supports PostgreSQL only**
29
-
30
-
31
- ## Installation
32
-
33
- ```bash
34
- $ pip install sqlalchemy-events-lib
35
- ```
36
- ## Quick start
37
-
38
-
39
- ### Define models with enabled event tracking using **`@with_events`**
40
- models.py
41
- ```python
42
- import uuid
43
-
44
- from sqlalchemy import UUID
45
- from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
46
-
47
- from sqlalchemy_events import with_events, SaEvent
48
-
49
-
50
- class Base(DeclarativeBase):
51
- id: Mapped[uuid.UUID] = mapped_column(
52
- UUID, nullable=False, primary_key=True, default=uuid.uuid4
53
- )
54
-
55
- @with_events([SaEvent.INSERT, SaEvent.UPDATE, SaEvent.DELETE])
56
- class UserModel(Base):
57
- __tablename__ = 'users'
58
-
59
- name: Mapped[str] = mapped_column()
60
- ```
61
- ___
62
-
63
-
64
- ### Define event handlers using decorators `@sa_insert_handler`, `@sa_update_handler`, `@sa_delete_handler`
65
- services/handlers.py
66
- ```python
67
- from models import UserModel
68
- from sqlalchemy_events import sa_insert_handler
69
-
70
- @sa_insert_handler(UserModel)
71
- async def handle_user_insert():
72
- print('User inserted!')
73
- ```
74
-
75
- **Optional Argument**: `rows`
76
- Handlers can optionally accept a rows argument.
77
-
78
- If the parameter is declared in the function signature, it will automatically receive a list of affected `row` IDs.
79
-
80
- ```python
81
- from models import UserModel
82
- from sqlalchemy_events import sa_insert_handler
83
-
84
- @sa_insert_handler(UserModel)
85
- async def handle_user_insert(rows: list[DB_ID]):
86
- print('Users inserted!', rows)
87
- ```
88
- **Output:**
89
- ```
90
- Users inserted! ['3310aa38-f555-4c05-a57f-5acae32a0a7b', '6aeba1b0-8e80-4369-8adf-cf967ab7ba7a']
91
- ```
92
-
93
- ___
94
-
95
- ### Configure SQLAlchemy async engine
96
- session.py
97
- ```python
98
- from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
99
- from config import DATABASE_URL
100
-
101
- engine = create_async_engine(DATABASE_URL)
102
- async_session = async_sessionmaker(engine, expire_on_commit=False, autoflush=False)
103
-
104
- ```
105
- ___
106
-
107
- ### Initialize event system and start listening
108
- main.py
109
- ```python
110
- import asyncio
111
- from sqlalchemy_events import SQLAlchemyEvents
112
- from session import engine
113
-
114
-
115
- async def main():
116
- sa_events = SQLAlchemyEvents(
117
- engine=engine,
118
- autodiscover_paths=['services']
119
- )
120
- await sa_events()
121
- while True:
122
- await asyncio.sleep(9999)
123
-
124
- if __name__ == '__main__':
125
- asyncio.run(main())
126
- ```
127
-
128
- ## Configuration
129
- ### SQLAlchemyEvents
130
-
131
- The SQLAlchemyEvents class accepts the following parameters:
132
- ```python
133
- SQLAlchemyEvents(
134
- engine,
135
- autodiscover_paths,
136
- logger=None,
137
- verbose=True
138
- )
139
- ```
140
-
141
- Parameters:
142
- * **engine** - SQLAlchemy Engine or AsyncEngine instance.
143
- * **autodiscover_paths** - List of Python module paths where event handlers are defined.
144
- These modules are automatically imported so that decorators such as
145
- `@sa_insert_handler`, `@sa_update_handler`, `@sa_delete_handler` are executed.
146
- **Example:**
147
- `autodiscover_paths=["services", "app.handlers"]`
148
-
149
- * **verbose** - Enables detailed logging output. When set to True, the library will log additional informational and warning messages to help with debugging and configuration.
150
-
151
- ### Important:
152
-
153
- All modules containing event handlers must be imported through autodiscover
154
- This ensures decorator registration is executed at startup
155
-
156
- ### logger (optional)
157
- A standard Python logging.Logger instance.
158
-
159
- If provided, the library will log internal lifecycle events such as:
160
-
161
- * successful initialization
162
- * listener startup
163
- * trigger setup
164
-
165
- **Example:**
166
- ```python
167
- import logging
168
- import asyncio
169
- from sqlalchemy_events import SQLAlchemyEvents
170
- from session import engine
171
-
172
- logger = logging.getLogger('sqlalchemy_events')
173
- logger.setLevel(logging.INFO)
174
-
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())
187
- ```
188
-
189
- ## How it works
190
- 1. autodiscover_paths modules are imported at startup
191
- 2. Decorators register event handlers into a global registry
192
- 3. Triggers send events via LISTEN/NOTIFY
193
- 4. The library receives notifications and dispatches them to registered handlers
194
-
195
- ## Notes
196
- * Handlers can be both async and regular functions
197
- * Only models registered with @with_events will emit events
198
- * Currently supports LISTEN/NOTIFY
199
- * Ensure handlers are imported via autodiscover_paths, otherwise they will not be registered
200
-
201
- ## Example flow
202
- INSERT INTO/UPDATE/DELETE FROM {table} → DATABASE trigger fires →
203
- NOTIFY → Python listener receives event →
204
- handler is executed
205
-
206
- ## License
207
-
208
- MIT
1
+ Metadata-Version: 2.4
2
+ Name: sqlalchemy-events-lib
3
+ Version: 0.4.0
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
+ Author-email: Alexey Kostarev <normjkeeewm@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/NormanwOw/SQLAlchemy-Events
8
+ Project-URL: Repository, https://github.com/NormanwOw/SQLAlchemy-Events
9
+ Project-URL: Issues, https://github.com/NormanwOw/SQLAlchemy-Events/issues
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Requires-Python: >=3.12
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: sqlalchemy>=2.0.49
18
+ Provides-Extra: test
19
+ Requires-Dist: pytest; extra == "test"
20
+ Requires-Dist: pytest-asyncio; extra == "test"
21
+ Dynamic: license-file
22
+
23
+ # SQLAlchemy Events
24
+
25
+ ## About
26
+ Event-driven extension for SQLAlchemy that enables listening to database CUD events.
27
+ This library allows you to react to database changes in real time using a clean, declarative API.
28
+ * **Currently supports PostgreSQL only**
29
+
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ $ pip install sqlalchemy-events-lib
35
+ ```
36
+ ## Quick start
37
+
38
+
39
+ ### Define models with enabled event tracking using **`@with_events`**
40
+ models.py
41
+ ```python
42
+ import uuid
43
+
44
+ from sqlalchemy import UUID
45
+ from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
46
+
47
+ from sqlalchemy_events import with_events, SaEvent
48
+
49
+
50
+ class Base(DeclarativeBase):
51
+ id: Mapped[uuid.UUID] = mapped_column(
52
+ UUID, nullable=False, primary_key=True, default=uuid.uuid4
53
+ )
54
+
55
+ @with_events([SaEvent.INSERT, SaEvent.UPDATE, SaEvent.DELETE])
56
+ class UserModel(Base):
57
+ __tablename__ = 'users'
58
+
59
+ name: Mapped[str] = mapped_column()
60
+ ```
61
+ ___
62
+
63
+
64
+ ### Define event handlers using decorators `@sa_insert_handler`, `@sa_update_handler`, `@sa_delete_handler`
65
+ services/handlers.py
66
+ ```python
67
+ from models import UserModel
68
+ from sqlalchemy_events import sa_insert_handler
69
+
70
+ @sa_insert_handler(UserModel)
71
+ async def handle_user_insert():
72
+ print('User inserted!')
73
+ ```
74
+
75
+ **Optional Argument**: `rows`
76
+ Handlers can optionally accept a rows argument.
77
+
78
+ If the parameter is declared in the function signature, it will automatically receive a list of affected `row` IDs.
79
+
80
+ ```python
81
+ from models import UserModel
82
+ from sqlalchemy_events import sa_insert_handler
83
+
84
+ @sa_insert_handler(UserModel)
85
+ async def handle_user_insert(rows: list[DB_ID]):
86
+ print('Users inserted!', rows)
87
+ ```
88
+ **Output:**
89
+ ```
90
+ Users inserted! ['3310aa38-f555-4c05-a57f-5acae32a0a7b', '6aeba1b0-8e80-4369-8adf-cf967ab7ba7a']
91
+ ```
92
+
93
+ ___
94
+
95
+ ### Configure SQLAlchemy async engine
96
+ session.py
97
+ ```python
98
+ from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
99
+ from config import DATABASE_URL
100
+
101
+ engine = create_async_engine(DATABASE_URL)
102
+ async_session = async_sessionmaker(engine, expire_on_commit=False, autoflush=False)
103
+
104
+ ```
105
+ ___
106
+
107
+ ### Initialize event system and start listening
108
+ main.py
109
+ ```python
110
+ import asyncio
111
+ from sqlalchemy_events import SQLAlchemyEvents
112
+ from session import engine
113
+
114
+
115
+ async def main():
116
+ sa_events = SQLAlchemyEvents(
117
+ engine=engine,
118
+ autodiscover_paths=['services']
119
+ )
120
+ await sa_events()
121
+ while True:
122
+ await asyncio.sleep(9999)
123
+
124
+ if __name__ == '__main__':
125
+ asyncio.run(main())
126
+ ```
127
+
128
+ ## Configuration
129
+ ### SQLAlchemyEvents
130
+
131
+ The SQLAlchemyEvents class accepts the following parameters:
132
+ ```python
133
+ SQLAlchemyEvents(
134
+ engine,
135
+ autodiscover_paths,
136
+ schema='',
137
+ logger=None,
138
+ verbose=True
139
+ )
140
+ ```
141
+
142
+ Parameters:
143
+ * **engine** - SQLAlchemy Engine or AsyncEngine instance.
144
+ * **autodiscover_paths** - List of Python module paths where event handlers are defined.
145
+ These modules are automatically imported so that decorators such as
146
+ `@sa_insert_handler`, `@sa_update_handler`, `@sa_delete_handler` are executed.
147
+ **Example:**
148
+ `autodiscover_paths=["services", "app.handlers"]`
149
+
150
+ * **schema** - Custom database schema
151
+ * **verbose** - Enables detailed logging output. When set to True, the library will log additional informational and warning messages to help with debugging and configuration.
152
+
153
+ ### Important:
154
+
155
+ All modules containing event handlers must be imported through autodiscover
156
+ This ensures decorator registration is executed at startup
157
+
158
+ ### logger (optional)
159
+ A standard Python logging.Logger instance.
160
+
161
+ If provided, the library will log internal lifecycle events such as:
162
+
163
+ * successful initialization
164
+ * listener startup
165
+ * trigger setup
166
+
167
+ **Example:**
168
+ ```python
169
+ import logging
170
+ import asyncio
171
+ from sqlalchemy_events import SQLAlchemyEvents
172
+ from session import engine
173
+
174
+ logger = logging.getLogger('sqlalchemy_events')
175
+ logger.setLevel(logging.INFO)
176
+
177
+ async def main():
178
+ sa_events = SQLAlchemyEvents(
179
+ engine=engine,
180
+ autodiscover_paths=['services'],
181
+ logger=logger
182
+ )
183
+ await sa_events()
184
+ while True:
185
+ await asyncio.sleep(9999)
186
+
187
+ if __name__ == '__main__':
188
+ asyncio.run(main())
189
+ ```
190
+
191
+ ## How it works
192
+ 1. autodiscover_paths modules are imported at startup
193
+ 2. Decorators register event handlers into a global registry
194
+ 3. Triggers send events via LISTEN/NOTIFY
195
+ 4. The library receives notifications and dispatches them to registered handlers
196
+
197
+ ## Notes
198
+ * Handlers can be both async and regular functions
199
+ * Only models registered with @with_events will emit events
200
+ * Currently supports LISTEN/NOTIFY
201
+ * Ensure handlers are imported via autodiscover_paths, otherwise they will not be registered
202
+
203
+ ## Example flow
204
+ INSERT INTO/UPDATE/DELETE FROM {table} → DATABASE trigger fires →
205
+ NOTIFY → Python listener receives event →
206
+ handler is executed
207
+
208
+ ## License
209
+
210
+ MIT