udata 7.0.8.dev28841__py2.py3-none-any.whl → 9.0.1.dev29390__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.

Files changed (73) hide show
  1. udata/__init__.py +1 -1
  2. udata/api/__init__.py +6 -4
  3. udata/api/oauth2.py +2 -1
  4. udata/api_fields.py +254 -0
  5. udata/commands/purge.py +8 -2
  6. udata/core/badges/models.py +2 -1
  7. udata/core/dataservices/__init__.py +0 -0
  8. udata/core/dataservices/api.py +92 -0
  9. udata/core/dataservices/models.py +142 -0
  10. udata/core/dataservices/permissions.py +7 -0
  11. udata/core/dataservices/tasks.py +25 -0
  12. udata/core/dataset/apiv2.py +2 -0
  13. udata/core/dataset/csv.py +8 -1
  14. udata/core/dataset/models.py +1 -0
  15. udata/core/dataset/rdf.py +77 -15
  16. udata/core/metrics/commands.py +18 -3
  17. udata/core/metrics/models.py +2 -3
  18. udata/core/organization/api_fields.py +28 -3
  19. udata/core/organization/csv.py +5 -3
  20. udata/core/organization/models.py +3 -1
  21. udata/core/owned.py +39 -2
  22. udata/core/reuse/csv.py +3 -0
  23. udata/core/site/api.py +4 -1
  24. udata/core/spatial/api.py +5 -10
  25. udata/core/spatial/models.py +7 -2
  26. udata/core/spatial/tasks.py +7 -0
  27. udata/core/spatial/tests/test_api.py +26 -0
  28. udata/core/user/api.py +11 -7
  29. udata/core/user/models.py +13 -2
  30. udata/harvest/backends/base.py +93 -103
  31. udata/harvest/backends/dcat.py +65 -90
  32. udata/harvest/tasks.py +3 -13
  33. udata/harvest/tests/dcat/bnodes.xml +10 -1
  34. udata/harvest/tests/dcat/catalog.xml +1 -0
  35. udata/harvest/tests/factories.py +13 -6
  36. udata/harvest/tests/test_actions.py +2 -2
  37. udata/harvest/tests/test_base_backend.py +9 -5
  38. udata/harvest/tests/test_dcat_backend.py +17 -1
  39. udata/rdf.py +4 -0
  40. udata/routing.py +6 -0
  41. udata/settings.py +4 -1
  42. udata/static/admin.css +2 -2
  43. udata/static/admin.css.map +1 -1
  44. udata/static/chunks/{0.6f1698738c9b0618b673.js → 0.93c3ae13b5b94753ee80.js} +3 -3
  45. udata/static/chunks/0.93c3ae13b5b94753ee80.js.map +1 -0
  46. udata/static/chunks/{14.f4037a917d5364cb564b.js → 14.e64890872b31c55fcdf7.js} +2 -2
  47. udata/static/chunks/14.e64890872b31c55fcdf7.js.map +1 -0
  48. udata/static/chunks/{2.7c89fae92899be371ed3.js → 2.614b3e73b072982fd9b1.js} +2 -2
  49. udata/static/chunks/2.614b3e73b072982fd9b1.js.map +1 -0
  50. udata/static/chunks/{5.3dc97ea195d251881552.js → 5.48417db6b33328fa9d6a.js} +2 -2
  51. udata/static/chunks/5.48417db6b33328fa9d6a.js.map +1 -0
  52. udata/static/common.js +1 -1
  53. udata/static/common.js.map +1 -1
  54. udata/tasks.py +1 -0
  55. udata/tests/api/__init__.py +3 -0
  56. udata/tests/api/test_dataservices_api.py +236 -0
  57. udata/tests/api/test_organizations_api.py +78 -5
  58. udata/tests/api/test_user_api.py +47 -13
  59. udata/tests/dataservice/test_dataservice_tasks.py +46 -0
  60. udata/tests/dataset/test_dataset_rdf.py +17 -2
  61. udata/tests/plugin.py +5 -0
  62. udata/tests/site/test_site_rdf.py +16 -0
  63. {udata-7.0.8.dev28841.dist-info → udata-9.0.1.dev29390.dist-info}/METADATA +27 -1
  64. {udata-7.0.8.dev28841.dist-info → udata-9.0.1.dev29390.dist-info}/RECORD +68 -60
  65. udata/core/metrics/api.py +0 -10
  66. udata/static/chunks/0.6f1698738c9b0618b673.js.map +0 -1
  67. udata/static/chunks/14.f4037a917d5364cb564b.js.map +0 -1
  68. udata/static/chunks/2.7c89fae92899be371ed3.js.map +0 -1
  69. udata/static/chunks/5.3dc97ea195d251881552.js.map +0 -1
  70. {udata-7.0.8.dev28841.dist-info → udata-9.0.1.dev29390.dist-info}/LICENSE +0 -0
  71. {udata-7.0.8.dev28841.dist-info → udata-9.0.1.dev29390.dist-info}/WHEEL +0 -0
  72. {udata-7.0.8.dev28841.dist-info → udata-9.0.1.dev29390.dist-info}/entry_points.txt +0 -0
  73. {udata-7.0.8.dev28841.dist-info → udata-9.0.1.dev29390.dist-info}/top_level.txt +0 -0
