Skip to content

Overwrite policy: an empty value cannot clear a property, and kept pages are reported as stored #190

Description

@LukasGold

Two defects in the selective overwrite feature (OSW.OverwriteClassParam, OSW._apply_overwrite_policy). Both were found during the assessment in #163 and listed there under "Found but not fixed - needs a design decision". Both are still present on main (v2.5.1, 9351f6b).

1. A property cannot be cleared by assigning an empty value

remove_empty=True is the default. It strips "", [] and {} from the local content before the merge:

osw-python/src/osw/core.py

Lines 1567 to 1569 in 9351f6b

local_content["jsondata"] = json.loads(param.entity.json(exclude_none=True))
if param.remove_empty:
remove_empty(local_content["jsondata"])

The merge then starts from the remote content and pulls in only those keys that are still present in the stripped local content:

new_content["jsondata"] = remote_content["jsondata"]

The stored value therefore always survives. A caller who assigns "" to clear a property gets no change and no warning. The only workaround is remove_empty=False for the whole call, which also writes every unrelated empty default.

Expected: an empty value that the caller assigned on purpose clears the stored value, subject to the overwrite setting as usual. An empty value that is merely a field default is still stripped.

2. Pages kept by keep existing are indistinguishable from pages that were written

StoreEntityResult declares change_id, pages and failed:

osw-python/src/osw/core.py

Lines 1707 to 1720 in 9351f6b

class StoreEntityResult(OswBaseModel):
"""Result of store_entity()"""
change_id: str
"""The ID of the change"""
pages: Dict[str, WtPage]
"""The pages that have been successfully stored, keyed by full page title.
On partial failure this contains only the successfully-stored pages."""
failed: Dict[str, Exception] = {}
"""Entities that could not be stored, mapped to the exception that caused the
failure. Empty on full success. The key is the full page title where one could
be determined. For an entity whose title or namespace could not be resolved it
falls back to the entity name, then to its uuid, then to 'unknown', so do not
parse this key as 'namespace:title'."""

A page that exists and is left untouched under keep existing passes the guard at

osw-python/src/osw/core.py

Lines 1913 to 1920 in 9351f6b

kept_existing = (
page.exists
# mirrors the branch order of _apply_overwrite_policy(), which
# tests 'offline is True' before it tests 'keep existing'
and param.offline is not True
and overwrite_class_param.overwrite
== AddOverwriteClassOptions.keep_existing
)

and still enters pages at

created_pages[page.title] = page

The caller cannot tell which entities were written and which were kept. The docstring of pages reads "The pages that have been successfully stored", which does not hold for a kept page.

Expected: kept pages are identifiable, for example through an additional skipped list. Listing them in pages as well is acceptable, because callers that only need the final set of pages on the wiki depend on it.

Status

A fix for both is in #168, which is open and currently conflicting with main.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions