Skip to content

adding stubs for passpy API - #6651

Merged
JelleZijlstra merged 5 commits into
python:masterfrom
Kevin-Gruber:passpy-api
Dec 22, 2021
Merged

JelleZijlstra merged 5 commits into
python:masterfrom
Kevin-Gruber:passpy-api

Conversation

@Kevin-Gruber

Copy link
Copy Markdown
Contributor

adding stubs for passpy: https://pypi.org/project/passpy/

I had to replace re.Match by Any for python 3.6 compatibility. I'm not sure this is the right way to do this.

@JelleZijlstra

Copy link
Copy Markdown
Member

You can just use typing.Match.

Following recommendations from JelleZijlstra.
@Kevin-Gruber

Kevin-Gruber commented Dec 21, 2021

Copy link
Copy Markdown
Contributor Author

How nice. This looks better already.

Thanks.

Comment thread stubs/passpy/passpy/store.pyi Outdated
) -> None: ...
def __iter__(self) -> Iterator[str]: ...
def is_init(self) -> bool: ...
def init_store(self, gpg_ids: Iterable[str], path: str | None = ...) -> None: ...

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.

The code has

        # Ensure that gpg_ids is a list so that the later .join does
        # not accidentally join single letters of a string.
        if gpg_ids is not None and not isinstance(gpg_ids, list):
            gpg_ids = [gpg_ids]

So I think it can be None, str, or list[str], but not any Iterable.

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

Thanks! I have a couple of comments in addition to the inline ones:

  • passpy.util.gen_password also seems to be public, could you add it?
  • I think many of the path argument should work with any PathLike object, because they just get passed to os.path. You could use _typeshed.StrPath to annotate them.
  • I noticed you use Mapping and Iterable for some return types even though the implementation uses concrete types like dict and list. We generally prefer using concrete types in return annotations.

Comment thread stubs/passpy/passpy/store.pyi Outdated
def is_init(self) -> bool: ...
def init_store(self, gpg_ids: Iterable[str], path: str | None = ...) -> None: ...
def init_git(self) -> None: ...
def git(self, method: str, *args: Iterable[object], **kwargs: Mapping[str, object]) -> None: ...

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.

Suggested change
def git(self, method: str, *args: Iterable[object], **kwargs: Mapping[str, object]) -> None: ...
def git(self, method: str, *args: object, **kwargs: object) -> None: ...

Annotations on *args and **kwargs refer to individual element, not the whole object.

Comment thread stubs/passpy/passpy/store.pyi Outdated
def init_store(self, gpg_ids: Iterable[str], path: str | None = ...) -> None: ...
def init_git(self) -> None: ...
def git(self, method: str, *args: Iterable[object], **kwargs: Mapping[str, object]) -> None: ...
def get_key(self, path: str) -> str: ...

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.

Suggested change
def get_key(self, path: str) -> str: ...
def get_key(self, path: str | None) -> str | None: ...

It can return None. It may be useful to add an overload to indicate that it only returns None if the argument is None or the empty string.

Comment thread stubs/passpy/passpy/store.pyi Outdated
def init_git(self) -> None: ...
def git(self, method: str, *args: Iterable[object], **kwargs: Mapping[str, object]) -> None: ...
def get_key(self, path: str) -> str: ...
def set_key(self, path: str, key_data: str, force: bool = ...) -> None: ...

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.

Suggested change
def set_key(self, path: str, key_data: str, force: bool = ...) -> None: ...
def set_key(self, path: str | None, key_data: str, force: bool = ...) -> None: ...

This library is really into accepting None everywhere.

Comment thread stubs/passpy/passpy/store.pyi Outdated
def get_key(self, path: str) -> str: ...
def set_key(self, path: str, key_data: str, force: bool = ...) -> None: ...
def remove_path(self, path: str, recursive: bool = ..., force: bool = ...) -> None: ...
def gen_key(self, path: str, length: int, symbols: bool = ..., force: bool = ..., inplace: bool = ...) -> str | None: ...

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.

Suggested change
def gen_key(self, path: str, length: int, symbols: bool = ..., force: bool = ..., inplace: bool = ...) -> str | None: ...
def gen_key(self, path: str | None, length: int, symbols: bool = ..., force: bool = ..., inplace: bool = ...) -> str | None: ...

Comment thread stubs/passpy/passpy/store.pyi Outdated
def copy_path(self, old_path: str, new_path: str, force: bool = ...) -> None: ...
def move_path(self, old_path: str, new_path: str, force: bool = ...) -> None: ...
def list_dir(self, path: str) -> tuple[Iterable[str], Iterable[str]]: ...
def iter_dir(self, path: str) -> None: ...

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.

Suggested change
def iter_dir(self, path: str) -> None: ...
def iter_dir(self, path: str) -> Iterator[str]: ...

It's a generator

Comment thread stubs/passpy/passpy/store.pyi Outdated
def move_path(self, old_path: str, new_path: str, force: bool = ...) -> None: ...
def list_dir(self, path: str) -> tuple[Iterable[str], Iterable[str]]: ...
def iter_dir(self, path: str) -> None: ...
def find(self, names: Iterable[str]) -> Iterable[str]: ...

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.

Suggested change
def find(self, names: Iterable[str]) -> Iterable[str]: ...
def find(self, names: None | str | list[str]) -> list[str]: ...

Another one that does

        if not isinstance(names, list):
            names = [names]

Kevin Gruber added 2 commits December 22, 2021 11:06
 * using _typeshed.StrPath rather that str when possible
 * switching to concrete return types annotations
 * adding passpy.util.gen_password since this can considered part of
   the passpy API
 * fixing additional parameter annotations

references:

 * #6651 (comment)
 * #6651 (review)

acknowledgement:

 * thanks to JelleZijlstra for their review
Co-authored-by: JelleZijlstra
@Kevin-Gruber

Copy link
Copy Markdown
Contributor Author

Okay, I think I addressed all your comments.

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

Just one more thing, thanks! I'll apply the change and then merge this once CI passes.

Comment thread stubs/passpy/passpy/__init__.pyi
@JelleZijlstra
JelleZijlstra merged commit bd0cbf4 into python:master Dec 22, 2021
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