Skip to content

RIS: Rename for label of members - #2745

Open
cyrillkuettel wants to merge 1 commit into
masterfrom
ogc-3484-parlamentsmitglieder-in-einwohnerratsmitglieder-umbenennen
Open

cyrillkuettel wants to merge 1 commit into
masterfrom
ogc-3484-parlamentsmitglieder-in-einwohnerratsmitglieder-umbenennen

Conversation

@cyrillkuettel

Copy link
Copy Markdown
Contributor

Please fill in the commit message below and work through the checklist. You can delete parts that are not needed, e.g. the optional description, the link to a ticket or irrelevant options of the checklist.

Commit message

:

TYPE: <Feature|Performance|Bugfix>
LINK:
HINT:

Checklist

  • I have performed a self-review of my code
  • I considered adding a reviewer
  • I have added an upgrade hint such as data migration commands to be run
  • I have updated the PO files
  • I have added new modules to the docs
  • I made changes/features for both org and town6
  • I have updated the election_day API docs
  • I have tested my code thoroughly by hand
    • I have tested styling changes/features on different browsers
    • I have tested javascript changes/features on different browsers
    • I have tested database upgrades
    • I have tested sending mails
    • I have tested building the documentation
  • I have added tests for my changes/features
    • I am using freezegun for tests depending on date and times
    • I considered using browser tests für javascript changes/features
    • I have added/updated jest tests for d3rendering (election_day, swissvotes)

@linear

linear Bot commented Oct 19, 2026

Copy link
Copy Markdown

OGC-3484

@codecov

codecov Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

❌ 6 Tests Failed:

Tests completed Failed Passed Skipped
2999 6 2993 16
View the top 3 failed test(s) by shortest run time
tests/onegov/directory/test_content_hash.py::test_upgrade_preserves_modified_timestamp
Stack Traces | 0.952s run time
session = <sqlalchemy.orm.session.Session object at 0x7f9c40b6f380>

    def test_upgrade_preserves_modified_timestamp(session: Session) -> None:
        rooms = DirectoryCollection(session).add(
            title='Rooms',
            structure='Name *= ___',
            configuration=DirectoryConfiguration(title='Name', order=['Name']),
        )
    
        conference = rooms.add(values=dict(name='Conference Room'))
        original_modified = datetime(2020, 1, 1, tzinfo=timezone.utc)
    
        # simulate pre-upgrade state: no hash, known modified timestamp
        none_hash: str | None = None
        conference.content_hash = none_hash
        conference.modified = original_modified
        session.flush()
    
        context = Bunch(session=session, has_column=lambda table, col: True)
        calc_content_hash_for_directory_entries(cast(UpgradeContext, context))
        session.flush()
    
        assert conference.content_hash is not None
>       assert conference.modified == original_modified
E       assert datetime.datetime(2026, 10, 19, 15, 2, 52, 503567, tzinfo=<UTC>) == datetime.datetime(2020, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)
E        +  where datetime.datetime(2026, 10, 19, 15, 2, 52, 503567, tzinfo=<UTC>) = <onegov.directory.models.directory_entry.DirectoryEntry object at 0x7f9c404d8d70>.modified

