udata 10.8.3.dev37097__py2.py3-none-any.whl → 10.8.3.dev37152__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.

Potentially problematic release.


This version of udata might be problematic. Click here for more details.

@@ -1,11 +1,13 @@
1
1
  from datetime import datetime
2
2
 
3
3
  from blinker import Signal
4
+ from mongoengine.errors import DoesNotExist
4
5
  from mongoengine.signals import post_save
5
6
 
6
7
  from udata.api_fields import get_fields
7
8
  from udata.auth import current_user
8
9
  from udata.mongo import db
10
+ from udata.utils import get_field_value_from_path
9
11
 
10
12
  from .signals import new_activity
11
13
 
@@ -79,6 +81,25 @@ class Activity(db.Document, metaclass=EmitNewActivityMetaClass):
79
81
 
80
82
 
81
83
  class Auditable(object):
84
+ def clean(self, **kwargs):
85
+ super().clean()
86
+ """
87
+ Fetch original document changed fields values before the new one erase it.
88
+ """
89
+ changed_fields = self._get_changed_fields()
90
+ if changed_fields:
91
+ try:
92
+ # `only` does not support having nested list as expressed in changed fields, ex resources.0.title
93
+ # thus we only strip to direct attributes for simplicity
94
+ direct_attributes = set(field.split(".")[0] for field in changed_fields)
95
+ old_document = self.__class__.objects.only(*direct_attributes).get(pk=self.pk)
96
+ self._previous_changed_fields = {}
97
+ for field_path in changed_fields:
98
+ field_value = get_field_value_from_path(old_document, field_path)
99
+ self._previous_changed_fields[field_path] = field_value
100
+ except DoesNotExist:
101
+ pass
102
+
82
103
  @classmethod
83
104
  def post_save(cls, sender, document, **kwargs):
84
105
  try:
@@ -97,6 +118,7 @@ class Auditable(object):
97
118
  if kwargs.get("created"):
98
119
  cls.on_create.send(document)
99
120
  elif len(changed_fields):
100
- cls.on_update.send(document, changed_fields=changed_fields)
121
+ previous = getattr(document, "_previous_changed_fields", None)
122
+ cls.on_update.send(document, changed_fields=changed_fields, previous=previous)
101
123
  if getattr(document, "deleted_at", None) or getattr(document, "deleted", None):
102
124
  cls.on_delete.send(document)
