diff --git a/osc/conf.py b/osc/conf.py index 0ac5157d2..fe9295693 100644 --- a/osc/conf.py +++ b/osc/conf.py @@ -60,6 +60,7 @@ import textwrap from io import BytesIO from io import StringIO +from typing import Optional, Tuple from urllib.parse import urlsplit from . import credentials @@ -1571,7 +1572,10 @@ def sanitize_apiurl(apiurl): return urljoin(*parse_apisrv_url(None, apiurl)) -def parse_apisrv_url(scheme, apisrv): +def parse_apisrv_url(scheme: Optional[str], apisrv: str) -> Tuple[str, str, str]: + """ + Parses the api server url ``apisrv`` and returns the tuple (scheme, url, path). + """ if apisrv.startswith('http://') or apisrv.startswith('https://'): url = apisrv elif scheme is not None: @@ -1582,17 +1586,17 @@ def parse_apisrv_url(scheme, apisrv): return scheme, url, path.rstrip('/') -def urljoin(scheme, apisrv, path=''): - return f"{scheme}://{apisrv}" + path +def urljoin(scheme: str, apisrv: str, path: str='') -> str: + return f"{scheme}://{apisrv}{path}" -def is_known_apiurl(url): +def is_known_apiurl(url: str) -> bool: """returns ``True`` if url is a known apiurl""" apiurl = sanitize_apiurl(url) return apiurl in config['api_host_options'] -def extract_known_apiurl(url): +def extract_known_apiurl(url: str) -> Optional[str]: """ Return longest prefix of given url that is known apiurl, None if there is no known apiurl that is prefix of given url. diff --git a/osc/core.py b/osc/core.py index 6b72dae8a..5c70c872c 100644 --- a/osc/core.py +++ b/osc/core.py @@ -28,7 +28,7 @@ from http.client import IncompleteRead from io import StringIO from pathlib import Path -from typing import Optional, Dict, Union, List, Iterable +from typing import TYPE_CHECKING, Any, Optional, Dict, Union, List, Iterable, Tuple, overload from urllib.parse import parse_qs, urlsplit, urlunsplit, urlparse, urlunparse, quote, urlencode, unquote from urllib.error import HTTPError from xml.etree import ElementTree as ET @@ -1335,7 +1335,7 @@ def show_package_trigger_reason(apiurl: str, prj: str, pac: str, repo: str, arch raise -def show_package_meta(apiurl: str, prj: str, pac: str, meta=False, blame=None): +def show_package_meta(apiurl: str, prj: str, pac: str, meta: bool=False, blame=None) -> List[bytes]: query: Dict[str, Union[str, int]] = {} if meta: query['meta'] = 1 @@ -1394,7 +1394,7 @@ def show_scmsync(apiurl, prj, pac=None): return project_obj.scmsync -def show_devel_project(apiurl, prj, pac): +def show_devel_project(apiurl: str, prj: str, pac: str) -> Tuple[Optional[str], Optional[str]]: from . import obs_api package_obj = obs_api.Package.from_api(apiurl, prj, pac) @@ -1521,7 +1521,7 @@ def is_force_supported(self): def __call__(self, **kwargs): return self._delegate(**kwargs) - def __init__(self, url, input, change_is_required=False, file_ext='.xml', method=None): + def __init__(self, url, input: Union[List[str], str, bytes, List[bytes]], change_is_required=False, file_ext='.xml', method=None): if isinstance(url, self._URLFactory): self._url_factory = url else: @@ -1608,8 +1608,20 @@ def discard(self): os.unlink(self.filename) +if TYPE_CHECKING: + from typing import Literal, TypedDict + + MetaType = Literal['prj', 'pkg', 'attribute', 'prjconf', 'user', 'group', 'pattern'] + + class _MetaType(TypedDict): + path: str + template: str + file_ext: str + + # different types of metadata -metatypes = {'prj': {'path': 'source/%s/_meta', +metatypes: "Dict[MetaType, _MetaType]" = { + 'prj': {'path': 'source/%s/_meta', 'template': new_project_templ, 'file_ext': '.xml' }, @@ -1640,7 +1652,7 @@ def discard(self): } -def meta_exists(metatype: str, path_args=None, template_args=None, create_new=True, apiurl=None): +def meta_exists(metatype: "MetaType", path_args=None, template_args=None, create_new=True, apiurl=None): global metatypes @@ -1661,7 +1673,7 @@ def meta_exists(metatype: str, path_args=None, template_args=None, create_new=Tr def make_meta_url( - metatype: str, + metatype: "MetaType", path_args=None, apiurl: Optional[str] = None, force=False, @@ -1704,7 +1716,7 @@ def parse_meta_to_string(data: Union[bytes, list, Iterable]) -> str: def edit_meta( - metatype, + metatype: "MetaType", path_args=None, data: Optional[List[str]] = None, template_args=None, @@ -3684,6 +3696,7 @@ def attribute_branch_pkg( return r +@overload def branch_pkg( apiurl: str, src_project: str, @@ -3705,7 +3718,54 @@ def branch_pkg( maintenance=False, newinstance=False, disable_build=False, -): +) -> Tuple[False, Optional[str], Optional[str], Optional[str], Optional[str]]: ... + +@overload +def branch_pkg( + apiurl: str, + src_project: str, + src_package: str, + nodevelproject=False, + rev=None, + linkrev=None, + target_project: Optional[str] = None, + target_package=None, + return_existing=True, + msg="", + force=False, + noaccess=False, + add_repositories=False, + add_repositories_block=None, + add_repositories_rebuild=None, + extend_package_names=False, + missingok=False, + maintenance=False, + newinstance=False, + disable_build=False, +) -> Union[Tuple[True, str, str, None, None], Tuple[False, Optional[str], Optional[str], Optional[str], Optional[str]]]: ... + +def branch_pkg( + apiurl: str, + src_project: str, + src_package: str, + nodevelproject=False, + rev=None, + linkrev=None, + target_project: Optional[str] = None, + target_package=None, + return_existing=False, + msg="", + force=False, + noaccess=False, + add_repositories=False, + add_repositories_block=None, + add_repositories_rebuild=None, + extend_package_names=False, + missingok=False, + maintenance=False, + newinstance=False, + disable_build=False, +) -> Union[Tuple[True, str, str, None, None], Tuple[False, Optional[str], Optional[str], Optional[str], Optional[str]]]: """ Branch a package (via API call) """