Skip to content

Recombinant Org Based Triggers#1602

Closed
JVickery-TBS wants to merge 6 commits into
masterfrom
feature/recombinant-org-based-trigger-choices
Closed

Recombinant Org Based Triggers#1602
JVickery-TBS wants to merge 6 commits into
masterfrom
feature/recombinant-org-based-trigger-choices

Conversation

@JVickery-TBS

Copy link
Copy Markdown
Contributor

Mainly for the Service Inventory PD type for now, but will allow us to do org based choices in the future for other data collection things. This was branch off of the service-2025

- Started working on schema directive for per org triggers.
- Fixed valid org choices in PD dattables editor.
- Fixed valid org choices in edit/add pd record flask view.
@codecov

codecov Bot commented Mar 26, 2026

Copy link
Copy Markdown

❌ 7 Tests Failed:

Tests completed Failed Passed Skipped
276 7 269 0
View the top 3 failed test(s) by shortest run time
ckanext/canada/tests/test_webforms.py::TestRecombinantWebForms::test_admin_can_update_single_record
Stack Traces | 9.09s run time
self = <ckanext.canada.tests.test_webforms.TestRecombinantWebForms object at 0x7f4a1c86a400>
app = <ckan.tests.helpers.CKANTestApp object at 0x7f4a1c40e6d0>

    @mock.patch.object(h, 'flash_notice', flashes.mock_flash)
    @mock.patch.object(h, 'get_flashed_messages', flashes.mock_get_flashed_messages)
    @mock.patch.object(h, 'is_registry_domain', mock_is_registry_domain)
    def test_admin_can_update_single_record(self, app):
        self._lc_create_pd_record()
    
        offset = h.url_for('canada.update_pd_record',
                           resource_name=self.pd_type,
                           owner_org=self.org['name'],
                           pk=self.example_record['request_number'])
        response = app.get(offset, extra_environ=self.extra_environ_system,
                           environ_overrides=self.environ_overrides_system)
    
>       assert 'Update Record' in response.body
E       assert 'Update Record' in '<!DOCTYPE html><!--[if lt IE 9]>\n  <html class="no-js lt-ie9" lang="en" dir="ltr"><![endif]--> <!--[if gt IE 8]><!-->\n  <html class="no-js" lang="en" dir="ltr"> <!--<![endif]-->\n  <head>\n    \n  <meta charset="utf-8" />\n      <meta name="csrf_field_name" content="_csrf_token" />\n      <meta name="_csrf_token" content="IjhhNmFiM2Y4YmM5NjA3ZTk3ZjUyODMzOWQwNWE2OGNjZTIwNDcyZGIi.acWdxQ.WQW_DDembHe1YkzdjIW9CqCDqII" />\n\n      <meta name="generator" content="ckan 2.10.8" />\n      <meta name="viewport" content="width=device-width, initial-scale=1.0">\n  \n    <meta property="og:title" content="Error 500 - CKAN">\n  \n  \n    \n  \n\n    <title>Error 500 - CKAN</title>\n\n    \n    \n  <link rel="shortcut icon" href="https://www.canada..../wet-boew/assets/favicon.ico" />\n    \n  \n    \n    \n    \n  \n  \n  \n\n  \n  \n      \n      \n      \n    \n  \n\n  \n\n\n    \n      \n      <link rel="stylesheet" href="TEST_TEMPLATE_HEAD_END.css" type="text/css">\n    \n\n    \n    <link href="....../webassets/base/b44cc5bc_main.css" rel="stylesheet" nonce="h3xgtDNHGM1BAbtBWa4Iqn"/>\n<link href="....../webassets/ckanext-scheming/073d7cfa_scheming_css.css" rel="st...e7_fontawesome.css" rel="stylesheet" nonce="h3xgtDNHGM1BAbtBWa4Iqn"/>\n    <script src="....../webassets/canada_public/562e1564_canada_public_analytics.js" type="text/javascript" nonce="h3xgtDNHGM1BAbtBWa4Iqn"></script>\n<script src="....../webassets/canada_internal_analytics/201f40a5_canada_internal_analytics.js" type="text/javascript" nonce="h3xgtDNHGM1BAbtBWa4Iqn"></script>\n<script src="....../webassets/vendor/8c3c143a_jquery.js" type="text/javascript" nonce="h3xgtDNHGM1BAbtBWa4Iqn"></script>\n<script src="....../webassets/vendor/9cf42cfd_vendor.js" type="text/javascript" nonce="h3xgtDNHGM1BAbtBWa4Iqn"></script>\n<script src="....../webassets/vendor/6d1ad7e6_bootstrap.js" type="text/javascript" nonce="h3xgtDNHGM1BAbtBWa4Iqn"></script>\n<script src="....../webassets/base/6fddaa3f_main.js" type="text/javascript" nonce="h3xgtDNHGM1BAbtBWa4Iqn"></script>\n<script src="....../webassets/base/7435ee13_ckan.js" type="text/javascript" nonce="h3xgtDNHGM1BAbtBWa4Iqn"></script>\n<script src="....../webassets/base/cd2c0272_tracking.js" type="text/javascript" nonce="h3xgtDNHGM1BAbtBWa4Iqn"></script>\n<script src="....../webassets/activity/0fdb5ee0_activity.js" type="text/javascript" nonce="h3xgtDNHGM1BAbtBWa4Iqn"></script>\n  </body>\n</html>'
E        +  where '<!DOCTYPE html><!--[if lt IE 9]>\n  <html class="no-js lt-ie9" lang="en" dir="ltr"><![endif]--> <!--[if gt IE 8]><!-->\n  <html class="no-js" lang="en" dir="ltr"> <!--<![endif]-->\n  <head>\n    \n  <meta charset="utf-8" />\n      <meta name="csrf_field_name" content="_csrf_token" />\n      <meta name="_csrf_token" content="IjhhNmFiM2Y4YmM5NjA3ZTk3ZjUyODMzOWQwNWE2OGNjZTIwNDcyZGIi.acWdxQ.WQW_DDembHe1YkzdjIW9CqCDqII" />\n\n      <meta name="generator" content="ckan 2.10.8" />\n      <meta name="viewport" content="width=device-width, initial-scale=1.0">\n  \n    <meta property="og:title" content="Error 500 - CKAN">\n  \n  \n    \n  \n\n    <title>Error 500 - CKAN</title>\n\n    \n    \n  <link rel="shortcut icon" href="https://www.canada..../wet-boew/assets/favicon.ico" />\n    \n  \n    \n    \n    \n  \n  \n  \n\n  \n  \n      \n      \n      \n    \n  \n\n  \n\n\n    \n      \n      <link rel="stylesheet" href="TEST_TEMPLATE_HEAD_END.css" type="text/css">\n    \n\n    \n    <link href="....../webassets/base/b44cc5bc_main.css" rel="stylesheet" nonce="h3xgtDNHGM1BAbtBWa4Iqn"/>\n<link href="....../webassets/ckanext-scheming/073d7cfa_scheming_css.css" rel="st...e7_fontawesome.css" rel="stylesheet" nonce="h3xgtDNHGM1BAbtBWa4Iqn"/>\n    <script src="....../webassets/canada_public/562e1564_canada_public_analytics.js" type="text/javascript" nonce="h3xgtDNHGM1BAbtBWa4Iqn"></script>\n<script src="....../webassets/canada_internal_analytics/201f40a5_canada_internal_analytics.js" type="text/javascript" nonce="h3xgtDNHGM1BAbtBWa4Iqn"></script>\n<script src="....../webassets/vendor/8c3c143a_jquery.js" type="text/javascript" nonce="h3xgtDNHGM1BAbtBWa4Iqn"></script>\n<script src="....../webassets/vendor/9cf42cfd_vendor.js" type="text/javascript" nonce="h3xgtDNHGM1BAbtBWa4Iqn"></script>\n<script src="....../webassets/vendor/6d1ad7e6_bootstrap.js" type="text/javascript" nonce="h3xgtDNHGM1BAbtBWa4Iqn"></script>\n<script src="....../webassets/base/6fddaa3f_main.js" type="text/javascript" nonce="h3xgtDNHGM1BAbtBWa4Iqn"></script>\n<script src="....../webassets/base/7435ee13_ckan.js" type="text/javascript" nonce="h3xgtDNHGM1BAbtBWa4Iqn"></script>\n<script src="....../webassets/base/cd2c0272_tracking.js" type="text/javascript" nonce="h3xgtDNHGM1BAbtBWa4Iqn"></script>\n<script src="....../webassets/activity/0fdb5ee0_activity.js" type="text/javascript" nonce="h3xgtDNHGM1BAbtBWa4Iqn"></script>\n  </body>\n</html>' = <WrapperTestResponse 20618 bytes [500 INTERNAL SERVER ERROR]>.body

