udata 9.1.2.dev30754__py2.py3-none-any.whl → 9.1.4.dev30983__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 (90) hide show
  1. tasks/helpers.py +6 -5
  2. udata/__init__.py +1 -1
  3. udata/api/__init__.py +2 -3
  4. udata/api/commands.py +0 -1
  5. udata/api/fields.py +22 -1
  6. udata/api_fields.py +22 -12
  7. udata/app.py +1 -1
  8. udata/assets.py +1 -1
  9. udata/auth/__init__.py +8 -12
  10. udata/commands/db.py +3 -3
  11. udata/commands/dcat.py +1 -1
  12. udata/commands/fixtures.py +110 -54
  13. udata/commands/init.py +2 -2
  14. udata/commands/tests/test_fixtures.py +71 -0
  15. udata/core/activity/tasks.py +1 -1
  16. udata/core/badges/models.py +0 -2
  17. udata/core/contact_point/api.py +1 -3
  18. udata/core/dataservices/tasks.py +1 -1
  19. udata/core/dataset/actions.py +2 -2
  20. udata/core/dataset/forms.py +0 -2
  21. udata/core/dataset/models.py +12 -10
  22. udata/core/dataset/rdf.py +1 -1
  23. udata/core/discussions/api.py +1 -1
  24. udata/core/discussions/models.py +2 -2
  25. udata/core/discussions/tasks.py +1 -1
  26. udata/core/organization/api.py +3 -4
  27. udata/core/organization/api_fields.py +2 -1
  28. udata/core/organization/apiv2.py +1 -1
  29. udata/core/reports/api.py +11 -0
  30. udata/core/reports/models.py +6 -1
  31. udata/core/reuse/metrics.py +1 -1
  32. udata/core/reuse/permissions.py +2 -1
  33. udata/core/reuse/search.py +2 -2
  34. udata/core/reuse/tasks.py +2 -2
  35. udata/core/spatial/commands.py +3 -3
  36. udata/core/spatial/factories.py +1 -1
  37. udata/core/spatial/forms.py +1 -1
  38. udata/core/spatial/models.py +2 -2
  39. udata/core/spatial/tests/test_models.py +1 -1
  40. udata/core/spatial/translations.py +3 -1
  41. udata/core/user/api.py +4 -4
  42. udata/core/user/metrics.py +1 -1
  43. udata/frontend/__init__.py +1 -1
  44. udata/harvest/actions.py +1 -1
  45. udata/harvest/backends/__init__.py +1 -1
  46. udata/harvest/tasks.py +0 -1
  47. udata/harvest/tests/factories.py +0 -2
  48. udata/harvest/tests/test_base_backend.py +0 -1
  49. udata/harvest/tests/test_dcat_backend.py +16 -17
  50. udata/migrations/2020-07-24-remove-s-from-scope-oauth.py +1 -1
  51. udata/migrations/2021-07-05-remove-unused-badges.py +0 -1
  52. udata/migrations/2023-02-08-rename-internal-dates.py +0 -2
  53. udata/migrations/2024-06-11-fix-reuse-datasets-references.py +0 -1
  54. udata/models/__init__.py +1 -0
  55. udata/routing.py +5 -0
  56. udata/search/commands.py +1 -1
  57. udata/search/query.py +1 -1
  58. udata/sentry.py +11 -2
  59. udata/settings.py +1 -0
  60. udata/tags.py +3 -3
  61. udata/tests/api/test_base_api.py +1 -1
  62. udata/tests/api/test_contact_points.py +4 -4
  63. udata/tests/api/test_datasets_api.py +10 -10
  64. udata/tests/api/test_organizations_api.py +39 -39
  65. udata/tests/api/test_reports_api.py +53 -3
  66. udata/tests/api/test_tags_api.py +2 -2
  67. udata/tests/api/test_transfer_api.py +1 -1
  68. udata/tests/apiv2/test_datasets.py +4 -4
  69. udata/tests/dataset/test_dataset_model.py +3 -3
  70. udata/tests/frontend/__init__.py +0 -2
  71. udata/tests/frontend/test_auth.py +0 -1
  72. udata/tests/organization/test_csv_adapter.py +0 -2
  73. udata/tests/organization/test_notifications.py +3 -3
  74. udata/tests/reuse/test_reuse_model.py +0 -1
  75. udata/tests/site/test_site_rdf.py +1 -3
  76. udata/tests/test_cors.py +0 -3
  77. udata/tests/test_owned.py +4 -4
  78. udata/tests/test_routing.py +1 -1
  79. udata/tests/test_tags.py +1 -1
  80. udata/tests/test_transfer.py +1 -2
  81. udata/tests/workers/test_jobs_commands.py +1 -1
  82. udata/utils.py +15 -14
  83. {udata-9.1.2.dev30754.dist-info → udata-9.1.4.dev30983.dist-info}/METADATA +20 -4
  84. {udata-9.1.2.dev30754.dist-info → udata-9.1.4.dev30983.dist-info}/RECORD +88 -89
  85. udata/commands/tests/fixtures.py +0 -44
  86. udata/tests/features/territories/commands.py +0 -9
  87. {udata-9.1.2.dev30754.dist-info → udata-9.1.4.dev30983.dist-info}/LICENSE +0 -0
  88. {udata-9.1.2.dev30754.dist-info → udata-9.1.4.dev30983.dist-info}/WHEEL +0 -0
  89. {udata-9.1.2.dev30754.dist-info → udata-9.1.4.dev30983.dist-info}/entry_points.txt +0 -0
  90. {udata-9.1.2.dev30754.dist-info → udata-9.1.4.dev30983.dist-info}/top_level.txt +0 -0