@@ -6,9 +6,10 @@ from flask.signals import Namespace
6
6
 
7
7
  from udata.factories import ModelFactory
8
8
  from udata.core.dataset.factories import DatasetFactory
9
+ from udata.core.dataset.models import Dataset
9
10
 
10
11
  from .. import backends
11
- from ..models import HarvestSource, HarvestJob
12
+ from ..models import HarvestItem, HarvestSource, HarvestJob
12
13
 
13
14
 
14
15
  def dtfactory(start, end):
@@ -55,14 +56,20 @@ class FactoryBackend(backends.BaseBackend):
55
56
  backends.HarvestFeature('toggled', 'Toggled', 'A togglable', True),
56
57
  )
57
58
 
58
- def initialize(self):
59
+ def inner_harvest(self):
59
60
  mock_initialize.send(self)
60
61
  for i in range(self.config.get('count', DEFAULT_COUNT)):
61
- self.add_item(i)
62
+ self.process_dataset(str(i))
63
+ if self.is_done():
64
+ return
62
65
 
63
- def process(self, item):
64
- mock_process.send(self, item=item)
65
- return DatasetFactory.build(title='dataset-{0}'.format(item.remote_id))
66
+ def inner_process_dataset(self, item: HarvestItem):
67
+ mock_process.send(self, item=item.remote_id)
68
+
69
+ dataset = self.get_dataset(item.remote_id)
70
+ dataset.title = f'dataset-{item.remote_id}'
71
+
72
+ return dataset
66
73
 
67
74
 
68
75
  class MockBackendsMixin(object):
@@ -580,7 +580,7 @@ class ExecutionTestMixin(MockBackendsMixin):
580
580
 
581
581
  def test_error_on_item(self):
582
582
  def process(self, item):
583
- if item.remote_id == '1':
583
+ if item == '1':
584
584
  raise ValueError('test')
585
585
 
586
586
  source = HarvestSourceFactory(backend='factory')
@@ -723,7 +723,7 @@ class HarvestPreviewTest(MockBackendsMixin):
723
723
 
724
724
  def test_preview_with_error_on_item(self):
725
725
  def process(self, item):
726
- if item.remote_id == '1':
726
+ if item == '1':
727
727
  raise ValueError('test')
728
728
 
729
729
  source = HarvestSourceFactory(backend='factory')
@@ -5,6 +5,7 @@ from urllib.parse import urlparse
5
5
  from dateutil.parser import parse
6
6
  from voluptuous import Schema
7
7
 
8
+ from udata.harvest.models import HarvestItem
8
9
  from udata.utils import faker
9
10
  from udata.core.dataset import tasks
10
11
  from udata.core.dataset.factories import DatasetFactory
@@ -31,12 +32,16 @@ class FakeBackend(BaseBackend):
31
32
  HarvestFeature('enabled', 'A test feature enabled by default', default=True),
