Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add pylint linter #248

Merged
merged 3 commits into from
Sep 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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