Skip to content

Enable ANN (flake8-annotations) ruleset and fix violations#1371

Open
Sherwin-14 wants to merge 2 commits into
earthaccess-dev:mainfrom
Sherwin-14:ANN
Open

Enable ANN (flake8-annotations) ruleset and fix violations#1371
Sherwin-14 wants to merge 2 commits into
earthaccess-dev:mainfrom
Sherwin-14:ANN

Conversation

@Sherwin-14

@Sherwin-14 Sherwin-14 commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Fixed errors and violations as a result of enabling ANN rulesets. Related to #383.


📚 Documentation preview 📚: https://earthaccess--1371.org.readthedocs.build/en/1371/

@github-actions

github-actions Bot commented Jun 27, 2026

Copy link
Copy Markdown

Binder 👈 Launch a binder notebook on this branch for commit ed3c02f

I will automatically update this comment whenever this PR is modified

Binder 👈 Launch a binder notebook on this branch for commit 9af951e

Binder 👈 Launch a binder notebook on this branch for commit 3846b5e

Binder 👈 Launch a binder notebook on this branch for commit 9dbdaa6

Binder 👈 Launch a binder notebook on this branch for commit 2541f40

Binder 👈 Launch a binder notebook on this branch for commit 25de6a8

Binder 👈 Launch a binder notebook on this branch for commit ee2c8c7

Binder 👈 Launch a binder notebook on this branch for commit f2063d5

Binder 👈 Launch a binder notebook on this branch for commit 25e320f

Binder 👈 Launch a binder notebook on this branch for commit 99214b5

@Sherwin-14 Sherwin-14 force-pushed the ANN branch 11 times, most recently from f2063d5 to ee2c8c7 Compare June 27, 2026 13:36
@Sherwin-14

Copy link
Copy Markdown
Contributor Author

No clue how to fix the unit test, any ideas?

@mfisher87 mfisher87 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.

I think we need to do more in this PR to actually define some of these types instead of using ignores. Many of them appear to be low-hanging fruit at first glance, but I could be wrong. What do you think?

parser: ParserType,
group: str | None = None,
) -> Any:
) -> Any: # noqa: ANN401

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.

I'd like to fix this one in this PR. I think we can change the ParserType type in earthaccess/virtual/_types.py to be ParserName (and remove | Any there as well), and create a new Parser type which is HDFParser | NetCDF3Parser | KerchunkJSONParser | KerchunkParquetParser. Then this function can accept parser: ParserName | Parser and return Parser. These two new types would need to be kept in sync because Python has no way to dynamically generate string literal types from object names. But it would be better than using Any.

We could then type _parser_map as dict[ParserName, Callable[[], Parser]].

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.

def test_resolve_parser_invalid_string_raises() -> None:
    """resolve_parser raises ValueError and lists valid names in the message."""
    with pytest.raises(ValueError, match="DMRPPParser"):
        resolve_parser("UnknownParser")

This one starts failing, I can delete this yeah?

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.

I need more detail -- is there a type checker error? Or the test fails? What is the error?

I don't think we should delete the test, I'd have to be convinced :)

@Sherwin-14 Sherwin-14 Jul 2, 2026

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.

Sorry was in a bit of a hurry that day..
and yeah, it's a type checker error.

tests/unit/test_virtual.py:196: error: Argument 1 to "resolve_parser" has incompatible type "Literal['UnknownParser']";
expected
"Literal['DMRPPParser', 'HDFParser', 'NetCDF3Parser', 'KerchunkJSONParser', 'KerchunkParquetParser'] | HDFParser | NetCDF3Parser | KerchunkJSONParser | KerchunkParquetParser | DMRPPParser"
 [arg-type]
            resolve_parser("UnknownParser")

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.

I'd say we can type ignore that line. We want to test runtime behavior when the defined input type is violated, and the type checker is getting in the way of that. End-users may not be using a type checker so maybe they could get in this situation in real world usage.

def get_urls_for_parser(
granules: list[earthaccess.DataGranule],
parser: Any,
parser: Any, # noqa: ANN401

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.

We could then also use the Parser type here.

parser: Any,
registry: Any,
parser: Any, # noqa: ANN401
registry: Any, # noqa: ANN401

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.

Based on virtualizarr docs, this should be ObjectStoreRegistry (https://virtualizarr.readthedocs.io/en/stable/api/virtualizarr.html)

Comment thread earthaccess/__init__.py


def __getattr__(name): # type: ignore
def __getattr__(name: str): # noqa: ANN202 # type: ignore

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.

We know the return type here -- Auth | Store | None if I'm reading correctly.

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.

Yeah, but we end up with a cascade of errors if we do that.

~
earthaccess/api.py:530: error: Item Auth? of Auth? | Store? | None? has no attribute "authenticated"  [union-attr]
        if earthaccess.__auth__.authenticated:
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Only solution seems to be to add if not isinstance(..., None) where this error shows up.

@mfisher87 mfisher87 Jul 2, 2026

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.

I read a bit more carefully. Looks like the correct solution is to use typing.overload. If name is "__auth__" then we return an Auth.

@overload
def __getattr__(name: Literal["__auth__"]) -> Auth:
    ...

@overload
def __getattr__(name: Literal["__store__"]) -> Store:
    ...

def __getattr__(name: Literal["__auth__", "__store__"]) -> Auth | Store:  # Or this could be untyped? I don't know what's conventional, but I normally include the type information. The docs show the implementation function as untyped so maybe better to do that.
    # Actual implementation here

(I think we need to do #1004 and eliminate this singleton pattern before 1.0)

Comment thread earthaccess/auth.py
persist: bool = False, # noqa: FBT001, FBT002
system: System | None = None,
) -> Any:
) -> Any: # noqa: ANN401

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.

This should be Auth right? Based on the docstring.

Comment thread earthaccess/store.py
return getattr(proxy, name)

def __reduce_ex__(self, protocol: Any) -> Any:
def __reduce_ex__(self, protocol: Any) -> Any: # noqa: ANN401

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.

This looks like it's a tuple of a callable and a tuple of objects of known types. We can type this!

Comment thread earthaccess/store.py
granule: DataGranule,
auth: Auth,
data: Any,
data: Any, # noqa: ANN401

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.

Is this a file path? As a Path or str?

Comment thread earthaccess/store.py

def make_instance(
cls: Any,
cls: Any, # noqa: ANN401

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.

I think there is a finite list of classes this could be right?

Comment thread earthaccess/store.py
"""Store class to access granules on-prem or in the cloud."""

def __init__(self, auth: Any, pre_authorize: bool = False) -> None: # noqa: FBT001, FBT002
def __init__(self, auth: Any, pre_authorize: bool = False) -> None: # noqa: FBT001, FBT002, ANN401

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.

auth is an Auth, right?

Comment thread pyproject.toml
"*.ipynb" = ["T201", "T203", "N803", "RET504", "ERA001", "PLR2004", "PD002", "PD010", "PD011", "EM", "ARG001", "BLE001", "FBT", "ANN001", "ANN002","ANN003", "ANN201", "ANN202", "ANN204","ANN401",]
"tests/**/*.py" = ["PLR2004", "FBT", "INP001", "ANN001","ANN002","ANN003", "ANN201", "ANN202","ANN204","ANN401"]
"scripts/**/*.py" = ["INP001"]
"stubs/**/*.pyi" = ["ANN401"]

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.

What kind of errors are we seeing with stubs? Our stubs should be well-typed.

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