syncmodels 0.1.312__py2.py3-none-any.whl → 0.1.313__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 +24 -11
- syncmodels/helpers/orion.py +2 -1
- syncmodels/model/__init__.py +1 -0
- syncmodels/model/model.py +1 -1
- syncmodels/runner.py +5 -0
- syncmodels/storage.py +52 -23
- {syncmodels-0.1.312.dist-info → syncmodels-0.1.313.dist-info}/METADATA +2 -2
- {syncmodels-0.1.312.dist-info → syncmodels-0.1.313.dist-info}/RECORD +14 -14
- {syncmodels-0.1.312.dist-info → syncmodels-0.1.313.dist-info}/AUTHORS.rst +0 -0
- {syncmodels-0.1.312.dist-info → syncmodels-0.1.313.dist-info}/LICENSE +0 -0
- {syncmodels-0.1.312.dist-info → syncmodels-0.1.313.dist-info}/WHEEL +0 -0
- {syncmodels-0.1.312.dist-info → syncmodels-0.1.313.dist-info}/entry_points.txt +0 -0
- {syncmodels-0.1.312.dist-info → syncmodels-0.1.313.dist-info}/top_level.txt +0 -0
syncmodels/__init__.py
CHANGED
syncmodels/crawler.py
CHANGED
@@ -217,7 +217,7 @@ class iAgent(iRunner):
|
|
217
217
|
include=None,
|
218
218
|
exclude=None,
|
219
219
|
credentials=None,
|
220
|
-
prefix=
|
220
|
+
prefix="",
|
221
221
|
*args,
|
222
222
|
**kw,
|
223
223
|
):
|
@@ -235,9 +235,8 @@ class iAgent(iRunner):
|
|
235
235
|
}
|
236
236
|
|
237
237
|
# prefix template
|
238
|
-
|
239
|
-
|
240
|
-
self.prefix = prefix
|
238
|
+
self.prefix_template = self._compile_template(prefix)
|
239
|
+
self.prefix = prefix
|
241
240
|
|
242
241
|
# config file
|
243
242
|
if not config_path:
|
@@ -268,6 +267,11 @@ class iAgent(iRunner):
|
|
268
267
|
|
269
268
|
return template
|
270
269
|
|
270
|
+
async def start(self):
|
271
|
+
"start runner"
|
272
|
+
await super().start()
|
273
|
+
await self._bootstrap()
|
274
|
+
|
271
275
|
async def _bootstrap(self):
|
272
276
|
"Add the initial tasks to be executed by agent"
|
273
277
|
log.debug(">> [%s] entering bootstrap()", self.name)
|
@@ -403,7 +407,7 @@ class iAgent(iRunner):
|
|
403
407
|
log.debug("+ Task: [%s]: [%s] %s", i, self.name, task)
|
404
408
|
|
405
409
|
# TODO: agp: generalize and provide a better way to save activity records
|
406
|
-
if activity_logger := getattr(self, "activity_logger"):
|
410
|
+
if activity_logger := getattr(self, "activity_logger", None):
|
407
411
|
if activity := task.get(ACTIVITY_LOG_KEY):
|
408
412
|
activity.status = "pending"
|
409
413
|
await activity_logger.update_activity(activity)
|
@@ -1635,6 +1639,21 @@ class SortPlugin(iPlugin):
|
|
1635
1639
|
kind = context.get(KIND_KEY)
|
1636
1640
|
SortKeyFinder.register(kind, sort_key)
|
1637
1641
|
|
1642
|
+
mapper = self.bot.parent.MAPPERS.get(kind)
|
1643
|
+
if not mapper:
|
1644
|
+
log.error("cant find mapper [%s] in crawler??", kind)
|
1645
|
+
return
|
1646
|
+
|
1647
|
+
# TODO: unify this code (exists sort_key or not exists)
|
1648
|
+
model = mapper.PYDANTIC
|
1649
|
+
item_fields = model.model_fields
|
1650
|
+
reverse = list(set(sort_key).intersection(item_fields))
|
1651
|
+
if not reverse:
|
1652
|
+
log.error("model [%s] has not datetime alike key??", model)
|
1653
|
+
return
|
1654
|
+
|
1655
|
+
context[REVERSE_SORT_KEY] = reverse
|
1656
|
+
|
1638
1657
|
def order(data, accessor):
|
1639
1658
|
result = data
|
1640
1659
|
for key in accessor:
|
@@ -1642,7 +1661,6 @@ class SortPlugin(iPlugin):
|
|
1642
1661
|
result = result[key]
|
1643
1662
|
except Exception as why:
|
1644
1663
|
pass
|
1645
|
-
|
1646
1664
|
return result
|
1647
1665
|
|
1648
1666
|
stream.sort(key=partial(order, accessor=sort_key))
|
@@ -2521,11 +2539,6 @@ class iAsyncCrawler(iCrawler):
|
|
2521
2539
|
# TODO: REVIEW: always is a single value (len==1), why not return waves[0]
|
2522
2540
|
return waves
|
2523
2541
|
|
2524
|
-
async def start(self):
|
2525
|
-
"start runner"
|
2526
|
-
await super().start()
|
2527
|
-
await self._bootstrap()
|
2528
|
-
|
2529
2542
|
async def idle(self):
|
2530
2543
|
"default implementation when loop has nothing to do"
|
2531
2544
|
# check running bots
|
syncmodels/helpers/orion.py
CHANGED
@@ -117,7 +117,7 @@ class OrionInjector:
|
|
117
117
|
"put",
|
118
118
|
self.target_url
|
119
119
|
# + "/v2/entities/{id}/attrs?options=append,keyValues",
|
120
|
-
+ "/v2/entities/{id}/attrs",
|
120
|
+
+ "/v2/entities/{id}/attrs?type={type}",
|
121
121
|
self.FULL_EXCLUDE,
|
122
122
|
],
|
123
123
|
),
|
@@ -137,6 +137,7 @@ class OrionInjector:
|
|
137
137
|
self.target_url
|
138
138
|
# + "/v2/entities/{id}/attrs?options=append,keyValues",
|
139
139
|
+ "/v2/entities/{id}",
|
140
|
+
# + "/v2/entities/{id}?type={type}", # TODO: avoid posibly 409 if id is used in other fs_pathservice
|
140
141
|
# self.EXCLUDE_ALL,
|
141
142
|
self.FULL_EXCLUDE,
|
142
143
|
],
|
syncmodels/model/__init__.py
CHANGED
syncmodels/model/model.py
CHANGED
@@ -23,7 +23,7 @@ from typing_extensions import Annotated
|
|
23
23
|
from pydantic import BaseModel as _BaseModel
|
24
24
|
from pydantic import Field
|
25
25
|
from pydantic import PlainSerializer, BeforeValidator
|
26
|
-
from pydantic.functional_validators import field_validator
|
26
|
+
from pydantic.functional_validators import field_validator, model_validator
|
27
27
|
|
28
28
|
# from pydantic.dataclasses import dataclass
|
29
29
|
|
syncmodels/runner.py
CHANGED
@@ -62,7 +62,9 @@ class iRunner:
|
|
62
62
|
self.t0 = 0
|
63
63
|
self.t1 = 0
|
64
64
|
self.nice = 600
|
65
|
+
self.clock = 0
|
65
66
|
|
67
|
+
self.hooks = []
|
66
68
|
self.stop_when_empty = stop_when_empty
|
67
69
|
|
68
70
|
self._wip = []
|
@@ -160,6 +162,9 @@ class iRunner:
|
|
160
162
|
if not func:
|
161
163
|
func = getattr(self, task[FUNC_KEY]) # let fail with AttributeError
|
162
164
|
await func(**task)
|
165
|
+
self.clock += 1
|
166
|
+
for hook in self.hooks:
|
167
|
+
await hook(**task)
|
163
168
|
|
164
169
|
async def idle(self):
|
165
170
|
"default implementation when loop has nothing to do"
|
syncmodels/storage.py
CHANGED
@@ -9,7 +9,7 @@ import time
|
|
9
9
|
import sys
|
10
10
|
import traceback
|
11
11
|
from typing import List
|
12
|
-
from datetime import timedelta
|
12
|
+
from datetime import timedelta, datetime
|
13
13
|
import pytz
|
14
14
|
from multiprocessing import Process
|
15
15
|
import random
|
@@ -129,6 +129,20 @@ def split_fqui(fqid):
|
|
129
129
|
return fqid, None
|
130
130
|
|
131
131
|
|
132
|
+
def normalize_payload(data, keys):
|
133
|
+
for key in set(keys).intersection(data):
|
134
|
+
value = DATE(data[key])
|
135
|
+
if isinstance(value, datetime):
|
136
|
+
if not value.tzinfo:
|
137
|
+
value = pytz.utc.localize(value)
|
138
|
+
value = value.astimezone(UTC_TZ)
|
139
|
+
value = value.strftime("%Y-%m-%dT%H:%M:%SZ")
|
140
|
+
|
141
|
+
data[key] = value
|
142
|
+
|
143
|
+
return data
|
144
|
+
|
145
|
+
|
132
146
|
# ---------------------------------------------------------
|
133
147
|
# Data Store / Ignore Policies
|
134
148
|
# ---------------------------------------------------------
|
@@ -853,6 +867,9 @@ class WaveStorage(iWaves, iStorage):
|
|
853
867
|
# now
|
854
868
|
# ['2005-06-01T00:00:00.000+02:00']
|
855
869
|
# [datetime.datetime(2005, 6, 1, 0, 0, tzinfo=tzoffset(None, 7200))]
|
870
|
+
|
871
|
+
normalize_payload(data, sort_keys)
|
872
|
+
|
856
873
|
monotonic = data.setdefault(MONOTONIC_KEY, monotonic_wave())
|
857
874
|
for monotonic_key in set(sort_keys or []).intersection(data):
|
858
875
|
monotonic_value = DATE(data[monotonic_key])
|
@@ -878,8 +895,8 @@ class WaveStorage(iWaves, iStorage):
|
|
878
895
|
|
879
896
|
query = f"{namespace}://{database}/{thing}"
|
880
897
|
|
881
|
-
|
882
|
-
data_sort_blueprint =
|
898
|
+
data_sort_blueprint = build_dict(data, sort_keys)
|
899
|
+
# data_sort_blueprint = build_comparisson_dict(data, reverse_sort_keys)
|
883
900
|
blueprint = {
|
884
901
|
MONOTONIC_SINCE_KEY: monotonic_key,
|
885
902
|
MONOTONIC_SINCE_VALUE: since_value,
|
@@ -890,7 +907,7 @@ class WaveStorage(iWaves, iStorage):
|
|
890
907
|
LIMIT_KEY, 50 # TODO: agp: set in definition?
|
891
908
|
), # TODO: this is temporal, ideally None
|
892
909
|
ORG_KEY: uid,
|
893
|
-
**data_sort_blueprint, # implies sv = True
|
910
|
+
# **data_sort_blueprint, # implies sv = True
|
894
911
|
}
|
895
912
|
# TODO: LIMIT 1 ?
|
896
913
|
|
@@ -921,15 +938,38 @@ class WaveStorage(iWaves, iStorage):
|
|
921
938
|
|
922
939
|
self.behavior_uri[query] = behavior
|
923
940
|
|
924
|
-
t0 = time.time()
|
925
|
-
|
941
|
+
# t0 = time.time()
|
942
|
+
|
943
|
+
# search the same data
|
944
|
+
# TODO: update blueprint
|
945
|
+
blueprint = {
|
946
|
+
# MONOTONIC_SINCE_KEY: monotonic_key,
|
947
|
+
# MONOTONIC_SINCE_VALUE: since_value,
|
948
|
+
# MONOTONIC_SINCE_OPERATOR: ">=",
|
949
|
+
# ORDER_KEY: monotonic_key,
|
950
|
+
# DIRECTION_KEY: DIRECTION_DESC,
|
951
|
+
LIMIT_KEY: kw.get(
|
952
|
+
LIMIT_KEY, 50 # TODO: agp: set in definition?
|
953
|
+
), # TODO: this is temporal, ideally None
|
954
|
+
ORG_KEY: uid,
|
955
|
+
**data_sort_blueprint, # implies sv = True
|
956
|
+
}
|
957
|
+
identical = await self.storage.query(
|
926
958
|
query,
|
927
959
|
**blueprint,
|
928
960
|
# **data_sort_bp,
|
929
961
|
)
|
930
|
-
|
931
|
-
|
932
|
-
|
962
|
+
# TODO: try to create only a single query
|
963
|
+
# TODO: review different structures case
|
964
|
+
similar = await self.storage.query(
|
965
|
+
query,
|
966
|
+
**blueprint,
|
967
|
+
# **data_sort_bp,
|
968
|
+
)
|
969
|
+
# t1 = time.time()
|
970
|
+
# _elapsed = t1 - t0
|
971
|
+
existing = identical + similar
|
972
|
+
N2 = len(existing)
|
933
973
|
if data_sort_blueprint and N2 > 1:
|
934
974
|
if behavior & ALLOW_DUPLICATED_ITEMS:
|
935
975
|
log.debug(
|
@@ -937,7 +977,7 @@ class WaveStorage(iWaves, iStorage):
|
|
937
977
|
uid,
|
938
978
|
N2,
|
939
979
|
)
|
940
|
-
|
980
|
+
existing.clear()
|
941
981
|
else:
|
942
982
|
log.debug(
|
943
983
|
"tube has multiples records: [%s] = %s records, must just 1 and sort_key is defined by: [%s]",
|
@@ -947,20 +987,9 @@ class WaveStorage(iWaves, iStorage):
|
|
947
987
|
)
|
948
988
|
|
949
989
|
push = True
|
950
|
-
for exists in
|
990
|
+
for exists in existing:
|
951
991
|
existing_sort_blueprint = build_dict(exists, reverse_sort_keys)
|
952
|
-
|
953
|
-
# check if stream provide an old-echo item
|
954
|
-
# sort_keys must exists in both data
|
955
|
-
old_echo = [
|
956
|
-
old_echo.append(data[_] < exists[_]) if _ in exists else False
|
957
|
-
]
|
958
|
-
if any(old_echo):
|
959
|
-
log.warning(
|
960
|
-
"provider give old data again, preserving storage value and ignore this old_echo"
|
961
|
-
)
|
962
|
-
push = False
|
963
|
-
break
|
992
|
+
# existing_sort_blueprint = build_comparisson_dict(exists, reverse_sort_keys)
|
964
993
|
|
965
994
|
same_sort_key = existing_sort_blueprint == data_sort_blueprint
|
966
995
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: syncmodels
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.313
|
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.313
|
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=F-gwFoSn9hneX4i5kpR9dYY6CUDVidYhx9nW2WiEJcU,142
|
2
2
|
syncmodels/context.py,sha256=k1Gs_ip9BfyRFpyRnzqYvRDKo0sYBqJsh6z9sWln9oE,451
|
3
|
-
syncmodels/crawler.py,sha256=
|
3
|
+
syncmodels/crawler.py,sha256=vfMn39Fev1yKY8ELvTK3rM-RUPiiy8YoxAG2q7b9MkM,94247
|
4
4
|
syncmodels/crud.py,sha256=viHBwzczcjNyFiLxL7VGYSbWJW5VjU8AvKaPufBMP7M,15303
|
5
5
|
syncmodels/definitions.py,sha256=2P-Sfgj18viSHZ-wAK4WfQEzDKdyygs8Z-XLzA0jg_k,5420
|
6
6
|
syncmodels/exceptions.py,sha256=8EOYW8h_2noeoKAYqG4aEQTgB1FEkamxKt3t4pDJ3pM,626
|
@@ -9,9 +9,9 @@ syncmodels/http.py,sha256=FFVT3QJJgur2dv1Q_7l9ZsWN8z6_gUjOT9hJff1ZAqk,3335
|
|
9
9
|
syncmodels/parallel.py,sha256=Ll8HmyFF9v9fIofqqSgfhyTlklvb77mTtNdG5Y9lqdQ,7145
|
10
10
|
syncmodels/registry.py,sha256=YaQtgbSwa0je1MpCcVHALI3_b85vrddyOlhsnrUcKZs,8224
|
11
11
|
syncmodels/requests.py,sha256=wWoC5hPDm1iBM_zrlyKRauzhXgdKR3pT5RqyC-5UZhQ,538
|
12
|
-
syncmodels/runner.py,sha256=
|
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=N69l-CSZOZomwVJMALKbPI1jPsngxDNlxbxX9SV4vfg,70505
|
15
15
|
syncmodels/syncmodels.py,sha256=EzSC4C75V4wJDmsLLbp8YUVwqA6A16KCNW8nB-MqPcs,10567
|
16
16
|
syncmodels/timequeue.py,sha256=YRd3ULRaIhoszaBsYhfr0epMqAbL6-NwVEtScjUYttM,595
|
17
17
|
syncmodels/wave.py,sha256=Gra22BLiA9z2nF-6diXpjAc4GZv9nebmyvHxdAfXec4,7764
|
@@ -32,7 +32,7 @@ syncmodels/helpers/geojson.py,sha256=9VZjdEw19fLS_Q9topapUOPGxRg2D4GOqm2tlx11W7M
|
|
32
32
|
syncmodels/helpers/importers.py,sha256=KImR9pQu4ir6EI6Ipta0q3RWloFT_VTJi67kM0lZsKQ,3919
|
33
33
|
syncmodels/helpers/loaders.py,sha256=aus0aRcbU1vVa_zWo42aX6uV3B0fQ0aQpkTWlR9xGLA,4325
|
34
34
|
syncmodels/helpers/models.py,sha256=c_ATzmiw5mVY1IGnwmyhjIuu5d2idHU-XeRigZSMkOQ,719
|
35
|
-
syncmodels/helpers/orion.py,sha256=
|
35
|
+
syncmodels/helpers/orion.py,sha256=Lblk4OGRNidYl1-2lZKUPXyvuR1hXip7FHloXLtU-XA,30717
|
36
36
|
syncmodels/helpers/surreal.py,sha256=zoWtGm5oAxwvgJNq_NTpKOHN3h9FNObhFDLuiBOl1YY,10050
|
37
37
|
syncmodels/helpers/units.py,sha256=g50m5DQrAyP_qpDRa4LCEA5Rz2UZUmlIixfWG_ddw9I,3571
|
38
38
|
syncmodels/logic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -43,11 +43,11 @@ syncmodels/logic/swarm.py,sha256=eRBVlNAOzzWKFGCb7LGLx2aj7yQlTY1OwLoeSEllvXY,172
|
|
43
43
|
syncmodels/mapper/__init__.py,sha256=jS82LFr9zzyqXBz82tSw04vDowhTpKxhg_W2XvhUlt0,129
|
44
44
|
syncmodels/mapper/fiware.py,sha256=auszPmhCS46z_68MXjksrQAFUfctjbVrVdBvOpOkMj8,523
|
45
45
|
syncmodels/mapper/mapper.py,sha256=SphMhr59bbTWWxnvitonURk3lSPDerGqUTs5-P-Tjlg,17397
|
46
|
-
syncmodels/model/__init__.py,sha256=
|
46
|
+
syncmodels/model/__init__.py,sha256=mD6fpRvBOl7i98pqqwpB2NKlviyD-G8iRXqufjU-9z8,148
|
47
47
|
syncmodels/model/activity.py,sha256=tKzc9zc_5Sx549yTdaTYkfnLnbEsEmzpu53BHstqvFQ,4592
|
48
48
|
syncmodels/model/geofilters.py,sha256=YxZZPk60MvzrBslOrpJec_Er1aTWGg1wgYrXPovrpP8,9284
|
49
49
|
syncmodels/model/geojson.py,sha256=BsW3phXHBGeaIOyOZg7U8bRYKKerAEgNjCl8EnBS2Dg,8329
|
50
|
-
syncmodels/model/model.py,sha256=
|
50
|
+
syncmodels/model/model.py,sha256=c8fAvGZ8_oXYQbdNixltRFhWjY3zYE1Y7MTLXIjbpac,11558
|
51
51
|
syncmodels/model/swarm.py,sha256=0QMc1iyiuW5goLLQGFTIky3dJcc5BfuBPHtVbn7iRK4,1266
|
52
52
|
syncmodels/model/schema_org/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
53
53
|
syncmodels/model/schema_org/aboutpage.py,sha256=_sqPMc7LxGWNSHwkvTB6OZZAfEovgHltisp6AAz2t9Y,452
|
@@ -302,10 +302,10 @@ syncmodels/session/postgresql.py,sha256=ZMIu1Rv93pKfvFlovFBmWArzlrT2xaQWNYGZT_LW
|
|
302
302
|
syncmodels/session/sql.py,sha256=bD7zXRrEKKJmqY2UoibWENuWb5zHrrU72F3_dYbS6LY,6569
|
303
303
|
syncmodels/session/sqlite.py,sha256=nCDjopLiBpX1F10qkKoARM7JrVdIpJ1WdGOduFVxaiA,2080
|
304
304
|
syncmodels/source/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
305
|
-
syncmodels-0.1.
|
306
|
-
syncmodels-0.1.
|
307
|
-
syncmodels-0.1.
|
308
|
-
syncmodels-0.1.
|
309
|
-
syncmodels-0.1.
|
310
|
-
syncmodels-0.1.
|
311
|
-
syncmodels-0.1.
|
305
|
+
syncmodels-0.1.313.dist-info/AUTHORS.rst,sha256=3ZPoqg8Aav8DSYKd0fwcwn4_5HwSiMLart0E5Un00-U,168
|
306
|
+
syncmodels-0.1.313.dist-info/LICENSE,sha256=uzMOYtIiUsnsD0xHJR7aJWJ4v_bvan0kTnvufy5eNoA,1075
|
307
|
+
syncmodels-0.1.313.dist-info/METADATA,sha256=NRPuII9unMl4-z_TQqvb9W-Tp94LIT6CXU3ctK_v3us,2700
|
308
|
+
syncmodels-0.1.313.dist-info/WHEEL,sha256=SrDKpSbFN1G94qcmBqS9nyHcDMp9cUS9OC06hC0G3G0,109
|
309
|
+
syncmodels-0.1.313.dist-info/entry_points.txt,sha256=dMnigjZsHMxTwXiiZyBZdBbMYE0-hY3L5cG15EcDAzw,51
|
310
|
+
syncmodels-0.1.313.dist-info/top_level.txt,sha256=2DfQ9NuAhKMjY3BvQGVBA7GfqTm7EoHNbaehSUiqiHQ,11
|
311
|
+
syncmodels-0.1.313.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|