@@ -4,12 +4,12 @@ from datetime import datetime
4
4
  from flask import current_app, render_template
5
5
 
6
6
  from udata import i18n
7
- from udata.models import Discussion, Message
7
+ from udata.models import Dataset, Discussion, Message
8
8
 
9
9
  log = logging.getLogger(__name__)
10
10
 
11
11
 
12
- def archive(dataset, comment=False):
12
+ def archive(dataset: Dataset, comment=False) -> None:
13
13
  """Archive a dataset"""
14
14
  if dataset.archived:
15
15
  log.warning("Dataset %s already archived, bumping date", dataset)
@@ -1,5 +1,3 @@
1
- from mongoengine import ValidationError
2
-
3
1
  from udata.core.spatial.forms import SpatialCoverageField
4
2
  from udata.core.storages import resources
5
3
  from udata.forms import ModelForm, fields, validators
@@ -256,8 +256,8 @@ class License(db.Document):
256
256
 
257
257
  if license is None:
258
258
  # Try to single match `slug` with a low Damerau-Levenshtein distance
259
- computed = ((l, rdlevenshtein(l.slug, slug)) for l in cls.objects)
260
- candidates = [l for l, d in computed if d <= MAX_DISTANCE]
259
+ computed = ((license_, rdlevenshtein(license_.slug, slug)) for license_ in cls.objects)
260
+ candidates = [license_ for license_, d in computed if d <= MAX_DISTANCE]
261
261
  # If there is more that one match, we cannot determinate
262
262
  # which one is closer to safely choose between candidates
263
263
  if len(candidates) == 1:
@@ -265,8 +265,10 @@ class License(db.Document):
265
265
 
266
266
  if license is None:
267
267
  # Try to match `title` with a low Damerau-Levenshtein distance
268
- computed = ((l, rdlevenshtein(l.title.lower(), text)) for l in cls.objects)
269
- candidates = [l for l, d in computed if d <= MAX_DISTANCE]
268
+ computed = (
269
+ (license_, rdlevenshtein(license_.title.lower(), text)) for license_ in cls.objects
270
+ )
271
+ candidates = [license_ for license_, d in computed if d <= MAX_DISTANCE]
270
272
  # If there is more that one match, we cannot determinate
271
273
  # which one is closer to safely choose between candidates
272
274
  if len(candidates) == 1:
@@ -275,11 +277,11 @@ class License(db.Document):
275
277
  if license is None:
276
278
  # Try to single match `alternate_titles` with a low Damerau-Levenshtein distance
277
279
  computed = (
278
- (l, rdlevenshtein(cls.slug.slugify(t), slug))
279
- for l in cls.objects
280
- for t in l.alternate_titles
280
+ (license_, rdlevenshtein(cls.slug.slugify(title_), slug))
281
+ for license_ in cls.objects
282
+ for title_ in license_.alternate_titles
281
283
  )
282
- candidates = [l for l, d in computed if d <= MAX_DISTANCE]
284
+ candidates = [license_ for license_, distance_ in computed if distance_ <= MAX_DISTANCE]
283
285
  # If there is more that one license matching, we cannot determinate
284
286
  # which one is closer to safely choose between candidates
285
287
  if len(set(candidates)) == 1:
