Skip to content

Org: Fixes event search index corrupted after fetch.#2495

Open
cyrillkuettel wants to merge 2 commits into
masterfrom
ogc-3101-suchfunktion-im-veranstaltungskalender
Open

Org: Fixes event search index corrupted after fetch.#2495
cyrillkuettel wants to merge 2 commits into
masterfrom
ogc-3101-suchfunktion-im-veranstaltungskalender

Conversation

@cyrillkuettel
Copy link
Copy Markdown
Contributor

@cyrillkuettel cyrillkuettel commented May 28, 2026

We have hourly cronjobs that fetch events. They look like this: sudo /usr/sbin/container-exec onegov-cloud onegov-org --select /onegov_town6_without_yubikey/zug fetch --source huenenberg --source risch --source steinhausen --published-only --create-tickets

We have empirically determined that this exact command above results in:
image

I have tested this fix (hotfix and run the cli manually) and with the fix this problem doesn't appear.

Commit message

Org: Fixes event search index corrupted after fetch.

The fetch CLI switches schemas multiple times in a loop (remote → local
per source key), violating the session_manager's own design contract:
"we only set the schema once per request". Any ORM flush during the
schema-switch window would send indexing signals tagged with the wrong
schema.

Wrap from_import() and the submit/publish/ticket block in
disable_change_signals(), then explicitly index each added/updated
published event after signals are restored.

TYPE: Bugfix
LINK: OGC-3101

Checklist

  • I have performed a self-review of my code
  • I considered adding a reviewer
  • I have tested my code thoroughly by hand

The fetch CLI switches schemas multiple times in a loop (remote → local
per source key), violating the session_manager's own design contract:
"we only set the schema once per request". Any ORM flush during the
schema-switch window would send indexing signals tagged with the wrong
schema.

Wrap from_import() and the submit/publish/ticket block in
disable_change_signals(), then explicitly index each added/updated
published event after signals are restored.
@linear
Copy link
Copy Markdown

linear Bot commented May 28, 2026

OGC-3101

@cyrillkuettel cyrillkuettel requested a review from Daverball May 28, 2026 12:46
Copy link
Copy Markdown
Member

@Daverball Daverball left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can go a step further and directly emit the tasks to the indexer, instead of going the indirect route through the queue. You also forgot to handle the pruned events.

Comment thread src/onegov/org/cli.py Outdated
Comment on lines +797 to +800
if hasattr(app, 'fts_orm_events'):
for event_ in (*added, *updated):
if not event_.fts_skip:
app.fts_orm_events.index(local_schema, event_)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if hasattr(app, 'fts_orm_events'):
for event_ in (*added, *updated):
if not event_.fts_skip:
app.fts_orm_events.index(local_schema, event_)
if app.fts_search_enabled:
if added or updated:
self.fts_indexer.process((
task
for event_ in chained(added, updated)
if (
task := self.fts_orm_events.index_task(local_schema, _event) # type: ignore[arg-type]
) is not None
), local_session)
if purged:
self.fts_indexer.process((
task
for event_ in purged
if (
task := self.fts_orm_events.delete_task(local_schema, _event) # type: ignore[arg-type]
) is not None
), local_session)
# NOTE: Make sure all changes are flushed, before signals are emitted again
local_session.flush()

I think it's worth doing what we're doing in perform_reindex here and directly process the tasks using the indexer, instead of going through the queue, if you're already taking the extra step to manually emit the tasks.

You also forgot to emit delete tasks for the purged events.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok this is updated now. The CI seems to be quite red, a lot of stuff failing on master as well. Seems unrelated tough.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redis 8 was just released, looks like that's the cause, pin it to <8 for now.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 28, 2026

❌ 10 Tests Failed:

Tests completed Failed Passed Skipped
910 10 900 11
View the top 3 failed test(s) by shortest run time
tests/onegov/user/test_oauth_saml2.py::test_saml2_authenticate_request
Stack Traces | 1.05s run time
app = <tests.onegov.user.test_oauth_saml2.App object at 0x7efc8d3fb770>
idp_metadata = '.../user/fixtures/idp.xml'

    def test_saml2_authenticate_request(app: App, idp_metadata: str) -> None:
    
        configure_provider(app, idp_metadata)
    
        provider = app.providers['idp']
        assert isinstance(provider, SAML2Provider)
        provider.to = '/'
    
        # test authenticate request (requires xmlsec1 to be installed)
        browser_session: dict[str, Any] = {}
        request: Any = Bunch(
            app=app,
            application_url='http://example.com/',
            url='http://example..../auth/provider/idp',
            browser_session=browser_session,
            class_link=lambda cls, args, name:
            f'http://example.com/auth/provider/{args["name"]}/{name}')
>       response = provider.authenticate_request(request)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.../onegov/user/test_oauth_saml2.py:177: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../user/auth/provider.py:1210: in authenticate_request
    sessions[session_id] = request.url
    ^^^^^^^^^^^^^^^^^^^^
.../auth/clients/saml2.py:506: in __setitem__
    self._cache.set(self.mangle(name_id), value)
........................................../app/lib/python3.14.../dogpile/cache/region.py:1379: in set
    self.backend.set_serialized(key, self._serialized_payload(value))
........................................../app/lib/python3.14.../cache/backends/redis.py:275: in set_serialized
    self.writer_client.setex(key, self.redis_expiration_time, value)
........................................../app/lib/python3.14.../site-packages/redis/utils.py:164: in wrapper
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
........................................../app/lib/python3.14.../redis/commands/core.py:4370: in setex
    return self.execute_command("SETEX", name, time, value)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
