Skip to content

StaticFetcher() Implementation + from_pdb() refactor - #5436

Open
jauy123 wants to merge 95 commits into
MDAnalysis:developfrom
jauy123:Fetcher_Class
Open

StaticFetcher() Implementation + from_pdb() refactor#5436
jauy123 wants to merge 95 commits into
MDAnalysis:developfrom
jauy123:Fetcher_Class

Conversation

@jauy123

@jauy123 jauy123 commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Fixes #5429 and #5431

Changes made in this Pull Request:

  • Implements fetch.fetchers.StaticFetcher()
  • Refactors fetch.pdb.from_pdb() to use StaticFetchers()

LLM / AI generated code disclosure

LLMs or other AI-powered tools (beyond simple IDE use cases) were used in this contribution: yes / no
From comment: #5436 (comment)

Per AI policy, I'm declaring that I used in AI in primary two ways: IDE autocomplete and help with reviewing the docstring used for the documentation to make it look more professional.

The one notable exception is that I used AI to help me draft test_multiple_downloads_existing_database and test_existing_database in testsuite/MDAnalysisTests/fetch/test_static_fetcher.py

I prompt is "Is there a unique way to determine the hash in order if two files are exactly the same including modification time in python using the standard library"

It gave code that used os.stat(), so I googled it and found pathlib.Path.stat().st_mtime in the official [docs](https://docs.python.org/3/library/pathlib.html#pathlib.Path.stat) which I then used manually for test_existing_database and test_multiple_downloads_existing_database with no AI.

PR Checklist

  • Issue raised/referenced?
  • Tests updated/added?
  • Documentation updated/added?
  • package/CHANGELOG file updated?
  • Is your name in package/AUTHORS? (If it is not, add it!)
  • LLM/AI disclosure was updated.

Developers Certificate of Origin

I certify that I can submit this code contribution as described in the Developer Certificate of Origin, under the MDAnalysis LICENSE.

Copilot AI review requested due to automatic review settings July 24, 2026 22:02

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a new MDAnalysis.fetch.fetchers.StaticFetcher abstraction for downloading/caching files via pooch, and refactors MDAnalysis.fetch.pdb.from_PDB() to use this new fetcher as its backend.

Changes:

  • Adds StaticFetcher implementation with registry read/write/append helpers.
  • Refactors from_PDB() to delegate downloads to StaticFetcher.
  • Adds/updates tests and Sphinx module docs for the new fetcher module.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
testsuite/MDAnalysisTests/fetch/test_static_fetcher.py New test coverage for StaticFetcher behavior and error cases.
testsuite/MDAnalysisTests/fetch/test_from_PDB.py Updates from_PDB() tests for the refactored implementation.
testsuite/MDAnalysisTests/fetch/servers.py Adds a local HTTP server helper for fetcher tests.
package/MDAnalysis/fetch/pdb.py Refactors from_PDB() to use StaticFetcher and renames supported-format constant.
package/MDAnalysis/fetch/fetchers.py Adds the StaticFetcher implementation and supporting utilities/constants.
package/MDAnalysis/fetch/init.py Exposes StaticFetcher via package imports (but needs __all__ alignment).
package/doc/sphinx/source/documentation_pages/fetchers/fetchers.rst Adds Sphinx automodule page for MDAnalysis.fetch.fetchers.
package/doc/sphinx/source/documentation_pages/fetchers_modules.rst Registers the new fetchers documentation page in the module index.
.gitignore Adds ignores for local scripts (should be reverted/clarified).
Comments suppressed due to low confidence (2)

package/MDAnalysis/fetch/init.py:41

  • __all__ does not include StaticFetcher, but the module imports it, so from MDAnalysis.fetch import * will not export the new public symbol consistently.
__all__ = ["from_PDB"]

from .pdb import from_PDB
from .fetchers import StaticFetcher

package/MDAnalysis/fetch/fetchers.py:633

  • In _set_downloader(), when downloader="auto" and base_url doesn't match the regex (or is missing a scheme), _downloader is never set, leading to UnboundLocalError. Also, there is no default case for unsupported schemes, so the function can silently return None.
        # Regex matching if downloader is set to auto
        if downloader == "auto":
            regex = r"^([^:]+):"
            match = re.match(regex, base_url)

            if match:
                _downloader = match.group(1)

        else:
            _downloader = downloader

        match _downloader:
            case "http" | "https":
                return pooch.HTTPDownloader(**kwargs)
            case "ftp":
                return pooch.FTPDownloader(**kwargs)
            case "sftp":
                return pooch.SFTPDownloader(**kwargs)
            case "doi":
                return pooch.DOIDownloader(**kwargs)


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

Comment thread package/MDAnalysis/fetch/pdb.py Outdated
Comment thread package/MDAnalysis/fetch/fetchers.py
Comment thread package/MDAnalysis/fetch/fetchers.py
Comment on lines +326 to +328
if APPEND_DATABASE and LOAD_FROM_CACHE:
self.append_registry(db_path, requested_files)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is currently intentional. Should it be changed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Sleeping on it, I think the best behavior would have like an argument that making it so that the function appends to the registry unconditionally.

The default behavior should be the registry is not appended if there is a duplicate.

Comment thread package/MDAnalysis/fetch/fetchers.py Outdated
Comment thread testsuite/MDAnalysisTests/fetch/servers.py Outdated
Comment on lines +24 to +30
import re
from pathlib import Path
from shutil import rmtree

from servers import temporary_http_server

import hashlib

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.

Can you use

from .servers import temporary_http_server

?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This breaks testsuite/MDAnalysisTests/utils/test_imports.py

Comment thread testsuite/MDAnalysisTests/fetch/test_from_PDB.py Outdated
Comment thread package/MDAnalysis/fetch/fetchers.py Outdated
Comment thread package/MDAnalysis/fetch/fetchers.py
@jauy123

jauy123 commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

I have no idea what trigger copilot on this. I didn't turn on anything

Copilot AI review requested due to automatic review settings July 24, 2026 22:31
@orbeckst

Copy link
Copy Markdown
Member

@jauy123 , the copilot reviews are currently enabled to automatically occur on all PRs. I am not sure if that was intentional or just a setting changed on GitHub. If you (or anyone else) wants to jump into a discussion, I posted on discord #developers https://discord.com/channels/807348386012987462/808088023957897258/1530342254256979978

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 9 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (3)

testsuite/MDAnalysisTests/fetch/test_static_fetcher.py:28

  • from servers import ... is likely to fail under pytest because the test root is on sys.path, not this subdirectory, so servers.py may not be importable as the top-level module name servers. Import it via the MDAnalysisTests package namespace to make the test import robust.
from servers import temporary_http_server

testsuite/MDAnalysisTests/fetch/servers.py:55

  • The test HTTP server binds to a fixed port (7123). This can cause spurious failures when the port is already in use (or when tests run in parallel). Binding to port 0 lets the OS pick a free ephemeral port.
        server = ThreadingHTTPServer(("127.0.0.1", 7123), http_handler)

package/MDAnalysis/fetch/pdb.py:163

  • from_PDB(..., progressbar=...) forwards progressbar into StaticFetcher.fetch() as an unknown kwarg. StaticFetcher.fetch() currently forwards unknown kwargs into the downloader constructor, which will likely raise a TypeError (e.g., HTTPDownloader(..., progressbar=...)). Pass this through the existing verbose parameter instead.
    return fetcher.fetch(
        file_name=_pdb_ids,
        base_url="https://files.wwpdb.org/download/",
        progressbar=progressbar,
    )

Comment on lines +40 to +51
if HAS_POOCH:
import pooch

REGISTRY_NAME = "hashes.txt"


@pytest.fixture()
def clean_up_default_cache():
rmtree(pooch.os_cache(DEFAULT_CACHE_NAME_DOWNLOADER), ignore_errors=True)
yield
rmtree(pooch.os_cache(DEFAULT_CACHE_NAME_DOWNLOADER), ignore_errors=True)

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.

fair comment!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Indeed, a fair comment.

However, by design, this fixture exists to test the StaticFetcher().fetch(cache_path=None) argument which is guarded by requiring pooch to run the corresponding test. All the other tests uses the tmp_path fixture instead.

So the NameError should never run in this case.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

To make it more obvious, I can add a guard saying that pooch is required for clean_up_default_cache()

Comment thread testsuite/MDAnalysisTests/fetch/servers.py
Comment thread package/MDAnalysis/fetch/__init__.py
Comment thread package/MDAnalysis/fetch/fetchers.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fetcher GSoC GSoC project

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[GSoC 2026] Implementation of Static Fetcher

5 participants