udata 9.1.2.dev30355__py2.py3-none-any.whl → 9.1.2.dev30382__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 +135 -124
- 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 +56 -54
- 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/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/static/chunks/{11.e9b9ca1f3e03d4020377.js → 11.52e531c19f8de80c00cf.js} +3 -3
- udata/static/chunks/{11.e9b9ca1f3e03d4020377.js.map → 11.52e531c19f8de80c00cf.js.map} +1 -1
- udata/static/chunks/{13.038c0d9aa0dfa0181c4b.js → 13.c3343a7f1070061c0e10.js} +2 -2
- udata/static/chunks/{13.038c0d9aa0dfa0181c4b.js.map → 13.c3343a7f1070061c0e10.js.map} +1 -1
- udata/static/chunks/{16.0baa2b64a74a2dcde25c.js → 16.8fa42440ad75ca172e6d.js} +2 -2
- udata/static/chunks/{16.0baa2b64a74a2dcde25c.js.map → 16.8fa42440ad75ca172e6d.js.map} +1 -1
- udata/static/chunks/{19.350a9f150b074b4ecefa.js → 19.9c6c8412729cd6d59cfa.js} +3 -3
- udata/static/chunks/{19.350a9f150b074b4ecefa.js.map → 19.9c6c8412729cd6d59cfa.js.map} +1 -1
- udata/static/chunks/{5.6ebbce2b9b3e696d3da5.js → 5.71d15c2e4f21feee2a9a.js} +3 -3
- udata/static/chunks/{5.6ebbce2b9b3e696d3da5.js.map → 5.71d15c2e4f21feee2a9a.js.map} +1 -1
- udata/static/chunks/{6.d8a5f7b017bcbd083641.js → 6.9139dc098b8ea640b890.js} +3 -3
- udata/static/chunks/{6.d8a5f7b017bcbd083641.js.map → 6.9139dc098b8ea640b890.js.map} +1 -1
- udata/static/common.js +1 -1
- udata/static/common.js.map +1 -1
- 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 +5 -6
- udata/tests/api/test_auth_api.py +395 -321
- udata/tests/api/test_base_api.py +31 -33
- 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 +76 -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_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.dev30382.dist-info}/METADATA +3 -2
- udata-9.1.2.dev30382.dist-info/RECORD +704 -0
- udata-9.1.2.dev30355.dist-info/RECORD +0 -704
- {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/LICENSE +0 -0
- {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/WHEEL +0 -0
- {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/entry_points.txt +0 -0
- {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/top_level.txt +0 -0
udata/core/jobs/commands.py
CHANGED
|
@@ -2,38 +2,37 @@ import logging
|
|
|
2
2
|
|
|
3
3
|
import click
|
|
4
4
|
|
|
5
|
-
from udata.commands import cli,
|
|
6
|
-
from udata.tasks import
|
|
5
|
+
from udata.commands import cli, echo, exit_with_error, white
|
|
6
|
+
from udata.tasks import celery, schedulables
|
|
7
7
|
|
|
8
8
|
from .models import PeriodicTask
|
|
9
9
|
|
|
10
10
|
log = logging.getLogger(__name__)
|
|
11
11
|
|
|
12
|
-
SCHEDULE_LINE =
|
|
12
|
+
SCHEDULE_LINE = "{name}: {label} ↦ {schedule}"
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def job_label(name, args, kwargs):
|
|
16
16
|
label = name
|
|
17
17
|
params = args[:]
|
|
18
|
-
params += [
|
|
18
|
+
params += ["=".join((k, v)) for k, v in sorted(kwargs.items())]
|
|
19
19
|
if params:
|
|
20
|
-
label +=
|
|
20
|
+
label += "(" + ", ".join(params) + ")"
|
|
21
21
|
return label
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
@cli.group(
|
|
24
|
+
@cli.group("job")
|
|
25
25
|
def grp():
|
|
26
|
-
|
|
26
|
+
"""Jobs related operations"""
|
|
27
27
|
pass
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
@grp.command()
|
|
31
|
-
@click.argument(
|
|
32
|
-
@click.argument(
|
|
33
|
-
@click.option(
|
|
34
|
-
help='Run the job asynchronously on a worker')
|
|
31
|
+
@click.argument("name", metavar="<name>")
|
|
32
|
+
@click.argument("params", nargs=-1, metavar="<arg key=value ...>")
|
|
33
|
+
@click.option("-d", "--delay", is_flag=True, help="Run the job asynchronously on a worker")
|
|
35
34
|
def run(name, params, delay):
|
|
36
|
-
|
|
35
|
+
"""
|
|
37
36
|
Run the job <name>
|
|
38
37
|
|
|
39
38
|
Jobs args and kwargs are given as parameters without dashes.
|
|
@@ -41,50 +40,50 @@ def run(name, params, delay):
|
|
|
41
40
|
Ex:
|
|
42
41
|
udata job run my-job arg1 arg2 key1=value key2=value
|
|
43
42
|
udata job run my-job -- arg1 arg2 key1=value key2=value
|
|
44
|
-
|
|
45
|
-
args = [p for p in params if
|
|
46
|
-
kwargs = dict(p.split(
|
|
43
|
+
"""
|
|
44
|
+
args = [p for p in params if "=" not in p]
|
|
45
|
+
kwargs = dict(p.split("=") for p in params if "=" in p)
|
|
47
46
|
|
|
48
47
|
if name not in celery.tasks:
|
|
49
|
-
exit_with_error(
|
|
48
|
+
exit_with_error("Job %s not found", name)
|
|
50
49
|
job = celery.tasks[name]
|
|
51
50
|
label = job_label(name, args, kwargs)
|
|
52
51
|
if delay:
|
|
53
|
-
log.info(
|
|
52
|
+
log.info("Sending job %s", label)
|
|
54
53
|
job.delay(*args, **kwargs)
|
|
55
|
-
log.info(
|
|
54
|
+
log.info("Job sended to workers")
|
|
56
55
|
else:
|
|
57
|
-
log.info(
|
|
56
|
+
log.info("Running job %s", label)
|
|
58
57
|
job.run(*args, **kwargs)
|
|
59
|
-
log.info(
|
|
58
|
+
log.info("Job %s done", name)
|
|
60
59
|
|
|
61
60
|
|
|
62
61
|
@grp.command()
|
|
63
62
|
def list():
|
|
64
|
-
|
|
63
|
+
"""List all availables jobs"""
|
|
65
64
|
for job in sorted([s.name for s in schedulables()]):
|
|
66
65
|
echo(job)
|
|
67
66
|
|
|
68
67
|
|
|
69
68
|
@grp.command()
|
|
70
|
-
@click.argument(
|
|
71
|
-
@click.argument(
|
|
72
|
-
@click.argument(
|
|
69
|
+
@click.argument("cron", metavar="<cron>")
|
|
70
|
+
@click.argument("name", metavar="<name>")
|
|
71
|
+
@click.argument("params", nargs=-1, metavar="<arg key=value ...>")
|
|
73
72
|
def schedule(cron, name, params):
|
|
74
|
-
|
|
73
|
+
"""
|
|
75
74
|
Schedule the job <name> to run periodically given the <cron> expression.
|
|
76
75
|
|
|
77
76
|
Jobs args and kwargs are given as parameters without dashes.
|
|
78
77
|
|
|
79
78
|
Ex:
|
|
80
79
|
udata job schedule "* * 0 * *" my-job arg1 arg2 key1=value key2=value
|
|
81
|
-
|
|
80
|
+
"""
|
|
82
81
|
if name not in celery.tasks:
|
|
83
|
-
exit_with_error(
|
|
82
|
+
exit_with_error("Job %s not found", name)
|
|
84
83
|
|
|
85
|
-
args = [p for p in params if
|
|
86
|
-
kwargs = dict(p.split(
|
|
87
|
-
label =
|
|
84
|
+
args = [p for p in params if "=" not in p]
|
|
85
|
+
kwargs = dict(p.split("=") for p in params if "=" in p)
|
|
86
|
+
label = "Job {0}".format(job_label(name, args, kwargs))
|
|
88
87
|
|
|
89
88
|
try:
|
|
90
89
|
task = PeriodicTask.objects.get(task=name, args=args, kwargs=kwargs)
|
|
@@ -93,56 +92,56 @@ def schedule(cron, name, params):
|
|
|
93
92
|
task = PeriodicTask.objects.create(
|
|
94
93
|
task=name,
|
|
95
94
|
name=label,
|
|
96
|
-
description=
|
|
95
|
+
description="Periodic {0} job".format(name),
|
|
97
96
|
enabled=True,
|
|
98
97
|
args=args,
|
|
99
98
|
kwargs=kwargs,
|
|
100
99
|
crontab=PeriodicTask.Crontab.parse(cron),
|
|
101
100
|
)
|
|
102
101
|
|
|
103
|
-
msg =
|
|
102
|
+
msg = "Scheduled {label} with the following crontab: {cron}"
|
|
104
103
|
log.info(msg.format(label=label, cron=task.schedule_display))
|
|
105
104
|
|
|
106
105
|
|
|
107
106
|
@grp.command()
|
|
108
|
-
@click.argument(
|
|
109
|
-
@click.argument(
|
|
107
|
+
@click.argument("name", metavar="<name>")
|
|
108
|
+
@click.argument("params", nargs=-1, metavar="<arg key=value ...>")
|
|
110
109
|
def unschedule(name, params):
|
|
111
|
-
|
|
110
|
+
"""
|
|
112
111
|
Unschedule the job <name> with the given parameters.
|
|
113
112
|
|
|
114
113
|
Jobs args and kwargs are given as parameters without dashes.
|
|
115
114
|
|
|
116
115
|
Ex:
|
|
117
116
|
udata job unschedule my-job arg1 arg2 key1=value key2=value
|
|
118
|
-
|
|
117
|
+
"""
|
|
119
118
|
if name not in celery.tasks:
|
|
120
|
-
exit_with_error(
|
|
119
|
+
exit_with_error("Job %s not found", name)
|
|
121
120
|
|
|
122
|
-
args = [p for p in params if
|
|
123
|
-
kwargs = dict(p.split(
|
|
124
|
-
label =
|
|
121
|
+
args = [p for p in params if "=" not in p]
|
|
122
|
+
kwargs = dict(p.split("=") for p in params if "=" in p)
|
|
123
|
+
label = "Job {0}".format(job_label(name, args, kwargs))
|
|
125
124
|
|
|
126
125
|
try:
|
|
127
126
|
task = PeriodicTask.objects.get(task=name, args=args, kwargs=kwargs)
|
|
128
127
|
except PeriodicTask.DoesNotExist:
|
|
129
|
-
exit_with_error(
|
|
128
|
+
exit_with_error("No scheduled job match {0}".format(label))
|
|
130
129
|
|
|
131
130
|
task.delete()
|
|
132
|
-
msg =
|
|
131
|
+
msg = "Unscheduled {label} with the following crontab: {cron}"
|
|
133
132
|
log.info(msg.format(label=label, cron=task.schedule_display))
|
|
134
133
|
|
|
135
134
|
|
|
136
135
|
@grp.command()
|
|
137
136
|
def scheduled():
|
|
138
|
-
|
|
137
|
+
"""
|
|
139
138
|
List scheduled jobs.
|
|
140
|
-
|
|
139
|
+
"""
|
|
141
140
|
for job in sorted(schedulables(), key=lambda s: s.name):
|
|
142
141
|
for task in PeriodicTask.objects(task=job.name):
|
|
143
142
|
label = job_label(task.task, task.args, task.kwargs)
|
|
144
|
-
echo(
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
)
|
|
143
|
+
echo(
|
|
144
|
+
SCHEDULE_LINE.format(
|
|
145
|
+
name=white(task.name), label=label, schedule=task.schedule_display
|
|
146
|
+
)
|
|
147
|
+
)
|
udata/core/jobs/forms.py
CHANGED
|
@@ -7,11 +7,11 @@ from .models import PeriodicTask
|
|
|
7
7
|
class CrontabForm(ModelForm):
|
|
8
8
|
model_class = PeriodicTask.Crontab
|
|
9
9
|
|
|
10
|
-
minute = fields.StringField(default=
|
|
11
|
-
hour = fields.StringField(default=
|
|
12
|
-
day_of_week = fields.StringField(default=
|
|
13
|
-
day_of_month = fields.StringField(default=
|
|
14
|
-
month_of_year = fields.StringField(default=
|
|
10
|
+
minute = fields.StringField(default="*")
|
|
11
|
+
hour = fields.StringField(default="*")
|
|
12
|
+
day_of_week = fields.StringField(default="*")
|
|
13
|
+
day_of_month = fields.StringField(default="*")
|
|
14
|
+
month_of_year = fields.StringField(default="*")
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class IntervalForm(ModelForm):
|
|
@@ -24,16 +24,16 @@ class IntervalForm(ModelForm):
|
|
|
24
24
|
class PeriodicTaskForm(ModelForm):
|
|
25
25
|
model_class = PeriodicTask
|
|
26
26
|
|
|
27
|
-
name = fields.StringField(_(
|
|
28
|
-
description = fields.StringField(_(
|
|
29
|
-
task = fields.StringField(_(
|
|
30
|
-
enabled = fields.BooleanField(_(
|
|
27
|
+
name = fields.StringField(_("Name"), [validators.DataRequired()])
|
|
28
|
+
description = fields.StringField(_("Description"))
|
|
29
|
+
task = fields.StringField(_("Tasks"))
|
|
30
|
+
enabled = fields.BooleanField(_("Enabled"))
|
|
31
31
|
|
|
32
32
|
def save(self, commit=True, **kwargs):
|
|
33
|
-
|
|
33
|
+
"""
|
|
34
34
|
PeriodicTask is dynamic and save behavior changed
|
|
35
35
|
See: https://github.com/zakird/celerybeat-mongo/commit/dfbbd20edde91134b57f5406d0ce4eac59d6899b
|
|
36
|
-
|
|
36
|
+
"""
|
|
37
37
|
if not self.instance:
|
|
38
38
|
self.instance = self.model_class() # Force populate_obj in super()
|
|
39
39
|
return super(PeriodicTaskForm, self).save(commit, **kwargs)
|
udata/core/jobs/models.py
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
from celerybeatmongo.models import
|
|
1
|
+
from celerybeatmongo.models import PERIODS
|
|
2
|
+
from celerybeatmongo.models import PeriodicTask as BasePeriodicTask
|
|
2
3
|
|
|
3
4
|
from udata.i18n import lazy_gettext as _
|
|
4
5
|
from udata.mongo import db
|
|
5
6
|
|
|
7
|
+
__all__ = ("PeriodicTask", "PERIODS")
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
CRON = '{minute} {hour} {day_of_month} {month_of_year} {day_of_week}'
|
|
9
|
+
CRON = "{minute} {hour} {day_of_month} {month_of_year} {day_of_week}"
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class PeriodicTask(BasePeriodicTask):
|
|
@@ -15,8 +15,8 @@ class PeriodicTask(BasePeriodicTask):
|
|
|
15
15
|
class Interval(BasePeriodicTask.Interval):
|
|
16
16
|
def __str__(self):
|
|
17
17
|
if self.every == 1:
|
|
18
|
-
return _(
|
|
19
|
-
return _(
|
|
18
|
+
return _("every {0.period_singular}").format(self)
|
|
19
|
+
return _("every {0.every} {0.period}").format(self)
|
|
20
20
|
|
|
21
21
|
class Crontab(BasePeriodicTask.Crontab):
|
|
22
22
|
def __str__(self):
|
udata/core/metrics/__init__.py
CHANGED
|
@@ -6,8 +6,8 @@ def init_app(app):
|
|
|
6
6
|
import udata.core.user.metrics # noqa
|
|
7
7
|
import udata.core.organization.metrics # noqa
|
|
8
8
|
import udata.core.discussions.metrics # noqa
|
|
9
|
-
import udata.core.reuse.metrics
|
|
9
|
+
import udata.core.reuse.metrics # noqa
|
|
10
10
|
import udata.core.followers.metrics # noqa
|
|
11
11
|
|
|
12
12
|
# Load metrics from plugins
|
|
13
|
-
entrypoints.get_enabled(
|
|
13
|
+
entrypoints.get_enabled("udata.metrics", app)
|
udata/core/metrics/commands.py
CHANGED
|
@@ -1,40 +1,44 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
|
|
3
3
|
import click
|
|
4
|
-
|
|
5
4
|
from flask import current_app
|
|
6
5
|
|
|
7
6
|
from udata.commands import cli, success
|
|
8
|
-
from udata.models import
|
|
7
|
+
from udata.models import Dataset, GeoZone, Organization, Reuse, Site, User
|
|
9
8
|
|
|
10
9
|
log = logging.getLogger(__name__)
|
|
11
10
|
|
|
12
11
|
|
|
13
|
-
@cli.group(
|
|
12
|
+
@cli.group("metrics")
|
|
14
13
|
def grp():
|
|
15
|
-
|
|
14
|
+
"""Metrics related operations"""
|
|
16
15
|
pass
|
|
17
16
|
|
|
18
17
|
|
|
19
18
|
@grp.command()
|
|
20
|
-
@click.option(
|
|
21
|
-
@click.option(
|
|
22
|
-
|
|
23
|
-
@click.option(
|
|
24
|
-
|
|
25
|
-
@click.option(
|
|
26
|
-
@click.option(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
19
|
+
@click.option("-s", "--site", is_flag=True, help="Update site metrics")
|
|
20
|
+
@click.option("-o", "--organizations", is_flag=True, help="Compute organizations metrics")
|
|
21
|
+
@click.option("-d", "--datasets", is_flag=True, help="Compute datasets metrics")
|
|
22
|
+
@click.option("-r", "--reuses", is_flag=True, help="Compute reuses metrics")
|
|
23
|
+
@click.option("-u", "--users", is_flag=True, help="Compute users metrics")
|
|
24
|
+
@click.option("-g", "--geozones", is_flag=True, help="Compute geo levels metrics")
|
|
25
|
+
@click.option("--drop", is_flag=True, help="Clear old metrics before computing new ones")
|
|
26
|
+
def update(
|
|
27
|
+
site=False,
|
|
28
|
+
organizations=False,
|
|
29
|
+
users=False,
|
|
30
|
+
datasets=False,
|
|
31
|
+
reuses=False,
|
|
32
|
+
geozones=False,
|
|
33
|
+
drop=False,
|
|
34
|
+
):
|
|
35
|
+
"""Update all metrics for the current date"""
|
|
32
36
|
do_all = not any((site, organizations, users, datasets, reuses, geozones))
|
|
33
37
|
|
|
34
38
|
if do_all or site:
|
|
35
|
-
log.info(
|
|
39
|
+
log.info("Update site metrics")
|
|
36
40
|
try:
|
|
37
|
-
site = Site.objects(id=current_app.config[
|
|
41
|
+
site = Site.objects(id=current_app.config["SITE_ID"]).first()
|
|
38
42
|
if drop:
|
|
39
43
|
site.metrics.clear()
|
|
40
44
|
site.count_users()
|
|
@@ -53,10 +57,10 @@ def update(site=False, organizations=False, users=False, datasets=False,
|
|
|
53
57
|
site.count_max_org_reuses()
|
|
54
58
|
site.count_max_org_datasets()
|
|
55
59
|
except Exception as e:
|
|
56
|
-
log.info(f
|
|
60
|
+
log.info(f"Error during update: {e}")
|
|
57
61
|
|
|
58
62
|
if do_all or datasets:
|
|
59
|
-
log.info(
|
|
63
|
+
log.info("Update datasets metrics")
|
|
60
64
|
all_datasets = Dataset.objects.visible().timeout(False)
|
|
61
65
|
with click.progressbar(all_datasets, length=Dataset.objects.count()) as dataset_bar:
|
|
62
66
|
for dataset in dataset_bar:
|
|
@@ -67,11 +71,11 @@ def update(site=False, organizations=False, users=False, datasets=False,
|
|
|
67
71
|
dataset.count_reuses()
|
|
68
72
|
dataset.count_followers()
|
|
69
73
|
except Exception as e:
|
|
70
|
-
log.info(f
|
|
74
|
+
log.info(f"Error during update: {e}")
|
|
71
75
|
continue
|
|
72
76
|
|
|
73
77
|
if do_all or reuses:
|
|
74
|
-
log.info(
|
|
78
|
+
log.info("Update reuses metrics")
|
|
75
79
|
all_reuses = Reuse.objects.visible().timeout(False)
|
|
76
80
|
with click.progressbar(all_reuses, length=Reuse.objects.visible().count()) as reuses_bar:
|
|
77
81
|
for reuse in reuses_bar:
|
|
@@ -81,11 +85,11 @@ def update(site=False, organizations=False, users=False, datasets=False,
|
|
|
81
85
|
reuse.count_discussions()
|
|
82
86
|
reuse.count_followers()
|
|
83
87
|
except Exception as e:
|
|
84
|
-
log.info(f
|
|
88
|
+
log.info(f"Error during update: {e}")
|
|
85
89
|
continue
|
|
86
90
|
|
|
87
91
|
if do_all or organizations:
|
|
88
|
-
log.info(
|
|
92
|
+
log.info("Update organizations metrics")
|
|
89
93
|
all_org = Organization.objects.visible().timeout(False)
|
|
90
94
|
with click.progressbar(all_org, length=Organization.objects.visible().count()) as org_bar:
|
|
91
95
|
for organization in org_bar:
|
|
@@ -97,11 +101,11 @@ def update(site=False, organizations=False, users=False, datasets=False,
|
|
|
97
101
|
organization.count_followers()
|
|
98
102
|
organization.count_members()
|
|
99
103
|
except Exception as e:
|
|
100
|
-
log.info(f
|
|
104
|
+
log.info(f"Error during update: {e}")
|
|
101
105
|
continue
|
|
102
106
|
|
|
103
107
|
if do_all or users:
|
|
104
|
-
log.info(
|
|
108
|
+
log.info("Update user metrics")
|
|
105
109
|
all_users = User.objects.timeout(False)
|
|
106
110
|
with click.progressbar(all_users, length=User.objects.count()) as users_bar:
|
|
107
111
|
for user in users_bar:
|
|
@@ -113,11 +117,11 @@ def update(site=False, organizations=False, users=False, datasets=False,
|
|
|
113
117
|
user.count_followers()
|
|
114
118
|
user.count_following()
|
|
115
119
|
except Exception as e:
|
|
116
|
-
log.info(f
|
|
120
|
+
log.info(f"Error during update: {e}")
|
|
117
121
|
continue
|
|
118
122
|
|
|
119
123
|
if do_all or geozones:
|
|
120
|
-
log.info(
|
|
124
|
+
log.info("Update GeoZone metrics")
|
|
121
125
|
all_geozones = GeoZone.objects.timeout(False)
|
|
122
126
|
with click.progressbar(all_geozones, length=GeoZone.objects.count()) as geozones_bar:
|
|
123
127
|
for geozone in geozones_bar:
|
|
@@ -126,7 +130,7 @@ def update(site=False, organizations=False, users=False, datasets=False,
|
|
|
126
130
|
geozone.metrics.clear()
|
|
127
131
|
geozone.count_datasets()
|
|
128
132
|
except Exception as e:
|
|
129
|
-
log.info(f
|
|
133
|
+
log.info(f"Error during update: {e}")
|
|
130
134
|
continue
|
|
131
135
|
|
|
132
|
-
success(
|
|
136
|
+
success("All metrics have been updated")
|
udata/core/metrics/models.py
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
from udata.api_fields import field
|
|
2
2
|
from udata.mongo import db
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
__all__ = ('WithMetrics',)
|
|
4
|
+
__all__ = ("WithMetrics",)
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
class WithMetrics(object):
|
|
@@ -11,5 +10,4 @@ class WithMetrics(object):
|
|
|
11
10
|
__metrics_keys__ = []
|
|
12
11
|
|
|
13
12
|
def get_metrics(self):
|
|
14
|
-
return {key:self.metrics.get(key, 0) for key in self.__metrics_keys__}
|
|
15
|
-
|
|
13
|
+
return {key: self.metrics.get(key, 0) for key in self.__metrics_keys__}
|
udata/core/metrics/signals.py
CHANGED
udata/core/metrics/tasks.py
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
from flask import current_app
|
|
2
2
|
|
|
3
|
+
from udata.core.metrics.signals import on_site_metrics_computed
|
|
3
4
|
from udata.models import Site
|
|
4
5
|
from udata.tasks import job
|
|
5
|
-
from udata.core.metrics.signals import on_site_metrics_computed
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
@job(
|
|
8
|
+
@job("compute-site-metrics")
|
|
9
9
|
def compute_site_metrics(self):
|
|
10
|
-
site = Site.objects(id=current_app.config[
|
|
10
|
+
site = Site.objects(id=current_app.config["SITE_ID"]).first()
|
|
11
11
|
site.count_users()
|
|
12
12
|
site.count_org()
|
|
13
13
|
site.count_datasets()
|
|
@@ -1,31 +1,28 @@
|
|
|
1
1
|
from flask_security import current_user
|
|
2
2
|
|
|
3
3
|
from udata.i18n import lazy_gettext as _
|
|
4
|
-
from udata.models import
|
|
4
|
+
from udata.models import Activity, Organization, db
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
__all__ = (
|
|
8
|
-
'UserCreatedOrganization', 'UserUpdatedOrganization', 'OrgRelatedActivity'
|
|
9
|
-
)
|
|
6
|
+
__all__ = ("UserCreatedOrganization", "UserUpdatedOrganization", "OrgRelatedActivity")
|
|
10
7
|
|
|
11
8
|
|
|
12
9
|
class OrgRelatedActivity(object):
|
|
13
|
-
related_to = db.ReferenceField(
|
|
14
|
-
template =
|
|
10
|
+
related_to = db.ReferenceField("Organization")
|
|
11
|
+
template = "activity/organization.html"
|
|
15
12
|
|
|
16
13
|
|
|
17
14
|
class UserCreatedOrganization(OrgRelatedActivity, Activity):
|
|
18
|
-
key =
|
|
19
|
-
icon =
|
|
20
|
-
badge_type =
|
|
21
|
-
label = _(
|
|
15
|
+
key = "organization:created"
|
|
16
|
+
icon = "fa fa-plus"
|
|
17
|
+
badge_type = "success"
|
|
18
|
+
label = _("created an organization")
|
|
22
19
|
|
|
23
20
|
|
|
24
21
|
class UserUpdatedOrganization(OrgRelatedActivity, Activity):
|
|
25
|
-
key =
|
|
26
|
-
icon =
|
|
27
|
-
badge_type =
|
|
28
|
-
label = _(
|
|
22
|
+
key = "organization:updated"
|
|
23
|
+
icon = "fa fa-pencil"
|
|
24
|
+
badge_type = "error"
|
|
25
|
+
label = _("updated an organization")
|
|
29
26
|
|
|
30
27
|
|
|
31
28
|
@Organization.on_create.connect
|