.../canada/tests/test_webforms.py:597: AssertionError
ckanext/canada/tests/test_webforms.py::TestRecombinantWebForms::test_admin_can_create_single_record
Stack Traces | 9.72s run time
self = <ckanext.canada.tests.test_webforms.TestRecombinantWebForms object at 0x7f06c50164f0>
app = <ckan.tests.helpers.CKANTestApp object at 0x7f06c067c250>

    @mock.patch.object(h, 'flash_notice', flashes.mock_flash)
    @mock.patch.object(h, 'get_flashed_messages', flashes.mock_get_flashed_messages)
    @mock.patch.object(h, 'is_registry_domain', mock_is_registry_domain)
    def test_admin_can_create_single_record(self, app):
        self._lc_init_pd()
    
        offset = h.url_for('canada.create_pd_record',
                           resource_name=self.pd_type,
                           owner_org=self.org['name'])
        response = app.get(offset, extra_environ=self.extra_environ_system,
                           environ_overrides=self.environ_overrides_system)
    
>       assert 'Create Record' in response.body
E       assert 'Create Record' in '<!DOCTYPE html><!--[if lt IE 9]>\n  <html class="no-js lt-ie9" lang="en" dir="ltr"><![endif]--> <!--[if gt IE 8]><!-->\n  <html class="no-js" lang="en" dir="ltr"> <!--<![endif]-->\n  <head>\n    \n  <meta charset="utf-8" />\n      <meta name="csrf_field_name" content="_csrf_token" />\n      <meta name="_csrf_token" content="ImEyMmVmNmM1ZDVkNTZhNjI1ZTZhZDgyNTU4Y2I2NDgyMDU5OWI2NGUi.acWd8Q.ZK3gN9uZn1b6KZtCdqzL-nbIPyQ" />\n\n      <meta name="generator" content="ckan 2.10.8" />\n      <meta name="viewport" content="width=device-width, initial-scale=1.0">\n  \n    <meta property="og:title" content="Error 500 - CKAN">\n  \n  \n    \n  \n\n    <title>Error 500 - CKAN</title>\n\n    \n    \n  <link rel="shortcut icon" href="https://www.canada..../wet-boew/assets/favicon.ico" />\n    \n  \n    \n    \n    \n  \n  \n  \n\n  \n  \n      \n      \n      \n    \n  \n\n  \n\n\n    \n      \n      <link rel="stylesheet" href="TEST_TEMPLATE_HEAD_END.css" type="text/css">\n    \n\n    \n    <link href="....../webassets/base/b44cc5bc_main.css" rel="stylesheet" nonce="ZIU5RjnSCV6OLhs313fR1Q"/>\n<link href="....../webassets/ckanext-scheming/073d7cfa_scheming_css.css" rel="st...e7_fontawesome.css" rel="stylesheet" nonce="ZIU5RjnSCV6OLhs313fR1Q"/>\n    <script src="....../webassets/canada_public/562e1564_canada_public_analytics.js" type="text/javascript" nonce="ZIU5RjnSCV6OLhs313fR1Q"></script>\n<script src="....../webassets/canada_internal_analytics/201f40a5_canada_internal_analytics.js" type="text/javascript" nonce="ZIU5RjnSCV6OLhs313fR1Q"></script>\n<script src="....../webassets/vendor/8c3c143a_jquery.js" type="text/javascript" nonce="ZIU5RjnSCV6OLhs313fR1Q"></script>\n<script src="....../webassets/vendor/9cf42cfd_vendor.js" type="text/javascript" nonce="ZIU5RjnSCV6OLhs313fR1Q"></script>\n<script src="....../webassets/vendor/6d1ad7e6_bootstrap.js" type="text/javascript" nonce="ZIU5RjnSCV6OLhs313fR1Q"></script>\n<script src="....../webassets/base/6fddaa3f_main.js" type="text/javascript" nonce="ZIU5RjnSCV6OLhs313fR1Q"></script>\n<script src="....../webassets/base/7435ee13_ckan.js" type="text/javascript" nonce="ZIU5RjnSCV6OLhs313fR1Q"></script>\n<script src="....../webassets/base/cd2c0272_tracking.js" type="text/javascript" nonce="ZIU5RjnSCV6OLhs313fR1Q"></script>\n<script src="....../webassets/activity/0fdb5ee0_activity.js" type="text/javascript" nonce="ZIU5RjnSCV6OLhs313fR1Q"></script>\n  </body>\n</html>'
E        +  where '<!DOCTYPE html><!--[if lt IE 9]>\n  <html class="no-js lt-ie9" lang="en" dir="ltr"><![endif]--> <!--[if gt IE 8]><!-->\n  <html class="no-js" lang="en" dir="ltr"> <!--<![endif]-->\n  <head>\n    \n  <meta charset="utf-8" />\n      <meta name="csrf_field_name" content="_csrf_token" />\n      <meta name="_csrf_token" content="ImEyMmVmNmM1ZDVkNTZhNjI1ZTZhZDgyNTU4Y2I2NDgyMDU5OWI2NGUi.acWd8Q.ZK3gN9uZn1b6KZtCdqzL-nbIPyQ" />\n\n      <meta name="generator" content="ckan 2.10.8" />\n      <meta name="viewport" content="width=device-width, initial-scale=1.0">\n  \n    <meta property="og:title" content="Error 500 - CKAN">\n  \n  \n    \n  \n\n    <title>Error 500 - CKAN</title>\n\n    \n    \n  <link rel="shortcut icon" href="https://www.canada..../wet-boew/assets/favicon.ico" />\n    \n  \n    \n    \n    \n  \n  \n  \n\n  \n  \n      \n      \n      \n    \n  \n\n  \n\n\n    \n      \n      <link rel="stylesheet" href="TEST_TEMPLATE_HEAD_END.css" type="text/css">\n    \n\n    \n    <link href="....../webassets/base/b44cc5bc_main.css" rel="stylesheet" nonce="ZIU5RjnSCV6OLhs313fR1Q"/>\n<link href="....../webassets/ckanext-scheming/073d7cfa_scheming_css.css" rel="st...e7_fontawesome.css" rel="stylesheet" nonce="ZIU5RjnSCV6OLhs313fR1Q"/>\n    <script src="....../webassets/canada_public/562e1564_canada_public_analytics.js" type="text/javascript" nonce="ZIU5RjnSCV6OLhs313fR1Q"></script>\n<script src="....../webassets/canada_internal_analytics/201f40a5_canada_internal_analytics.js" type="text/javascript" nonce="ZIU5RjnSCV6OLhs313fR1Q"></script>\n<script src="....../webassets/vendor/8c3c143a_jquery.js" type="text/javascript" nonce="ZIU5RjnSCV6OLhs313fR1Q"></script>\n<script src="....../webassets/vendor/9cf42cfd_vendor.js" type="text/javascript" nonce="ZIU5RjnSCV6OLhs313fR1Q"></script>\n<script src="....../webassets/vendor/6d1ad7e6_bootstrap.js" type="text/javascript" nonce="ZIU5RjnSCV6OLhs313fR1Q"></script>\n<script src="....../webassets/base/6fddaa3f_main.js" type="text/javascript" nonce="ZIU5RjnSCV6OLhs313fR1Q"></script>\n<script src="....../webassets/base/7435ee13_ckan.js" type="text/javascript" nonce="ZIU5RjnSCV6OLhs313fR1Q"></script>\n<script src="....../webassets/base/cd2c0272_tracking.js" type="text/javascript" nonce="ZIU5RjnSCV6OLhs313fR1Q"></script>\n<script src="....../webassets/activity/0fdb5ee0_activity.js" type="text/javascript" nonce="ZIU5RjnSCV6OLhs313fR1Q"></script>\n  </body>\n</html>' = <WrapperTestResponse 20621 bytes [500 INTERNAL SERVER ERROR]>.body

