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
udata/commands/db.py
CHANGED
|
@@ -1,87 +1,85 @@
|
|
|
1
1
|
import collections
|
|
2
|
-
from itertools import groupby
|
|
3
2
|
import logging
|
|
4
3
|
import os
|
|
5
4
|
import traceback
|
|
5
|
+
from itertools import groupby
|
|
6
6
|
|
|
7
|
-
from bson import DBRef
|
|
8
7
|
import click
|
|
9
8
|
import mongoengine
|
|
9
|
+
from bson import DBRef
|
|
10
10
|
|
|
11
|
-
from udata import migrations
|
|
11
|
+
from udata import migrations
|
|
12
|
+
from udata import models as core_models
|
|
12
13
|
from udata.api import oauth2 as oauth2_models
|
|
13
|
-
from udata.commands import cli,
|
|
14
|
+
from udata.commands import cli, cyan, echo, green, magenta, red, white, yellow
|
|
14
15
|
from udata.harvest import models as harvest_models
|
|
15
16
|
from udata.mongo import db
|
|
16
17
|
|
|
17
|
-
|
|
18
18
|
# Date format used to for display
|
|
19
|
-
DATE_FORMAT =
|
|
19
|
+
DATE_FORMAT = "%Y-%m-%d %H:%M"
|
|
20
20
|
|
|
21
21
|
log = logging.getLogger(__name__)
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
@cli.group(
|
|
24
|
+
@cli.group("db")
|
|
25
25
|
def grp():
|
|
26
|
-
|
|
26
|
+
"""Database related operations"""
|
|
27
27
|
pass
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
def log_status(migration, status):
|
|
31
|
-
|
|
31
|
+
"""Properly display a migration status line"""
|
|
32
32
|
name = os.path.splitext(migration.filename)[0]
|
|
33
|
-
display =
|
|
34
|
-
log.info(
|
|
33
|
+
display = ":".join((migration.plugin, name)) + " "
|
|
34
|
+
log.info("%s [%s]", "{:.<70}".format(display), status)
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
def status_label(record):
|
|
38
38
|
if record.ok:
|
|
39
39
|
return green(record.last_date.strftime(DATE_FORMAT))
|
|
40
40
|
elif not record.exists():
|
|
41
|
-
return yellow(
|
|
41
|
+
return yellow("Not applied")
|
|
42
42
|
else:
|
|
43
43
|
return red(record.status)
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
def format_output(output, success=True, traceback=None):
|
|
47
|
-
echo(
|
|
47
|
+
echo(" │")
|
|
48
48
|
for level, msg in output:
|
|
49
|
-
echo(
|
|
50
|
-
echo(
|
|
49
|
+
echo(" │ {0}".format(msg))
|
|
50
|
+
echo(" │")
|
|
51
51
|
if traceback:
|
|
52
|
-
for tb in traceback.split(
|
|
53
|
-
echo(
|
|
54
|
-
echo(
|
|
55
|
-
echo(
|
|
56
|
-
echo(
|
|
52
|
+
for tb in traceback.split("\n"):
|
|
53
|
+
echo(" │ {0}".format(tb))
|
|
54
|
+
echo(" │")
|
|
55
|
+
echo(" └──[{0}]".format(green("OK") if success else red("KO")))
|
|
56
|
+
echo("")
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
@grp.command()
|
|
60
60
|
def status():
|
|
61
|
-
|
|
61
|
+
"""Display the database migrations status"""
|
|
62
62
|
for migration in migrations.list_available():
|
|
63
63
|
log_status(migration, status_label(migration.record))
|
|
64
64
|
|
|
65
65
|
|
|
66
66
|
@grp.command()
|
|
67
|
-
@click.option(
|
|
68
|
-
|
|
69
|
-
@click.option('-d', '--dry-run', is_flag=True,
|
|
70
|
-
help='Only print migrations to be applied')
|
|
67
|
+
@click.option("-r", "--record", is_flag=True, help="Only records the migrations")
|
|
68
|
+
@click.option("-d", "--dry-run", is_flag=True, help="Only print migrations to be applied")
|
|
71
69
|
def migrate(record, dry_run=False):
|
|
72
|
-
|
|
70
|
+
"""Perform database migrations"""
|
|
73
71
|
success = True
|
|
74
72
|
for migration in migrations.list_available():
|
|
75
73
|
if migration.record.ok or not success:
|
|
76
|
-
log_status(migration, cyan(
|
|
74
|
+
log_status(migration, cyan("Skipped"))
|
|
77
75
|
else:
|
|
78
|
-
status = magenta(
|
|
76
|
+
status = magenta("Recorded") if record else yellow("Apply")
|
|
79
77
|
log_status(migration, status)
|
|
80
78
|
try:
|
|
81
79
|
output = migration.execute(recordonly=record, dryrun=dry_run)
|
|
82
80
|
except migrations.RollbackError as re:
|
|
83
81
|
format_output(re.migrate_exc.output, False)
|
|
84
|
-
log_status(migration, red(
|
|
82
|
+
log_status(migration, red("Rollback"))
|
|
85
83
|
format_output(re.output, not re.exc)
|
|
86
84
|
success = False
|
|
87
85
|
except migrations.MigrationError as me:
|
|
@@ -93,10 +91,10 @@ def migrate(record, dry_run=False):
|
|
|
93
91
|
|
|
94
92
|
|
|
95
93
|
@grp.command()
|
|
96
|
-
@click.argument(
|
|
97
|
-
@click.argument(
|
|
94
|
+
@click.argument("plugin_or_specs")
|
|
95
|
+
@click.argument("filename", default=None, required=False, metavar="[FILENAME]")
|
|
98
96
|
def unrecord(plugin_or_specs, filename):
|
|
99
|
-
|
|
97
|
+
"""
|
|
100
98
|
Remove a database migration record.
|
|
101
99
|
|
|
102
100
|
\b
|
|
@@ -105,155 +103,202 @@ def unrecord(plugin_or_specs, filename):
|
|
|
105
103
|
- plugin filename.js
|
|
106
104
|
- plugin:filename
|
|
107
105
|
- plugin:fliename.js
|
|
108
|
-
|
|
106
|
+
"""
|
|
109
107
|
migration = migrations.get(plugin_or_specs, filename)
|
|
110
108
|
removed = migration.unrecord()
|
|
111
109
|
if removed:
|
|
112
|
-
log.info(
|
|
110
|
+
log.info("Removed migration %s", migration.label)
|
|
113
111
|
else:
|
|
114
|
-
log.error(
|
|
112
|
+
log.error("Migration not found %s", migration.label)
|
|
115
113
|
|
|
116
114
|
|
|
117
115
|
@grp.command()
|
|
118
|
-
@click.argument(
|
|
119
|
-
@click.argument(
|
|
116
|
+
@click.argument("plugin_or_specs")
|
|
117
|
+
@click.argument("filename", default=None, required=False, metavar="[FILENAME]")
|
|
120
118
|
def info(plugin_or_specs, filename):
|
|
121
|
-
|
|
119
|
+
"""
|
|
122
120
|
Display detailed info about a migration
|
|
123
|
-
|
|
121
|
+
"""
|
|
124
122
|
migration = migrations.get(plugin_or_specs, filename)
|
|
125
123
|
log_status(migration, status_label(migration.record))
|
|
126
124
|
try:
|
|
127
125
|
echo(migration.module.__doc__)
|
|
128
126
|
except migrations.MigrationError:
|
|
129
|
-
echo(yellow(
|
|
127
|
+
echo(yellow("Module not found"))
|
|
130
128
|
|
|
131
|
-
for op in migration.record.get(
|
|
129
|
+
for op in migration.record.get("ops", []):
|
|
132
130
|
display_op(op)
|
|
133
131
|
|
|
134
132
|
|
|
135
133
|
def display_op(op):
|
|
136
|
-
timestamp = white(op[
|
|
137
|
-
label = white(op[
|
|
138
|
-
echo(
|
|
139
|
-
format_output(op[
|
|
134
|
+
timestamp = white(op["date"].strftime(DATE_FORMAT))
|
|
135
|
+
label = white(op["type"].title()) + " "
|
|
136
|
+
echo("{label:.<70} [{date}]".format(label=label, date=timestamp))
|
|
137
|
+
format_output(op["output"], success=op["success"], traceback=op.get("traceback"))
|
|
138
|
+
|
|
140
139
|
|
|
141
140
|
def check_references(models_to_check):
|
|
142
141
|
# Cannot modify local scope from Python… :-(
|
|
143
|
-
class Log:
|
|
142
|
+
class Log:
|
|
143
|
+
errors = []
|
|
144
144
|
|
|
145
145
|
def print_and_save(text: str):
|
|
146
146
|
Log.errors.append(text.strip())
|
|
147
|
-
print(text)
|
|
147
|
+
print(text)
|
|
148
148
|
|
|
149
149
|
errors = collections.defaultdict(int)
|
|
150
150
|
|
|
151
151
|
_models = []
|
|
152
152
|
for models in core_models, harvest_models, oauth2_models:
|
|
153
153
|
_models += [
|
|
154
|
-
elt
|
|
154
|
+
elt
|
|
155
|
+
for _, elt in models.__dict__.items()
|
|
155
156
|
if isinstance(elt, type) and issubclass(elt, (db.Document))
|
|
156
157
|
]
|
|
157
158
|
|
|
158
159
|
references = []
|
|
159
160
|
for model in set(_models):
|
|
160
|
-
if model.__name__ ==
|
|
161
|
-
print(f
|
|
161
|
+
if model.__name__ == "Activity":
|
|
162
|
+
print(f"Skipping Activity model, scheduled for deprecation")
|
|
162
163
|
continue
|
|
163
|
-
if model.__name__ ==
|
|
164
|
-
print(f
|
|
164
|
+
if model.__name__ == "GeoLevel":
|
|
165
|
+
print(f"Skipping GeoLevel model, scheduled for deprecation")
|
|
165
166
|
continue
|
|
166
167
|
|
|
167
168
|
if models_to_check and model.__name__ not in models_to_check:
|
|
168
169
|
continue
|
|
169
170
|
|
|
170
171
|
# find "root" ReferenceField fields
|
|
171
|
-
refs = [
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
172
|
+
refs = [
|
|
173
|
+
elt
|
|
174
|
+
for elt in model._fields.values()
|
|
175
|
+
if isinstance(elt, mongoengine.fields.ReferenceField)
|
|
176
|
+
]
|
|
177
|
+
references += [
|
|
178
|
+
{
|
|
179
|
+
"model": model,
|
|
180
|
+
"repr": f"{model.__name__}.{r.name}",
|
|
181
|
+
"name": r.name,
|
|
182
|
+
"destination": r.document_type.__name__,
|
|
183
|
+
"type": "direct",
|
|
184
|
+
}
|
|
185
|
+
for r in refs
|
|
186
|
+
]
|
|
180
187
|
|
|
181
188
|
# find "root" GenericReferenceField
|
|
182
|
-
refs = [
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
189
|
+
refs = [
|
|
190
|
+
elt
|
|
191
|
+
for elt in model._fields.values()
|
|
192
|
+
if isinstance(elt, mongoengine.fields.GenericReferenceField)
|
|
193
|
+
]
|
|
194
|
+
references += [
|
|
195
|
+
{
|
|
196
|
+
"model": model,
|
|
197
|
+
"repr": f"{model.__name__}.{r.name}",
|
|
198
|
+
"name": r.name,
|
|
199
|
+
"destination": "Generic",
|
|
200
|
+
"type": "direct",
|
|
201
|
+
}
|
|
202
|
+
for r in refs
|
|
203
|
+
]
|
|
191
204
|
|
|
192
205
|
# find ListField with ReferenceField
|
|
193
|
-
list_fields = [
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
206
|
+
list_fields = [
|
|
207
|
+
elt for elt in model._fields.values() if isinstance(elt, mongoengine.fields.ListField)
|
|
208
|
+
]
|
|
209
|
+
list_refs = [
|
|
210
|
+
elt for elt in list_fields if isinstance(elt.field, mongoengine.fields.ReferenceField)
|
|
211
|
+
]
|
|
212
|
+
references += [
|
|
213
|
+
{
|
|
214
|
+
"model": model,
|
|
215
|
+
"repr": f"{model.__name__}.{lr.name}",
|
|
216
|
+
"name": lr.name,
|
|
217
|
+
"destination": lr.field.document_type.__name__,
|
|
218
|
+
"type": "list",
|
|
219
|
+
}
|
|
220
|
+
for lr in list_refs
|
|
221
|
+
]
|
|
204
222
|
|
|
205
223
|
# find ListField w/ EmbeddedDocumentField w/ ReferenceField
|
|
206
|
-
list_embeds = [
|
|
207
|
-
|
|
224
|
+
list_embeds = [
|
|
225
|
+
(elt, elt.field)
|
|
226
|
+
for elt in list_fields
|
|
227
|
+
if isinstance(elt.field, mongoengine.fields.EmbeddedDocumentField)
|
|
228
|
+
]
|
|
208
229
|
for embed, embed_field in list_embeds:
|
|
209
|
-
embed_refs = [
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
230
|
+
embed_refs = [
|
|
231
|
+
elt
|
|
232
|
+
for elt in embed_field.document_type_obj._fields.values()
|
|
233
|
+
if isinstance(elt, mongoengine.fields.ReferenceField)
|
|
234
|
+
]
|
|
235
|
+
references += [
|
|
236
|
+
{
|
|
237
|
+
"model": model,
|
|
238
|
+
"repr": f"{model.__name__}.{embed.name}__{er.name}",
|
|
239
|
+
"name": f"{embed.name}__{er.name}",
|
|
240
|
+
"destination": er.document_type.__name__,
|
|
241
|
+
"type": "embed_list",
|
|
242
|
+
}
|
|
243
|
+
for er in embed_refs
|
|
244
|
+
]
|
|
218
245
|
|
|
219
246
|
# find EmbeddedDocumentField w/ ReferenceField
|
|
220
|
-
embeds = [
|
|
221
|
-
|
|
247
|
+
embeds = [
|
|
248
|
+
elt
|
|
249
|
+
for elt in model._fields.values()
|
|
250
|
+
if isinstance(elt, mongoengine.fields.EmbeddedDocumentField)
|
|
251
|
+
]
|
|
222
252
|
for embed_field in embeds:
|
|
223
|
-
embed_refs = [
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
253
|
+
embed_refs = [
|
|
254
|
+
elt
|
|
255
|
+
for elt in embed_field.document_type_obj._fields.values()
|
|
256
|
+
if isinstance(elt, mongoengine.fields.ReferenceField)
|
|
257
|
+
]
|
|
258
|
+
references += [
|
|
259
|
+
{
|
|
260
|
+
"model": model,
|
|
261
|
+
"repr": f"{model.__name__}.{embed_field.name}__{er.name}",
|
|
262
|
+
"name": f"{embed_field.name}__{er.name}",
|
|
263
|
+
"destination": er.document_type.__name__,
|
|
264
|
+
"type": "embed",
|
|
265
|
+
}
|
|
266
|
+
for er in embed_refs
|
|
267
|
+
]
|
|
232
268
|
|
|
233
269
|
# find EmbeddedDocumentField w/ ListField w/ ReferenceField
|
|
234
270
|
for embed_field in embeds:
|
|
235
|
-
embed_lists = [
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
271
|
+
embed_lists = [
|
|
272
|
+
elt
|
|
273
|
+
for elt in embed_field.document_type_obj._fields.values()
|
|
274
|
+
if isinstance(elt, mongoengine.fields.ListField)
|
|
275
|
+
]
|
|
276
|
+
elists_refs = [
|
|
277
|
+
elt
|
|
278
|
+
for elt in embed_lists
|
|
279
|
+
if isinstance(elt.field, mongoengine.fields.ReferenceField)
|
|
280
|
+
]
|
|
281
|
+
references += [
|
|
282
|
+
{
|
|
283
|
+
"model": model,
|
|
284
|
+
"repr": f"{model.__name__}.{embed_field.name}__{lr.name}",
|
|
285
|
+
"name": f"{embed_field.name}__{lr.name}",
|
|
286
|
+
"destination": lr.field.document_type.__name__,
|
|
287
|
+
"type": "embed_list_ref",
|
|
288
|
+
}
|
|
289
|
+
for lr in elists_refs
|
|
290
|
+
]
|
|
291
|
+
|
|
292
|
+
print("Those references will be inspected:")
|
|
248
293
|
for reference in references:
|
|
249
294
|
print(f'- {reference["repr"]}({reference["destination"]}) — {reference["type"]}')
|
|
250
|
-
print(
|
|
295
|
+
print("")
|
|
251
296
|
|
|
252
297
|
total = 0
|
|
253
298
|
for model, model_references in groupby(references, lambda i: i["model"]):
|
|
254
299
|
model_references = list(model_references)
|
|
255
300
|
count = model.objects.count()
|
|
256
|
-
print(f
|
|
301
|
+
print(f"- doing {count} {model.__name__}…")
|
|
257
302
|
errors[model] = {}
|
|
258
303
|
|
|
259
304
|
qs = model.objects().no_cache().all()
|
|
@@ -265,71 +310,87 @@ def check_references(models_to_check):
|
|
|
265
310
|
errors[model][key] = 0
|
|
266
311
|
|
|
267
312
|
try:
|
|
268
|
-
if reference[
|
|
313
|
+
if reference["type"] == "direct":
|
|
269
314
|
try:
|
|
270
|
-
_ = getattr(obj, reference[
|
|
315
|
+
_ = getattr(obj, reference["name"])
|
|
271
316
|
except mongoengine.errors.DoesNotExist:
|
|
272
317
|
errors[model][key] += 1
|
|
273
|
-
print_and_save(
|
|
274
|
-
|
|
275
|
-
|
|
318
|
+
print_and_save(
|
|
319
|
+
f'\t{model.__name__}#{obj.id} have a broken reference for `{reference["name"]}`'
|
|
320
|
+
)
|
|
321
|
+
elif reference["type"] == "list":
|
|
322
|
+
attr_list = getattr(obj, reference["name"], [])
|
|
276
323
|
for i, sub in enumerate(attr_list):
|
|
277
324
|
# If it's still an instance of DBRef it means that it failed to
|
|
278
325
|
# dereference the ID.
|
|
279
326
|
if isinstance(sub, DBRef):
|
|
280
327
|
errors[model][key] += 1
|
|
281
|
-
print_and_save(
|
|
282
|
-
|
|
283
|
-
|
|
328
|
+
print_and_save(
|
|
329
|
+
f'\t{model.__name__}#{obj.id} have a broken reference for {reference["name"]}[{i}]'
|
|
330
|
+
)
|
|
331
|
+
elif reference["type"] == "embed_list":
|
|
332
|
+
p1, p2 = reference["name"].split("__")
|
|
284
333
|
attr_list = getattr(obj, p1, [])
|
|
285
334
|
for i, sub in enumerate(attr_list):
|
|
286
335
|
try:
|
|
287
336
|
getattr(sub, p2)
|
|
288
337
|
except mongoengine.errors.DoesNotExist:
|
|
289
338
|
errors[model][key] += 1
|
|
290
|
-
print_and_save(
|
|
291
|
-
|
|
292
|
-
|
|
339
|
+
print_and_save(
|
|
340
|
+
f"\t{model.__name__}#{obj.id} have a broken reference for {p1}[{i}].{p2}"
|
|
341
|
+
)
|
|
342
|
+
elif reference["type"] == "embed":
|
|
343
|
+
p1, p2 = reference["name"].split("__")
|
|
293
344
|
sub = getattr(obj, p1)
|
|
294
|
-
if sub is None:
|
|
345
|
+
if sub is None:
|
|
346
|
+
continue
|
|
295
347
|
try:
|
|
296
348
|
getattr(sub, p2)
|
|
297
349
|
except mongoengine.errors.DoesNotExist:
|
|
298
350
|
errors[model][key] += 1
|
|
299
|
-
print_and_save(
|
|
300
|
-
|
|
301
|
-
|
|
351
|
+
print_and_save(
|
|
352
|
+
f"\t{model.__name__}#{obj.id} have a broken reference for {p1}.{p2}"
|
|
353
|
+
)
|
|
354
|
+
elif reference["type"] == "embed_list_ref":
|
|
355
|
+
p1, p2 = reference["name"].split("__")
|
|
302
356
|
a = getattr(obj, p1)
|
|
303
|
-
if a is None:
|
|
357
|
+
if a is None:
|
|
358
|
+
continue
|
|
304
359
|
sub = getattr(a, p2, [])
|
|
305
360
|
for i, child in enumerate(sub):
|
|
306
361
|
# If it's still an instance of DBRef it means that it failed to
|
|
307
362
|
# dereference the ID.
|
|
308
363
|
if isinstance(child, DBRef):
|
|
309
364
|
errors[model][key] += 1
|
|
310
|
-
print_and_save(
|
|
365
|
+
print_and_save(
|
|
366
|
+
f"\t{model.__name__}#{obj.id} have a broken reference for {p1}.{p2}[{i}]"
|
|
367
|
+
)
|
|
311
368
|
else:
|
|
312
369
|
print_and_save(f'Unknown ref type {reference["type"]}')
|
|
313
370
|
except mongoengine.errors.FieldDoesNotExist as e:
|
|
314
|
-
print_and_save(
|
|
371
|
+
print_and_save(
|
|
372
|
+
f"[ERROR for {model.__name__} {obj.id}] {traceback.format_exc()}"
|
|
373
|
+
)
|
|
315
374
|
|
|
316
375
|
for key, nb_errors in errors[model].items():
|
|
317
|
-
print(f
|
|
376
|
+
print(f"{key}: {nb_errors}")
|
|
318
377
|
total += nb_errors
|
|
319
378
|
|
|
320
|
-
print(f
|
|
379
|
+
print(f"\n Total errors: {total}")
|
|
321
380
|
|
|
322
381
|
if total > 0:
|
|
323
382
|
try:
|
|
324
383
|
import sentry_sdk
|
|
384
|
+
|
|
325
385
|
with sentry_sdk.push_scope() as scope:
|
|
326
386
|
scope.set_extra("errors", Log.errors)
|
|
327
387
|
sentry_sdk.capture_message(f"{total} integrity errors", "fatal")
|
|
328
388
|
except ImportError:
|
|
329
389
|
print("`sentry_sdk` not installed. The errors weren't reported")
|
|
330
390
|
|
|
391
|
+
|
|
331
392
|
@grp.command()
|
|
332
|
-
@click.option(
|
|
393
|
+
@click.option("--models", multiple=True, default=[], help="Model(s) to check")
|
|
333
394
|
def check_integrity(models):
|
|
334
|
-
|
|
395
|
+
"""Check the integrity of the database from a business perspective"""
|
|
335
396
|
check_references(models)
|
udata/commands/dcat.py
CHANGED
|
@@ -2,50 +2,54 @@ import logging
|
|
|
2
2
|
|
|
3
3
|
import click
|
|
4
4
|
import mongoengine
|
|
5
|
-
|
|
6
5
|
from rdflib import Graph
|
|
7
6
|
|
|
8
|
-
from udata.commands import cli,
|
|
7
|
+
from udata.commands import cli, cyan, echo, green, magenta, yellow
|
|
9
8
|
from udata.core.dataset.factories import DatasetFactory
|
|
10
9
|
from udata.core.dataset.rdf import dataset_from_rdf
|
|
11
|
-
from udata.harvest.backends.dcat import
|
|
10
|
+
from udata.harvest.backends.dcat import (
|
|
11
|
+
CswDcatBackend,
|
|
12
|
+
CswIso19139DcatBackend,
|
|
13
|
+
DcatBackend,
|
|
14
|
+
)
|
|
12
15
|
from udata.rdf import namespace_manager
|
|
13
16
|
|
|
14
17
|
log = logging.getLogger(__name__)
|
|
15
18
|
|
|
16
19
|
|
|
17
|
-
@cli.group(
|
|
20
|
+
@cli.group("dcat")
|
|
18
21
|
def grp():
|
|
19
|
-
|
|
22
|
+
"""DCAT diagnosis operations"""
|
|
20
23
|
pass
|
|
21
24
|
|
|
22
25
|
|
|
23
26
|
@grp.command()
|
|
24
|
-
@click.argument(
|
|
25
|
-
@click.option(
|
|
26
|
-
@click.option(
|
|
27
|
-
@click.option(
|
|
28
|
-
@click.option(
|
|
29
|
-
def parse_url(url, csw, iso, quiet=False, rid=
|
|
30
|
-
|
|
27
|
+
@click.argument("url")
|
|
28
|
+
@click.option("-q", "--quiet", is_flag=True, help="Ignore warnings")
|
|
29
|
+
@click.option("-r", "--rid", help="Inspect specific remote id (contains)")
|
|
30
|
+
@click.option("-c", "--csw", is_flag=True, help="The target is a CSW endpoint with DCAT output")
|
|
31
|
+
@click.option("-i", "--iso", is_flag=True, help="The target is a CSW endpoint with ISO output")
|
|
32
|
+
def parse_url(url, csw, iso, quiet=False, rid=""):
|
|
33
|
+
"""Parse the datasets in a DCAT format located at URL (debug)"""
|
|
31
34
|
if quiet:
|
|
32
|
-
verbose_loggers = [
|
|
35
|
+
verbose_loggers = ["rdflib", "udata.core.dataset"]
|
|
33
36
|
[logging.getLogger(l).setLevel(logging.ERROR) for l in verbose_loggers]
|
|
34
37
|
|
|
35
38
|
class MockSource:
|
|
36
|
-
url =
|
|
39
|
+
url = ""
|
|
37
40
|
|
|
38
41
|
class MockJob:
|
|
39
42
|
items = []
|
|
40
43
|
|
|
41
44
|
class MockDatasetFactory(DatasetFactory):
|
|
42
|
-
|
|
45
|
+
"""Use DatasetFactory without .save()"""
|
|
46
|
+
|
|
43
47
|
@classmethod
|
|
44
48
|
def _create(cls, model_class, *args, **kwargs):
|
|
45
49
|
instance = model_class(*args, **kwargs)
|
|
46
50
|
return instance
|
|
47
51
|
|
|
48
|
-
echo(cyan(
|
|
52
|
+
echo(cyan("Parsing url {}".format(url)))
|
|
49
53
|
source = MockSource()
|
|
50
54
|
source.url = url
|
|
51
55
|
if csw:
|
|
@@ -56,7 +60,7 @@ def parse_url(url, csw, iso, quiet=False, rid=''):
|
|
|
56
60
|
backend = DcatBackend(source, dryrun=True)
|
|
57
61
|
backend.job = MockJob()
|
|
58
62
|
format = backend.get_format()
|
|
59
|
-
echo(yellow(
|
|
63
|
+
echo(yellow("Detected format: {}".format(format)))
|
|
60
64
|
graphs = backend.parse_graph(url, format)
|
|
61
65
|
|
|
62
66
|
# serialize/unserialize graph like in the job mechanism
|
|
@@ -68,25 +72,27 @@ def parse_url(url, csw, iso, quiet=False, rid=''):
|
|
|
68
72
|
|
|
69
73
|
for item in backend.job.items:
|
|
70
74
|
if not rid or rid in item.remote_id:
|
|
71
|
-
echo(magenta(
|
|
72
|
-
echo(
|
|
75
|
+
echo(magenta("Processing item {}".format(item.remote_id)))
|
|
76
|
+
echo("Item kwargs: {}".format(yellow(item.kwargs)))
|
|
73
77
|
node = backend.get_node_from_item(graph, item)
|
|
74
78
|
dataset = MockDatasetFactory()
|
|
75
79
|
dataset = dataset_from_rdf(graph, dataset, node=node)
|
|
76
|
-
echo(
|
|
77
|
-
echo(green(
|
|
78
|
-
echo(
|
|
79
|
-
echo(
|
|
80
|
-
echo(
|
|
81
|
-
echo(
|
|
82
|
-
echo(
|
|
83
|
-
|
|
84
|
-
|
|
80
|
+
echo("")
|
|
81
|
+
echo(green("Dataset found!"))
|
|
82
|
+
echo("Title: {}".format(yellow(dataset)))
|
|
83
|
+
echo("License: {}".format(yellow(dataset.license)))
|
|
84
|
+
echo("Description: {}".format(yellow(dataset.description)))
|
|
85
|
+
echo("Tags: {}".format(yellow(dataset.tags)))
|
|
86
|
+
echo(
|
|
87
|
+
"Resources: {}".format(
|
|
88
|
+
yellow([(r.title, r.format, r.url) for r in dataset.resources])
|
|
89
|
+
)
|
|
90
|
+
)
|
|
85
91
|
|
|
86
92
|
try:
|
|
87
93
|
dataset.validate()
|
|
88
94
|
except mongoengine.errors.ValidationError as e:
|
|
89
95
|
log.error(e, exc_info=True)
|
|
90
96
|
else:
|
|
91
|
-
echo(green(
|
|
92
|
-
echo(
|
|
97
|
+
echo(green("Dataset is valid ✅"))
|
|
98
|
+
echo("")
|