32
33
  )
33
34
 
34
- def initialize(self):
35
+ def inner_harvest(self):
35
36
  for i in range(self.source.config.get('nb_datasets', 3)):
36
- self.add_item('fake-{0}'.format(i))
37
+ remote_id = f'fake-{i}'
38
+ self.process_dataset(remote_id)
39
+ if self.is_done():
40
+ return
37
41
 
38
- def process(self, item):
42
+ def inner_process_dataset(self, item: HarvestItem):
39
43
  dataset = self.get_dataset(item.remote_id)
44
+
40
45
  for key, value in DatasetFactory.as_dict(visible=True).items():
41
46
  setattr(dataset, key, value)
42
47
  if self.source.config.get('last_modified'):
@@ -219,8 +224,7 @@ class BaseBackendTest:
219
224
  assert 'archived_at' not in dataset_no_arch.harvest
220
225
 
221
226
  # test unarchive: archive manually then relaunch harvest
222
- q = {'harvest__remote_id': 'fake-1'}
223
- dataset = Dataset.objects.get(**q)
227
+ dataset = Dataset.objects.get(**{'harvest__remote_id': 'fake-1'})
224
228
  dataset.archived = datetime.utcnow()
225
229
  dataset.harvest.archived = 'not-on-remote'
226
230
  dataset.harvest.archived_at = datetime.utcnow()
@@ -240,6 +240,19 @@ class DcatBackendTest:
240
240
  actions.purge_jobs()
241
241
  assert get_from_json(current_app.config.get('HARVEST_GRAPHS_S3_BUCKET'), job.data['filename']) is None
242
242
 
243
+ @pytest.mark.options(SCHEMA_CATALOG_URL='https://example.com/schemas', HARVEST_MAX_ITEMS=2)
244
+ def test_harvest_max_items(self, rmock):
245
+ rmock.get('https://example.com/schemas', json=ResourceSchemaMockData.get_mock_data())
246
+
247
+ filename = 'bnodes.xml'
248
+ url = mock_dcat(rmock, filename)
249
+ org = OrganizationFactory()
250
+ source = HarvestSourceFactory(backend='dcat', url=url, organization=org)
251
+
252
+ actions.run(source.slug)
253
+
254
+ assert Dataset.objects.count() == 2
255
+ assert HarvestJob.objects.first().status == 'done'
243
256
 
244
257
  @pytest.mark.options(SCHEMA_CATALOG_URL='https://example.com/schemas')
245
258
  def test_harvest_spatial(self, rmock):
@@ -255,7 +268,7 @@ class DcatBackendTest:
255
268
  datasets = {d.harvest.dct_identifier: d for d in Dataset.objects}
256
269
 
257
270
  assert datasets['1'].spatial == None
258
- assert datasets['2'].spatial.geom == {'type': 'MultiPolygon', 'coordinates': [[[[4.44641288, 45.54214467], [4.44641288, 46.01316963], [4.75655252, 46.01316963], [4.75655252, 45.54214467], [4.44641288, 45.54214467]]]]}
271
+ assert datasets['2'].spatial.geom == {'type': 'MultiPolygon', 'coordinates': [[[[-6,51],[10,51],[10,40],[-6,40],[-6,51]]], [[[4, 45], [4, 46], [4, 46], [4, 45], [4, 45]]], [[[159, -25.], [159, -11], [212, -11], [212, -25.], [159, -25.]]]]}
259
272
  assert datasets['3'].spatial == None
260
273
 
261
274
  @pytest.mark.options(SCHEMA_CATALOG_URL='https://example.com/schemas')
@@ -440,6 +453,9 @@ class DcatBackendTest:
440
453
  assert dataset.extras["harvest"]["dct:accessRights"] == "http://inspire.ec.europa.eu/metadata-codelist/LimitationsOnPublicAccess/INSPIRE_Directive_Article13_1e"
441
454
  assert dataset.extras["harvest"]["dct:provenance"] == ["Description de la provenance des données"]