.../canada/tests/test_webforms.py:521: AssertionError
ckanext/canada/tests/test_webforms.py::TestRecombinantWebForms::test_editor_can_update_single_record
Stack Traces | 9.75s run time
self = <ckanext.canada.tests.test_webforms.TestRecombinantWebForms object at 0x7f68bb7a4100>
app = <ckan.tests.helpers.CKANTestApp object at 0x7f68b687e2b0>

    @mock.patch.object(h, 'flash_notice', flashes.mock_flash)
    @mock.patch.object(h, 'get_flashed_messages', flashes.mock_get_flashed_messages)
    @mock.patch.object(h, 'is_registry_domain', mock_is_registry_domain)
    def test_editor_can_update_single_record(self, app):
        self._lc_create_pd_record()
    
        offset = h.url_for('canada.update_pd_record',
                           resource_name=self.pd_type,
                           owner_org=self.org['name'],
                           pk=self.example_record['request_number'])
        response = app.get(offset, extra_environ=self.extra_environ_editor,
                           environ_overrides=self.environ_overrides_editor)
    
>       assert 'Update Record' in response.body
E       assert 'Update Record' in '<!DOCTYPE html><!--[if lt IE 9]>\n  <html class="no-js lt-ie9" lang="en" dir="ltr"><![endif]--> <!--[if gt IE 8]><!-->\n  <html class="no-js" lang="en" dir="ltr"> <!--<![endif]-->\n  <head>\n    \n  <meta charset="utf-8" />\n      <meta name="csrf_field_name" content="_csrf_token" />\n      <meta name="_csrf_token" content="IjAwZGFlMmJkOWFjNzk0NTA3Mzg5YzlhMjVmZGJhMTlkZGQ3Yjk5M2Qi.acWeBQ.BLBzcWXujLcPUovlUPtTHuODZ5w" />\n\n      <meta name="generator" content="ckan 2.10.8" />\n      <meta name="viewport" content="width=device-width, initial-scale=1.0">\n  \n    <meta property="og:title" content="Error 500 - CKAN">\n  \n  \n    \n  \n\n    <title>Error 500 - CKAN</title>\n\n    \n    \n  <link rel="shortcut icon" href="https://www.canada..../wet-boew/assets/favicon.ico" />\n    \n  \n    \n    \n    \n  \n  \n  \n\n  \n  \n      \n      \n      \n    \n  \n\n  \n\n\n    \n      \n      <link rel="stylesheet" href="TEST_TEMPLATE_HEAD_END.css" type="text/css">\n    \n\n    \n    <link href="....../webassets/base/b44cc5bc_main.css" rel="stylesheet" nonce="EMc28XdtGLZGwn93IXLKFH"/>\n<link href="....../webassets/ckanext-scheming/073d7cfa_scheming_css.css" rel="st...e7_fontawesome.css" rel="stylesheet" nonce="EMc28XdtGLZGwn93IXLKFH"/>\n    <script src="....../webassets/canada_public/562e1564_canada_public_analytics.js" type="text/javascript" nonce="EMc28XdtGLZGwn93IXLKFH"></script>\n<script src="....../webassets/canada_internal_analytics/201f40a5_canada_internal_analytics.js" type="text/javascript" nonce="EMc28XdtGLZGwn93IXLKFH"></script>\n<script src="....../webassets/vendor/8c3c143a_jquery.js" type="text/javascript" nonce="EMc28XdtGLZGwn93IXLKFH"></script>\n<script src="....../webassets/vendor/9cf42cfd_vendor.js" type="text/javascript" nonce="EMc28XdtGLZGwn93IXLKFH"></script>\n<script src="....../webassets/vendor/6d1ad7e6_bootstrap.js" type="text/javascript" nonce="EMc28XdtGLZGwn93IXLKFH"></script>\n<script src="....../webassets/base/6fddaa3f_main.js" type="text/javascript" nonce="EMc28XdtGLZGwn93IXLKFH"></script>\n<script src="....../webassets/base/7435ee13_ckan.js" type="text/javascript" nonce="EMc28XdtGLZGwn93IXLKFH"></script>\n<script src="....../webassets/base/cd2c0272_tracking.js" type="text/javascript" nonce="EMc28XdtGLZGwn93IXLKFH"></script>\n<script src="....../webassets/activity/0fdb5ee0_activity.js" type="text/javascript" nonce="EMc28XdtGLZGwn93IXLKFH"></script>\n  </body>\n</html>'
E        +  where '<!DOCTYPE html><!--[if lt IE 9]>\n  <html class="no-js lt-ie9" lang="en" dir="ltr"><![endif]--> <!--[if gt IE 8]><!-->\n  <html class="no-js" lang="en" dir="ltr"> <!--<![endif]-->\n  <head>\n    \n  <meta charset="utf-8" />\n      <meta name="csrf_field_name" content="_csrf_token" />\n      <meta name="_csrf_token" content="IjAwZGFlMmJkOWFjNzk0NTA3Mzg5YzlhMjVmZGJhMTlkZGQ3Yjk5M2Qi.acWeBQ.BLBzcWXujLcPUovlUPtTHuODZ5w" />\n\n      <meta name="generator" content="ckan 2.10.8" />\n      <meta name="viewport" content="width=device-width, initial-scale=1.0">\n  \n    <meta property="og:title" content="Error 500 - CKAN">\n  \n  \n    \n  \n\n    <title>Error 500 - CKAN</title>\n\n    \n    \n  <link rel="shortcut icon" href="https://www.canada..../wet-boew/assets/favicon.ico" />\n    \n  \n    \n    \n    \n  \n  \n  \n\n  \n  \n      \n      \n      \n    \n  \n\n  \n\n\n    \n      \n      <link rel="stylesheet" href="TEST_TEMPLATE_HEAD_END.css" type="text/css">\n    \n\n    \n    <link href="....../webassets/base/b44cc5bc_main.css" rel="stylesheet" nonce="EMc28XdtGLZGwn93IXLKFH"/>\n<link href="....../webassets/ckanext-scheming/073d7cfa_scheming_css.css" rel="st...e7_fontawesome.css" rel="stylesheet" nonce="EMc28XdtGLZGwn93IXLKFH"/>\n    <script src="....../webassets/canada_public/562e1564_canada_public_analytics.js" type="text/javascript" nonce="EMc28XdtGLZGwn93IXLKFH"></script>\n<script src="....../webassets/canada_internal_analytics/201f40a5_canada_internal_analytics.js" type="text/javascript" nonce="EMc28XdtGLZGwn93IXLKFH"></script>\n<script src="....../webassets/vendor/8c3c143a_jquery.js" type="text/javascript" nonce="EMc28XdtGLZGwn93IXLKFH"></script>\n<script src="....../webassets/vendor/9cf42cfd_vendor.js" type="text/javascript" nonce="EMc28XdtGLZGwn93IXLKFH"></script>\n<script src="....../webassets/vendor/6d1ad7e6_bootstrap.js" type="text/javascript" nonce="EMc28XdtGLZGwn93IXLKFH"></script>\n<script src="....../webassets/base/6fddaa3f_main.js" type="text/javascript" nonce="EMc28XdtGLZGwn93IXLKFH"></script>\n<script src="....../webassets/base/7435ee13_ckan.js" type="text/javascript" nonce="EMc28XdtGLZGwn93IXLKFH"></script>\n<script src="....../webassets/base/cd2c0272_tracking.js" type="text/javascript" nonce="EMc28XdtGLZGwn93IXLKFH"></script>\n<script src="....../webassets/activity/0fdb5ee0_activity.js" type="text/javascript" nonce="EMc28XdtGLZGwn93IXLKFH"></script>\n  </body>\n</html>' = <WrapperTestResponse 20226 bytes [500 INTERNAL SERVER ERROR]>.body

