Skip to content

Commit

Permalink
test: add pylint linter (#248)
Browse files Browse the repository at this point in the history
* chore: add pylint linter

* refactor: fix linting errors

* docs: fix incomplete docstring
  • Loading branch information
jooola authored Sep 12, 2023
1 parent 4374a7b commit f238c2e
Show file tree
Hide file tree
Showing 21 changed files with 96 additions and 24 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ venv:
venv/bin/pip install -e .[docs,test]

lint: venv
venv/bin/pylint hcloud
venv/bin/mypy hcloud

test: venv
Expand Down
2 changes: 1 addition & 1 deletion hcloud/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def __init__(
poll_interval: int = 1,
timeout: float | tuple[float, float] | None = None,
):
"""Create an new Client instance
"""Create a new Client instance
:param token: Hetzner Cloud API token
:param api_endpoint: Hetzner Cloud API endpoint
Expand Down
1 change: 1 addition & 0 deletions hcloud/actions/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def wait_until_finished(self, max_retries: int = 100) -> None:
while self.status == Action.STATUS_RUNNING:
if max_retries > 0:
self.reload()
# pylint: disable=protected-access
time.sleep(self._client._client.poll_interval)
max_retries = max_retries - 1
else:
Expand Down
1 change: 1 addition & 0 deletions hcloud/core/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def _iter_pages( # type: ignore[no-untyped-def]

def _get_first_by(self, **kwargs): # type: ignore[no-untyped-def]
assert hasattr(self, "get_list")
# pylint: disable=no-member
entities, _ = self.get_list(**kwargs)
return entities[0] if entities else None

Expand Down
14 changes: 11 additions & 3 deletions hcloud/core/domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ class BaseDomain:

@classmethod
def from_dict(cls, data: dict): # type: ignore[no-untyped-def]
"""
Build the domain object from the data dict.
"""
supported_data = {k: v for k, v in data.items() if k in cls.__slots__}
return cls(**supported_data)

Expand All @@ -22,12 +25,14 @@ class DomainIdentityMixin:

@property
def id_or_name(self) -> int | str:
"""
Return the first defined value, and fails if none is defined.
"""
if self.id is not None:
return self.id
elif self.name is not None:
if self.name is not None:
return self.name
else:
raise ValueError("id or name must be set")
raise ValueError("id or name must be set")


class Pagination(BaseDomain):
Expand Down Expand Up @@ -65,6 +70,9 @@ def __init__(self, pagination: Pagination | None = None):

@classmethod
def parse_meta(cls, response: dict) -> Meta | None:
"""
If present, extract the meta details from the response and return a meta object.
"""
meta = None
if response and "meta" in response:
meta = cls()
Expand Down
25 changes: 14 additions & 11 deletions hcloud/firewalls/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,29 +39,32 @@ def __init__(self, client: FirewallsClient, data: dict, complete: bool = True):

applied_to = data.get("applied_to", [])
if applied_to:
# pylint: disable=import-outside-toplevel
from ..servers import BoundServer

ats = []
for a in applied_to:
if a["type"] == FirewallResource.TYPE_SERVER:
ats.append(
data_applied_to = []
for firewall_resource in applied_to:
if firewall_resource["type"] == FirewallResource.TYPE_SERVER:
data_applied_to.append(
FirewallResource(
type=a["type"],
type=firewall_resource["type"],
server=BoundServer(
client._client.servers, a["server"], complete=False
client._client.servers,
firewall_resource["server"],
complete=False,
),
)
)
elif a["type"] == FirewallResource.TYPE_LABEL_SELECTOR:
ats.append(
elif firewall_resource["type"] == FirewallResource.TYPE_LABEL_SELECTOR:
data_applied_to.append(
FirewallResource(
type=a["type"],
type=firewall_resource["type"],
label_selector=FirewallResourceLabelSelector(
selector=a["label_selector"]["selector"]
selector=firewall_resource["label_selector"]["selector"]
),
)
)
data["applied_to"] = ats
data["applied_to"] = data_applied_to

super().__init__(client, data, complete)

Expand Down
6 changes: 6 additions & 0 deletions hcloud/firewalls/domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ def __init__(
self.description = description

def to_payload(self) -> dict[str, Any]:
"""
Generates the request payload from this domain object.
"""
payload: dict[str, Any] = {
"direction": self.direction,
"protocol": self.protocol,
Expand Down Expand Up @@ -151,6 +154,9 @@ def __init__(
self.label_selector = label_selector

def to_payload(self) -> dict[str, Any]:
"""
Generates the request payload from this domain object.
"""
payload: dict[str, Any] = {"type": self.type}
if self.server is not None:
payload["server"] = {"id": self.server.id}
Expand Down
1 change: 1 addition & 0 deletions hcloud/floating_ips/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class BoundFloatingIP(BoundModelBase):
model = FloatingIP

def __init__(self, client: FloatingIPsClient, data: dict, complete: bool = True):
# pylint: disable=import-outside-toplevel
from ..servers import BoundServer

server = data.get("server")
Expand Down
1 change: 1 addition & 0 deletions hcloud/hcloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@
stacklevel=2,
)

# pylint: disable=wildcard-import,wrong-import-position,unused-wildcard-import
from ._client import * # noqa
22 changes: 14 additions & 8 deletions hcloud/helpers/labels.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ def validate(labels: dict[str, str]) -> bool:
:return: bool
"""
for k, v in labels.items():
if LabelValidator.KEY_REGEX.match(k) is None:
for key, value in labels.items():
if LabelValidator.KEY_REGEX.match(key) is None:
return False
if LabelValidator.VALUE_REGEX.match(v) is None:
if LabelValidator.VALUE_REGEX.match(value) is None:
return False
return True

Expand All @@ -32,9 +32,15 @@ def validate_verbose(labels: dict[str, str]) -> tuple[bool, str]:
:return: bool, str
"""
for k, v in labels.items():
if LabelValidator.KEY_REGEX.match(k) is None:
return False, f"label key {k} is not correctly formatted"
if LabelValidator.VALUE_REGEX.match(v) is None:
return False, f"label value {v} (key: {k}) is not correctly formatted"
for key, value in labels.items():
if LabelValidator.KEY_REGEX.match(key) is None:
return (
False,
f"label key {key} is not correctly formatted",
)
if LabelValidator.VALUE_REGEX.match(value) is None:
return (
False,
f"label value {value} (key: {key}) is not correctly formatted",
)
return True, ""
1 change: 1 addition & 0 deletions hcloud/images/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class BoundImage(BoundModelBase):
model = Image

def __init__(self, client: ImagesClient, data: dict):
# pylint: disable=import-outside-toplevel
from ..servers import BoundServer

created_from = data.get("created_from")
Expand Down
1 change: 1 addition & 0 deletions hcloud/images/domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class Image(BaseDomain, DomainIdentityMixin):
"deprecated",
)

# pylint: disable=too-many-locals
def __init__(
self,
id: int | None = None,
Expand Down
1 change: 1 addition & 0 deletions hcloud/load_balancers/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class BoundLoadBalancer(BoundModelBase):

model = LoadBalancer

# pylint: disable=too-many-branches,too-many-locals
def __init__(self, client: LoadBalancersClient, data: dict, complete: bool = True):
algorithm = data.get("algorithm")
if algorithm:
Expand Down
8 changes: 8 additions & 0 deletions hcloud/load_balancers/domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class LoadBalancer(BaseDomain):
"included_traffic",
)

# pylint: disable=too-many-locals
def __init__(
self,
id: int,
Expand Down Expand Up @@ -137,7 +138,11 @@ def __init__(
self.health_check = health_check
self.http = http

# pylint: disable=too-many-branches
def to_payload(self) -> dict[str, Any]:
"""
Generates the request payload from this domain object.
"""
payload: dict[str, Any] = {}

if self.protocol is not None:
Expand Down Expand Up @@ -334,6 +339,9 @@ def __init__(
self.health_status = health_status

def to_payload(self) -> dict[str, Any]:
"""
Generates the request payload from this domain object.
"""
payload: dict[str, Any] = {
"type": self.type,
}
Expand Down
1 change: 1 addition & 0 deletions hcloud/networks/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def __init__(self, client: NetworksClient, data: dict, complete: bool = True):
routes = [NetworkRoute.from_dict(route) for route in routes]
data["routes"] = routes

# pylint: disable=import-outside-toplevel
from ..servers import BoundServer

servers = data.get("servers", [])
Expand Down
1 change: 1 addition & 0 deletions hcloud/primary_ips/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class BoundPrimaryIP(BoundModelBase):
model = PrimaryIP

def __init__(self, client: PrimaryIPsClient, data: dict, complete: bool = True):
# pylint: disable=import-outside-toplevel
from ..datacenters import BoundDatacenter

datacenter = data.get("datacenter", {})
Expand Down
2 changes: 2 additions & 0 deletions hcloud/servers/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class BoundServer(BoundModelBase):

model = Server

# pylint: disable=too-many-locals
def __init__(self, client: ServersClient, data: dict, complete: bool = True):
datacenter = data.get("datacenter")
if datacenter is not None:
Expand Down Expand Up @@ -540,6 +541,7 @@ def get_by_name(self, name: str) -> BoundServer | None:
"""
return self._get_first_by(name=name)

# pylint: disable=too-many-branches,too-many-locals
def create(
self,
name: str,
Expand Down
1 change: 1 addition & 0 deletions hcloud/servers/domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ class Server(BaseDomain):
"placement_group",
)

# pylint: disable=too-many-locals
def __init__(
self,
id: int,
Expand Down
3 changes: 2 additions & 1 deletion hcloud/volumes/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def __init__(self, client: VolumesClient, data: dict, complete: bool = True):
if location is not None:
data["location"] = BoundLocation(client._client.locations, location)

# pylint: disable=import-outside-toplevel
from ..servers import BoundServer

server = data.get("server")
Expand Down Expand Up @@ -254,7 +255,7 @@ def create(
if size <= 0:
raise ValueError("size must be greater than 0")

if not (bool(location) ^ bool(server)):
if not bool(location) ^ bool(server):
raise ValueError("only one of server or location must be provided")

data: dict[str, Any] = {"name": name, "size": size}
Expand Down
26 changes: 26 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,29 @@ source = ["hcloud"]
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

[tool.pylint.main]
py-version = "3.8"
recursive = true
jobs = 0

[tool.pylint.reports]
output-format = "colorized"

[tool.pylint.basic]
good-names = ["i", "j", "k", "ex", "_", "ip", "id"]

[tool.pylint."messages control"]
disable = [
"fixme",
"line-too-long",
"missing-class-docstring",
"missing-module-docstring",
"redefined-builtin",
# Consider disabling line-by-line
"too-few-public-methods",
"too-many-public-methods",
"too-many-arguments",
"too-many-instance-attributes",
"too-many-lines",
]
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
],
"test": [
"coverage>=7.3,<7.4",
"pylint>=2.17.4,<2.18",
"pytest>=7.4,<7.5",
"mypy>=1.5,<1.6",
"types-python-dateutil",
Expand Down

0 comments on commit f238c2e

Please sign in to comment.