@@ -0,0 +1,34 @@
1
+ from udata.core.dataservices.models import Dataservice
2
+ from udata.core.reuse.models import Reuse
3
+
4
+ from .models import Dataset
5
+
6
+
7
+ @Reuse.on_create.connect
8
+ @Reuse.on_update.connect
9
+ @Reuse.on_delete.connect
10
+ def update_dataset_reuses_metric(reuse, **kwargs):
11
+ previous = kwargs.get("previous")
12
+ if previous and previous.get("datasets"):
13
+ datasets_delta = set(dat.id for dat in reuse.datasets).symmetric_difference(
14
+ set(dat.id for dat in previous["datasets"])
15
+ )
16
+ else:
17
+ datasets_delta = set(dat.id for dat in reuse.datasets)
18
+ for dataset in datasets_delta:
19
+ Dataset.get(dataset).count_reuses()
20
+
21
+
22
+ @Dataservice.on_create.connect
23
+ @Dataservice.on_update.connect
24
+ @Dataservice.on_delete.connect
25
+ def update_dataset_dataservices_metric(dataservice, **kwargs):
26
+ previous = kwargs.get("previous")
27
+ if previous and previous.get("datasets"):
28
+ datasets_delta = set(dat.id for dat in dataservice.datasets).symmetric_difference(
29
+ set(dat.id for dat in previous["datasets"])
30
+ )
31
+ else:
32
+ datasets_delta = set(dat.id for dat in dataservice.datasets)
33
+ for dataset in datasets_delta:
34
+ Dataset.get(dataset).count_dataservices()
@@ -616,6 +616,7 @@ class Dataset(Auditable, WithMetrics, DatasetBadgeMixin, Owned, Linkable, db.Doc
616
616
  "discussions_open",
617
617
  "reuses",
618
618
  "reuses_by_months",
619
+ "dataservices",
619
620
  "followers",
620
621
  "followers_by_months",
621
622
  "views",
@@ -628,6 +629,7 @@ class Dataset(Auditable, WithMetrics, DatasetBadgeMixin, Owned, Linkable, db.Doc
628
629
  "created_at_internal",
629
630
  "last_modified_internal",
630
631
  "metrics.reuses",
632
+ "metrics.dataservices",
631
633
  "metrics.followers",
632
634
  "metrics.views",
633
635
  "slug",
@@ -1100,6 +1102,12 @@ class Dataset(Auditable, WithMetrics, DatasetBadgeMixin, Owned, Linkable, db.Doc
1100
1102
  self.metrics["reuses_by_months"] = get_stock_metrics(Reuse.objects(datasets=self).visible())
1101
1103
  self.save(signal_kwargs={"ignores": ["post_save"]})
1102
1104
 
1105
+ def count_dataservices(self):
1106
+ from udata.core.dataservices.models import Dataservice
1107
+
1108
+ self.metrics["dataservices"] = Dataservice.objects(datasets=self).visible().count()
1109
+ self.save(signal_kwargs={"ignores": ["post_save"]})
1110
+
1103
1111
  def count_followers(self):
1104
1112
  from udata.models import Follow
1105
1113
 
@@ -123,17 +123,6 @@ def send_frequency_reminder(self):
123
123
  print("Done")
124
124
 
125
125
 
126
- @job("update-datasets-reuses-metrics")
127
- def update_datasets_reuses_metrics(self):
128
- all_datasets = Dataset.objects.visible().timeout(False)
129
- for dataset in all_datasets:
130
- try:
131
- dataset.count_reuses()
132
- except Exception as e:
133
- log.error(f"Error for dataset {dataset} during reuses metrics update: {e}")
134
- continue
135
-
136
-
137
126
  def get_queryset(model_cls):
138
127
  # special case for resources
139
128
  if model_cls.__name__ == "Resource":
@@ -6,6 +6,7 @@ def init_app(app):
6
6
  import udata.core.user.metrics # noqa
7
7
  import udata.core.organization.metrics # noqa
8
8
  import udata.core.discussions.metrics # noqa
9
+ import udata.core.dataset.metrics # noqa
9
10
  import udata.core.reuse.metrics # noqa
10
11
  import udata.core.followers.metrics # noqa
11
12
 
@@ -74,6 +74,7 @@ def update(
74
74
  dataset.metrics.clear()
75
75
  dataset.count_discussions()
76
76
  dataset.count_reuses()
77
+ dataset.count_dataservices()
77
78
  dataset.count_followers()
78
79
  except Exception as e:
79
80
  log.info(f"Error during update: {e}")
@@ -119,6 +120,7 @@ def update(
119
120
  organization.metrics.clear()
120
121
  organization.count_datasets()
121
122
  organization.count_reuses()
123
+ organization.count_dataservices()
122
124
  organization.count_followers()
123
125
  organization.count_members()
124
126
  except Exception as e:
@@ -135,6 +137,7 @@ def update(
135
137
  user.metrics.clear()
136
138
  user.count_datasets()
137
139
  user.count_reuses()
140
+ user.count_dataservices()
138
141
  user.count_followers()
139
142
  user.count_following()
140
143
  except Exception as e:
@@ -35,3 +35,5 @@ def update_org_metrics(document, previous):
35
35
  previous.count_datasets()
36
36
  elif isinstance(document, Reuse):
37
37
  previous.count_reuses()
38
+ elif isinstance(document, Dataservice):
39
+ previous.count_dataservices()
@@ -42,3 +42,5 @@ def update_owner_metrics(document, previous):
42
42
  previous.count_datasets()
43
43
  elif isinstance(document, Reuse):
44
44
  previous.count_reuses()
45
+ elif isinstance(document, Dataservice):
46
+ previous.count_dataservices()
@@ -202,7 +202,10 @@ class DcatBackend(BaseBackend):
202
202
  )
203
203
 
204
204
  def process_one_dataservices_page(self, page_number: int, page: Graph):
205
+ access_services = {o for _, _, o in page.triples((None, DCAT.accessService, None))}
205
206
  for node in page.subjects(RDF.type, DCAT.DataService):
207
+ if node in access_services:
208
+ continue
206
209
  remote_id = page.value(node, DCT.identifier)
207
210
  self.process_dataservice(remote_id, page_number=page_number, page=page, node=node)
208
211
 
@@ -159,6 +159,7 @@
159
159
  <dcat:accessURL>http://data.test.org/datasets/1/resources/4/services?SERVICE=WMS&amp;REQUEST=GetCapabilities&amp;VERSION=1.3.0</dcat:accessURL>
160
160
  <dcat:accessService>
161
161
  <dcat:DataService>
162
+ <rdf:type rdf:resource="http://www.w3.org/ns/dcat#DataService"/>
162
163
  <dcterms:title xml:lang="fr">Geo Service</dcterms:title>
163
164
  <dcat:endpointURL rdf:resource="http://data.test.org/datasets/1/resources/4/services"/>
164
165
  <dcat:endpointDescription rdf:resource="http://data.test.org/datasets/1/resources/4/services?SERVICE=WMS&amp;REQUEST=GetCapabilities&amp;VERSION=1.3.0"/>
@@ -187,6 +187,23 @@ class DcatBackendTest:
187
187
  == "https://data.paris2024.org/api/explore/v2.1/console"
188
188
  )
189
189
 
190
+ def test_harvest_dataservices_ignore_accessservices(self, rmock):
191
+ rmock.get("https://example.com/schemas", json=ResourceSchemaMockData.get_mock_data())
192
+
193
+ url = mock_dcat(rmock, "catalog.xml")
194
+ org = OrganizationFactory()
195
+ source = HarvestSourceFactory(backend="dcat", url=url, organization=org)
196
+
197
+ actions.run(source)
198
+
199
+ source.reload()
200
+
201
+ job = source.get_last_job()
202
+ assert len(job.items) == 4
203
+
204
+ dataservices = Dataservice.objects
205
+ assert len(dataservices) == 0
206
+
190
207
  def test_harvest_literal_spatial(self, rmock):
191
208
  url = mock_dcat(rmock, "evian.json")
192
209
  org = OrganizationFactory()
@@ -478,12 +495,8 @@ class DcatBackendTest:
478
495
 
479
496
  assert job.status == "done"
480
497
  assert job.errors == []
481
- assert len(job.items) == 5
482
- # 4 datasets and one Dataservice mentionned but not described
483
- # because it appears in a distribution as DCAT.accessService
484
- # but is missing a proper DCT.identifier
498
+ assert len(job.items) == 4
485
499
  assert len([item for item in job.items if item.status == "done"]) == 4
486
- assert len([item for item in job.items if item.status == "skipped"]) == 1
487
500
 
488
501
  def test_xml_catalog(self, rmock):
489
502
  LicenseFactory(id="lov2", title="Licence Ouverte Version 2.0")
@@ -9,6 +9,9 @@ from mongoengine import ValidationError as MongoEngineValidationError
9
9
  from mongoengine import post_save
10
10
 
11
11
  from udata.app import cache
12
+ from udata.core import metrics
13
+ from udata.core.dataservices.factories import DataserviceFactory
14
+ from udata.core.dataservices.models import Dataservice
12
15
  from udata.core.dataset.activities import (
13
16
  UserAddedResourceToDataset,
14
17
  UserCreatedDataset,
@@ -30,8 +33,10 @@ from udata.core.dataset.factories import (
30
33
  ResourceSchemaMockData,
31
34
  )
32
35
  from udata.core.dataset.models import HarvestDatasetMetadata, HarvestResourceMetadata
36
+ from udata.core.followers.signals import on_follow, on_unfollow
37
+ from udata.core.reuse.factories import ReuseFactory, VisibleReuseFactory
33
38
  from udata.core.user.factories import UserFactory
34
- from udata.models import Dataset, License, ResourceSchema, Schema, db
39
+ from udata.models import Dataset, Follow, License, ResourceSchema, Reuse, Schema, db
35
40
  from udata.tests.helpers import assert_emit, assert_equal_dates, assert_not_emit
36
41
  from udata.utils import faker
37
42
 
@@ -399,6 +404,63 @@ class DatasetModelTest:
399
404
  dataset.save()
400
405
  mock_deleted.assert_called()
401
406
 
407
+ def test_dataset_metrics(self):
408
+ # We need to init metrics module
409
+ metrics.init_app(current_app)
410
+
411
+ dataset = DatasetFactory()
412
+
413
+ # Add related elements
414
+ with assert_emit(Reuse.on_create):
415
+ reuse = VisibleReuseFactory(datasets=[dataset])
416
+ ReuseFactory()
417
+ with assert_emit(Dataservice.on_create):
418
+ dataservice = DataserviceFactory(datasets=[dataset])
419
+ with assert_emit(on_follow):
420
+ follow = Follow.objects.create(
421
+ following=dataset, follower=UserFactory(), since=datetime.utcnow()
422
+ )
423
+
424
+ dataset.reload()
425
+ assert dataset.get_metrics()["reuses"] == 1
426
+ assert dataset.get_metrics()["dataservices"] == 1
427
+ assert dataset.get_metrics()["followers"] == 1
428
+
429
+ # Delete related elements
430
+ with assert_emit(Reuse.on_delete):
431
+ reuse.deleted = datetime.utcnow()
432
+ reuse.save()
433
+ with assert_emit(Dataservice.on_delete):
434
+ dataservice.deleted_at = datetime.utcnow()
435
+ dataservice.save()
436
+ with assert_emit(on_unfollow):
437
+ follow.until = datetime.utcnow()
438
+ follow.save()
439
+
440
+ dataset.reload()
441
+ assert dataset.get_metrics()["reuses"] == 0
442
+ assert dataset.get_metrics()["dataservices"] == 0
443
+ assert dataset.get_metrics()["followers"] == 0
444
+
445
+ # Attach and then detach related elements
446
+ reuse = VisibleReuseFactory(datasets=[dataset])
447
+ dataservice = DataserviceFactory(datasets=[dataset])
448
+
449
+ dataset.reload()
450
+ assert dataset.get_metrics()["reuses"] == 1
451
+ assert dataset.get_metrics()["dataservices"] == 1
452
+
453
+ with assert_emit(Reuse.on_update):
454
+ reuse.datasets = []
455
+ reuse.save()
456
+ with assert_emit(Dataservice.on_update):
457
+ dataservice.datasets = []
458
+ dataservice.save()
459
+
460
+ dataset.reload()
461
+ assert dataset.get_metrics()["reuses"] == 0
462
+ assert dataset.get_metrics()["dataservices"] == 0
463
+
402
464
 
403
465
  class ResourceModelTest:
404
466
  def test_url_is_required(self):
@@ -1,8 +1,9 @@
1
1
  from datetime import datetime
2
2
 
3
3
  import pytest
4
+ from flask import current_app
4
5
 
5
- from udata.core.dataset import tasks as dataset_tasks
6
+ from udata.core import metrics
6
7
  from udata.core.dataset.factories import DatasetFactory
7
8
  from udata.core.discussions.factories import DiscussionFactory
8
9
  from udata.core.organization.factories import OrganizationFactory
@@ -69,6 +70,9 @@ class ReuseModelTest(TestCase, DBTestMixin):
69
70
  reuse.save()
70
71
 
71
72
  def test_reuse_metrics(self):
73
+ # We need to init metrics module
74
+ metrics.init_app(current_app)
75
+
72
76
  dataset = DatasetFactory()
73
77
  reuse = VisibleReuseFactory()
74
78
  DiscussionFactory(subject=reuse)
@@ -83,17 +87,15 @@ class ReuseModelTest(TestCase, DBTestMixin):
83
87
  reuse.datasets.append(dataset)
84
88
  reuse.save()
85
89
 
86
- reuse.count_datasets()
87
90
  assert reuse.get_metrics()["datasets"] == 2
88
91
 
89
- dataset.count_reuses()
92
+ dataset.reload()
90
93
  assert dataset.get_metrics()["reuses"] == 1
91
94
 
92
95
  with assert_emit(Reuse.on_update):
93
96
  reuse.datasets.remove(dataset)
94
97
  reuse.save()
95
98
 
96
- dataset_tasks.update_datasets_reuses_metrics()
97
99
  dataset.reload()
98
100
  assert dataset.get_metrics()["reuses"] == 0
99
101
 
udata/utils.py CHANGED
@@ -37,6 +37,22 @@ def multi_to_dict(multi):
37
37
  )
38
38
 
39
39
 
40
+ def get_field_value_from_path(document, field_path: str):
41
+ # The field_path is a pattern of dot-separated nested field as returned
42
+ # by mongoengine.base.document._get_changed_fields
43
+ # Inspired from mongoengine.base.document._clear_changed_fields iteration
44
+ doc_field = document
45
+ for part in field_path.split("."):
46
+ if isinstance(doc_field, list) and part.isdigit():
47
+ doc_field = doc_field[int(part)]
48
+ elif isinstance(doc_field, dict):
49
+ doc_field = doc_field.get(part, None)
50
+ else:
51
+ field_name = doc_field._reverse_db_field_map.get(part, part)
52
+ doc_field = getattr(doc_field, field_name, None)
53
+ return doc_field
54
+
55
+
40
56
  FIRST_CAP_RE = re.compile("(.)([A-Z][a-z]+)")
41
57
  ALL_CAP_RE = re.compile("([a-z0-9])([A-Z])")
42
58
  UUID_LENGTH = 36
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: udata
3
- Version: 10.8.3.dev37097
3
+ Version: 10.8.3.dev37152
4
4
  Summary: Open data portal
5
5
  Home-page: https://github.com/opendatateam/udata
6
6
  Author: Opendata Team
@@ -143,7 +143,9 @@ It is collectively taken care of by members of the
143
143
 
144
144
  ## Current (in progress)
145
145
 
146
- - Nothing yet
146
+ - Count dataservices and reuses for datasets based on signal [#3335](https://github.com/opendatateam/udata/pull/3335)
147
+ :warning: the job `update-datasets-reuses-metrics` disappears, you should unschedule it before installing this version
148
+ - Ignore Dataset.accessService when processing DataService [#3399](https://github.com/opendatateam/udata/pull/3399)
147
149
 
148
150
  ## 10.8.2 (2025-07-31)
149
151
 
@@ -20,7 +20,7 @@ udata/tasks.py,sha256=yTYBJG5bzEChX27p3MSqurSji84rg7w7OUvK4vuPRfY,5080
20
20
  udata/terms.md,sha256=nFx978tUQ3vTEv6POykXaZvcQ5e_gcvmO4ZgcfbSWXo,187
21
21
  udata/tracking.py,sha256=WOcqA1RlHN8EPFuEc2kNau54mec4-pvi-wUFrMXevzg,345
22
22
  udata/uris.py,sha256=1wOrsxu6lmZJ1h4634kNHjqOjaOO0D5cIWKF_v_Gtn4,4264
23
- udata/utils.py,sha256=zNxbPOMZIZ2fivhx47nH5IBpVmrKf5iFuucM1E7u_5M,8983
23
+ udata/utils.py,sha256=W2-pZwpEYQULrovX4msGNjBvj6EvP9eJm6ueQ2ujbP0,9681
24
24
  udata/worker.py,sha256=K-Wafye5-uXP4kQlffRKws2J9YbJ6m6n2QjcVsY8Nsg,118
25
25
  udata/wsgi.py,sha256=MY8en9K9eDluvJYUxTdzqSDoYaDgCVZ69ZcUvxAvgqA,77
26
26
  udata/admin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -59,7 +59,7 @@ udata/core/linkable.py,sha256=8YuTzZo5Y36CVIYxESC-EPJ-zKsQTRbi4OIZTp-wWig,587
59
59
  udata/core/owned.py,sha256=OQT7wdk7dAqGvWDiJRVkKJxerDc9_Io910nvLmfBAVI,5561
60
60
  udata/core/activity/__init__.py,sha256=dLTseBmVYbQzxB7OR7Dz0LtIwEjNQvgUSR7SwfInb68,399
61
61
  udata/core/activity/api.py,sha256=dwdEkJxxwbQ2PsCSnv6fEE8Ps1FiJ4fEHpTog_gk4Rs,4291
62
- udata/core/activity/models.py,sha256=ipViQMB1UMgxd9nolueanEgOB31s9pihTqkDdfo11u4,3214
62
+ udata/core/activity/models.py,sha256=iPDfGvvegKM6cUu29qwYJ1qnSqA2uqA-Ch0QabLEgiU,4349
63
63
  udata/core/activity/signals.py,sha256=Io2A43as3yR-DZ5R3wzM_bTpn528pxWsZDUFZ9xtj2Y,191
64
64
  udata/core/activity/tasks.py,sha256=F3PY12dnpT5Z8VuYfuOyDP6VPKPJmq1Sm4lSiPfmUCA,1498
65
65
  udata/core/badges/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -106,14 +106,15 @@ udata/core/dataset/events.py,sha256=bSM0nFEX14r4JHc-bAM-7OOuD3JAxUIpw9GgXbOsUyw,
106
106
  udata/core/dataset/exceptions.py,sha256=uKiayLSpSzsnLvClObS6hOO0qXEqvURKN7_w8eimQNU,498
107
107
  udata/core/dataset/factories.py,sha256=fRDWDlybR_ud4pDs1-ntWuYHKtV9LMHeBOBp2SmTT6M,9006
108
108
  udata/core/dataset/forms.py,sha256=7KUxuFcEGT0MUe0cZCiZtsnZhvGgvEd68pe13NgeSMI,6292
109
- udata/core/dataset/models.py,sha256=JBIORJcJf1UamIBCpBplKU2L_QjvzmG0FZ3XuhuI3Xw,43577
109
+ udata/core/dataset/metrics.py,sha256=s8Xs_rqRXfNWsErkiJTuRMG5o_cU5iSK8mUJFKVSc7w,1204
110
+ udata/core/dataset/models.py,sha256=HifPskf9ObuLVm9cUrrVNskw79OcQXVyyCWgBahBN3Q,43888
110
111
  udata/core/dataset/permissions.py,sha256=zXQ6kU-Ni3Pl5tDtat-ZPupug9InsNeCN7xRLc2Vcrc,1097
111
112
  udata/core/dataset/preview.py,sha256=qXmd4-nKvIPtcKLrMqC-aJne4-vMIiq_NubpX39D6I0,855
112
113
  udata/core/dataset/rdf.py,sha256=PFSzkpTFRdpa4cF-mxYU7IV1cJ73m80MmX-GZfWk3hg,30845
113
114
  udata/core/dataset/recommendations.py,sha256=DlGSLU8D0nW6Ds1rjBav1WxC-0VW5yOCjkO5w-ltFcI,7171
114
115
  udata/core/dataset/search.py,sha256=B8s4vp4Z5pma5c_Wm03Ncaeoi3LtX6jhbiaWd20bomI,5625
115
116
  udata/core/dataset/signals.py,sha256=WN4sV-lJlNsRkhcnhoy0SYJvCoYmK_5QFYZd1u-h4gs,161
116
- udata/core/dataset/tasks.py,sha256=6FzeLzJRQxzq7sBLUE8H8ZGLByix2EDOzGAsA8FteX8,10019
117
+ udata/core/dataset/tasks.py,sha256=Fx1w3YtU8uXR6tSy7IYQQ8Bae54ROVvAObrJgbEiWwI,9655
117
118
  udata/core/dataset/transport.py,sha256=ihCXirY1dZjOfXKbf9HRCJTfIOc75rM1McwbeGjsW6A,1296
118
119
  udata/core/discussions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
119
120
  udata/core/discussions/actions.py,sha256=kjdBLDIeu0yWTSxQGgOpN1WoxUqbMygn4SiBk_S9T5I,1051
@@ -140,8 +141,8 @@ udata/core/jobs/api.py,sha256=Cml8mTEXFPw9SBd-1sYBH50YrVv4nvxo7R1o5VpPXE0,5959
140
141
  udata/core/jobs/commands.py,sha256=85P5hDPdKMJzV_xbobNT8nqEW71HchPjTUJ-1u5wddE,4402
141
142
  udata/core/jobs/forms.py,sha256=B-B6jXHZsYV-PWAkD8DLoOlh6trv4l1hGZ4HOPm-PD4,1495
142
143
  udata/core/jobs/models.py,sha256=xK8T3FCmhtERNbZmh1Tq_ZTO6vojM172tTc0oplNoQ0,1358
143
- udata/core/metrics/__init__.py,sha256=CB0MhZqNe4gKLBO-6zoGisXK7FtavxWx_Kkkle-INrc,398
144
- udata/core/metrics/commands.py,sha256=vHoljRR9ei4apSU2I2FjJLXeqgPwt6ONfXQaMIQ4418,6042
144
+ udata/core/metrics/__init__.py,sha256=eCmFPBR01Np6iEoz5n8dkfkCPGeCpPGTBT0kJ0SfpTw,444
145
+ udata/core/metrics/commands.py,sha256=JmEBsjmvQl0W32g4m_n7OdtB3zcAvcMCvlzJa0DzZJ4,6191
145
146
  udata/core/metrics/helpers.py,sha256=AJJouc5QLd6dtHXltGQPxTOYg7IqkgBfU3Kcpb9KwKU,4418
146
147
  udata/core/metrics/models.py,sha256=Sv2Qhmqdug_atfDc_pyOJCb-8ACpvU-_0FFVPVOFDGk,353
147
148
  udata/core/metrics/signals.py,sha256=9mdJW__gR2GJT3huBr6HN2SDhKYJRgNbW9dnh48cAnU,176
@@ -156,7 +157,7 @@ udata/core/organization/constants.py,sha256=fncNtA-vFrRM22K1Wo6iYu9DQZjzknYxH6TI
156
157
  udata/core/organization/csv.py,sha256=QR49HfMUtDzkAtxi8q3-P3VtQR4xf3cCnM6vIEJhRHU,1628
157
158
  udata/core/organization/factories.py,sha256=g8ubBcz79xbjvpunZ02IDOakFg1KE6cXjNkE9vFyFAc,624
158
159
  udata/core/organization/forms.py,sha256=tscDb1_yOpbTx3ahl8ttA7oDkX9jIyzLc4gOf6WbN3s,3552
159
- udata/core/organization/metrics.py,sha256=90romzr-FhnPKh-6UHBJ1Af2loDa4-8I1iZEgztA160,1062
160
+ udata/core/organization/metrics.py,sha256=CEhkZLUufDyWi2XyizMoXkuddz7xDJvmdkPTweqfWyI,1144
160
161
  udata/core/organization/models.py,sha256=7RkX_Cj6exgRyAuE0LN1qTsIq5fNKIurk8isSt6m-po,10753
161
162
  udata/core/organization/notifications.py,sha256=i_36-l2y7fOGmnBmr5NDWmGGmrGRaCWbU-6XS4c2wQs,917
162
163
  udata/core/organization/permissions.py,sha256=GD-9TMtRppVCPaC1ysXYrONvGJV-ArzAOXm2XMKf9yo,1256
@@ -250,7 +251,7 @@ udata/core/user/commands.py,sha256=d33hjgUi8WLA8YFvoq__FJJ_E-fk8f4tWo1iuT8jJvM,3
250
251
  udata/core/user/constants.py,sha256=aTluhTR2RGZ_cdG7-mkEoT5Ndbg8BNUwwzCOld0aLMY,77
251
252
  udata/core/user/factories.py,sha256=kkwaojciLzfuAOeRnL1E7XCcGPo8waAal_G2eeuVc0k,825
252
253
  udata/core/user/forms.py,sha256=yotqZozH9ViKuNI8SwdKocDEi7NXVs_XUMpdr_bIe5s,966
253
- udata/core/user/metrics.py,sha256=ZuCxYHu-770IsO-KPMhh-ZDkl2hYSVCuHDRvp-H1NfA,1192
254
+ udata/core/user/metrics.py,sha256=J4zgjcAudQAi6NUIb47o2Pfe0xZ_Eu17ta9HjhE-HvE,1274
254
255
  udata/core/user/models.py,sha256=E7WxSBa9jVqgrUF3bjqwemrDD0HYmJH3MN8tajq3-Aw,11293
255
256
  udata/core/user/permissions.py,sha256=Wbd8bLqSjqp9RHJ6ffLBj74L-LECcAhWazuw4Hq-2Gk,435
256
257
  udata/core/user/rdf.py,sha256=_tN8KlJHt8mYwJhLKoULhmZ3sapUGmX1Sl5W8uawxeU,718
@@ -299,7 +300,7 @@ udata/harvest/signals.py,sha256=3AhFHMPIFH5vz01NX5ycR_RWH14MXFWnCT6__LSa-QI,1338
299
300
  udata/harvest/tasks.py,sha256=id5YmHIhnkgez0LVC1fNg_6Yz1Sp0jrvQ1caslVOWdY,1722
300
301
  udata/harvest/backends/__init__.py,sha256=QjoFfBJfpw_xgk5YYWI1SgKJOMEmTMlxSfW79GNkSTI,459
301
302
  udata/harvest/backends/base.py,sha256=2wyfw83e3xGQcHnQI-z26g1dg-uVtWcDgzsBk7iGX3Y,17480
302
- udata/harvest/backends/dcat.py,sha256=IfUmqHy68Tt30E_kn4riExfgb-d7qPa--7KjCLCsia0,18637
303
+ udata/harvest/backends/dcat.py,sha256=TAKeMUxhnxbMP-V3IIL-Sy63yMUxw8iXIJrO4R_BqhI,18794
303
304
  udata/harvest/backends/maaf.py,sha256=N7ty8ZWO9pfKPtZRk1wTaJ5pY6qi-0-GtF1p8jiYiY4,8102
304
305
  udata/harvest/backends/maaf.xsd,sha256=vEyG8Vqw7Yn_acjRdXjqUJgxOj4pv8bibep-FX-f3BQ,18322
305
306
  udata/harvest/backends/ckan/__init__.py,sha256=JE7Qa7kX7Yd8OvmJnAO_NupZe0tqYyhhkgJ-iGNxX64,35
@@ -313,7 +314,7 @@ udata/harvest/tests/person.jsonld,sha256=I7Ynh-PQlNeD51I1LrCgYOEjhL-WBeb65xzIE_s
313
314
  udata/harvest/tests/test_actions.py,sha256=oXNTwDuSHtlVANRcsNyq3J33u4XU_jM9o67FbZjLCys,24860
314
315
  udata/harvest/tests/test_api.py,sha256=gSuICkPy3KVRUhHAyudXVf_gLwiB7SoriUp3DLXWDdA,21611
315
316
  udata/harvest/tests/test_base_backend.py,sha256=ow8ecGtD836mUqyPWYjkS5nx0STyT5RMLgBdDyOhts4,19233
316
- udata/harvest/tests/test_dcat_backend.py,sha256=6CKQmhlPf5Ceipj6Nj0qKb-myb48f003kwlgIvHQAi8,43568
317
+ udata/harvest/tests/test_dcat_backend.py,sha256=xe8X4Q88-Y50IQYT3Q9lz2rcFeb2ADIg1wLz-I7-ewc,43835
317
318
  udata/harvest/tests/test_filters.py,sha256=PT2qopEIoXsqi8MsNDRuhNH7jGXiQo8r0uJrCOUd4aM,2465
318
319
  udata/harvest/tests/test_models.py,sha256=f9NRR2_S4oZFgF8qOumg0vv-lpnEBJbI5vNtcwFdSqM,831
319
320
  udata/harvest/tests/test_notifications.py,sha256=MMzTzkv-GXMNFeOwAi31rdTsAXyLCLOSna41zOtaJG0,816
@@ -334,7 +335,7 @@ udata/harvest/tests/csw_dcat/geonetworkv4-page-3.xml,sha256=fsN0E4TVd_ts-sYA612y
334
335
  udata/harvest/tests/csw_dcat/geonetworkv4-page-5.xml,sha256=0VmPp1kspik7YAmOFyr-3yJLzWGA6kuQp_x_w-W385o,21213
335
336
  udata/harvest/tests/dcat/bnodes.jsonld,sha256=Leqny-ccp30564yojQYYckw_HKbhR0f5qUCaavc2ruE,7964
336
337
  udata/harvest/tests/dcat/bnodes.xml,sha256=bjG-pE2jDuJ7ZNDzQV4JEiMeAHCeX5eMQyUcDecVQ08,11333
337
- udata/harvest/tests/dcat/catalog.xml,sha256=ZBBH3JntmnmK9F9tGABvlfoXU4gBPOJTWL4942mhsto,12339
338
+ udata/harvest/tests/dcat/catalog.xml,sha256=1tfktnFDEcJrJWSj_yt0zZVE5j8p-kiUanW9V-oxOrs,12412
338
339
  udata/harvest/tests/dcat/evian.json,sha256=R3RxP5azUuf9aZ9fU7n6iJkfbJ6oj-Zej2cjOtkYr8M,16647
339
340
  udata/harvest/tests/dcat/flat.jsonld,sha256=BAw08MDhtW9Px3q6RAoTIqO_OwJmAwBS9EpC8BY_x98,8459
340
341
  udata/harvest/tests/dcat/geonetwork.xml,sha256=9_pksE74Zzkbgs9okj6hEbo8CJS0FZjEnIdvopKfm7k,7928
@@ -681,7 +682,7 @@ udata/tests/dataset/test_csv_adapter.py,sha256=7U83RiuSKNVgX-mV45Txp9a828mnWE4eK
681
682
  udata/tests/dataset/test_dataset_actions.py,sha256=bgDjVYjOvu3sX_FCTCzf2snZYSprsqor2nAhIVuokSs,722
682
683
  udata/tests/dataset/test_dataset_commands.py,sha256=zMPJG2wYwKBee2zI65kmboxf59Zqa84DDjT8V5wj9uo,801
683
684
  udata/tests/dataset/test_dataset_events.py,sha256=hlrpoOiBbnX_COUI9Pzdqlp45GZZDqu5piwupbnPiTI,3601
684
- udata/tests/dataset/test_dataset_model.py,sha256=5NYgIcl_7w4KJqWMwtNDb4OTXsjIA_gzECXmEoxXj84,33130
685
+ udata/tests/dataset/test_dataset_model.py,sha256=nxAE7SH9HZEHWsNSFwclfxQbS7XN5gvv_D93KlDTW04,35474
685
686
  udata/tests/dataset/test_dataset_rdf.py,sha256=j919psNAH0scn0DIwHNlqiZGFKd_lKOlyTisICNGeOE,44327
686
687
  udata/tests/dataset/test_dataset_recommendations.py,sha256=K52HXGXi9DuUSiSRQWpqTrsFCkYbv7K3upNp0fFp5v8,7068
687
688
  udata/tests/dataset/test_dataset_tasks.py,sha256=n1W2Pg0ez02d66zQG3N93kh7dpR2yLMRDqUI6PnPaI0,3088
@@ -722,7 +723,7 @@ udata/tests/organization/test_organization_model.py,sha256=ZEUHX7lvGMYMlHDpPiVUP
722
723
  udata/tests/organization/test_organization_rdf.py,sha256=Uf-OgXV615wLUHfcBTmp9QFuV8VCFmjI4wgvShve-mc,8074
723
724
  udata/tests/organization/test_organization_tasks.py,sha256=9Ta-f4R3RoKdARYUFWHO4pE1nijceTHzyEvI34lYBJo,2876
724
725
  udata/tests/reuse/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
725
- udata/tests/reuse/test_reuse_model.py,sha256=3IbpL6Z6e_ieYDkQtWtuJIooIslCX2BU5BTqtbgKF8k,4667
726
+ udata/tests/reuse/test_reuse_model.py,sha256=PtdC39JrDCtF9iSfYSH98115309Q-E8aKn4s6rZCqCY,4662
726
727
  udata/tests/reuse/test_reuse_task.py,sha256=4gMsKHjGafb6kpRKnqF167Htd-Ff0tRD4iQajW1e_lg,1380
727
728
  udata/tests/search/__init__.py,sha256=ub8kS6vG9EjzkJ-9sAR7j1eLSYpud1Gzry4MQ8fpgxM,1493
728
729
  udata/tests/search/test_adapter.py,sha256=mi-M53JQSPYxU8ahkqtfyIrIyhz_cC_ATdLbWWa3onM,6941
@@ -757,9 +758,9 @@ udata/translations/pt/LC_MESSAGES/udata.mo,sha256=ogtEGsjwIkOEtzrI49e57izi-NUim5
757
758
  udata/translations/pt/LC_MESSAGES/udata.po,sha256=1omSlqdMEdwYtzHGalXrtptVk14mlb6JS_8xR8BsznU,48428
758
759
  udata/translations/sr/LC_MESSAGES/udata.mo,sha256=V7unDjO31PNLiRhfEkYU3pU47wWWct-otdL0GDma0S4,28692
759
760
  udata/translations/sr/LC_MESSAGES/udata.po,sha256=wVBipfpPl-DmYeVm5wrlzWWM3oEvuruDVbJHx4I1p8s,55170
760
- udata-10.8.3.dev37097.dist-info/LICENSE,sha256=V8j_M8nAz8PvAOZQocyRDX7keai8UJ9skgmnwqETmdY,34520
761
- udata-10.8.3.dev37097.dist-info/METADATA,sha256=crzl3FAX479PFqBh52LDs2-8aVqnp_wMEmRGRAfkK_I,153076
762
- udata-10.8.3.dev37097.dist-info/WHEEL,sha256=Kh9pAotZVRFj97E15yTA4iADqXdQfIVTHcNaZTjxeGM,110
763
- udata-10.8.3.dev37097.dist-info/entry_points.txt,sha256=v2u12qO11i2lyLNIp136WmLJ-NHT-Kew3Duu8J-AXPM,614
764
- udata-10.8.3.dev37097.dist-info/top_level.txt,sha256=39OCg-VWFWOq4gCKnjKNu-s3OwFlZIu_dVH8Gl6ndHw,12
765
- udata-10.8.3.dev37097.dist-info/RECORD,,
761
+ udata-10.8.3.dev37152.dist-info/LICENSE,sha256=V8j_M8nAz8PvAOZQocyRDX7keai8UJ9skgmnwqETmdY,34520
762
+ udata-10.8.3.dev37152.dist-info/METADATA,sha256=PseQl0wFZEwaakB9RoiAJHINKCNDVEHmytT_EoOAl-Q,153417
763
+ udata-10.8.3.dev37152.dist-info/WHEEL,sha256=Kh9pAotZVRFj97E15yTA4iADqXdQfIVTHcNaZTjxeGM,110
764
+ udata-10.8.3.dev37152.dist-info/entry_points.txt,sha256=v2u12qO11i2lyLNIp136WmLJ-NHT-Kew3Duu8J-AXPM,614
765
+ udata-10.8.3.dev37152.dist-info/top_level.txt,sha256=39OCg-VWFWOq4gCKnjKNu-s3OwFlZIu_dVH8Gl6ndHw,12
766
+ udata-10.8.3.dev37152.dist-info/RECORD,,