@@ -998,7 +1000,7 @@ class ResourceSchema(object):
998
1000
  f"Schemas catalog does not exist at {endpoint}"
999
1001
  )
1000
1002
  response.raise_for_status()
1001
- except requests.exceptions.RequestException as e:
1003
+ except requests.exceptions.RequestException:
1002
1004
  log.exception(f"Error while getting schema catalog from {endpoint}")
1003
1005
  schemas = cache.get(cache_key)
1004
1006
  else:
@@ -1006,7 +1008,7 @@ class ResourceSchema(object):
1006
1008
  cache.set(cache_key, schemas)
1007
1009
  # no cached version or no content
1008
1010
  if not schemas:
1009
- log.error(f"No content found inc. from cache for schema catalog")
1011
+ log.error("No content found inc. from cache for schema catalog")
1010
1012
  raise SchemasCacheUnavailableException("No content in cache for schema catalog")
1011
1013
 
1012
1014
  return schemas
udata/core/dataset/rdf.py CHANGED
@@ -387,7 +387,7 @@ def spatial_from_rdf(graph):
387
387
  continue
388
388
 
389
389
  if not polygons:
390
- log.warning(f"No supported types found in the GeoJSON data.")
390
+ log.warning("No supported types found in the GeoJSON data.")
391
391
  return None
392
392
 
393
393
  spatial_coverage = SpatialCoverage(
@@ -152,7 +152,7 @@ class DiscussionAPI(API):
152
152
 
153
153
  @ns.route("/<id>/comments/<int:cidx>/spam", endpoint="discussion_comment_spam")
154
154
  @ns.doc(delete={"id": "unspam"})
155
- class DiscussionSpamAPI(SpamAPIMixin):
155
+ class DiscussionCommentSpamAPI(SpamAPIMixin):
156
156
  def get_model(self, id, cidx):
157
157
  discussion = Discussion.objects.get_or_404(id=id_or_404(id))
158
158
  if len(discussion.discussion) <= cidx:
@@ -20,7 +20,7 @@ class Message(SpamMixin, db.EmbeddedDocument):
20
20
  return [self.content]
21
21
 
22
22
  def spam_report_message(self, breadcrumb):
23
- message = f"Spam potentiel dans le message"
23
+ message = "Spam potentiel dans le message"
24
24
  if self.posted_by:
25
25
  message += f" de [{self.posted_by.fullname}]({self.posted_by.external_url})"
26
26
 
@@ -34,7 +34,7 @@ class Message(SpamMixin, db.EmbeddedDocument):
34
34
  discussion = breadcrumb[0]
35
35
  if not isinstance(discussion, Discussion):
36
36
  log.warning(
37
- f"`spam_report_message` called on message with a breadcrumb not containing a Discussion at index 0.",
37
+ "`spam_report_message` called on message with a breadcrumb not containing a Discussion at index 0.",
38
38
  extra={"breadcrumb": breadcrumb},
39
39
  )
40
40
  return message
@@ -5,7 +5,7 @@ from udata.core.reuse.models import Reuse
5
5
  from udata.i18n import lazy_gettext as _
6
6
  from udata.tasks import connect, get_logger
7
7
 
8
- from .models import Discussion, Message
8
+ from .models import Discussion
9
9
  from .signals import on_discussion_closed, on_new_discussion, on_new_discussion_comment
10
10
 
11
11
  log = get_logger(__name__)
@@ -8,6 +8,8 @@ from udata.api.parsers import ModelApiParser
8
8
  from udata.auth import admin_permission, current_user
9
9
  from udata.core.badges import api as badges_api
10
10
  from udata.core.badges.fields import badge_fields
11
+ from udata.core.contact_point.api import ContactPointApiParser
12
+ from udata.core.contact_point.api_fields import contact_point_page_fields
11
13
  from udata.core.dataset.api import DatasetApiParser
12
14
  from udata.core.dataset.api_fields import dataset_page_fields
13
15
  from udata.core.dataset.models import Dataset
@@ -21,6 +23,7 @@ from udata.core.storages.api import (
21
23
  parse_uploaded_image,
22
24
  uploaded_image_fields,
23
25
  )
26
+ from udata.models import ContactPoint
24
27
  from udata.rdf import RDF_EXTENSIONS, graph_response, negociate_content
25
28
  from udata.utils import multi_to_dict
26
29
 
@@ -207,10 +210,6 @@ class OrganizationBadgeAPI(API):
207
210
  return badges_api.remove(org, badge_kind)
208
211
 
209
212
 
210
- from udata.core.contact_point.api import ContactPointApiParser
211
- from udata.core.contact_point.api_fields import contact_point_page_fields
212
- from udata.models import ContactPoint
213
-
214
213
  contact_point_parser = ContactPointApiParser()
215
214
 
216
215
 
@@ -41,7 +41,8 @@ org_ref_fields = api.inherit(
41
41
  },
42
42
  )