442
455
 
456
+ assert 'observation-de-la-terre-et-environnement' in dataset.tags
457
+ assert 'hvd' in dataset.tags
458
+
443
459
  dataset = Dataset.objects.get(harvest__dct_identifier='1')
444
460
  # test html abstract description support
445
461
  assert dataset.description == '# h1 title\n\n## h2 title\n\n **and bold text**'
udata/rdf.py CHANGED
@@ -21,6 +21,7 @@ log = logging.getLogger(__name__)
21
21
  # Extra Namespaces
22
22
  ADMS = Namespace('http://www.w3.org/ns/adms#')
23
23
  DCAT = Namespace('http://www.w3.org/ns/dcat#')
24
+ DCATAP = Namespace('http://data.europa.eu/r5r/')
24
25
  HYDRA = Namespace('http://www.w3.org/ns/hydra/core#')
25
26
  SCHEMA = Namespace('http://schema.org/')
26
27
  SCV = Namespace('http://purl.org/NET/scovo#')
@@ -35,6 +36,7 @@ VCARD = Namespace('http://www.w3.org/2006/vcard/ns#')
35
36
 
36
37
  namespace_manager = NamespaceManager(Graph())
37
38
  namespace_manager.bind('dcat', DCAT)
39
+ namespace_manager.bind('dcatap', DCATAP)
38
40
  namespace_manager.bind('dct', DCT)
39
41
  namespace_manager.bind('foaf', FOAF)
40
42
  namespace_manager.bind('foaf', FOAF)
@@ -98,6 +100,8 @@ RDF_EXTENSIONS = {
98
100
  # Includes control characters, unicode surrogate characters and unicode end-of-plane non-characters
99
101
  ILLEGAL_XML_CHARS = '[\x00-\x08\x0b\x0c\x0e-\x1F\uD800-\uDFFF\uFFFE\uFFFF]'
100
102
 
103
+ HVD_LEGISLATION = 'http://data.europa.eu/eli/reg_impl/2023/138/oj'
104
+
101
105
 
102
106
  def guess_format(string):
103
107
  '''Guess format given an extension or a mime-type'''
udata/routing.py CHANGED
@@ -10,6 +10,7 @@ from werkzeug.urls import url_quote
10
10
  from udata import models
11
11
  from udata.mongo import db
12
12
  from udata.core.spatial.models import GeoZone
13
+ from udata.core.dataservices.models import Dataservice
13
14
  from udata.i18n import ISO_639_1_CODES
14
15
 
15
16
 
@@ -121,6 +122,10 @@ class DatasetConverter(ModelConverter):
121
122
  model = models.Dataset
122
123
 
123
124
 
125
+ class DataserviceConverter(ModelConverter):
126
+ model = Dataservice
127
+
128
+
124
129
  class CommunityResourceConverter(ModelConverter):
125
130
  model = models.CommunityResource
126
131
 
@@ -222,6 +227,7 @@ def init_app(app):
222
227
  app.url_map.converters['pathlist'] = PathListConverter
223
228
  app.url_map.converters['uuid'] = UUIDConverter
224
229
  app.url_map.converters['dataset'] = DatasetConverter
230
+ app.url_map.converters['dataservice'] = DataserviceConverter
225
231
  app.url_map.converters['crid'] = CommunityResourceConverter
226
232
  app.url_map.converters['org'] = OrganizationConverter
227
233
  app.url_map.converters['reuse'] = ReuseConverter
udata/settings.py CHANGED
@@ -269,7 +269,10 @@ class Defaults(object):
269
269
  # S3 connection details
270
270
  S3_URL = None
271
271
  S3_ACCESS_KEY_ID = None
272
- S3_SECRET_ACCESS_KEY = None
272
+ S3_SECRET_ACCESS_KEY = None
273
+
274
+ # Specific support for hvd (map HVD categories URIs to keywords)
275
+ HVD_SUPPORT = True
273
276
 
274
277
  ACTIVATE_TERRITORIES = False
275
278
  # The order is important to compute parents/children, smaller first.