Skip to content

Views and path for communal election/vote archived results#2460

Open
Tschuppi81 wants to merge 46 commits into
masterfrom
feature/ogc-3103-wab-communal-elections
Open

Views and path for communal election/vote archived results#2460
Tschuppi81 wants to merge 46 commits into
masterfrom
feature/ogc-3103-wab-communal-elections

Conversation

@Tschuppi81
Copy link
Copy Markdown
Contributor

@Tschuppi81 Tschuppi81 commented May 1, 2026

ElectionDay: Adds path and views for municipality results

TYPE: Feature
LINK: ogc-3103

treinhard and others added 21 commits March 13, 2026 10:52
Return proper errors in JSON for 401 and 500 errors.

TYPE: Feature
Replaces existing pre release support.

TYPE: Feature
HINT: New version of xsdata-ech required, run `make update`
Required for large eCH 0252 XML files.
Deleting all elections on the same date that are not in the current
eCH 0252 delivery is to aggressive. Remove only elections in the
same ElectionCompound.

TYPE: Feature
@linear
Copy link
Copy Markdown

linear Bot commented May 1, 2026

@codecov
Copy link
Copy Markdown

codecov Bot commented May 1, 2026

❌ 4 Tests Failed:

Tests completed Failed Passed Skipped
2657 4 2653 18
View the top 3 failed test(s) by shortest run time
tests/onegov/election_day/views/test_views_sitemap.py::test_view_sitemap
Stack Traces | 1.31s run time
election_day_app_zg = <tests.onegov.election_day.conftest.TestApp object at 0x7fa6639d0910>

    def test_view_sitemap(election_day_app_zg: TestApp) -> None:
        principal = election_day_app_zg.principal
        principal.email_notification = True
        principal.sms_notification = 'https://wab.ch/'
        election_day_app_zg.cache.set('principal', principal)
    
        client = Client(election_day_app_zg)
        client.get('/locale/de_CH').follow()
    
        login(client)
    
        new = client.get('.../manage/votes/new-vote')
        new.form['title_de'] = 'Abstimmung 1. Januar 2013'
        new.form['date'] = '2013-01-01'
        new.form['domain'] = 'federation'
        new.form.submit()
    
        new = client.get('.../manage/elections/new-election')
        new.form['title_de'] = 'Wahl 1. Januar 2013'
        new.form['date'] = '2013-01-01'
        new.form['mandates'] = 1
        new.form['type'] = 'majorz'
        new.form['domain'] = 'federation'
        new.form.submit()
    
        # XML
        namespace = '{http://www.sitemaps..../schemas/sitemap/0.9}'
>       xml = client.get('/sitemap.xml').xml
              ^^^^^^^^^^^^^^^^^^^^^^^^^^

