Skip to content

fix(client): persist file metadata on the second _update_state call - #358

Merged
luabida merged 2 commits into
AlertaDengue:mainfrom
devgtv:fix/client-update-state
Oct 1, 2026
Merged

luabida merged 2 commits into
AlertaDengue:mainfrom
devgtv:fix/client-update-state

Conversation

@devgtv

@devgtv devgtv commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

Summary

download() records a file twice: once as DOWNLOADING with no metadata, then as COMPLETED with the year, month, state and group parsed from the remote file. The second call finds the row the first one created and only ever touched status and last_synced:

await p._update_state(p, r, "ftp", DownloadStatus.DOWNLOADING)
await p._update_state(p, r, "ftp", DownloadStatus.COMPLETED,
                      year=2024, month=1, state="SP", group="DC")
# -> (None, None, None, None)

year, month, state and group stayed NULL for every file PySUS had ever downloaded.

Impact

  • all four metadata columns in local_file_state are permanently empty
  • get_local_hierarchy builds its {client: {dataset: {group: [...]}}} tree from group, so the tree was keyed off the wrong level and ungrouped files landed under the client's own name
  • a republished file kept the metadata from its first download forever

Fix

The existing record now takes remote_path and client_name (always supplied positionally), plus year/month/state/group when they are not None.

The None check is load-bearing: the FAILED call in download()'s except block also passes no metadata and must not erase what COMPLETED recorded.

Tests

The existing TestLocalFileState only covered the create path, which is why this was invisible. Added 4 tests reproducing the real two-step sequence: metadata is persisted on the second call, only one row is created, a FAILED call keeps the completed metadata, and stale metadata is refreshed.

All 4 fail against the previous code.

  • 1737 passed, 6 skipped
  • black and isort clean

`download()` records a file twice: once as DOWNLOADING with no
metadata, then as COMPLETED with the year, month, state and group
parsed from the remote file. The second call finds the row the first
one created and only ever touched `status` and `last_synced`, so
`year`, `month`, `state` and `group` stayed NULL:

    >>> await p._update_state(p, r, "ftp", DownloadStatus.DOWNLOADING)
    >>> await p._update_state(p, r, "ftp", DownloadStatus.COMPLETED,
    ...                       year=2024, month=1, state="SP", group="DC")
    >>> r.year, r.month, r.state, r.group
    (None, None, None, None)

Every file PySUS had ever downloaded was missing all four columns, and
`get_local_hierarchy` keys its output off `group`, so the tree came out
wrong as well.

The existing record now takes `remote_path` and `client_name` (always
supplied) plus `year`/`month`/`state`/`group` when they are not None.
The None check matters: the FAILED call in `download()`'s except block
also passes no metadata, and must not erase what COMPLETED recorded.
@codecov-commenter

codecov-commenter commented Sep 30, 2026 •

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (main@3a8d33c). Learn more about missing BASE report.
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #358   +/-   ##
=======================================
  Coverage        ?   97.22%           
=======================================
  Files           ?      180           
  Lines           ?    22790           
  Branches        ?        0           
=======================================
  Hits            ?    22158           
  Misses          ?      632           
  Partials        ?        0           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@luabida luabida left a comment

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.

Please solve the conflicts in order to merge this PR

Resolves the conflict with AlertaDengue#359 (already merged), which appends test
classes to the same two files.

The two fixes touch different regions of pysus/api/client.py and merge
cleanly there.

pysus/tests/api/test_client.py conflicted because AlertaDengue#358 and AlertaDengue#359 both
append at end of file. Beyond concatenating them, this fixes two
problems that AlertaDengue#359 introduced when it merged:

- It defined a second `TestGetLocalHierarchy`, shadowing the existing
  class of the same name, so
  `test_get_local_hierarchy_all_branches` silently stopped being
  collected. It is now `TestGetLocalHierarchyDatasetLevel` and both
  classes run (51 tests in this file, up from 46).

- That existing test asserted the *buggy* output of AlertaDengue#359: it expected a
  grouped file under its group name (`ftp_dict["DC"]`) and an ungrouped
  one under the client name (`ftp_dict["ftp"]`). Its assertions are
  updated to the corrected shape, and tightened: the old ones happened
  to pass partly by coincidence, so it now also pins down the
  directory record, the ungrouped bucket, and that "DC", "ftp" and
  "short" are not dataset keys.
@devgtv

devgtv commented Sep 30, 2026

Copy link
Copy Markdown
Contributor Author

Conflito resolvido — o PR agora está MERGEABLE.

A causa era o #359, que já foi mergeado e mexe nos mesmos dois arquivos. As duas correções em pysus/api/client.py estão em regiões distintas e mesclaram limpas; o conflito ficou só em pysus/tests/api/test_client.py, onde os dois PRs anexam classes no fim do arquivo.

Ao resolver, encontrei dois problemas que o #359 deixou no main e corrigi aqui:

1. Uma classe de teste foi silenciosamente desativada. O #359 definiu um segundo TestGetLocalHierarchy, sombreando a classe existente de mesmo nome. test_get_local_hierarchy_all_branches simplesmente parou de ser coletado — sem falhar, sem aviso. Renomeei a nova para TestGetLocalHierarchyDatasetLevel; as duas rodam agora (51 testes neste arquivo, eram 46).

2. O teste existente afirmava o comportamento incorreto. Ele esperava o arquivo agrupado sob o nome do grupo (ftp_dict["DC"]) e o não-agrupado sob o nome do cliente (ftp_dict["ftp"]) — exatamente o bug que o #359 corrige. As asserções foram atualizadas para a forma correta e apertadas: as antigas passavam partly por coincidência, então agora também fixo o registro de diretório, o bucket não-agrupado, e que "DC", "ftp" e "short" não são chaves de dataset.

Também vale notar que as asserções antigasEncode o bug de um jeito que só passava por acidente: assert "DC" in ftp_dict continua verdadeiro por causa do registro de diretório, não do arquivo agrupado.

  • 1741 passed, 6 skipped
  • black e isort limpos

@lubabida — se preferir, posso abrir isso como um PR separado (só a reparação do teste) e deixar o #358 restrito apenas ao _update_state; é só dizer.

@luabida
luabida merged commit 39bbf8b into AlertaDengue:main Oct 1, 2026
15 checks passed
@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown

🎉 This PR is included in version 2.11.4 🎉

The release is available on:

Your semantic-release bot 📦🚀

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants