Skip to content

Directory: Exclude all property names from the wtforms setattr loop#2499

Open
Tschuppi81 wants to merge 3 commits into
masterfrom
bugfix/ogc-3195-directory-exclude-read-only-properties-from-wtforms-setattr-loop
Open

Directory: Exclude all property names from the wtforms setattr loop#2499
Tschuppi81 wants to merge 3 commits into
masterfrom
bugfix/ogc-3195-directory-exclude-read-only-properties-from-wtforms-setattr-loop

Conversation

@Tschuppi81
Copy link
Copy Markdown
Contributor

@Tschuppi81 Tschuppi81 commented May 29, 2026

Directory: Exclude all property names from the wtforms setattr loop

TYPE: Bugfix
LINK: ogc-3195

@linear
Copy link
Copy Markdown

linear Bot commented May 29, 2026

OGC-3195

@codecov
Copy link
Copy Markdown

codecov Bot commented May 29, 2026

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
2692 1 2691 17
View the top 1 failed test(s) by shortest run time
tests/onegov/org/test_browser.py::test_browse_directory_coordinates@browser
Stack Traces | 19.3s run time
browser = <tests.shared.browser.ExtendedBrowser object at 0x7f2ed04caea0>
org_app = <tests.onegov.org.conftest.TestOrgApp object at 0x7f2ecb31efd0>

    @pytest.mark.xdist_group(name="browser")
    def test_browse_directory_coordinates(
        browser: ExtendedBrowser,
        org_app: TestOrgApp
    ) -> None:
    
        DirectoryCollection(org_app.session(), type='extended').add(
            title="Restaurants",
            structure="""
                Name *= ___
                Tables = 0..1000
            """,
            configuration="""
                title: '[name]'
                lead: 'Offers [tables] tables'
                order:
                    - name
                display:
                    content:
                        - name
            """,
            meta={
                'enable_map': 'everywhere'
            },
            type='extended'
        )
    
        transaction.commit()
    
        # create two restaurants with two different coordinates
        browser.login_admin()
        browser.visit('/directories/restaurants/+new')
        browser.fill('name', "City Wok")
        browser.fill('tables', "10")
        assert browser.is_element_present_by_css('.add-point-active', wait_time=5)
        browser.execute_script('document.leafletmaps[0].panBy([-100, 100]);')
        browser.find_by_css('.add-point-active').click()
        browser.find_by_text("Speichern").click()
    
        browser.visit('/directories/restaurants/+new')
        browser.fill('name', "City Sushi")
        browser.fill('tables', "20")
        assert browser.is_element_present_by_css('.add-point-active', wait_time=5)
        browser.execute_script('document.leafletmaps[0].panBy([100, -100]);')
        browser.find_by_css('.add-point-active').click()
        browser.find_by_text("Speichern").click()
    
        # make sure the restaurants are visible in the overview
        browser.visit('/directories/restaurants')
        assert "Offers 20 tables" in browser.html
        assert "Offers 10 tables" in browser.html
    
        # as well as their points, which we can toggle
        assert not browser.is_element_present_by_css('.popup-title')
        assert not browser.is_element_present_by_css('.popup-lead')
    
>       browser.find_by_css('.vector-marker')[1].click()

.../onegov/org/test_browser.py:350: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tests/shared/browser.py:63: in click
    self._locator.click()
.............../app/lib/python3.14.../playwright/sync_api/_generated.py:17422: in click
    self._sync(
.............../app/lib/python3.14.../playwright/_impl/_locator.py:163: in click
    return await self._frame._click(self._selector, strict=True, **params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.............../app/lib/python3.14.../playwright/_impl/_frame.py:569: in _click
    await self._channel.send("click", self._timeout, locals_to_params(locals()))
.............../app/lib/python3.14.../playwright/_impl/_connection.py:69: in send
    return await self._connection.wrap_api_call(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <playwright._impl._connection.Connection object at 0x7f2ed6b12a50>
cb = <function Channel.send.<locals>.<lambda> at 0x7f2ec921e8d0>
is_internal = False, title = None

    async def wrap_api_call(
        self, cb: Callable[[], Any], is_internal: bool = False, title: str = None
    ) -> Any:
        if self._api_zone.get():
            return await cb()
        task = asyncio.current_task(self._loop)
        st: List[inspect.FrameInfo] = getattr(
            task, "__pw_stack__", None
        ) or inspect.stack(0)
    
        parsed_st = _extract_stack_trace_information_from_stack(st, is_internal, title)
        self._api_zone.set(parsed_st)
        try:
            return await cb()
        except Exception as error:
>           raise rewrite_error(error, f"{parsed_st['apiName']}: {error}") from None
E           playwright._impl._errors.TimeoutError: Locator.click: Timeout 5000ms exceeded.
E           Call log:
E             - waiting for locator(".vector-marker").nth(1)

.............../app/lib/python3.14.../playwright/_impl/_connection.py:559: TimeoutError

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

@Tschuppi81 Tschuppi81 changed the title Reproduce issue Directory: Exclude all property names from the wtforms setattr loop May 29, 2026
@Tschuppi81 Tschuppi81 requested a review from Copilot May 29, 2026 13:26
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes an AttributeError that occurred when a directory structure defined a field whose normalized id collided with a Python property defined on DirectoryEntry (e.g. text, values, external_link). Previously, only SQLAlchemy InstrumentedAttributes were excluded from the wtforms populate_obj setattr loop; properties (often read-only) were not, leading to errors when wtforms tried to assign to them.

Changes:

  • Include property in addition to InstrumentedAttribute when computing the exclude set in DirectoryEntryForm.populate_obj.
  • Add a regression test covering field names that collide with DirectoryEntry properties.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/onegov/directory/models/directory.py Also exclude property attributes from wtforms populate_obj to avoid setting read-only properties.
tests/onegov/directory/test_orm.py New regression test verifying directory fields named after DirectoryEntry properties work end-to-end.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

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