Skip to content

Commit

Permalink
Types (#575)
Browse files Browse the repository at this point in the history
* Improve some type hints

* Use TypedDict for PyPI metadata
  • Loading branch information
maresb authored Nov 13, 2024
1 parent 0e7db27 commit c3ceb8e
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 35 deletions.
8 changes: 4 additions & 4 deletions grayskull/config.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from dataclasses import dataclass, field
from typing import Dict, List, Optional, Tuple
from typing import Dict, Iterable, List, Optional, Tuple

from grayskull.cli.parser import parse_pkg_name_version
from grayskull.utils import PyVer
Expand Down Expand Up @@ -50,11 +50,11 @@ class Configuration:
missing_deps: set = field(default_factory=set)
extras_require_test: Optional[str] = None
github_release_tag: Optional[str] = None
extras_require_include: Tuple[str] = tuple()
extras_require_exclude: Tuple[str] = tuple()
extras_require_include: Iterable[str] = tuple()
extras_require_exclude: Iterable[str] = tuple()
extras_require_all: bool = False
extras_require_split: bool = False
licence_exclude_folders: Tuple[str] = tuple()
licence_exclude_folders: Iterable[str] = tuple()

def get_oldest_py3_version(self, list_py_ver: List[PyVer]) -> PyVer:
list_py_ver = sorted(list_py_ver)
Expand Down
6 changes: 3 additions & 3 deletions grayskull/license/discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ def search_license_file(
git_url: str | None = None,
version: str | None = None,
license_name_metadata: str | None = None,
folders_exclude_search: tuple[str] = tuple(),
folders_exclude_search: tuple[str, ...] = tuple(),
) -> list[ShortLicense]:
"""Search for the license file. First it will try to find it in the given
folder, after that it will search on the github api and for the last it will
Expand Down Expand Up @@ -334,7 +334,7 @@ def _get_api_github_url(github_url: str, version: str | None = None) -> str:
def search_license_folder(
path: str | Path,
default: str | None = None,
folders_exclude_search: tuple[str] = tuple(),
folders_exclude_search: tuple[str, ...] = tuple(),
) -> list[ShortLicense]:
"""Search for the license in the given folder
Expand Down Expand Up @@ -369,7 +369,7 @@ def search_license_repo(
git_url: str,
version: str | None,
default: str | None = None,
folders_exclude_search: tuple[str] = tuple(),
folders_exclude_search: tuple[str, ...] = tuple(),
) -> list[ShortLicense] | None:
"""Search for the license file in the given github repository
Expand Down
2 changes: 1 addition & 1 deletion grayskull/strategy/cran.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ def get_archive_metadata(path):


def scrap_main_page_cran_find_latest_package(
cran_url: str, pkg_name: str, pkg_version: str
cran_url: str, pkg_name: str, pkg_version: str | None
):
pkg_name = pkg_name.strip().lower()
pkg_version = pkg_version.strip().lower() if pkg_version else None
Expand Down
5 changes: 3 additions & 2 deletions grayskull/strategy/py_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from pathlib import Path
from subprocess import check_output
from tempfile import mkdtemp
from typing import ContextManager
from urllib.parse import urlparse

import requests
Expand Down Expand Up @@ -319,7 +320,7 @@ def get_setup_cfg(source_path: str) -> dict:


@contextmanager
def injection_distutils(folder: str) -> dict:
def injection_distutils(folder: str) -> ContextManager[dict]:
"""This is a bit of "dark magic", please don't do it at home.
It is injecting code in the distutils.core.setup and replacing the
setup function by the inner function __fake_distutils_setup.
Expand Down Expand Up @@ -836,7 +837,7 @@ def split_deps(deps: str) -> list[str]:
return result


def ensure_pep440(pkg: str) -> str:
def ensure_pep440(pkg: str | None) -> str | None:
if not pkg or RE_PEP725_PURL.match(pkg):
return pkg
pkg = pkg.strip()
Expand Down
70 changes: 45 additions & 25 deletions grayskull/strategy/pypi.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
import logging
import os
import re
from collections.abc import Mapping
from pathlib import Path
from tempfile import mkdtemp
from typing import Iterable
from typing import Iterable, MutableMapping, TypedDict

import requests
from colorama import Fore
Expand Down Expand Up @@ -155,7 +154,7 @@ def get_sha256_from_pypi_metadata(pypi_metadata: dict) -> str:
raise AttributeError("Hash information for sdist was not found on PyPi metadata.")


def get_sdist_url_from_pypi(metadata: dict) -> str:
def get_sdist_url_from_pypi(metadata: dict) -> str | None:
"""Return the sdist url looking for the pypi metadata
:param metadata: pypi metadata
Expand Down Expand Up @@ -241,7 +240,27 @@ def get_origin_wise_metadata(config):
return sdist_metadata, pypi_metadata


def get_pypi_metadata(config: Configuration) -> dict:
class SourceSection(TypedDict):
url: str
sha256: str


class PypiMetadata(TypedDict):
name: str
version: str
requires_dist: list[str]
requires_python: str | None
summary: str | None
project_urls: dict[str, str]
doc_url: str | None
dev_url: str | None
url: str | None
license: str | None
source: SourceSection
sdist_url: str


def get_pypi_metadata(config: Configuration) -> PypiMetadata:
"""Method responsible to communicate with the pypi api endpoints and
get the whole metadata available for the specified package and version.
Expand Down Expand Up @@ -278,24 +297,25 @@ def get_pypi_metadata(config: Configuration) -> dict:
sdist_url = get_sdist_url_from_pypi(metadata)
if sdist_url is None:
raise AttributeError(f"There is no sdist package on pypi for {config.name}.")
return {
"name": config.name,
"version": info["version"],
"requires_dist": info.get("requires_dist", []),
"requires_python": info.get("requires_python", None),
"summary": info.get("summary"),
"project_urls": info.get("project_urls") or info.get("project_url"),
"doc_url": info.get("docs_url"),
"dev_url": project_urls.get("Source"),
"url": info.get("home_page"),
"license": info.get("license"),
"source": {
"url": config.url_pypi + "/packages/source/{{ name[0] }}/{{ name }}/"
f"{get_url_filename(metadata)}",
"sha256": get_sha256_from_pypi_metadata(metadata),
},
"sdist_url": sdist_url,
}
return PypiMetadata(
name=config.name,
version=info["version"],
requires_dist=info.get("requires_dist", []),
requires_python=info.get("requires_python"),
summary=info.get("summary"),
project_urls=info.get("project_urls") or info.get("project_url", {}),
doc_url=info.get("docs_url"),
dev_url=project_urls.get("Source"),
url=info.get("home_page"),
license=info.get("license"),
source=SourceSection(
url=config.url_pypi
+ "/packages/source/{{ name[0] }}/{{ name }}/"
+ get_url_filename(metadata),
sha256=get_sha256_from_pypi_metadata(metadata),
),
sdist_url=sdist_url,
)


def get_run_req_from_requires_dist(requires_dist: list, config: Configuration) -> list:
Expand Down Expand Up @@ -489,9 +509,9 @@ def get_metadata(recipe, config) -> dict:
}


def remove_all_inner_nones(metadata: dict) -> dict:
def remove_all_inner_nones(metadata):
"""Remove all inner None values from a dictionary."""
if not isinstance(metadata, Mapping):
if not isinstance(metadata, MutableMapping):
return metadata
for k, v in metadata.items():
if not isinstance(v, list):
Expand All @@ -500,7 +520,7 @@ def remove_all_inner_nones(metadata: dict) -> dict:
return metadata


def update_recipe(recipe: Recipe, config: Configuration, all_sections: list[str]):
def update_recipe(recipe: Recipe, config: Configuration, all_sections: Iterable[str]):
"""Update one specific section."""
from souschef.section import Section

Expand Down

0 comments on commit c3ceb8e

Please sign in to comment.