udata 9.1.2.dev30355__py2.py3-none-any.whl → 9.1.2.dev30454__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.
- tasks/__init__.py +109 -107
- tasks/helpers.py +18 -18
- udata/__init__.py +4 -4
- udata/admin/views.py +5 -5
- udata/api/__init__.py +111 -134
- udata/api/commands.py +45 -37
- udata/api/errors.py +5 -4
- udata/api/fields.py +23 -21
- udata/api/oauth2.py +55 -74
- udata/api/parsers.py +15 -15
- udata/api/signals.py +1 -1
- udata/api_fields.py +137 -89
- udata/app.py +58 -55
- udata/assets.py +5 -5
- udata/auth/__init__.py +37 -26
- udata/auth/forms.py +23 -15
- udata/auth/helpers.py +1 -1
- udata/auth/mails.py +3 -3
- udata/auth/password_validation.py +19 -15
- udata/auth/views.py +94 -68
- udata/commands/__init__.py +71 -69
- udata/commands/cache.py +7 -7
- udata/commands/db.py +201 -140
- udata/commands/dcat.py +36 -30
- udata/commands/fixtures.py +100 -84
- udata/commands/images.py +21 -20
- udata/commands/info.py +17 -20
- udata/commands/init.py +10 -10
- udata/commands/purge.py +12 -13
- udata/commands/serve.py +41 -29
- udata/commands/static.py +16 -18
- udata/commands/test.py +20 -20
- udata/commands/tests/fixtures.py +26 -24
- udata/commands/worker.py +31 -33
- udata/core/__init__.py +12 -12
- udata/core/activity/__init__.py +0 -1
- udata/core/activity/api.py +59 -49
- udata/core/activity/models.py +28 -26
- udata/core/activity/signals.py +1 -1
- udata/core/activity/tasks.py +16 -10
- udata/core/badges/api.py +6 -6
- udata/core/badges/commands.py +14 -13
- udata/core/badges/fields.py +8 -5
- udata/core/badges/forms.py +7 -4
- udata/core/badges/models.py +16 -31
- udata/core/badges/permissions.py +1 -3
- udata/core/badges/signals.py +2 -2
- udata/core/badges/tasks.py +3 -2
- udata/core/badges/tests/test_commands.py +10 -10
- udata/core/badges/tests/test_model.py +24 -31
- udata/core/contact_point/api.py +19 -18
- udata/core/contact_point/api_fields.py +21 -14
- udata/core/contact_point/factories.py +2 -2
- udata/core/contact_point/forms.py +7 -6
- udata/core/contact_point/models.py +3 -5
- udata/core/dataservices/api.py +26 -21
- udata/core/dataservices/factories.py +13 -11
- udata/core/dataservices/models.py +35 -40
- udata/core/dataservices/permissions.py +4 -4
- udata/core/dataservices/rdf.py +40 -17
- udata/core/dataservices/tasks.py +4 -3
- udata/core/dataset/actions.py +10 -10
- udata/core/dataset/activities.py +21 -23
- udata/core/dataset/api.py +321 -298
- udata/core/dataset/api_fields.py +443 -271
- udata/core/dataset/apiv2.py +305 -229
- udata/core/dataset/commands.py +38 -36
- udata/core/dataset/constants.py +61 -54
- udata/core/dataset/csv.py +70 -74
- udata/core/dataset/events.py +39 -32
- udata/core/dataset/exceptions.py +8 -4
- udata/core/dataset/factories.py +57 -65
- udata/core/dataset/forms.py +87 -63
- udata/core/dataset/models.py +336 -280
- udata/core/dataset/permissions.py +9 -6
- udata/core/dataset/preview.py +15 -17
- udata/core/dataset/rdf.py +156 -122
- udata/core/dataset/search.py +92 -77
- udata/core/dataset/signals.py +1 -1
- udata/core/dataset/tasks.py +63 -54
- udata/core/discussions/actions.py +5 -5
- udata/core/discussions/api.py +124 -120
- udata/core/discussions/factories.py +2 -2
- udata/core/discussions/forms.py +9 -7
- udata/core/discussions/metrics.py +1 -3
- udata/core/discussions/models.py +25 -24
- udata/core/discussions/notifications.py +18 -14
- udata/core/discussions/permissions.py +3 -3
- udata/core/discussions/signals.py +4 -4
- udata/core/discussions/tasks.py +24 -28
- udata/core/followers/api.py +32 -33
- udata/core/followers/models.py +9 -9
- udata/core/followers/signals.py +3 -3
- udata/core/jobs/actions.py +7 -7
- udata/core/jobs/api.py +99 -92
- udata/core/jobs/commands.py +48 -49
- udata/core/jobs/forms.py +11 -11
- udata/core/jobs/models.py +6 -6
- udata/core/metrics/__init__.py +2 -2
- udata/core/metrics/commands.py +34 -30
- udata/core/metrics/models.py +2 -4
- udata/core/metrics/signals.py +1 -1
- udata/core/metrics/tasks.py +3 -3
- udata/core/organization/activities.py +12 -15
- udata/core/organization/api.py +167 -174
- udata/core/organization/api_fields.py +183 -124
- udata/core/organization/apiv2.py +32 -32
- udata/core/organization/commands.py +20 -22
- udata/core/organization/constants.py +11 -11
- udata/core/organization/csv.py +17 -15
- udata/core/organization/factories.py +8 -11
- udata/core/organization/forms.py +32 -26
- udata/core/organization/metrics.py +2 -1
- udata/core/organization/models.py +87 -67
- udata/core/organization/notifications.py +18 -14
- udata/core/organization/permissions.py +10 -11
- udata/core/organization/rdf.py +14 -14
- udata/core/organization/search.py +30 -28
- udata/core/organization/signals.py +7 -7
- udata/core/organization/tasks.py +42 -61
- udata/core/owned.py +38 -27
- udata/core/post/api.py +82 -81
- udata/core/post/constants.py +8 -5
- udata/core/post/factories.py +4 -4
- udata/core/post/forms.py +13 -14
- udata/core/post/models.py +20 -22
- udata/core/post/tests/test_api.py +30 -32
- udata/core/reports/api.py +8 -7
- udata/core/reports/constants.py +1 -3
- udata/core/reports/models.py +10 -10
- udata/core/reuse/activities.py +15 -19
- udata/core/reuse/api.py +123 -126
- udata/core/reuse/api_fields.py +120 -85
- udata/core/reuse/apiv2.py +11 -10
- udata/core/reuse/constants.py +23 -23
- udata/core/reuse/csv.py +18 -18
- udata/core/reuse/factories.py +5 -9
- udata/core/reuse/forms.py +24 -21
- udata/core/reuse/models.py +55 -51
- udata/core/reuse/permissions.py +2 -2
- udata/core/reuse/search.py +49 -46
- udata/core/reuse/signals.py +1 -1
- udata/core/reuse/tasks.py +4 -5
- udata/core/site/api.py +47 -50
- udata/core/site/factories.py +2 -2
- udata/core/site/forms.py +4 -5
- udata/core/site/models.py +94 -63
- udata/core/site/rdf.py +14 -14
- udata/core/spam/api.py +16 -9
- udata/core/spam/constants.py +4 -4
- udata/core/spam/fields.py +13 -7
- udata/core/spam/models.py +27 -20
- udata/core/spam/signals.py +1 -1
- udata/core/spam/tests/test_spam.py +6 -5
- udata/core/spatial/api.py +72 -80
- udata/core/spatial/api_fields.py +73 -58
- udata/core/spatial/commands.py +67 -64
- udata/core/spatial/constants.py +3 -3
- udata/core/spatial/factories.py +37 -54
- udata/core/spatial/forms.py +27 -26
- udata/core/spatial/geoids.py +17 -17
- udata/core/spatial/models.py +43 -47
- udata/core/spatial/tasks.py +2 -1
- udata/core/spatial/tests/test_api.py +115 -130
- udata/core/spatial/tests/test_fields.py +74 -77
- udata/core/spatial/tests/test_geoid.py +22 -22
- udata/core/spatial/tests/test_models.py +5 -7
- udata/core/spatial/translations.py +16 -16
- udata/core/storages/__init__.py +16 -18
- udata/core/storages/api.py +66 -64
- udata/core/storages/tasks.py +7 -7
- udata/core/storages/utils.py +15 -15
- udata/core/storages/views.py +5 -6
- udata/core/tags/api.py +17 -14
- udata/core/tags/csv.py +4 -4
- udata/core/tags/models.py +8 -5
- udata/core/tags/tasks.py +11 -13
- udata/core/tags/views.py +4 -4
- udata/core/topic/api.py +84 -73
- udata/core/topic/apiv2.py +157 -127
- udata/core/topic/factories.py +3 -4
- udata/core/topic/forms.py +12 -14
- udata/core/topic/models.py +14 -19
- udata/core/topic/parsers.py +26 -26
- udata/core/user/activities.py +30 -29
- udata/core/user/api.py +151 -152
- udata/core/user/api_fields.py +132 -100
- udata/core/user/apiv2.py +7 -7
- udata/core/user/commands.py +38 -38
- udata/core/user/factories.py +8 -9
- udata/core/user/forms.py +14 -11
- udata/core/user/metrics.py +2 -2
- udata/core/user/models.py +68 -69
- udata/core/user/permissions.py +4 -5
- udata/core/user/rdf.py +7 -8
- udata/core/user/tasks.py +2 -2
- udata/core/user/tests/test_user_model.py +24 -16
- udata/cors.py +99 -0
- udata/db/tasks.py +2 -1
- udata/entrypoints.py +35 -31
- udata/errors.py +2 -1
- udata/event/values.py +6 -6
- udata/factories.py +2 -2
- udata/features/identicon/api.py +5 -6
- udata/features/identicon/backends.py +48 -55
- udata/features/identicon/tests/test_backends.py +4 -5
- udata/features/notifications/__init__.py +0 -1
- udata/features/notifications/actions.py +9 -9
- udata/features/notifications/api.py +17 -13
- udata/features/territories/__init__.py +12 -10
- udata/features/territories/api.py +14 -15
- udata/features/territories/models.py +23 -28
- udata/features/transfer/actions.py +8 -11
- udata/features/transfer/api.py +84 -77
- udata/features/transfer/factories.py +2 -1
- udata/features/transfer/models.py +11 -12
- udata/features/transfer/notifications.py +19 -15
- udata/features/transfer/permissions.py +5 -5
- udata/forms/__init__.py +5 -2
- udata/forms/fields.py +164 -172
- udata/forms/validators.py +19 -22
- udata/forms/widgets.py +9 -13
- udata/frontend/__init__.py +31 -26
- udata/frontend/csv.py +68 -58
- udata/frontend/markdown.py +40 -44
- udata/harvest/actions.py +89 -77
- udata/harvest/api.py +294 -238
- udata/harvest/backends/__init__.py +4 -4
- udata/harvest/backends/base.py +128 -111
- udata/harvest/backends/dcat.py +80 -66
- udata/harvest/commands.py +56 -60
- udata/harvest/csv.py +8 -8
- udata/harvest/exceptions.py +6 -3
- udata/harvest/filters.py +24 -23
- udata/harvest/forms.py +27 -28
- udata/harvest/models.py +88 -80
- udata/harvest/notifications.py +15 -10
- udata/harvest/signals.py +13 -13
- udata/harvest/tasks.py +11 -10
- udata/harvest/tests/factories.py +23 -24
- udata/harvest/tests/test_actions.py +136 -166
- udata/harvest/tests/test_api.py +220 -214
- udata/harvest/tests/test_base_backend.py +117 -112
- udata/harvest/tests/test_dcat_backend.py +380 -308
- udata/harvest/tests/test_filters.py +33 -22
- udata/harvest/tests/test_models.py +11 -14
- udata/harvest/tests/test_notifications.py +6 -7
- udata/harvest/tests/test_tasks.py +7 -6
- udata/i18n.py +237 -78
- udata/linkchecker/backends.py +5 -11
- udata/linkchecker/checker.py +23 -22
- udata/linkchecker/commands.py +4 -6
- udata/linkchecker/models.py +6 -6
- udata/linkchecker/tasks.py +18 -20
- udata/mail.py +21 -21
- udata/migrations/2020-07-24-remove-s-from-scope-oauth.py +9 -8
- udata/migrations/2020-08-24-add-fs-filename.py +9 -8
- udata/migrations/2020-09-28-update-reuses-datasets-metrics.py +5 -4
- udata/migrations/2020-10-16-migrate-ods-resources.py +9 -10
- udata/migrations/2021-04-08-update-schema-with-new-structure.py +8 -7
- udata/migrations/2021-05-27-fix-default-schema-name.py +7 -6
- udata/migrations/2021-07-05-remove-unused-badges.py +17 -15
- udata/migrations/2021-07-07-update-schema-for-community-resources.py +7 -6
- udata/migrations/2021-08-17-follow-integrity.py +5 -4
- udata/migrations/2021-08-17-harvest-integrity.py +13 -12
- udata/migrations/2021-08-17-oauth2client-integrity.py +5 -4
- udata/migrations/2021-08-17-transfer-integrity.py +5 -4
- udata/migrations/2021-08-17-users-integrity.py +9 -8
- udata/migrations/2021-12-14-reuse-topics.py +7 -6
- udata/migrations/2022-04-21-improve-extension-detection.py +8 -7
- udata/migrations/2022-09-22-clean-inactive-harvest-datasets.py +16 -14
- udata/migrations/2022-10-10-add-fs_uniquifier-to-user-model.py +6 -6
- udata/migrations/2022-10-10-migrate-harvest-extras.py +36 -26
- udata/migrations/2023-02-08-rename-internal-dates.py +46 -28
- udata/migrations/2024-01-29-fix-reuse-and-dataset-with-private-None.py +10 -8
- udata/migrations/2024-03-22-migrate-activity-kwargs-to-extras.py +6 -4
- udata/migrations/2024-06-11-fix-reuse-datasets-references.py +7 -6
- udata/migrations/__init__.py +123 -105
- udata/models/__init__.py +4 -4
- udata/mongo/__init__.py +13 -11
- udata/mongo/badges_field.py +3 -2
- udata/mongo/datetime_fields.py +13 -12
- udata/mongo/document.py +17 -16
- udata/mongo/engine.py +15 -16
- udata/mongo/errors.py +2 -1
- udata/mongo/extras_fields.py +30 -20
- udata/mongo/queryset.py +12 -12
- udata/mongo/slug_fields.py +38 -28
- udata/mongo/taglist_field.py +1 -2
- udata/mongo/url_field.py +5 -5
- udata/mongo/uuid_fields.py +4 -3
- udata/notifications/__init__.py +1 -1
- udata/notifications/mattermost.py +10 -9
- udata/rdf.py +167 -188
- udata/routing.py +40 -45
- udata/search/__init__.py +18 -19
- udata/search/adapter.py +17 -16
- udata/search/commands.py +44 -51
- udata/search/fields.py +13 -20
- udata/search/query.py +23 -18
- udata/search/result.py +9 -10
- udata/sentry.py +21 -19
- udata/settings.py +262 -198
- udata/sitemap.py +8 -6
- udata/storage/s3.py +20 -13
- udata/tags.py +4 -5
- udata/tasks.py +43 -42
- udata/tests/__init__.py +9 -6
- udata/tests/api/__init__.py +8 -6
- udata/tests/api/test_auth_api.py +395 -321
- udata/tests/api/test_base_api.py +33 -35
- udata/tests/api/test_contact_points.py +7 -9
- udata/tests/api/test_dataservices_api.py +211 -158
- udata/tests/api/test_datasets_api.py +823 -812
- udata/tests/api/test_follow_api.py +13 -15
- udata/tests/api/test_me_api.py +95 -112
- udata/tests/api/test_organizations_api.py +301 -339
- udata/tests/api/test_reports_api.py +35 -25
- udata/tests/api/test_reuses_api.py +134 -139
- udata/tests/api/test_swagger.py +5 -5
- udata/tests/api/test_tags_api.py +18 -25
- udata/tests/api/test_topics_api.py +94 -94
- udata/tests/api/test_transfer_api.py +53 -48
- udata/tests/api/test_user_api.py +128 -141
- udata/tests/apiv2/test_datasets.py +290 -198
- udata/tests/apiv2/test_me_api.py +10 -11
- udata/tests/apiv2/test_organizations.py +56 -74
- udata/tests/apiv2/test_swagger.py +5 -5
- udata/tests/apiv2/test_topics.py +69 -87
- udata/tests/cli/test_cli_base.py +8 -8
- udata/tests/cli/test_db_cli.py +21 -19
- udata/tests/dataservice/test_dataservice_tasks.py +8 -12
- udata/tests/dataset/test_csv_adapter.py +44 -35
- udata/tests/dataset/test_dataset_actions.py +2 -3
- udata/tests/dataset/test_dataset_commands.py +7 -8
- udata/tests/dataset/test_dataset_events.py +36 -29
- udata/tests/dataset/test_dataset_model.py +224 -217
- udata/tests/dataset/test_dataset_rdf.py +142 -131
- udata/tests/dataset/test_dataset_tasks.py +15 -15
- udata/tests/dataset/test_resource_preview.py +10 -13
- udata/tests/features/territories/__init__.py +9 -13
- udata/tests/features/territories/test_territories_api.py +71 -91
- udata/tests/forms/test_basic_fields.py +7 -7
- udata/tests/forms/test_current_user_field.py +39 -66
- udata/tests/forms/test_daterange_field.py +31 -39
- udata/tests/forms/test_dict_field.py +28 -26
- udata/tests/forms/test_extras_fields.py +102 -76
- udata/tests/forms/test_form_field.py +8 -8
- udata/tests/forms/test_image_field.py +33 -26
- udata/tests/forms/test_model_field.py +134 -123
- udata/tests/forms/test_model_list_field.py +7 -7
- udata/tests/forms/test_nested_model_list_field.py +117 -79
- udata/tests/forms/test_publish_as_field.py +36 -65
- udata/tests/forms/test_reference_field.py +34 -53
- udata/tests/forms/test_user_forms.py +23 -21
- udata/tests/forms/test_uuid_field.py +6 -10
- udata/tests/frontend/__init__.py +9 -6
- udata/tests/frontend/test_auth.py +7 -6
- udata/tests/frontend/test_csv.py +81 -96
- udata/tests/frontend/test_hooks.py +43 -43
- udata/tests/frontend/test_markdown.py +211 -191
- udata/tests/helpers.py +32 -37
- udata/tests/models.py +2 -2
- udata/tests/organization/test_csv_adapter.py +21 -16
- udata/tests/organization/test_notifications.py +11 -18
- udata/tests/organization/test_organization_model.py +13 -13
- udata/tests/organization/test_organization_rdf.py +29 -22
- udata/tests/organization/test_organization_tasks.py +16 -17
- udata/tests/plugin.py +79 -73
- udata/tests/reuse/test_reuse_model.py +21 -21
- udata/tests/reuse/test_reuse_task.py +11 -13
- udata/tests/search/__init__.py +11 -12
- udata/tests/search/test_adapter.py +60 -70
- udata/tests/search/test_query.py +16 -16
- udata/tests/search/test_results.py +10 -7
- udata/tests/site/test_site_api.py +11 -16
- udata/tests/site/test_site_metrics.py +20 -30
- udata/tests/site/test_site_model.py +4 -5
- udata/tests/site/test_site_rdf.py +94 -78
- udata/tests/test_activity.py +17 -17
- udata/tests/test_cors.py +62 -0
- udata/tests/test_discussions.py +292 -299
- udata/tests/test_i18n.py +37 -40
- udata/tests/test_linkchecker.py +91 -85
- udata/tests/test_mail.py +13 -17
- udata/tests/test_migrations.py +219 -180
- udata/tests/test_model.py +164 -157
- udata/tests/test_notifications.py +17 -17
- udata/tests/test_owned.py +14 -14
- udata/tests/test_rdf.py +25 -23
- udata/tests/test_routing.py +89 -93
- udata/tests/test_storages.py +137 -128
- udata/tests/test_tags.py +44 -46
- udata/tests/test_topics.py +7 -7
- udata/tests/test_transfer.py +42 -49
- udata/tests/test_uris.py +160 -161
- udata/tests/test_utils.py +79 -71
- udata/tests/user/test_user_rdf.py +5 -9
- udata/tests/workers/test_jobs_commands.py +57 -58
- udata/tests/workers/test_tasks_routing.py +23 -29
- udata/tests/workers/test_workers_api.py +125 -131
- udata/tests/workers/test_workers_helpers.py +6 -6
- udata/tracking.py +4 -6
- udata/uris.py +45 -46
- udata/utils.py +68 -66
- udata/wsgi.py +1 -1
- {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/METADATA +7 -3
- udata-9.1.2.dev30454.dist-info/RECORD +706 -0
- udata-9.1.2.dev30355.dist-info/RECORD +0 -704
- {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/LICENSE +0 -0
- {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/WHEEL +0 -0
- {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/entry_points.txt +0 -0
- {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/top_level.txt +0 -0
|
@@ -6,22 +6,25 @@ from flask import current_app
|
|
|
6
6
|
from mongoengine import post_save
|
|
7
7
|
|
|
8
8
|
from udata.app import cache
|
|
9
|
-
from udata.models import db, Dataset, License, ResourceSchema, Schema
|
|
10
9
|
from udata.core.dataset.constants import LEGACY_FREQUENCIES, UPDATE_FREQUENCIES
|
|
11
|
-
from udata.core.dataset.models import HarvestDatasetMetadata, HarvestResourceMetadata
|
|
12
|
-
from udata.core.dataset.factories import (
|
|
13
|
-
ResourceFactory, DatasetFactory, CommunityResourceFactory, LicenseFactory, ResourceSchemaMockData
|
|
14
|
-
)
|
|
15
10
|
from udata.core.dataset.exceptions import (
|
|
16
|
-
|
|
11
|
+
SchemasCacheUnavailableException,
|
|
12
|
+
SchemasCatalogNotFoundException,
|
|
13
|
+
)
|
|
14
|
+
from udata.core.dataset.factories import (
|
|
15
|
+
CommunityResourceFactory,
|
|
16
|
+
DatasetFactory,
|
|
17
|
+
LicenseFactory,
|
|
18
|
+
ResourceFactory,
|
|
19
|
+
ResourceSchemaMockData,
|
|
17
20
|
)
|
|
21
|
+
from udata.core.dataset.models import HarvestDatasetMetadata, HarvestResourceMetadata
|
|
18
22
|
from udata.core.user.factories import UserFactory
|
|
23
|
+
from udata.models import Dataset, License, ResourceSchema, Schema, db
|
|
24
|
+
from udata.tests.helpers import assert_emit, assert_equal_dates, assert_not_emit
|
|
19
25
|
from udata.utils import faker
|
|
20
|
-
from udata.tests.helpers import (
|
|
21
|
-
assert_emit, assert_not_emit, assert_equal_dates
|
|
22
|
-
)
|
|
23
26
|
|
|
24
|
-
pytestmark = pytest.mark.usefixtures(
|
|
27
|
+
pytestmark = pytest.mark.usefixtures("clean_db")
|
|
25
28
|
|
|
26
29
|
|
|
27
30
|
class DatasetModelTest:
|
|
@@ -71,13 +74,13 @@ class DatasetModelTest:
|
|
|
71
74
|
dataset = DatasetFactory(owner=user, resources=[resource])
|
|
72
75
|
expected_signals = (Dataset.on_resource_updated,)
|
|
73
76
|
|
|
74
|
-
resource.description =
|
|
77
|
+
resource.description = "New description"
|
|
75
78
|
|
|
76
79
|
with assert_emit(*expected_signals):
|
|
77
80
|
dataset.update_resource(resource)
|
|
78
81
|
assert len(dataset.resources) == 1
|
|
79
82
|
assert dataset.resources[0].id == resource.id
|
|
80
|
-
assert dataset.resources[0].description ==
|
|
83
|
+
assert dataset.resources[0].description == "New description"
|
|
81
84
|
|
|
82
85
|
def test_update_resource_missing_checksum_type(self):
|
|
83
86
|
user = UserFactory()
|
|
@@ -127,149 +130,155 @@ class DatasetModelTest:
|
|
|
127
130
|
assert dataset.next_update is None
|
|
128
131
|
|
|
129
132
|
def test_next_update_hourly(self):
|
|
130
|
-
dataset = DatasetFactory(frequency=
|
|
131
|
-
assert_equal_dates(dataset.next_update,
|
|
132
|
-
datetime.utcnow() + timedelta(hours=1))
|
|
133
|
+
dataset = DatasetFactory(frequency="hourly")
|
|
134
|
+
assert_equal_dates(dataset.next_update, datetime.utcnow() + timedelta(hours=1))
|
|
133
135
|
|
|
134
|
-
@pytest.mark.parametrize(
|
|
136
|
+
@pytest.mark.parametrize("freq", ["fourTimesADay", "threeTimesADay", "semidaily", "daily"])
|
|
135
137
|
def test_next_update_daily(self, freq):
|
|
136
138
|
dataset = DatasetFactory(frequency=freq)
|
|
137
|
-
assert_equal_dates(dataset.next_update,
|
|
138
|
-
datetime.utcnow() + timedelta(days=1))
|
|
139
|
+
assert_equal_dates(dataset.next_update, datetime.utcnow() + timedelta(days=1))
|
|
139
140
|
|
|
140
|
-
@pytest.mark.parametrize(
|
|
141
|
+
@pytest.mark.parametrize("freq", ["fourTimesAWeek", "threeTimesAWeek", "semiweekly", "weekly"])
|
|
141
142
|
def test_next_update_weekly(self, freq):
|
|
142
143
|
dataset = DatasetFactory(frequency=freq)
|
|
143
|
-
assert_equal_dates(dataset.next_update,
|
|
144
|
-
datetime.utcnow() + timedelta(days=7))
|
|
144
|
+
assert_equal_dates(dataset.next_update, datetime.utcnow() + timedelta(days=7))
|
|
145
145
|
|
|
146
146
|
def test_next_update_biweekly(self):
|
|
147
|
-
dataset = DatasetFactory(frequency=
|
|
148
|
-
assert_equal_dates(dataset.next_update,
|
|
149
|
-
datetime.utcnow() + timedelta(weeks=2))
|
|
147
|
+
dataset = DatasetFactory(frequency="biweekly")
|
|
148
|
+
assert_equal_dates(dataset.next_update, datetime.utcnow() + timedelta(weeks=2))
|
|
150
149
|
|
|
151
150
|
def test_next_update_quarterly(self):
|
|
152
|
-
dataset = DatasetFactory(frequency=
|
|
153
|
-
assert_equal_dates(dataset.next_update,
|
|
154
|
-
datetime.utcnow() + timedelta(days=365/4))
|
|
151
|
+
dataset = DatasetFactory(frequency="quarterly")
|
|
152
|
+
assert_equal_dates(dataset.next_update, datetime.utcnow() + timedelta(days=365 / 4))
|
|
155
153
|
|
|
156
|
-
@pytest.mark.parametrize(
|
|
154
|
+
@pytest.mark.parametrize("freq", ["threeTimesAYear", "semiannual", "annual"])
|
|
157
155
|
def test_next_update_annual(self, freq):
|
|
158
156
|
dataset = DatasetFactory(frequency=freq)
|
|
159
|
-
assert_equal_dates(dataset.next_update,
|
|
160
|
-
datetime.utcnow() + timedelta(days=365))
|
|
157
|
+
assert_equal_dates(dataset.next_update, datetime.utcnow() + timedelta(days=365))
|
|
161
158
|
|
|
162
159
|
def test_next_update_biennial(self):
|
|
163
|
-
dataset = DatasetFactory(frequency=
|
|
164
|
-
assert_equal_dates(dataset.next_update,
|
|
165
|
-
datetime.utcnow() + timedelta(days=365*2))
|
|
160
|
+
dataset = DatasetFactory(frequency="biennial")
|
|
161
|
+
assert_equal_dates(dataset.next_update, datetime.utcnow() + timedelta(days=365 * 2))
|
|
166
162
|
|
|
167
163
|
def test_next_update_triennial(self):
|
|
168
|
-
dataset = DatasetFactory(frequency=
|
|
169
|
-
assert_equal_dates(dataset.next_update,
|
|
170
|
-
datetime.utcnow() + timedelta(days=365*3))
|
|
164
|
+
dataset = DatasetFactory(frequency="triennial")
|
|
165
|
+
assert_equal_dates(dataset.next_update, datetime.utcnow() + timedelta(days=365 * 3))
|
|
171
166
|
|
|
172
167
|
def test_next_update_quinquennial(self):
|
|
173
|
-
dataset = DatasetFactory(frequency=
|
|
174
|
-
assert_equal_dates(dataset.next_update,
|
|
175
|
-
datetime.utcnow() + timedelta(days=365*5))
|
|
168
|
+
dataset = DatasetFactory(frequency="quinquennial")
|
|
169
|
+
assert_equal_dates(dataset.next_update, datetime.utcnow() + timedelta(days=365 * 5))
|
|
176
170
|
|
|
177
|
-
@pytest.mark.parametrize(
|
|
171
|
+
@pytest.mark.parametrize("freq", ["continuous", "punctual", "irregular", "unknown"])
|
|
178
172
|
def test_next_update_undefined(self, freq):
|
|
179
173
|
dataset = DatasetFactory(frequency=freq)
|
|
180
174
|
assert dataset.next_update is None
|
|
181
175
|
|
|
182
176
|
def test_quality_default(self):
|
|
183
|
-
dataset = DatasetFactory(description=
|
|
177
|
+
dataset = DatasetFactory(description="")
|
|
184
178
|
assert dataset.quality == {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
179
|
+
"license": False,
|
|
180
|
+
"temporal_coverage": False,
|
|
181
|
+
"spatial": False,
|
|
182
|
+
"update_frequency": False,
|
|
183
|
+
"dataset_description_quality": False,
|
|
184
|
+
"score": 0,
|
|
191
185
|
}
|
|
192
186
|
|
|
193
|
-
@pytest.mark.parametrize(
|
|
187
|
+
@pytest.mark.parametrize("freq", UPDATE_FREQUENCIES)
|
|
194
188
|
def test_quality_frequency_update(self, freq):
|
|
195
|
-
dataset = DatasetFactory(description=
|
|
196
|
-
if freq ==
|
|
197
|
-
assert dataset.quality[
|
|
198
|
-
assert
|
|
189
|
+
dataset = DatasetFactory(description="", frequency=freq)
|
|
190
|
+
if freq == "unknown":
|
|
191
|
+
assert dataset.quality["update_frequency"] is False
|
|
192
|
+
assert "update_fulfilled_in_time" not in dataset.quality
|
|
199
193
|
return
|
|
200
|
-
assert dataset.quality[
|
|
201
|
-
assert dataset.quality[
|
|
202
|
-
assert dataset.quality[
|
|
194
|
+
assert dataset.quality["update_frequency"] is True
|
|
195
|
+
assert dataset.quality["update_fulfilled_in_time"] is True
|
|
196
|
+
assert dataset.quality["score"] == Dataset.normalize_score(2)
|
|
203
197
|
|
|
204
198
|
def test_quality_frequency_update_one_day_late(self):
|
|
205
199
|
dataset = DatasetFactory(
|
|
206
|
-
description=
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
assert dataset.quality[
|
|
200
|
+
description="",
|
|
201
|
+
frequency="daily",
|
|
202
|
+
last_modified_internal=datetime.utcnow() - timedelta(days=1, hours=1),
|
|
203
|
+
)
|
|
204
|
+
assert dataset.quality["update_frequency"] is True
|
|
205
|
+
assert dataset.quality["update_fulfilled_in_time"] is True
|
|
206
|
+
assert dataset.quality["score"] == Dataset.normalize_score(2)
|
|
211
207
|
|
|
212
208
|
def test_quality_frequency_update_two_days_late(self):
|
|
213
209
|
dataset = DatasetFactory(
|
|
214
|
-
description=
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
assert dataset.quality[
|
|
210
|
+
description="",
|
|
211
|
+
frequency="daily",
|
|
212
|
+
last_modified_internal=datetime.utcnow() - timedelta(days=2, hours=1),
|
|
213
|
+
)
|
|
214
|
+
assert dataset.quality["update_frequency"] is True
|
|
215
|
+
assert dataset.quality["update_fulfilled_in_time"] is False
|
|
216
|
+
assert dataset.quality["score"] == Dataset.normalize_score(1)
|
|
219
217
|
|
|
220
218
|
def test_quality_description_length(self):
|
|
221
|
-
dataset = DatasetFactory(
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
dataset
|
|
225
|
-
assert dataset.quality[
|
|
226
|
-
|
|
219
|
+
dataset = DatasetFactory(
|
|
220
|
+
description="a" * (current_app.config.get("QUALITY_DESCRIPTION_LENGTH") - 1)
|
|
221
|
+
)
|
|
222
|
+
assert dataset.quality["dataset_description_quality"] is False
|
|
223
|
+
assert dataset.quality["score"] == 0
|
|
224
|
+
dataset = DatasetFactory(
|
|
225
|
+
description="a" * (current_app.config.get("QUALITY_DESCRIPTION_LENGTH") + 1)
|
|
226
|
+
)
|
|
227
|
+
assert dataset.quality["dataset_description_quality"] is True
|
|
228
|
+
assert dataset.quality["score"] == Dataset.normalize_score(1)
|
|
227
229
|
|
|
228
230
|
def test_quality_has_open_formats(self):
|
|
229
|
-
dataset = DatasetFactory(
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
231
|
+
dataset = DatasetFactory(
|
|
232
|
+
description="",
|
|
233
|
+
)
|
|
234
|
+
dataset.add_resource(ResourceFactory(format="pdf"))
|
|
235
|
+
assert not dataset.quality["has_open_format"]
|
|
236
|
+
assert dataset.quality["score"] == Dataset.normalize_score(2)
|
|
233
237
|
|
|
234
238
|
def test_quality_has_opened_formats(self):
|
|
235
|
-
dataset = DatasetFactory(
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
239
|
+
dataset = DatasetFactory(
|
|
240
|
+
description="",
|
|
241
|
+
)
|
|
242
|
+
dataset.add_resource(ResourceFactory(format="pdf"))
|
|
243
|
+
dataset.add_resource(ResourceFactory(format="csv"))
|
|
244
|
+
assert dataset.quality["has_open_format"]
|
|
245
|
+
assert dataset.quality["score"] == Dataset.normalize_score(3)
|
|
240
246
|
|
|
241
247
|
def test_quality_has_undefined_and_closed_format(self):
|
|
242
|
-
dataset = DatasetFactory(
|
|
248
|
+
dataset = DatasetFactory(
|
|
249
|
+
description="",
|
|
250
|
+
)
|
|
243
251
|
dataset.add_resource(ResourceFactory(format=None))
|
|
244
|
-
dataset.add_resource(ResourceFactory(format=
|
|
245
|
-
assert not dataset.quality[
|
|
246
|
-
assert dataset.quality[
|
|
252
|
+
dataset.add_resource(ResourceFactory(format="xls"))
|
|
253
|
+
assert not dataset.quality["has_open_format"]
|
|
254
|
+
assert dataset.quality["score"] == Dataset.normalize_score(2)
|
|
247
255
|
|
|
248
256
|
def test_quality_all(self):
|
|
249
257
|
user = UserFactory()
|
|
250
|
-
dataset = DatasetFactory(
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
258
|
+
dataset = DatasetFactory(
|
|
259
|
+
owner=user, frequency="weekly", tags=["foo", "bar"], description="a" * 42
|
|
260
|
+
)
|
|
261
|
+
dataset.add_resource(ResourceFactory(format="pdf"))
|
|
262
|
+
assert dataset.quality["score"] == Dataset.normalize_score(4)
|
|
254
263
|
assert sorted(dataset.quality.keys()) == [
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
264
|
+
"all_resources_available",
|
|
265
|
+
"dataset_description_quality",
|
|
266
|
+
"has_open_format",
|
|
267
|
+
"has_resources",
|
|
268
|
+
"license",
|
|
269
|
+
"resources_documentation",
|
|
270
|
+
"score",
|
|
271
|
+
"spatial",
|
|
272
|
+
"temporal_coverage",
|
|
273
|
+
"update_frequency",
|
|
274
|
+
"update_fulfilled_in_time",
|
|
266
275
|
]
|
|
267
276
|
|
|
268
277
|
def test_tags_normalized(self):
|
|
269
|
-
tags = [
|
|
278
|
+
tags = [" one another!", " one another!", 'This IS a "tag"…']
|
|
270
279
|
dataset = DatasetFactory(tags=tags)
|
|
271
280
|
assert len(dataset.tags) == 2
|
|
272
|
-
assert dataset.tags[1] ==
|
|
281
|
+
assert dataset.tags[1] == "this-is-a-tag"
|
|
273
282
|
|
|
274
283
|
def test_legacy_frequencies(self):
|
|
275
284
|
for oldFreq, newFreq in LEGACY_FREQUENCIES.items():
|
|
@@ -287,8 +296,8 @@ class DatasetModelTest:
|
|
|
287
296
|
unexpected_signals = Dataset.after_save, Dataset.on_update
|
|
288
297
|
|
|
289
298
|
with assert_not_emit(*unexpected_signals), assert_emit(post_save):
|
|
290
|
-
dataset.title =
|
|
291
|
-
dataset.save(signal_kwargs={
|
|
299
|
+
dataset.title = "New title"
|
|
300
|
+
dataset.save(signal_kwargs={"ignores": ["post_save"]})
|
|
292
301
|
|
|
293
302
|
def test_dataset_without_private(self):
|
|
294
303
|
dataset = DatasetFactory()
|
|
@@ -310,10 +319,10 @@ class ResourceModelTest:
|
|
|
310
319
|
|
|
311
320
|
def test_bad_url(self):
|
|
312
321
|
with pytest.raises(db.ValidationError):
|
|
313
|
-
DatasetFactory(resources=[ResourceFactory(url=
|
|
322
|
+
DatasetFactory(resources=[ResourceFactory(url="not-an-url")])
|
|
314
323
|
|
|
315
324
|
def test_url_is_stripped(self):
|
|
316
|
-
url =
|
|
325
|
+
url = "http://www.somewhere.com/with/spaces/ "
|
|
317
326
|
dataset = DatasetFactory(resources=[ResourceFactory(url=url)])
|
|
318
327
|
assert dataset.resources[0].url == url.strip()
|
|
319
328
|
|
|
@@ -324,8 +333,8 @@ class ResourceModelTest:
|
|
|
324
333
|
unexpected_signals = Dataset.after_save, Dataset.on_update
|
|
325
334
|
|
|
326
335
|
with assert_not_emit(*unexpected_signals), assert_emit(post_save):
|
|
327
|
-
resource.title =
|
|
328
|
-
resource.save(signal_kwargs={
|
|
336
|
+
resource.title = "New title"
|
|
337
|
+
resource.save(signal_kwargs={"ignores": ["post_save"]})
|
|
329
338
|
|
|
330
339
|
|
|
331
340
|
class LicenseModelTest:
|
|
@@ -335,12 +344,12 @@ class LicenseModelTest:
|
|
|
335
344
|
LicenseFactory.create_batch(3)
|
|
336
345
|
|
|
337
346
|
def test_not_found(self):
|
|
338
|
-
found = License.guess(
|
|
347
|
+
found = License.guess("should not be found")
|
|
339
348
|
assert found is None
|
|
340
349
|
|
|
341
350
|
def test_not_found_with_default(self):
|
|
342
351
|
license = LicenseFactory()
|
|
343
|
-
found = License.guess(
|
|
352
|
+
found = License.guess("should not be found", default=license)
|
|
344
353
|
assert found.id == license.id
|
|
345
354
|
|
|
346
355
|
def test_none(self):
|
|
@@ -348,7 +357,7 @@ class LicenseModelTest:
|
|
|
348
357
|
assert found is None
|
|
349
358
|
|
|
350
359
|
def test_empty_string(self):
|
|
351
|
-
found = License.guess(
|
|
360
|
+
found = License.guess("")
|
|
352
361
|
assert found is None
|
|
353
362
|
|
|
354
363
|
def test_exact_match_by_id(self):
|
|
@@ -358,14 +367,14 @@ class LicenseModelTest:
|
|
|
358
367
|
assert license.id == found.id
|
|
359
368
|
|
|
360
369
|
def test_imatch_by_id(self):
|
|
361
|
-
license = LicenseFactory(id=
|
|
370
|
+
license = LicenseFactory(id="CAPS-ID")
|
|
362
371
|
found = License.guess(license.id)
|
|
363
372
|
assert isinstance(found, License)
|
|
364
373
|
assert license.id == found.id
|
|
365
374
|
|
|
366
375
|
def test_exact_match_by_id_with_spaces(self):
|
|
367
376
|
license = LicenseFactory()
|
|
368
|
-
found = License.guess(
|
|
377
|
+
found = License.guess(" {0} ".format(license.id))
|
|
369
378
|
assert isinstance(found, License)
|
|
370
379
|
assert license.id == found.id
|
|
371
380
|
|
|
@@ -376,30 +385,30 @@ class LicenseModelTest:
|
|
|
376
385
|
assert license.id == found.id
|
|
377
386
|
|
|
378
387
|
def test_match_by_url_with_final_slash(self):
|
|
379
|
-
license = LicenseFactory(url=
|
|
380
|
-
found = License.guess(
|
|
388
|
+
license = LicenseFactory(url="https://example.com/license")
|
|
389
|
+
found = License.guess("https://example.com/license/")
|
|
381
390
|
assert isinstance(found, License)
|
|
382
391
|
assert license.id == found.id
|
|
383
392
|
|
|
384
393
|
def test_match_by_url_without_final_slash(self):
|
|
385
|
-
license = LicenseFactory(url=
|
|
386
|
-
found = License.guess(
|
|
394
|
+
license = LicenseFactory(url="https://example.com/license/")
|
|
395
|
+
found = License.guess("https://example.com/license")
|
|
387
396
|
assert isinstance(found, License)
|
|
388
397
|
assert license.id == found.id
|
|
389
398
|
|
|
390
399
|
def test_match_by_url_not_too_fuzzy(self):
|
|
391
|
-
LicenseFactory(url=
|
|
392
|
-
found = License.guess(
|
|
400
|
+
LicenseFactory(url="https://example.com/licensea")
|
|
401
|
+
found = License.guess("https://example.com/licenseb")
|
|
393
402
|
assert found is None
|
|
394
403
|
|
|
395
404
|
def test_match_by_url_scheme_mismatch(self):
|
|
396
|
-
license = LicenseFactory(url=
|
|
397
|
-
found = License.guess(
|
|
405
|
+
license = LicenseFactory(url="https://example.com/license")
|
|
406
|
+
found = License.guess("http://example.com/license")
|
|
398
407
|
assert isinstance(found, License)
|
|
399
408
|
assert license.id == found.id
|
|
400
409
|
|
|
401
410
|
def test_imatch_by_url(self):
|
|
402
|
-
url =
|
|
411
|
+
url = "%s/CAPS.php" % faker.uri()
|
|
403
412
|
license = LicenseFactory(url=url)
|
|
404
413
|
found = License.guess(license.url)
|
|
405
414
|
assert isinstance(found, License)
|
|
@@ -413,16 +422,16 @@ class LicenseModelTest:
|
|
|
413
422
|
assert license.id == found.id
|
|
414
423
|
|
|
415
424
|
def test_imatch_by_alternate_url(self):
|
|
416
|
-
alternate_url =
|
|
425
|
+
alternate_url = "%s/CAPS.php" % faker.uri()
|
|
417
426
|
license = LicenseFactory(alternate_urls=[alternate_url])
|
|
418
427
|
found = License.guess(alternate_url)
|
|
419
428
|
assert isinstance(found, License)
|
|
420
429
|
assert license.id == found.id
|
|
421
430
|
|
|
422
431
|
def test_match_by_alternate_url_scheme_slash_mismatch(self):
|
|
423
|
-
alternate_url =
|
|
432
|
+
alternate_url = "https://example.com/license"
|
|
424
433
|
license = LicenseFactory(alternate_urls=[alternate_url])
|
|
425
|
-
found = License.guess(
|
|
434
|
+
found = License.guess("http://example.com/license/")
|
|
426
435
|
assert isinstance(found, License)
|
|
427
436
|
assert license.id == found.id
|
|
428
437
|
|
|
@@ -440,25 +449,25 @@ class LicenseModelTest:
|
|
|
440
449
|
|
|
441
450
|
def test_exact_match_by_title_with_spaces(self):
|
|
442
451
|
license = LicenseFactory()
|
|
443
|
-
found = License.guess(
|
|
452
|
+
found = License.guess(" {0} ".format(license.title))
|
|
444
453
|
assert isinstance(found, License)
|
|
445
454
|
assert license.id == found.id
|
|
446
455
|
|
|
447
456
|
def test_match_by_title_with_low_edit_distance(self):
|
|
448
|
-
license = LicenseFactory(title=
|
|
449
|
-
found = License.guess(
|
|
457
|
+
license = LicenseFactory(title="License")
|
|
458
|
+
found = License.guess("Licence")
|
|
450
459
|
assert isinstance(found, License)
|
|
451
460
|
assert license.id == found.id
|
|
452
461
|
|
|
453
462
|
def test_match_by_title_with_extra_inner_space(self):
|
|
454
|
-
license = LicenseFactory(title=
|
|
455
|
-
found = License.guess(
|
|
463
|
+
license = LicenseFactory(title="License ODBl")
|
|
464
|
+
found = License.guess("License ODBl") # 2 spaces instead of 1
|
|
456
465
|
assert isinstance(found, License)
|
|
457
466
|
assert license.id == found.id
|
|
458
467
|
|
|
459
468
|
def test_match_by_title_with_mismatching_case(self):
|
|
460
|
-
license = LicenseFactory(title=
|
|
461
|
-
found = License.guess(
|
|
469
|
+
license = LicenseFactory(title="License ODBl")
|
|
470
|
+
found = License.guess("License ODBL")
|
|
462
471
|
assert isinstance(found, License)
|
|
463
472
|
assert license.id == found.id
|
|
464
473
|
|
|
@@ -472,38 +481,38 @@ class LicenseModelTest:
|
|
|
472
481
|
def test_exact_match_by_alternate_title_with_spaces(self):
|
|
473
482
|
alternate_title = faker.sentence()
|
|
474
483
|
license = LicenseFactory(alternate_titles=[alternate_title])
|
|
475
|
-
found = License.guess(
|
|
484
|
+
found = License.guess(" {0} ".format(alternate_title))
|
|
476
485
|
assert isinstance(found, License)
|
|
477
486
|
assert license.id == found.id
|
|
478
487
|
|
|
479
488
|
def test_match_by_alternate_title_with_low_edit_distance(self):
|
|
480
|
-
license = LicenseFactory(alternate_titles=[
|
|
481
|
-
found = License.guess(
|
|
489
|
+
license = LicenseFactory(alternate_titles=["License"])
|
|
490
|
+
found = License.guess("Licence")
|
|
482
491
|
assert isinstance(found, License)
|
|
483
492
|
assert license.id == found.id
|
|
484
493
|
|
|
485
494
|
def test_match_by_alternate_title_with_extra_inner_space(self):
|
|
486
|
-
license = LicenseFactory(alternate_titles=[
|
|
487
|
-
found = License.guess(
|
|
495
|
+
license = LicenseFactory(alternate_titles=["License ODBl"])
|
|
496
|
+
found = License.guess("License ODBl") # 2 spaces instead of 1
|
|
488
497
|
assert isinstance(found, License)
|
|
489
498
|
assert license.id == found.id
|
|
490
499
|
|
|
491
500
|
def test_match_by_alternate_title_with_mismatching_case(self):
|
|
492
|
-
license = LicenseFactory(alternate_titles=[
|
|
493
|
-
found = License.guess(
|
|
501
|
+
license = LicenseFactory(alternate_titles=["License ODBl"])
|
|
502
|
+
found = License.guess("License ODBL")
|
|
494
503
|
assert isinstance(found, License)
|
|
495
504
|
assert license.id == found.id
|
|
496
505
|
|
|
497
506
|
def test_match_by_alternate_title_with_multiple_candidates_from_one_licence(self):
|
|
498
|
-
license = LicenseFactory(alternate_titles=[
|
|
499
|
-
found = License.guess(
|
|
507
|
+
license = LicenseFactory(alternate_titles=["Licence Ouverte v2", "Licence Ouverte v2.0"])
|
|
508
|
+
found = License.guess("Licence Ouverte v2.0")
|
|
500
509
|
assert isinstance(found, License)
|
|
501
510
|
assert license.id == found.id
|
|
502
511
|
|
|
503
512
|
def test_no_with_multiple_alternate_titles_from_different_licences(self):
|
|
504
|
-
LicenseFactory(alternate_titles=[
|
|
505
|
-
LicenseFactory(alternate_titles=[
|
|
506
|
-
found = License.guess(
|
|
513
|
+
LicenseFactory(alternate_titles=["Licence Ouverte v2"])
|
|
514
|
+
LicenseFactory(alternate_titles=["Licence Ouverte v2.0"])
|
|
515
|
+
found = License.guess("Licence Ouverte v2.0")
|
|
507
516
|
assert found is None
|
|
508
517
|
|
|
509
518
|
def test_prioritize_title_over_alternate_title(self):
|
|
@@ -516,61 +525,52 @@ class LicenseModelTest:
|
|
|
516
525
|
|
|
517
526
|
def test_multiple_strings(self):
|
|
518
527
|
license = LicenseFactory()
|
|
519
|
-
found = License.guess(
|
|
528
|
+
found = License.guess("should not match", license.id)
|
|
520
529
|
assert isinstance(found, License)
|
|
521
530
|
assert license.id == found.id
|
|
522
531
|
|
|
523
532
|
|
|
524
533
|
class ResourceSchemaTest:
|
|
525
|
-
@pytest.mark.options(SCHEMA_CATALOG_URL=
|
|
534
|
+
@pytest.mark.options(SCHEMA_CATALOG_URL="https://example.com/notfound")
|
|
526
535
|
def test_resource_schema_objects_404_endpoint(self, rmock):
|
|
527
|
-
rmock.get(
|
|
536
|
+
rmock.get("https://example.com/notfound", status_code=404)
|
|
528
537
|
with pytest.raises(SchemasCatalogNotFoundException):
|
|
529
538
|
ResourceSchema.all()
|
|
530
539
|
|
|
531
|
-
@pytest.mark.options(SCHEMA_CATALOG_URL=
|
|
540
|
+
@pytest.mark.options(SCHEMA_CATALOG_URL="https://example.com/schemas")
|
|
532
541
|
def test_resource_schema_objects_timeout_no_cache(self, client, rmock):
|
|
533
|
-
rmock.get(
|
|
542
|
+
rmock.get("https://example.com/schemas", exc=requests.exceptions.ConnectTimeout)
|
|
534
543
|
with pytest.raises(SchemasCacheUnavailableException):
|
|
535
544
|
ResourceSchema.all()
|
|
536
545
|
|
|
537
|
-
@pytest.mark.options(SCHEMA_CATALOG_URL=
|
|
546
|
+
@pytest.mark.options(SCHEMA_CATALOG_URL="https://example.com/schemas")
|
|
538
547
|
def test_resource_schema_objects(self, app, rmock):
|
|
539
|
-
rmock.get(
|
|
540
|
-
"schemas"
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
"version_name": "1.0.
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
}
|
|
556
|
-
]
|
|
557
|
-
})
|
|
548
|
+
rmock.get(
|
|
549
|
+
"https://example.com/schemas",
|
|
550
|
+
json={
|
|
551
|
+
"schemas": [
|
|
552
|
+
{
|
|
553
|
+
"name": "etalab/schema-irve",
|
|
554
|
+
"title": "Schéma IRVE",
|
|
555
|
+
"versions": [
|
|
556
|
+
{"version_name": "1.0.0"},
|
|
557
|
+
{"version_name": "1.0.1"},
|
|
558
|
+
{"version_name": "1.0.2"},
|
|
559
|
+
],
|
|
560
|
+
}
|
|
561
|
+
]
|
|
562
|
+
},
|
|
563
|
+
)
|
|
558
564
|
|
|
559
565
|
assert ResourceSchema.all() == [
|
|
560
566
|
{
|
|
561
567
|
"name": "etalab/schema-irve",
|
|
562
568
|
"title": "Schéma IRVE",
|
|
563
569
|
"versions": [
|
|
564
|
-
{
|
|
565
|
-
|
|
566
|
-
},
|
|
567
|
-
|
|
568
|
-
"version_name": "1.0.1"
|
|
569
|
-
},
|
|
570
|
-
{
|
|
571
|
-
"version_name": "1.0.2"
|
|
572
|
-
}
|
|
573
|
-
]
|
|
570
|
+
{"version_name": "1.0.0"},
|
|
571
|
+
{"version_name": "1.0.1"},
|
|
572
|
+
{"version_name": "1.0.2"},
|
|
573
|
+
],
|
|
574
574
|
}
|
|
575
575
|
]
|
|
576
576
|
|
|
@@ -578,90 +578,96 @@ class ResourceSchemaTest:
|
|
|
578
578
|
def test_resource_schema_objects_no_catalog_url(self):
|
|
579
579
|
assert ResourceSchema.all() == []
|
|
580
580
|
|
|
581
|
-
@pytest.mark.options(SCHEMA_CATALOG_URL=
|
|
581
|
+
@pytest.mark.options(SCHEMA_CATALOG_URL="https://example.com/schemas")
|
|
582
582
|
def test_resource_schema_objects_w_cache(self, rmock, mocker):
|
|
583
|
-
cache_mock_set = mocker.patch.object(cache,
|
|
583
|
+
cache_mock_set = mocker.patch.object(cache, "set")
|
|
584
584
|
|
|
585
585
|
# fill cache
|
|
586
|
-
rmock.get(
|
|
586
|
+
rmock.get("https://example.com/schemas", json=ResourceSchemaMockData.get_mock_data())
|
|
587
587
|
ResourceSchema.all()
|
|
588
588
|
assert cache_mock_set.called
|
|
589
589
|
|
|
590
|
-
mocker.patch.object(
|
|
591
|
-
|
|
592
|
-
|
|
590
|
+
mocker.patch.object(
|
|
591
|
+
cache, "get", return_value=ResourceSchemaMockData.get_mock_data()["schemas"]
|
|
592
|
+
)
|
|
593
|
+
rmock.get("https://example.com/schemas", status_code=500)
|
|
594
|
+
assert (
|
|
595
|
+
ResourceSchemaMockData.get_all_schemas_from_mock_data(with_datapackage_info=False)
|
|
596
|
+
== ResourceSchema.all()
|
|
597
|
+
)
|
|
593
598
|
assert rmock.call_count == 2
|
|
594
599
|
|
|
595
|
-
@pytest.mark.options(SCHEMA_CATALOG_URL=
|
|
600
|
+
@pytest.mark.options(SCHEMA_CATALOG_URL="https://example.com/schemas")
|
|
596
601
|
def test_resource_schema_validation(self, rmock):
|
|
597
|
-
rmock.get(
|
|
602
|
+
rmock.get("https://example.com/schemas", json=ResourceSchemaMockData.get_mock_data())
|
|
598
603
|
|
|
599
604
|
resource = ResourceFactory()
|
|
600
605
|
|
|
601
|
-
resource.schema = Schema(name=
|
|
606
|
+
resource.schema = Schema(name="etalab/schema-irve-statique")
|
|
602
607
|
resource.validate()
|
|
603
608
|
|
|
604
|
-
resource.schema = Schema(url=
|
|
609
|
+
resource.schema = Schema(url="https://example.com")
|
|
605
610
|
resource.validate()
|
|
606
611
|
|
|
607
|
-
resource.schema = Schema(name=
|
|
612
|
+
resource.schema = Schema(name="some-name", url="https://example.com")
|
|
608
613
|
resource.validate()
|
|
609
614
|
|
|
610
|
-
resource.schema = Schema(name=
|
|
615
|
+
resource.schema = Schema(name="etalab/schema-irve-statique")
|
|
611
616
|
resource.schema.clean(check_schema_in_catalog=True)
|
|
612
617
|
|
|
613
|
-
resource.schema = Schema(url=
|
|
618
|
+
resource.schema = Schema(url="https://example.com")
|
|
614
619
|
resource.schema.clean(check_schema_in_catalog=True)
|
|
615
620
|
|
|
616
|
-
resource.schema = Schema(name=
|
|
621
|
+
resource.schema = Schema(name="some-name", url="https://example.com")
|
|
617
622
|
resource.schema.clean(check_schema_in_catalog=True)
|
|
618
623
|
|
|
619
624
|
# Check that no exception is raised when we do not ask for schema check for schema errors
|
|
620
|
-
resource.schema = Schema(name=
|
|
625
|
+
resource.schema = Schema(name="some-name")
|
|
621
626
|
resource.validate()
|
|
622
627
|
|
|
623
|
-
resource.schema = Schema(name=
|
|
628
|
+
resource.schema = Schema(name="etalab/schema-irve-statique", version="1337.42.0")
|
|
624
629
|
resource.validate()
|
|
625
630
|
|
|
626
631
|
with pytest.raises(db.ValidationError):
|
|
627
|
-
resource.schema = Schema(version=
|
|
632
|
+
resource.schema = Schema(version="2.0.0")
|
|
628
633
|
resource.validate()
|
|
629
634
|
|
|
630
635
|
with pytest.raises(db.ValidationError):
|
|
631
|
-
resource.schema = Schema(name=
|
|
636
|
+
resource.schema = Schema(name="some-name")
|
|
632
637
|
resource.schema.clean(check_schema_in_catalog=True)
|
|
633
638
|
|
|
634
639
|
with pytest.raises(db.ValidationError):
|
|
635
|
-
resource.schema = Schema(name=
|
|
640
|
+
resource.schema = Schema(name="etalab/schema-irve-statique", version="1337.42.0")
|
|
636
641
|
resource.schema.clean(check_schema_in_catalog=True)
|
|
637
642
|
|
|
638
643
|
with pytest.raises(db.ValidationError):
|
|
639
|
-
resource.schema = Schema(version=
|
|
644
|
+
resource.schema = Schema(version="2.0.0")
|
|
640
645
|
resource.schema.clean(check_schema_in_catalog=True)
|
|
641
646
|
|
|
647
|
+
|
|
642
648
|
class HarvestMetadataTest:
|
|
643
649
|
def test_harvest_dataset_metadata_validate_success(self):
|
|
644
650
|
dataset = DatasetFactory()
|
|
645
651
|
|
|
646
652
|
harvest_metadata = HarvestDatasetMetadata(
|
|
647
|
-
backend=
|
|
653
|
+
backend="DCAT",
|
|
648
654
|
created_at=datetime.utcnow(),
|
|
649
655
|
modified_at=datetime.utcnow(),
|
|
650
|
-
source_id=
|
|
651
|
-
remote_id=
|
|
652
|
-
domain=
|
|
656
|
+
source_id="source_id",
|
|
657
|
+
remote_id="remote_id",
|
|
658
|
+
domain="domain.gouv.fr",
|
|
653
659
|
last_update=datetime.utcnow(),
|
|
654
|
-
remote_url=
|
|
655
|
-
uri=
|
|
656
|
-
dct_identifier=
|
|
660
|
+
remote_url="http://domain.gouv.fr/dataset/remote_url",
|
|
661
|
+
uri="http://domain.gouv.fr/dataset/uri",
|
|
662
|
+
dct_identifier="http://domain.gouv.fr/dataset/identifier",
|
|
657
663
|
archived_at=datetime.utcnow(),
|
|
658
|
-
archived=
|
|
664
|
+
archived="not-on-remote",
|
|
659
665
|
)
|
|
660
666
|
dataset.harvest = harvest_metadata
|
|
661
667
|
dataset.save()
|
|
662
668
|
|
|
663
669
|
def test_harvest_dataset_metadata_validation_error(self):
|
|
664
|
-
harvest_metadata = HarvestDatasetMetadata(created_at=
|
|
670
|
+
harvest_metadata = HarvestDatasetMetadata(created_at="maintenant")
|
|
665
671
|
dataset = DatasetFactory()
|
|
666
672
|
dataset.harvest = harvest_metadata
|
|
667
673
|
with pytest.raises(db.ValidationError):
|
|
@@ -670,7 +676,7 @@ class HarvestMetadataTest:
|
|
|
670
676
|
def test_harvest_dataset_metadata_no_validation_dynamic(self):
|
|
671
677
|
# Adding a dynamic field (not defined in HarvestDatasetMetadata) does not raise error
|
|
672
678
|
# at validation time
|
|
673
|
-
harvest_metadata = HarvestDatasetMetadata(dynamic_created_at=
|
|
679
|
+
harvest_metadata = HarvestDatasetMetadata(dynamic_created_at="maintenant")
|
|
674
680
|
dataset = DatasetFactory()
|
|
675
681
|
dataset.harvest = harvest_metadata
|
|
676
682
|
dataset.save()
|
|
@@ -679,8 +685,7 @@ class HarvestMetadataTest:
|
|
|
679
685
|
dataset = DatasetFactory()
|
|
680
686
|
|
|
681
687
|
harvest_metadata = HarvestDatasetMetadata(
|
|
682
|
-
created_at=datetime.utcnow(),
|
|
683
|
-
modified_at=datetime.utcnow()+timedelta(days=1)
|
|
688
|
+
created_at=datetime.utcnow(), modified_at=datetime.utcnow() + timedelta(days=1)
|
|
684
689
|
)
|
|
685
690
|
dataset.harvest = harvest_metadata
|
|
686
691
|
dataset.save()
|
|
@@ -703,13 +708,13 @@ class HarvestMetadataTest:
|
|
|
703
708
|
harvest_metadata = HarvestResourceMetadata(
|
|
704
709
|
created_at=datetime.utcnow(),
|
|
705
710
|
modified_at=datetime.utcnow(),
|
|
706
|
-
uri=
|
|
711
|
+
uri="http://domain.gouv.fr/dataset/uri",
|
|
707
712
|
)
|
|
708
713
|
resource.harvest = harvest_metadata
|
|
709
714
|
resource.validate()
|
|
710
715
|
|
|
711
716
|
def test_harvest_resource_metadata_validation_error(self):
|
|
712
|
-
harvest_metadata = HarvestResourceMetadata(created_at=
|
|
717
|
+
harvest_metadata = HarvestResourceMetadata(created_at="maintenant")
|
|
713
718
|
resource = ResourceFactory()
|
|
714
719
|
resource.harvest = harvest_metadata
|
|
715
720
|
with pytest.raises(db.ValidationError):
|
|
@@ -718,14 +723,16 @@ class HarvestMetadataTest:
|
|
|
718
723
|
def test_harvest_resource_metadata_no_validation_dynamic(self):
|
|
719
724
|
# Adding a dynamic field (not defined in HarvestResourceMetadata) does not raise error
|
|
720
725
|
# at validation time
|
|
721
|
-
harvest_metadata = HarvestResourceMetadata(dynamic_created_at=
|
|
726
|
+
harvest_metadata = HarvestResourceMetadata(dynamic_created_at="maintenant")
|
|
722
727
|
resource = ResourceFactory()
|
|
723
728
|
resource.harvest = harvest_metadata
|
|
724
729
|
resource.validate()
|
|
725
730
|
|
|
726
731
|
def test_harvest_resource_metadata_future_modifed_at(self):
|
|
727
732
|
resource = ResourceFactory()
|
|
728
|
-
harvest_metadata = HarvestResourceMetadata(
|
|
733
|
+
harvest_metadata = HarvestResourceMetadata(
|
|
734
|
+
modified_at=datetime.utcnow() + timedelta(days=1)
|
|
735
|
+
)
|
|
729
736
|
resource.harvest = harvest_metadata
|
|
730
737
|
resource.validate()
|
|
731
738
|
|
|
@@ -740,8 +747,8 @@ class HarvestMetadataTest:
|
|
|
740
747
|
assert resource.last_modified == harvest_metadata.modified_at
|
|
741
748
|
|
|
742
749
|
def test_resource_metadata_extra_modifed_at(self):
|
|
743
|
-
resource = ResourceFactory(filetype=
|
|
744
|
-
resource.extras.update({
|
|
750
|
+
resource = ResourceFactory(filetype="remote")
|
|
751
|
+
resource.extras.update({"analysis:last-modified-at": datetime(2023, 1, 1)})
|
|
745
752
|
resource.validate()
|
|
746
753
|
|
|
747
|
-
assert resource.last_modified == resource.extras[
|
|
754
|
+
assert resource.last_modified == resource.extras["analysis:last-modified-at"]
|