.../canada/tests/test_webforms.py:571: AssertionError
ckanext/canada/tests/test_webforms.py::TestRecombinantWebForms::test_editor_can_create_single_record
Stack Traces | 10.6s run time
self = <ckanext.canada.tests.test_webforms.TestRecombinantWebForms object at 0x7f68b78ede50>
app = <ckan.tests.helpers.CKANTestApp object at 0x7f68b82deb50>

    @mock.patch.object(h, 'flash_notice', flashes.mock_flash)
    @mock.patch.object(h, 'get_flashed_messages', flashes.mock_get_flashed_messages)
    @mock.patch.object(h, 'is_registry_domain', mock_is_registry_domain)
    def test_editor_can_create_single_record(self, app):
        self._lc_init_pd()
    
        offset = h.url_for('canada.create_pd_record',
                           resource_name=self.pd_type,
                           owner_org=self.org['name'])
        response = app.get(offset, extra_environ=self.extra_environ_editor,
                           environ_overrides=self.environ_overrides_editor)
    
>       assert 'Create Record' in response.body
E       assert 'Create Record' in '<!DOCTYPE html><!--[if lt IE 9]>\n  <html class="no-js lt-ie9" lang="en" dir="ltr"><![endif]--> <!--[if gt IE 8]><!-->\n  <html class="no-js" lang="en" dir="ltr"> <!--<![endif]-->\n  <head>\n    \n  <meta charset="utf-8" />\n      <meta name="csrf_field_name" content="_csrf_token" />\n      <meta name="_csrf_token" content="IjZiMTVkOWJiOTlmZDQxOTJlMjFkMTE0MTVkOTRjMzZkZDU4N2U3ZWQi.acWd-w.0cbcAKJEi1B5urJf0-7Ds7P081c" />\n\n      <meta name="generator" content="ckan 2.10.8" />\n      <meta name="viewport" content="width=device-width, initial-scale=1.0">\n  \n    <meta property="og:title" content="Error 500 - CKAN">\n  \n  \n    \n  \n\n    <title>Error 500 - CKAN</title>\n\n    \n    \n  <link rel="shortcut icon" href="https://www.canada..../wet-boew/assets/favicon.ico" />\n    \n  \n    \n    \n    \n  \n  \n  \n\n  \n  \n      \n      \n      \n    \n  \n\n  \n\n\n    \n      \n      <link rel="stylesheet" href="TEST_TEMPLATE_HEAD_END.css" type="text/css">\n    \n\n    \n    <link href="....../webassets/base/b44cc5bc_main.css" rel="stylesheet" nonce="punRs5H9OSG4HJSYNvipI3"/>\n<link href="....../webassets/ckanext-scheming/073d7cfa_scheming_css.css" rel="st...e7_fontawesome.css" rel="stylesheet" nonce="punRs5H9OSG4HJSYNvipI3"/>\n    <script src="....../webassets/canada_public/562e1564_canada_public_analytics.js" type="text/javascript" nonce="punRs5H9OSG4HJSYNvipI3"></script>\n<script src="....../webassets/canada_internal_analytics/201f40a5_canada_internal_analytics.js" type="text/javascript" nonce="punRs5H9OSG4HJSYNvipI3"></script>\n<script src="....../webassets/vendor/8c3c143a_jquery.js" type="text/javascript" nonce="punRs5H9OSG4HJSYNvipI3"></script>\n<script src="....../webassets/vendor/9cf42cfd_vendor.js" type="text/javascript" nonce="punRs5H9OSG4HJSYNvipI3"></script>\n<script src="....../webassets/vendor/6d1ad7e6_bootstrap.js" type="text/javascript" nonce="punRs5H9OSG4HJSYNvipI3"></script>\n<script src="....../webassets/base/6fddaa3f_main.js" type="text/javascript" nonce="punRs5H9OSG4HJSYNvipI3"></script>\n<script src="....../webassets/base/7435ee13_ckan.js" type="text/javascript" nonce="punRs5H9OSG4HJSYNvipI3"></script>\n<script src="....../webassets/base/cd2c0272_tracking.js" type="text/javascript" nonce="punRs5H9OSG4HJSYNvipI3"></script>\n<script src="....../webassets/activity/0fdb5ee0_activity.js" type="text/javascript" nonce="punRs5H9OSG4HJSYNvipI3"></script>\n  </body>\n</html>'
E        +  where '<!DOCTYPE html><!--[if lt IE 9]>\n  <html class="no-js lt-ie9" lang="en" dir="ltr"><![endif]--> <!--[if gt IE 8]><!-->\n  <html class="no-js" lang="en" dir="ltr"> <!--<![endif]-->\n  <head>\n    \n  <meta charset="utf-8" />\n      <meta name="csrf_field_name" content="_csrf_token" />\n      <meta name="_csrf_token" content="IjZiMTVkOWJiOTlmZDQxOTJlMjFkMTE0MTVkOTRjMzZkZDU4N2U3ZWQi.acWd-w.0cbcAKJEi1B5urJf0-7Ds7P081c" />\n\n      <meta name="generator" content="ckan 2.10.8" />\n      <meta name="viewport" content="width=device-width, initial-scale=1.0">\n  \n    <meta property="og:title" content="Error 500 - CKAN">\n  \n  \n    \n  \n\n    <title>Error 500 - CKAN</title>\n\n    \n    \n  <link rel="shortcut icon" href="https://www.canada..../wet-boew/assets/favicon.ico" />\n    \n  \n    \n    \n    \n  \n  \n  \n\n  \n  \n      \n      \n      \n    \n  \n\n  \n\n\n    \n      \n      <link rel="stylesheet" href="TEST_TEMPLATE_HEAD_END.css" type="text/css">\n    \n\n    \n    <link href="....../webassets/base/b44cc5bc_main.css" rel="stylesheet" nonce="punRs5H9OSG4HJSYNvipI3"/>\n<link href="....../webassets/ckanext-scheming/073d7cfa_scheming_css.css" rel="st...e7_fontawesome.css" rel="stylesheet" nonce="punRs5H9OSG4HJSYNvipI3"/>\n    <script src="....../webassets/canada_public/562e1564_canada_public_analytics.js" type="text/javascript" nonce="punRs5H9OSG4HJSYNvipI3"></script>\n<script src="....../webassets/canada_internal_analytics/201f40a5_canada_internal_analytics.js" type="text/javascript" nonce="punRs5H9OSG4HJSYNvipI3"></script>\n<script src="....../webassets/vendor/8c3c143a_jquery.js" type="text/javascript" nonce="punRs5H9OSG4HJSYNvipI3"></script>\n<script src="....../webassets/vendor/9cf42cfd_vendor.js" type="text/javascript" nonce="punRs5H9OSG4HJSYNvipI3"></script>\n<script src="....../webassets/vendor/6d1ad7e6_bootstrap.js" type="text/javascript" nonce="punRs5H9OSG4HJSYNvipI3"></script>\n<script src="....../webassets/base/6fddaa3f_main.js" type="text/javascript" nonce="punRs5H9OSG4HJSYNvipI3"></script>\n<script src="....../webassets/base/7435ee13_ckan.js" type="text/javascript" nonce="punRs5H9OSG4HJSYNvipI3"></script>\n<script src="....../webassets/base/cd2c0272_tracking.js" type="text/javascript" nonce="punRs5H9OSG4HJSYNvipI3"></script>\n<script src="....../webassets/activity/0fdb5ee0_activity.js" type="text/javascript" nonce="punRs5H9OSG4HJSYNvipI3"></script>\n  </body>\n</html>' = <WrapperTestResponse 20213 bytes [500 INTERNAL SERVER ERROR]>.body