43
43
 
44
- from udata.core.user.api_fields import user_ref_fields # noqa: required
44
+ # This import is not at the top of the file to avoid circular imports
45
+ from udata.core.user.api_fields import user_ref_fields # noqa
45
46
 
46
47
 
47
48
  def check_can_access_email():
@@ -7,7 +7,7 @@ from udata.core.contact_point.api_fields import contact_point_fields
7
7
  from udata.utils import multi_to_dict
8
8
 
9
9
  from .api_fields import member_fields, org_fields, org_page_fields
10
- from .permissions import EditOrganizationPermission, OrganizationPrivatePermission
10
+ from .permissions import EditOrganizationPermission
11
11
  from .search import OrganizationSearch
12
12
 
13
13
  apiv2.inherit("OrganizationPage", org_page_fields)
udata/core/reports/api.py CHANGED
@@ -4,6 +4,7 @@ from flask_login import current_user
4
4
 
5
5
  from udata.api import API, api, fields
6
6
  from udata.api_fields import patch
7
+ from udata.auth import admin_permission
7
8
 
8
9
  from .constants import reports_reasons_translations
9
10
  from .models import Report
@@ -16,6 +17,7 @@ class ReportsAPI(API):
16
17
  @api.doc("list_reports")
17
18
  @api.expect(Report.__index_parser__)
18
19
  @api.marshal_with(Report.__page_fields__)
20
+ @api.secure(admin_permission)
19
21
  def get(self):
20
22
  query = Report.objects
21
23
 
@@ -37,6 +39,15 @@ class ReportsAPI(API):
37
39
  return report, 201
38
40
 
39
41
 
42
+ @ns.route("/<report:report>/", endpoint="report")
43
+ class ReportAPI(API):
44
+ @api.doc("get_report")
45
+ @api.marshal_with(Report.__read_fields__)
46
+ @api.secure(admin_permission)
47
+ def get(self, report):
48
+ return report
49
+
50
+
40
51
  @ns.route("/reasons/", endpoint="reports_reasons")
41
52
  class ReportsReasonsAPI(API):
42
53
  @api.doc("list_reports_reasons")
@@ -3,10 +3,11 @@ from datetime import datetime
3
3
  from bson import DBRef
4
4
  from mongoengine import DO_NOTHING, NULLIFY, signals
5
5
 
6
- from udata.api_fields import field, generate_fields
6
+ from udata.api_fields import field, function_field, generate_fields
7
7
  from udata.core.user.api_fields import user_ref_fields
8
8
  from udata.core.user.models import User
9
9
  from udata.mongo import db
10
+ from udata.uris import endpoint_for
10
11
 
11
12
  from .constants import REPORT_REASONS_CHOICES, REPORTABLE_MODELS
12
13
 
@@ -45,6 +46,10 @@ class Report(db.Document):
45
46
  readonly=True,
46
47
  )
47
48
 
49
+ @function_field(description="Link to the API endpoint for this report")
50
+ def self_api_url(self):
51
+ return endpoint_for("api.report", report=self, _external=True)
52
+
48
53
  @classmethod
49
54
  def mark_as_deleted_soft_delete(cls, sender, document, **kwargs):
