datanommer.models 1.2.0__tar.gz → 1.3.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.
- {datanommer_models-1.2.0 → datanommer_models-1.3.0}/NEWS.rst +35 -4
- {datanommer_models-1.2.0 → datanommer_models-1.3.0}/PKG-INFO +2 -1
- {datanommer_models-1.2.0 → datanommer_models-1.3.0}/coverage.xml +76 -60
- {datanommer_models-1.2.0 → datanommer_models-1.3.0}/datanommer/models/__init__.py +70 -14
- {datanommer_models-1.2.0 → datanommer_models-1.3.0}/datanommer/models/testing/__init__.py +12 -4
- {datanommer_models-1.2.0 → datanommer_models-1.3.0}/pyproject.toml +3 -1
- {datanommer_models-1.2.0 → datanommer_models-1.3.0}/tests/test_jsonencodeddict.py +2 -2
- {datanommer_models-1.2.0 → datanommer_models-1.3.0}/tests/test_model.py +57 -32
- {datanommer_models-1.2.0 → datanommer_models-1.3.0}/LICENSE +0 -0
- {datanommer_models-1.2.0 → datanommer_models-1.3.0}/README.rst +0 -0
- {datanommer_models-1.2.0 → datanommer_models-1.3.0}/alembic.ini +0 -0
- {datanommer_models-1.2.0 → datanommer_models-1.3.0}/datanommer/models/alembic/env.py +0 -0
- {datanommer_models-1.2.0 → datanommer_models-1.3.0}/datanommer/models/alembic/script.py.mako +0 -0
- {datanommer_models-1.2.0 → datanommer_models-1.3.0}/datanommer/models/alembic/versions/5db25abc63be_init.py +0 -0
- {datanommer_models-1.2.0 → datanommer_models-1.3.0}/datanommer/models/alembic/versions/951c40020acc_unique.py +0 -0
- {datanommer_models-1.2.0 → datanommer_models-1.3.0}/tests/conftest.py +0 -0
- {datanommer_models-1.2.0 → datanommer_models-1.3.0}/tox.ini +0 -0
@@ -2,8 +2,39 @@
|
|
2
2
|
Release Notes
|
3
3
|
=============
|
4
4
|
|
5
|
+
For ``datanommer.models``
|
6
|
+
|
5
7
|
.. towncrier release notes start
|
6
8
|
|
9
|
+
v1.3.0
|
10
|
+
======
|
11
|
+
|
12
|
+
Released on 2024-05-22.
|
13
|
+
|
14
|
+
Features
|
15
|
+
^^^^^^^^
|
16
|
+
|
17
|
+
* Add a ``get_first()`` method on ``Message`` to get the first message matching
|
18
|
+
a grep-like query (`99fb739 <https://github.com/fedora-infra/datanommer/commit/99fb739>`_).
|
19
|
+
|
20
|
+
Bug Fixes
|
21
|
+
^^^^^^^^^
|
22
|
+
|
23
|
+
* Don't compute the total when not necessary (`99fb739 <https://github.com/fedora-infra/datanommer/commit/99fb739>`_).
|
24
|
+
|
25
|
+
Documentation Improvements
|
26
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
27
|
+
|
28
|
+
* Add online documentation with Sphinx, see https://datanommer.readthedocs.io
|
29
|
+
(`2631885 <https://github.com/fedora-infra/datanommer/commit/2631885>`_).
|
30
|
+
|
31
|
+
Other Changes
|
32
|
+
^^^^^^^^^^^^^
|
33
|
+
|
34
|
+
* Improve the unit tests (`610067f <https://github.com/fedora-infra/datanommer/commit/610067f>`_, `075052c <https://github.com/fedora-infra/datanommer/commit/075052c>`_).
|
35
|
+
* Update dependencies
|
36
|
+
|
37
|
+
|
7
38
|
v1.2.0
|
8
39
|
======
|
9
40
|
|
@@ -21,8 +52,8 @@ Features
|
|
21
52
|
Development Improvements
|
22
53
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
23
54
|
|
24
|
-
* Use Ruff instead of flake8 and isort and bandit (
|
25
|
-
|
55
|
+
* Use Ruff instead of flake8 and isort and bandit (`4f7ffaa
|
56
|
+
<https://github.com/fedora-infra/datanommer/commit/4f7ffaa>`_).
|
26
57
|
|
27
58
|
|
28
59
|
v1.1.0
|
@@ -38,8 +69,8 @@ Dependency Changes
|
|
38
69
|
|
39
70
|
* Drop support for python 3.7, add support for python 3.10 (`PR#890
|
40
71
|
<https://github.com/fedora-infra/datanommer/pull/890>`_).
|
41
|
-
* Add the ``koji-fedoramessaging-messages`` package (
|
42
|
-
|
72
|
+
* Add the ``koji-fedoramessaging-messages`` package (`#1257
|
73
|
+
<https://github.com/fedora-infra/datanommer/issues/1257>`_).
|
43
74
|
|
44
75
|
|
45
76
|
v1.0.4
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: datanommer.models
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.3.0
|
4
4
|
Summary: SQLAlchemy models for datanommer
|
5
5
|
Home-page: https://github.com/fedora-infra/datanommer
|
6
6
|
License: GPL-3.0-or-later
|
@@ -32,6 +32,7 @@ Requires-Dist: fmn-messages ; extra == "schemas"
|
|
32
32
|
Requires-Dist: kerneltest-messages (>=1.0.0,<2.0.0) ; extra == "schemas"
|
33
33
|
Requires-Dist: koji-fedoramessaging-messages (>=1.2.2,<2.0.0) ; extra == "schemas"
|
34
34
|
Requires-Dist: koschei-messages ; extra == "schemas"
|
35
|
+
Requires-Dist: maubot-fedora-messages ; extra == "schemas"
|
35
36
|
Requires-Dist: mdapi-messages ; extra == "schemas"
|
36
37
|
Requires-Dist: mediawiki-messages ; extra == "schemas"
|
37
38
|
Requires-Dist: meetbot-messages ; extra == "schemas"
|
@@ -1,14 +1,14 @@
|
|
1
1
|
<?xml version="1.0" ?>
|
2
|
-
<coverage version="7.
|
3
|
-
<!-- Generated by coverage.py: https://coverage.readthedocs.io/en/7.
|
2
|
+
<coverage version="7.5.1" timestamp="1716382532447" lines-valid="236" lines-covered="236" line-rate="1" branches-valid="108" branches-covered="108" branch-rate="1" complexity="0">
|
3
|
+
<!-- Generated by coverage.py: https://coverage.readthedocs.io/en/7.5.1 -->
|
4
4
|
<!-- Based on https://raw.githubusercontent.com/cobertura/web/master/htdocs/xml/coverage-04.dtd -->
|
5
5
|
<sources>
|
6
6
|
<source>/home/abompard/Fedora/apps/datanommer/datanommer.models/datanommer</source>
|
7
7
|
</sources>
|
8
8
|
<packages>
|
9
|
-
<package name="models" line-rate="
|
9
|
+
<package name="models" line-rate="1" branch-rate="1" complexity="0">
|
10
10
|
<classes>
|
11
|
-
<class name="__init__.py" filename="models/__init__.py" complexity="0" line-rate="
|
11
|
+
<class name="__init__.py" filename="models/__init__.py" complexity="0" line-rate="1" branch-rate="1">
|
12
12
|
<methods/>
|
13
13
|
<lines>
|
14
14
|
<line number="16" hits="1"/>
|
@@ -61,9 +61,9 @@
|
|
61
61
|
<line number="132" hits="1"/>
|
62
62
|
<line number="135" hits="1"/>
|
63
63
|
<line number="136" hits="1"/>
|
64
|
-
<line number="137" hits="
|
65
|
-
<line number="138" hits="
|
66
|
-
<line number="143" hits="
|
64
|
+
<line number="137" hits="1"/>
|
65
|
+
<line number="138" hits="1"/>
|
66
|
+
<line number="143" hits="1"/>
|
67
67
|
<line number="144" hits="1"/>
|
68
68
|
<line number="145" hits="1"/>
|
69
69
|
<line number="146" hits="1"/>
|
@@ -160,77 +160,93 @@
|
|
160
160
|
<line number="359" hits="1"/>
|
161
161
|
<line number="361" hits="1"/>
|
162
162
|
<line number="362" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
163
|
-
<line number="
|
163
|
+
<line number="405" hits="1"/>
|
164
|
+
<line number="406" hits="1"/>
|
165
|
+
<line number="407" hits="1"/>
|
166
|
+
<line number="408" hits="1"/>
|
167
|
+
<line number="409" hits="1"/>
|
168
|
+
<line number="410" hits="1"/>
|
169
|
+
<line number="411" hits="1"/>
|
170
|
+
<line number="412" hits="1"/>
|
171
|
+
<line number="413" hits="1"/>
|
164
172
|
<line number="415" hits="1"/>
|
165
173
|
<line number="416" hits="1"/>
|
166
|
-
<line number="
|
167
|
-
<line number="418" hits="1"/>
|
168
|
-
<line number="419" hits="1"/>
|
169
|
-
<line number="420" hits="1"/>
|
174
|
+
<line number="420" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
170
175
|
<line number="421" hits="1"/>
|
171
|
-
<line number="
|
172
|
-
<line number="
|
173
|
-
<line number="
|
174
|
-
<line number="429" hits="1"
|
175
|
-
<line number="
|
176
|
-
<line number="
|
177
|
-
<line number="435" hits="1"/>
|
178
|
-
<line number="
|
179
|
-
<line number="438" hits="1"/>
|
176
|
+
<line number="425" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
177
|
+
<line number="426" hits="1"/>
|
178
|
+
<line number="428" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
179
|
+
<line number="429" hits="1"/>
|
180
|
+
<line number="432" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
181
|
+
<line number="433" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
182
|
+
<line number="435" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
183
|
+
<line number="436" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
184
|
+
<line number="438" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
185
|
+
<line number="439" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
180
186
|
<line number="441" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
181
187
|
<line number="442" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
182
188
|
<line number="444" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
183
189
|
<line number="445" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
184
|
-
<line number="447" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
185
190
|
<line number="448" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
186
|
-
<line number="
|
191
|
+
<line number="449" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
187
192
|
<line number="451" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
188
|
-
<line number="
|
189
|
-
<line number="
|
193
|
+
<line number="452" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
194
|
+
<line number="456" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
190
195
|
<line number="457" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
191
|
-
<line number="
|
196
|
+
<line number="459" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
192
197
|
<line number="460" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
193
|
-
<line number="
|
198
|
+
<line number="462" hits="1"/>
|
199
|
+
<line number="464" hits="1"/>
|
194
200
|
<line number="465" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
195
|
-
<line number="
|
196
|
-
<line number="
|
197
|
-
<line number="
|
198
|
-
<line number="
|
199
|
-
<line number="473" hits="1"/>
|
200
|
-
<line number="475" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
201
|
-
<line number="476" hits="1"/>
|
202
|
-
<line number="478" hits="1"/>
|
203
|
-
<line number="479" hits="1"/>
|
204
|
-
<line number="481" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
205
|
-
<line number="482" hits="1"/>
|
206
|
-
<line number="485" hits="1"/>
|
207
|
-
<line number="486" hits="1"/>
|
208
|
-
<line number="489" hits="1"/>
|
209
|
-
<line number="490" hits="1"/>
|
210
|
-
<line number="491" hits="1"/>
|
211
|
-
<line number="493" hits="1"/>
|
212
|
-
<line number="494" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
213
|
-
<line number="500" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
214
|
-
<line number="503" hits="1"/>
|
215
|
-
<line number="504" hits="1"/>
|
216
|
-
<line number="505" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
217
|
-
<line number="506" hits="1"/>
|
218
|
-
<line number="507" hits="1"/>
|
219
|
-
<line number="508" hits="1"/>
|
220
|
-
<line number="509" hits="1"/>
|
221
|
-
<line number="510" hits="1"/>
|
222
|
-
<line number="512" hits="1"/>
|
223
|
-
<line number="513" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
224
|
-
<line number="514" hits="1"/>
|
201
|
+
<line number="511" hits="1"/>
|
202
|
+
<line number="513" hits="1"/>
|
203
|
+
<line number="515" hits="1"/>
|
204
|
+
<line number="516" hits="1"/>
|
225
205
|
<line number="517" hits="1"/>
|
226
|
-
<line number="
|
227
|
-
<line number="
|
206
|
+
<line number="519" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
207
|
+
<line number="520" hits="1"/>
|
228
208
|
<line number="522" hits="1"/>
|
229
209
|
<line number="523" hits="1"/>
|
230
210
|
<line number="524" hits="1"/>
|
231
|
-
<line number="
|
211
|
+
<line number="526" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
212
|
+
<line number="527" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
232
213
|
<line number="528" hits="1"/>
|
214
|
+
<line number="529" hits="1"/>
|
215
|
+
<line number="532" hits="1"/>
|
216
|
+
<line number="533" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
217
|
+
<line number="534" hits="1"/>
|
233
218
|
<line number="535" hits="1"/>
|
219
|
+
<line number="537" hits="1"/>
|
220
|
+
<line number="538" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
221
|
+
<line number="540" hits="1"/>
|
222
|
+
<line number="541" hits="1"/>
|
223
|
+
<line number="542" hits="1"/>
|
224
|
+
<line number="545" hits="1"/>
|
225
|
+
<line number="546" hits="1"/>
|
226
|
+
<line number="547" hits="1"/>
|
227
|
+
<line number="549" hits="1"/>
|
228
|
+
<line number="550" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
229
|
+
<line number="556" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
230
|
+
<line number="559" hits="1"/>
|
231
|
+
<line number="560" hits="1"/>
|
232
|
+
<line number="561" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
233
|
+
<line number="562" hits="1"/>
|
234
|
+
<line number="563" hits="1"/>
|
235
|
+
<line number="564" hits="1"/>
|
236
|
+
<line number="565" hits="1"/>
|
237
|
+
<line number="566" hits="1"/>
|
238
|
+
<line number="568" hits="1"/>
|
239
|
+
<line number="569" hits="1" branch="true" condition-coverage="100% (2/2)"/>
|
240
|
+
<line number="570" hits="1"/>
|
241
|
+
<line number="573" hits="1"/>
|
242
|
+
<line number="574" hits="1"/>
|
243
|
+
<line number="575" hits="1"/>
|
244
|
+
<line number="578" hits="1"/>
|
245
|
+
<line number="579" hits="1"/>
|
246
|
+
<line number="580" hits="1"/>
|
247
|
+
<line number="583" hits="1"/>
|
248
|
+
<line number="584" hits="1"/>
|
249
|
+
<line number="591" hits="1"/>
|
234
250
|
</lines>
|
235
251
|
</class>
|
236
252
|
</classes>
|
@@ -168,7 +168,7 @@ def add(message):
|
|
168
168
|
# https://docs.sqlalchemy.org/en/14/core/custom_types.html#marshal-json-strings
|
169
169
|
|
170
170
|
|
171
|
-
class
|
171
|
+
class _JSONEncodedDict(TypeDecorator):
|
172
172
|
"""Represents an immutable structure as a json-encoded string."""
|
173
173
|
|
174
174
|
impl = UnicodeText
|
@@ -227,7 +227,7 @@ class Message(DeclarativeBase):
|
|
227
227
|
crypto = Column(UnicodeText)
|
228
228
|
source_name = Column(Unicode, default="datanommer")
|
229
229
|
source_version = Column(Unicode, default=lambda context: __version__)
|
230
|
-
msg = Column(
|
230
|
+
msg = Column(_JSONEncodedDict, nullable=False)
|
231
231
|
headers = Column(postgresql.JSONB(none_as_null=True))
|
232
232
|
users = relationship(
|
233
233
|
"User",
|
@@ -359,13 +359,10 @@ class Message(DeclarativeBase):
|
|
359
359
|
return self.as_dict(request)
|
360
360
|
|
361
361
|
@classmethod
|
362
|
-
def
|
362
|
+
def make_query(
|
363
363
|
cls,
|
364
364
|
start=None,
|
365
365
|
end=None,
|
366
|
-
page=1,
|
367
|
-
rows_per_page=100,
|
368
|
-
order="asc",
|
369
366
|
msg_id=None,
|
370
367
|
users=None,
|
371
368
|
not_users=None,
|
@@ -376,7 +373,6 @@ class Message(DeclarativeBase):
|
|
376
373
|
topics=None,
|
377
374
|
not_topics=None,
|
378
375
|
contains=None,
|
379
|
-
defer=False,
|
380
376
|
):
|
381
377
|
"""Flexible query interface for messages.
|
382
378
|
|
@@ -404,11 +400,6 @@ class Message(DeclarativeBase):
|
|
404
400
|
|
405
401
|
(user == 'ralph') AND
|
406
402
|
NOT (category == 'bodhi' OR category == 'wiki')
|
407
|
-
|
408
|
-
----
|
409
|
-
|
410
|
-
If the `defer` argument evaluates to True, the query won't actually
|
411
|
-
be executed, but a SQLAlchemy query object returned instead.
|
412
403
|
"""
|
413
404
|
|
414
405
|
users = users or []
|
@@ -468,23 +459,88 @@ class Message(DeclarativeBase):
|
|
468
459
|
if not_topics:
|
469
460
|
query = query.where(not_(or_(*(Message.topic == topic for topic in not_topics))))
|
470
461
|
|
462
|
+
return query
|
463
|
+
|
464
|
+
@classmethod
|
465
|
+
def grep(
|
466
|
+
cls,
|
467
|
+
*,
|
468
|
+
page=1,
|
469
|
+
rows_per_page=100,
|
470
|
+
order="asc",
|
471
|
+
defer=False,
|
472
|
+
**kwargs,
|
473
|
+
):
|
474
|
+
"""Flexible query interface for messages.
|
475
|
+
|
476
|
+
Arguments are filters. start and end should be :mod:`datetime` objs.
|
477
|
+
|
478
|
+
Other filters should be lists of strings. They are applied in a
|
479
|
+
conjunctive-normal-form (CNF) kind of way
|
480
|
+
|
481
|
+
for example, the following::
|
482
|
+
|
483
|
+
users = ['ralph', 'lmacken']
|
484
|
+
categories = ['bodhi', 'wiki']
|
485
|
+
|
486
|
+
should return messages where
|
487
|
+
|
488
|
+
(user=='ralph' OR user=='lmacken') AND
|
489
|
+
(category=='bodhi' OR category=='wiki')
|
490
|
+
|
491
|
+
Furthermore, you can use a negative version of each argument.
|
492
|
+
|
493
|
+
users = ['ralph']
|
494
|
+
not_categories = ['bodhi', 'wiki']
|
495
|
+
|
496
|
+
should return messages where
|
497
|
+
|
498
|
+
(user == 'ralph') AND
|
499
|
+
NOT (category == 'bodhi' OR category == 'wiki')
|
500
|
+
|
501
|
+
----
|
502
|
+
|
503
|
+
The ``jsons`` argument is a list of jsonpath filters, please refer to
|
504
|
+
`PostgreSQL's documentation
|
505
|
+
<https://www.postgresql.org/docs/current/functions-json.html#FUNCTIONS-SQLJSON-PATH>`_
|
506
|
+
on the matter to learn how to build the jsonpath expression.
|
507
|
+
|
508
|
+
The ``jsons_and`` argument is similar to the ``jsons`` argument, but all
|
509
|
+
the values must match for a message to be returned.
|
510
|
+
"""
|
511
|
+
query = cls.make_query(**kwargs)
|
471
512
|
# Finally, tag on our pagination arguments
|
472
|
-
|
513
|
+
Message = cls
|
514
|
+
|
515
|
+
query_total = query.with_only_columns(func.count(Message.id))
|
516
|
+
total = None
|
473
517
|
query = query.order_by(getattr(Message.timestamp, order)())
|
474
518
|
|
475
519
|
if not rows_per_page:
|
476
520
|
pages = 1
|
477
521
|
else:
|
522
|
+
total = session.scalar(query_total)
|
478
523
|
pages = int(math.ceil(total / float(rows_per_page)))
|
479
524
|
query = query.offset(rows_per_page * (page - 1)).limit(rows_per_page)
|
480
525
|
|
481
526
|
if defer:
|
482
|
-
|
527
|
+
if total is None:
|
528
|
+
total = session.scalar(query_total)
|
529
|
+
return total, pages, query
|
483
530
|
else:
|
484
531
|
# Execute!
|
485
532
|
messages = session.scalars(query).all()
|
533
|
+
if pages == 1:
|
534
|
+
total = len(messages)
|
486
535
|
return total, pages, messages
|
487
536
|
|
537
|
+
@classmethod
|
538
|
+
def get_first(cls, *, order="asc", **kwargs):
|
539
|
+
"""Get the first message matching the regular grep filters."""
|
540
|
+
query = cls.make_query(**kwargs)
|
541
|
+
query = query.order_by(getattr(Message.timestamp, order)())
|
542
|
+
return session.scalars(query).first()
|
543
|
+
|
488
544
|
|
489
545
|
class NamedSingleton:
|
490
546
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
@@ -21,8 +21,8 @@ def datanommer_db_url(postgresql_proc):
|
|
21
21
|
)
|
22
22
|
|
23
23
|
|
24
|
-
@pytest.fixture()
|
25
|
-
def
|
24
|
+
@pytest.fixture(scope="session")
|
25
|
+
def datanommer_db_engine(postgresql_proc, datanommer_db_url):
|
26
26
|
with DatabaseJanitor(
|
27
27
|
user=postgresql_proc.user,
|
28
28
|
host=postgresql_proc.host,
|
@@ -32,12 +32,20 @@ def datanommer_db(postgresql_proc, datanommer_db_url):
|
|
32
32
|
# template_dbname=postgresql_proc.template_dbname,
|
33
33
|
version=postgresql_proc.version,
|
34
34
|
):
|
35
|
-
engine = sa.create_engine(datanommer_db_url, future=True
|
35
|
+
engine = sa.create_engine(datanommer_db_url, future=True)
|
36
36
|
# Renew the global object, dm.init checks a custom attribute
|
37
37
|
dm.session = scoped_session(dm.maker)
|
38
38
|
dm.init(engine=engine, create=True)
|
39
39
|
yield engine
|
40
|
-
|
40
|
+
engine.dispose()
|
41
|
+
|
42
|
+
|
43
|
+
@pytest.fixture()
|
44
|
+
def datanommer_db(datanommer_db_url, datanommer_db_engine):
|
45
|
+
for table in reversed(dm.DeclarativeBase.metadata.sorted_tables):
|
46
|
+
dm.session.execute(table.delete())
|
47
|
+
dm.session.commit()
|
48
|
+
yield datanommer_db_engine
|
41
49
|
|
42
50
|
|
43
51
|
@pytest.fixture()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "datanommer.models"
|
3
|
-
version = "1.
|
3
|
+
version = "1.3.0"
|
4
4
|
description = "SQLAlchemy models for datanommer"
|
5
5
|
authors = [
|
6
6
|
"Fedora Infrastructure <admin@fedoraproject.org>"
|
@@ -48,6 +48,7 @@ fmn-messages = {version = "*", optional = true}
|
|
48
48
|
kerneltest-messages = {version = "^1.0.0", optional = true}
|
49
49
|
koji-fedoramessaging-messages = {version = "^1.2.2", optional = true}
|
50
50
|
koschei-messages = {version = "*", optional = true}
|
51
|
+
maubot-fedora-messages = {version = "*", optional = true}
|
51
52
|
mediawiki-messages = {version = "*", optional = true}
|
52
53
|
meetbot-messages = {version = "*", optional = true}
|
53
54
|
mdapi-messages = {version = "*", optional = true}
|
@@ -86,6 +87,7 @@ schemas = [
|
|
86
87
|
"kerneltest-messages",
|
87
88
|
"koji-fedoramessaging-messages",
|
88
89
|
"koschei-messages",
|
90
|
+
"maubot-fedora-messages",
|
89
91
|
"mediawiki-messages",
|
90
92
|
"meetbot-messages",
|
91
93
|
"mdapi-messages",
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import pytest
|
2
2
|
from sqlalchemy import Column, create_engine, Integer, MetaData, select, Table, text
|
3
3
|
|
4
|
-
from datanommer.models import
|
4
|
+
from datanommer.models import _JSONEncodedDict
|
5
5
|
|
6
6
|
|
7
7
|
@pytest.fixture
|
@@ -18,7 +18,7 @@ def table(connection):
|
|
18
18
|
"test_table",
|
19
19
|
metadata,
|
20
20
|
Column("id", Integer, primary_key=True),
|
21
|
-
Column("data",
|
21
|
+
Column("data", _JSONEncodedDict),
|
22
22
|
)
|
23
23
|
metadata.create_all(connection)
|
24
24
|
yield table
|
@@ -62,6 +62,15 @@ def generate_bodhi_update_complete_message(text="testing testing"):
|
|
62
62
|
return msg
|
63
63
|
|
64
64
|
|
65
|
+
@pytest.fixture
|
66
|
+
def add_200_messages(datanommer_models):
|
67
|
+
for x in range(0, 200):
|
68
|
+
example_message = generate_message()
|
69
|
+
example_message.id = f"{x}"
|
70
|
+
dm.add(example_message)
|
71
|
+
dm.session.flush()
|
72
|
+
|
73
|
+
|
65
74
|
def test_init_uri_and_engine():
|
66
75
|
uri = "sqlite:///db.db"
|
67
76
|
engine = create_engine(uri, future=True)
|
@@ -131,9 +140,9 @@ def test_add_missing_timestamp(datanommer_models):
|
|
131
140
|
|
132
141
|
dbmsg = dm.session.scalar(select(dm.Message))
|
133
142
|
timediff = datetime.datetime.now() - dbmsg.timestamp
|
134
|
-
#
|
143
|
+
# 60 seconds between adding the message and checking
|
135
144
|
# the timestamp should be more than enough.
|
136
|
-
assert timediff < datetime.timedelta(seconds=
|
145
|
+
assert timediff < datetime.timedelta(seconds=60)
|
137
146
|
|
138
147
|
|
139
148
|
def test_add_timestamp_with_Z(datanommer_models):
|
@@ -419,39 +428,20 @@ def test_grep_contains(datanommer_models):
|
|
419
428
|
assert r[0].msg == example_message.body
|
420
429
|
|
421
430
|
|
422
|
-
def
|
423
|
-
for x in range(0, 200):
|
424
|
-
example_message = generate_message()
|
425
|
-
example_message.id = f"{x}"
|
426
|
-
dm.add(example_message)
|
427
|
-
|
428
|
-
dm.session.flush()
|
429
|
-
|
431
|
+
def test_grep_rows_per_page(datanommer_models, add_200_messages):
|
430
432
|
total, pages, messages = dm.Message.grep()
|
431
433
|
assert total == 200
|
432
434
|
assert pages == 2
|
433
435
|
assert len(messages) == 100
|
434
436
|
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
example_message = generate_message()
|
444
|
-
example_message.id = f"{x}"
|
445
|
-
dm.add(example_message)
|
446
|
-
dm.session.flush()
|
447
|
-
|
448
|
-
try:
|
449
|
-
total, pages, messages = dm.Message.grep(rows_per_page=0)
|
450
|
-
except ZeroDivisionError as e:
|
451
|
-
pytest.fail(e)
|
452
|
-
assert total == 200
|
453
|
-
assert pages == 1
|
454
|
-
assert len(messages) == 200
|
437
|
+
for rows_per_page in (None, 0):
|
438
|
+
try:
|
439
|
+
total, pages, messages = dm.Message.grep(rows_per_page=rows_per_page)
|
440
|
+
except ZeroDivisionError as e:
|
441
|
+
pytest.fail(e)
|
442
|
+
assert total == 200
|
443
|
+
assert pages == 1
|
444
|
+
assert len(messages) == 200
|
455
445
|
|
456
446
|
|
457
447
|
def test_grep_defer(datanommer_models):
|
@@ -466,6 +456,33 @@ def test_grep_defer(datanommer_models):
|
|
466
456
|
assert dm.session.scalars(query).all() == dm.Message.grep()[2]
|
467
457
|
|
468
458
|
|
459
|
+
def test_grep_no_paging_and_defer(datanommer_models, add_200_messages):
|
460
|
+
total, pages, messages = dm.Message.grep(rows_per_page=0, defer=True)
|
461
|
+
assert total == 200
|
462
|
+
assert pages == 1
|
463
|
+
|
464
|
+
|
465
|
+
def test_grep_no_total_if_single_page(datanommer_models, add_200_messages, mocker):
|
466
|
+
# Assert we don't query the total of messages if we're getting them all anyway
|
467
|
+
scalar_spy = mocker.spy(dm.session, "scalar")
|
468
|
+
total, pages, messages = dm.Message.grep(rows_per_page=0)
|
469
|
+
assert total == 200
|
470
|
+
scalar_spy.assert_not_called()
|
471
|
+
|
472
|
+
|
473
|
+
def test_get_first(datanommer_models):
|
474
|
+
messages = []
|
475
|
+
for x in range(0, 200):
|
476
|
+
example_message = generate_message()
|
477
|
+
example_message.id = f"{x}"
|
478
|
+
dm.add(example_message)
|
479
|
+
messages.append(example_message)
|
480
|
+
dm.session.flush()
|
481
|
+
msg = dm.Message.get_first()
|
482
|
+
assert msg.msg_id == "0"
|
483
|
+
assert msg.msg == messages[0].body
|
484
|
+
|
485
|
+
|
469
486
|
def test_add_duplicate(datanommer_models, caplog):
|
470
487
|
example_message = generate_message()
|
471
488
|
dm.add(example_message)
|
@@ -511,7 +528,10 @@ def test_add_duplicate_package(datanommer_models):
|
|
511
528
|
assert dbmsg.packages[0].name == "pkg"
|
512
529
|
|
513
530
|
|
514
|
-
|
531
|
+
@pytest.mark.parametrize(
|
532
|
+
"property_name,name_in_msg", [("usernames", "users"), ("packages", "packages")]
|
533
|
+
)
|
534
|
+
def test_add_message_with_error_on_property(datanommer_models, caplog, property_name, name_in_msg):
|
515
535
|
# Define a special message schema and register it
|
516
536
|
class CustomMessage(fedora_message.Message):
|
517
537
|
@property
|
@@ -521,6 +541,11 @@ def test_add_message_with_error_on_packages(datanommer_models, caplog):
|
|
521
541
|
def _filter_headers(self):
|
522
542
|
return {}
|
523
543
|
|
544
|
+
def _crash(self):
|
545
|
+
raise KeyError
|
546
|
+
|
547
|
+
setattr(CustomMessage, property_name, property(_crash))
|
548
|
+
|
524
549
|
fedora_message._schema_name_to_class["CustomMessage"] = CustomMessage
|
525
550
|
fedora_message._class_to_schema_name[CustomMessage] = "CustomMessage"
|
526
551
|
example_message = CustomMessage(
|
@@ -534,7 +559,7 @@ def test_add_message_with_error_on_packages(datanommer_models, caplog):
|
|
534
559
|
pytest.fail(e)
|
535
560
|
assert dm.session.scalar(select(func.count(dm.Message.id))) == 1
|
536
561
|
assert caplog.records[0].message == (
|
537
|
-
f"Could not get the list of
|
562
|
+
f"Could not get the list of {name_in_msg} from a message on "
|
538
563
|
f"org.fedoraproject.test.a.nice.message with id {example_message.id}"
|
539
564
|
)
|
540
565
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{datanommer_models-1.2.0 → datanommer_models-1.3.0}/datanommer/models/alembic/script.py.mako
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|