diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 685ed3a97b..b5bad323dc 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -104,7 +104,7 @@ jobs: - name: "Install packages" run: | sudo apt-get -y update - sudo apt-get -y --no-install-recommends install python3-behave diffstat diffutils python3 python3-cryptography python3-pip python3-rpm python3-setuptools python3-urllib3 + sudo apt-get -y --no-install-recommends install python3-behave diffstat diffutils python3 python3-cryptography python3-pip python3-rpm python3-setuptools python3-typeguard python3-urllib3 - name: "Checkout sources" uses: actions/checkout@v3 diff --git a/contrib/osc.spec b/contrib/osc.spec index 95ef97aa1a..1a1e3eb354 100644 --- a/contrib/osc.spec +++ b/contrib/osc.spec @@ -30,6 +30,13 @@ %bcond_with fdupes %endif +# use typeguard during build on distros where typeguard is available +%if (0%{?suse_version} > 1500 || 0%{?fedora} >= 37) +%bcond_without typeguard +%else +%bcond_with typeguard +%endif + %define argparse_manpage_pkg argparse-manpage %define obs_build_pkg obs-build %define openssh_pkg openssh @@ -68,6 +75,9 @@ BuildRequires: %{use_python_pkg}-cryptography BuildRequires: %{use_python_pkg}-devel >= 3.6 BuildRequires: %{use_python_pkg}-rpm BuildRequires: %{use_python_pkg}-setuptools +%if %{with typeguard} +BuildRequires: %{use_python_pkg}-typeguard +%endif BuildRequires: %{use_python_pkg}-urllib3 BuildRequires: diffstat %if %{with fdupes} diff --git a/osc-wrapper.py b/osc-wrapper.py index 952f69cf62..3411a4af5a 100755 --- a/osc-wrapper.py +++ b/osc-wrapper.py @@ -4,6 +4,28 @@ This wrapper allows osc to be called from the source directory during development. """ + +# developers and early adopters have typeguard enabled +# so they can catch and report issues early +try: + from typeguard import install_import_hook +except ImportError: + install_import_hook = None + +if install_import_hook is None: + try: + from typeguard.importhook import install_import_hook + except ImportError: + install_import_hook = None + +if install_import_hook: + # install typeguard import hook only if available + install_import_hook("osc") +else: + import osc.oscerr + raise osc.oscerr.PackageNotInstalled("python3-typeguard") + + import osc.babysitter osc.babysitter.main() diff --git a/osc/commandline.py b/osc/commandline.py index f488794e6d..1e8d027976 100644 --- a/osc/commandline.py +++ b/osc/commandline.py @@ -584,10 +584,10 @@ def pop_args( args, arg1_name: str = None, arg1_is_optional: bool = False, - arg1_default: str = None, + arg1_default: Optional[str] = None, arg2_name: str = None, arg2_is_optional: bool = False, - arg2_default: str = None, + arg2_default: Optional[str] = None, ): """ Pop 2 arguments from `args`. @@ -658,9 +658,9 @@ def pop_args( def pop_project_package_from_args( args: List[str], project_is_optional: bool = False, - default_project: str = None, + default_project: Optional[str] = None, package_is_optional: bool = False, - default_package: str = None, + default_package: Optional[str] = None, ): """ Pop project and package from given `args`. @@ -729,9 +729,9 @@ def pop_project_package_from_args( def pop_repository_arch_from_args( args: List[str], repository_is_optional: bool = False, - default_repository: str = None, + default_repository: Optional[str] = None, arch_is_optional: bool = False, - default_arch: str = None, + default_arch: Optional[str] = None, ): """ Pop repository and arch from given `args`. @@ -768,13 +768,13 @@ def pop_repository_arch_from_args( def pop_project_package_repository_arch_from_args( args: List[str], project_is_optional: bool = False, - default_project: str = None, + default_project: Optional[str] = None, package_is_optional: bool = False, - default_package: str = None, + default_package: Optional[str] = None, repository_is_optional: bool = False, - default_repository: str = None, + default_repository: Optional[str] = None, arch_is_optional: bool = False, - default_arch: str = None, + default_arch: Optional[str] = None, ): """ Pop project, package, repository and arch from given `args`. @@ -854,13 +854,13 @@ def pop_project_package_repository_arch_from_args( def pop_project_package_targetproject_targetpackage_from_args( args: List[str], project_is_optional: bool = False, - default_project: str = None, + default_project: Optional[str] = None, package_is_optional: bool = False, - default_package: str = None, + default_package: Optional[str] = None, target_project_is_optional: bool = False, - default_target_project: str = None, + default_target_project: Optional[str] = None, target_package_is_optional: bool = False, - default_target_package: str = None, + default_target_package: Optional[str] = None, ): """ Pop project, package, target project and target package from given `args`. diff --git a/osc/core.py b/osc/core.py index a9bb3b6801..19809b44be 100644 --- a/osc/core.py +++ b/osc/core.py @@ -1192,7 +1192,7 @@ def __str__(self): @staticmethod def init_project( apiurl: str, - dir: Path, + dir: str, project, package_tracking=True, getPackageList=True, @@ -2176,7 +2176,7 @@ def status(self, n): return state - def get_diff(self, revision=None, ignoreUnversioned=False): + def get_diff(self, revision: Optional[int] = None, ignoreUnversioned=False): diff_hdr = b'Index: %s\n' diff_hdr += b'===================================================================\n' kept = [] @@ -2274,7 +2274,7 @@ def diff_add_delete(fname, add, revision): continue elif state == ' ' and revision is None: continue - elif not revision_is_empty(revision) and self.findfilebyname(f.name).md5 == f.md5 and state != 'M': + elif not revision_is_empty(revision) and self.findfilebyname(f.name).md5 == f.md5 and state != "M": continue yield [diff_hdr % f.name.encode()] if revision is None: @@ -3739,7 +3739,7 @@ def meta_get_project_list(apiurl: str, deleted=False): return sorted(node.get('name') for node in root if node.get('name')) -def show_project_meta(apiurl: str, prj: str, rev=None, blame=None): +def show_project_meta(apiurl: str, prj: str, rev: Optional[int] = None, blame=None): query = {} if blame: query['view'] = "blame" @@ -3766,7 +3766,7 @@ def show_project_meta(apiurl: str, prj: str, rev=None, blame=None): return f.readlines() -def show_project_conf(apiurl: str, prj: str, rev=None, blame=None): +def show_project_conf(apiurl: str, prj: str, rev: Optional[int] = None, blame=None): query = {} url = None if not revision_is_empty(rev): @@ -4196,7 +4196,7 @@ def show_files_meta( apiurl: str, prj: str, pac: str, - revision=None, + revision: Optional[int] = None, expand=False, linkrev=None, linkrepair=False, @@ -4843,7 +4843,7 @@ def get_request_collection( package=None, states=None, review_states=None, - types: List[str] = None, + types: Optional[List[str]] = None, ids=None, withfullhistory=False ): @@ -5388,10 +5388,10 @@ def server_diff( apiurl: str, old_project: str, old_package: str, - old_revision: str, + old_revision: Optional[str], new_project: str, new_package: str, - new_revision: str, + new_revision: Optional[str], unified=False, missingok=False, meta=False, @@ -5399,7 +5399,7 @@ def server_diff( onlyissues=False, full=True, xml=False, - files: list = None, + files: Optional[list] = None, ): query: Dict[str, Union[str, int]] = {"cmd": "diff"} if expand: @@ -5454,17 +5454,17 @@ def server_diff_noex( apiurl: str, old_project: str, old_package: str, - old_revision: str, + old_revision: Optional[str], new_project: str, new_package: str, - new_revision: str, + new_revision: Optional[str], unified=False, missingok=False, meta=False, expand=True, onlyissues=False, xml=False, - files: list = None, + files: Optional[list] = None, ): try: return server_diff(apiurl, @@ -7709,7 +7709,7 @@ def owner( return res -def set_link_rev(apiurl: str, project: str, package: str, revision="", expand=False, msg: str=None): +def set_link_rev(apiurl: str, project: str, package: str, revision="", expand=False, msg: Optional[str] = None): url = makeurl(apiurl, ["source", project, package, "_link"]) try: f = http_GET(url) diff --git a/setup.cfg b/setup.cfg index 0987f75808..713aa2bb3f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -42,6 +42,7 @@ install_requires = cryptography # rpm is not available on pip, install a matching package manually prior installing osc rpm + typeguard urllib3 [options.extras_require] diff --git a/tests/__init__.py b/tests/__init__.py index e69de29bb2..2740d5773f 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -0,0 +1,14 @@ +try: + from typeguard import install_import_hook +except ImportError: + install_import_hook = None + +if not install_import_hook: + try: + from typeguard.importhook import install_import_hook + except ImportError: + install_import_hook = None + +if install_import_hook: + # install typeguard import hook only if available + install_import_hook("osc")