........................................../app/lib/python3.14.............../site-packages/redis/client.py:787: in execute_command
    return self._execute_command(*args, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
........................................../app/lib/python3.14.............../site-packages/redis/client.py:809: in _execute_command
    result = conn.retry.call_with_retry(
........................................../app/lib/python3.14....../site-packages/redis/retry.py:132: in call_with_retry
    raise error
........................................../app/lib/python3.14....../site-packages/redis/retry.py:120: in call_with_retry
    return do()
           ^^^^
........................................../app/lib/python3.14.............../site-packages/redis/client.py:810: in <lambda>
    lambda: self._send_command_parse_response(
........................................../app/lib/python3.14.............../site-packages/redis/client.py:753: in _send_command_parse_response
    return self.parse_response(conn, command_name, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
........................................../app/lib/python3.14.............../site-packages/redis/client.py:853: in parse_response
    response = connection.read_response()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
........................................../app/lib/python3.14.../site-packages/redis/connection.py:1371: in read_response
    response = self._parser.read_response(
........................................../app/lib/python3.14.../redis/_parsers/hiredis.py:151: in read_response
    self.read_from_socket(timeout=timeout)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <redis._parsers.hiredis._HiredisParser object at 0x7efc95016210>
timeout = <object object at 0x7efcd2409cf0>, raise_on_timeout = True

    def read_from_socket(self, timeout=SENTINEL, raise_on_timeout=True):
        sock = self._sock
        custom_timeout = timeout is not SENTINEL
        try:
            if custom_timeout:
                sock.settimeout(timeout)
            bufflen = self._sock.recv_into(self._buffer)
            if bufflen == 0:
>               raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)
E               redis.exceptions.ConnectionError: Connection closed by server.

........................................../app/lib/python3.14.../redis/_parsers/hiredis.py:111: ConnectionError
tests/onegov/translator_directory/test_views.py::test_view_translator
Stack Traces | 2.23s run time
client = <tests.onegov.translator_directory.conftest.Client object at 0x7f5b91ae6780>

    def test_view_translator(client: Client) -> None:
        session = client.app.session()
        languages = create_languages(session)
        certs = create_certificates(session)
        cert_ids = [str(cert.id) for cert in certs]
        cert_names = [cert.name for cert in certs]
        language_ids = [str(lang.id) for lang in languages]
        language_names = [lang.name for lang in languages]
        transaction.commit()
    
>       client.login_editor()

.../onegov/translator_directory/test_views.py:156: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tests/shared/client.py:69: in login_editor
    return self.login('editor@example.org', 'hunter2', to)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tests/shared/client.py:60: in login
    login_page = self.get(url)
                 ^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14....../site-packages/webtest/app.py:328: in get
    return self.do_request(req, status=status,
tests/shared/client.py:159: in do_request
    return self.extend_response(super().do_request(*args, **kwargs))
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.........................................................................../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:1765: in http_conflict_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1790: in activate_session_manager
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1808: in close_session_after_request
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/file/integration.py:477: in configure_depot_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14.../more/transaction/main.py:53: in transaction_tween
    userid = request.identity.userid
             ^^^^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14.../site-packages/morepath/reify.py:44: in __get__
    val = self.wrapped(inst)
          ^^^^^^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14.../site-packages/morepath/request.py:85: in identity
    result = self.app._identify(self)
             ^^^^^^^^^^^^^^^^^^^^^^^^
.../core/security/identity_policy.py:24: in identify
    key: request.browser_session[key] for key in self.required_keys
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:191: in __getitem__
    result = self._get(name)
             ^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:124: in _get
    return self._cache.get(name)
           ^^^^^^^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:34: in get
    return self.cache.get(self.mangle(key))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14.../dogpile/cache/region.py:783: in get
    value = self._get_cache_value(key, expiration_time, ignore_expiration)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14.../dogpile/cache/region.py:821: in _get_cache_value
    value = self._get_from_backend(key)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14.../dogpile/cache/region.py:1325: in _get_from_backend
    self.backend.get_serialized(key)
.........................................................................../app/lib/python3.14.../cache/backends/redis.py:262: in get_serialized
    value = self.reader_client.get(key)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14.../redis/commands/core.py:3194: in get
    return self.execute_command("GET", name, keys=[name])
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14.............../site-packages/redis/client.py:787: in execute_command
    return self._execute_command(*args, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14.............../site-packages/redis/client.py:809: in _execute_command
    result = conn.retry.call_with_retry(
.........................................................................../app/lib/python3.14....../site-packages/redis/retry.py:132: in call_with_retry
    raise error
.........................................................................../app/lib/python3.14....../site-packages/redis/retry.py:120: in call_with_retry
    return do()
           ^^^^
.........................................................................../app/lib/python3.14.............../site-packages/redis/client.py:810: in <lambda>
    lambda: self._send_command_parse_response(
.........................................................................../app/lib/python3.14.............../site-packages/redis/client.py:753: in _send_command_parse_response
    return self.parse_response(conn, command_name, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14.............../site-packages/redis/client.py:853: in parse_response
    response = connection.read_response()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14.../site-packages/redis/connection.py:1371: in read_response
    response = self._parser.read_response(
.........................................................................../app/lib/python3.14.../redis/_parsers/hiredis.py:151: in read_response
    self.read_from_socket(timeout=timeout)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <redis._parsers.hiredis._HiredisParser object at 0x7f5b94bdcfc0>
timeout = <object object at 0x7f5bcf775cf0>, raise_on_timeout = True

    def read_from_socket(self, timeout=SENTINEL, raise_on_timeout=True):
        sock = self._sock
        custom_timeout = timeout is not SENTINEL
        try:
            if custom_timeout:
                sock.settimeout(timeout)
            bufflen = self._sock.recv_into(self._buffer)
            if bufflen == 0:
>               raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)
E               redis.exceptions.ConnectionError: Connection closed by server.

.........................................................................../app/lib/python3.14.../redis/_parsers/hiredis.py:111: ConnectionError
tests/onegov/election_day/screen_widgets/test_election_widgets.py::test_majorz_election_widgets
Stack Traces | 2.42s run time
self = <PageTemplate <string>>
_BaseTemplate__kw = {'__decode': <method 'decode' of 'bytes' objects>, '__on_error_handler': None, '__translate': <function simple_transla...e, 'Grüne', Decimal('15.0'), None, None), (746, 'Thöni', 'Stefan', False, 'Piraten', Decimal('4.4'), None, None)], ...}
econtext = {'layout': <onegov.election_day.layouts.election.ElectionLayout object at 0x7f3c378719a0>, 'request': <tests.onegov.el...hameleon.tal.RepeatDict object at 0x7f3c3cffba60>, 'macroname': "layout.macros['election-candidates-by-entity-table']"}
rcontext = {'__error__': [("layout.principal.label('entity')", 799, 95, '.../onegov/election_day/t...nnectionError), ("layout.macros['election-candidates-by-entity-table']", 10, 60, '<string>', network:ConnectionError)]}
stream = ['<div class="homepage">\n\n          \n        ', '<span class="my-class-1">', 'majorz_internal_staenderatswahl-2015-intermediate', '</span>\n        ', '<span class="my-class-2">', '\n    ', ...]
target_language = None, cls = <class 'redis.exceptions.ConnectionError'>

    def render(self, **__kw: Any) -> str:
        econtext = Scope(__kw)
        rcontext: dict[str, Any] = {}
        self.cook_check()
        stream = self.output_stream_factory()
        target_language = __kw.get("target_language")
        try:
>           self._render(
                stream,
                econtext,
                rcontext,
                target_language=target_language
            )

............................................................................................................................../app/lib/python3.14............/site-packages/chameleon/template.py:238: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
5aff39bfbfad83d9baa7b56bff7bf72b.py:384: in render
    ???
macros_53c5c9e53349d4dabd7270a2d3a57510.py:14440: in render_election_candidates_by_entity_table
    ???
............................................................................................................................../app/lib/python3.14........./site-packages/chameleon/utils.py:517: in lookup_attr
    return getattr(obj, key)
           ^^^^^^^^^^^^^^^^^
....../usr/lib/python3.14/functools.py:1126: in __get__
    val = self.func(instance)
          ^^^^^^^^^^^^^^^^^^^
.../election_day/layouts/default.py:62: in principal
    return self.request.app.principal
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
.../onegov/election_day/app.py:63: in principal
    return self.cache.get_or_create('principal', self.load_principal)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
............................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:1097: in get_or_create
    with Lock(
............................................................................................................................../app/lib/python3.14............/site-packages/dogpile/lock.py:185: in __enter__
    return self._enter()
           ^^^^^^^^^^^^^
............................................................................................................................../app/lib/python3.14............/site-packages/dogpile/lock.py:87: in _enter
    value = value_fn()
            ^^^^^^^^^^
............................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:1033: in get_value
    value = self._get_from_backend(key)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
............................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:1325: in _get_from_backend
    self.backend.get_serialized(key)
............................................................................................................................../app/lib/python3.14.../cache/backends/redis.py:262: in get_serialized
    value = self.reader_client.get(key)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
............................................................................................................................../app/lib/python3.14.../redis/commands/core.py:3194: in get
    return self.execute_command("GET", name, keys=[name])
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
............................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:787: in execute_command
    return self._execute_command(*args, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
............................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:809: in _execute_command
    result = conn.retry.call_with_retry(
............................................................................................................................../app/lib/python3.14............/site-packages/redis/retry.py:132: in call_with_retry
    raise error
............................................................................................................................../app/lib/python3.14............/site-packages/redis/retry.py:120: in call_with_retry
    return do()
           ^^^^
............................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:810: in <lambda>
    lambda: self._send_command_parse_response(
............................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:753: in _send_command_parse_response
    return self.parse_response(conn, command_name, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
............................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:853: in parse_response
    response = connection.read_response()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
............................................................................................................................../app/lib/python3.14....../site-packages/redis/connection.py:1371: in read_response
    response = self._parser.read_response(
............................................................................................................................../app/lib/python3.14.../redis/_parsers/hiredis.py:151: in read_response
    self.read_from_socket(timeout=timeout)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <redis._parsers.hiredis._HiredisParser object at 0x7f3c3b1ae0f0>
timeout = <object object at 0x7f3c76b35cf0>, raise_on_timeout = True

    def read_from_socket(self, timeout=SENTINEL, raise_on_timeout=True):
        sock = self._sock
        custom_timeout = timeout is not SENTINEL
        try:
            if custom_timeout:
                sock.settimeout(timeout)
            bufflen = self._sock.recv_into(self._buffer)
            if bufflen == 0:
>               raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)
E               redis.exceptions.ConnectionError: Connection closed by server.

............................................................................................................................../app/lib/python3.14.../redis/_parsers/hiredis.py:111: ConnectionError

During handling of the above exception, another exception occurred:

election_day_app_zg = <tests.onegov.election_day.conftest.TestApp object at 0x7f3c3aad2350>
import_test_datasets = <function import_test_datasets.<locals>._import_test_datasets at 0x7f3c3895fc10>

    def test_majorz_election_widgets(
        election_day_app_zg: TestApp,
        import_test_datasets: ImportTestDatasets
    ) -> None:
    
        structure = """
            <model-title class="my-class-1"/>
            <model-progress class="my-class-2"/>
            <counted-entities class="my-class-3"/>
            <election-candidates-table class="my-class-4" lists="SP, Grüne,"/>
            <election-candidates-chart class="my-class-5"/>
            <election-candidates-chart class="my-class-6" limit="2"
                lists="x,y" sort-by-lists="True" elected="True"/>
            <election-candidates-by-entity-table class="my-class-7"/>
            <number-of-counted-entities class="my-class-8"/>
            <total-entities class="my-class-9"/>
            <election-turnout class="my-class-a"/>
            <absolute-majority class="my-class-b"/>
            <allocated-mandates class="my-class-c"/>
            <number-of-mandates class="my-class-d"/>
            <mandates class="my-class-e"/>
            <last-result-change class="my-class-f"/>
            <if-completed>is-completed</if-completed>
            <if-not-completed>is-not-completed</if-not-completed>
            <if-absolute-majority>is-am</if-absolute-majority>
            <if-relative-majority>is-rm</if-relative-majority>
        """
        widgets: list[Widget] = [
            AbsoluteMajorityWidget(),
            AllocatedMandatesWidget(),
            CountedEntitiesWidget(),
            ElectionCandidatesByEntityTableWidget(),
            ElectionCandidatesChartWidget(),
            ElectionCandidatesTableWidget(),
            ElectionTurnoutWidget(),
            IfAbsoluteMajorityWidget(),
            IfCompletedWidget(),
            IfNotCompletedWidget(),
            IfRelateMajorityWidget(),
            LastResultChangeWidget(),
            MandatesWidget(),
            ModelProgressWidget(),
            ModelTitleWidget(),
            NumberOfCountedEntitiesWidget(),
            NumberOfMandatesWidget(),
            TotalEntitiesWidget(),
        ]
    
        # Empty
        session = election_day_app_zg.session()
        session.add(
            Election(title='Election', domain='canton', date=date(2015, 6, 18))
        )
        session.flush()
        model = session.query(Election).one()
        request: Any = DummyRequest(app=election_day_app_zg, session=session)
        layout = ElectionLayout(model, request)
        default = {'layout': layout, 'request': request}
        data = inject_variables(widgets, layout, structure, default, False)
    
        assert data == {
            'candidates': [],
            'candidates_by_entites': ([], []),
            'election': model,
            'embed': False,
            'entities': '',
            'layout': layout,
            'model': model,
            'request': request,
        }
    
        result = transform_structure(widgets, structure)
        result = PageTemplate(result)(**data)
        etree.fromstring(result.encode('utf-8'))
    
        assert '>Election</span>' in result
        assert 'is-completed' not in result
        assert 'is-not-completed' in result
        assert 'is-am' not in result
        assert 'is-rm' not in result
        assert 'my-class-1' in result
        assert 'my-class-2' in result
        assert 'my-class-3' in result
        assert 'my-class-4' in result
        assert 'my-class-5' in result
        assert 'my-class-6' in result
        assert 'my-class-7' in result
        assert 'my-class-8' in result
        assert 'my-class-9' in result
        assert 'my-class-a' in result
        assert 'my-class-b' in result
        assert 'my-class-c' in result
        assert 'my-class-d' in result
        assert 'my-class-e' in result
        assert 'my-class-f' in result
    
        # Add intermediate results
        with freeze_time('2022-01-01 12:00'):
            results = import_test_datasets(
                'internal',
                'election',
                'zg',
                'canton',
                'majorz',
                date_=date(2015, 10, 18),
                number_of_mandates=2,
                dataset_name='staenderatswahl-2015-intermediate',
                app_session=session
            )
            assert len(results) == 1
            model, errors = next(iter(results.values()))
            model.majority_type = 'absolute'
            assert not errors
            session.add(model)
            session.flush()
    
        layout = ElectionLayout(model, request)
        default = {'layout': layout, 'request': request}
        data = inject_variables(widgets, layout, structure, default, False)
    
        assert data['candidates'] == [
            (10693, 'Hegglin', 'Peter', True, 'CVP', Decimal('63.3'), None, None),
            (10103, 'Eder', 'Joachim', True, 'FDP', Decimal('59.8'), None, None),
            (4845, 'Brandenberg', 'Manuel', False, 'SVP', Decimal('28.7'), None,
             None),
            (2890, 'Gysel', 'Barbara', False, 'SP', Decimal('17.1'), None, None),
            (2541, 'Lustenberger', 'Andreas', False, 'Grüne', Decimal('15.0'),
             None, None),
            (746, 'Thöni', 'Stefan', False, 'Piraten', Decimal('4.4'), None, None)
        ]
    
        assert [c[1:] for c in data['candidates_by_entites'][0]] == [
            ('Hegglin', 'Peter', 10693),
            ('Eder', 'Joachim', 10103),
            ('Brandenberg', 'Manuel', 4845),
            ('Gysel', 'Barbara', 2890),
            ('Lustenberger', 'Andreas', 2541),
            ('Thöni', 'Stefan', 746)
        ]
        assert data['candidates_by_entites'][1] == [
            ('Baar', [
                ('Baar', 'Hegglin', 'Peter', 4207),
                ('Baar', 'Eder', 'Joachim', 4237),
                ('Baar', 'Brandenberg', 'Manuel', 2100),
                ('Baar', 'Gysel', 'Barbara', 1264),
                ('Baar', 'Lustenberger', 'Andreas', 1269),
                ('Baar', 'Thöni', 'Stefan', 320)
            ]),
            ('Cham', [
                ('Cham', 'Hegglin', 'Peter', 2905),
                ('Cham', 'Eder', 'Joachim', 2726),
                ('Cham', 'Brandenberg', 'Manuel', 1404),
                ('Cham', 'Gysel', 'Barbara', 888),
                ('Cham', 'Lustenberger', 'Andreas', 685),
                ('Cham', 'Thöni', 'Stefan', 232)
            ]),
            ('Hünenberg', [
                ('Hünenberg', 'Hegglin', 'Peter', 2205),
                ('Hünenberg', 'Eder', 'Joachim', 2098),
                ('Hünenberg', 'Brandenberg', 'Manuel', 881),
                ('Hünenberg', 'Gysel', 'Barbara', 540),
                ('Hünenberg', 'Lustenberger', 'Andreas', 397),
                ('Hünenberg', 'Thöni', 'Stefan', 140)
            ]),
            ('Menzingen', [
                ('Menzingen', 'Hegglin', 'Peter', 1376),
                ('Menzingen', 'Eder', 'Joachim', 1042),
                ('Menzingen', 'Brandenberg', 'Manuel', 460),
                ('Menzingen', 'Gysel', 'Barbara', 198),
                ('Menzingen', 'Lustenberger', 'Andreas', 190),
                ('Menzingen', 'Thöni', 'Stefan', 54)
            ])
        ]
        assert data['election'] == model
        assert data['embed'] == False
        assert data['entities'] == 'Baar, Cham, Hünenberg, Menzingen'
        assert data['layout'] == layout
        assert data['model'] == model
        assert data['request'] == request
    
        result = transform_structure(widgets, structure)
>       result = PageTemplate(result)(**data)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.../election_day/screen_widgets/test_election_widgets.py:227: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
............................................................................................................................../app/lib/python3.14............/site-packages/chameleon/template.py:183: in __call__
    return self.render(**kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
............................................................................................................................../app/lib/python3.14.../chameleon/zpt/template.py:359: in render
    return super().render(**_kw)
           ^^^^^^^^^^^^^^^^^^^^^
............................................................................................................................../app/lib/python3.14............/site-packages/chameleon/template.py:268: in render
    raise_with_traceback(exc, tb)
............................................................................................................................../app/lib/python3.14........./site-packages/chameleon/utils.py:52: in raise_with_traceback
    raise exc
............................................................................................................................../app/lib/python3.14............/site-packages/chameleon/template.py:238: in render
    self._render(
5aff39bfbfad83d9baa7b56bff7bf72b.py:384: in render
    ???
macros_53c5c9e53349d4dabd7270a2d3a57510.py:14440: in render_election_candidates_by_entity_table
    ???
............................................................................................................................../app/lib/python3.14........./site-packages/chameleon/utils.py:517: in lookup_attr
    return getattr(obj, key)
           ^^^^^^^^^^^^^^^^^
....../usr/lib/python3.14/functools.py:1126: in __get__
    val = self.func(instance)
          ^^^^^^^^^^^^^^^^^^^
.../election_day/layouts/default.py:62: in principal
    return self.request.app.principal
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
.../onegov/election_day/app.py:63: in principal
    return self.cache.get_or_create('principal', self.load_principal)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
............................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:1097: in get_or_create
    with Lock(
............................................................................................................................../app/lib/python3.14............/site-packages/dogpile/lock.py:185: in __enter__
    return self._enter()
           ^^^^^^^^^^^^^
............................................................................................................................../app/lib/python3.14............/site-packages/dogpile/lock.py:87: in _enter
    value = value_fn()
            ^^^^^^^^^^
............................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:1033: in get_value
    value = self._get_from_backend(key)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
............................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:1325: in _get_from_backend
    self.backend.get_serialized(key)
............................................................................................................................../app/lib/python3.14.../cache/backends/redis.py:262: in get_serialized
    value = self.reader_client.get(key)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
............................................................................................................................../app/lib/python3.14.../redis/commands/core.py:3194: in get
    return self.execute_command("GET", name, keys=[name])
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
............................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:787: in execute_command
    return self._execute_command(*args, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
............................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:809: in _execute_command
    result = conn.retry.call_with_retry(
............................................................................................................................../app/lib/python3.14............/site-packages/redis/retry.py:132: in call_with_retry
    raise error
............................................................................................................................../app/lib/python3.14............/site-packages/redis/retry.py:120: in call_with_retry
    return do()
           ^^^^
............................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:810: in <lambda>
    lambda: self._send_command_parse_response(
............................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:753: in _send_command_parse_response
    return self.parse_response(conn, command_name, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
............................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:853: in parse_response
    response = connection.read_response()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
............................................................................................................................../app/lib/python3.14....../site-packages/redis/connection.py:1371: in read_response
    response = self._parser.read_response(
............................................................................................................................../app/lib/python3.14.../redis/_parsers/hiredis.py:151: in read_response
    self.read_from_socket(timeout=timeout)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <redis._parsers.hiredis._HiredisParser object at 0x7f3c3b1ae0f0>
timeout = <object object at 0x7f3c76b35cf0>, raise_on_timeout = True

    def read_from_socket(self, timeout=SENTINEL, raise_on_timeout=True):
        sock = self._sock
        custom_timeout = timeout is not SENTINEL
        try:
            if custom_timeout:
                sock.settimeout(timeout)
            bufflen = self._sock.recv_into(self._buffer)
            if bufflen == 0:
>               raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)
E               redis.exceptions.ConnectionError: redis.exceptions.ConnectionError: Connection closed by server.
E               
E                - Expression: "layout.principal.label('entity')"
E                - Filename:   ... .../election_day/templates/macros.pt
E                - Location:   (line 799: col 95)
E                - Source:     ... n:translate="">${layout.principal.label('entity')}</th>
E                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E                - Expression: "layout.macros['election-candidates-by-entity-table']"
E                - Filename:   <string>
E                - Location:   (line 10: col 60)
E                - Arguments:  layout: <ElectionLayout ('None',) at 0x7f3c378719a0>
E                              request: <DummyRequest ('None',) at 0x7f3c3892bc50>
E                              model: <Election ('None',) at 0x7f3c37871400>
E                              entities: Baar, Cham, Hünenberg, Menzingen
E                              election: <Election ('None',) at 0x7f3c37871400>
E                              candidates_by_entites: <tuple ('None',) at 0x7f3c38f36980>
E                              embed: False
E                              candidates: <list ('None',) at 0x7f3c3a8f6a40>
E                              target_language: <NoneType ('None',) at 0xa1f2e0>
E                              repeat: <RepeatDict ('None',) at 0x7f3c3cffba60>
E                              macroname: layout.macros['election-candidates-by-entity-table']

............................................................................................................................../app/lib/python3.14.../redis/_parsers/hiredis.py:111: ConnectionError
tests/onegov/translator_directory/test_views.py::test_view_export_translators_with_filters
Stack Traces | 3.19s run time
client = <tests.onegov.translator_directory.conftest.Client object at 0x7fb8d8bdf6f0>

    def test_view_export_translators_with_filters(client: Client) -> None:
        session = client.app.session()
        languages = create_languages(session)
        lang_ids = [str(lang.id) for lang in languages]
        translators = TranslatorCollection(client.app)
    
        # Add translator 1
        data1 = copy.deepcopy(translator_data)
        data1['pers_id'] = 1111
        data1['first_name'] = 'Filtered'
        data1['last_name'] = 'One'
        data1['email'] = 'filtered.one@example.com'
        data1['spoken_languages'] = [languages[0], languages[1]]  # German, French
        data1['written_languages'] = [languages[2]]  # Italian
        translators.add(**data1)
    
        # Add translator 2
        data2 = copy.deepcopy(translator_data)
        data2['pers_id'] = 2222
        data2['first_name'] = 'Filtered'
        data2['last_name'] = 'Two'
        data2['email'] = 'filtered.two@example.com'
        data2['spoken_languages'] = [languages[0]]  # German
        data2['written_languages'] = [languages[3]]  # Arabic
        translators.add(**data2)
    
        # Add translator 3 (should be filtered out)
        data3 = copy.deepcopy(translator_data)
        data3['pers_id'] = 3333
        data3['first_name'] = 'NotFiltered'
        data3['last_name'] = 'Three'
        data3['email'] = 'not.filtered@example.com'
        data3['spoken_languages'] = [languages[1]]  # French
        data3['written_languages'] = [languages[2]]  # Italian
        translators.add(**data3)
    
        transaction.commit()
    
>       client.login_admin()

.../onegov/translator_directory/test_views.py:699: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tests/shared/client.py:66: in login_admin
    return self.login('admin@example.org', 'hunter2', to)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tests/shared/client.py:60: in login
    login_page = self.get(url)
                 ^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14....../site-packages/webtest/app.py:328: in get
    return self.do_request(req, status=status,
tests/shared/client.py:159: in do_request
    return self.extend_response(super().do_request(*args, **kwargs))
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.........................................................................../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:1765: in http_conflict_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1790: in activate_session_manager
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1808: in close_session_after_request
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/file/integration.py:477: in configure_depot_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14.../more/transaction/main.py:53: in transaction_tween
    userid = request.identity.userid
             ^^^^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14.../site-packages/morepath/reify.py:44: in __get__
    val = self.wrapped(inst)
          ^^^^^^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14.../site-packages/morepath/request.py:85: in identity
    result = self.app._identify(self)
             ^^^^^^^^^^^^^^^^^^^^^^^^
.../core/security/identity_policy.py:24: in identify
    key: request.browser_session[key] for key in self.required_keys
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:191: in __getitem__
    result = self._get(name)
             ^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:124: in _get
    return self._cache.get(name)
           ^^^^^^^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:34: in get
    return self.cache.get(self.mangle(key))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14.../dogpile/cache/region.py:783: in get
    value = self._get_cache_value(key, expiration_time, ignore_expiration)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14.../dogpile/cache/region.py:821: in _get_cache_value
    value = self._get_from_backend(key)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14.../dogpile/cache/region.py:1325: in _get_from_backend
    self.backend.get_serialized(key)
.........................................................................../app/lib/python3.14.../cache/backends/redis.py:262: in get_serialized
    value = self.reader_client.get(key)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14.../redis/commands/core.py:3194: in get
    return self.execute_command("GET", name, keys=[name])
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14.............../site-packages/redis/client.py:787: in execute_command
    return self._execute_command(*args, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14.............../site-packages/redis/client.py:809: in _execute_command
    result = conn.retry.call_with_retry(
.........................................................................../app/lib/python3.14....../site-packages/redis/retry.py:132: in call_with_retry
    raise error
.........................................................................../app/lib/python3.14....../site-packages/redis/retry.py:120: in call_with_retry
    return do()
           ^^^^
.........................................................................../app/lib/python3.14.............../site-packages/redis/client.py:810: in <lambda>
    lambda: self._send_command_parse_response(
.........................................................................../app/lib/python3.14.............../site-packages/redis/client.py:753: in _send_command_parse_response
    return self.parse_response(conn, command_name, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14.............../site-packages/redis/client.py:853: in parse_response
    response = connection.read_response()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
.........................................................................../app/lib/python3.14.../site-packages/redis/connection.py:1371: in read_response
    response = self._parser.read_response(
.........................................................................../app/lib/python3.14.../redis/_parsers/hiredis.py:151: in read_response
    self.read_from_socket(timeout=timeout)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <redis._parsers.hiredis._HiredisParser object at 0x7fb8da2c9220>
timeout = <object object at 0x7fb914dd5cf0>, raise_on_timeout = True

    def read_from_socket(self, timeout=SENTINEL, raise_on_timeout=True):
        sock = self._sock
        custom_timeout = timeout is not SENTINEL
        try:
            if custom_timeout:
                sock.settimeout(timeout)
            bufflen = self._sock.recv_into(self._buffer)
            if bufflen == 0:
>               raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)
E               redis.exceptions.ConnectionError: Connection closed by server.

.........................................................................../app/lib/python3.14.../redis/_parsers/hiredis.py:111: ConnectionError
tests/onegov/org/test_cli.py::test_fetch_with_state_and_tickets
Stack Traces | 7.7s run time
cfg_path = '.../tmp/tmp5wmmvbp_/onegov.yml'
session_manager = <onegov.core.orm.session_manager.SessionManager object at 0x7ff20d966ba0>
test_password = '$bcrypt-sha256$v=2,t=2b,r=12$sJoBC9xASB.oBBcQQe/yJe$wq9UnxHPc/Y1SAkWRnOvz.RurOTD6yK'

    def test_fetch_with_state_and_tickets(
        cfg_path: str,
        session_manager: SessionManager,
        test_password: str
    ) -> None:
    
        runner = CliRunner()
        local = 'baz'
        remote = 'bar'
        session_manager.ensure_schema_exists('foo-baz')
        session_manager.ensure_schema_exists('foo-bar')
    
        def events(entity: str = local) -> Query[Event]:
            return get_session(entity).query(Event)
    
        def get_session(entity: str) -> Session:
            session_manager.set_current_schema(f'foo-{entity}')
            return session_manager.session()
    
        for entity, title, source, tags, location in (
            (remote, '1', None, [], ''),
            (remote, '2', None, [], None),
        ):
            EventCollection(get_session(entity)).add(
                title=title,
                start=datetime(2015, 6, 16, 9, 30),
                end=datetime(2015, 6, 16, 18, 00),
                timezone='Europe/Zurich',
                tags=tags,
                location=location,
                source=source,
                organizer_email='triceracops@newyork.com',
                organizer_phone='079 123 45 67',
            )
        commit()
    
        get_session(local).add(User(
            username='admin@example.org',
            password_hash=test_password,
            role='admin'
        ))
        commit()
    
        # test published_only, import none
        result = runner.invoke(cli, [
            '--config', cfg_path,
            '--select', f'/foo/{local}',
            'fetch',
            '--source', remote,
            '--create-tickets',
            '--published-only'
        ])
>       assert result.exit_code == 0
E       assert 1 == 0
E        +  where 1 = <Result AttributeError("'CliApplication' object has no attribute 'fts_search_enabled'")>.exit_code

.../onegov/org/test_cli.py:139: AssertionError
tests/onegov/org/test_cli.py::test_fetch
Stack Traces | 8.39s run time
cfg_path = '.../tmp/tmp87a8wp47/onegov.yml'
session_manager = <onegov.core.orm.session_manager.SessionManager object at 0x7fd5345f2ba0>
test_password = '$bcrypt-sha256$v=2,t=2b,r=12$1vlLlO9T2M18dA8ck.3u4e$ECu4ZH20oFtC1ce65kq6vVWjbQZO5/q'

    def test_fetch(
        cfg_path: str,
        session_manager: SessionManager,
        test_password: str
    ) -> None:
    
        runner = CliRunner()
    
        session_manager.ensure_schema_exists('foo-baz')
        session_manager.ensure_schema_exists('foo-qux')
    
        def get_session(entity: str) -> Session:
            session_manager.set_current_schema(f'foo-{entity}')
            return session_manager.session()
    
        for entity, title, source, tags, location in (
            ('bar', '1', None, [], ''),
            ('bar', '2', None, ['A'], None),
            ('bar', '3', None, ['A', 'B'], 'bar'),
            ('bar', '4', None, ['A', 'C'], '1234 Bar'),
            ('bar', '5', None, ['C'], 'there in 4321 baz!'),
            ('bar', '6', 'xxx', [], 'bar'),
            ('bar', '7', 'yyy', ['A', 'B'], None),
            ('baz', 'a', None, [], 'BAZ'),
            ('baz', 'b', None, ['A', 'C'], '4321 Baz'),
            ('baz', 'c', 'zzz', ['B', 'C'], 'bar'),
        ):
            EventCollection(get_session(entity)).add(
                title=title,
                start=datetime(2015, 6, 16, 9, 30),
                end=datetime(2015, 6, 16, 18, 00),
                timezone='Europe/Zurich',
                tags=tags,
                location=location,
                source=source
            )
        commit()
        for entity in ('bar', 'baz', 'qux'):
            get_session(entity).add(User(
                username='admin@example.org',
                password_hash=test_password,
                role='admin'
            ))
        commit()
    
        assert get_session('bar').query(Event).count() == 7
        assert get_session('baz').query(Event).count() == 3
        assert get_session('qux').query(Event).count() == 0
        assert get_session('bar').query(Event).first().state == 'initiated'  # type: ignore[union-attr]
    
        # No sources provided
        result = runner.invoke(cli, [
            '--config', cfg_path,
            '--select', '/foo/qux',
            'fetch',
        ])
        assert result.exit_code != 0
        assert "Provide at least one source" in result.output
    
        # Bar[*] -> Qux
        result = runner.invoke(cli, [
            '--config', cfg_path,
            '--select', '/foo/qux',
            'fetch',
            '--source', 'bar'
        ])
>       assert result.exit_code == 0
E       assert 1 == 0
E        +  where 1 = <Result AttributeError("'CliApplication' object has no attribute 'fts_search_enabled'")>.exit_code

.../onegov/org/test_cli.py:342: AssertionError
tests/onegov/landsgemeinde/test_views.py::test_views
Stack Traces | 17.5s run time
self = <PageTemplateFile .../town6/templates/login.pt>
_BaseTemplate__kw = {'Markup': <class 'markupsafe.Markup'>, '__decode': <method 'decode' of 'bytes' objects>, '__on_error_handler': None, '__translate': <function ChameleonTranslate.<locals>.translate at 0x7f58901a54e0>, ...}
econtext = {'request': <OrgRequest at 0x7f5898628050 GET http:.../localhost/auth/login>, 'translate': <function ChameleonTranslate....peatDict object at 0x7f588e04b5e0>, 'macroname': 'layout.base', '__slot_title': deque([]), '__slot_content': deque([])}
rcontext = {'__error__': [('request.consume_messages()', 30, 29, '.../town6/templates/macro...('layout.base', 1, 22, '.../town6/templates/login.pt', network:ConnectionError)]}
stream = ['<!DOCTYPE html>\n', '<html', '\n    class="no-js"', '\n    lang="de-CH"', '\n    xmlns="http://www.w3.org/1999/xhtml"', ' data-version="2026.30"', ...]
target_language = None, cls = <class 'redis.exceptions.ConnectionError'>

    def render(self, **__kw: Any) -> str:
        econtext = Scope(__kw)
        rcontext: dict[str, Any] = {}
        self.cook_check()
        stream = self.output_stream_factory()
        target_language = __kw.get("target_language")
        try:
>           self._render(
                stream,
                econtext,
                rcontext,
                target_language=target_language
            )

................................................................................................................................................................../app/lib/python3.14........./site-packages/chameleon/template.py:238: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
login_8a1d93341b325aa27ecf87295d924660.py:774: in render
    ???
................................................................................................................................................................../app/lib/python3.14.../chameleon/zpt/template.py:363: in include
    self._render(*args, **kwargs)
layout_2c567ac953ccc515e1ff0d46fd67bf77.py:2600: in render
    ???
layout_2c567ac953ccc515e1ff0d46fd67bf77.py:2174: in render_layout
    ???
macros_3ed63d59d67f51dffe3049f26da2ff8f.py:3795: in render_consume_messages
    ???
................................................................................................................................................................../app/lib/python3.14....../site-packages/chameleon/tal.py:436: in __call__
    iterable = list(iterable) if iterable is not None else ()
               ^^^^^^^^^^^^^^
.../onegov/core/request.py:635: in consume_messages
    yield from self.browser_session.pop('messages', ())
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:150: in pop
    value = self.get(name, default=default)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:183: in get
    result = self._get(name)
             ^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:124: in _get
    return self._cache.get(name)
           ^^^^^^^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:34: in get
    return self.cache.get(self.mangle(key))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:783: in get
    value = self._get_cache_value(key, expiration_time, ignore_expiration)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:821: in _get_cache_value
    value = self._get_from_backend(key)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:1325: in _get_from_backend
    self.backend.get_serialized(key)
................................................................................................................................................................../app/lib/python3.14.../cache/backends/redis.py:262: in get_serialized
    value = self.reader_client.get(key)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../redis/commands/core.py:3194: in get
    return self.execute_command("GET", name, keys=[name])
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:787: in execute_command
    return self._execute_command(*args, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:809: in _execute_command
    result = conn.retry.call_with_retry(
................................................................................................................................................................../app/lib/python3.14............/site-packages/redis/retry.py:132: in call_with_retry
    raise error
................................................................................................................................................................../app/lib/python3.14............/site-packages/redis/retry.py:120: in call_with_retry
    return do()
           ^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:810: in <lambda>
    lambda: self._send_command_parse_response(
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:753: in _send_command_parse_response
    return self.parse_response(conn, command_name, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:853: in parse_response
    response = connection.read_response()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14....../site-packages/redis/connection.py:1371: in read_response
    response = self._parser.read_response(
................................................................................................................................................................../app/lib/python3.14.../redis/_parsers/hiredis.py:151: in read_response
    self.read_from_socket(timeout=timeout)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <redis._parsers.hiredis._HiredisParser object at 0x7f589353b0e0>
timeout = <object object at 0x7f58cd905cf0>, raise_on_timeout = True

    def read_from_socket(self, timeout=SENTINEL, raise_on_timeout=True):
        sock = self._sock
        custom_timeout = timeout is not SENTINEL
        try:
            if custom_timeout:
                sock.settimeout(timeout)
            bufflen = self._sock.recv_into(self._buffer)
            if bufflen == 0:
>               raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)
E               redis.exceptions.ConnectionError: Connection closed by server.

................................................................................................................................................................../app/lib/python3.14.../redis/_parsers/hiredis.py:111: ConnectionError

During handling of the above exception, another exception occurred:

client_with_fts = <tests.onegov.town6.conftest.Client object at 0x7f58991f3e00>

    def test_views(client_with_fts: Client[TestApp]) -> None:
        last_modified = []
    
        def assert_last_modified() -> None:
            response = client_with_fts.head('.../assembly/2023-05-07/ticker')
            last_modified.append(parser.parse(response.headers['Last-Modified']))
            assert sorted(last_modified) == last_modified
            assert len(set(last_modified)) == len(last_modified)
    
>       client_with_fts.login_admin()

.../onegov/landsgemeinde/test_views.py:26: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tests/shared/client.py:66: in login_admin
    return self.login('admin@example.org', 'hunter2', to)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tests/shared/client.py:60: in login
    login_page = self.get(url)
                 ^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14....../site-packages/webtest/app.py:328: in get
    return self.do_request(req, status=status,
tests/shared/client.py:159: in do_request
    return self.extend_response(super().do_request(*args, **kwargs))
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../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:1765: in http_conflict_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1790: in activate_session_manager
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1808: in close_session_after_request
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/file/integration.py:477: in configure_depot_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1833: in current_language_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/landsgemeinde/app.py:133: in pages_cache_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../more/transaction/main.py:67: in transaction_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1628: 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:1875: in set_cache_control_header_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/gis/integration.py:139: in inject_mapbox_api_token_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/websockets/integration.py:151: in websocket_csp_tween
    result = handler(request)
             ^^^^^^^^^^^^^^^^
.../onegov/org/app.py:751: in enable_iframes_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
    ???
.../onegov/org/app.py:991: in wrapped
    response = func(self, obj, request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../site-packages/morepath/view.py:87: in __call__
    response = self.render(content, request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.../onegov/core/templates.py:220: in render
    return original_render(template.render(**variables), request)
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../chameleon/zpt/template.py:359: in render
    return super().render(**_kw)
           ^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14........./site-packages/chameleon/template.py:268: in render
    raise_with_traceback(exc, tb)
................................................................................................................................................................../app/lib/python3.14.../site-packages/chameleon/utils.py:52: in raise_with_traceback
    raise exc
................................................................................................................................................................../app/lib/python3.14........./site-packages/chameleon/template.py:238: in render
    self._render(
login_8a1d93341b325aa27ecf87295d924660.py:774: in render
    ???
................................................................................................................................................................../app/lib/python3.14.../chameleon/zpt/template.py:363: in include
    self._render(*args, **kwargs)
layout_2c567ac953ccc515e1ff0d46fd67bf77.py:2600: in render
    ???
layout_2c567ac953ccc515e1ff0d46fd67bf77.py:2174: in render_layout
    ???
macros_3ed63d59d67f51dffe3049f26da2ff8f.py:3795: in render_consume_messages
    ???
................................................................................................................................................................../app/lib/python3.14....../site-packages/chameleon/tal.py:436: in __call__
    iterable = list(iterable) if iterable is not None else ()
               ^^^^^^^^^^^^^^
.../onegov/core/request.py:635: in consume_messages
    yield from self.browser_session.pop('messages', ())
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:150: in pop
    value = self.get(name, default=default)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:183: in get
    result = self._get(name)
             ^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:124: in _get
    return self._cache.get(name)
           ^^^^^^^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:34: in get
    return self.cache.get(self.mangle(key))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:783: in get
    value = self._get_cache_value(key, expiration_time, ignore_expiration)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:821: in _get_cache_value
    value = self._get_from_backend(key)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:1325: in _get_from_backend
    self.backend.get_serialized(key)
................................................................................................................................................................../app/lib/python3.14.../cache/backends/redis.py:262: in get_serialized
    value = self.reader_client.get(key)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../redis/commands/core.py:3194: in get
    return self.execute_command("GET", name, keys=[name])
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:787: in execute_command
    return self._execute_command(*args, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:809: in _execute_command
    result = conn.retry.call_with_retry(
................................................................................................................................................................../app/lib/python3.14............/site-packages/redis/retry.py:132: in call_with_retry
    raise error
................................................................................................................................................................../app/lib/python3.14............/site-packages/redis/retry.py:120: in call_with_retry
    return do()
           ^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:810: in <lambda>
    lambda: self._send_command_parse_response(
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:753: in _send_command_parse_response
    return self.parse_response(conn, command_name, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:853: in parse_response
    response = connection.read_response()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14....../site-packages/redis/connection.py:1371: in read_response
    response = self._parser.read_response(
................................................................................................................................................................../app/lib/python3.14.../redis/_parsers/hiredis.py:151: in read_response
    self.read_from_socket(timeout=timeout)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <redis._parsers.hiredis._HiredisParser object at 0x7f589353b0e0>
timeout = <object object at 0x7f58cd905cf0>, raise_on_timeout = True

    def read_from_socket(self, timeout=SENTINEL, raise_on_timeout=True):
        sock = self._sock
        custom_timeout = timeout is not SENTINEL
        try:
            if custom_timeout:
                sock.settimeout(timeout)
            bufflen = self._sock.recv_into(self._buffer)
            if bufflen == 0:
>               raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)
E               redis.exceptions.ConnectionError: redis.exceptions.ConnectionError: Connection closed by server.
E               
E                - Expression: "request.consume_messages()"
E                - Filename:   ... .../town6/templates/macros.pt
E                - Location:   (line 30: col 29)
E                - Source:     ... :repeat="message request.consume_messages()" data-closable c ...
E                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
E                - Expression: "layout.macros['consume_messages']"
E                - Filename:   ... .../landsgemeinde/templates/layout.pt
E                - Location:   (line 201: col 52)
E                - Source:     ... metal:use-macro="layout.macros['consume_messages']" />
E                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E                - Expression: "layout.base"
E                - Filename:   ... .../town6/templates/login.pt
E                - Location:   (line 1: col 22)
E                - Source:     <div metal:use-macro="layout.base" i18n:domain="onegov.town6 ...
E                                                    ^^^^^^^^^^^
E                - Arguments:  request: <OrgRequest ('None',) at 0x7f5898628050>
E                              translate: <function ('translate',) at 0x7f58901a54e0>
E                              escape: <function ('escape',) at 0x7f58c121c3b0>
E                              Markup: <type ('Markup',) at 0x28307380>
E                              layout: <DefaultLayout ('None',) at 0x7f58926ad450>
E                              password_reset_link: http:.../localhost/auth/request-password?skip=0&to=%2F
E                              register_link: http:.../localhost/auth/register?skip=0&to=%2F
E                              may_register: False
E                              button_text: Login
E                              providers: <dict_values ('None',) at 0x7f588fcd4310>
E                              provider_login: <function ('provider_login',) at 0x7f58901a6140>
E                              render_untrusted_markdown: <function ('render_untrusted_markdown',) at 0x7f58a190c7d0>
E                              title: Login to ${org}
E                              form: <TranslationBoundForm ('None',) at 0x7f588fb5f230>
E                              global_tools: <tuple ('None',) at 0xa6def0>
E                              top_navigation: <tuple ('None',) at 0x7f5890fd99c0>
E                              modules: <LinkGroup ('None',) at 0x7f589210ec50>
E                              target_language: <NoneType ('None',) at 0xa1f2e0>
E                              repeat: <RepeatDict ('None',) at 0x7f588e04b5e0>
E                              macroname: layout.base

................................................................................................................................................................../app/lib/python3.14.../redis/_parsers/hiredis.py:111: ConnectionError
tests/onegov/landsgemeinde/test_browser.py::test_ticker
Stack Traces | 20.2s run time
browser = <tests.shared.browser.ExtendedBrowser object at 0x7fc063e00ec0>
assembly = <onegov.landsgemeinde.models.assembly.Assembly object at 0x7fc0636a9be0>

    def test_ticker(browser: WebsocketBrowser, assembly: Assembly) -> None:
        app = browser.wsgi_server.app
        app.session().add(assembly)
        commit()
    
>       browser.visit('.../landsgemeinde/2023-05-07/ticker')

.../onegov/landsgemeinde/test_browser.py:17: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tests/shared/browser.py:348: in visit
    self.fail_on_console_errors(sleep_before_fail, expected_errors)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.shared.browser.ExtendedBrowser object at 0x7fc063e00ec0>
sleep_before = 0, expected_errors = []

    def fail_on_console_errors(
        self,
        sleep_before: float = 0,
        expected_errors: list[dict[str, Any]] | None = None
    ) -> None:
        expected_errors = expected_errors or []
        filters = expected_errors + self.failsafe_filters
        error_msgs = self.get_console_log(filters)
        if error_msgs and environ.get('SHOW_BROWSER') == '1':
            time.sleep(sleep_before)
>       assert not error_msgs, error_msgs
E       AssertionError: [{'level': 'SEVERE', 'message': 'http://127.0.0.1:.../assembly/2023-05-07/ticker - Failed to load resource: the server responded with a status of 500 (INTERNAL SERVER ERROR)', 'source': 'console-api'}]
E       assert not [{'level': 'SEVERE', 'message': 'http://127.0.0.1:.../assembly/2023-05-07/ticker - Failed to load resource: the server responded with a status of 500 (INTERNAL SERVER ERROR)', 'source': 'console-api'}]

tests/shared/browser.py:671: AssertionError
tests/onegov/fsi/test_views_course_event.py::test_add_delete_course_event
Stack Traces | 24.1s run time
self = <PageTemplateFile .../town6/templates/login.pt>
_BaseTemplate__kw = {'Markup': <class 'markupsafe.Markup'>, '__decode': <method 'decode' of 'bytes' objects>, '__on_error_handler': None, '__translate': <function ChameleonTranslate.<locals>.translate at 0x7fc064d90e00>, ...}
econtext = {'request': <FsiRequest at 0x7fc064edcd70 GET http:.../localhost/auth/login>, 'translate': <function ChameleonTranslate....peatDict object at 0x7fc06940d510>, 'macroname': 'layout.base', '__slot_title': deque([]), '__slot_content': deque([])}
rcontext = {'__error__': [('request.is_logged_in or request.authenticated_email', 97, 132, '.../onegov-cloud/src/on...('layout.base', 1, 22, '.../town6/templates/login.pt', network:ConnectionError)]}
stream = ['<!DOCTYPE html>\n', '<html', '\n    class="no-js"', '\n    lang="de-CH"', '\n    xmlns="http://www.w3.org/1999/xhtml"', ' data-version="2026.30"', ...]
target_language = None, cls = <class 'redis.exceptions.ConnectionError'>

    def render(self, **__kw: Any) -> str:
        econtext = Scope(__kw)
        rcontext: dict[str, Any] = {}
        self.cook_check()
        stream = self.output_stream_factory()
        target_language = __kw.get("target_language")
        try:
>           self._render(
                stream,
                econtext,
                rcontext,
                target_language=target_language
            )

................................................................................................................................................................../app/lib/python3.14........./site-packages/chameleon/template.py:238: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
login_8a1d93341b325aa27ecf87295d924660.py:774: in render
    ???
................................................................................................................................................................../app/lib/python3.14.../chameleon/zpt/template.py:363: in include
    self._render(*args, **kwargs)
layout_83b903260078580fb8f2a30f270a1b49.py:2606: in render
    ???
layout_83b903260078580fb8f2a30f270a1b49.py:1192: in render_layout
    ???
................................................................................................................................................................../app/lib/python3.14........./site-packages/chameleon/utils.py:517: in lookup_attr
    return getattr(obj, key)
           ^^^^^^^^^^^^^^^^^
....../usr/lib/python3.14/functools.py:1126: in __get__
    val = self.func(instance)
          ^^^^^^^^^^^^^^^^^^^
.../onegov/org/request.py:142: in authenticated_email
    return self.browser_session.get('authenticated_email')
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:183: in get
    result = self._get(name)
             ^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:124: in _get
    return self._cache.get(name)
           ^^^^^^^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:34: in get
    return self.cache.get(self.mangle(key))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:783: in get
    value = self._get_cache_value(key, expiration_time, ignore_expiration)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:821: in _get_cache_value
    value = self._get_from_backend(key)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:1325: in _get_from_backend
    self.backend.get_serialized(key)
................................................................................................................................................................../app/lib/python3.14.../cache/backends/redis.py:262: in get_serialized
    value = self.reader_client.get(key)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../redis/commands/core.py:3194: in get
    return self.execute_command("GET", name, keys=[name])
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:787: in execute_command
    return self._execute_command(*args, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:809: in _execute_command
    result = conn.retry.call_with_retry(
................................................................................................................................................................../app/lib/python3.14............/site-packages/redis/retry.py:132: in call_with_retry
    raise error
................................................................................................................................................................../app/lib/python3.14............/site-packages/redis/retry.py:120: in call_with_retry
    return do()
           ^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:810: in <lambda>
    lambda: self._send_command_parse_response(
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:753: in _send_command_parse_response
    return self.parse_response(conn, command_name, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:853: in parse_response
    response = connection.read_response()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14....../site-packages/redis/connection.py:1371: in read_response
    response = self._parser.read_response(
................................................................................................................................................................../app/lib/python3.14.../redis/_parsers/hiredis.py:151: in read_response
    self.read_from_socket(timeout=timeout)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <redis._parsers.hiredis._HiredisParser object at 0x7fc064edef90>
timeout = <object object at 0x7fc09f2cdcf0>, raise_on_timeout = True

    def read_from_socket(self, timeout=SENTINEL, raise_on_timeout=True):
        sock = self._sock
        custom_timeout = timeout is not SENTINEL
        try:
            if custom_timeout:
                sock.settimeout(timeout)
            bufflen = self._sock.recv_into(self._buffer)
            if bufflen == 0:
>               raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)
E               redis.exceptions.ConnectionError: Connection closed by server.

................................................................................................................................................................../app/lib/python3.14.../redis/_parsers/hiredis.py:111: ConnectionError

During handling of the above exception, another exception occurred:

client_with_db = <tests.onegov.fsi.conftest.Client object at 0x7fc069e83a10>

    def test_add_delete_course_event(client_with_db: Client) -> None:
        view = '.../fsi/events/add'
        client = client_with_db
>       client.login_editor()

.../onegov/fsi/test_views_course_event.py:73: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tests/shared/client.py:69: in login_editor
    return self.login('editor@example.org', 'hunter2', to)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tests/shared/client.py:60: in login
    login_page = self.get(url)
                 ^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14....../site-packages/webtest/app.py:328: in get
    return self.do_request(req, status=status,
tests/shared/client.py:159: in do_request
    return self.extend_response(super().do_request(*args, **kwargs))
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../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:1765: in http_conflict_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1790: in activate_session_manager
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1808: in close_session_after_request
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/file/integration.py:477: in configure_depot_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../more/transaction/main.py:67: in transaction_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1628: 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:1833: in current_language_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1875: in set_cache_control_header_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/gis/integration.py:139: in inject_mapbox_api_token_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/websockets/integration.py:151: in websocket_csp_tween
    result = handler(request)
             ^^^^^^^^^^^^^^^^
.../onegov/org/app.py:751: in enable_iframes_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
    ???
.../onegov/org/app.py:991: in wrapped
    response = func(self, obj, request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../site-packages/morepath/view.py:87: in __call__
    response = self.render(content, request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.../onegov/core/templates.py:220: in render
    return original_render(template.render(**variables), request)
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../chameleon/zpt/template.py:359: in render
    return super().render(**_kw)
           ^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14........./site-packages/chameleon/template.py:268: in render
    raise_with_traceback(exc, tb)
................................................................................................................................................................../app/lib/python3.14........./site-packages/chameleon/utils.py:52: in raise_with_traceback
    raise exc
................................................................................................................................................................../app/lib/python3.14........./site-packages/chameleon/template.py:238: in render
    self._render(
login_8a1d93341b325aa27ecf87295d924660.py:774: in render
    ???
................................................................................................................................................................../app/lib/python3.14.../chameleon/zpt/template.py:363: in include
    self._render(*args, **kwargs)
layout_83b903260078580fb8f2a30f270a1b49.py:2606: in render
    ???
layout_83b903260078580fb8f2a30f270a1b49.py:1192: in render_layout
    ???
................................................................................................................................................................../app/lib/python3.14........./site-packages/chameleon/utils.py:517: in lookup_attr
    return getattr(obj, key)
           ^^^^^^^^^^^^^^^^^
....../usr/lib/python3.14/functools.py:1126: in __get__
    val = self.func(instance)
          ^^^^^^^^^^^^^^^^^^^
.../onegov/org/request.py:142: in authenticated_email
    return self.browser_session.get('authenticated_email')
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:183: in get
    result = self._get(name)
             ^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:124: in _get
    return self._cache.get(name)
           ^^^^^^^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:34: in get
    return self.cache.get(self.mangle(key))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:783: in get
    value = self._get_cache_value(key, expiration_time, ignore_expiration)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:821: in _get_cache_value
    value = self._get_from_backend(key)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:1325: in _get_from_backend
    self.backend.get_serialized(key)
................................................................................................................................................................../app/lib/python3.14.../cache/backends/redis.py:262: in get_serialized
    value = self.reader_client.get(key)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../redis/commands/core.py:3194: in get
    return self.execute_command("GET", name, keys=[name])
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:787: in execute_command
    return self._execute_command(*args, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:809: in _execute_command
    result = conn.retry.call_with_retry(
................................................................................................................................................................../app/lib/python3.14............/site-packages/redis/retry.py:132: in call_with_retry
    raise error
................................................................................................................................................................../app/lib/python3.14............/site-packages/redis/retry.py:120: in call_with_retry
    return do()
           ^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:810: in <lambda>
    lambda: self._send_command_parse_response(
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:753: in _send_command_parse_response
    return self.parse_response(conn, command_name, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:853: in parse_response
    response = connection.read_response()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14....../site-packages/redis/connection.py:1371: in read_response
    response = self._parser.read_response(
................................................................................................................................................................../app/lib/python3.14.../redis/_parsers/hiredis.py:151: in read_response
    self.read_from_socket(timeout=timeout)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <redis._parsers.hiredis._HiredisParser object at 0x7fc064edef90>
timeout = <object object at 0x7fc09f2cdcf0>, raise_on_timeout = True

    def read_from_socket(self, timeout=SENTINEL, raise_on_timeout=True):
        sock = self._sock
        custom_timeout = timeout is not SENTINEL
        try:
            if custom_timeout:
                sock.settimeout(timeout)
            bufflen = self._sock.recv_into(self._buffer)
            if bufflen == 0:
>               raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)
E               redis.exceptions.ConnectionError: redis.exceptions.ConnectionError: Connection closed by server.
E               
E                - Expression: "request.is_logged_in or request.authenticated_email"
E                - Filename:   ... .../town6/templates/layout.pt
E                - Location:   (line 97: col 132)
E                - Source:     ... ition="request.is_logged_in or request.authenticated_email">
E                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E                - Expression: "layout.base"
E                - Filename:   ... .../town6/templates/login.pt
E                - Location:   (line 1: col 22)
E                - Source:     <div metal:use-macro="layout.base" i18n:domain="onegov.town6 ...
E                                                    ^^^^^^^^^^^
E                - Arguments:  request: <FsiRequest ('None',) at 0x7fc064edcd70>
E                              translate: <function ('translate',) at 0x7fc064d90e00>
E                              escape: <function ('escape',) at 0x7fc092c543b0>
E                              Markup: <type ('Markup',) at 0x36018dd0>
E                              layout: <DefaultLayout ('None',) at 0x7fc064d8d160>
E                              password_reset_link: http:.../localhost/auth/request-password?skip=0&to=%...
E                              register_link: http:.../localhost/auth/register?skip=0&to=%2Ffsi%2F...
E                              may_register: False
E                              button_text: Login
E                              providers: <dict_values ('None',) at 0x7fc064f021d0>
E                              provider_login: <function ('provider_login',) at 0x7fc064d90ca0>
E                              render_untrusted_markdown: <function ('render_untrusted_markdown',) at 0x7fc0747647d0>
E                              title: Login to ${org}
E                              form: <TranslationBoundForm ('None',) at 0x7fc064d8c830>
E                              global_tools: <tuple ('None',) at 0x7fc064dc1480>
E                              top_navigation: <tuple ('None',) at 0x7fc064e45100>
E                              hide_search_header: True
E                              target_language: <NoneType ('None',) at 0xa1f2e0>
E                              repeat: <RepeatDict ('None',) at 0x7fc06940d510>
E                              macroname: layout.base

................................................................................................................................................................../app/lib/python3.14.../redis/_parsers/hiredis.py:111: ConnectionError
tests/onegov/fsi/test_views_course_event.py::test_edit_course_event
Stack Traces | 24.1s run time
self = <PageTemplateFile .../town6/templates/login.pt>
_BaseTemplate__kw = {'Markup': <class 'markupsafe.Markup'>, '__decode': <method 'decode' of 'bytes' objects>, '__on_error_handler': None, '__translate': <function ChameleonTranslate.<locals>.translate at 0x7fddef1a1640>, ...}
econtext = {'request': <FsiRequest at 0x7fddef324ad0 GET http:.../localhost/auth/login>, 'translate': <function ChameleonTranslate....peatDict object at 0x7fddeed758d0>, 'macroname': 'layout.base', '__slot_title': deque([]), '__slot_content': deque([])}
rcontext = {'__error__': [('request.is_logged_in or request.authenticated_email', 97, 132, '.../onegov-cloud/src/on...('layout.base', 1, 22, '.../town6/templates/login.pt', network:ConnectionError)]}
stream = ['<!DOCTYPE html>\n', '<html', '\n    class="no-js"', '\n    lang="de-CH"', '\n    xmlns="http://www.w3.org/1999/xhtml"', ' data-version="2026.30"', ...]
target_language = None, cls = <class 'redis.exceptions.ConnectionError'>

    def render(self, **__kw: Any) -> str:
        econtext = Scope(__kw)
        rcontext: dict[str, Any] = {}
        self.cook_check()
        stream = self.output_stream_factory()
        target_language = __kw.get("target_language")
        try:
>           self._render(
                stream,
                econtext,
                rcontext,
                target_language=target_language
            )

................................................................................................................................................................../app/lib/python3.14........./site-packages/chameleon/template.py:238: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
login_8a1d93341b325aa27ecf87295d924660.py:774: in render
    ???
................................................................................................................................................................../app/lib/python3.14.../chameleon/zpt/template.py:363: in include
    self._render(*args, **kwargs)
layout_83b903260078580fb8f2a30f270a1b49.py:2606: in render
    ???
layout_83b903260078580fb8f2a30f270a1b49.py:1192: in render_layout
    ???
................................................................................................................................................................../app/lib/python3.14........./site-packages/chameleon/utils.py:517: in lookup_attr
    return getattr(obj, key)
           ^^^^^^^^^^^^^^^^^
....../usr/lib/python3.14/functools.py:1126: in __get__
    val = self.func(instance)
          ^^^^^^^^^^^^^^^^^^^
.../onegov/org/request.py:142: in authenticated_email
    return self.browser_session.get('authenticated_email')
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:183: in get
    result = self._get(name)
             ^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:124: in _get
    return self._cache.get(name)
           ^^^^^^^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:34: in get
    return self.cache.get(self.mangle(key))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:783: in get
    value = self._get_cache_value(key, expiration_time, ignore_expiration)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:821: in _get_cache_value
    value = self._get_from_backend(key)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:1325: in _get_from_backend
    self.backend.get_serialized(key)
................................................................................................................................................................../app/lib/python3.14.../cache/backends/redis.py:262: in get_serialized
    value = self.reader_client.get(key)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../redis/commands/core.py:3194: in get
    return self.execute_command("GET", name, keys=[name])
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:787: in execute_command
    return self._execute_command(*args, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:809: in _execute_command
    result = conn.retry.call_with_retry(
................................................................................................................................................................../app/lib/python3.14............/site-packages/redis/retry.py:132: in call_with_retry
    raise error
................................................................................................................................................................../app/lib/python3.14............/site-packages/redis/retry.py:120: in call_with_retry
    return do()
           ^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:810: in <lambda>
    lambda: self._send_command_parse_response(
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:753: in _send_command_parse_response
    return self.parse_response(conn, command_name, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:853: in parse_response
    response = connection.read_response()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14....../site-packages/redis/connection.py:1371: in read_response
    response = self._parser.read_response(
................................................................................................................................................................../app/lib/python3.14.../redis/_parsers/hiredis.py:151: in read_response
    self.read_from_socket(timeout=timeout)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <redis._parsers.hiredis._HiredisParser object at 0x7fddef3270e0>
timeout = <object object at 0x7fde29329cf0>, raise_on_timeout = True

    def read_from_socket(self, timeout=SENTINEL, raise_on_timeout=True):
        sock = self._sock
        custom_timeout = timeout is not SENTINEL
        try:
            if custom_timeout:
                sock.settimeout(timeout)
            bufflen = self._sock.recv_into(self._buffer)
            if bufflen == 0:
>               raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)
E               redis.exceptions.ConnectionError: Connection closed by server.

................................................................................................................................................................../app/lib/python3.14.../redis/_parsers/hiredis.py:111: ConnectionError

During handling of the above exception, another exception occurred:

client_with_db = <tests.onegov.fsi.conftest.Client object at 0x7fddf2a8ba10>

    def test_edit_course_event(client_with_db: Client) -> None:
        client = client_with_db
        session = client.app.session()
    
        event = session.query(CourseEvent).first()
        assert event is not None
        view = f'/fsi/event/{event.id}/edit'
    
>       client.login_editor()

.../onegov/fsi/test_views_course_event.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tests/shared/client.py:69: in login_editor
    return self.login('editor@example.org', 'hunter2', to)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tests/shared/client.py:60: in login
    login_page = self.get(url)
                 ^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14....../site-packages/webtest/app.py:328: in get
    return self.do_request(req, status=status,
tests/shared/client.py:159: in do_request
    return self.extend_response(super().do_request(*args, **kwargs))
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../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:1765: in http_conflict_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1790: in activate_session_manager
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1808: in close_session_after_request
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/file/integration.py:477: in configure_depot_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../more/transaction/main.py:67: in transaction_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1628: 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:1833: in current_language_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1875: in set_cache_control_header_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/gis/integration.py:139: in inject_mapbox_api_token_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/websockets/integration.py:151: in websocket_csp_tween
    result = handler(request)
             ^^^^^^^^^^^^^^^^
.../onegov/org/app.py:751: in enable_iframes_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
    ???
.../onegov/org/app.py:991: in wrapped
    response = func(self, obj, request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../site-packages/morepath/view.py:87: in __call__
    response = self.render(content, request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.../onegov/core/templates.py:220: in render
    return original_render(template.render(**variables), request)
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../chameleon/zpt/template.py:359: in render
    return super().render(**_kw)
           ^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14........./site-packages/chameleon/template.py:268: in render
    raise_with_traceback(exc, tb)
................................................................................................................................................................../app/lib/python3.14........./site-packages/chameleon/utils.py:52: in raise_with_traceback
    raise exc
................................................................................................................................................................../app/lib/python3.14........./site-packages/chameleon/template.py:238: in render
    self._render(
login_8a1d93341b325aa27ecf87295d924660.py:774: in render
    ???
................................................................................................................................................................../app/lib/python3.14.../chameleon/zpt/template.py:363: in include
    self._render(*args, **kwargs)
layout_83b903260078580fb8f2a30f270a1b49.py:2606: in render
    ???
layout_83b903260078580fb8f2a30f270a1b49.py:1192: in render_layout
    ???
................................................................................................................................................................../app/lib/python3.14........./site-packages/chameleon/utils.py:517: in lookup_attr
    return getattr(obj, key)
           ^^^^^^^^^^^^^^^^^
....../usr/lib/python3.14/functools.py:1126: in __get__
    val = self.func(instance)
          ^^^^^^^^^^^^^^^^^^^
.../onegov/org/request.py:142: in authenticated_email
    return self.browser_session.get('authenticated_email')
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:183: in get
    result = self._get(name)
             ^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:124: in _get
    return self._cache.get(name)
           ^^^^^^^^^^^^^^^^^^^^^
.../onegov/core/browser_session.py:34: in get
    return self.cache.get(self.mangle(key))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:783: in get
    value = self._get_cache_value(key, expiration_time, ignore_expiration)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:821: in _get_cache_value
    value = self._get_from_backend(key)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../dogpile/cache/region.py:1325: in _get_from_backend
    self.backend.get_serialized(key)
................................................................................................................................................................../app/lib/python3.14.../cache/backends/redis.py:262: in get_serialized
    value = self.reader_client.get(key)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14.../redis/commands/core.py:3194: in get
    return self.execute_command("GET", name, keys=[name])
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:787: in execute_command
    return self._execute_command(*args, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:809: in _execute_command
    result = conn.retry.call_with_retry(
................................................................................................................................................................../app/lib/python3.14............/site-packages/redis/retry.py:132: in call_with_retry
    raise error
................................................................................................................................................................../app/lib/python3.14............/site-packages/redis/retry.py:120: in call_with_retry
    return do()
           ^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:810: in <lambda>
    lambda: self._send_command_parse_response(
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:753: in _send_command_parse_response
    return self.parse_response(conn, command_name, **options)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14............................../site-packages/redis/client.py:853: in parse_response
    response = connection.read_response()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
................................................................................................................................................................../app/lib/python3.14....../site-packages/redis/connection.py:1371: in read_response
    response = self._parser.read_response(
................................................................................................................................................................../app/lib/python3.14.../redis/_parsers/hiredis.py:151: in read_response
    self.read_from_socket(timeout=timeout)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <redis._parsers.hiredis._HiredisParser object at 0x7fddef3270e0>
timeout = <object object at 0x7fde29329cf0>, raise_on_timeout = True

    def read_from_socket(self, timeout=SENTINEL, raise_on_timeout=True):
        sock = self._sock
        custom_timeout = timeout is not SENTINEL
        try:
            if custom_timeout:
                sock.settimeout(timeout)
            bufflen = self._sock.recv_into(self._buffer)
            if bufflen == 0:
>               raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)
E               redis.exceptions.ConnectionError: redis.exceptions.ConnectionError: Connection closed by server.
E               
E                - Expression: "request.is_logged_in or request.authenticated_email"
E                - Filename:   ... .../town6/templates/layout.pt
E                - Location:   (line 97: col 132)
E                - Source:     ... ition="request.is_logged_in or request.authenticated_email">
E                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E                - Expression: "layout.base"
E                - Filename:   ... .../town6/templates/login.pt
E                - Location:   (line 1: col 22)
E                - Source:     <div metal:use-macro="layout.base" i18n:domain="onegov.town6 ...
E                                                    ^^^^^^^^^^^
E                - Arguments:  request: <FsiRequest ('None',) at 0x7fddef324ad0>
E                              translate: <function ('translate',) at 0x7fddef1a1640>
E                              escape: <function ('escape',) at 0x7fde1cc503b0>
E                              Markup: <type ('Markup',) at 0x35994870>
E                              layout: <DefaultLayout ('None',) at 0x7fddeeffd2b0>
E                              password_reset_link: http:.../localhost/auth/request-password?skip=0&to=%...
E                              register_link: http:.../localhost/auth/register?skip=0&to=%2Ffsi%2F...
E                              may_register: False
E                              button_text: Login
E                              providers: <dict_values ('None',) at 0x7fddef24a530>
E                              provider_login: <function ('provider_login',) at 0x7fddeec94930>
E                              render_untrusted_markdown: <function ('render_untrusted_markdown',) at 0x7fddfda387d0>
E                              title: Login to ${org}
E                              form: <TranslationBoundForm ('None',) at 0x7fddeeffc050>
E                              global_tools: <tuple ('None',) at 0x7fddeef52d40>
E                              top_navigation: <tuple ('None',) at 0x7fddeef5a800>
E                              hide_search_header: True
E                              target_language: <NoneType ('None',) at 0xa1f2e0>
E                              repeat: <RepeatDict ('None',) at 0x7fddeed758d0>
E                              macroname: layout.base

................................................................................................................................................................../app/lib/python3.14.../redis/_parsers/hiredis.py:111: ConnectionError

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