From 8816889a7d69f466e0370f6065fd67a3fc6a2ee1 Mon Sep 17 00:00:00 2001 From: Trim21 Date: Fri, 14 Jul 2023 20:49:28 +0800 Subject: [PATCH] Enable mypy `check_untyped_defs` (#2607) --- github/AccessToken.py | 16 +- github/Authorization.py | 46 ++-- github/CWE.py | 20 +- github/Environment.py | 37 +-- github/EnvironmentDeploymentBranchPolicy.py | 9 +- github/EnvironmentProtectionRule.py | 26 +- github/EnvironmentProtectionRuleReviewer.py | 12 +- github/GithubObject.py | 5 +- github/Repository.py | 4 - github/RepositoryAdvisory.py | 233 ++++++------------ github/RepositoryAdvisoryCredit.py | 13 +- github/RepositoryAdvisoryCreditDetailed.py | 16 +- github/RepositoryAdvisoryVulnerability.py | 36 +-- .../RepositoryAdvisoryVulnerabilityPackage.py | 15 +- github/Requester.py | 2 +- github/RequiredPullRequestReviews.py | 13 +- github/Stargazer.py | 6 +- pyproject.toml | 11 + tox.ini | 5 - 19 files changed, 215 insertions(+), 310 deletions(-) diff --git a/github/AccessToken.py b/github/AccessToken.py index 2a3000b5..2f001ece 100644 --- a/github/AccessToken.py +++ b/github/AccessToken.py @@ -19,9 +19,9 @@ # along with PyGithub. If not, see . # # # ################################################################################ +from __future__ import annotations from datetime import datetime, timedelta, timezone -from typing import Optional from github.GithubObject import Attribute, NonCompletableGithubObject, NotSet @@ -37,9 +37,9 @@ class AccessToken(NonCompletableGithubObject): self._token: Attribute[str] = NotSet self._type: Attribute[str] = NotSet self._scope: Attribute[str] = NotSet - self._expires_in: Attribute[Optional[int]] = NotSet + self._expires_in: Attribute[int | None] = NotSet self._refresh_token: Attribute[str] = NotSet - self._refresh_expires_in: Attribute[Optional[int]] = NotSet + self._refresh_expires_in: Attribute[int | None] = NotSet def __repr__(self) -> str: return self.get__repr__( @@ -82,14 +82,14 @@ class AccessToken(NonCompletableGithubObject): return self._created @property - def expires_in(self) -> Optional[int]: + def expires_in(self) -> int | None: """ :type: Optional[int] """ return self._expires_in.value @property - def expires_at(self) -> Optional[datetime]: + def expires_at(self) -> datetime | None: """ :type: Optional[datetime] """ @@ -99,21 +99,21 @@ class AccessToken(NonCompletableGithubObject): return None @property - def refresh_token(self) -> Optional[str]: + def refresh_token(self) -> str | None: """ :type: Optional[string] """ return self._refresh_token.value @property - def refresh_expires_in(self) -> Optional[int]: + def refresh_expires_in(self) -> int | None: """ :type: Optional[int] """ return self._refresh_expires_in.value @property - def refresh_expires_at(self) -> Optional[datetime]: + def refresh_expires_at(self) -> datetime | None: """ :type: Optional[datetime] """ diff --git a/github/Authorization.py b/github/Authorization.py index f16590d4..bd6422d7 100644 --- a/github/Authorization.py +++ b/github/Authorization.py @@ -27,8 +27,10 @@ # along with PyGithub. If not, see . # # # ################################################################################ +from __future__ import annotations + from datetime import datetime -from typing import TYPE_CHECKING, List, Optional +from typing import TYPE_CHECKING import github.AuthorizationApplication import github.GithubObject @@ -43,21 +45,22 @@ class Authorization(github.GithubObject.CompletableGithubObject): This class represents Authorizations. The reference can be found here https://docs.github.com/en/enterprise-server@3.0/rest/reference/oauth-authorizations """ - _app: Attribute["AuthorizationApplication"] - _created_at: Attribute[datetime] - _id: Attribute[int] - _note: Attribute[Optional[str]] - _note_url: Attribute[Optional[str]] - _scopes: Attribute[str] - _token: Attribute[str] - _updated_at: Attribute[datetime] - _url: Attribute[str] + def _initAttributes(self): + self._app: Attribute[AuthorizationApplication] = NotSet + self._created_at: Attribute[datetime] = NotSet + self._id: Attribute[int] = NotSet + self._note: Attribute[str | None] = NotSet + self._note_url: Attribute[str | None] = NotSet + self._scopes: Attribute[str] = NotSet + self._token: Attribute[str] = NotSet + self._updated_at: Attribute[datetime] = NotSet + self._url: Attribute[str] = NotSet def __repr__(self) -> str: return self.get__repr__({"scopes": self._scopes.value}) @property - def app(self) -> "AuthorizationApplication": + def app(self) -> AuthorizationApplication: self._completeIfNotSet(self._app) return self._app.value @@ -75,12 +78,12 @@ class Authorization(github.GithubObject.CompletableGithubObject): return self._id.value @property - def note(self) -> Optional[str]: + def note(self) -> str | None: self._completeIfNotSet(self._note) return self._note.value @property - def note_url(self) -> Optional[str]: + def note_url(self) -> str | None: self._completeIfNotSet(self._note_url) return self._note_url.value @@ -112,9 +115,9 @@ class Authorization(github.GithubObject.CompletableGithubObject): def edit( self, - scopes: Opt[List[str]] = NotSet, - add_scopes: Opt[List[str]] = NotSet, - remove_scopes: Opt[List[str]] = NotSet, + scopes: Opt[list[str]] = NotSet, + add_scopes: Opt[list[str]] = NotSet, + remove_scopes: Opt[list[str]] = NotSet, note: Opt[str] = NotSet, note_url: Opt[str] = NotSet, ) -> None: @@ -150,17 +153,6 @@ class Authorization(github.GithubObject.CompletableGithubObject): headers, data = self._requester.requestJsonAndCheck("PATCH", self.url, input=post_parameters) self._useAttributes(data) - def _initAttributes(self): - self._app = NotSet - self._created_at = NotSet - self._id = NotSet - self._note = NotSet - self._note_url = NotSet - self._scopes = NotSet - self._token = NotSet - self._updated_at = NotSet - self._url = NotSet - def _useAttributes(self, attributes): if "app" in attributes: # pragma no branch self._app = self._makeClassAttribute( diff --git a/github/CWE.py b/github/CWE.py index c6518acf..57a8c6f3 100644 --- a/github/CWE.py +++ b/github/CWE.py @@ -20,35 +20,27 @@ # # ################################################################################ -import github.GithubObject +from github.GithubObject import Attribute, CompletableGithubObject, NotSet -class CWE(github.GithubObject.CompletableGithubObject): +class CWE(CompletableGithubObject): """ This class represents a CWE. The reference can be found here https://docs.github.com/en/rest/security-advisories/repository-advisories """ + def _initAttributes(self): + self._cwe_id: Attribute[str] = NotSet + self._name: Attribute[str] = NotSet + @property def cwe_id(self) -> str: - """ - :type: string - """ return self._cwe_id.value @property def name(self) -> str: - """ - :type: string - """ return self._name.value - # noinspection PyPep8Naming - def _initAttributes(self): - self._cwe_id = github.GithubObject.NotSet - self._name = github.GithubObject.NotSet - - # noinspection PyPep8Naming def _useAttributes(self, attributes): if "cwe_id" in attributes: # pragma no branch self._cwe_id = self._makeStringAttribute(attributes["cwe_id"]) diff --git a/github/Environment.py b/github/Environment.py index 0c4dbb00..56eb2ae7 100644 --- a/github/Environment.py +++ b/github/Environment.py @@ -19,20 +19,36 @@ # along with PyGithub. If not, see . # # # ################################################################################ +from __future__ import annotations from datetime import datetime -from typing import List +from typing import TYPE_CHECKING import github.EnvironmentDeploymentBranchPolicy import github.EnvironmentProtectionRule -import github.GithubObject +from github.GithubObject import Attribute, CompletableGithubObject, NotSet + +if TYPE_CHECKING: + from github.EnvironmentDeploymentBranchPolicy import EnvironmentDeploymentBranchPolicy + from github.EnvironmentProtectionRule import EnvironmentProtectionRule -class Environment(github.GithubObject.CompletableGithubObject): +class Environment(CompletableGithubObject): """ This class represents Environment. The reference can be found here https://docs.github.com/en/rest/reference/deployments#environments """ + def _initAttributes(self): + self._created_at: Attribute[datetime] = NotSet + self._html_url: Attribute[str] = NotSet + self._id: Attribute[int] = NotSet + self._name: Attribute[str] = NotSet + self._node_id: Attribute[str] = NotSet + self._protection_rules: Attribute[list[EnvironmentProtectionRule]] = NotSet + self._updated_at: Attribute[datetime] = NotSet + self._url: Attribute[str] = NotSet + self._deployment_branch_policy: Attribute[EnvironmentDeploymentBranchPolicy] = NotSet + def __repr__(self): return self.get__repr__({"name": self._name.value}) @@ -64,7 +80,7 @@ class Environment(github.GithubObject.CompletableGithubObject): @property def protection_rules( self, - ) -> List[github.EnvironmentProtectionRule.EnvironmentProtectionRule]: + ) -> list[EnvironmentProtectionRule]: self._completeIfNotSet(self._protection_rules) return self._protection_rules.value @@ -81,21 +97,10 @@ class Environment(github.GithubObject.CompletableGithubObject): @property def deployment_branch_policy( self, - ) -> github.EnvironmentDeploymentBranchPolicy.EnvironmentDeploymentBranchPolicy: + ) -> EnvironmentDeploymentBranchPolicy: self._completeIfNotSet(self._deployment_branch_policy) return self._deployment_branch_policy.value - def _initAttributes(self): - self._created_at = github.GithubObject.NotSet - self._html_url = github.GithubObject.NotSet - self._id = github.GithubObject.NotSet - self._name = github.GithubObject.NotSet - self._node_id = github.GithubObject.NotSet - self._protection_rules = github.GithubObject.NotSet - self._updated_at = github.GithubObject.NotSet - self._url = github.GithubObject.NotSet - self._deployment_branch_policy = github.GithubObject.NotSet - def _useAttributes(self, attributes): if "created_at" in attributes: # pragma no branch self._created_at = self._makeDatetimeAttribute(attributes["created_at"]) diff --git a/github/EnvironmentDeploymentBranchPolicy.py b/github/EnvironmentDeploymentBranchPolicy.py index cd55ff79..3b3a6797 100644 --- a/github/EnvironmentDeploymentBranchPolicy.py +++ b/github/EnvironmentDeploymentBranchPolicy.py @@ -20,11 +20,10 @@ # # ################################################################################ -import github.EnvironmentProtectionRuleReviewer -import github.GithubObject +from github.GithubObject import Attribute, NonCompletableGithubObject, NotSet -class EnvironmentDeploymentBranchPolicy(github.GithubObject.NonCompletableGithubObject): +class EnvironmentDeploymentBranchPolicy(NonCompletableGithubObject): """ This class represents a deployment branch policy for an environment. The reference can be found here https://docs.github.com/en/rest/reference/deployments#environments """ @@ -41,8 +40,8 @@ class EnvironmentDeploymentBranchPolicy(github.GithubObject.NonCompletableGithub return self._custom_branch_policies.value def _initAttributes(self): - self._protected_branches = github.GithubObject.NotSet - self._custom_branch_policies = github.GithubObject.NotSet + self._protected_branches: Attribute[bool] = NotSet + self._custom_branch_policies: Attribute[bool] = NotSet def _useAttributes(self, attributes): if "protected_branches" in attributes: # pragma no branch diff --git a/github/EnvironmentProtectionRule.py b/github/EnvironmentProtectionRule.py index ce7271bc..199972ee 100644 --- a/github/EnvironmentProtectionRule.py +++ b/github/EnvironmentProtectionRule.py @@ -19,18 +19,29 @@ # along with PyGithub. If not, see . # # # ################################################################################ +from __future__ import annotations -from typing import List +from typing import TYPE_CHECKING import github.EnvironmentProtectionRuleReviewer -import github.GithubObject +from github.GithubObject import Attribute, NonCompletableGithubObject, NotSet + +if TYPE_CHECKING: + from github.EnvironmentProtectionRuleReviewer import EnvironmentProtectionRuleReviewer -class EnvironmentProtectionRule(github.GithubObject.NonCompletableGithubObject): +class EnvironmentProtectionRule(NonCompletableGithubObject): """ This class represents a protection rule for an environment. The reference can be found here https://docs.github.com/en/rest/reference/deployments#environments """ + def _initAttributes(self): + self._id: Attribute[int] = NotSet + self._node_id: Attribute[str] = NotSet + self._type: Attribute[str] = NotSet + self._reviewers: Attribute[list[EnvironmentProtectionRuleReviewer]] = NotSet + self._wait_timer: Attribute[int] = NotSet + def __repr__(self): return self.get__repr__({"id": self._id.value}) @@ -49,20 +60,13 @@ class EnvironmentProtectionRule(github.GithubObject.NonCompletableGithubObject): @property def reviewers( self, - ) -> List[github.EnvironmentProtectionRuleReviewer.EnvironmentProtectionRuleReviewer]: + ) -> list[EnvironmentProtectionRuleReviewer]: return self._reviewers.value @property def wait_timer(self) -> int: return self._wait_timer.value - def _initAttributes(self): - self._id = github.GithubObject.NotSet - self._node_id = github.GithubObject.NotSet - self._type = github.GithubObject.NotSet - self._reviewers = github.GithubObject.NotSet - self._wait_timer = github.GithubObject.NotSet - def _useAttributes(self, attributes): if "id" in attributes: # pragma no branch self._id = self._makeIntAttribute(attributes["id"]) diff --git a/github/EnvironmentProtectionRuleReviewer.py b/github/EnvironmentProtectionRuleReviewer.py index 690dbd20..0d938727 100644 --- a/github/EnvironmentProtectionRuleReviewer.py +++ b/github/EnvironmentProtectionRuleReviewer.py @@ -22,16 +22,20 @@ from __future__ import annotations -import github.GithubObject import github.NamedUser import github.Team +from github.GithubObject import Attribute, NonCompletableGithubObject, NotSet -class EnvironmentProtectionRuleReviewer(github.GithubObject.NonCompletableGithubObject): +class EnvironmentProtectionRuleReviewer(NonCompletableGithubObject): """ This class represents a reviewer for an EnvironmentProtectionRule. The reference can be found here https://docs.github.com/en/rest/reference/deployments#environments """ + def _initAttributes(self): + self._type: Attribute[str] = NotSet + self._reviewer: Attribute[github.NamedUser.NamedUser | github.Team.Team] = NotSet + def __repr__(self): return self.get__repr__({"type": self._type.value}) @@ -43,10 +47,6 @@ class EnvironmentProtectionRuleReviewer(github.GithubObject.NonCompletableGithub def reviewer(self) -> github.NamedUser.NamedUser | github.Team.Team: return self._reviewer.value - def _initAttributes(self): - self._type = github.GithubObject.NotSet - self._reviewer = github.GithubObject.NotSet - def _useAttributes(self, attributes): if "type" in attributes: # pragma no branch self._type = self._makeStringAttribute(attributes["type"]) diff --git a/github/GithubObject.py b/github/GithubObject.py index 4f54c5b6..768f3ac2 100644 --- a/github/GithubObject.py +++ b/github/GithubObject.py @@ -55,6 +55,7 @@ if TYPE_CHECKING: T = typing.TypeVar("T") K = typing.TypeVar("K") T_co = typing.TypeVar("T_co", covariant=True) +T_gh = typing.TypeVar("T_gh", bound="GithubObject") class Attribute(Protocol[T_co]): @@ -68,7 +69,7 @@ class _NotSetType: return "NotSet" @property - def value(self): + def value(self) -> Any: return None @staticmethod @@ -262,7 +263,7 @@ class GithubObject: ) -> Attribute: return GithubObject.__makeSimpleListAttribute(value, list) - def _makeListOfClassesAttribute(self, klass: Any, value: Any) -> Union[_ValuedAttribute, _BadAttribute]: + def _makeListOfClassesAttribute(self, klass: Type[T_gh], value: Any) -> Attribute[List[T_gh]]: if isinstance(value, list) and all(isinstance(element, dict) for element in value): return _ValuedAttribute( [klass(self._requester, self._headers, element, completed=False) for element in value] diff --git a/github/Repository.py b/github/Repository.py index 039e40e1..90c9e64d 100644 --- a/github/Repository.py +++ b/github/Repository.py @@ -1524,7 +1524,6 @@ class Repository(github.GithubObject.CompletableGithubObject): assert isinstance(cve_id, (str, type(None))), cve_id assert isinstance(vulnerabilities, typing.Iterable), vulnerabilities for vulnerability in vulnerabilities: - # noinspection PyProtectedMember github.RepositoryAdvisoryVulnerability.RepositoryAdvisoryVulnerability._validate_vulnerability( vulnerability ) @@ -1533,9 +1532,7 @@ class Repository(github.GithubObject.CompletableGithubObject): assert isinstance(credits, (typing.Iterable, type(None))), credits if credits is not None: for credit in credits: - # noinspection PyProtectedMember github.RepositoryAdvisoryCredit.RepositoryAdvisoryCredit._validate_credit(credit) - # noinspection PyProtectedMember post_parameters = { "summary": summary, "description": description, @@ -1548,7 +1545,6 @@ class Repository(github.GithubObject.CompletableGithubObject): if cve_id is not None: post_parameters["cve_id"] = cve_id if credits is not None: - # noinspection PyProtectedMember post_parameters["credits"] = [ github.RepositoryAdvisoryCredit.RepositoryAdvisoryCredit._to_github_dict(credit) for credit in credits ] diff --git a/github/RepositoryAdvisory.py b/github/RepositoryAdvisory.py index 75780f99..003c2b5d 100644 --- a/github/RepositoryAdvisory.py +++ b/github/RepositoryAdvisory.py @@ -19,184 +19,142 @@ # along with PyGithub. If not, see . # # # ################################################################################ +from __future__ import annotations -import typing from datetime import datetime +from typing import TYPE_CHECKING, Any, Iterable -import github.GithubObject import github.NamedUser from github.CWE import CWE +from github.GithubObject import Attribute, NonCompletableGithubObject, NotSet, Opt from github.RepositoryAdvisoryCredit import Credit, RepositoryAdvisoryCredit from github.RepositoryAdvisoryCreditDetailed import RepositoryAdvisoryCreditDetailed from github.RepositoryAdvisoryVulnerability import AdvisoryVulnerability, RepositoryAdvisoryVulnerability -from github.Requester import Requester + +if TYPE_CHECKING: + from github.NamedUser import NamedUser -class RepositoryAdvisory(github.GithubObject.NonCompletableGithubObject): +class RepositoryAdvisory(NonCompletableGithubObject): """ This class represents a RepositoryAdvisory. The reference can be found here https://docs.github.com/en/rest/security-advisories/repository-advisories """ - _requester: Requester + def _initAttributes(self): + self._author: Attribute[NamedUser] = NotSet + self._closed_at: Attribute[datetime] = NotSet + self._created_at: Attribute[datetime] = NotSet + self._credits: Attribute[list[RepositoryAdvisoryCredit]] = NotSet + self._credits_detailed: Attribute[list[RepositoryAdvisoryCreditDetailed]] = NotSet + self._cve_id: Attribute[str] = NotSet + self._cwe_ids: Attribute[list[str]] = NotSet + self._cwes: Attribute[list[CWE]] = NotSet + self._description: Attribute[str] = NotSet + self._ghsa_id: Attribute[str] = NotSet + self._html_url: Attribute[str] = NotSet + self._published_at: Attribute[datetime] = NotSet + self._severity: Attribute[str] = NotSet + self._state: Attribute[str] = NotSet + self._summary: Attribute[str] = NotSet + self._updated_at: Attribute[datetime] = NotSet + self._url: Attribute[str] = NotSet + self._vulnerabilities: Attribute[list[RepositoryAdvisoryVulnerability]] = NotSet + self._withdrawn_at: Attribute[datetime] = NotSet def __repr__(self): return self.get__repr__({"ghsa_id": self.ghsa_id, "summary": self.summary}) @property - def author(self) -> "github.NamedUser.NamedUser": - """ - :type: :class:`github.NamedUser.NamedUser` - """ + def author(self) -> NamedUser: return self._author.value @property def closed_at(self) -> datetime: - """ - :type: datetime - """ return self._closed_at.value @property def created_at(self) -> datetime: - """ - :type: datetime - """ return self._created_at.value @property def credits( self, - ) -> typing.List[RepositoryAdvisoryCredit]: - """ - :type: list of :class:`github.RepositoryAdvisoryCredit.RepositoryAdvisoryCredit` - """ + ) -> list[RepositoryAdvisoryCredit]: return self._credits.value @property def credits_detailed( self, - ) -> typing.List[RepositoryAdvisoryCreditDetailed]: - """ - :type: list of :class:`github.RepositoryAdvisoryCreditDetailed.RepositoryAdvisoryCreditDetailed` - """ + ) -> list[RepositoryAdvisoryCreditDetailed]: return self._credits_detailed.value @property def cve_id(self) -> str: - """ - :type: string - """ return self._cve_id.value @property - def cwe_ids(self) -> typing.List[str]: - """ - :type: list of string - """ + def cwe_ids(self) -> list[str]: return self._cwe_ids.value @property - def cwes(self) -> typing.List[CWE]: - """ - :type: list of :class:`github.CWE.CWE` - """ + def cwes(self) -> list[CWE]: return self._cwes.value @property def description(self) -> str: - """ - :type: string - """ return self._description.value @property def ghsa_id(self) -> str: - """ - :type: string - """ return self._ghsa_id.value @property def html_url(self) -> str: - """ - :type: string - """ return self._html_url.value @property def published_at(self) -> datetime: - """ - :type: datetime - """ return self._published_at.value @property def severity(self) -> str: - """ - :type: string - """ return self._severity.value @property def state(self) -> str: - """ - :type: string - """ return self._state.value @property def summary(self) -> str: - """ - :type: string - """ return self._summary.value @property def updated_at(self) -> datetime: - """ - :type: datetime - """ return self._updated_at.value @property def url(self) -> str: - """ - :type: string - """ return self._url.value @property - def vulnerabilities( - self, - ) -> typing.List[RepositoryAdvisoryVulnerability]: - """ - :type: list of :class:`github.RepositoryAdvisoryVulnerability.RepositoryAdvisoryVulnerability` - """ + def vulnerabilities(self) -> list[RepositoryAdvisoryVulnerability]: return self._vulnerabilities.value @property def withdrawn_at(self) -> datetime: - """ - :type: datetime - """ return self._withdrawn_at.value def add_vulnerability( self, ecosystem: str, - package_name: typing.Optional[str] = None, - vulnerable_version_range: typing.Optional[str] = None, - patched_versions: typing.Optional[str] = None, - vulnerable_functions: typing.Optional[typing.List[str]] = None, + package_name: str | None = None, + vulnerable_version_range: str | None = None, + patched_versions: str | None = None, + vulnerable_functions: list[str] | None = None, ): """ :calls: `PATCH /repos/{owner}/{repo}/security-advisories/:advisory_id `\ - :param ecosystem: string - :param package_name: string - :param vulnerable_version_range: string - :param patched_versions: string - :param vulnerable_functions: list of string """ return self.add_vulnerabilities( [ @@ -212,18 +170,16 @@ class RepositoryAdvisory(github.GithubObject.NonCompletableGithubObject): ] ) - def add_vulnerabilities(self, vulnerabilities: typing.Iterable[AdvisoryVulnerability]): + def add_vulnerabilities(self, vulnerabilities: Iterable[AdvisoryVulnerability]): """ :calls: `PATCH /repos/{owner}/{repo}/security-advisories/:advisory_id ` - :param vulnerabilities: iterable of :class:`github.RepositoryAdvisoryVulnerability.AdvisoryVulnerability` """ - assert isinstance(vulnerabilities, typing.Iterable), vulnerabilities + assert isinstance(vulnerabilities, Iterable), vulnerabilities for vulnerability in vulnerabilities: - # noinspection PyProtectedMember github.RepositoryAdvisoryVulnerability.RepositoryAdvisoryVulnerability._validate_vulnerability( vulnerability ) - # noinspection PyProtectedMember + post_parameters = { "vulnerabilities": [ github.RepositoryAdvisoryVulnerability.RepositoryAdvisoryVulnerability._to_github_dict(vulnerability) @@ -239,21 +195,19 @@ class RepositoryAdvisory(github.GithubObject.NonCompletableGithubObject): def offer_credit( self, - login_or_user: typing.Union[str, "github.NamedUser.NamedUser"], + login_or_user: str | github.NamedUser.NamedUser, credit_type: str, ): """ :calls: `PATCH /repos/{owner}/{repo}/security-advisories/:advisory_id ` Offers credit to a user for a vulnerability in a repository. Unless you are giving credit to yourself, the user having credit offered will need to explicitly accept the credit. - :param login_or_user: string username or :class:`github.NamedUser.NamedUser` - :param credit_type: string """ self.offer_credits([{"login": login_or_user, "type": credit_type}]) def offer_credits( self, - credited: typing.Iterable["Credit"], + credited: Iterable[Credit], ): """ :calls: `PATCH /repos/{owner}/{repo}/security-advisories/:advisory_id ` @@ -261,11 +215,10 @@ class RepositoryAdvisory(github.GithubObject.NonCompletableGithubObject): Unless you are giving credit to yourself, the user having credit offered will need to explicitly accept the credit. :param credited: iterable of dict with keys "login" and "type" """ - assert isinstance(credited, typing.Iterable), credited + assert isinstance(credited, Iterable), credited for credit in credited: - # noinspection PyProtectedMember RepositoryAdvisoryCredit._validate_credit(credit) - # noinspection PyProtectedMember + patch_parameters = { "credits": [RepositoryAdvisoryCredit._to_github_dict(credit) for credit in (self.credits + list(credited))] } @@ -276,10 +229,9 @@ class RepositoryAdvisory(github.GithubObject.NonCompletableGithubObject): ) self._useAttributes(data) - def revoke_credit(self, login_or_user: typing.Union[str, "github.NamedUser.NamedUser"]): + def revoke_credit(self, login_or_user: str | NamedUser): """ :calls: `PATCH /repos/{owner}/{repo}/security-advisories/:advisory_id `_ - :param login_or_user: string username or :class:`github.NamedUser.NamedUser` """ assert isinstance(login_or_user, (str, github.NamedUser.NamedUser)), login_or_user if isinstance(login_or_user, github.NamedUser.NamedUser): @@ -300,7 +252,7 @@ class RepositoryAdvisory(github.GithubObject.NonCompletableGithubObject): """ :calls: `PATCH /repos/{owner}/{repo}/security-advisories/:advisory_id `_ """ - patch_parameters = {"credits": []} + patch_parameters: dict[str, Any] = {"credits": []} headers, data = self._requester.requestJsonAndCheck( "PATCH", self.url, @@ -310,76 +262,61 @@ class RepositoryAdvisory(github.GithubObject.NonCompletableGithubObject): def edit( self, - summary: github.GithubObject.Opt[str] = github.GithubObject.NotSet, - description: github.GithubObject.Opt[str] = github.GithubObject.NotSet, - severity_or_cvss_vector_string: github.GithubObject.Opt[str] = github.GithubObject.NotSet, - cve_id: github.GithubObject.Opt[str] = github.GithubObject.NotSet, - vulnerabilities: github.GithubObject.Opt[typing.Iterable[AdvisoryVulnerability]] = github.GithubObject.NotSet, - cwe_ids: github.GithubObject.Opt[typing.Iterable[str]] = github.GithubObject.NotSet, - credits: github.GithubObject.Opt[typing.Iterable[Credit]] = github.GithubObject.NotSet, - state: github.GithubObject.Opt[str] = github.GithubObject.NotSet, - ) -> "RepositoryAdvisory": + summary: Opt[str] = NotSet, + description: Opt[str] = NotSet, + severity_or_cvss_vector_string: Opt[str] = NotSet, + cve_id: Opt[str] = NotSet, + vulnerabilities: Opt[Iterable[AdvisoryVulnerability]] = NotSet, + cwe_ids: Opt[Iterable[str]] = NotSet, + credits: Opt[Iterable[Credit]] = NotSet, + state: Opt[str] = NotSet, + ) -> RepositoryAdvisory: """ :calls: `PATCH /repos/{owner}/{repo}/security-advisories/:advisory_id `_ - :param summary: string - :param description: string - :param severity_or_cvss_vector_string: string - :param cve_id: string - :param vulnerabilities: iterable of :class:`github.RepositoryAdvisoryVulnerability.AdvisoryVulnerability` - :param cwe_ids: iterable of string - :param credits: iterable of :class:`github.RepositoryAdvisoryCredit.Credit` - :param state: string - :rtype: :class:`github.RepositoryAdvisory.RepositoryAdvisory` """ - assert summary is github.GithubObject.NotSet or isinstance(summary, str), summary - assert description is github.GithubObject.NotSet or isinstance(description, str), description - assert severity_or_cvss_vector_string is github.GithubObject.NotSet or isinstance( + assert summary is NotSet or isinstance(summary, str), summary + assert description is NotSet or isinstance(description, str), description + assert severity_or_cvss_vector_string is NotSet or isinstance( severity_or_cvss_vector_string, str ), severity_or_cvss_vector_string - assert cve_id is github.GithubObject.NotSet or isinstance(cve_id, str), cve_id - assert vulnerabilities is github.GithubObject.NotSet or isinstance( - vulnerabilities, typing.Iterable - ), vulnerabilities - if isinstance(vulnerabilities, typing.Iterable): + assert cve_id is NotSet or isinstance(cve_id, str), cve_id + assert vulnerabilities is NotSet or isinstance(vulnerabilities, Iterable), vulnerabilities + if isinstance(vulnerabilities, Iterable): for vulnerability in vulnerabilities: - # noinspection PyProtectedMember github.RepositoryAdvisoryVulnerability.RepositoryAdvisoryVulnerability._validate_vulnerability( vulnerability ) - assert cwe_ids is github.GithubObject.NotSet or ( - isinstance(cwe_ids, typing.Iterable) and all(isinstance(element, str) for element in cwe_ids) + assert cwe_ids is NotSet or ( + isinstance(cwe_ids, Iterable) and all(isinstance(element, str) for element in cwe_ids) ), cwe_ids - if isinstance(credits, typing.Iterable): + if isinstance(credits, Iterable): for credit in credits: - # noinspection PyProtectedMember github.RepositoryAdvisoryCredit.RepositoryAdvisoryCredit._validate_credit(credit) - assert state is github.GithubObject.NotSet or isinstance(state, str), state - patch_parameters: typing.Dict[str, typing.Any] = dict() - if summary is not github.GithubObject.NotSet: + assert state is NotSet or isinstance(state, str), state + patch_parameters: dict[str, Any] = {} + if summary is not NotSet: patch_parameters["summary"] = summary - if description is not github.GithubObject.NotSet: + if description is not NotSet: patch_parameters["description"] = description if isinstance(severity_or_cvss_vector_string, str): if severity_or_cvss_vector_string.startswith("CVSS:"): patch_parameters["cvss_vector_string"] = severity_or_cvss_vector_string else: patch_parameters["severity"] = severity_or_cvss_vector_string - if cve_id is not github.GithubObject.NotSet: + if cve_id is not NotSet: patch_parameters["cve_id"] = cve_id - if isinstance(vulnerabilities, typing.Iterable): - # noinspection PyProtectedMember + if isinstance(vulnerabilities, Iterable): patch_parameters["vulnerabilities"] = [ github.RepositoryAdvisoryVulnerability.RepositoryAdvisoryVulnerability._to_github_dict(vulnerability) for vulnerability in vulnerabilities ] - if isinstance(cwe_ids, typing.Iterable): + if isinstance(cwe_ids, Iterable): patch_parameters["cwe_ids"] = list(cwe_ids) - if isinstance(credits, typing.Iterable): - # noinspection PyProtectedMember + if isinstance(credits, Iterable): patch_parameters["credits"] = [ github.RepositoryAdvisoryCredit.RepositoryAdvisoryCredit._to_github_dict(credit) for credit in credits ] - if state is not github.GithubObject.NotSet: + if state is not NotSet: patch_parameters["state"] = state headers, data = self._requester.requestJsonAndCheck( "PATCH", @@ -428,30 +365,6 @@ class RepositoryAdvisory(github.GithubObject.NonCompletableGithubObject): ) self._useAttributes(data) - # noinspection DuplicatedCode - # noinspection PyPep8Naming - def _initAttributes(self): - self._author = github.GithubObject.NotSet - self._closed_at = github.GithubObject.NotSet - self._created_at = github.GithubObject.NotSet - self._credits = github.GithubObject.NotSet - self._credits_detailed = github.GithubObject.NotSet - self._cve_id = github.GithubObject.NotSet - self._cwe_ids = github.GithubObject.NotSet - self._cwes = github.GithubObject.NotSet - self._description = github.GithubObject.NotSet - self._ghsa_id = github.GithubObject.NotSet - self._html_url = github.GithubObject.NotSet - self._published_at = github.GithubObject.NotSet - self._severity = github.GithubObject.NotSet - self._state = github.GithubObject.NotSet - self._summary = github.GithubObject.NotSet - self._updated_at = github.GithubObject.NotSet - self._url = github.GithubObject.NotSet - self._vulnerabilities = github.GithubObject.NotSet - self._withdrawn_at = github.GithubObject.NotSet - - # noinspection PyPep8Naming def _useAttributes(self, attributes): if "author" in attributes: # pragma no branch self._author = self._makeClassAttribute(github.NamedUser.NamedUser, attributes["author"]) diff --git a/github/RepositoryAdvisoryCredit.py b/github/RepositoryAdvisoryCredit.py index 99bd9359..96a8726e 100644 --- a/github/RepositoryAdvisoryCredit.py +++ b/github/RepositoryAdvisoryCredit.py @@ -19,13 +19,14 @@ # along with PyGithub. If not, see . # # # ################################################################################ +from __future__ import annotations from typing import Union from typing_extensions import TypedDict -import github.GithubObject import github.NamedUser +from github.GithubObject import Attribute, NonCompletableGithubObject, NotSet class SimpleCredit(TypedDict): @@ -33,14 +34,14 @@ class SimpleCredit(TypedDict): A simple credit for a security advisory. """ - login: Union[str, "github.NamedUser.NamedUser"] + login: str | github.NamedUser.NamedUser type: str Credit = Union[SimpleCredit, "RepositoryAdvisoryCredit"] -class RepositoryAdvisoryCredit(github.GithubObject.NonCompletableGithubObject): +class RepositoryAdvisoryCredit(NonCompletableGithubObject): """ This class represents a credit that is assigned to a SecurityAdvisory. The reference can be found here https://docs.github.com/en/rest/security-advisories/repository-advisories @@ -60,12 +61,10 @@ class RepositoryAdvisoryCredit(github.GithubObject.NonCompletableGithubObject): """ return self._type.value - # noinspection PyPep8Naming def _initAttributes(self): - self._login = github.GithubObject.NotSet - self._type = github.GithubObject.NotSet + self._login: Attribute[str] = NotSet + self._type: Attribute[str] = NotSet - # noinspection PyPep8Naming def _useAttributes(self, attributes): if "login" in attributes: # pragma no branch self._login = self._makeStringAttribute(attributes["login"]) diff --git a/github/RepositoryAdvisoryCreditDetailed.py b/github/RepositoryAdvisoryCreditDetailed.py index 9ceed418..d11309e4 100644 --- a/github/RepositoryAdvisoryCreditDetailed.py +++ b/github/RepositoryAdvisoryCreditDetailed.py @@ -19,12 +19,13 @@ # along with PyGithub. If not, see . # # # ################################################################################ +from __future__ import annotations -import github.GithubObject import github.NamedUser +from github.GithubObject import Attribute, NonCompletableGithubObject, NotSet -class RepositoryAdvisoryCreditDetailed(github.GithubObject.NonCompletableGithubObject): +class RepositoryAdvisoryCreditDetailed(NonCompletableGithubObject): """ This class represents a credit that is assigned to a SecurityAdvisory. The reference can be found here https://docs.github.com/en/rest/security-advisories/repository-advisories @@ -44,21 +45,18 @@ class RepositoryAdvisoryCreditDetailed(github.GithubObject.NonCompletableGithubO """ return self._type.value - # noinspection PyPep8Naming @property - def user(self) -> "github.NamedUser.NamedUser": + def user(self) -> github.NamedUser.NamedUser: """ :type: :class:`github.NamedUser.NamedUser` """ return self._user.value - # noinspection PyPep8Naming def _initAttributes(self): - self._state = github.GithubObject.NotSet - self._type = github.GithubObject.NotSet - self._user = github.GithubObject.NotSet + self._state: Attribute[str] = NotSet + self._type: Attribute[str] = NotSet + self._user: Attribute[github.NamedUser.NamedUser] = NotSet - # noinspection PyPep8Naming def _useAttributes(self, attributes): if "state" in attributes: # pragma no branch self._state = self._makeStringAttribute(attributes["state"]) diff --git a/github/RepositoryAdvisoryVulnerability.py b/github/RepositoryAdvisoryVulnerability.py index e91118bf..8d5dfd73 100644 --- a/github/RepositoryAdvisoryVulnerability.py +++ b/github/RepositoryAdvisoryVulnerability.py @@ -19,13 +19,17 @@ # along with PyGithub. If not, see . # # # ################################################################################ +from __future__ import annotations -from typing import List, Optional, Union +from typing import TYPE_CHECKING, Union -from typing_extensions import NotRequired, TypedDict +from typing_extensions import TypedDict -import github.GithubObject import github.RepositoryAdvisoryVulnerabilityPackage +from github.GithubObject import Attribute, NonCompletableGithubObject, NotSet + +if TYPE_CHECKING: + from github.RepositoryAdvisoryVulnerabilityPackage import RepositoryAdvisoryVulnerabilityPackage class SimpleAdvisoryVulnerabilityPackage(TypedDict): @@ -34,7 +38,7 @@ class SimpleAdvisoryVulnerabilityPackage(TypedDict): """ ecosystem: str - name: NotRequired[Optional[str]] + name: str | None class SimpleAdvisoryVulnerability(TypedDict): @@ -43,15 +47,15 @@ class SimpleAdvisoryVulnerability(TypedDict): """ package: SimpleAdvisoryVulnerabilityPackage - patched_versions: NotRequired[Optional[str]] - vulnerable_functions: NotRequired[Optional[List[str]]] - vulnerable_version_range: NotRequired[Optional[str]] + patched_versions: str | None + vulnerable_functions: list[str] | None + vulnerable_version_range: str | None AdvisoryVulnerability = Union[SimpleAdvisoryVulnerability, "RepositoryAdvisoryVulnerability"] -class RepositoryAdvisoryVulnerability(github.GithubObject.NonCompletableGithubObject): +class RepositoryAdvisoryVulnerability(NonCompletableGithubObject): """ This class represents a package that is vulnerable to a parent SecurityAdvisory. The reference can be found here https://docs.github.com/en/rest/security-advisories/repository-advisories @@ -60,7 +64,7 @@ class RepositoryAdvisoryVulnerability(github.GithubObject.NonCompletableGithubOb @property def package( self, - ) -> github.RepositoryAdvisoryVulnerabilityPackage.RepositoryAdvisoryVulnerabilityPackage: + ) -> RepositoryAdvisoryVulnerabilityPackage: """ :type: :class:`github.RepositoryAdvisoryVulnerability.RepositoryAdvisoryVulnerability` """ @@ -74,27 +78,25 @@ class RepositoryAdvisoryVulnerability(github.GithubObject.NonCompletableGithubOb return self._patched_versions.value @property - def vulnerable_functions(self) -> Optional[List[str]]: + def vulnerable_functions(self) -> list[str] | None: """ :type: list of string """ return self._vulnerable_functions.value @property - def vulnerable_version_range(self) -> Optional[str]: + def vulnerable_version_range(self) -> str | None: """ :type: string """ return self._vulnerable_version_range.value - # noinspection PyPep8Naming def _initAttributes(self): - self._package = github.GithubObject.NotSet - self._patched_versions = github.GithubObject.NotSet - self._vulnerable_functions = github.GithubObject.NotSet - self._vulnerable_version_range = github.GithubObject.NotSet + self._package: Attribute[RepositoryAdvisoryVulnerabilityPackage] = NotSet + self._patched_versions: Attribute[str] = NotSet + self._vulnerable_functions: Attribute[list[str]] = NotSet + self._vulnerable_version_range: Attribute[str] = NotSet - # noinspection PyPep8Naming def _useAttributes(self, attributes): if "package" in attributes: # pragma no branch self._package = self._makeClassAttribute( diff --git a/github/RepositoryAdvisoryVulnerabilityPackage.py b/github/RepositoryAdvisoryVulnerabilityPackage.py index 41ecc941..3bf3701b 100644 --- a/github/RepositoryAdvisoryVulnerabilityPackage.py +++ b/github/RepositoryAdvisoryVulnerabilityPackage.py @@ -19,13 +19,12 @@ # along with PyGithub. If not, see . # # # ################################################################################ +from __future__ import annotations -from typing import Optional - -import github.GithubObject +from github.GithubObject import Attribute, NonCompletableGithubObject, NotSet -class RepositoryAdvisoryVulnerabilityPackage(github.GithubObject.NonCompletableGithubObject): +class RepositoryAdvisoryVulnerabilityPackage(NonCompletableGithubObject): """ This class represents an identifier for a package that is vulnerable to a parent SecurityAdvisory. The reference can be found here https://docs.github.com/en/rest/security-advisories/repository-advisories @@ -39,18 +38,16 @@ class RepositoryAdvisoryVulnerabilityPackage(github.GithubObject.NonCompletableG return self._ecosystem.value @property - def name(self) -> Optional[str]: + def name(self) -> str | None: """ :type: string or None """ return self._name.value - # noinspection PyPep8Naming def _initAttributes(self): - self._ecosystem = github.GithubObject.NotSet - self._name = github.GithubObject.NotSet + self._ecosystem: Attribute[str] = NotSet + self._name: Attribute[str | None] = NotSet - # noinspection PyPep8Naming def _useAttributes(self, attributes): if "ecosystem" in attributes: # pragma no branch self._ecosystem = self._makeStringAttribute(attributes["ecosystem"]) diff --git a/github/Requester.py b/github/Requester.py index e9e50b52..75f38039 100644 --- a/github/Requester.py +++ b/github/Requester.py @@ -858,7 +858,7 @@ class WithRequester(Generic[T]): __requester: Requester def __init__(self): - self.__requester: Optional[Requester] = None + self.__requester: Optional[Requester] = None # type: ignore @property def requester(self) -> Requester: diff --git a/github/RequiredPullRequestReviews.py b/github/RequiredPullRequestReviews.py index 9ae61613..4f897611 100644 --- a/github/RequiredPullRequestReviews.py +++ b/github/RequiredPullRequestReviews.py @@ -24,17 +24,16 @@ from __future__ import annotations from typing import TYPE_CHECKING -import github.GithubObject import github.NamedUser import github.Team -from github.GithubObject import Attribute, NotSet +from github.GithubObject import Attribute, CompletableGithubObject, NotSet if TYPE_CHECKING: from github.NamedUser import NamedUser from github.Team import Team -class RequiredPullRequestReviews(github.GithubObject.CompletableGithubObject): +class RequiredPullRequestReviews(CompletableGithubObject): """ This class represents Required Pull Request Reviews. The reference can be found here https://docs.github.com/en/rest/reference/repos#get-pull-request-review-protection """ @@ -43,8 +42,8 @@ class RequiredPullRequestReviews(github.GithubObject.CompletableGithubObject): self._dismiss_stale_reviews: Attribute[bool] = NotSet self._require_code_owner_reviews: Attribute[bool] = NotSet self._required_approving_review_count: Attribute[int] = NotSet - self._users: Attribute[NamedUser] = NotSet - self._teams: Attribute[Team] = NotSet + self._users: Attribute[list[NamedUser]] = NotSet + self._teams: Attribute[list[Team]] = NotSet def __repr__(self): return self.get__repr__( @@ -76,12 +75,12 @@ class RequiredPullRequestReviews(github.GithubObject.CompletableGithubObject): return self._url.value @property - def dismissal_users(self) -> NamedUser: + def dismissal_users(self) -> list[NamedUser]: self._completeIfNotSet(self._users) return self._users.value @property - def dismissal_teams(self) -> Team: + def dismissal_teams(self) -> list[Team]: self._completeIfNotSet(self._teams) return self._teams.value diff --git a/github/Stargazer.py b/github/Stargazer.py index eeee4b35..63391398 100644 --- a/github/Stargazer.py +++ b/github/Stargazer.py @@ -28,7 +28,7 @@ from __future__ import annotations from datetime import datetime from typing import TYPE_CHECKING -import github +import github.NamedUser from github.GithubObject import Attribute, NonCompletableGithubObject, NotSet if TYPE_CHECKING: @@ -46,7 +46,9 @@ class Stargazer(NonCompletableGithubObject): self._url: Attribute[str] = NotSet def __repr__(self): - return self.get__repr__({"user": self._user.value._login.value}) + # this is not a type error, just we didn't type `NamedUser` yet. + # enable type checker here after we typed attribute of `NamedUser` + return self.get__repr__({"user": self._user.value._login.value}) # type: ignore @property def starred_at(self) -> datetime: diff --git a/pyproject.toml b/pyproject.toml index 96e69ccb..b4e3163f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,14 @@ +[tool.mypy] +python_version = '3.7' +ignore_missing_imports = true +namespace_packages = true + +[[tool.mypy.overrides]] +module = ["github.*"] +check_untyped_defs = true +# TODO: enable this later +# disallow_untyped_defs = true + [tool.black] # https://github.com/psf/black line-length = 120 diff --git a/tox.ini b/tox.ini index 1e6c0489..88c1cb55 100644 --- a/tox.ini +++ b/tox.ini @@ -40,8 +40,3 @@ commands = sphinx-build doc build max-line-length = 120 select = C,E,F,W ignore = E266, E501, W503 - -[mypy] -python_version = 3.7 -ignore_missing_imports = True -namespace_packages = True