.../election_day/views/test_views_sitemap.py:39: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
............................................./app/lib/python3.14....../site-packages/webtest/app.py:328: in get
    return self.do_request(req, status=status,
............................................./app/lib/python3.14....../site-packages/webtest/app.py:627: in do_request
    res = req.get_response(app, catch_exc_info=True)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
............................................./app/lib/python3.14....../site-packages/webob/request.py:1309: in send
    status, headers, app_iter, exc_info = self.call_application(
............................................./app/lib/python3.14....../site-packages/webob/request.py:1278: in call_application
    app_iter = application(self.environ, start_response)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
............................................./app/lib/python3.14.../site-packages/webtest/lint.py:196: in lint_app
    iterator = application(environ, start_response_wrapper)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:219: in with_request_cache_wrapper
    return fn(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:234: in with_print_exceptions_wrapper
    return fn(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^
............................................./app/lib/python3.14.../site-packages/morepath/app.py:138: in __call__
    response = self.publish(request)
               ^^^^^^^^^^^^^^^^^^^^^
............................................./app/lib/python3.14....../site-packages/morepath/core.py:201: in poisoned_host_header_protection_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1762: in http_conflict_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1787: in activate_session_manager
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1805: in close_session_after_request
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/file/integration.py:476: in configure_depot_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/election_day/app.py:221: in override_language_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/election_day/app.py:246: in cache_control_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/election_day/app.py:301: in micro_cache_anonymous_pages_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
............................................./app/lib/python3.14.../more/transaction/main.py:67: in transaction_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1625: in fix_webassets_url
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/user/integration.py:376: in auto_login_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
............................................./app/lib/python3.14.../more/webassets/tweens.py:132: in __call__
    return self.handler(request)
           ^^^^^^^^^^^^^^^^^^^^^
............................................./app/lib/python3.14.../more/webassets/tweens.py:84: in __call__
    response = self.handler(request)
               ^^^^^^^^^^^^^^^^^^^^^
............................................./app/lib/python3.14....../site-packages/morepath/core.py:157: in excview_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
............................................./app/lib/python3.14.../more/content_security/core.py:99: in content_security_policy_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1830: in current_language_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1872: in set_cache_control_header_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/election_day/app.py:186: in enable_iframes_and_analytics_tween
    result = handler(request)
             ^^^^^^^^^^^^^^^^
............................................./app/lib/python3.14....../site-packages/morepath/publish.py:38: in publish
    return resolve_response(obj, request)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
............................................./app/lib/python3.14....../site-packages/morepath/publish.py:93: in resolve_response
    return request.app.get_view(obj, request)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<generated code: def call(self, obj, request):
    _key = _registry_key(self=self, obj=obj, request=request)
    return (_component_lookup(_key) or
            _fallback_lookup(_key) or
            _fallback)(self, obj, request)
>:3: in call
    ???
............................................./app/lib/python3.14.../site-packages/morepath/view.py:82: in __call__
    content = self.func(obj, request)
              ^^^^^^^^^^^^^^^^^^^^^^^
.../election_day/views/sitemap.py:66: in view_sitemap_xml
    return {'urls': sorted(urls(self, request))}
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

principal = <onegov.election_day.models.principal.Canton object at 0x7fa6639d2850>
request = <ElectionDayRequest at 0x7fa663b5ab70 GET http:.../localhost/sitemap.xml>

    def urls(
        principal: Principal,
        request: ElectionDayRequest
    ) -> Iterator[str]:
        layout = DefaultLayout(principal, request)
    
        yield request.link(principal)
        yield layout.archive_search_link
        if layout.principal.email_notification:
            yield request.link(principal, 'subscribe-email')
            yield request.link(principal, 'unsubscribe-email')
        if layout.principal.sms_notification:
            yield request.link(principal, 'subscribe-sms')
            yield request.link(principal, 'unsubscribe-sms')
        for year in layout.archive.get_years():
            yield request.link(layout.archive.for_date(str(year)))
    
            archive = ArchivedResultCollection(request.session, str(year))
            results, _last_modified = archive.by_date()
            grouped_results = archive.group_items(results, request) or {}
            for date_, domains in grouped_results.items():
                yield request.link(layout.archive.for_date(date_.isoformat()))
                for items in domains.values():
                    for value in items.values():
                        for result in value:
>                           yield result.adjusted_url(request)
                                  ^^^^^^^^^^^^^^^^^^^
E                           AttributeError: 'str' object has no attribute 'adjusted_url'

.../election_day/views/sitemap.py:43: AttributeError
tests/onegov/election_day/collections/test_archived_result_collection.py::test_archived_result_collection_grouping
Stack Traces | 1.36s run time
session = <sqlalchemy.orm.session.Session object at 0x7f9088998ad0>

    def test_archived_result_collection_grouping(session: Session) -> None:
        # Add a vote and election for each domain on two dates
        for domain in (
            'federation', 'canton', 'region', 'district', 'none', 'municipality'
        ):
            session.add(
                Election(
                    title="{} election 1".format(domain),
                    domain=domain,
                    date=date(2017, 2, 12)
                )
            )
            session.add(
                Vote(
                    title="{} vote 1".format(domain),
                    domain=domain,
                    date=date(2017, 2, 12)
                )
            )
            session.add(
                Election(
                    title="{} election 2".format(domain),
                    domain=domain,
                    date=date(2017, 5, 21)
                )
            )
            session.add(
                Vote(
                    title="{} vote 2".format(domain),
                    domain=domain,
                    date=date(2017, 5, 21)
                )
            )
    
        # Add a compound for all elections on the first date
        compound = ElectionCompound(
            title='Legislative Elections',
            domain='canton',
            date=date(2017, 2, 12),
        )
        compound.elections = session.query(Election).filter(Election.id.in_([
            'federation-election-1',
            'canton-election-1',
            'region-election-1',
            'district-election-1',
            'none-election-1',
            'municipality-election-1'
        ])).all()
        session.add(compound)
        session.flush()
    
        # Get the results for a year
        archive = ArchivedResultCollection(session).for_date('2017')
        request: Any = DummyRequest()
        archive.update_all(request)
        items, last_modified = archive.by_date()
    
        # Test grouping of a cantonal instance
        request.app.principal.domain = 'canton'
        expected = ['federation', 'canton', 'region', 'municipality']
        grouped = archive.group_items(items, request)
        assert grouped is not None
        assert list(grouped) == [date(2017, 5, 21), date(2017, 2, 12)]
        assert all([list(group) == expected for group in grouped.values()])
>       assert len(grouped[date(2017, 5, 21)]['region']['election']) == 3
E       AssertionError: assert 1 == 3
E        +  where 1 = len(OrderedDict({'': [<onegov.election_day.models.archived_result.ArchivedResult object at 0x7f9088668050>]}))

.../election_day/collections/test_archived_result_collection.py:194: AssertionError
tests/onegov/election_day/collections/test_archived_result_collection.py::test_archived_result_collection
Stack Traces | 1.63s run time
session = <sqlalchemy.orm.session.Session object at 0x7f4909998830>

    def test_archived_result_collection(session: Session) -> None:
        archive = ArchivedResultCollection(session)
    
        assert archive.for_date(2015).date == 2015  # type: ignore
        assert archive.for_date('2015').date == '2015'
        assert archive.for_date('2015-01-01').date == '2015-01-01'
    
        assert archive.get_years() == []
        assert archive.current() == ([], None)
        assert archive.for_date(2015).by_date() == ([], None)  # type: ignore[arg-type]
        assert archive.for_date('2015').by_date() == ([], None)
        assert archive.for_date('2015-01-01').by_date() == ([], None)
        assert archive.for_date(2015).by_year(2015) == ([], None)  # type: ignore[arg-type]
        assert archive.for_date('2015').by_year('2015') == ([], None)  # type: ignore[arg-type]
    
        for year in (2009, 2011, 2014, 2016):
            session.add(
                Election(
                    title="Election {}".format(year),
                    domain='federation',
                    date=date(year, 1, 1),
                )
            )
        for year in (2008, 2012):
            session.add(
                ElectionCompound(
                    title="Elections {}".format(year),
                    domain='federation',
                    date=date(year, 1, 1),
                )
            )
        for year in (2007, 2011, 2015, 2016):
            session.add(
                Vote(
                    title="Vote {}".format(year),
                    domain='federation',
                    date=date(year, 1, 1),
                )
            )
    
        session.flush()
    
        archive.update_all(DummyRequest())  # type: ignore[arg-type]
    
        assert archive.get_years() == [
            2016, 2015, 2014, 2012, 2011, 2009, 2008, 2007
        ]
    
        with freeze_time('2006-08-31'):
            assert archive.current() == archive.for_date('2007').by_date()
        with freeze_time('2007-01-01'):
            assert archive.current() == archive.for_date('2007').by_date()
        with freeze_time('2007-01-02'):
            assert archive.current() == archive.for_date('2008').by_date()
        with freeze_time('2016-08-31'):
            for date_ in (2016, '2016', '2016-01-01'):
                assert archive.current() == archive.for_date(date_).by_date()  # type: ignore[arg-type]
    
        assert archive.for_date('2016-02-02').by_date() == ([], None)
    
        for year in (2009, 2011, 2014, 2016):
            query = session.query(ArchivedResult)
            item = query.filter_by(date=date(year, 1, 1), type='election').one()
            items, modified = archive.for_date(year).by_date()  # type: ignore[arg-type]
            assert item in items
            items, modified = archive.for_date(str(year)).by_date()
            assert item in items
            items, modified = archive.by_year(year)
            assert item in items
            items, modified = archive.by_year(str(year))  # type: ignore[arg-type]
            assert item in items
    
            groups = archive.group_items(items, DummyRequest())  # type: ignore[arg-type]
>           assert groups[date(year, 1, 1)]['federation']['election'] == [item]  # type: ignore[index]
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E           AssertionError: assert OrderedDict({...490ec94350>]}) == [<onegov.elec...7f490ec94350>]
E             
E             Full diff:
E             - [
E             + OrderedDict({
E             +     '': [
E             -     <onegov.election_day.models.archived_result.ArchivedResult object at 0x7f490ec94350>,
E             +         <onegov.election_day.models.archived_result.ArchivedResult object at 0x7f490ec94350>,
E             ? ++++
E             - ]
E             +     ],
E             + })

.../election_day/collections/test_archived_result_collection.py:94: AssertionError
tests/onegov/election_day/forms/test_upload_form.py::test_upload_vote_form
Stack Traces | 4.26s run time
session = <sqlalchemy.orm.session.Session object at 0x7f908d243620>

    def test_upload_vote_form(session: Session) -> None:
        principal = Canton(name='be', canton='be')
        vote = Vote(title='Vote', date=date(2017, 1, 1), domain='canton')
    
        # Test if wabsti_c is added when data sources are available
        form = UploadVoteForm()
>       assert sorted(f[0] for f in form.file_format.choices) == ['internal']
E       AssertionError: assert ['internal', 'xml'] == ['internal']
E         
E         Left contains one more item: 'xml'
E         
E         Full diff:
E           [
E               'internal',
E         +     'xml',
E           ]

.../election_day/forms/test_upload_form.py:31: AssertionError

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

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants