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/tests/test_utils.py
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
from datetime import date, datetime
|
|
2
2
|
|
|
3
3
|
from udata.utils import (
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
daterange_end,
|
|
5
|
+
daterange_start,
|
|
6
|
+
get_by,
|
|
7
|
+
recursive_get,
|
|
8
|
+
safe_unicode,
|
|
9
|
+
to_bool,
|
|
10
|
+
to_iso,
|
|
11
|
+
to_iso_date,
|
|
12
|
+
to_iso_datetime,
|
|
13
|
+
to_naive_datetime,
|
|
6
14
|
)
|
|
7
15
|
|
|
8
16
|
TEST_LIST = [
|
|
9
|
-
{
|
|
10
|
-
{
|
|
11
|
-
{
|
|
17
|
+
{"name": "aaa", "other": "bbb"},
|
|
18
|
+
{"name": "bbb", "another": "ddd"},
|
|
19
|
+
{"name": "ccc", "other": "bbb"},
|
|
12
20
|
]
|
|
13
21
|
|
|
14
22
|
|
|
@@ -19,34 +27,34 @@ class ObjDict(object):
|
|
|
19
27
|
|
|
20
28
|
class GetByFieldTest:
|
|
21
29
|
def test_find_dict(self):
|
|
22
|
-
|
|
23
|
-
result = get_by(TEST_LIST,
|
|
24
|
-
assert result == {
|
|
30
|
+
"""get_by() should find a dictionnary in list"""
|
|
31
|
+
result = get_by(TEST_LIST, "name", "bbb")
|
|
32
|
+
assert result == {"name": "bbb", "another": "ddd"}
|
|
25
33
|
|
|
26
34
|
def test_find_object(self):
|
|
27
|
-
|
|
35
|
+
"""get_by() should find an object in list"""
|
|
28
36
|
obj_lst = [ObjDict(d) for d in TEST_LIST]
|
|
29
|
-
result = get_by(obj_lst,
|
|
30
|
-
assert result.name ==
|
|
31
|
-
assert result.another ==
|
|
37
|
+
result = get_by(obj_lst, "name", "bbb")
|
|
38
|
+
assert result.name == "bbb"
|
|
39
|
+
assert result.another == "ddd"
|
|
32
40
|
|
|
33
41
|
def test_not_found(self):
|
|
34
|
-
|
|
35
|
-
assert get_by(TEST_LIST,
|
|
42
|
+
"""get_by() should return None if not found"""
|
|
43
|
+
assert get_by(TEST_LIST, "name", "not-found") is None
|
|
36
44
|
|
|
37
45
|
def test_attribute_not_found(self):
|
|
38
|
-
|
|
39
|
-
assert get_by(TEST_LIST,
|
|
46
|
+
"""get_by() should not fail if an object don't have the given attr"""
|
|
47
|
+
assert get_by(TEST_LIST, "inexistant", "value") is None
|
|
40
48
|
|
|
41
49
|
|
|
42
50
|
class DateRangeTest:
|
|
43
51
|
def test_parse_daterange_start_empty(self):
|
|
44
52
|
assert daterange_start(None) is None
|
|
45
|
-
assert daterange_start(
|
|
53
|
+
assert daterange_start("") is None
|
|
46
54
|
|
|
47
55
|
def test_parse_daterange_end_empty(self):
|
|
48
56
|
assert daterange_end(None) is None
|
|
49
|
-
assert daterange_end(
|
|
57
|
+
assert daterange_end("") is None
|
|
50
58
|
|
|
51
59
|
def test_parse_daterange_start_date(self):
|
|
52
60
|
today = date.today()
|
|
@@ -65,37 +73,37 @@ class DateRangeTest:
|
|
|
65
73
|
assert daterange_end(now) == now.date()
|
|
66
74
|
|
|
67
75
|
def test_parse_daterange_start_full_iso(self):
|
|
68
|
-
assert daterange_start(
|
|
76
|
+
assert daterange_start("1984-06-07T00:00:00+00:00") == date(1984, 6, 7)
|
|
69
77
|
|
|
70
78
|
def test_parse_daterange_end_full_iso(self):
|
|
71
|
-
assert daterange_end(
|
|
79
|
+
assert daterange_end("1984-06-07T00:00:00+00:00") == date(1984, 6, 7)
|
|
72
80
|
|
|
73
81
|
def test_parse_daterange_start_full(self):
|
|
74
|
-
assert daterange_start(
|
|
82
|
+
assert daterange_start("1984-06-07") == date(1984, 6, 7)
|
|
75
83
|
|
|
76
84
|
def test_parse_daterange_end_full(self):
|
|
77
|
-
assert daterange_end(
|
|
85
|
+
assert daterange_end("1984-06-07") == date(1984, 6, 7)
|
|
78
86
|
|
|
79
87
|
def test_parse_daterange_start_month(self):
|
|
80
|
-
assert daterange_start(
|
|
88
|
+
assert daterange_start("1984-06") == date(1984, 6, 1)
|
|
81
89
|
|
|
82
90
|
def test_parse_daterange_end_month(self):
|
|
83
|
-
assert daterange_end(
|
|
84
|
-
assert daterange_end(
|
|
91
|
+
assert daterange_end("1984-06") == date(1984, 6, 30)
|
|
92
|
+
assert daterange_end("1984-07") == date(1984, 7, 31)
|
|
85
93
|
|
|
86
94
|
def test_parse_daterange_end_month_february(self):
|
|
87
|
-
assert daterange_end(
|
|
88
|
-
assert daterange_end(
|
|
95
|
+
assert daterange_end("1984-02") == date(1984, 2, 29)
|
|
96
|
+
assert daterange_end("1985-02") == date(1985, 2, 28)
|
|
89
97
|
|
|
90
98
|
def test_parse_daterange_start_year(self):
|
|
91
|
-
assert daterange_start(
|
|
99
|
+
assert daterange_start("1984") == date(1984, 1, 1)
|
|
92
100
|
|
|
93
101
|
def test_parse_daterange_end_year(self):
|
|
94
|
-
assert daterange_end(
|
|
102
|
+
assert daterange_end("1984") == date(1984, 12, 31)
|
|
95
103
|
|
|
96
104
|
def test_parse_before_1900(self):
|
|
97
|
-
assert daterange_start(
|
|
98
|
-
assert daterange_end(
|
|
105
|
+
assert daterange_start("1860") == date(1860, 1, 1)
|
|
106
|
+
assert daterange_end("1860") == date(1860, 12, 31)
|
|
99
107
|
|
|
100
108
|
|
|
101
109
|
class ToBoolTest:
|
|
@@ -104,15 +112,15 @@ class ToBoolTest:
|
|
|
104
112
|
assert to_bool(False) is False
|
|
105
113
|
|
|
106
114
|
def test_string_values(self):
|
|
107
|
-
assert to_bool(
|
|
108
|
-
assert to_bool(
|
|
109
|
-
assert to_bool(
|
|
110
|
-
assert to_bool(
|
|
111
|
-
assert to_bool(
|
|
112
|
-
assert to_bool(
|
|
113
|
-
assert to_bool(
|
|
114
|
-
assert to_bool(
|
|
115
|
-
assert to_bool(
|
|
115
|
+
assert to_bool("True") is True
|
|
116
|
+
assert to_bool("true") is True
|
|
117
|
+
assert to_bool("False") is False
|
|
118
|
+
assert to_bool("false") is False
|
|
119
|
+
assert to_bool("bla") is False
|
|
120
|
+
assert to_bool("T") is True
|
|
121
|
+
assert to_bool("F") is False
|
|
122
|
+
assert to_bool("t") is True
|
|
123
|
+
assert to_bool("f") is False
|
|
116
124
|
|
|
117
125
|
def test_int_values(self):
|
|
118
126
|
assert to_bool(0) is False
|
|
@@ -126,114 +134,114 @@ class ToIsoTest:
|
|
|
126
134
|
assert to_iso_date(None) is None
|
|
127
135
|
|
|
128
136
|
def test_to_iso_date_with_datetime(self):
|
|
129
|
-
assert to_iso_date(datetime(1984, 2, 29, 1, 2, 3)) ==
|
|
137
|
+
assert to_iso_date(datetime(1984, 2, 29, 1, 2, 3)) == "1984-02-29"
|
|
130
138
|
|
|
131
139
|
def test_to_iso_date_with_date(self):
|
|
132
|
-
assert to_iso_date(date(1984, 2, 29)) ==
|
|
140
|
+
assert to_iso_date(date(1984, 2, 29)) == "1984-02-29"
|
|
133
141
|
|
|
134
142
|
def test_to_iso_date_before_1900(self):
|
|
135
|
-
assert to_iso_date(date(1884, 2, 29)) ==
|
|
143
|
+
assert to_iso_date(date(1884, 2, 29)) == "1884-02-29"
|
|
136
144
|
|
|
137
145
|
def test_to_iso_datetime_emtpy(self):
|
|
138
146
|
assert to_iso_datetime(None) is None
|
|
139
147
|
|
|
140
148
|
def test_to_iso_datetime_with_datetime(self):
|
|
141
149
|
result = to_iso_datetime(datetime(1984, 2, 29, 1, 2, 3))
|
|
142
|
-
assert result ==
|
|
150
|
+
assert result == "1984-02-29T01:02:03"
|
|
143
151
|
|
|
144
152
|
def test_to_iso_datetime_with_date(self):
|
|
145
|
-
assert to_iso_datetime(date(1984, 2, 29)) ==
|
|
153
|
+
assert to_iso_datetime(date(1984, 2, 29)) == "1984-02-29T00:00:00"
|
|
146
154
|
|
|
147
155
|
def test_to_iso_datetime_before_1900(self):
|
|
148
|
-
assert to_iso_datetime(date(1884, 2, 29)) ==
|
|
156
|
+
assert to_iso_datetime(date(1884, 2, 29)) == "1884-02-29T00:00:00"
|
|
149
157
|
|
|
150
158
|
def test_to_iso_datetime_before_1000(self):
|
|
151
|
-
assert to_iso_datetime(date(908, 2, 29)) ==
|
|
159
|
+
assert to_iso_datetime(date(908, 2, 29)) == "0908-02-29T00:00:00"
|
|
152
160
|
|
|
153
161
|
def test_to_iso_emtpy(self):
|
|
154
162
|
assert to_iso(None) is None
|
|
155
163
|
|
|
156
164
|
def test_to_iso_with_datetime(self):
|
|
157
|
-
assert to_iso(datetime(1984, 2, 29, 1, 2, 3)) ==
|
|
165
|
+
assert to_iso(datetime(1984, 2, 29, 1, 2, 3)) == "1984-02-29T01:02:03"
|
|
158
166
|
|
|
159
167
|
def test_to_iso_with_date(self):
|
|
160
|
-
assert to_iso(date(1984, 2, 29)) ==
|
|
168
|
+
assert to_iso(date(1984, 2, 29)) == "1984-02-29"
|
|
161
169
|
|
|
162
170
|
|
|
163
171
|
class RecursiveGetTest:
|
|
164
172
|
def test_get_root_attribute(self):
|
|
165
173
|
class Tester(object):
|
|
166
|
-
attr =
|
|
174
|
+
attr = "value"
|
|
167
175
|
|
|
168
176
|
tester = Tester()
|
|
169
|
-
assert recursive_get(tester,
|
|
177
|
+
assert recursive_get(tester, "attr") == "value"
|
|
170
178
|
|
|
171
179
|
def test_get_root_key(self):
|
|
172
|
-
tester = {
|
|
173
|
-
assert recursive_get(tester,
|
|
180
|
+
tester = {"key": "value"}
|
|
181
|
+
assert recursive_get(tester, "key") == "value"
|
|
174
182
|
|
|
175
183
|
def test_get_nested_attribute(self):
|
|
176
184
|
class Nested(object):
|
|
177
|
-
attr =
|
|
185
|
+
attr = "value"
|
|
178
186
|
|
|
179
187
|
class Tester(object):
|
|
180
188
|
def __init__(self):
|
|
181
189
|
self.nested = Nested()
|
|
182
190
|
|
|
183
191
|
tester = Tester()
|
|
184
|
-
assert recursive_get(tester,
|
|
192
|
+
assert recursive_get(tester, "nested.attr") == "value"
|
|
185
193
|
|
|
186
194
|
def test_get_nested_key(self):
|
|
187
|
-
tester = {
|
|
188
|
-
assert recursive_get(tester,
|
|
195
|
+
tester = {"nested": {"key": "value"}}
|
|
196
|
+
assert recursive_get(tester, "nested.key") == "value"
|
|
189
197
|
|
|
190
198
|
def test_attr_not_found(self):
|
|
191
199
|
class Tester(object):
|
|
192
200
|
pass
|
|
193
201
|
|
|
194
202
|
tester = Tester()
|
|
195
|
-
assert recursive_get(tester,
|
|
203
|
+
assert recursive_get(tester, "attr") is None
|
|
196
204
|
|
|
197
205
|
def test_key_not_found(self):
|
|
198
|
-
tester = {
|
|
199
|
-
assert recursive_get(tester,
|
|
206
|
+
tester = {"key": "value"}
|
|
207
|
+
assert recursive_get(tester, "not-found") is None
|
|
200
208
|
|
|
201
209
|
def test_nested_attribute_not_found(self):
|
|
202
210
|
class Nested(object):
|
|
203
|
-
attr =
|
|
211
|
+
attr = "value"
|
|
204
212
|
|
|
205
213
|
class Tester(object):
|
|
206
214
|
def __init__(self):
|
|
207
215
|
self.nested = Nested()
|
|
208
216
|
|
|
209
217
|
tester = Tester()
|
|
210
|
-
assert recursive_get(tester,
|
|
218
|
+
assert recursive_get(tester, "nested.not_found") is None
|
|
211
219
|
|
|
212
220
|
def test_nested_key_not_found(self):
|
|
213
|
-
tester = {
|
|
214
|
-
assert recursive_get(tester,
|
|
221
|
+
tester = {"nested": {"key": "value"}}
|
|
222
|
+
assert recursive_get(tester, "nested.not_found") is None
|
|
215
223
|
|
|
216
224
|
def test_get_on_none(self):
|
|
217
|
-
assert recursive_get(None,
|
|
225
|
+
assert recursive_get(None, "attr") is None
|
|
218
226
|
|
|
219
227
|
def test_get_key_none(self):
|
|
220
|
-
tester = {
|
|
228
|
+
tester = {"key": "value"}
|
|
221
229
|
assert recursive_get(tester, None) is None
|
|
222
|
-
assert recursive_get(tester,
|
|
230
|
+
assert recursive_get(tester, "") is None
|
|
223
231
|
|
|
224
232
|
|
|
225
233
|
class SafeUnicodeTest(object):
|
|
226
234
|
def test_unicode_stays_unicode(self):
|
|
227
|
-
assert safe_unicode(
|
|
235
|
+
assert safe_unicode("ééé") == "ééé"
|
|
228
236
|
|
|
229
237
|
def test_bytes_is_decoded(self):
|
|
230
|
-
assert safe_unicode(b
|
|
238
|
+
assert safe_unicode(b"xxx") == "xxx"
|
|
231
239
|
|
|
232
240
|
def test_object_to_string(self):
|
|
233
|
-
assert safe_unicode({}) ==
|
|
241
|
+
assert safe_unicode({}) == "{}"
|
|
234
242
|
|
|
235
243
|
def test_unicode_to_string(self):
|
|
236
|
-
assert safe_unicode(ValueError(
|
|
244
|
+
assert safe_unicode(ValueError("é")) == "é"
|
|
237
245
|
|
|
238
246
|
|
|
239
247
|
class AwareDateTest:
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
from flask import url_for
|
|
2
|
-
|
|
3
|
-
from rdflib import
|
|
4
|
-
from rdflib.namespace import RDF, FOAF, RDFS
|
|
2
|
+
from rdflib import BNode, Literal, URIRef
|
|
3
|
+
from rdflib.namespace import FOAF, RDF, RDFS
|
|
5
4
|
from rdflib.resource import Resource as RdfResource
|
|
6
5
|
|
|
7
6
|
from udata import api
|
|
8
|
-
from udata.tests import TestCase, DBTestMixin
|
|
9
7
|
from udata.core.user.factories import UserFactory
|
|
10
8
|
from udata.core.user.rdf import user_to_rdf
|
|
9
|
+
from udata.tests import DBTestMixin, TestCase
|
|
11
10
|
from udata.utils import faker
|
|
12
11
|
|
|
13
12
|
|
|
@@ -33,9 +32,7 @@ class UserToRdfTest(DBTestMixin, TestCase):
|
|
|
33
32
|
|
|
34
33
|
def test_all_fields(self):
|
|
35
34
|
user = UserFactory(website=faker.uri())
|
|
36
|
-
user_url = url_for(
|
|
37
|
-
user=user.id,
|
|
38
|
-
_external=True)
|
|
35
|
+
user_url = url_for("api.user", user=user.id, _external=True)
|
|
39
36
|
u = user_to_rdf(user)
|
|
40
37
|
g = u.graph
|
|
41
38
|
|
|
@@ -48,5 +45,4 @@ class UserToRdfTest(DBTestMixin, TestCase):
|
|
|
48
45
|
self.assertEqual(u.identifier.toPython(), user_url)
|
|
49
46
|
self.assertEqual(u.value(FOAF.name), Literal(user.fullname))
|
|
50
47
|
self.assertEqual(u.value(RDFS.label), Literal(user.fullname))
|
|
51
|
-
self.assertEqual(u.value(FOAF.homepage).identifier,
|
|
52
|
-
URIRef(user.website))
|
|
48
|
+
self.assertEqual(u.value(FOAF.homepage).identifier, URIRef(user.website))
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
|
|
2
3
|
import pytest
|
|
3
4
|
|
|
4
5
|
from udata.core.jobs.commands import job_label
|
|
@@ -7,7 +8,7 @@ from udata.tasks import job
|
|
|
7
8
|
|
|
8
9
|
log = logging.getLogger(__name__)
|
|
9
10
|
|
|
10
|
-
JOB_NAME =
|
|
11
|
+
JOB_NAME = "fake-job"
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
@job(JOB_NAME)
|
|
@@ -15,33 +16,33 @@ def do_nothing(self, *args, **kwargs):
|
|
|
15
16
|
pass
|
|
16
17
|
|
|
17
18
|
|
|
18
|
-
@job(
|
|
19
|
+
@job("not-scheduled")
|
|
19
20
|
def not_scheduled(self):
|
|
20
21
|
pass
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
@pytest.fixture
|
|
24
25
|
def job_run(mocker):
|
|
25
|
-
return mocker.patch.object(do_nothing,
|
|
26
|
+
return mocker.patch.object(do_nothing, "run")
|
|
26
27
|
|
|
27
28
|
|
|
28
|
-
@pytest.mark.usefixtures(
|
|
29
|
+
@pytest.mark.usefixtures("clean_db")
|
|
29
30
|
class JobsCommandsTest:
|
|
30
31
|
def test_list_jobs(self, cli):
|
|
31
|
-
result = cli(
|
|
32
|
+
result = cli("job list")
|
|
32
33
|
assert JOB_NAME in result.output
|
|
33
34
|
|
|
34
35
|
def test_run_job(self, cli, job_run):
|
|
35
|
-
cli(
|
|
36
|
+
cli("job run fake-job")
|
|
36
37
|
job_run.assert_called()
|
|
37
38
|
|
|
38
39
|
def test_delay_job(self, cli, job_run):
|
|
39
|
-
cli(
|
|
40
|
+
cli("job run -d fake-job")
|
|
40
41
|
job_run.assert_called()
|
|
41
42
|
|
|
42
43
|
def test_run_job_kwargs(self, cli, job_run):
|
|
43
|
-
cli(
|
|
44
|
-
job_run.assert_called_with(
|
|
44
|
+
cli("job run fake-job arg key=value")
|
|
45
|
+
job_run.assert_called_with("arg", key="value")
|
|
45
46
|
|
|
46
47
|
def test_schedule_job(self, cli):
|
|
47
48
|
cli('job schedule "0 1 2 3 sunday" fake-job')
|
|
@@ -52,59 +53,58 @@ class JobsCommandsTest:
|
|
|
52
53
|
task = tasks[0]
|
|
53
54
|
assert task.args == []
|
|
54
55
|
assert task.kwargs == {}
|
|
55
|
-
assert task.crontab.minute ==
|
|
56
|
-
assert task.crontab.hour ==
|
|
57
|
-
assert task.crontab.day_of_month ==
|
|
58
|
-
assert task.crontab.month_of_year ==
|
|
59
|
-
assert task.crontab.day_of_week ==
|
|
56
|
+
assert task.crontab.minute == "0"
|
|
57
|
+
assert task.crontab.hour == "1"
|
|
58
|
+
assert task.crontab.day_of_month == "2"
|
|
59
|
+
assert task.crontab.month_of_year == "3"
|
|
60
|
+
assert task.crontab.day_of_week == "sunday"
|
|
60
61
|
assert task.enabled
|
|
61
|
-
assert task.name ==
|
|
62
|
+
assert task.name == "Job {0}".format(JOB_NAME)
|
|
62
63
|
|
|
63
64
|
def test_schedule_job_with_parameters(self, cli):
|
|
64
|
-
cli('job schedule "0 1 2 3 sunday" fake-job '
|
|
65
|
-
'arg0 arg1 key1=value1 key0=value0')
|
|
65
|
+
cli('job schedule "0 1 2 3 sunday" fake-job ' "arg0 arg1 key1=value1 key0=value0")
|
|
66
66
|
|
|
67
67
|
tasks = PeriodicTask.objects(task=JOB_NAME)
|
|
68
68
|
assert len(tasks) == 1
|
|
69
69
|
|
|
70
70
|
task = tasks[0]
|
|
71
|
-
assert task.args == [
|
|
72
|
-
assert task.kwargs == {
|
|
73
|
-
assert task.crontab.minute ==
|
|
74
|
-
assert task.crontab.hour ==
|
|
75
|
-
assert task.crontab.day_of_month ==
|
|
76
|
-
assert task.crontab.month_of_year ==
|
|
77
|
-
assert task.crontab.day_of_week ==
|
|
71
|
+
assert task.args == ["arg0", "arg1"] # Arguments order is preserved
|
|
72
|
+
assert task.kwargs == {"key0": "value0", "key1": "value1"}
|
|
73
|
+
assert task.crontab.minute == "0"
|
|
74
|
+
assert task.crontab.hour == "1"
|
|
75
|
+
assert task.crontab.day_of_month == "2"
|
|
76
|
+
assert task.crontab.month_of_year == "3"
|
|
77
|
+
assert task.crontab.day_of_week == "sunday"
|
|
78
78
|
assert task.enabled
|
|
79
79
|
# kwargs are sorted
|
|
80
|
-
expected =
|
|
80
|
+
expected = "Job {0}(arg0, arg1, key0=value0, key1=value1)"
|
|
81
81
|
assert task.name == expected.format(JOB_NAME)
|
|
82
82
|
|
|
83
83
|
def test_scheduled_jobs(self, cli):
|
|
84
84
|
tasks = [
|
|
85
85
|
PeriodicTask.objects.create(
|
|
86
86
|
task=JOB_NAME,
|
|
87
|
-
name=
|
|
88
|
-
description=
|
|
87
|
+
name="job-1",
|
|
88
|
+
description="I'm a scheduled job",
|
|
89
89
|
enabled=True,
|
|
90
|
-
crontab=PeriodicTask.Crontab.parse(
|
|
90
|
+
crontab=PeriodicTask.Crontab.parse("0 0 0 0 0"),
|
|
91
91
|
),
|
|
92
92
|
PeriodicTask.objects.create(
|
|
93
93
|
task=JOB_NAME,
|
|
94
|
-
name=
|
|
95
|
-
description=
|
|
94
|
+
name="job-2",
|
|
95
|
+
description="I'm a scheduled job",
|
|
96
96
|
enabled=True,
|
|
97
|
-
args=[
|
|
98
|
-
kwargs={
|
|
99
|
-
crontab=PeriodicTask.Crontab.parse(
|
|
100
|
-
)
|
|
97
|
+
args=["arg"],
|
|
98
|
+
kwargs={"key": "value"},
|
|
99
|
+
crontab=PeriodicTask.Crontab.parse("0 0 0 0 0"),
|
|
100
|
+
),
|
|
101
101
|
]
|
|
102
|
-
result = cli(
|
|
102
|
+
result = cli("job scheduled")
|
|
103
103
|
|
|
104
|
-
filtered = [l for l in result.output.splitlines() if
|
|
104
|
+
filtered = [l for l in result.output.splitlines() if "Tip" not in l]
|
|
105
105
|
assert len(filtered) == len(tasks)
|
|
106
106
|
|
|
107
|
-
assert
|
|
107
|
+
assert "not-scheduled" not in result.output
|
|
108
108
|
for task in tasks:
|
|
109
109
|
label = job_label(task.task, task.args, task.kwargs)
|
|
110
110
|
assert label in result.output
|
|
@@ -114,39 +114,38 @@ class JobsCommandsTest:
|
|
|
114
114
|
def test_unschedule_job(self, cli):
|
|
115
115
|
PeriodicTask.objects.create(
|
|
116
116
|
task=JOB_NAME,
|
|
117
|
-
name=
|
|
118
|
-
description=
|
|
117
|
+
name="job",
|
|
118
|
+
description="I'm a scheduled job",
|
|
119
119
|
enabled=True,
|
|
120
|
-
crontab=PeriodicTask.Crontab.parse(
|
|
120
|
+
crontab=PeriodicTask.Crontab.parse("0 0 0 0 0"),
|
|
121
121
|
)
|
|
122
|
-
cli(
|
|
122
|
+
cli("job unschedule {0}".format(JOB_NAME))
|
|
123
123
|
|
|
124
124
|
assert len(PeriodicTask.objects(task=JOB_NAME)) == 0
|
|
125
125
|
|
|
126
126
|
def test_unschedule_job_with_parameters(self, cli):
|
|
127
127
|
PeriodicTask.objects.create(
|
|
128
128
|
task=JOB_NAME,
|
|
129
|
-
name=
|
|
130
|
-
description=
|
|
129
|
+
name="job",
|
|
130
|
+
description="I'm a scheduled job",
|
|
131
131
|
enabled=True,
|
|
132
|
-
args=[
|
|
133
|
-
kwargs={
|
|
134
|
-
crontab=PeriodicTask.Crontab.parse(
|
|
132
|
+
args=["arg"],
|
|
133
|
+
kwargs={"key": "value"},
|
|
134
|
+
crontab=PeriodicTask.Crontab.parse("0 0 0 0 0"),
|
|
135
135
|
)
|
|
136
|
-
cli(
|
|
136
|
+
cli("job unschedule {0} arg key=value".format(JOB_NAME))
|
|
137
137
|
|
|
138
138
|
assert len(PeriodicTask.objects(task=JOB_NAME)) == 0
|
|
139
139
|
|
|
140
140
|
def test_unschedule_job_different_parameters(self, cli):
|
|
141
141
|
PeriodicTask.objects.create(
|
|
142
142
|
task=JOB_NAME,
|
|
143
|
-
name=
|
|
144
|
-
description=
|
|
143
|
+
name="job",
|
|
144
|
+
description="I'm a scheduled job",
|
|
145
145
|
enabled=True,
|
|
146
|
-
crontab=PeriodicTask.Crontab.parse(
|
|
146
|
+
crontab=PeriodicTask.Crontab.parse("0 0 0 0 0"),
|
|
147
147
|
)
|
|
148
|
-
result = cli(
|
|
149
|
-
check=False)
|
|
148
|
+
result = cli("job unschedule {0} arg".format(JOB_NAME), check=False)
|
|
150
149
|
|
|
151
150
|
assert result.exit_code != 0
|
|
152
151
|
assert len(PeriodicTask.objects(task=JOB_NAME)) == 1
|
|
@@ -161,10 +160,10 @@ class JobsCommandsTest:
|
|
|
161
160
|
task = tasks[0]
|
|
162
161
|
assert task.args == []
|
|
163
162
|
assert task.kwargs == {}
|
|
164
|
-
assert task.crontab.minute ==
|
|
165
|
-
assert task.crontab.hour ==
|
|
166
|
-
assert task.crontab.day_of_month ==
|
|
167
|
-
assert task.crontab.month_of_year ==
|
|
168
|
-
assert task.crontab.day_of_week ==
|
|
163
|
+
assert task.crontab.minute == "1"
|
|
164
|
+
assert task.crontab.hour == "0"
|
|
165
|
+
assert task.crontab.day_of_month == "0"
|
|
166
|
+
assert task.crontab.month_of_year == "0"
|
|
167
|
+
assert task.crontab.day_of_week == "*"
|
|
169
168
|
assert task.enabled
|
|
170
|
-
assert task.name ==
|
|
169
|
+
assert task.name == "Job {0}".format(JOB_NAME)
|
|
@@ -1,37 +1,32 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
|
|
3
|
-
from udata.tasks import celery,
|
|
3
|
+
from udata.tasks import celery, job, task
|
|
4
4
|
from udata.utils import unique_string
|
|
5
5
|
|
|
6
|
-
|
|
7
6
|
TASKS = [
|
|
8
|
-
({},
|
|
9
|
-
({
|
|
10
|
-
({
|
|
11
|
-
({
|
|
12
|
-
({
|
|
13
|
-
({
|
|
14
|
-
({
|
|
7
|
+
({}, "default", None),
|
|
8
|
+
({"queue": "low"}, "low", "low.{name}"),
|
|
9
|
+
({"queue": "low", "routing_key": "key"}, "low", "key"),
|
|
10
|
+
({"routing_key": "key"}, None, "key"),
|
|
11
|
+
({"route": "low.topic"}, "low", "low.topic"),
|
|
12
|
+
({"route": "low.topic", "queue": "q"}, "low", "low.topic"),
|
|
13
|
+
({"route": "low.topic", "routing_key": "rk"}, "low", "low.topic"),
|
|
15
14
|
]
|
|
16
15
|
|
|
17
16
|
JOBS = [
|
|
18
|
-
({},
|
|
19
|
-
({
|
|
20
|
-
({
|
|
21
|
-
({
|
|
22
|
-
({
|
|
23
|
-
({
|
|
24
|
-
({
|
|
17
|
+
({}, "low", "low.{name}"),
|
|
18
|
+
({"queue": "high"}, "high", "high.{name}"),
|
|
19
|
+
({"queue": "high", "routing_key": "key"}, "high", "key"),
|
|
20
|
+
({"routing_key": "key"}, "low", "key"),
|
|
21
|
+
({"route": "high.topic"}, "high", "high.topic"),
|
|
22
|
+
({"route": "high.topic", "queue": "q"}, "high", "high.topic"),
|
|
23
|
+
({"route": "high.topic", "routing_key": "rk"}, "high", "high.topic"),
|
|
25
24
|
]
|
|
26
25
|
|
|
27
26
|
|
|
28
27
|
def idify(params):
|
|
29
|
-
|
|
30
|
-
return [
|
|
31
|
-
', '.join('='.join(tup) for tup in row[0].items())
|
|
32
|
-
or 'none'
|
|
33
|
-
for row in params
|
|
34
|
-
]
|
|
28
|
+
"""Proper param display for easier debugging"""
|
|
29
|
+
return [", ".join("=".join(tup) for tup in row[0].items()) or "none" for row in params]
|
|
35
30
|
|
|
36
31
|
|
|
37
32
|
def fake_task(*args, **kwargs):
|
|
@@ -40,7 +35,6 @@ def fake_task(*args, **kwargs):
|
|
|
40
35
|
|
|
41
36
|
@pytest.fixture
|
|
42
37
|
def route_to(app, mocker):
|
|
43
|
-
|
|
44
38
|
def assertion(func, args, kwargs, queue, key=None):
|
|
45
39
|
__tracebackhide__ = True
|
|
46
40
|
|
|
@@ -48,28 +42,28 @@ def route_to(app, mocker):
|
|
|
48
42
|
router = celery.amqp.router
|
|
49
43
|
|
|
50
44
|
# Celery instanciate only one task by name so we need unique names
|
|
51
|
-
suffix = unique_string().replace(
|
|
52
|
-
fake_task.__name__ =
|
|
45
|
+
suffix = unique_string().replace("-", "_")
|
|
46
|
+
fake_task.__name__ = "task_{0}".format(suffix)
|
|
53
47
|
t = decorator(fake_task)
|
|
54
48
|
|
|
55
49
|
options = t._get_exec_options()
|
|
56
50
|
|
|
57
51
|
route = router.route(options, t.name, task_type=t)
|
|
58
52
|
if queue:
|
|
59
|
-
assert route[
|
|
53
|
+
assert route["queue"].name == queue, "queue mismatch"
|
|
60
54
|
if key:
|
|
61
55
|
key = key.format(name=t.name)
|
|
62
|
-
assert route[
|
|
56
|
+
assert route["routing_key"] == key, "routing_key mismatch"
|
|
63
57
|
return route
|
|
64
58
|
|
|
65
59
|
return assertion
|
|
66
60
|
|
|
67
61
|
|
|
68
|
-
@pytest.mark.parametrize(
|
|
62
|
+
@pytest.mark.parametrize("kwargs,queue,key", TASKS, ids=idify(TASKS))
|
|
69
63
|
def test_tasks_routing(route_to, kwargs, queue, key):
|
|
70
64
|
route_to(task, [], kwargs, queue, key)
|
|
71
65
|
|
|
72
66
|
|
|
73
|
-
@pytest.mark.parametrize(
|
|
67
|
+
@pytest.mark.parametrize("kwargs,queue,key", JOBS, ids=idify(JOBS))
|
|
74
68
|
def test_job_routing(route_to, kwargs, queue, key):
|
|
75
69
|
route_to(job, [unique_string()], kwargs, queue, key)
|