.../onegov/directory/test_content_hash.py:414: AssertionError
tests/onegov/election_day/collections/test_searchable_archived_result_collection.py::test_searchable_archive
Stack Traces | 1.08s run time
session = <sqlalchemy.orm.session.Session object at 0x7f4c182c6ba0>
searchable_archive = <onegov.election_day.collections.archived_results.SearchableArchivedResultCollection object at 0x7f4c182c63c0>

    def test_searchable_archive(
        session: Session,
        searchable_archive: SearchableArchivedResultCollection
    ) -> None:
        # Test to_date is always filled in and is type date
        archive = SearchableArchivedResultCollection(DummyApp(session))  # type: ignore[arg-type]
        assert archive.to_date
        assert archive.from_date is None
        assert isinstance(archive.to_date, date)
    
        # Test initial query without params
        assert archive.query().count() == 14
    
        # Test with values like you would when going to search form first time
        archive = SearchableArchivedResultCollection(DummyApp(session))  # type: ignore[arg-type]
        archive.domains = ['federation', 'canton', 'region', 'municipality']
        archive.answers = ['accepted', 'rejected', 'counter_proposal']
        archive.term = ''
        assert not archive.item_type
        assert archive.query().count() == 14
    
        # Test to_date is neglected if from_date is not given
        archive = SearchableArchivedResultCollection(DummyApp(session))  # type: ignore[arg-type]
        assert not archive.from_date
        assert 'WHERE archived_results.date' not in str(archive.query())
    
        # Test query and results with a value of to_date and from_date
        archive = SearchableArchivedResultCollection(DummyApp(session))  # type: ignore[arg-type]
        archive.from_date = date(2009, 1, 1)
        assert 'WHERE archived_results.date' in str(archive.query())
        assert archive.query().count() == 13
    
        # Test getting et the 2009 election
        archive = SearchableArchivedResultCollection(DummyApp(session))  # type: ignore[arg-type]
        archive.from_date = date(2008, 1, 1)
        archive.to_date = date(2008, 1, 2)
        assert archive.query().count() == 1
    
        # Test by item type
        archive = SearchableArchivedResultCollection(DummyApp(session))  # type: ignore[arg-type]
        archive.item_type = 'vote'
        assert archive.query().count() == 3
    
        archive.reset_query_params()
        archive.item_type = 'election'
        assert archive.query().count() == 11
    
        # Test domains
        archive = SearchableArchivedResultCollection(DummyApp(session))  # type: ignore[arg-type]
        archive.domains = ['federation']
        assert archive.query().count() == 9
    
        archive.domains = ['canton']
        assert archive.query().count() == 1
    
        archive.domains = ['region']
        assert archive.query().count() == 3
    
        archive.domains = ['district']
        assert archive.query().count() == 1
    
        archive.domains = ['none']
        assert archive.query().count() == 1
    
        archive.domains = ['municipality']
        assert archive.query().count() == 1
    
        archive.domains = ['@@CX6d3', 'invalid-value']
        assert archive.query().count() == 14  # invalid values ignored → no filter
    
        archive.domains = ['federation', '@@CX6d3']
        assert archive.query().count() == 9  # invalid value stripped, valid kept
    
        # Test voting result
        results = session.query(ArchivedResult).filter_by(type='vote').all()
        for item in results:
            item.answer = 'accepted'
    
        archive = SearchableArchivedResultCollection(DummyApp(session))  # type: ignore[arg-type]
        archive.item_type = 'vote'
        archive.answers = ['accepted']
        assert archive.query().count() == 3
    
        # Test term
        # want to find the 2008 election
        archive = SearchableArchivedResultCollection(DummyApp(session))  # type: ignore[arg-type]
        archive.term = 'election 2009'
        assert archive.query().count() == 1
    
        # Test combination of parameters
        archive = SearchableArchivedResultCollection(DummyApp(session))  # type: ignore[arg-type]
        archive.domains = ['federation']   # filter to 10
        archive.item_type = 'election'     # filters to 6
        archive.answers = ['accepted', 'rejected', 'counter_proposal']
        archive.from_date = date(2009, 1, 1)
        archive.to_date = date(2009, 1, 2)
        archive.term = 'Election 2009'
        assert archive.locale == 'de_CH'
        assert archive.query().count() == 1
    
        sql_query = str(archive.query())
        assert 'archived_results.domain IN' in sql_query
        assert 'archived_results.date >=' in sql_query
        assert 'archived_results.type IN' in sql_query
        assert 'archived_results.date >=' in sql_query
        assert 'archived_results.date <=' in sql_query
>       assert "archived_results.title_translations -> 'de_CH'" in sql_query
E       assert "archived_results.title_translations -> 'de_CH'" in 'SELECT archived_results.id AS archived_results_id, archived_results.date AS archived_results_date, archived_results.l... = %(domain_6)s) THEN %(param_6)s::INTEGER WHEN (archived_results.domain = %(domain_7)s) THEN %(param_7)s::INTEGER END'

.../election_day/collections/test_searchable_archived_result_collection.py:167: AssertionError
tests/onegov/org/test_browser.py::test_browse_activities@browser
Stack Traces | 12.4s run time
browser = <tests.shared.browser.ExtendedBrowser object at 0x7efcae3d41a0>

    @pytest.mark.xdist_group(name="browser")
    def test_browse_activities(browser: ExtendedBrowser) -> None:
        # admins
        browser.login_admin()
        browser.visit('/timeline')
    
        assert browser.is_text_present("Noch keine Aktivität")
    
        # anonymous
>       browser.logout()

.../onegov/org/test_browser.py:43: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tests/shared/browser.py:373: in logout
    self.visit('/auth/logout')
tests/shared/browser.py:349: in visit
    self.fail_on_console_errors(sleep_before_fail, expected_errors)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <tests.shared.browser.ExtendedBrowser object at 0x7efcae3d41a0>
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', 'source': 'console-api', 'message': 'http://127.0.0.1:35357/ - Failed to load resource: the server responded with a status of 500 (INTERNAL SERVER ERROR)'}]
E       assert not [{'level': 'SEVERE', 'source': 'console-api', 'message': 'http://127.0.0.1:35357/ - Failed to load resource: the server responded with a status of 500 (INTERNAL SERVER ERROR)'}]

