Skip to content

Commit

Permalink
Support 202404
Browse files Browse the repository at this point in the history
Fixes issue with automatic resolving of unique constraint errors (#85)
  • Loading branch information
20c-ed authored and vegu committed May 20, 2024
1 parent b9495b9 commit d81229b
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 16 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@


## Unreleased
### Fixed
- fixes automatic solving of unique constraint errors (#85)


## 2.0.0
Expand Down
3 changes: 2 additions & 1 deletion CHANGELOG.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
Unreleased:
added: []
fixed: []
fixed:
- fixes automatic solving of unique constraint errors (#85)
changed: []
deprecated: []
removed: []
Expand Down
17 changes: 11 additions & 6 deletions src/peeringdb/_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,13 +244,18 @@ def update_one(self, res, pk: int, depth=0):
:param depth: Depth of recursion
:return:
"""
self.fetcher.load(res.tag, 0)
row = self.fetcher.get(res.tag, pk, depth=depth)
obj, ret = self.create_obj(row, res)
if ret:
if depth != 0:
# no longer relevant, deprecation warning
self._log.warning(

Check warning on line 249 in src/peeringdb/_update.py

View check run for this annotation

Codecov / codecov/patch

src/peeringdb/_update.py#L249

Added line #L249 was not covered by tests
"update_one: depth parameter is not used and will be removed in a future version"
)

row = self.fetcher.get(res.tag, pk, depth=0, force_fetch=True)
try:
obj, _ = self.create_obj(row, res)
self.copy_object(obj)
except self.backend.object_missing_error(self.backend.get_concrete(res)):
obj, _ = self.create_obj(row, res)
if obj:
self.clean_obj(obj)
self.backend.save(obj)

def update_collision(self, res, row: dict, exc: Exception):
Expand Down
5 changes: 3 additions & 2 deletions src/peeringdb/fetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,15 @@ def entries(self, tag: str):
self.load(tag)
return self.resources[tag]

def get(self, tag: str, pk: int, depth: int = 0):
def get(self, tag: str, pk: int, depth: int = 0, force_fetch: bool = False):
"""
Get an individual object or attempt to query
:param tag: Resource tag (i.e. "net")
:param pk: Primary key
:param depth: Depth of related objects to fetch
:param force_fetch: Force a fetch from the API
"""
if tag not in self.resources:
if tag not in self.resources or force_fetch:
objs = self._get(tag, since=1, id=pk, depth=depth)
if len(objs) > 0:
return objs[0]
Expand Down
40 changes: 33 additions & 7 deletions tests/test_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,6 @@ def test_single(client_empty):
assert client.get(Organization, FIRST_NET)


def test_single_deep(client_empty):
client = get_pclient()
client.updater.update_one(Network, FIRST_NET, depth=2)
assert client.get(Network, FIRST_NET)
assert client.get(Organization, FIRST_NET)


# Test sync where update would result in a duplicate field
# Test data should include: swapped case; deleted case
def test_nonunique(client_dup):
Expand Down Expand Up @@ -96,6 +89,39 @@ def test_nonunique_single(client_dup):
assert client.get(Network, FIRST_NET)


def test_auto_resolve_unique_conflict(client_empty):
# first load all entries
client = get_client()
rs = all_resources()
client.updater.update_all(rs)

# then manually change name of network with id 3
net = client.get(Network, 3)

net_3_remote_name = net.name

net.name = "placeholder"
client.updater.backend.save(net)

# then manually change name of network with id 1
# to the same name as network with id 3 creating
# a conflict

net = client.get(Network, 1)
net.name = net_3_remote_name
client.updater.backend.save(net)

class DummyUniqueException:
error_dict = {"name": "already exists"}

row = client.fetcher._get("net", id=3)[0]
client.updater.update_collision(Network, row, DummyUniqueException())

# check if the conflict was resolved
net = client.get(Network, 1)
assert net.name != net_3_remote_name


@pytest.mark.sync
def test_auth(client_empty):
with pytest.raises(ValueError):
Expand Down

0 comments on commit d81229b

Please sign in to comment.