udata 7.0.5.dev27829__py2.py3-none-any.whl → 7.0.5.dev27885__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.

udata/core/dataset/rdf.py CHANGED
@@ -2,17 +2,21 @@
2
2
  This module centralize dataset helpers for RDF/DCAT serialization and parsing
3
3
  '''
4
4
  import calendar
5
+ import json
5
6
  import logging
6
7
 
7
8
  from datetime import date
8
9
  from html.parser import HTMLParser
9
10
  from dateutil.parser import parse as parse_dt
10
11
  from flask import current_app
12
+ from geomet import wkt
11
13
  from rdflib import Graph, URIRef, Literal, BNode
12
14
  from rdflib.resource import Resource as RdfResource
13
15
  from rdflib.namespace import RDF
16
+ from mongoengine.errors import ValidationError
14
17
 
15
18
  from udata import i18n, uris
19
+ from udata.core.spatial.models import SpatialCoverage
16
20
  from udata.frontend.markdown import parse_html
17
21
  from udata.core.dataset.models import HarvestDatasetMetadata, HarvestResourceMetadata
18
22
  from udata.models import db, ContactPoint
@@ -334,6 +338,42 @@ def contact_point_from_rdf(rdf, dataset):
334
338
  ContactPoint(name=name, email=email, owner=dataset.owner).save())
335
339
 
336
340
 
341
+ def spatial_from_rdf(term):
342
+ if term is None:
343
+ return None
344
+
345
+ for object in term.objects():
346
+ if isinstance(object, Literal):
347
+ if object.datatype.__str__() == 'https://www.iana.org/assignments/media-types/application/vnd.geo+json':
348
+ try:
349
+ geojson = json.loads(object.toPython())
350
+ except ValueError as e:
351
+ log.warning(f"Invalid JSON in spatial GeoJSON {object.toPython()} {e}")
352
+ continue
353
+ elif object.datatype.__str__() == 'http://www.opengis.net/rdf#wktLiteral':
354
+ try:
355
+ # .upper() si here because geomet doesn't support Polygon but only POLYGON
356
+ geojson = wkt.loads(object.toPython().strip().upper())
357
+ except ValueError as e:
358
+ log.warning(f"Invalid JSON in spatial WKT {object.toPython()} {e}")
359
+ continue
360
+ else:
361
+ continue
362
+
363
+ if geojson['type'] == 'Polygon':
364
+ geojson['type'] = 'MultiPolygon'
365
+ geojson['coordinates'] = [geojson['coordinates']]
366
+
367
+ spatial_coverage = SpatialCoverage(geom=geojson)
368
+
369
+ try:
370
+ spatial_coverage.clean()
371
+ return spatial_coverage
372
+ except ValidationError:
373
+ return None
374
+
375
+ return None
376
+
337
377
  def frequency_from_rdf(term):
338
378
  if isinstance(term, str):
339
379
  try:
@@ -488,7 +528,7 @@ def resource_from_rdf(graph_or_distrib, dataset=None, is_additionnal=False):
488
528
  return resource
489
529
 
490
530
 
491
- def dataset_from_rdf(graph, dataset=None, node=None):
531
+ def dataset_from_rdf(graph: Graph, dataset=None, node=None):
492
532
  '''
493
533
  Create or update a dataset from a RDF/DCAT graph
494
534
  '''
@@ -509,6 +549,10 @@ def dataset_from_rdf(graph, dataset=None, node=None):
509
549
  if schema:
510
550
  dataset.schema = schema
511
551
 
552
+ spatial_coverage = spatial_from_rdf(d.value(DCT.spatial))
553
+ if spatial_coverage:
554
+ dataset.spatial = spatial_coverage
555
+
512
556
  acronym = rdf_value(d, SKOS.altLabel)
513
557
  if acronym:
514
558
  dataset.acronym = acronym
udata/forms/fields.py CHANGED
@@ -180,6 +180,16 @@ class BooleanField(FieldHelper, fields.BooleanField):
180
180
  self.stacked = kwargs.pop('stacked', False)
181
181
  super(BooleanField, self).__init__(*args, **kwargs)
182
182
 
183
+ def process_formdata(self, valuelist):
184
+ # We override this so that when no value is provided
185
+ # the form doesn't think the value is `False` instead
186
+ # the value is not present and the model can keep the
187
+ # existing value
188
+ if not valuelist:
189
+ return
190
+
191
+ super().process_formdata(valuelist)
192
+
183
193
 
184
194
  class RadioField(FieldHelper, fields.RadioField):
185
195
  def __init__(self, *args, **kwargs):
@@ -5,6 +5,8 @@
5
5
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
6
6
  xmlns:dcat="http://www.w3.org/ns/dcat#"
7
7
  xmlns:dct="http://purl.org/dc/terms/"
8
+ xmlns:ogc="http://www.opengis.net/ogc"
9
+ xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
8
10
  xmlns:dcterms="http://purl.org/dc/terms/"
9
11
  xmlns:vcard="http://www.w3.org/2006/vcard/ns#"
10
12
  xmlns:schema="http://schema.org/"
@@ -54,7 +56,13 @@
54
56
  <owl:versionInfo>1.0</owl:versionInfo>
55
57
  <dcat:distribution rdf:resource="http://data.test.org/datasets/1/resources/2"/>
56
58
  <dcat:keyword>Tag 4</dcat:keyword>
57
- <dcterms:spatial rdf:resource="http://wuEurope.com/"/>
59
+ <dct:spatial>
60
+ <ogc:Polygon>
61
+ <geo:asWKT rdf:datatype="http://www.opengis.net/rdf#wktLiteral">
62
+ wrong wkt
63
+ </geo:asWKT>
64
+ </ogc:Polygon>
65
+ </dct:spatial>
58
66
  <dcterms:modified rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime">2016-12-14T19:01:24.184120</dcterms:modified>
59
67
  <dcat:keyword>Tag 2</dcat:keyword>
60
68
  <dcat:keyword>Tag 1</dcat:keyword>
@@ -79,7 +87,13 @@
79
87
  <dcat:keyword>Tag 3</dcat:keyword>
80
88
  <dcat:distribution rdf:resource="http://data.test.org/datasets/2/resources/2"/>
81
89
  <dcterms:title>Dataset 2</dcterms:title>
82
- <dcterms:spatial rdf:resource="http://wuEurope.com/"/>
90
+ <dct:spatial>
91
+ <ogc:Polygon>
92
+ <geo:asWKT rdf:datatype="http://www.opengis.net/rdf#wktLiteral">
93
+ Polygon((4.44641288 45.54214467, 4.44641288 46.01316963, 4.75655252 46.01316963, 4.75655252 45.54214467, 4.44641288 45.54214467))
94
+ </geo:asWKT>
95
+ </ogc:Polygon>
96
+ </dct:spatial>
83
97
  <dcterms:identifier>2</dcterms:identifier>
84
98
  <dct:conformsTo rdf:resource="https://www.ecologie.gouv.fr/sites/default/files/R%C3%A9glementation%20IRVE.pdf" />
85
99
  </dcat:Dataset>
@@ -156,6 +156,24 @@ class DcatBackendTest:
156
156
  assert len(datasets['1'].resources) == 2
157
157
  assert len(datasets['2'].resources) == 2
158
158
 
159
+
160
+ @pytest.mark.options(SCHEMA_CATALOG_URL='https://example.com/schemas')
161
+ def test_harvest_spatial(self, rmock):
162
+ rmock.get('https://example.com/schemas', json=ResourceSchemaMockData.get_mock_data())
163
+
164
+ filename = 'bnodes.xml'
165
+ url = mock_dcat(rmock, filename)
166
+ org = OrganizationFactory()
167
+ source = HarvestSourceFactory(backend='dcat', url=url, organization=org)
168
+
169
+ actions.run(source.slug)
170
+
171
+ datasets = {d.harvest.dct_identifier: d for d in Dataset.objects}
172
+
173
+ assert datasets['1'].spatial == None
174
+ 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]]]]}
175
+ assert datasets['3'].spatial == None
176
+
159
177
  @pytest.mark.options(SCHEMA_CATALOG_URL='https://example.com/schemas')
160
178
  def test_harvest_schemas(self, rmock):
161
179
  rmock.get('https://example.com/schemas', json=ResourceSchemaMockData.get_mock_data())
@@ -462,6 +462,33 @@ class DatasetAPITest(APITestCase):
462
462
  dataset = Dataset.objects.first()
463
463
  self.assertEqual(len(dataset.resources), initial_length + 1)
464
464
 
465
+ def test_dataset_api_update_private(self):
466
+ user = self.login()
467
+ dataset = DatasetFactory(owner=user, private=True)
468
+ data = dataset.to_dict()
469
+ data['description'] = 'new description'
470
+ del data['private']
471
+
472
+ response = self.put(url_for('api.dataset', dataset=dataset), data)
473
+ self.assert200(response)
474
+ dataset.reload()
475
+ self.assertEqual(dataset.description, 'new description')
476
+ self.assertEqual(dataset.private, True)
477
+
478
+ data['private'] = None
479
+ response = self.put(url_for('api.dataset', dataset=dataset), data)
480
+ self.assert200(response)
481
+ dataset.reload()
482
+ self.assertEqual(dataset.private, False)
483
+
484
+ data['private'] = True
485
+ response = self.put(url_for('api.dataset', dataset=dataset), data)
486
+ self.assert200(response)
487
+ dataset.reload()
488
+ self.assertEqual(dataset.private, True)
489
+
490
+
491
+
465
492
  def test_dataset_api_update_new_resource_with_extras(self):
466
493
  '''It should update a dataset with a new resource with extras'''
467
494
  user = self.login()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: udata
3
- Version: 7.0.5.dev27829
3
+ Version: 7.0.5.dev27885
4
4
  Summary: Open data portal
5
5
  Home-page: https://github.com/opendatateam/udata
6
6
  Author: Opendata Team
@@ -41,6 +41,7 @@ Requires-Dist: certifi ==2021.5.30
41
41
  Requires-Dist: cffi ==1.14.6
42
42
  Requires-Dist: chardet ==3.0.4
43
43
  Requires-Dist: click ==8.0.0
44
+ Requires-Dist: colorama ==0.4.6
44
45
  Requires-Dist: cryptography ==2.8
45
46
  Requires-Dist: dnspython ==2.1.0
46
47
  Requires-Dist: email-validator ==1.1.3
@@ -63,6 +64,7 @@ Requires-Dist: flask-sitemap ==0.3.0
63
64
  Requires-Dist: flask-storage ==1.3.2
64
65
  Requires-Dist: flask-wtf ==1.0.1
65
66
  Requires-Dist: geojson ==2.5.0
67
+ Requires-Dist: geomet ==1.1.0
66
68
  Requires-Dist: html2text ==2019.9.26
67
69
  Requires-Dist: idna ==2.10
68
70
  Requires-Dist: importlib-metadata ==6.0.0
@@ -136,6 +138,8 @@ It is collectively taken care of by members of the
136
138
 
137
139
  ## Current (in progress)
138
140
 
141
+ - Add spatial coverage harvesting [#2959](https://github.com/opendatateam/udata/pull/2959)
142
+ - Fix: updating a dataset without `private` do not reset `private` to `False`, the previous saved value is kept [#2955](https://github.com/opendatateam/udata/pull/2955)
139
143
  - Fix: return the correct error when no `Content-Type` is sent instead of 500 [#2967](https://github.com/opendatateam/udata/pull/2967)
140
144
  - Improve documentation for API errors [#2952](https://github.com/opendatateam/udata/pull/2965)
141
145
 
@@ -90,7 +90,7 @@ udata/core/dataset/forms.py,sha256=auVYxLrPMdtvf2uhgEpJviHiQOSfLpBJdpZ3dXwcjNs,6
90
90
  udata/core/dataset/models.py,sha256=SK16LJP_vlSkeGrLJTFbHFNc9iHWwM6_A6DOT0SX5D4,39609
91
91
  udata/core/dataset/permissions.py,sha256=3F2J7le3_rEYNhh88o3hSRWHAAt01_yHJM6RPmvCrRo,1090
92
92
  udata/core/dataset/preview.py,sha256=puPKT3fBD7ezAcT6owh0JK1_rGNDFZOqgT223qGn3LY,2597
93
- udata/core/dataset/rdf.py,sha256=lVON8z1aNgMe-tyIL14HbSbr3h-CAOVDtFy8DkPh9fA,19817
93
+ udata/core/dataset/rdf.py,sha256=7IguXzHgNcmbGY9FtiqjZ1Ju8wDxD6ahdvTj-5OzNgA,21476
94
94
  udata/core/dataset/search.py,sha256=LOHtOJYZJDPJ5S_Ch7QmmvInpw8aysmNlzbAWbMq9d0,5329
95
95
  udata/core/dataset/signals.py,sha256=TK6dfrOUitZZkGGOh6XmhYqYvIjzZpI70JTLV4k-JRM,161
96
96
  udata/core/dataset/tasks.py,sha256=VB1sQ6Fwbax46IRLGyZUDPGgGOWBYrzAlKzV3npDCyM,8412
@@ -243,7 +243,7 @@ udata/features/transfer/models.py,sha256=YjX0O53DQS8jUU9pb6hFCsBx-eo8g8DOAD7EHZM
243
243
  udata/features/transfer/notifications.py,sha256=oh_uP0XlEEeT7747A292WkjAjAyO4d0YK28oBICN24Y,1003
244
244
  udata/features/transfer/permissions.py,sha256=-iEgQkIfLYDGarhDVp3TMas4ABl_Pc4KJTSP8pcewws,953
245
245
  udata/forms/__init__.py,sha256=ZxakXdJMwsM_YFT96Z2X24J5YpbpnP_VZ_VEh15gK3w,820
246
- udata/forms/fields.py,sha256=rR32Jw2OO5yCvBJ42iNhKjrccleNGg-Iz5cCokmfgHE,28783
246
+ udata/forms/fields.py,sha256=WTCAc4KVPS6EanpUPuan_reDM9gwx4K2wdvJBxu_pTY,29129
247
247
  udata/forms/validators.py,sha256=EqCJloDOR3BonrR34N_ZaMGBXr0iuliDc82khc98e20,2816
248
248
  udata/forms/widgets.py,sha256=P-D3uYfNH5OhAa-SqNoXROg_DuDlnpv_DaO_e4LcJ5I,1380
249
249
  udata/frontend/__init__.py,sha256=Xc71TI6a8b_QR_wqEOc1tty2y1CwHVbV4tS04nElme0,3494
@@ -269,7 +269,7 @@ udata/harvest/tests/factories.py,sha256=CbQORC1OJ1_Agtv_3LjCXysNumjMYlROwZPSEAHo
269
269
  udata/harvest/tests/test_actions.py,sha256=7xSpouCAcf5p_bd38zHCyPN7sKWUUZXA7IlpI-yNVrQ,27603
270
270
  udata/harvest/tests/test_api.py,sha256=QXhseHfnkBEmMbIJzroMdDYGLDj6Njal1s-2sn0xhEM,14888
271
271
  udata/harvest/tests/test_base_backend.py,sha256=JA8Df1Eu-lEPLZfxyK81bsmT6exOjV_3PtKHJekAp5g,12092
272
- udata/harvest/tests/test_dcat_backend.py,sha256=3n_nI2Of8M1kq4nD9oGgWqSeOIaxQXBrMqi6e8lBlCQ,23930
272
+ udata/harvest/tests/test_dcat_backend.py,sha256=8bdpPMh9WsnUDpO19ZoMHfUnU1_fe8Zl_hLSntFwXwI,24761
273
273
  udata/harvest/tests/test_filters.py,sha256=V2HFZlexIJa6r1DX6g2ktvIgjg4gSY11QPfPOd3_Oug,2370
274
274
  udata/harvest/tests/test_models.py,sha256=p2VazyrPXSArBuf8Kf19TGPcQ86SnOGCGmvjcMOw0s0,924
275
275
  udata/harvest/tests/test_notifications.py,sha256=ZwtwioittW3XcZc0x6zbHjs1dVaAxPytlVymnJa5w0E,817
@@ -278,7 +278,7 @@ udata/harvest/tests/csw_dcat/geonetworkv4-page-1.xml,sha256=k2pKidlQvJpoltGFm9HN
278
278
  udata/harvest/tests/csw_dcat/geonetworkv4-page-3.xml,sha256=fsN0E4TVd_ts-sYA612yBP-gRAwpyQWqJdNm7ohczbs,20945
279
279
  udata/harvest/tests/csw_dcat/geonetworkv4-page-5.xml,sha256=0VmPp1kspik7YAmOFyr-3yJLzWGA6kuQp_x_w-W385o,21213
280
280
  udata/harvest/tests/dcat/bnodes.jsonld,sha256=Leqny-ccp30564yojQYYckw_HKbhR0f5qUCaavc2ruE,7964
281
- udata/harvest/tests/dcat/bnodes.xml,sha256=nltHV8RtvitU6OiwX6CjGtaKNlvzJZY0IAO3CmOFmak,8562
281
+ udata/harvest/tests/dcat/bnodes.xml,sha256=KHrVtHiHrWLIT7vxSK7xpYlClCWSWvczeOp-QzzBZVc,9128
282
282
  udata/harvest/tests/dcat/catalog.xml,sha256=pBVSNZzA4gkgxHCttrjuBBVSumLFgXgvtSgnHr0ybk4,9239
283
283
  udata/harvest/tests/dcat/flat.jsonld,sha256=BAw08MDhtW9Px3q6RAoTIqO_OwJmAwBS9EpC8BY_x98,8459
284
284
  udata/harvest/tests/dcat/geonetwork.xml,sha256=9_pksE74Zzkbgs9okj6hEbo8CJS0FZjEnIdvopKfm7k,7928
@@ -557,7 +557,7 @@ udata/tests/api/__init__.py,sha256=Tz_WigHLDlnJNKOKzEAnJswkKiLtHlIpCE54-wgocgM,9
557
557
  udata/tests/api/test_auth_api.py,sha256=3Zhn2A29poZIcCJ_R9_-LkR3xOFUTw1aTquiZVXQ2F0,20306
558
558
  udata/tests/api/test_base_api.py,sha256=DRX5nuFIj51GFmMIAxUzoW1yiq1apNgr1vS4U4agzeg,2319
559
559
  udata/tests/api/test_contact_points.py,sha256=MJm8B06iaUqIZCqxll3NViFwUCxwqZZ4u9e9s1h8MgU,1056
560
- udata/tests/api/test_datasets_api.py,sha256=i52H9Tg8qKBk2sS9I6v85Zbz3N8Wnx0Wu4Uadz8LjW8,80444
560
+ udata/tests/api/test_datasets_api.py,sha256=kCl55lyWgDxCwkYTa1HVMNlR3GBJiAcwOCkvh1BQzXw,81372
561
561
  udata/tests/api/test_fields.py,sha256=OW85Z5MES5HeWOpapeem8OvR1cIcrqW-xMWpdZO4LZ8,1033
562
562
  udata/tests/api/test_follow_api.py,sha256=0h54P_Dfbo07u6tg0Rbai1WWgWb19ZLN2HGv4oLCWfg,3383
563
563
  udata/tests/api/test_me_api.py,sha256=-JskdyxcbREceC1PxMj9NUs6QBE3YzKa5TXhHIaPy-o,14275
@@ -649,9 +649,9 @@ udata/translations/pt/LC_MESSAGES/udata.mo,sha256=dXTr2zzGPgclSMzAJo4qhOEVHYWYP7
649
649
  udata/translations/pt/LC_MESSAGES/udata.po,sha256=G-MNwE4Gih-4w-xNAjp7PAvQOeW1uyM-27Z6O08_SCc,42104
650
650
  udata/translations/sr/LC_MESSAGES/udata.mo,sha256=5bvKeJp9nqk76tZsgbGC2qnbpJws5lODdMcezr6LKbQ,28553
651
651
  udata/translations/sr/LC_MESSAGES/udata.po,sha256=d_uBu93oIsmeewv8QzrB2Z8tmkUXn8juwT5OiySALog,48684
652
- udata-7.0.5.dev27829.dist-info/LICENSE,sha256=V8j_M8nAz8PvAOZQocyRDX7keai8UJ9skgmnwqETmdY,34520
653
- udata-7.0.5.dev27829.dist-info/METADATA,sha256=H3hZ8-KhDGt4cc3IS2hncX4WaOQ_JeLgIlJxo5zq9LE,117925
654
- udata-7.0.5.dev27829.dist-info/WHEEL,sha256=-G_t0oGuE7UD0DrSpVZnq1hHMBV9DD2XkS5v7XpmTnk,110
655
- udata-7.0.5.dev27829.dist-info/entry_points.txt,sha256=ZqIUHhOth0MMQvMIeuhODbUCDwjR-Hvo7PaKrMwTKuQ,384
656
- udata-7.0.5.dev27829.dist-info/top_level.txt,sha256=39OCg-VWFWOq4gCKnjKNu-s3OwFlZIu_dVH8Gl6ndHw,12
657
- udata-7.0.5.dev27829.dist-info/RECORD,,
652
+ udata-7.0.5.dev27885.dist-info/LICENSE,sha256=V8j_M8nAz8PvAOZQocyRDX7keai8UJ9skgmnwqETmdY,34520
653
+ udata-7.0.5.dev27885.dist-info/METADATA,sha256=kcy_O4ue_mJRqxGZ2UdLKoxeigd80IF9igrM5DCOfxI,118247
654
+ udata-7.0.5.dev27885.dist-info/WHEEL,sha256=-G_t0oGuE7UD0DrSpVZnq1hHMBV9DD2XkS5v7XpmTnk,110
655
+ udata-7.0.5.dev27885.dist-info/entry_points.txt,sha256=ZqIUHhOth0MMQvMIeuhODbUCDwjR-Hvo7PaKrMwTKuQ,384
656
+ udata-7.0.5.dev27885.dist-info/top_level.txt,sha256=39OCg-VWFWOq4gCKnjKNu-s3OwFlZIu_dVH8Gl6ndHw,12
657
+ udata-7.0.5.dev27885.dist-info/RECORD,,