tests/shared/browser.py:672: AssertionError
tests/onegov/org/test_views_resources.py::test_reserve_allocation[reject-all]
Stack Traces | 21.3s run time
broadcast = <AsyncMock name='broadcast' id='139648764471552'>
authenticate = <AsyncMock name='authenticate' id='139648764473232'>
connect = <MagicMock name='connect' id='139648764473904'>
client = <tests.onegov.org.conftest.Client object at 0x7f028740c1a0>
reject_type = 'reject-all'

    @pytest.mark.parametrize(
        'reject_type', ['reject-all', 'reject-all-with-message']
    )
    @freeze_time('2015-08-28', tick=True)
    @patch('onegov.websockets.integration.connect')
    @patch('onegov.websockets.integration.authenticate')
    @patch('onegov.websockets.integration.broadcast')
    def test_reserve_allocation(
        broadcast: MagicMock,
        authenticate: MagicMock,
        connect: MagicMock,
        client: Client,
        reject_type: str,
    ) -> None:
        # prepate the required data
        resources = ResourceCollection(client.app.libres_context)
        resource = resources.by_name('tageskarte')
        assert resource is not None
        resource.definition = 'Note = ___'
        scheduler = resource.get_scheduler(client.app.libres_context)
    
        allocations = scheduler.allocate(
            dates=(datetime(2015, 8, 28), datetime(2015, 8, 28)),
            whole_day=True,
            quota=4,
            quota_limit=4,
        )
    
        reserve = client.bound_reserve(allocations[0])
        transaction.commit()
    
        # create a reservation
        result = reserve(quota=4, whole_day=True)
        assert result.json == {'success': True}
        assert result.headers['X-IC-Trigger'] == 'rc-reservations-changed'
    
        # and fill out the form
        formular = client.get('.../resource/tageskarte/form')
        formular.form['email'] = 'info@example.org'
        formular.form['note'] = 'Foobar'
    
        ticket = formular.form.submit().follow().form.submit().follow()
    
        assert 'RSV-' in ticket.text
        assert len(os.listdir(client.app.maildir)) == 1
    
        # make sure the resulting reservation has no session_id set
        ids = [r.session_id for r in scheduler.managed_reservations()]
        assert not any(ids)
    
        # try to create another reservation the same time
        result = reserve(quota=4, whole_day=True)
        assert result.json == {
            'success': False,
            'message': 'Der gewünschte Zeitraum ist nicht mehr verfügbar.',
        }
    
        assert result.headers['X-IC-Trigger'] == 'rc-reservation-error'
        assert json.loads(result.headers['X-IC-Trigger-Data']) == result.json
    
        # try deleting the allocation with the existing reservation
        client.login_admin()
    
        slots = client.get(
            ('.../resource/tageskarte/slots?start=2015-08-28&end=2015-08-28')
        )
    
        assert len(slots.json) == 1
    
        response = client.delete(client.extract_href(slots.json[0]['actions'][3]))
        result = json.loads(response.headers['X-IC-Trigger-Data'])
        assert result == {
            'success': False,
            'message': (
                'Eine bestehende Reservation wäre von der gewünschten Änderung '
                'betroffen.'
            ),
        }
    
        # open the created ticket
        client.login_supporter()
