diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index efea44b4..0de03222 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -43,6 +43,10 @@ jobs: run: | uv run ruff check jenkinsapi/ --output-format full + - name: Lint with mypy + run: | + uv run mypy || true + build: runs-on: ubuntu-latest strategy: diff --git a/jenkinsapi/artifact.py b/jenkinsapi/artifact.py index 72e73818..76a7809a 100644 --- a/jenkinsapi/artifact.py +++ b/jenkinsapi/artifact.py @@ -14,13 +14,17 @@ import os import logging import hashlib -from typing import Any, Literal +from typing import Any, Literal, TYPE_CHECKING from jenkinsapi.fingerprint import Fingerprint from jenkinsapi.custom_exceptions import ArtifactBroken log = logging.getLogger(__name__) +if TYPE_CHECKING: + from jenkinsapi.build import Build + from jenkinsapi.jenkins import Jenkins + class Artifact(object): """ diff --git a/jenkinsapi/build.py b/jenkinsapi/build.py index 2bde2d43..9de71a16 100644 --- a/jenkinsapi/build.py +++ b/jenkinsapi/build.py @@ -16,7 +16,7 @@ import datetime from time import sleep -from typing import Iterator, List, Dict, Any +from typing import TYPE_CHECKING, Iterator, List, Dict, Any import pytz from jenkinsapi import config @@ -35,6 +35,10 @@ log = logging.getLogger(__name__) +if TYPE_CHECKING: + from jenkinsapi.jenkins import Jenkins + from jenkinsapi.job import Job + class Build(JenkinsBase): """ @@ -238,8 +242,8 @@ def get_upstream_job(self) -> Job | None: Get the upstream job object if it exist, None otherwise :return: Job or None """ - if self.get_upstream_job_name(): - return self.get_jenkins_obj().get_job(self.get_upstream_job_name()) + if name := self.get_upstream_job_name(): + return self.get_jenkins_obj().get_job(name) return None def get_upstream_build_number(self) -> int | None: @@ -278,8 +282,8 @@ def get_master_job(self) -> Job | None: Get the master job object if it exist, None otherwise :return: Job or None """ - if self.get_master_job_name(): - return self.get_jenkins_obj().get_job(self.get_master_job_name()) + if name := self.get_master_job_name(): + return self.get_jenkins_obj().get_job(name) return None diff --git a/jenkinsapi/credential.py b/jenkinsapi/credential.py index b3ae7330..69efa38c 100644 --- a/jenkinsapi/credential.py +++ b/jenkinsapi/credential.py @@ -83,6 +83,9 @@ class UsernamePasswordCredential(Credential): dict """ + username: str + password: str + def __init__(self, cred_dict: dict) -> None: jenkins_class: str = ( "com.cloudbees.plugins.credentials.impl." @@ -92,12 +95,11 @@ def __init__(self, cred_dict: dict) -> None: cred_dict, jenkins_class ) if "typeName" in cred_dict: - username: str = cred_dict["displayName"].split("/")[0] + self.username = cred_dict["displayName"].split("/")[0] else: - username: str = cred_dict["userName"] + self.username = cred_dict["userName"] - self.username: str = username - self.password: str = cred_dict.get("password", "") + self.password = cred_dict.get("password", "") def get_attributes(self): """ @@ -223,26 +225,31 @@ class SSHKeyCredential(Credential): dict """ + username: str + passphrase: str + key_type: int + key_value: str + def __init__(self, cred_dict: dict) -> None: jenkins_class: str = ( "com.cloudbees.jenkins.plugins.sshcredentials.impl." "BasicSSHUserPrivateKey" ) super(SSHKeyCredential, self).__init__(cred_dict, jenkins_class) + if "typeName" in cred_dict: - username: str = cred_dict["displayName"].split(" ")[0] + self.username = cred_dict["displayName"].split(" ")[0] else: - username: str = cred_dict["userName"] + self.username = cred_dict["userName"] - self.username: str = username - self.passphrase: str = cred_dict.get("passphrase", "") + self.passphrase = cred_dict.get("passphrase", "") if "private_key" not in cred_dict or cred_dict["private_key"] is None: - self.key_type: int = -1 - self.key_value: str = "" + self.key_type = -1 + self.key_value = "" elif cred_dict["private_key"].startswith("-"): - self.key_type: int = 0 - self.key_value: str = cred_dict["private_key"] + self.key_type = 0 + self.key_value = cred_dict["private_key"] else: raise ValueError("Invalid private_key value") diff --git a/jenkinsapi/credentials.py b/jenkinsapi/credentials.py index e3953efb..8472de4d 100644 --- a/jenkinsapi/credentials.py +++ b/jenkinsapi/credentials.py @@ -6,7 +6,7 @@ from __future__ import annotations -from typing import Iterator +from typing import TYPE_CHECKING, Iterator, Tuple import logging from urllib.parse import urlencode @@ -20,6 +20,9 @@ log: logging.Logger = logging.getLogger(__name__) +if TYPE_CHECKING: + from jenkinsapi.jenkins import Jenkins + class Credentials(JenkinsBase): """ @@ -65,7 +68,7 @@ def iterkeys(self): def keys(self): return list(self.iterkeys()) - def iteritems(self) -> Iterator[str, "Credential"]: + def iteritems(self) -> Iterator[Tuple[str, "Credential"]]: for cred in self.credentials.values(): yield cred.description, cred diff --git a/jenkinsapi/executor.py b/jenkinsapi/executor.py index 4f691356..c2603d7d 100644 --- a/jenkinsapi/executor.py +++ b/jenkinsapi/executor.py @@ -3,12 +3,16 @@ """ from __future__ import annotations +from typing import TYPE_CHECKING from jenkinsapi.jenkinsbase import JenkinsBase import logging log = logging.getLogger(__name__) +if TYPE_CHECKING: + from jenkinsapi.jenkins import Jenkins + class Executor(JenkinsBase): """ diff --git a/jenkinsapi/executors.py b/jenkinsapi/executors.py index 84f0b6d2..0c36781b 100644 --- a/jenkinsapi/executors.py +++ b/jenkinsapi/executors.py @@ -7,13 +7,16 @@ from __future__ import annotations import logging -from typing import Iterator +from typing import TYPE_CHECKING, Iterator from jenkinsapi.executor import Executor from jenkinsapi.jenkinsbase import JenkinsBase log: logging.Logger = logging.getLogger(__name__) +if TYPE_CHECKING: + from jenkinsapi.jenkins import Jenkins + class Executors(JenkinsBase): """ @@ -27,7 +30,7 @@ def __init__( self, baseurl: str, nodename: str, jenkins: "Jenkins" ) -> None: self.nodename: str = nodename - self.jenkins: str = jenkins + self.jenkins: "Jenkins" = jenkins JenkinsBase.__init__(self, baseurl) self.count: int = self._data["numExecutors"] diff --git a/jenkinsapi/fingerprint.py b/jenkinsapi/fingerprint.py index 2d457cec..48eb6275 100644 --- a/jenkinsapi/fingerprint.py +++ b/jenkinsapi/fingerprint.py @@ -6,7 +6,7 @@ import re import logging -from typing import Any +from typing import TYPE_CHECKING, Any import requests @@ -15,6 +15,9 @@ log: logging.Logger = logging.getLogger(__name__) +if TYPE_CHECKING: + from jenkinsapi.jenkins import Jenkins + class Fingerprint(JenkinsBase): """ diff --git a/jenkinsapi/jenkinsbase.py b/jenkinsapi/jenkinsbase.py index 02eec9f4..bab6f722 100644 --- a/jenkinsapi/jenkinsbase.py +++ b/jenkinsapi/jenkinsbase.py @@ -20,6 +20,8 @@ class JenkinsBase(object): inherited from """ + _data: dict + def __repr__(self): return """<%s.%s %s>""" % ( self.__class__.__module__, diff --git a/jenkinsapi/job.py b/jenkinsapi/job.py index 00df4714..350fc358 100644 --- a/jenkinsapi/job.py +++ b/jenkinsapi/job.py @@ -6,6 +6,7 @@ import json import logging +from typing import TYPE_CHECKING import xml.etree.ElementTree as ET import urllib.parse as urlparse @@ -34,6 +35,9 @@ log = logging.getLogger(__name__) +if TYPE_CHECKING: + from jenkinsapi.jenkins import Jenkins + class Job(JenkinsBase, MutableJenkinsThing): """ diff --git a/jenkinsapi/jobs.py b/jenkinsapi/jobs.py index 5eff7035..b0f87999 100644 --- a/jenkinsapi/jobs.py +++ b/jenkinsapi/jobs.py @@ -5,7 +5,7 @@ from __future__ import annotations -from typing import Iterator +from typing import TYPE_CHECKING, Iterator, Tuple import logging import time @@ -14,6 +14,10 @@ log = logging.getLogger(__name__) +if TYPE_CHECKING: + from jenkinsapi.jenkins import Jenkins + from jenkinsapi.queue import QueueItem + class Jobs(object): """ @@ -94,7 +98,7 @@ def __getitem__(self, job_name: str) -> "Job": else: raise UnknownJob(job_name) - def iteritems(self) -> Iterator[str, "Job"]: + def iteritems(self) -> Iterator[Tuple[str, "Job"]]: """ Iterate over the names & objects for all jobs """ diff --git a/jenkinsapi/node.py b/jenkinsapi/node.py index bf258fb2..0ec21177 100644 --- a/jenkinsapi/node.py +++ b/jenkinsapi/node.py @@ -7,6 +7,7 @@ import json import logging +from typing import TYPE_CHECKING, Optional, Union import xml.etree.ElementTree as ET import time @@ -17,6 +18,9 @@ log = logging.getLogger(__name__) +if TYPE_CHECKING: + from jenkinsapi.jenkins import Jenkins + class Node(JenkinsBase): """ @@ -24,6 +28,8 @@ class Node(JenkinsBase): to the master jenkins instance """ + _element_tree: Optional[ET.Element] + def __init__( self, jenkins_obj: "Jenkins", @@ -117,6 +123,7 @@ def get_node_attributes(self) -> dict: :return: Node attributes dict formatted for Jenkins API request to create node """ + launcher: dict[str, object] na: dict = self.node_attributes if not na.get("credential_description", False): # If credentials description is not present - we will create @@ -372,7 +379,7 @@ def load_config(self) -> None: self._config = self.get_config() self._get_config_element_tree() - def upload_config(self, config_xml: str) -> None: + def upload_config(self, config_xml: Union[str, bytes]) -> None: """ Uploads config_xml to the config.xml for the node. """ @@ -489,7 +496,7 @@ def set_config_element(self, el_name: str, value: str) -> None: xml_str = ET.tostring(self._et) self.upload_config(xml_str) - def get_monitor(self, monitor_name: str, poll_monitor=True) -> str: + def get_monitor(self, monitor_name: str, poll_monitor=True) -> object: """ Polls the node returning one of the monitors in the monitorData branch of the returned node api tree. @@ -507,60 +514,72 @@ def get_monitor(self, monitor_name: str, poll_monitor=True) -> str: return monitor_data[full_monitor_name] + def get_monitor_dict( + self, + monitor_name: str, + poll_monitor: bool = True, + ) -> dict: + value = self.get_monitor(monitor_name, poll_monitor) + if not isinstance(value, dict): + raise JenkinsAPIException( + f"Monitor {monitor_name!r} did not return a dictionary" + ) + return value + def get_available_physical_memory(self) -> int: """ Returns the node's available physical memory in bytes. """ - monitor_data = self.get_monitor("SwapSpaceMonitor") + monitor_data = self.get_monitor_dict("SwapSpaceMonitor") return monitor_data["availablePhysicalMemory"] def get_available_swap_space(self) -> int: """ Returns the node's available swap space in bytes. """ - monitor_data = self.get_monitor("SwapSpaceMonitor") + monitor_data = self.get_monitor_dict("SwapSpaceMonitor") return monitor_data["availableSwapSpace"] def get_total_physical_memory(self) -> int: """ Returns the node's total physical memory in bytes. """ - monitor_data = self.get_monitor("SwapSpaceMonitor") + monitor_data = self.get_monitor_dict("SwapSpaceMonitor") return monitor_data["totalPhysicalMemory"] def get_total_swap_space(self) -> int: """ Returns the node's total swap space in bytes. """ - monitor_data = self.get_monitor("SwapSpaceMonitor") + monitor_data = self.get_monitor_dict("SwapSpaceMonitor") return monitor_data["totalSwapSpace"] def get_workspace_path(self) -> str: """ Returns the local path to the node's Jenkins workspace directory. """ - monitor_data = self.get_monitor("DiskSpaceMonitor") + monitor_data = self.get_monitor_dict("DiskSpaceMonitor") return monitor_data["path"] def get_workspace_size(self) -> int: """ Returns the size in bytes of the node's Jenkins workspace directory. """ - monitor_data = self.get_monitor("DiskSpaceMonitor") + monitor_data = self.get_monitor_dict("DiskSpaceMonitor") return monitor_data["size"] def get_temp_path(self) -> str: """ Returns the local path to the node's temp directory. """ - monitor_data = self.get_monitor("TemporarySpaceMonitor") + monitor_data = self.get_monitor_dict("TemporarySpaceMonitor") return monitor_data["path"] def get_temp_size(self) -> int: """ Returns the size in bytes of the node's temp directory. """ - monitor_data = self.get_monitor("TemporarySpaceMonitor") + monitor_data = self.get_monitor_dict("TemporarySpaceMonitor") return monitor_data["size"] def get_architecture(self) -> str: @@ -568,7 +587,12 @@ def get_architecture(self) -> str: Returns the system architecture of the node eg. "Linux (amd64)". """ # no need to poll as the architecture will never change - return self.get_monitor("ArchitectureMonitor", poll_monitor=False) + value = self.get_monitor("ArchitectureMonitor", poll_monitor=False) + if not isinstance(value, str): + raise JenkinsAPIException( + "Monitor ArchitectureMonitor did not return a string" + ) + return value def block_until_idle(self, timeout: int, poll_time: int = 5) -> None: """ @@ -596,7 +620,7 @@ def get_response_time(self) -> int: """ Returns the node's average response time. """ - monitor_data = self.get_monitor("ResponseTimeMonitor") + monitor_data = self.get_monitor_dict("ResponseTimeMonitor") return monitor_data["average"] def get_clock_difference(self) -> int: @@ -605,5 +629,5 @@ def get_clock_difference(self) -> int: the master Jenkins clock. Used to detect out of sync clocks. """ - monitor_data = self.get_monitor("ClockMonitor") + monitor_data = self.get_monitor_dict("ClockMonitor") return monitor_data["diff"] diff --git a/jenkinsapi/nodes.py b/jenkinsapi/nodes.py index 03edea01..ed037306 100644 --- a/jenkinsapi/nodes.py +++ b/jenkinsapi/nodes.py @@ -4,7 +4,7 @@ from __future__ import annotations -from typing import Iterator +from typing import TYPE_CHECKING, Iterator import logging @@ -17,6 +17,9 @@ log: logging.Logger = logging.getLogger(__name__) +if TYPE_CHECKING: + from jenkinsapi.jenkins import Jenkins + class Nodes(JenkinsBase): """ diff --git a/jenkinsapi/plugins.py b/jenkinsapi/plugins.py index 8e3dc6ce..d59b8eeb 100644 --- a/jenkinsapi/plugins.py +++ b/jenkinsapi/plugins.py @@ -4,7 +4,7 @@ from __future__ import annotations -from typing import Generator +from typing import TYPE_CHECKING, Iterable, Tuple import logging import time import re @@ -20,9 +20,11 @@ from jenkinsapi.utils.jsonp_to_json import jsonp_to_json from jenkinsapi.utils.manifest import Manifest, read_manifest - log: logging.Logger = logging.getLogger(__name__) +if TYPE_CHECKING: + from jenkinsapi.jenkins import Jenkins + class Plugins(JenkinsBase): """ @@ -53,18 +55,18 @@ def update_center_dict(self): def _poll(self, tree=None): return self.get_data(self.baseurl, tree=tree) - def keys(self) -> list[str]: + def keys(self) -> Iterable[str]: return self.get_plugins_dict().keys() __iter__ = keys - def iteritems(self) -> Generator[str, "Plugin"]: + def iteritems(self) -> Iterable[Tuple[str, "Plugin"]]: return self._get_plugins() def values(self) -> list["Plugin"]: return [a[1] for a in self.iteritems()] - def _get_plugins(self) -> Generator[str, "Plugin"]: + def _get_plugins(self) -> Iterable[Tuple[str, "Plugin"]]: if "plugins" in self._data: for p_dict in self._data["plugins"]: yield p_dict["shortName"], Plugin(p_dict) diff --git a/jenkinsapi/queue.py b/jenkinsapi/queue.py index 3a80ead5..43d0548f 100644 --- a/jenkinsapi/queue.py +++ b/jenkinsapi/queue.py @@ -4,7 +4,7 @@ from __future__ import annotations -from typing import Iterator, Tuple +from typing import TYPE_CHECKING, Iterator, Tuple import logging import time from requests import HTTPError @@ -13,6 +13,11 @@ log: logging.Logger = logging.getLogger(__name__) +if TYPE_CHECKING: + from jenkinsapi.build import Build + from jenkinsapi.jenkins import Jenkins + from jenkinsapi.job import Job + class Queue(JenkinsBase): """ @@ -36,12 +41,7 @@ def get_jenkins_obj(self) -> "Jenkins": def iteritems(self) -> Iterator[Tuple[str, "QueueItem"]]: for item in self._data["items"]: - queue_id = item["id"] - item_baseurl = "%s/item/%i" % (self.baseurl, queue_id) - yield ( - item["id"], - QueueItem(baseurl=item_baseurl, jenkins_obj=self.jenkins), - ) + yield item["id"], self._get_queue_item(item) def iterkeys(self) -> Iterator[str]: for item in self._data["items"]: @@ -49,7 +49,7 @@ def iterkeys(self) -> Iterator[str]: def itervalues(self) -> Iterator["QueueItem"]: for item in self._data["items"]: - yield QueueItem(self.jenkins, **item) + yield self._get_queue_item(item) def keys(self) -> list[str]: return list(self.iterkeys()) @@ -70,14 +70,19 @@ def __getitem__(self, item_id: str) -> "QueueItem": def _get_queue_items_for_job(self, job_name: str) -> Iterator["QueueItem"]: for item in self._data["items"]: if "name" in item["task"] and item["task"]["name"] == job_name: - yield QueueItem( - self.get_queue_item_url(item), jenkins_obj=self.jenkins - ) + yield self._get_queue_item(item) def get_queue_items_for_job(self, job_name: str): return list(self._get_queue_items_for_job(job_name)) - def get_queue_item_url(self, item: str) -> str: + def _get_queue_item(self, item: dict) -> QueueItem: + """Get a QueueItem object from a queue item dict""" + return QueueItem( + baseurl=self.get_queue_item_url(item), + jenkins_obj=self.jenkins, + ) + + def get_queue_item_url(self, item: dict) -> str: return "%s/item/%i" % (self.baseurl, item["id"]) def delete_item(self, queue_item: "QueueItem"): diff --git a/jenkinsapi/result_set.py b/jenkinsapi/result_set.py index 5bf5394f..e821fba1 100644 --- a/jenkinsapi/result_set.py +++ b/jenkinsapi/result_set.py @@ -3,10 +3,15 @@ """ from __future__ import annotations +from typing import TYPE_CHECKING from jenkinsapi.jenkinsbase import JenkinsBase from jenkinsapi.result import Result +if TYPE_CHECKING: + from jenkinsapi.build import Build + from jenkinsapi.jenkins import Jenkins + class ResultSet(JenkinsBase): """ diff --git a/jenkinsapi/utils/simple_post_logger.py b/jenkinsapi/utils/simple_post_logger.py index 29dbce36..4a80c452 100755 --- a/jenkinsapi/utils/simple_post_logger.py +++ b/jenkinsapi/utils/simple_post_logger.py @@ -1,14 +1,7 @@ #!/usr/bin/env python -try: - from SimpleHTTPServer import SimpleHTTPRequestHandler -except ImportError: - from http.server import SimpleHTTPRequestHandler - -try: - import SocketServer as socketserver -except ImportError: - import socketserver +from http.server import SimpleHTTPRequestHandler +import socketserver import logging import cgi diff --git a/jenkinsapi/view.py b/jenkinsapi/view.py index c9298608..8551a387 100644 --- a/jenkinsapi/view.py +++ b/jenkinsapi/view.py @@ -4,7 +4,7 @@ from __future__ import annotations -from typing import Iterator, Tuple +from typing import TYPE_CHECKING, Iterable, Iterator, Tuple import logging @@ -15,6 +15,9 @@ log: logging.Logger = logging.getLogger(__name__) +if TYPE_CHECKING: + from jenkinsapi.jenkins import Jenkins + class View(JenkinsBase): """ @@ -56,7 +59,7 @@ def delete(self) -> None: self.jenkins_obj.poll() self.deleted = True - def keys(self) -> list[str]: + def keys(self) -> Iterable[str]: return self.get_job_dict().keys() def iteritems(self) -> Iterator[Tuple[str, Job]]: diff --git a/jenkinsapi_tests/systests/test_nodes.py b/jenkinsapi_tests/systests/test_nodes.py index 9027d7df..c48ddc94 100644 --- a/jenkinsapi_tests/systests/test_nodes.py +++ b/jenkinsapi_tests/systests/test_nodes.py @@ -316,3 +316,8 @@ def test_offline_reason(jenkins): assert node.offline_reason() == "test2" del jenkins.nodes[node_name] + + +def test_get_node_architecture(jenkins): + mn = jenkins.get_node("Built-In Node") + assert isinstance(mn.get_architecture(), str) diff --git a/jenkinsapi_tests/systests/test_scm.py b/jenkinsapi_tests/systests/test_scm.py index 3558b787..7aad8c6b 100644 --- a/jenkinsapi_tests/systests/test_scm.py +++ b/jenkinsapi_tests/systests/test_scm.py @@ -1,10 +1,6 @@ # ''' # System tests for `jenkinsapi.jenkins` module. # ''' -# To run unittests on python 2.6 please use unittest2 library -# try: -# import unittest2 as unittest -# except ImportError: # import unittest # from jenkinsapi_tests.systests.base import BaseSystemTest # from jenkinsapi_tests.test_utils.random_strings import random_string diff --git a/jenkinsapi_tests/unittests/test_artifact.py b/jenkinsapi_tests/unittests/test_artifact.py index 73250d8c..0e83ce52 100644 --- a/jenkinsapi_tests/unittests/test_artifact.py +++ b/jenkinsapi_tests/unittests/test_artifact.py @@ -1,15 +1,12 @@ import pytest -from mock import Mock, patch, call +from unittest.mock import Mock, patch, call from requests.exceptions import HTTPError from jenkinsapi.artifact import Artifact from jenkinsapi.jenkinsbase import JenkinsBase from jenkinsapi.fingerprint import Fingerprint from jenkinsapi.custom_exceptions import ArtifactBroken -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest @pytest.fixture() diff --git a/jenkinsapi_tests/unittests/test_executors.py b/jenkinsapi_tests/unittests/test_executors.py index d582a489..b62d5a5d 100644 --- a/jenkinsapi_tests/unittests/test_executors.py +++ b/jenkinsapi_tests/unittests/test_executors.py @@ -1,5 +1,5 @@ import pytest -import mock +from unittest import mock from jenkinsapi.jenkins import Jenkins from jenkinsapi.executors import Executors from jenkinsapi.executor import Executor diff --git a/jenkinsapi_tests/unittests/test_job.py b/jenkinsapi_tests/unittests/test_job.py index 068103b8..d5a1a678 100644 --- a/jenkinsapi_tests/unittests/test_job.py +++ b/jenkinsapi_tests/unittests/test_job.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- import pytest -import mock +from unittest import mock import json from . import configs from jenkinsapi.job import Job diff --git a/jenkinsapi_tests/unittests/test_job_folders.py b/jenkinsapi_tests/unittests/test_job_folders.py index c3ba53c5..b5dae8b2 100644 --- a/jenkinsapi_tests/unittests/test_job_folders.py +++ b/jenkinsapi_tests/unittests/test_job_folders.py @@ -1,5 +1,5 @@ import pytest -import mock +from unittest import mock from jenkinsapi.jenkins import JenkinsBase diff --git a/jenkinsapi_tests/unittests/test_job_get_all_builds.py b/jenkinsapi_tests/unittests/test_job_get_all_builds.py index 54385b9b..5b0798bb 100644 --- a/jenkinsapi_tests/unittests/test_job_get_all_builds.py +++ b/jenkinsapi_tests/unittests/test_job_get_all_builds.py @@ -1,10 +1,6 @@ -import mock +from unittest import mock -# To run unittests on python 2.6 please use unittest2 library -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest from jenkinsapi import config from jenkinsapi.job import Job diff --git a/jenkinsapi_tests/unittests/test_job_scm_hg.py b/jenkinsapi_tests/unittests/test_job_scm_hg.py index 925d2bdd..cbb16c58 100644 --- a/jenkinsapi_tests/unittests/test_job_scm_hg.py +++ b/jenkinsapi_tests/unittests/test_job_scm_hg.py @@ -1,11 +1,7 @@ # flake8: noqa -# import mock +# from unittest import mock # -# # To run unittests on python 2.6 please use unittest2 library -# try: -# import unittest2 as unittest -# except ImportError: -# import unittest +# import unittest # # from jenkinsapi import config # from jenkinsapi.job import Job diff --git a/jenkinsapi_tests/unittests/test_plugins.py b/jenkinsapi_tests/unittests/test_plugins.py index 06da2990..21b13487 100644 --- a/jenkinsapi_tests/unittests/test_plugins.py +++ b/jenkinsapi_tests/unittests/test_plugins.py @@ -2,17 +2,11 @@ jenkinsapi_tests.test_plugins """ -import mock - -# To run unittests on python 2.6 please use unittest2 library -try: - import unittest2 as unittest -except ImportError: - import unittest -try: - from StringIO import StringIO # python2 -except ImportError: - from io import BytesIO as StringIO # python3 +from unittest import mock + +import unittest + +from io import BytesIO import zipfile from jenkinsapi.jenkins import Requester @@ -227,7 +221,7 @@ def test_install_plugin_good_input( @mock.patch.object(Plugins, "_poll") @mock.patch.object(Plugins, "plugin_version_already_installed") @mock.patch.object( - Plugins, "restart_required", new_callable=mock.mock.PropertyMock + Plugins, "restart_required", new_callable=mock.PropertyMock ) @mock.patch.object(Plugins, "_wait_until_plugin_installed") @mock.patch.object(Requester, "post_xml_and_confirm_status") @@ -253,7 +247,7 @@ def test_install_plugins_good_input_no_restart_required( @mock.patch.object(Plugins, "_poll") @mock.patch.object(Plugins, "plugin_version_already_installed") @mock.patch.object( - Plugins, "restart_required", new_callable=mock.mock.PropertyMock + Plugins, "restart_required", new_callable=mock.PropertyMock ) @mock.patch.object(Plugins, "_wait_until_plugin_installed") @mock.patch.object(Requester, "post_xml_and_confirm_status") @@ -282,7 +276,7 @@ def test_get_plugin_dependencies(self, _poll_plugins): "bla: somestuff\n" "Plugin-Dependencies: aws-java-sdk:1.10.45,aws-credentials:1.15" ) - downloaded_plugin = StringIO() + downloaded_plugin = BytesIO() zipfile.ZipFile(downloaded_plugin, mode="w").writestr( "META-INF/MANIFEST.MF", manifest ) @@ -317,7 +311,7 @@ def test_plugin_version_already_installed(self, _poll_plugins, _update): @mock.patch.object( Plugins, "update_center_install_status", - new_callable=mock.mock.PropertyMock, + new_callable=mock.PropertyMock, ) def test_restart_required_after_plugin_installation( self, status, _poll_plugins @@ -344,7 +338,7 @@ def test_restart_required_after_plugin_installation( @mock.patch.object( Plugins, "update_center_install_status", - new_callable=mock.mock.PropertyMock, + new_callable=mock.PropertyMock, ) def test_restart_not_required_after_plugin_installation( self, status, _poll_plugins diff --git a/jenkinsapi_tests/unittests/test_requester.py b/jenkinsapi_tests/unittests/test_requester.py index 925696bf..e9ab0289 100644 --- a/jenkinsapi_tests/unittests/test_requester.py +++ b/jenkinsapi_tests/unittests/test_requester.py @@ -2,7 +2,7 @@ import requests from jenkinsapi.jenkins import Requester from jenkinsapi.custom_exceptions import JenkinsAPIException -from mock import patch +from unittest.mock import patch def test_no_parameters_uses_default_values(): diff --git a/jenkinsapi_tests/unittests/test_result_set.py b/jenkinsapi_tests/unittests/test_result_set.py index 78562b05..8d46b0ca 100644 --- a/jenkinsapi_tests/unittests/test_result_set.py +++ b/jenkinsapi_tests/unittests/test_result_set.py @@ -1,10 +1,6 @@ -import mock +from unittest import mock -# To run unittests on python 2.6 please use unittest2 library -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest from jenkinsapi.result_set import ResultSet from jenkinsapi.result import Result diff --git a/pyproject.toml b/pyproject.toml index 0bfe2670..509570b7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -64,6 +64,9 @@ upload-dir = "doc/build/html" [tool.distutils.bdist_wheel] universal = 1 +[tool.mypy] +files = "jenkinsapi, jenkinsapi_tests" + [tool.pycodestyle] exclude = ".tox,doc/source/conf.py,build,.venv,.eggs" max-line-length = "99" @@ -77,10 +80,12 @@ dev = [ "astroid>=1.4.8", "pylint>=1.7.1", "tox>=2.3.1", - "mock>=5.1.0", "codecov>=2.1.13", "requests-kerberos>=0.15.0", "ruff>=0.9.6", + "mypy", + "types-pytz", + "types-requests", ] docs = [ "docutils>=0.20.1",