syncmodels 0.1.341__py2.py3-none-any.whl → 0.1.343__py2.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.
- syncmodels/__init__.py +1 -1
- syncmodels/crawler.py +35 -29
- syncmodels/helpers/crawler.py +2 -0
- syncmodels/session/__init__.py +6 -0
- syncmodels/session/sql.py +16 -2
- syncmodels/storage.py +52 -21
- {syncmodels-0.1.341.dist-info → syncmodels-0.1.343.dist-info}/METADATA +2 -2
- {syncmodels-0.1.341.dist-info → syncmodels-0.1.343.dist-info}/RECORD +13 -13
- {syncmodels-0.1.341.dist-info → syncmodels-0.1.343.dist-info}/AUTHORS.rst +0 -0
- {syncmodels-0.1.341.dist-info → syncmodels-0.1.343.dist-info}/LICENSE +0 -0
- {syncmodels-0.1.341.dist-info → syncmodels-0.1.343.dist-info}/WHEEL +0 -0
- {syncmodels-0.1.341.dist-info → syncmodels-0.1.343.dist-info}/entry_points.txt +0 -0
- {syncmodels-0.1.341.dist-info → syncmodels-0.1.343.dist-info}/top_level.txt +0 -0
syncmodels/__init__.py
CHANGED
syncmodels/crawler.py
CHANGED
@@ -1578,6 +1578,11 @@ class SortPlugin(iPlugin):
|
|
1578
1578
|
or self.bot.context.get(SORT_KEY)
|
1579
1579
|
or getattr(self.bot, "SORT_KEY", None)
|
1580
1580
|
)
|
1581
|
+
if isinstance(sort_key, str):
|
1582
|
+
sort_key = (sort_key,)
|
1583
|
+
elif isinstance(sort_key, list):
|
1584
|
+
sort_key = tuple(sort_key)
|
1585
|
+
|
1581
1586
|
if sort_key:
|
1582
1587
|
context[SORT_KEY] = sort_key
|
1583
1588
|
|
@@ -1588,36 +1593,37 @@ class SortPlugin(iPlugin):
|
|
1588
1593
|
# figure out the sort_key
|
1589
1594
|
sort_key = SortKeyFinder.find_sort_key(stream)
|
1590
1595
|
|
1591
|
-
|
1592
|
-
|
1593
|
-
|
1594
|
-
|
1595
|
-
mapper = self.bot.parent.MAPPERS.get(kind)
|
1596
|
-
if not mapper:
|
1597
|
-
log.error("cant find mapper [%s] in crawler??", kind)
|
1598
|
-
return
|
1596
|
+
kind = context.get(KIND_KEY) # must exixts
|
1597
|
+
if not kind:
|
1598
|
+
log.error("cant find KIND_KEY in context??")
|
1599
|
+
return
|
1599
1600
|
|
1600
|
-
|
1601
|
-
|
1602
|
-
|
1603
|
-
|
1604
|
-
# set(
|
1605
|
-
# [
|
1606
|
-
# "datetime",
|
1607
|
-
# ]
|
1608
|
-
# ).intersection(item_fields)
|
1609
|
-
# )
|
1610
|
-
reverse = list(set(sort_key).intersection(item_fields))
|
1611
|
-
if not reverse:
|
1612
|
-
log.debug(
|
1613
|
-
"model [%s] attributes:[%s] doesn't match any datetime alike sort keys: [%s]",
|
1614
|
-
model,
|
1615
|
-
list(item_fields),
|
1616
|
-
sort_key,
|
1617
|
-
)
|
1618
|
-
# return
|
1601
|
+
mapper = self.bot.parent.MAPPERS.get(kind)
|
1602
|
+
if not mapper:
|
1603
|
+
log.error("cant find mapper [%s] in crawler??", kind)
|
1604
|
+
return
|
1619
1605
|
|
1620
|
-
|
1606
|
+
model = mapper.PYDANTIC
|
1607
|
+
item_fields = model.model_fields
|
1608
|
+
# datetime
|
1609
|
+
# reverse = list(
|
1610
|
+
# set(
|
1611
|
+
# [
|
1612
|
+
# "datetime",
|
1613
|
+
# ]
|
1614
|
+
# ).intersection(item_fields)
|
1615
|
+
# )
|
1616
|
+
reverse = list(set(sort_key).intersection(item_fields))
|
1617
|
+
if not reverse:
|
1618
|
+
log.debug(
|
1619
|
+
"model [%s] attributes:[%s] doesn't match any datetime alike sort keys: [%s]",
|
1620
|
+
model,
|
1621
|
+
list(item_fields),
|
1622
|
+
sort_key,
|
1623
|
+
)
|
1624
|
+
# return
|
1625
|
+
|
1626
|
+
context[REVERSE_SORT_KEY] = reverse
|
1621
1627
|
|
1622
1628
|
if sort_key:
|
1623
1629
|
context[SORT_KEY] = sort_key
|
@@ -1947,7 +1953,7 @@ class MetaExtractPlugin(iPlugin):
|
|
1947
1953
|
# MAP = self.bot.parent.MAPPERS
|
1948
1954
|
geojson = data.get(GEOJSON_KEY) # TODO: fix, coords are tuples!
|
1949
1955
|
if geojson is None:
|
1950
|
-
log.
|
1956
|
+
log.debug("no geojson info: [%s]", data)
|
1951
1957
|
continue
|
1952
1958
|
kind = geojson["type"]
|
1953
1959
|
# TODO: use (slower) more general jinja render?
|
syncmodels/helpers/crawler.py
CHANGED
syncmodels/session/__init__.py
CHANGED
@@ -32,6 +32,7 @@ from syncmodels.definitions import (
|
|
32
32
|
# MONOTONIC_SINCE,
|
33
33
|
MONOTONIC_SINCE_KEY,
|
34
34
|
MONOTONIC_SINCE_VALUE,
|
35
|
+
SORT_KEY,
|
35
36
|
URI,
|
36
37
|
DURI,
|
37
38
|
WAVE_LAST_KEY,
|
@@ -410,6 +411,11 @@ class iSession(iContext, iSchema, iRegistry): # , iAuthenticator):
|
|
410
411
|
break
|
411
412
|
break
|
412
413
|
|
414
|
+
if not params.get(MONOTONIC_SINCE_KEY):
|
415
|
+
if since_key := params.get(SORT_KEY):
|
416
|
+
# if the 1st time that crawler want to retrieve data
|
417
|
+
params[MONOTONIC_SINCE_KEY] = since_key
|
418
|
+
|
413
419
|
call_kw = {
|
414
420
|
"url": url,
|
415
421
|
"headers": self.headers,
|
syncmodels/session/sql.py
CHANGED
@@ -3,6 +3,9 @@ import re
|
|
3
3
|
from itertools import chain
|
4
4
|
|
5
5
|
from agptools.helpers import parse_uri, build_uri, tf
|
6
|
+
from agptools.containers import overlap
|
7
|
+
from syncmodels.http import CONTENT_TYPE, APPLICATION_PYTHON
|
8
|
+
|
6
9
|
from syncmodels.definitions import (
|
7
10
|
KIND_KEY,
|
8
11
|
TABLE_KEY,
|
@@ -13,6 +16,7 @@ from syncmodels.definitions import (
|
|
13
16
|
JSON,
|
14
17
|
LIMIT_KEY_VALUE,
|
15
18
|
)
|
19
|
+
from syncmodels.storage import is_sort_key_id
|
16
20
|
|
17
21
|
from ..crud import DEFAULT_NAMESPACE, parse_duri
|
18
22
|
from ..schema import StructShema
|
@@ -115,7 +119,11 @@ class iSQLSession(iSession):
|
|
115
119
|
|
116
120
|
query = f"SELECT * FROM {table}"
|
117
121
|
if MONOTONIC_SINCE_VALUE in params:
|
118
|
-
|
122
|
+
if is_sort_key_id(since_key):
|
123
|
+
query += f" WHERE {since_key} > :{MONOTONIC_SINCE_VALUE}"
|
124
|
+
else:
|
125
|
+
query += f" WHERE {since_key} >= :{MONOTONIC_SINCE_VALUE}"
|
126
|
+
|
119
127
|
if since_key:
|
120
128
|
query += f" ORDER BY {since_key}"
|
121
129
|
# limit = 128 # TODO: agp: REMOVE
|
@@ -164,7 +172,7 @@ class iSQLSession(iSession):
|
|
164
172
|
|
165
173
|
async def get(self, url, headers=None, params=None, **kw):
|
166
174
|
headers = headers or {}
|
167
|
-
params = params or
|
175
|
+
params = params or kw["json"]["params"] # TODO: check with centesimal
|
168
176
|
|
169
177
|
_uri = parse_uri(url)
|
170
178
|
_uri["query_"].update(params)
|
@@ -190,6 +198,12 @@ class iSQLSession(iSession):
|
|
190
198
|
# {schema.names[i]: v for i, v in enumerate(row)} for row in data
|
191
199
|
# ]
|
192
200
|
|
201
|
+
overlap(
|
202
|
+
headers,
|
203
|
+
{
|
204
|
+
CONTENT_TYPE: APPLICATION_PYTHON,
|
205
|
+
},
|
206
|
+
)
|
193
207
|
response = iResponse(
|
194
208
|
status=200, headers=headers, links=None, real_url=url, body=body
|
195
209
|
)
|
syncmodels/storage.py
CHANGED
@@ -137,6 +137,12 @@ UTC_TZ = pytz.timezone("UTC")
|
|
137
137
|
# REGEXP_FQUI = re.compile(r"((?P<ns>[^/]*?)/)?(?P<table>[^:]+):(?P<uid>.*)$")
|
138
138
|
|
139
139
|
|
140
|
+
def is_sort_key_id(sort_keys):
|
141
|
+
if isinstance(sort_keys, str):
|
142
|
+
return re.search(REGEXP_RECORD_ID, sort_keys)
|
143
|
+
return any([re.search(REGEXP_RECORD_ID, _) for _ in sort_keys])
|
144
|
+
|
145
|
+
|
140
146
|
def comparable_struct(data, patterns):
|
141
147
|
wdata = Walk(data)
|
142
148
|
|
@@ -150,8 +156,15 @@ def split_fqui(fqid):
|
|
150
156
|
return fqid, None
|
151
157
|
|
152
158
|
|
159
|
+
REGEXP_RECORD_ID = r"(\W*|_)id$"
|
160
|
+
|
161
|
+
|
153
162
|
def normalize_payload(data, keys):
|
154
163
|
for key in set(keys or []).intersection(data):
|
164
|
+
# skip record_id and similar keys
|
165
|
+
if re.search(REGEXP_RECORD_ID, key):
|
166
|
+
continue
|
167
|
+
|
155
168
|
value = DATE(data[key])
|
156
169
|
if isinstance(value, datetime):
|
157
170
|
if not value.tzinfo:
|
@@ -908,27 +921,45 @@ class WaveStorage(iWaves, iStorage):
|
|
908
921
|
nonlocal uid
|
909
922
|
nonlocal monotonic
|
910
923
|
nonlocal data_sort_blueprint
|
911
|
-
for monotonic_key in set(sort_keys).intersection(data):
|
912
|
-
monotonic_value = DATE(data[monotonic_key])
|
913
|
-
|
914
|
-
# seconds
|
915
|
-
grace_period = kw.get(GRACE_PERIOD_KEY, DEFAULT_GRACE_PERIOD)
|
916
|
-
grace_period = timedelta(seconds=grace_period)
|
917
|
-
since_value = monotonic_value - grace_period
|
918
|
-
# pass to UTC time
|
919
|
-
if not since_value.tzinfo:
|
920
|
-
# x = x.replace(tzinfo=timezone.utc)
|
921
|
-
# x = x.replace(tzinfo=LOCAL_TZ)
|
922
|
-
since_value = pytz.utc.localize(since_value)
|
923
|
-
since_value = since_value.astimezone(UTC_TZ)
|
924
|
-
since_value = since_value.strftime("%Y-%m-%dT%H:%M:%SZ")
|
925
924
|
|
926
|
-
|
925
|
+
# using record_id alike sort_key?
|
926
|
+
if is_sort_key_id(sort_keys):
|
927
|
+
for monotonic_key in set(sort_keys).intersection(data):
|
928
|
+
monotonic_value = data[monotonic_key]
|
929
|
+
break
|
930
|
+
else:
|
931
|
+
log.error("can't find %s key in %s", monotonic_key, data)
|
932
|
+
# in this case, no grace_period is needed
|
933
|
+
since_value = monotonic_value
|
934
|
+
monotonic_operator = ">"
|
927
935
|
else:
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
936
|
+
# using datetime alike sort_key
|
937
|
+
monotonic_operator = ">="
|
938
|
+
for monotonic_key in set(sort_keys).intersection(data):
|
939
|
+
monotonic_value = DATE(data[monotonic_key])
|
940
|
+
|
941
|
+
# seconds
|
942
|
+
grace_period = kw.get(
|
943
|
+
GRACE_PERIOD_KEY, DEFAULT_GRACE_PERIOD
|
944
|
+
)
|
945
|
+
grace_period = timedelta(seconds=grace_period)
|
946
|
+
since_value = monotonic_value - grace_period
|
947
|
+
# pass to UTC time
|
948
|
+
if not since_value.tzinfo:
|
949
|
+
# x = x.replace(tzinfo=timezone.utc)
|
950
|
+
# x = x.replace(tzinfo=LOCAL_TZ)
|
951
|
+
since_value = pytz.utc.localize(since_value)
|
952
|
+
since_value = since_value.astimezone(UTC_TZ)
|
953
|
+
since_value = since_value.strftime("%Y-%m-%dT%H:%M:%SZ")
|
954
|
+
|
955
|
+
break
|
956
|
+
else:
|
957
|
+
monotonic_key = MONOTONIC_KEY # ??
|
958
|
+
grace_period = kw.get(
|
959
|
+
GRACE_PERIOD_KEY, DEFAULT_GRACE_PERIOD
|
960
|
+
)
|
961
|
+
grace_period *= 10**9 # nanoseconds
|
962
|
+
since_value = monotonic - grace_period
|
932
963
|
|
933
964
|
query = f"{namespace}://{database}/{thing}"
|
934
965
|
|
@@ -937,7 +968,7 @@ class WaveStorage(iWaves, iStorage):
|
|
937
968
|
data_sort_bp = {
|
938
969
|
MONOTONIC_SINCE_KEY: monotonic_key,
|
939
970
|
MONOTONIC_SINCE_VALUE: since_value,
|
940
|
-
MONOTONIC_SINCE_OPERATOR:
|
971
|
+
MONOTONIC_SINCE_OPERATOR: monotonic_operator,
|
941
972
|
ORDER_KEY: monotonic_key,
|
942
973
|
DIRECTION_KEY: DIRECTION_DESC,
|
943
974
|
# LIMIT_KEY: kw.get(
|
@@ -1186,7 +1217,7 @@ class WaveStorage(iWaves, iStorage):
|
|
1186
1217
|
if must_check:
|
1187
1218
|
t0 = time.time()
|
1188
1219
|
await prevously_inserted()
|
1189
|
-
if False or random.random() < 0.
|
1220
|
+
if False or random.random() < 0.05:
|
1190
1221
|
elapsed = time.time() - t0
|
1191
1222
|
log.info("[%s] prevously_inserted took: %s secs", uid, elapsed)
|
1192
1223
|
if elapsed > 1.0:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: syncmodels
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.343
|
4
4
|
Summary: Synchronizable Models
|
5
5
|
Home-page: https://github.com/asterio.gonzalez/syncmodels
|
6
6
|
Author: Asterio Gonzalez
|
@@ -18,7 +18,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
18
18
|
Requires-Python: >=3.6
|
19
19
|
License-File: LICENSE
|
20
20
|
License-File: AUTHORS.rst
|
21
|
-
Requires-Dist: agptools>=0.1.
|
21
|
+
Requires-Dist: agptools>=0.1.343
|
22
22
|
Requires-Dist: aiocache
|
23
23
|
Requires-Dist: aiohttp
|
24
24
|
Requires-Dist: Click
|
@@ -1,6 +1,6 @@
|
|
1
|
-
syncmodels/__init__.py,sha256=
|
1
|
+
syncmodels/__init__.py,sha256=Mpde6Eca9MTKd_YLLbuJt4XCAjhQkFJWIMHIgyNtej0,142
|
2
2
|
syncmodels/context.py,sha256=k1Gs_ip9BfyRFpyRnzqYvRDKo0sYBqJsh6z9sWln9oE,451
|
3
|
-
syncmodels/crawler.py,sha256=
|
3
|
+
syncmodels/crawler.py,sha256=lx0IU586JD0qcdozWiv0y7970CkUEg3SzFB6gOYDS6I,94540
|
4
4
|
syncmodels/crud.py,sha256=oZIcwEKR2i-lesEF_059Y4yThohd9m7gs6R6xYgLH-I,15351
|
5
5
|
syncmodels/definitions.py,sha256=w-3TrSomp9T8OzLmJhKeZQDzrUIJLKldyh1lzlE7Yj0,5476
|
6
6
|
syncmodels/exceptions.py,sha256=ZLAwu19cs2UN2Sv3jaLnixT_jRI7T42TfyutCkUsuIk,685
|
@@ -11,7 +11,7 @@ syncmodels/registry.py,sha256=YaQtgbSwa0je1MpCcVHALI3_b85vrddyOlhsnrUcKZs,8224
|
|
11
11
|
syncmodels/requests.py,sha256=wWoC5hPDm1iBM_zrlyKRauzhXgdKR3pT5RqyC-5UZhQ,538
|
12
12
|
syncmodels/runner.py,sha256=IHDKuQ3yJ1DN9wktMiIrerPepYX61tc3AzbFfuUqEFw,5454
|
13
13
|
syncmodels/schema.py,sha256=uinUt8Asq_x7xa6MKWVXNyoWO6gKocjGPppjimaXzEU,2492
|
14
|
-
syncmodels/storage.py,sha256=
|
14
|
+
syncmodels/storage.py,sha256=GLEDryiBkgN9SgtvcqBRxP_22T00gGkIbiZqM6AqKDI,76158
|
15
15
|
syncmodels/syncmodels.py,sha256=jcUxVbv1hrx5hI81VCO1onIM6WyORTqJVPwIqlPocOc,10596
|
16
16
|
syncmodels/timequeue.py,sha256=YRd3ULRaIhoszaBsYhfr0epMqAbL6-NwVEtScjUYttM,595
|
17
17
|
syncmodels/wave.py,sha256=Gra22BLiA9z2nF-6diXpjAc4GZv9nebmyvHxdAfXec4,7764
|
@@ -24,7 +24,7 @@ syncmodels/cli/surreal.py,sha256=eL7pDicLo0_68JhpCZacde6DOVcfHE_UEzczvgDuvAc,106
|
|
24
24
|
syncmodels/cli/wingdbstub.py,sha256=q4z-RqHN1ttzNtiLYTzqQG2ZYZ6W3NOnEd2E5NGhfao,17165
|
25
25
|
syncmodels/cli/workspace.py,sha256=wajZnxf567nYoQysTEgxrDAp8ZBU8zSuoP4KyZtqvdc,2461
|
26
26
|
syncmodels/helpers/__init__.py,sha256=qZet64gMJNAAqzUdEqCV5WDk5D2Dbw1Kxlt9Jo6x3m4,23
|
27
|
-
syncmodels/helpers/crawler.py,sha256=
|
27
|
+
syncmodels/helpers/crawler.py,sha256=ptqj4g96nQfQIvdp18HRDovnWfB0RJXtTBzHQsNPrM8,4844
|
28
28
|
syncmodels/helpers/explorer.py,sha256=-Dol3z1pALCMI9OPSvVbROaTzLjbUpS0suJ82Z6Rmb4,7447
|
29
29
|
syncmodels/helpers/faker.py,sha256=tPtibNh28KoHb9kcwE9WaPdPrSrN6xMbCv5HhNFEVG0,1222
|
30
30
|
syncmodels/helpers/general.py,sha256=UAcSfrvsaT15iJuxsR3WMk51UjpLLGDf14xmpBojndg,6160
|
@@ -297,16 +297,16 @@ syncmodels/model/schema_org/webpage.py,sha256=-bqKOpEs_2lW7qrey2nHtvOZ9xbmmwcviN
|
|
297
297
|
syncmodels/model/schema_org/webpageelement.py,sha256=brXfhU3l3FBXpy8qnR1Ve-EckjHW8VGoyR2IsnT7t2Y,1104
|
298
298
|
syncmodels/model/schema_org/website.py,sha256=48Rox27BbFIg1u3wDlOtX-lLCPoFgvvrCw5Hrdf6uRU,912
|
299
299
|
syncmodels/model/schema_org/xpathtype.py,sha256=D8gKiCrGSSuUVYw7BIWmOIUbKATfv2IpbkV1B2TmjC0,484
|
300
|
-
syncmodels/session/__init__.py,sha256=
|
300
|
+
syncmodels/session/__init__.py,sha256=xjgmogPs-Nu5merFY-foJVT9X-qDbLk_fYbe9uGx6sY,16003
|
301
301
|
syncmodels/session/http.py,sha256=tf7z0ccAEYoCOZT4Ukv3NBXz9hUO3vs2s9bm491pCj8,1480
|
302
302
|
syncmodels/session/postgresql.py,sha256=ZMIu1Rv93pKfvFlovFBmWArzlrT2xaQWNYGZT_LW61k,175
|
303
|
-
syncmodels/session/sql.py,sha256=
|
303
|
+
syncmodels/session/sql.py,sha256=auZ_3RZTSWViED4UrExYaes42Y2bTZKixEsfOpa_zaU,7036
|
304
304
|
syncmodels/session/sqlite.py,sha256=nCDjopLiBpX1F10qkKoARM7JrVdIpJ1WdGOduFVxaiA,2080
|
305
305
|
syncmodels/source/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
306
|
-
syncmodels-0.1.
|
307
|
-
syncmodels-0.1.
|
308
|
-
syncmodels-0.1.
|
309
|
-
syncmodels-0.1.
|
310
|
-
syncmodels-0.1.
|
311
|
-
syncmodels-0.1.
|
312
|
-
syncmodels-0.1.
|
306
|
+
syncmodels-0.1.343.dist-info/AUTHORS.rst,sha256=3ZPoqg8Aav8DSYKd0fwcwn4_5HwSiMLart0E5Un00-U,168
|
307
|
+
syncmodels-0.1.343.dist-info/LICENSE,sha256=uzMOYtIiUsnsD0xHJR7aJWJ4v_bvan0kTnvufy5eNoA,1075
|
308
|
+
syncmodels-0.1.343.dist-info/METADATA,sha256=sXMUvCabKs5rQ2jAfNc1Vgp6XBoQbcpPCXhRq4rQ9a8,2700
|
309
|
+
syncmodels-0.1.343.dist-info/WHEEL,sha256=SrDKpSbFN1G94qcmBqS9nyHcDMp9cUS9OC06hC0G3G0,109
|
310
|
+
syncmodels-0.1.343.dist-info/entry_points.txt,sha256=dMnigjZsHMxTwXiiZyBZdBbMYE0-hY3L5cG15EcDAzw,51
|
311
|
+
syncmodels-0.1.343.dist-info/top_level.txt,sha256=2DfQ9NuAhKMjY3BvQGVBA7GfqTm7EoHNbaehSUiqiHQ,11
|
312
|
+
syncmodels-0.1.343.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|