>       ticket = client.get('.../tickets/ALL/open').click('Annehmen').follow()
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.../onegov/org/test_views_resources.py:1397: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
........................................................................................................./app/lib/python3.14....../site-packages/webtest/app.py:328: in get
    return self.do_request(req, status=status,
tests/shared/client.py:157: 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:1314: in send
    status, headers, app_iter, exc_info = self.call_application(
........................................................................................................./app/lib/python3.14....../site-packages/webob/request.py:1283: 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:232: in with_request_cache_wrapper
    return fn(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:247: in with_print_exceptions_wrapper
    return fn(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../site-packages/morepath/app.py:171: in __call__
    response = self.publish(request)
               ^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14....../site-packages/morepath/core.py:208: in poisoned_host_header_protection_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1782: in http_conflict_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1813: in activate_session_manager
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1831: in close_session_after_request
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1856: in current_language_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1883: in current_user
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/file/integration.py:476: in configure_depot_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../more/transaction/main.py:74: in transaction_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1645: 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:143: in __call__
    return self.handler(request)
           ^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../more/webassets/tweens.py:95: in __call__
    response = self.handler(request)
               ^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14....../site-packages/morepath/core.py:168: in excview_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../more/content_security/core.py:126: in content_security_policy_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1927: in set_cache_control_header_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/gis/integration.py:137: in inject_mapbox_api_token_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/websockets/integration.py:149: 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:49: in publish
    return resolve_response(obj, request)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14....../site-packages/morepath/publish.py:104: 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:1011: in wrapped
    response = func(self, obj, request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../site-packages/morepath/view.py:151: in __call__
    content = self.func(obj, request)
              ^^^^^^^^^^^^^^^^^^^^^^^
.../org/views/ticket.py:1760: in view_tickets
    submitters = tuple(get_submitters(self, request))
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.../org/views/ticket.py:1714: in get_submitters
    for email, in query:
                  ^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/orm/query.py:2907: in __iter__
    result = self._iter()
             ^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/orm/query.py:2921: in _iter
    result: Union[ScalarResult[_T], Result[_T]] = self.session.execute(
........................................................................................................./app/lib/python3.14.../sqlalchemy/orm/session.py:2473: in execute
    return self._execute_internal(
........................................................................................................./app/lib/python3.14.../sqlalchemy/orm/session.py:2363: in _execute_internal
    compile_state_cls.orm_execute_statement(
........................................................................................................./app/lib/python3.14.../sqlalchemy/orm/context.py:316: in orm_execute_statement
    result = conn.execute(
........................................................................................................./app/lib/python3.14.../sqlalchemy/engine/base.py:1458: in execute
    return meth(
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/elements.py:533: in _execute_on_connection
    return connection._execute_clauseelement(
........................................................................................................./app/lib/python3.14.../sqlalchemy/engine/base.py:1669: in _execute_clauseelement
    elem._compile_w_cache(
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/elements.py:733: in _compile_w_cache
    compiled_sql = self._compiler(
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/elements.py:330: in _compiler
    return dialect.statement_compiler(dialect, self, **kw)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/compiler.py:1543: in __init__
    Compiled.__init__(self, dialect, statement, **kwargs)
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/compiler.py:936: in __init__
    self.string = self.process(self.statement, **compile_kwargs)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/compiler.py:972: in process
    return obj._compiler_dispatch(self, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/visitors.py:128: in _compiler_dispatch
    return meth(self, **kw)  # type: ignore[no-any-return]  # noqa: E501
           ^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/compiler.py:5225: in visit_select
    self._label_select_column(
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/compiler.py:5035: in _label_select_column
    return result_expr._compiler_dispatch(self, **column_clause_args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/visitors.py:128: in _compiler_dispatch
    return meth(self, **kw)  # type: ignore[no-any-return]  # noqa: E501
           ^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/compiler.py:3346: in visit_unary
    util.warn(
........................................................................................................./app/lib/python3.14.../sqlalchemy/util/langhelpers.py:2020: in warn
    _warnings_warn(msg, exc.SAWarning)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

message = "Column-expression-level unary distinct() should not be used outside of an aggregate function. For general 'SELECT DISTINCT' support use select().distinct()."
category = <class 'sqlalchemy.exc.SAWarning'>, stacklevel = 20

    def _warnings_warn(
        message: Union[str, Warning],
        category: Optional[Type[Warning]] = None,
        stacklevel: int = 2,
    ) -> None:
    
        if category is None and isinstance(message, Warning):
            category = type(message)
    
        # adjust the given stacklevel to be outside of SQLAlchemy
        try:
            frame = sys._getframe(stacklevel)
        except ValueError:
            # being called from less than 3 (or given) stacklevels, weird,
            # but don't crash
            stacklevel = 0
        except:
            # _getframe() doesn't work, weird interpreter issue, weird,
            # ok, but don't crash
            stacklevel = 0
        else:
            stacklevel_found = warning_tag_found = False
            while frame is not None:
                # using __name__ here requires that we have __name__ in the
                # __globals__ of the decorated string functions we make also.
                # we generate this using {"__name__": fn.__module__}
                if not stacklevel_found and not re.match(
                    _not_sa_pattern, frame.f_globals.get("__name__", "")
                ):
                    # stop incrementing stack level if an out-of-SQLA line
                    # were found.
                    stacklevel_found = True
    
                    # however, for the warning tag thing, we have to keep
                    # scanning up the whole traceback
    
                if frame.f_code in _warning_tags:
                    warning_tag_found = True
                    _suffix, _category = _warning_tags[frame.f_code]
                    category = category or _category
                    message = f"{message} ({_suffix})"
    
                frame = frame.f_back  # type: ignore[assignment]
    
                if not stacklevel_found:
                    stacklevel += 1
                elif stacklevel_found and warning_tag_found:
                    break
    
        if category is not None:
>           warnings.warn(message, category, stacklevel=stacklevel + 1)
E           sqlalchemy.exc.SAWarning: Column-expression-level unary distinct() should not be used outside of an aggregate function. For general 'SELECT DISTINCT' support use select().distinct().

........................................................................................................./app/lib/python3.14.../sqlalchemy/util/langhelpers.py:2099: SAWarning
tests/onegov/org/test_views_resources.py::test_auto_accept_reservations[True-admin@example.org]
Stack Traces | 22.3s run time
client = <tests.onegov.org.conftest.Client object at 0x7fb1d5e941a0>
logged_in = True, expected_owner = 'admin@example.org'

    @pytest.mark.parametrize('logged_in,expected_owner', [
        # anonymous requester -> messages attributed to the auto-accept user
        (False, 'autoaccept@example.org'),
        # logged-in requester -> messages attributed to that logged-in user
        (True, 'admin@example.org'),
    ])
    @freeze_time('2015-08-28', tick=True)
    def test_auto_accept_reservations(
        client: Client,
        logged_in: bool,
        expected_owner: str,
    ) -> None:
        # prepare the required data
        resources = ResourceCollection(client.app.libres_context)
        resource = resources.by_name('tageskarte')
        assert resource is not None
        resource.definition = 'Note = ___'
        resource.pick_up = 'You can pick it up at the counter'
        scheduler = resource.get_scheduler(client.app.libres_context)
    
        allocations = scheduler.allocate(
            dates=(datetime(2015, 8, 28), datetime(2015, 8, 28)),
            whole_day=True,
            quota=4,
            quota_limit=4,
        )
    
        reserve = client.bound_reserve(allocations[0])
    
        # add a distinct admin as the configured auto-accept user, so we can
        # tell it apart from a logged-in requester (OGC-3256)
        UserCollection(client.app.session()).add(
            username='autoaccept@example.org', password='hunter2', role='admin'
        )
        transaction.commit()
    
        # configure auto-accept via a separate admin client, so the requester
        # below can stay anonymous
        admin_client = client.spawn()
        admin_client.login_admin()
        settings = admin_client.get('/ticket-settings')
        settings.form['ticket_auto_accepts'] = ['RSV']
        settings.form['auto_closing_user'] = 'autoaccept@example.org'
        settings.form.submit()
    
        # the requester is either anonymous or the logged-in admin
        if logged_in:
            client.login_admin()
    
        # create a reservation
        result = reserve(quota=4, whole_day=True)
        assert result.json == {'success': True}
    
        # and fill out the form
        formular = client.get('.../resource/tageskarte/form')
        formular.form['email'] = 'info@example.org'
        formular.form['note'] = 'Foobar'
    
        page = formular.form.submit().follow().form.submit().follow()
    
        assert 'Ihr Anliegen wurde abgeschlossen' in page
        assert 'Die Reservationen wurden angenommen' in page
        assert len(os.listdir(client.app.maildir)) == 1
        message = client.get_email(0)
        assert message is not None
        assert 'Tageskarte - 28.08.2015 - Angenommen' in message['Subject']
        assert 'Foobar' in message['TextBody']
        assert message['Attachments']
        _, pdf_content = extract_pdf_info(
            BytesIO(b64decode(message['Attachments'][0]['Content']))
        )
        assert 'Tageskarte' in pdf_content
        assert '28.08.2015' in pdf_content
        assert 'Ganztägig' in pdf_content
    
        # close the ticket and check not email is sent
>       tickets = admin_client.get('.../tickets/ALL/closed')
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.../onegov/org/test_views_resources.py:1239: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
........................................................................................................./app/lib/python3.14....../site-packages/webtest/app.py:328: in get
    return self.do_request(req, status=status,
tests/shared/client.py:157: 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:1314: in send
    status, headers, app_iter, exc_info = self.call_application(
........................................................................................................./app/lib/python3.14....../site-packages/webob/request.py:1283: 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:232: in with_request_cache_wrapper
    return fn(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:247: in with_print_exceptions_wrapper
    return fn(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../site-packages/morepath/app.py:171: in __call__
    response = self.publish(request)
               ^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14....../site-packages/morepath/core.py:208: in poisoned_host_header_protection_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1782: in http_conflict_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1813: in activate_session_manager
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1831: in close_session_after_request
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1856: in current_language_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1883: in current_user
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/file/integration.py:476: in configure_depot_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../more/transaction/main.py:74: in transaction_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1645: 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:143: in __call__
    return self.handler(request)
           ^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../more/webassets/tweens.py:95: in __call__
    response = self.handler(request)
               ^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14....../site-packages/morepath/core.py:168: in excview_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../more/content_security/core.py:126: in content_security_policy_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1927: in set_cache_control_header_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/gis/integration.py:137: in inject_mapbox_api_token_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/websockets/integration.py:149: 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:49: in publish
    return resolve_response(obj, request)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14....../site-packages/morepath/publish.py:104: 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:1011: in wrapped
    response = func(self, obj, request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../site-packages/morepath/view.py:151: in __call__
    content = self.func(obj, request)
              ^^^^^^^^^^^^^^^^^^^^^^^
.../org/views/ticket.py:1760: in view_tickets
    submitters = tuple(get_submitters(self, request))
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.../org/views/ticket.py:1714: in get_submitters
    for email, in query:
                  ^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/orm/query.py:2907: in __iter__
    result = self._iter()
             ^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/orm/query.py:2921: in _iter
    result: Union[ScalarResult[_T], Result[_T]] = self.session.execute(
........................................................................................................./app/lib/python3.14.../sqlalchemy/orm/session.py:2473: in execute
    return self._execute_internal(
........................................................................................................./app/lib/python3.14.../sqlalchemy/orm/session.py:2363: in _execute_internal
    compile_state_cls.orm_execute_statement(
........................................................................................................./app/lib/python3.14.../sqlalchemy/orm/context.py:316: in orm_execute_statement
    result = conn.execute(
........................................................................................................./app/lib/python3.14.../sqlalchemy/engine/base.py:1458: in execute
    return meth(
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/elements.py:533: in _execute_on_connection
    return connection._execute_clauseelement(
........................................................................................................./app/lib/python3.14.../sqlalchemy/engine/base.py:1669: in _execute_clauseelement
    elem._compile_w_cache(
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/elements.py:733: in _compile_w_cache
    compiled_sql = self._compiler(
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/elements.py:330: in _compiler
    return dialect.statement_compiler(dialect, self, **kw)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/compiler.py:1543: in __init__
    Compiled.__init__(self, dialect, statement, **kwargs)
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/compiler.py:936: in __init__
    self.string = self.process(self.statement, **compile_kwargs)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/compiler.py:972: in process
    return obj._compiler_dispatch(self, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/visitors.py:128: in _compiler_dispatch
    return meth(self, **kw)  # type: ignore[no-any-return]  # noqa: E501
           ^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/compiler.py:5225: in visit_select
    self._label_select_column(
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/compiler.py:5035: in _label_select_column
    return result_expr._compiler_dispatch(self, **column_clause_args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/visitors.py:128: in _compiler_dispatch
    return meth(self, **kw)  # type: ignore[no-any-return]  # noqa: E501
           ^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/compiler.py:3346: in visit_unary
    util.warn(
........................................................................................................./app/lib/python3.14.../sqlalchemy/util/langhelpers.py:2020: in warn
    _warnings_warn(msg, exc.SAWarning)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

message = "Column-expression-level unary distinct() should not be used outside of an aggregate function. For general 'SELECT DISTINCT' support use select().distinct()."
category = <class 'sqlalchemy.exc.SAWarning'>, stacklevel = 20

    def _warnings_warn(
        message: Union[str, Warning],
        category: Optional[Type[Warning]] = None,
        stacklevel: int = 2,
    ) -> None:
    
        if category is None and isinstance(message, Warning):
            category = type(message)
    
        # adjust the given stacklevel to be outside of SQLAlchemy
        try:
            frame = sys._getframe(stacklevel)
        except ValueError:
            # being called from less than 3 (or given) stacklevels, weird,
            # but don't crash
            stacklevel = 0
        except:
            # _getframe() doesn't work, weird interpreter issue, weird,
            # ok, but don't crash
            stacklevel = 0
        else:
            stacklevel_found = warning_tag_found = False
            while frame is not None:
                # using __name__ here requires that we have __name__ in the
                # __globals__ of the decorated string functions we make also.
                # we generate this using {"__name__": fn.__module__}
                if not stacklevel_found and not re.match(
                    _not_sa_pattern, frame.f_globals.get("__name__", "")
                ):
                    # stop incrementing stack level if an out-of-SQLA line
                    # were found.
                    stacklevel_found = True
    
                    # however, for the warning tag thing, we have to keep
                    # scanning up the whole traceback
    
                if frame.f_code in _warning_tags:
                    warning_tag_found = True
                    _suffix, _category = _warning_tags[frame.f_code]
                    category = category or _category
                    message = f"{message} ({_suffix})"
    
                frame = frame.f_back  # type: ignore[assignment]
    
                if not stacklevel_found:
                    stacklevel += 1
                elif stacklevel_found and warning_tag_found:
                    break
    
        if category is not None:
>           warnings.warn(message, category, stacklevel=stacklevel + 1)
E           sqlalchemy.exc.SAWarning: Column-expression-level unary distinct() should not be used outside of an aggregate function. For general 'SELECT DISTINCT' support use select().distinct().

........................................................................................................./app/lib/python3.14.../sqlalchemy/util/langhelpers.py:2099: SAWarning
tests/onegov/org/test_views_resources.py::test_auto_accept_reservations[False-autoaccept@example.org]
Stack Traces | 22.4s run time
client = <tests.onegov.org.conftest.Client object at 0x7f51fa8b81a0>
logged_in = False, expected_owner = 'autoaccept@example.org'

    @pytest.mark.parametrize('logged_in,expected_owner', [
        # anonymous requester -> messages attributed to the auto-accept user
        (False, 'autoaccept@example.org'),
        # logged-in requester -> messages attributed to that logged-in user
        (True, 'admin@example.org'),
    ])
    @freeze_time('2015-08-28', tick=True)
    def test_auto_accept_reservations(
        client: Client,
        logged_in: bool,
        expected_owner: str,
    ) -> None:
        # prepare the required data
        resources = ResourceCollection(client.app.libres_context)
        resource = resources.by_name('tageskarte')
        assert resource is not None
        resource.definition = 'Note = ___'
        resource.pick_up = 'You can pick it up at the counter'
        scheduler = resource.get_scheduler(client.app.libres_context)
    
        allocations = scheduler.allocate(
            dates=(datetime(2015, 8, 28), datetime(2015, 8, 28)),
            whole_day=True,
            quota=4,
            quota_limit=4,
        )
    
        reserve = client.bound_reserve(allocations[0])
    
        # add a distinct admin as the configured auto-accept user, so we can
        # tell it apart from a logged-in requester (OGC-3256)
        UserCollection(client.app.session()).add(
            username='autoaccept@example.org', password='hunter2', role='admin'
        )
        transaction.commit()
    
        # configure auto-accept via a separate admin client, so the requester
        # below can stay anonymous
        admin_client = client.spawn()
        admin_client.login_admin()
        settings = admin_client.get('/ticket-settings')
        settings.form['ticket_auto_accepts'] = ['RSV']
        settings.form['auto_closing_user'] = 'autoaccept@example.org'
        settings.form.submit()
    
        # the requester is either anonymous or the logged-in admin
        if logged_in:
            client.login_admin()
    
        # create a reservation
        result = reserve(quota=4, whole_day=True)
        assert result.json == {'success': True}
    
        # and fill out the form
        formular = client.get('.../resource/tageskarte/form')
        formular.form['email'] = 'info@example.org'
        formular.form['note'] = 'Foobar'
    
        page = formular.form.submit().follow().form.submit().follow()
    
        assert 'Ihr Anliegen wurde abgeschlossen' in page
        assert 'Die Reservationen wurden angenommen' in page
        assert len(os.listdir(client.app.maildir)) == 1
        message = client.get_email(0)
        assert message is not None
        assert 'Tageskarte - 28.08.2015 - Angenommen' in message['Subject']
        assert 'Foobar' in message['TextBody']
        assert message['Attachments']
        _, pdf_content = extract_pdf_info(
            BytesIO(b64decode(message['Attachments'][0]['Content']))
        )
        assert 'Tageskarte' in pdf_content
        assert '28.08.2015' in pdf_content
        assert 'Ganztägig' in pdf_content
    
        # close the ticket and check not email is sent
>       tickets = admin_client.get('.../tickets/ALL/closed')
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.../onegov/org/test_views_resources.py:1239: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
........................................................................................................./app/lib/python3.14....../site-packages/webtest/app.py:328: in get
    return self.do_request(req, status=status,
tests/shared/client.py:157: 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:1314: in send
    status, headers, app_iter, exc_info = self.call_application(
........................................................................................................./app/lib/python3.14....../site-packages/webob/request.py:1283: 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:232: in with_request_cache_wrapper
    return fn(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:247: in with_print_exceptions_wrapper
    return fn(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../site-packages/morepath/app.py:171: in __call__
    response = self.publish(request)
               ^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14....../site-packages/morepath/core.py:208: in poisoned_host_header_protection_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1782: in http_conflict_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1813: in activate_session_manager
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1831: in close_session_after_request
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1856: in current_language_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1883: in current_user
    return handler(request)
           ^^^^^^^^^^^^^^^^
.../onegov/file/integration.py:476: in configure_depot_tween
    return handler(request)
           ^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../more/transaction/main.py:74: in transaction_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1645: 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:143: in __call__
    return self.handler(request)
           ^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../more/webassets/tweens.py:95: in __call__
    response = self.handler(request)
               ^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14....../site-packages/morepath/core.py:168: in excview_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../more/content_security/core.py:126: in content_security_policy_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/core/framework.py:1927: in set_cache_control_header_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/gis/integration.py:137: in inject_mapbox_api_token_tween
    response = handler(request)
               ^^^^^^^^^^^^^^^^
.../onegov/websockets/integration.py:149: 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:49: in publish
    return resolve_response(obj, request)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14....../site-packages/morepath/publish.py:104: 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:1011: in wrapped
    response = func(self, obj, request)
               ^^^^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../site-packages/morepath/view.py:151: in __call__
    content = self.func(obj, request)
              ^^^^^^^^^^^^^^^^^^^^^^^
.../org/views/ticket.py:1760: in view_tickets
    submitters = tuple(get_submitters(self, request))
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.../org/views/ticket.py:1714: in get_submitters
    for email, in query:
                  ^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/orm/query.py:2907: in __iter__
    result = self._iter()
             ^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/orm/query.py:2921: in _iter
    result: Union[ScalarResult[_T], Result[_T]] = self.session.execute(
........................................................................................................./app/lib/python3.14.../sqlalchemy/orm/session.py:2473: in execute
    return self._execute_internal(
........................................................................................................./app/lib/python3.14.../sqlalchemy/orm/session.py:2363: in _execute_internal
    compile_state_cls.orm_execute_statement(
........................................................................................................./app/lib/python3.14.../sqlalchemy/orm/context.py:316: in orm_execute_statement
    result = conn.execute(
........................................................................................................./app/lib/python3.14.../sqlalchemy/engine/base.py:1458: in execute
    return meth(
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/elements.py:533: in _execute_on_connection
    return connection._execute_clauseelement(
........................................................................................................./app/lib/python3.14.../sqlalchemy/engine/base.py:1669: in _execute_clauseelement
    elem._compile_w_cache(
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/elements.py:733: in _compile_w_cache
    compiled_sql = self._compiler(
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/elements.py:330: in _compiler
    return dialect.statement_compiler(dialect, self, **kw)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/compiler.py:1543: in __init__
    Compiled.__init__(self, dialect, statement, **kwargs)
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/compiler.py:936: in __init__
    self.string = self.process(self.statement, **compile_kwargs)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/compiler.py:972: in process
    return obj._compiler_dispatch(self, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/visitors.py:128: in _compiler_dispatch
    return meth(self, **kw)  # type: ignore[no-any-return]  # noqa: E501
           ^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/compiler.py:5225: in visit_select
    self._label_select_column(
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/compiler.py:5035: in _label_select_column
    return result_expr._compiler_dispatch(self, **column_clause_args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/visitors.py:128: in _compiler_dispatch
    return meth(self, **kw)  # type: ignore[no-any-return]  # noqa: E501
           ^^^^^^^^^^^^^^^^
........................................................................................................./app/lib/python3.14.../sqlalchemy/sql/compiler.py:3346: in visit_unary
    util.warn(
........................................................................................................./app/lib/python3.14.../sqlalchemy/util/langhelpers.py:2020: in warn
    _warnings_warn(msg, exc.SAWarning)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

message = "Column-expression-level unary distinct() should not be used outside of an aggregate function. For general 'SELECT DISTINCT' support use select().distinct()."
category = <class 'sqlalchemy.exc.SAWarning'>, stacklevel = 20

    def _warnings_warn(
        message: Union[str, Warning],
        category: Optional[Type[Warning]] = None,
        stacklevel: int = 2,
    ) -> None:
    
        if category is None and isinstance(message, Warning):
            category = type(message)
    
        # adjust the given stacklevel to be outside of SQLAlchemy
        try:
            frame = sys._getframe(stacklevel)
        except ValueError:
            # being called from less than 3 (or given) stacklevels, weird,
            # but don't crash
            stacklevel = 0
        except:
            # _getframe() doesn't work, weird interpreter issue, weird,
            # ok, but don't crash
            stacklevel = 0
        else:
            stacklevel_found = warning_tag_found = False
            while frame is not None:
                # using __name__ here requires that we have __name__ in the
                # __globals__ of the decorated string functions we make also.
                # we generate this using {"__name__": fn.__module__}
                if not stacklevel_found and not re.match(
                    _not_sa_pattern, frame.f_globals.get("__name__", "")
                ):
                    # stop incrementing stack level if an out-of-SQLA line
                    # were found.
                    stacklevel_found = True
    
                    # however, for the warning tag thing, we have to keep
                    # scanning up the whole traceback
    
                if frame.f_code in _warning_tags:
                    warning_tag_found = True
                    _suffix, _category = _warning_tags[frame.f_code]
                    category = category or _category
                    message = f"{message} ({_suffix})"
    
                frame = frame.f_back  # type: ignore[assignment]
    
                if not stacklevel_found:
                    stacklevel += 1
                elif stacklevel_found and warning_tag_found:
                    break
    
        if category is not None:
>           warnings.warn(message, category, stacklevel=stacklevel + 1)
E           sqlalchemy.exc.SAWarning: Column-expression-level unary distinct() should not be used outside of an aggregate function. For general 'SELECT DISTINCT' support use select().distinct().

........................................................................................................./app/lib/python3.14.../sqlalchemy/util/langhelpers.py:2099: SAWarning

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

This branch has not been deployed

No deployments
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.

1 participant