50
55
  """
@@ -3,5 +3,5 @@ from udata.models import Reuse
3
3
 
4
4
  @Reuse.on_create.connect
5
5
  @Reuse.on_update.connect
6
- def update_reuses_dataset_metric(reuse, **kwargs):
6
+ def update_reuses_dataset_metric(reuse: Reuse, **kwargs) -> None:
7
7
  reuse.count_datasets()
@@ -3,10 +3,11 @@ from udata.core.organization.permissions import (
3
3
  OrganizationAdminNeed,
4
4
  OrganizationEditorNeed,
5
5
  )
6
+ from udata.core.reuse.models import Reuse
6
7
 
7
8
 
8
9
  class ReuseEditPermission(Permission):
9
- def __init__(self, reuse):
10
+ def __init__(self, reuse: Reuse) -> None:
10
11
  needs = []
11
12
 
12
13
  if reuse.organization:
@@ -38,7 +38,7 @@ class ReuseSearch(ModelSearchAdapter):
38
38
  }
39
39
 
40
40
  @classmethod
41
- def is_indexable(cls, reuse):
41
+ def is_indexable(cls, reuse: Reuse) -> bool:
42
42
  return reuse.deleted is None and len(reuse.datasets) > 0 and not reuse.private
43
43
 
44
44
  @classmethod
@@ -55,7 +55,7 @@ class ReuseSearch(ModelSearchAdapter):
55
55
  return reuses.order_by(sort).skip(offset).limit(args["page_size"]), reuses.count()
56
56
 
57
57
  @classmethod
58
- def serialize(cls, reuse):
58
+ def serialize(cls, reuse: Reuse) -> dict:
59
59
  organization = None
60
60
  owner = None
61
61
  if reuse.organization:
udata/core/reuse/tasks.py CHANGED
@@ -10,7 +10,7 @@ log = get_logger(__name__)
10
10
 
11
11
 
12
12
  @job("purge-reuses")
13
- def purge_reuses(self):
13
+ def purge_reuses(self) -> None:
14
14
  for reuse in Reuse.objects(deleted__ne=None):
15
15
  log.info(f"Purging reuse {reuse}")
16
16
  # Remove followers
@@ -32,7 +32,7 @@ def purge_reuses(self):
32
32
 
33
33
 
34
34
  @task
35
- def notify_new_reuse(reuse_id):
35
+ def notify_new_reuse(reuse_id: int) -> None:
36
36
  reuse = Reuse.objects.get(pk=reuse_id)
37
37
  for dataset in reuse.datasets:
38
38
  if dataset.organization:
@@ -177,8 +177,8 @@ def migrate():
177
177
 
178
178
  level_summary = "\n".join(
179
179
  [
180
- " - {0}: {1}".format(l.id, counter[l.id])
181
- for l in GeoLevel.objects.order_by("admin_level")
180
+ " - {0}: {1}".format(geolevel.id, counter[geolevel.id])
181
+ for geolevel in GeoLevel.objects.order_by("admin_level")
182
182
  ]
183
183
  )
184
184
  summary = "\n".join(
@@ -188,7 +188,7 @@ def migrate():
188
188
  Summary
189
189
  =======
190
190
  Processed {zones} zones in {datasets} datasets:\
191
- """.format(level_summary, **counter)
191
+ """.format(**counter)
192
192
  ),
193
193
  level_summary,
194
194
  ]
@@ -2,7 +2,7 @@ import factory
2
2
  from faker.providers import BaseProvider
3
3
  from geojson.utils import generate_random
4
4
 
5
- from udata.factories import DateRangeFactory, ModelFactory
5
+ from udata.factories import ModelFactory
6
6
  from udata.utils import faker_provider
7
7
 
8
8
  from . import geoids
@@ -62,7 +62,7 @@ class GeomField(Field):
62
62
  self.data = geojson.loads(value)
63
63
  else:
64
64
  self.data = geojson.GeoJSON.to_instance(value)
65
- except:
65
+ except Exception:
66
66
  self.data = None
67
67
  log.exception("Unable to parse GeoJSON")
68
68
  raise ValueError(self.gettext("Not a valid GeoJSON"))
@@ -120,7 +120,7 @@ class GeoZone(WithMetrics, db.Document):
120
120
  @cache.memoize()
121
121
  def get_spatial_granularities(lang):
122
122
  with language(lang):
123
- return [(l.id, _(l.name)) for l in GeoLevel.objects] + [
123
+ return [(geolevel.id, _(geolevel.name)) for geolevel in GeoLevel.objects] + [
124
124
  (id, str(label)) for id, label in BASE_GRANULARITIES
125
125
  ]
126
126
 
@@ -130,7 +130,7 @@ spatial_granularities = LocalProxy(lambda: get_spatial_granularities(get_locale(
130
130
 
131
131
  @cache.cached(timeout=50, key_prefix="admin_levels")
132
132
  def get_spatial_admin_levels():
133
- return dict((l.id, l.admin_level) for l in GeoLevel.objects)
133
+ return dict((geolevel.id, geolevel.admin_level) for geolevel in GeoLevel.objects)
134
134
 
135
135
 
136
136
  admin_levels = LocalProxy(get_spatial_admin_levels)
@@ -2,7 +2,7 @@ from datetime import timedelta
2
2
 
3
3
  from udata.tests import DBTestMixin, TestCase
4
4
 
5
- from ..factories import GeoLevelFactory, GeoZoneFactory
5
+ from ..factories import GeoZoneFactory
6
6
  from ..models import GeoZone, SpatialCoverage
7
7
 
8
8
  A_YEAR = timedelta(days=365)
@@ -1,5 +1,7 @@
1
1
  # Here to force translations by gettext
2
- _ = lambda s: s # noqa: force translations
2
+ def _(s):
3
+ return s # noqa: force translations
4
+
3
5
 
4
6
  TRANSLATIONS = (
5
7
  _("French region"),
udata/core/user/api.py CHANGED
@@ -4,7 +4,6 @@ from slugify import slugify
4
4
  from udata.api import API, api
5
5
  from udata.api.parsers import ModelApiParser
6
6
  from udata.auth import admin_permission
7
- from udata.core import storages
8
7
  from udata.core.dataset.api_fields import community_resource_fields, dataset_fields
9
8
  from udata.core.discussions.actions import discussions_for
10
9
  from udata.core.discussions.api import discussion_fields
@@ -321,9 +320,10 @@ class UserAPI(API):
321
320
  return "", 204
322
321
 
323
322
 
324
- from udata.core.contact_point.api import ContactPointApiParser
325
- from udata.core.contact_point.api_fields import contact_point_page_fields
326
- from udata.models import ContactPoint
323
+ # These imports are not at the top of the file to avoid circular imports
324
+ from udata.core.contact_point.api import ContactPointApiParser # noqa
325
+ from udata.core.contact_point.api_fields import contact_point_page_fields # noqa
326
+ from udata.models import ContactPoint # noqa
327
327
 
328
328
  contact_point_parser = ContactPointApiParser()
329
329
 
@@ -1,6 +1,6 @@
1
1
  from udata.core.followers.signals import on_follow, on_unfollow
2
2
  from udata.core.owned import Owned
3
- from udata.models import Dataset, Reuse, User, db
3
+ from udata.models import Dataset, Reuse, User
4
4
 
5
5
 
6
6
  @Dataset.on_create.connect
@@ -23,7 +23,7 @@ _template_hooks = {}
23
23
 
24
24
 
25
25
  @hook.app_template_global()
26
- def package_version(name):
26
+ def package_version(name: str) -> str:
27
27
  return pkg_resources.get_distribution(name).version
28
28
 
29
29
 
udata/harvest/actions.py CHANGED
@@ -177,7 +177,7 @@ def purge_jobs():
177
177
  bucket = current_app.config.get("HARVEST_GRAPHS_S3_BUCKET")
178
178
  if bucket is None:
179
179
  log.error(
180
- f"Bucket isn't configured anymore, but jobs still exist with external filenames. Could not delete them."
180
+ "Bucket isn't configured anymore, but jobs still exist with external filenames. Could not delete them."
181
181
  )
182
182
  break
183
183
 
@@ -14,4 +14,4 @@ def get_all(app):
14
14
  return get_enabled("udata.harvesters", app)
15
15
 
16
16
 
17
- from .base import BaseBackend, HarvestFeature, HarvestFilter # flake8: noqa
17
+ from .base import BaseBackend, HarvestFeature, HarvestFilter # noqa
udata/harvest/tasks.py CHANGED
@@ -1,4 +1,3 @@
1
- from celery import chord
2
1
  from flask import current_app
3
2
 
4
3
  from udata.tasks import get_logger, job, task
@@ -3,8 +3,6 @@ import pytest
3
3
  from factory.fuzzy import FuzzyChoice
4
4
  from flask.signals import Namespace
5
5
 
6
- from udata.core.dataset.factories import DatasetFactory
7
- from udata.core.dataset.models import Dataset
8
6
  from udata.factories import ModelFactory
9
7
 
10
8
  from .. import backends
@@ -2,7 +2,6 @@ from datetime import datetime, timedelta
2
2
  from urllib.parse import urlparse
3
3
 
4
4
  import pytest
5
- from dateutil.parser import parse
6
5
  from voluptuous import Schema
7
6
 
8
7
  from udata.core.dataset import tasks
@@ -4,7 +4,6 @@ import re
4
4
  import xml.etree.ElementTree as ET
5
5
  from datetime import date
6
6
 
7
- import boto3
8
7
  import pytest
9
8
  from flask import current_app
10
9
 
@@ -245,7 +244,7 @@ class DcatBackendTest:
245
244
 
246
245
  datasets = {d.harvest.dct_identifier: d for d in Dataset.objects}
247
246
 
248
- assert datasets["1"].schema == None
247
+ assert datasets["1"].schema is None
249
248
  resources_by_title = {resource["title"]: resource for resource in datasets["1"].resources}
250
249
 
251
250
  # Schema with wrong version are considered as external. Maybe we could change this in the future
@@ -253,8 +252,8 @@ class DcatBackendTest:
253
252
  resources_by_title["Resource 1-2"].schema.url
254
253
  == "https://schema.data.gouv.fr/schemas/etalab/schema-irve-statique/1337.42.0/schema-statique.json"
255
254
  )
256
- assert resources_by_title["Resource 1-2"].schema.name == None
257
- assert resources_by_title["Resource 1-2"].schema.version == None
255
+ assert resources_by_title["Resource 1-2"].schema.name is None
256
+ assert resources_by_title["Resource 1-2"].schema.version is None
258
257
 
259
258
  assert datasets["2"].schema.name == "RGF93 / Lambert-93 (EPSG:2154)"
260
259
  assert (
@@ -266,17 +265,17 @@ class DcatBackendTest:
266
265
  # Unknown schema are kept as they were provided
267
266
  assert resources_by_title["Resource 2-1"].schema.name == "Example Schema"
268
267
  assert resources_by_title["Resource 2-1"].schema.url == "https://example.org/schema.json"
269
- assert resources_by_title["Resource 2-1"].schema.version == None
268
+ assert resources_by_title["Resource 2-1"].schema.version is None
270
269
 
271
- assert resources_by_title["Resource 2-2"].schema == None
270
+ assert resources_by_title["Resource 2-2"].schema is None
272
271
 
273
- assert datasets["3"].schema == None
272
+ assert datasets["3"].schema is None
274
273
  resources_by_title = {resource["title"]: resource for resource in datasets["3"].resources}
275
274
 
276
275
  # If there is just the URL, and it matches a known schema inside the catalog, only set the name and the version
277
276
  # (discard the URL)
278
277
  assert resources_by_title["Resource 3-1"].schema.name == "etalab/schema-irve-statique"
279
- assert resources_by_title["Resource 3-1"].schema.url == None
278
+ assert resources_by_title["Resource 3-1"].schema.url is None
280
279
  assert resources_by_title["Resource 3-1"].schema.version == "2.2.0"
281
280
 
282
281
  job = HarvestJob.objects.order_by("-id").first()
@@ -321,7 +320,7 @@ class DcatBackendTest:
321
320
 
322
321
  datasets = {d.harvest.dct_identifier: d for d in Dataset.objects}
323
322
 
324
- assert datasets["1"].spatial == None
323
+ assert datasets["1"].spatial is None
325
324
  assert datasets["2"].spatial.geom == {
326
325
  "type": "MultiPolygon",
327
326
  "coordinates": [
@@ -330,7 +329,7 @@ class DcatBackendTest:
330
329
  [[[159, -25.0], [159, -11], [212, -11], [212, -25.0], [159, -25.0]]],
331
330
  ],
332
331
  }
333
- assert datasets["3"].spatial == None
332
+ assert datasets["3"].spatial is None
334
333
 
335
334
  @pytest.mark.options(SCHEMA_CATALOG_URL="https://example.com/schemas")
336
335
  def test_harvest_schemas(self, rmock):
@@ -345,7 +344,7 @@ class DcatBackendTest:
345
344
 
346
345
  datasets = {d.harvest.dct_identifier: d for d in Dataset.objects}
347
346
 
348
- assert datasets["1"].schema == None
347
+ assert datasets["1"].schema is None
349
348
  resources_by_title = {resource["title"]: resource for resource in datasets["1"].resources}
350
349
 
351
350
  # Schema with wrong version are considered as external. Maybe we could change this in the future
@@ -353,8 +352,8 @@ class DcatBackendTest:
353
352
  resources_by_title["Resource 1-2"].schema.url
354
353
  == "https://schema.data.gouv.fr/schemas/etalab/schema-irve-statique/1337.42.0/schema-statique.json"
355
354
  )
356
- assert resources_by_title["Resource 1-2"].schema.name == None
357
- assert resources_by_title["Resource 1-2"].schema.version == None
355
+ assert resources_by_title["Resource 1-2"].schema.name is None
356
+ assert resources_by_title["Resource 1-2"].schema.version is None
358
357
 
359
358
  assert datasets["2"].schema.name == "RGF93 / Lambert-93 (EPSG:2154)"
360
359
  assert (
@@ -366,17 +365,17 @@ class DcatBackendTest:
366
365
  # Unknown schema are kept as they were provided
367
366
  assert resources_by_title["Resource 2-1"].schema.name == "Example Schema"
368
367
  assert resources_by_title["Resource 2-1"].schema.url == "https://example.org/schema.json"
369
- assert resources_by_title["Resource 2-1"].schema.version == None
368
+ assert resources_by_title["Resource 2-1"].schema.version is None
370
369
 
371
- assert resources_by_title["Resource 2-2"].schema == None
370
+ assert resources_by_title["Resource 2-2"].schema is None
372
371
 
373
- assert datasets["3"].schema == None
372
+ assert datasets["3"].schema is None
374
373
  resources_by_title = {resource["title"]: resource for resource in datasets["3"].resources}
375
374
 
376
375
  # If there is just the URL, and it matches a known schema inside the catalog, only set the name and the version
377
376
  # (discard the URL)
378
377
  assert resources_by_title["Resource 3-1"].schema.name == "etalab/schema-irve-statique"
379
- assert resources_by_title["Resource 3-1"].schema.url == None
378
+ assert resources_by_title["Resource 3-1"].schema.url is None
380
379
  assert resources_by_title["Resource 3-1"].schema.version == "2.2.0"
381
380
 
382
381
  def test_simple_nested_attributes(self, rmock):
@@ -18,7 +18,7 @@ def migrate(db):
18
18
  oauth_clients = db.oauth2_client
19
19
  oauth_clients.update_many({}, {"$rename": {"scopes": "scope"}})
20
20
  for client in oauth_clients.find():
21
- if type(client["scope"]) == list:
21
+ if type(client["scope"]) is list:
22
22
  scope_str = " ".join(client["scope"])
23
23
  client["scope"] = scope_str
24
24
  oauth_clients.save(client)
@@ -4,7 +4,6 @@ The purpose here is to update every resource's metadata 'schema' name.
4
4
 
5
5
  import logging
6
6
 
7
- from udata.core.reuse.models import Reuse
8
7
  from udata.models import Dataset, Reuse
9
8
 
10
9
  log = logging.getLogger(__name__)
@@ -6,8 +6,6 @@ import logging
6
6
 
7
7
  from mongoengine.connection import get_db
8
8
 
9
- from udata.models import Dataset
10
-
11
9
  log = logging.getLogger(__name__)
12
10
 
13
11
 
@@ -4,7 +4,6 @@ Add a default topic to all reuses in db
4
4
 
5
5
  import logging
6
6
 
7
- import mongoengine
8
7
  from bson import DBRef
9
8
 
10
9
  from udata.models import Reuse
udata/models/__init__.py CHANGED
@@ -22,6 +22,7 @@ from udata.core.jobs.models import * # noqa
22
22
  from udata.core.tags.models import * # noqa
23
23
  from udata.core.spam.models import * # noqa
24
24
  from udata.core.reports.models import * # noqa
25
+ from udata.core.dataservices.models import * # noqa
25
26
 
26
27
  from udata.features.transfer.models import * # noqa
27
28
  from udata.features.territories.models import * # noqa
udata/routing.py CHANGED
@@ -153,6 +153,10 @@ class ContactPointConverter(ModelConverter):
153
153
  model = models.ContactPoint
154
154
 
155
155
 
156
+ class ReportConverter(ModelConverter):
157
+ model = models.Report
158
+
159
+
156
160
  class TerritoryConverter(PathConverter):
157
161
  DEFAULT_PREFIX = "fr" # TODO: make it a setting parameter
158
162
 
@@ -231,3 +235,4 @@ def init_app(app):
231
235
  app.url_map.converters["post"] = PostConverter
232
236
  app.url_map.converters["territory"] = TerritoryConverter
233
237
  app.url_map.converters["contact_point"] = ContactPointConverter
238
+ app.url_map.converters["report"] = ReportConverter
udata/search/commands.py CHANGED
@@ -93,7 +93,7 @@ def finalize_reindex(models, start):
93
93
  r = requests.post(url, json=payload)
94
94
  r.raise_for_status()
95
95
  except Exception:
96
- log.exception(f"Unable to set alias for index")
96
+ log.exception("Unable to set alias for index")
97
97
 
98
98
  modified_since_reindex = 0
99
99
  for adapter in iter_adapters():