.../canada/tests/test_webforms.py:498: AssertionError
ckanext/canada/tests/test_make.py::TestMakePD::test_make_service
Stack Traces | 71.8s run time
self = <ckanext.canada.tests.test_make.TestMakePD object at 0x7f06c0ed86a0>

    def test_make_service(self):
        assert self.ckan_ini
        self._setup_ini(self.ckan_ini)
    
        self._setup_pd(type='service', nil_type='service-std')
    
        make_process = subprocess.Popen(["make upload-service"], shell=True, cwd=MAKE_PATH, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        stdout, stderr = make_process.communicate()
    
        stdout = stdout.decode("utf-8")
    
        assert "Usage:" not in stdout
        assert "upload-service] Error" not in stdout
    
        make_process = subprocess.Popen(["make rebuild-service"], shell=True, cwd=MAKE_PATH, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        stdout, stderr = make_process.communicate()
    
        stdout = stdout.decode("utf-8")
    
        # there is no search for service inventory, just test for no errors
        assert "Usage:" not in stdout
        assert "rebuild-service] Error" not in stdout
    
        # test the published service resource
        chromo = get_chromo('service')
        resource_filepath = get_resource_uploader(self.action.resource_show(id=chromo['published_resource_id'])).get_path(chromo['published_resource_id'])
    
        loader.load_csv(
            resource_filepath,
            resource_id=chromo['published_resource_id'],
            mimetype="text/csv",
            logger=logger,
        )
    
        published_fields, published_records = self._get_ds_records('service')
        published_record = published_records[0]
    
        expected_fields = ['_id']
        removed_fields = ['record_created', 'record_modified', 'user_modified']
        for field in chromo['fields']:
            if field['datastore_id'] in removed_fields:
                continue
            expected_fields.append(field['datastore_id'])
    
        published_fields = [f['id'] for f in published_fields]
    
        expected_record = {
            '_id': published_record['_id'],
            'fiscal_yr': '2022-2023',
            'service_id': '1001',
            'service_name_en': 'Old Age Security (OAS) Benefits',
            'service_name_fr': 'Prestations de la Sécurité de la vieillesse',
            'service_description_en': 'The Old Age Security (OAS) pension is a monthly payment available to most Canadians 65 years of age who meet the Canadian legal status and residence requirements. In addition to the Old Age Security pension, there are three types of Old Age Security benefits:  the Guaranteed Income Supplement, Allowance and Allowance for the Survivor. The OAS provides financial support to millions of seniors, including those that are low-income, each year.',
            'service_description_fr': "La pension de la Sécurité de la vieillesse (SV) est une prestation mensuelle versée à la plupart des Canadiens âgés de 65 ans et plus qui satisfont aux exigences relatives au statut juridique et à la résidence au Canada. En plus de la pension de la Sécurité de la vieillesse, il existe trois types de prestations de la Sécurité de la vieillesse : le Supplément de revenu garanti, l'Allocation et l'Allocation au survivant. La SV verse chaque année un soutien financier à des millions d'aînés, incluant ceux à faible revenu.",
            'service_type': 'RES',
            'service_recipient_type': 'CLIENT',
            'service_scope': 'EXTERN',
            'client_target_groups': 'PERSON',
            'program_id': 'BGN01',
            'program_name_en': "'Old Age Security'",
            'program_name_fr': "'Sécurité de la vieillesse'",
            'client_feedback_channel': 'EML,FAX,ONL,PERSON,POST,TEL',
            'automated_decision_system': 'N',
            'automated_decision_system_description_en': None,
            'automated_decision_system_description_fr': None,
            'service_fee': 'N',
            'os_account_registration': 'Y',
            'os_authentication': 'Y',
            'os_application': 'Y',
            'os_decision': 'Y',
            'os_issuance': 'Y',
            'os_issue_resolution_feedback': 'Y',
            'os_comments_client_interaction_en': None,
            'os_comments_client_interaction_fr': None,
            'last_service_review': None,
            'last_service_improvement': '2021-2022',
            'sin_usage': 'Y',
            'cra_bn_identifier_usage': 'Y',
            'num_phone_enquiries': '7252346',
            'num_applications_by_phone': '0',
            'num_website_visits': '5446484',
            'num_applications_online': '276390',
            'num_applications_in_person': '0',
            'num_applications_by_mail': '792026',
            'num_applications_by_email': '0',
            'num_applications_by_fax': '0',
            'num_applications_by_other': '2218002',
            'num_applications_total': '3286418',
            'special_remarks_en': "- The volume reflected in the 'Applications by Mail' column include the volume of paper applications for the following OAS pension benefits application types: OAS basic pension; the Guaranteed Income Supplement (GIS); Allowance; Allowance Survivor; Renewal of GIS/Allowance/Allowance Survivor; Options for GIS/Allowance/Allowance Survivor; and foreign benefits.\n- The volume reflected in the 'Number of Automatic Enrolments' column represents the volume of Automatic Enrolment into the OAS basic pension and the GIS.\n- The volume reflected in the 'Applications through Other Channels' column represents the volume of the Automatic Renewal of income-tested benefits through the CRA for the GIS.\n- Applications to OAS pension benefits do not constitute the largest volume of work done by the OAS program. In addition to applications, there were also another 3,143,898 OAS and foreign benefit account revisions in 2022-2023.\n- OAS and CPP telephone enquiries are managed through the same Pensions Toll-free service, with significant overlap between the two programs on many calls. The metrics reported for CPP and OAS,  such as the volume of calls, are therefore identical and are non-cumulative (i.e. they are not to be added together).\"",
            'special_remarks_fr': "- Le volume indiqué dans la colonne « Demandes par la poste » comprend le volume de demandes papier pour les types de demandes de prestations de pension de la SV suivants : pension de base de la SV ; le Supplément de revenu garanti (SRG); Allocation ; Allocation de survivant ; Renouvellement du SRG/Allocation/ Allocation de survivant ; options pour le SRG/l'allocation/l'allocation de survivant ; et les prestations étrangères.\n- Le volume indiqué dans la colonne \"\"Nombre d'inscriptions automatiques\"\" représente le volume des inscriptions automatiques à la pension de base de la SV et au SRG.\n- Le volume reflété dans la colonne « Demandes par d'autres canaux » représente le volume d'adhésion automatique à la pension de base de la SV et du SRG, ainsi que le renouvellement automatique des prestations fondées sur le revenu par l'intermédiaire de l'ARC pour le SRG.\n- Les demandes de prestations de pension de la SV ne constituent pas le plus gros volume de travail effectué par le programme de la SV. En plus des demandes, il y a eu également 3 143 898 autres révisions des comptes de SV et de prestations étrangères en 2022-2023\n- Les demandes de renseignements téléphoniques sur la SV et le RPC sont gérées par le même service téléphonique sans frais des pensions, avec un chevauchement important entre les deux programmes pour de nombreux appels. Les mesures rapportées pour le RPC et la SV, comme le volume d'appels, sont donc identiques et non cumulatives (c'est-à-dire qu'elles ne doivent pas être additionnées). \"",
            'service_uri_en': 'https://www.canada..../publicpensions/cpp/old-age-security.html',
            'service_uri_fr': 'https://www.canada..../pensionspubliques/rpc/securite-vieillesse.html',
            'owner_org': self.org['name'],
            'owner_org_title': self.org['title'],
        }
    
        assert expected_fields == published_fields
>       assert expected_record == published_record
E       assert {'_id': 1, 'a...r': None, ...} == {'_id': 1, 'a...r': None, ...}
E         Omitting 45 identical items, use -vv to show
E         Differing items:
E         {'program_name_en': "'Old Age Security'"} != {'program_name_en': '"Old Age Security"'}
E         {'program_name_fr': "'Sécurité de la vieillesse'"} != {'program_name_fr': '"Sécurité de la vieillesse"'}
E         Full diff:
E           {
E            '_id': 1,
E            'automated_decision_system': 'N',
E            'automated_decision_system_description_en': None,
E            'automated_decision_system_description_fr': None,
E            'client_feedback_channel': 'EML,FAX,ONL,PERSON,POST,TEL',
E            'client_target_groups': 'PERSON',
E            'cra_bn_identifier_usage': 'Y',
E            'fiscal_yr': '2022-2023',
E            'last_service_improvement': '2021-2022',
E            'last_service_review': None,
E            'num_applications_by_email': '0',
E            'num_applications_by_fax': '0',
E            'num_applications_by_mail': '792026',
E            'num_applications_by_other': '2218002',
E            'num_applications_by_phone': '0',
E            'num_applications_in_person': '0',
E            'num_applications_online': '276390',
E            'num_applications_total': '3286418',
E            'num_phone_enquiries': '7252346',
E            'num_website_visits': '5446484',
E            'os_account_registration': 'Y',
E            'os_application': 'Y',
E            'os_authentication': 'Y',
E            'os_comments_client_interaction_en': None,
E            'os_comments_client_interaction_fr': None,
E            'os_decision': 'Y',
E            'os_issuance': 'Y',
E            'os_issue_resolution_feedback': 'Y',
E            'owner_org': 'test-org-06',
E            'owner_org_title': 'Test Org Title | Test FR Org Title',
E            'program_id': 'BGN01',
E         -  'program_name_en': '"Old Age Security"',
E         ?                      -                 -
E         +  'program_name_en': "'Old Age Security'",
E         ?                     +                 +
E         -  'program_name_fr': '"Sécurité de la vieillesse"',
E         ?                      -                          -
E         +  'program_name_fr': "'Sécurité de la vieillesse'",
E         ?                     +                          +
E            'service_description_en': 'The Old Age Security (OAS) pension is a monthly '
E                                      'payment available to most Canadians 65 years of '
E                                      'age who meet the Canadian legal status and '
E                                      'residence requirements. In addition to the Old Age '
E                                      'Security pension, there are three types of Old Age '
E                                      'Security benefits:  the Guaranteed Income '
E                                      'Supplement, Allowance and Allowance for the '
E                                      'Survivor. The OAS provides financial support to '
E                                      'millions of seniors, including those that are '
E                                      'low-income, each year.',
E            'service_description_fr': 'La pension de la Sécurité de la vieillesse (SV) '
E                                      'est une prestation mensuelle versée à la plupart '
E                                      'des Canadiens âgés de 65 ans et plus qui satisfont '
E                                      'aux exigences relatives au statut juridique et à '
E                                      'la résidence au Canada. En plus de la pension de '
E                                      'la Sécurité de la vieillesse, il existe trois '
E                                      'types de prestations de la Sécurité de la '
E                                      'vieillesse : le Supplément de revenu garanti, '
E                                      "l'Allocation et l'Allocation au survivant. La SV "
E                                      'verse chaque année un soutien financier à des '
E                                      "millions d'aînés, incluant ceux à faible revenu.",
E            'service_fee': 'N',
E            'service_id': '1001',
E            'service_name_en': 'Old Age Security (OAS) Benefits',
E            'service_name_fr': 'Prestations de la Sécurité de la vieillesse',
E            'service_recipient_type': 'CLIENT',
E            'service_scope': 'EXTERN',
E            'service_type': 'RES',
E            'service_uri_en': 'https://www.canada..../publicpensions/cpp/old-age-security.html',
E            'service_uri_fr': 'https://www.canada..../pensionspubliques/rpc/securite-vieillesse.html',
E            'sin_usage': 'Y',
E            'special_remarks_en': "- The volume reflected in the 'Applications by Mail' "
E                                  'column include the volume of paper applications for '
E                                  'the following OAS pension benefits application types: '
E                                  'OAS basic pension; the Guaranteed Income Supplement '
E                                  '(GIS); Allowance; Allowance Survivor; Renewal of '
E                                  'GIS/Allowance/Allowance Survivor; Options for '
E                                  'GIS/Allowance/Allowance Survivor; and foreign '
E                                  'benefits.\n'
E                                  "- The volume reflected in the 'Number of Automatic "
E                                  "Enrolments' column represents the volume of Automatic "
E                                  'Enrolment into the OAS basic pension and the GIS.\n'
E                                  "- The volume reflected in the 'Applications through "
E                                  "Other Channels' column represents the volume of the "
E                                  'Automatic Renewal of income-tested benefits through '
E                                  'the CRA for the GIS.\n'
E                                  '- Applications to OAS pension benefits do not '
E                                  'constitute the largest volume of work done by the OAS '
E                                  'program. In addition to applications, there were also '
E                                  'another 3,143,898 OAS and foreign benefit account '
E                                  'revisions in 2022-2023.\n'
E                                  '- OAS and CPP telephone enquiries are managed through '
E                                  'the same Pensions Toll-free service, with significant '
E                                  'overlap between the two programs on many calls. The '
E                                  'metrics reported for CPP and OAS,  such as the volume '
E                                  'of calls, are therefore identical and are '
E                                  'non-cumulative (i.e. they are not to be added '
E                                  'together)."',
E            'special_remarks_fr': '- Le volume indiqué dans la colonne « Demandes par la '
E                                  'poste » comprend le volume de demandes papier pour les '
E                                  'types de demandes de prestations de pension de la SV '
E                                  'suivants : pension de base de la SV ; le Supplément de '
E                                  'revenu garanti (SRG); Allocation ; Allocation de '
E                                  'survivant ; Renouvellement du SRG/Allocation/ '
E                                  'Allocation de survivant ; options pour le '
E                                  "SRG/l'allocation/l'allocation de survivant ; et les "
E                                  'prestations étrangères.\n'
E                                  '- Le volume indiqué dans la colonne ""Nombre '
E                                  'd\'inscriptions automatiques"" représente le volume '
E                                  'des inscriptions automatiques à la pension de base de '
E                                  'la SV et au SRG.\n'
E                                  '- Le volume reflété dans la colonne « Demandes par '
E                                  "d'autres canaux » représente le volume d'adhésion "
E                                  'automatique à la pension de base de la SV et du SRG, '
E                                  'ainsi que le renouvellement automatique des '
E                                  "prestations fondées sur le revenu par l'intermédiaire "
E                                  "de l'ARC pour le SRG.\n"
E                                  '- Les demandes de prestations de pension de la SV ne '
E                                  'constituent pas le plus gros volume de travail '
E                                  'effectué par le programme de la SV. En plus des '
E                                  'demandes, il y a eu également 3 143 898 autres '
E                                  'révisions des comptes de SV et de prestations '
E                                  'étrangères en 2022-2023\n'
E                                  '- Les demandes de renseignements téléphoniques sur la '
E                                  'SV et le RPC sont gérées par le même service '
E                                  'téléphonique sans frais des pensions, avec un '
E                                  'chevauchement important entre les deux programmes pour '
E                                  'de nombreux appels. Les mesures rapportées pour le RPC '
E                                  "et la SV, comme le volume d'appels, sont donc "
E                                  "identiques et non cumulatives (c'est-à-dire qu'elles "
E                                  'ne doivent pas être additionnées). "',
E           }

.../canada/tests/test_make.py:627: AssertionError
View the full list of 2 ❄️ flaky test(s)
ckanext/canada/tests/test_validators.py::TestNAVLSchema::test_guess_resource_format

Flake rate in main: 3.33% (Passed 29 times, Failed 1 times)

Stack Traces | 0.052s run time
self = <ckanext.canada.tests.test_validators.TestNAVLSchema object at 0x7f8ed6157310>

    def test_guess_resource_format(self):
        """
        Creating/updating a Resource should guess the format based on url.
        """
>       pkg = self.sysadmin_action.package_create(**self.complete_pkg)

.../canada/tests/test_validators.py:389: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../ckanapi/ckanapi/common.py:60: in action
    return self._ckan.call_action(name, data_dict=kwargs)
.../ckanapi/ckanapi/localckan.py:74: in call_action
    return self._get_action(action)(context, data_dict)
.../ckan/logic/__init__.py:581: in wrapped
    result = _action(context, data_dict, **kw)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

context = {'__auth_audit': [], '__auth_user_obj_checked': True, 'auth_user_obj': <User id=7e32f2f7-4b30-44b5-a26d-f9d55870afbc n...n.com/985/232 plugin_extras=None>, 'model': <module 'ckan.model' from '.../ckan/model/__init__.py'>, ...}
data_dict = {'collection': 'primary', 'date_published': '2013-01-01', 'frequency': 'as_needed', 'imso_approval': 'true', ...}

    def package_create(
            context: Context, data_dict: DataDict) -> ActionResult.PackageCreate:
        '''Create a new dataset (package).
    
        You must be authorized to create new datasets. If you specify any groups
        for the new dataset, you must also be authorized to edit these groups.
    
        Plugins may change the parameters of this function depending on the value
        of the ``type`` parameter, see the
        :py:class:`~ckan.plugins.interfaces.IDatasetForm` plugin interface.
    
        :param name: the name of the new dataset, must be between 2 and 100
            characters long and contain only lowercase alphanumeric characters,
            ``-`` and ``_``, e.g. ``'warandpeace'``
        :type name: string
        :param title: the title of the dataset (optional, default: same as
            ``name``)
        :type title: string
        :param private: If ``True`` creates a private dataset
        :type private: bool
        :param author: the name of the dataset's author (optional)
        :type author: string
        :param author_email: the email address of the dataset's author (optional)
        :type author_email: string
        :param maintainer: the name of the dataset's maintainer (optional)
        :type maintainer: string
        :param maintainer_email: the email address of the dataset's maintainer
            (optional)
        :type maintainer_email: string
        :param license_id: the id of the dataset's license, see
            :py:func:`~ckan.logic.action.get.license_list` for available values
            (optional)
        :type license_id: license id string
        :param notes: a description of the dataset (optional)
        :type notes: string
        :param url: a URL for the dataset's source (optional)
        :type url: string
        :param version: (optional)
        :type version: string, no longer than 100 characters
        :param state: the current state of the dataset, e.g. ``'active'`` or
            ``'deleted'``, only active datasets show up in search results and
            other lists of datasets, this parameter will be ignored if you are not
            authorized to change the state of the dataset (optional, default:
            ``'active'``)
        :type state: string
        :param type: the type of the dataset (optional),
            :py:class:`~ckan.plugins.interfaces.IDatasetForm` plugins
            associate themselves with different dataset types and provide custom
            dataset handling behaviour for these types
        :type type: string
        :param resources: the dataset's resources, see
            :py:func:`resource_create` for the format of resource dictionaries
            (optional)
        :type resources: list of resource dictionaries
        :param tags: the dataset's tags, see :py:func:`tag_create` for the format
            of tag dictionaries (optional)
        :type tags: list of tag dictionaries
        :param extras: the dataset's extras (optional), extras are arbitrary
            (key: value) metadata items that can be added to datasets, each extra
            dictionary should have keys ``'key'`` (a string), ``'value'`` (a
            string)
        :type extras: list of dataset extra dictionaries
        :param plugin_data: private package data belonging to plugins.
            Only sysadmin users may set this value. It should be a dict that can
            be dumped into JSON, and plugins should namespace their data with the
            plugin name to avoid collisions with other plugins, eg::
    
                {
                    "name": "test-dataset",
                    "plugin_data": {
                        "plugin1": {"key1": "value1"},
                        "plugin2": {"key2": "value2"}
                    }
                }
        :type plugin_data: dict
        :param relationships_as_object: see :py:func:`package_relationship_create`
            for the format of relationship dictionaries (optional)
        :type relationships_as_object: list of relationship dictionaries
        :param relationships_as_subject: see :py:func:`package_relationship_create`
            for the format of relationship dictionaries (optional)
        :type relationships_as_subject: list of relationship dictionaries
        :param groups: the groups to which the dataset belongs (optional), each
            group dictionary should have one or more of the following keys which
            identify an existing group:
            ``'id'`` (the id of the group, string), or ``'name'`` (the name of the
            group, string),  to see which groups exist
            call :py:func:`~ckan.logic.action.get.group_list`
        :type groups: list of dictionaries
        :param owner_org: the id of the dataset's owning organization, see
            :py:func:`~ckan.logic.action.get.organization_list` or
            :py:func:`~ckan.logic.action.get.organization_list_for_user` for
            available values. This parameter can be made optional if the config
            option :ref:`ckan.auth.create_unowned_dataset` is set to ``True``.
        :type owner_org: string
    
        :returns: the newly created dataset (unless 'return_id_only' is set to True
                  in the context, in which case just the dataset id will
                  be returned)
        :rtype: dictionary
    
        '''
        model = context['model']
        user = context['user']
    
        if 'type' not in data_dict:
            package_plugin = lib_plugins.lookup_package_plugin()
            try:
                # use first type as default if user didn't provide type
                package_type = package_plugin.package_types()[0]
            except (AttributeError, IndexError):
                package_type = 'dataset'
                # in case a 'dataset' plugin was registered w/o fallback
                package_plugin = lib_plugins.lookup_package_plugin(package_type)
            data_dict['type'] = package_type
        else:
            package_plugin = lib_plugins.lookup_package_plugin(data_dict['type'])
    
        schema: Schema = context.get(
            'schema') or package_plugin.create_package_schema()
    
        _check_access('package_create', context, data_dict)
    
        if 'api_version' not in context:
            # check_data_dict() is deprecated. If the package_plugin has a
            # check_data_dict() we'll call it, if it doesn't have the method we'll
            # do nothing.
            check_data_dict = getattr(package_plugin, 'check_data_dict', None)
            if check_data_dict:
                try:
                    check_data_dict(data_dict, schema)
                except TypeError:
                    # Old plugins do not support passing the schema so we need
                    # to ensure they still work
                    package_plugin.check_data_dict(data_dict)
    
        data, errors = lib_plugins.plugin_validate(
            package_plugin, context, data_dict, schema, 'package_create')
        log.debug('package_create validate_errs=%r user=%s package=%s data=%r',
                  errors, context.get('user'),
                  data.get('name'), data_dict)
    
        if errors:
            model.Session.rollback()
>           raise ValidationError(errors)
E           ckan.logic.ValidationError: None - {'resources': [{'id': ['Resource id already exists.']}]}

.../logic/action/create.py:203: ValidationError
ckanext/canada/tests/test_validators.py::TestNAVLSchema::test_validation_schema

Flake rate in main: 6.90% (Passed 27 times, Failed 2 times)

Stack Traces | 0.054s run time
self = <ckanext.canada.tests.test_validators.TestNAVLSchema object at 0x7f8ed6157040>

    def test_validation_schema(self):
        "creating a resource with a URL schema should empty the schema"
>       pkg = self.sysadmin_action.package_create(**self.complete_pkg)

.../canada/tests/test_validators.py:364: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../ckanapi/ckanapi/common.py:60: in action
    return self._ckan.call_action(name, data_dict=kwargs)
.../ckanapi/ckanapi/localckan.py:74: in call_action
    return self._get_action(action)(context, data_dict)
.../ckan/logic/__init__.py:581: in wrapped
    result = _action(context, data_dict, **kw)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

context = {'__auth_audit': [], '__auth_user_obj_checked': True, 'auth_user_obj': <User id=7e32f2f7-4b30-44b5-a26d-f9d55870afbc n...n.com/985/232 plugin_extras=None>, 'model': <module 'ckan.model' from '.../ckan/model/__init__.py'>, ...}
data_dict = {'collection': 'primary', 'date_published': '2013-01-01', 'frequency': 'as_needed', 'imso_approval': 'true', ...}

    def package_create(
            context: Context, data_dict: DataDict) -> ActionResult.PackageCreate:
        '''Create a new dataset (package).
    
        You must be authorized to create new datasets. If you specify any groups
        for the new dataset, you must also be authorized to edit these groups.
    
        Plugins may change the parameters of this function depending on the value
        of the ``type`` parameter, see the
        :py:class:`~ckan.plugins.interfaces.IDatasetForm` plugin interface.
    
        :param name: the name of the new dataset, must be between 2 and 100
            characters long and contain only lowercase alphanumeric characters,
            ``-`` and ``_``, e.g. ``'warandpeace'``
        :type name: string
        :param title: the title of the dataset (optional, default: same as
            ``name``)
        :type title: string
        :param private: If ``True`` creates a private dataset
        :type private: bool
        :param author: the name of the dataset's author (optional)
        :type author: string
        :param author_email: the email address of the dataset's author (optional)
        :type author_email: string
        :param maintainer: the name of the dataset's maintainer (optional)
        :type maintainer: string
        :param maintainer_email: the email address of the dataset's maintainer
            (optional)
        :type maintainer_email: string
        :param license_id: the id of the dataset's license, see
            :py:func:`~ckan.logic.action.get.license_list` for available values
            (optional)
        :type license_id: license id string
        :param notes: a description of the dataset (optional)
        :type notes: string
        :param url: a URL for the dataset's source (optional)
        :type url: string
        :param version: (optional)
        :type version: string, no longer than 100 characters
        :param state: the current state of the dataset, e.g. ``'active'`` or
            ``'deleted'``, only active datasets show up in search results and
            other lists of datasets, this parameter will be ignored if you are not
            authorized to change the state of the dataset (optional, default:
            ``'active'``)
        :type state: string
        :param type: the type of the dataset (optional),
            :py:class:`~ckan.plugins.interfaces.IDatasetForm` plugins
            associate themselves with different dataset types and provide custom
            dataset handling behaviour for these types
        :type type: string
        :param resources: the dataset's resources, see
            :py:func:`resource_create` for the format of resource dictionaries
            (optional)
        :type resources: list of resource dictionaries
        :param tags: the dataset's tags, see :py:func:`tag_create` for the format
            of tag dictionaries (optional)
        :type tags: list of tag dictionaries
        :param extras: the dataset's extras (optional), extras are arbitrary
            (key: value) metadata items that can be added to datasets, each extra
            dictionary should have keys ``'key'`` (a string), ``'value'`` (a
            string)
        :type extras: list of dataset extra dictionaries
        :param plugin_data: private package data belonging to plugins.
            Only sysadmin users may set this value. It should be a dict that can
            be dumped into JSON, and plugins should namespace their data with the
            plugin name to avoid collisions with other plugins, eg::
    
                {
                    "name": "test-dataset",
                    "plugin_data": {
                        "plugin1": {"key1": "value1"},
                        "plugin2": {"key2": "value2"}
                    }
                }
        :type plugin_data: dict
        :param relationships_as_object: see :py:func:`package_relationship_create`
            for the format of relationship dictionaries (optional)
        :type relationships_as_object: list of relationship dictionaries
        :param relationships_as_subject: see :py:func:`package_relationship_create`
            for the format of relationship dictionaries (optional)
        :type relationships_as_subject: list of relationship dictionaries
        :param groups: the groups to which the dataset belongs (optional), each
            group dictionary should have one or more of the following keys which
            identify an existing group:
            ``'id'`` (the id of the group, string), or ``'name'`` (the name of the
            group, string),  to see which groups exist
            call :py:func:`~ckan.logic.action.get.group_list`
        :type groups: list of dictionaries
        :param owner_org: the id of the dataset's owning organization, see
            :py:func:`~ckan.logic.action.get.organization_list` or
            :py:func:`~ckan.logic.action.get.organization_list_for_user` for
            available values. This parameter can be made optional if the config
            option :ref:`ckan.auth.create_unowned_dataset` is set to ``True``.
        :type owner_org: string
    
        :returns: the newly created dataset (unless 'return_id_only' is set to True
                  in the context, in which case just the dataset id will
                  be returned)
        :rtype: dictionary
    
        '''
        model = context['model']
        user = context['user']
    
        if 'type' not in data_dict:
            package_plugin = lib_plugins.lookup_package_plugin()
            try:
                # use first type as default if user didn't provide type
                package_type = package_plugin.package_types()[0]
            except (AttributeError, IndexError):
                package_type = 'dataset'
                # in case a 'dataset' plugin was registered w/o fallback
                package_plugin = lib_plugins.lookup_package_plugin(package_type)
            data_dict['type'] = package_type
        else:
            package_plugin = lib_plugins.lookup_package_plugin(data_dict['type'])
    
        schema: Schema = context.get(
            'schema') or package_plugin.create_package_schema()
    
        _check_access('package_create', context, data_dict)
    
        if 'api_version' not in context:
            # check_data_dict() is deprecated. If the package_plugin has a
            # check_data_dict() we'll call it, if it doesn't have the method we'll
            # do nothing.
            check_data_dict = getattr(package_plugin, 'check_data_dict', None)
            if check_data_dict:
                try:
                    check_data_dict(data_dict, schema)
                except TypeError:
                    # Old plugins do not support passing the schema so we need
                    # to ensure they still work
                    package_plugin.check_data_dict(data_dict)
    
        data, errors = lib_plugins.plugin_validate(
            package_plugin, context, data_dict, schema, 'package_create')
        log.debug('package_create validate_errs=%r user=%s package=%s data=%r',
                  errors, context.get('user'),
                  data.get('name'), data_dict)
    
        if errors:
            model.Session.rollback()
>           raise ValidationError(errors)
E           ckan.logic.ValidationError: None - {'resources': [{'id': ['Resource id already exists.']}]}

.../logic/action/create.py:203: ValidationError

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@JVickery-TBS JVickery-TBS marked this pull request as draft March 30, 2026 12:40
@JVickery-TBS

Copy link
Copy Markdown
Contributor Author

Closing in favour of #1668

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants