From 593baef5de3fed93a45709be0c8bcfd359c138b3 Mon Sep 17 00:00:00 2001 From: Adrian Huber Date: Tue, 10 Aug 2021 14:28:20 +0200 Subject: [PATCH] Fix crash on extra fields in response (#142) * Fix crash on extra fields in public_net response * Run black for code formatting * Update CHANGELOG --- .github/workflows/code_style.yml | 5 +- .github/workflows/unit_test.yml | 1 + .gitlab-ci.yml | 10 +- CHANGELOG.rst | 5 + docs/conf.py | 57 +- examples/create_server.py | 8 +- examples/list_servers.py | 4 +- examples/usage_oop.py | 20 +- examples/usage_procedurale.py | 28 +- hcloud/__version__.py | 2 +- hcloud/actions/client.py | 27 +- hcloud/actions/domain.py | 21 +- hcloud/certificates/client.py | 128 +-- hcloud/certificates/domain.py | 37 +- hcloud/core/client.py | 51 +- hcloud/core/domain.py | 25 +- hcloud/datacenters/client.py | 63 +- hcloud/datacenters/domain.py | 15 +- hcloud/firewalls/client.py | 243 +++-- hcloud/firewalls/domain.py | 67 +- hcloud/floating_ips/client.py | 217 +++-- hcloud/floating_ips/domain.py | 17 +- hcloud/hcloud.py | 52 +- hcloud/images/client.py | 158 ++-- hcloud/images/domain.py | 49 +- hcloud/isos/client.py | 27 +- hcloud/isos/domain.py | 8 +- hcloud/load_balancer_types/client.py | 26 +- hcloud/load_balancer_types/domain.py | 20 +- hcloud/load_balancers/client.py | 371 +++++--- hcloud/load_balancers/domain.py | 225 +++-- hcloud/locations/client.py | 13 +- hcloud/locations/domain.py | 20 +- hcloud/networks/client.py | 123 ++- hcloud/networks/domain.py | 33 +- hcloud/server_types/client.py | 23 +- hcloud/server_types/domain.py | 5 +- hcloud/servers/client.py | 475 ++++++---- hcloud/servers/domain.py | 197 ++-- hcloud/ssh_keys/client.py | 71 +- hcloud/ssh_keys/domain.py | 12 +- hcloud/volumes/client.py | 149 ++-- hcloud/volumes/domain.py | 43 +- requirements/test.txt | 1 + setup.py | 53 +- tests/unit/actions/conftest.py | 62 +- tests/unit/actions/test_client.py | 55 +- tests/unit/actions/test_domain.py | 13 +- tests/unit/certificates/conftest.py | 119 +-- tests/unit/certificates/test_client.py | 183 ++-- tests/unit/certificates/test_domain.py | 20 +- tests/unit/conftest.py | 16 +- tests/unit/core/test_client.py | 113 ++- tests/unit/core/test_domain.py | 57 +- tests/unit/datacenters/conftest.py | 92 +- tests/unit/datacenters/test_client.py | 39 +- tests/unit/firewalls/conftest.py | 180 +--- tests/unit/firewalls/test_client.py | 300 ++++--- tests/unit/firewalls/test_domain.py | 5 +- tests/unit/floating_ips/conftest.py | 118 +-- tests/unit/floating_ips/test_client.py | 211 +++-- tests/unit/floating_ips/test_domain.py | 5 +- tests/unit/images/conftest.py | 69 +- tests/unit/images/test_client.py | 145 +-- tests/unit/images/test_domain.py | 5 +- tests/unit/isos/conftest.py | 10 +- tests/unit/isos/test_client.py | 41 +- tests/unit/isos/test_domain.py | 5 +- tests/unit/load_balancer_types/conftest.py | 42 +- tests/unit/load_balancer_types/test_client.py | 54 +- tests/unit/load_balancers/conftest.py | 396 +++----- tests/unit/load_balancers/test_client.py | 372 +++++--- tests/unit/load_balancers/test_domain.py | 5 +- tests/unit/locations/conftest.py | 5 +- tests/unit/locations/test_client.py | 27 +- tests/unit/networks/conftest.py | 140 +-- tests/unit/networks/test_client.py | 323 ++++--- tests/unit/networks/test_domain.py | 5 +- tests/unit/server_types/conftest.py | 42 +- tests/unit/server_types/test_client.py | 27 +- tests/unit/servers/conftest.py | 843 ++++++------------ tests/unit/servers/test_client.py | 663 +++++++++----- tests/unit/servers/test_domain.py | 5 +- tests/unit/ssh_keys/conftest.py | 12 +- tests/unit/ssh_keys/test_client.py | 90 +- tests/unit/ssh_keys/test_domain.py | 5 +- tests/unit/test_hcloud.py | 85 +- tests/unit/volumes/conftest.py | 88 +- tests/unit/volumes/test_client.py | 195 ++-- tests/unit/volumes/test_domain.py | 5 +- tox.ini | 5 + 91 files changed, 4519 insertions(+), 3983 deletions(-) diff --git a/.github/workflows/code_style.yml b/.github/workflows/code_style.yml index 32b0307..132aa94 100644 --- a/.github/workflows/code_style.yml +++ b/.github/workflows/code_style.yml @@ -17,5 +17,8 @@ jobs: python -m pip install --upgrade pip pip install -r requirements/test.txt pip install tox tox-gh-actions - - name: Test with tox + sudo apt install build-essential + - name: flake8 with tox run: tox -e flake8 + - name: black with tox + run: tox -e black diff --git a/.github/workflows/unit_test.yml b/.github/workflows/unit_test.yml index a29c986..ba7c79f 100644 --- a/.github/workflows/unit_test.yml +++ b/.github/workflows/unit_test.yml @@ -21,6 +21,7 @@ jobs: python -m pip install --upgrade pip pip install -r requirements/test.txt pip install tox tox-gh-actions + sudo apt install build-essential - name: Test with tox run: tox env: diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 64e1a75..c64963f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,6 +4,7 @@ stages: .tests_template: &tests_template before_script: - pip install tox + - apk add build-base stage: test script: tox @@ -36,9 +37,8 @@ python310: script: tox -e py310 test-style: - before_script: - - pip install tox + <<: *tests_template image: python:3.7-alpine - script: tox -e flake8 - tags: - - hc-bladerunner + script: + - tox -e flake8 + - tox -e black diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 32951b8..e451a44 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,11 @@ History ======= +v1.14.1 (2021-08-10) +--------------------- +* Bugfix: Fix crash on extra fields in public_net response +* Improvement: Format code with black + v1.14.0 (2021-08-03) --------------------- * Feature: Add support for Firewall rule descriptions diff --git a/docs/conf.py b/docs/conf.py index 5902a3e..6ec4f48 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -21,7 +21,7 @@ import os import sys -sys.path.insert(0, os.path.abspath('..')) +sys.path.insert(0, os.path.abspath("..")) from hcloud.__version__ import VERSION # noqa # -- General configuration --------------------------------------------- @@ -32,10 +32,10 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] +extensions = ["sphinx.ext.autodoc", "sphinx.ext.viewcode"] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: @@ -44,10 +44,10 @@ # source_suffix = '.rst' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'Hetzner Cloud Python' +project = u"Hetzner Cloud Python" copyright = u"2019, Hetzner Cloud GmbH" author = u"Hetzner Cloud GmbH" @@ -70,10 +70,10 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False @@ -87,25 +87,25 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'sphinx_rtd_theme' -html_logo = '_static/logo-hetzner-online.svg' +html_theme = "sphinx_rtd_theme" +html_logo = "_static/logo-hetzner-online.svg" # Theme options are theme-specific and customize the look and feel of a # theme further. For a list of options available for each theme, see the # documentation. # html_theme_options = { - 'logo_only': True, + "logo_only": True, } # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # -- Options for HTMLHelp output --------------------------------------- # Output file base name for HTML help builder. -htmlhelp_basename = 'hclouddoc' +htmlhelp_basename = "hclouddoc" # -- Options for LaTeX output ------------------------------------------ @@ -113,15 +113,12 @@ # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # # 'preamble': '', - # Latex figure (float) alignment # # 'figure_align': 'htbp', @@ -131,20 +128,20 @@ # (source start file, target name, title, author, documentclass # [howto, manual, or own class]). latex_documents = [ - (master_doc, 'hcloud.tex', - u'Hetzner Cloud Python Documentation', - u'Hetzner Cloud GmbH', 'manual'), + ( + master_doc, + "hcloud.tex", + u"Hetzner Cloud Python Documentation", + u"Hetzner Cloud GmbH", + "manual", + ), ] # -- Options for manual page output ------------------------------------ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, - u'Hetzner Cloud Python Documentation', - [author], 1) -] +man_pages = [(master_doc, u"Hetzner Cloud Python Documentation", [author], 1)] # -- Options for Texinfo output ---------------------------------------- @@ -152,11 +149,13 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, - u'Hetzner Cloud Python Documentation', - author, - 'HCloud-python is a library for the Hetzner Cloud API.', - 'Miscellaneous'), + ( + master_doc, + u"Hetzner Cloud Python Documentation", + author, + "HCloud-python is a library for the Hetzner Cloud API.", + "Miscellaneous", + ), ] -source_suffix = ['.rst'] +source_suffix = [".rst"] diff --git a/examples/create_server.py b/examples/create_server.py index 7e91af1..2aaae82 100644 --- a/examples/create_server.py +++ b/examples/create_server.py @@ -2,8 +2,12 @@ from hcloud.images.domain import Image from hcloud.server_types.domain import ServerType -client = Client(token="{YOUR_API_TOKEN}") # Please paste your API token here between the quotes -response = client.servers.create(name="my-server", server_type=ServerType("cx11"), image=Image(name="ubuntu-20.04")) +client = Client( + token="{YOUR_API_TOKEN}" +) # Please paste your API token here between the quotes +response = client.servers.create( + name="my-server", server_type=ServerType("cx11"), image=Image(name="ubuntu-20.04") +) server = response.server print(server) print("Root Password" + response.root_password) diff --git a/examples/list_servers.py b/examples/list_servers.py index 61d074e..9e34e5c 100644 --- a/examples/list_servers.py +++ b/examples/list_servers.py @@ -1,5 +1,7 @@ from hcloud import Client -client = Client(token="{YOUR_API_TOKEN}") # Please paste your API token here between the quotes +client = Client( + token="{YOUR_API_TOKEN}" +) # Please paste your API token here between the quotes servers = client.servers.get_all() print(servers) diff --git a/examples/usage_oop.py b/examples/usage_oop.py index 992b1d5..f246052 100644 --- a/examples/usage_oop.py +++ b/examples/usage_oop.py @@ -8,15 +8,11 @@ # Create 2 servers # Create 2 servers response1 = client.servers.create( - "Server1", - server_type=ServerType(name="cx11"), - image=Image(id=4711) + "Server1", server_type=ServerType(name="cx11"), image=Image(id=4711) ) response2 = client.servers.create( - "Server2", - server_type=ServerType(name="cx11"), - image=Image(id=4711) + "Server2", server_type=ServerType(name="cx11"), image=Image(id=4711) ) # Get all servers server1 = response1.server @@ -28,16 +24,8 @@ assert servers[1].id == server2.id # Create 2 volumes -response1 = client.volumes.create( - size=15, - name="Volume1", - location=server1.location -) -response2 = client.volumes.create( - size=10, - name="Volume2", - location=server2.location -) +response1 = client.volumes.create(size=15, name="Volume1", location=server1.location) +response2 = client.volumes.create(size=10, name="Volume2", location=server2.location) volume1 = response1.volume volume2 = response2.volume diff --git a/examples/usage_procedurale.py b/examples/usage_procedurale.py index 3a5c54b..b49f780 100644 --- a/examples/usage_procedurale.py +++ b/examples/usage_procedurale.py @@ -9,15 +9,11 @@ # Create 2 servers response1 = client.servers.create( - name="Server1", - server_type=ServerType(name="cx11"), - image=Image(id=4711) + name="Server1", server_type=ServerType(name="cx11"), image=Image(id=4711) ) response2 = client.servers.create( - "Server2", - server_type=ServerType(name="cx11"), - image=Image(id=4711) + "Server2", server_type=ServerType(name="cx11"), image=Image(id=4711) ) server1 = response1.server @@ -32,16 +28,8 @@ # Create 2 volumes -response1 = client.volumes.create( - size=15, - name="Volume1", - location=server1.location -) -response2 = client.volumes.create( - size=10, - name="Volume2", - location=server2.location -) +response1 = client.volumes.create(size=15, name="Volume1", location=server1.location) +response2 = client.volumes.create(size=10, name="Volume2", location=server2.location) volume1 = response1.volume volume2 = response2.volume @@ -61,11 +49,7 @@ # Create one more volume and attach it to server with id=33 server33 = Server(id=33) -response = client.volumes.create( - size=33, - name="Volume33", - server=server33 -) +response = client.volumes.create(size=33, name="Volume33", server=server33) print(response.action.status) @@ -74,5 +58,5 @@ "Server3", server_type=ServerType(name="cx11"), image=Image(id=4711), - volumes = [Volume(id=221), Volume(id=222)] + volumes=[Volume(id=221), Volume(id=222)], ) diff --git a/hcloud/__version__.py b/hcloud/__version__.py index 9fb1be8..cfa2a19 100644 --- a/hcloud/__version__.py +++ b/hcloud/__version__.py @@ -1 +1 @@ -VERSION = '1.13.0' +VERSION = "1.13.0" diff --git a/hcloud/actions/client.py b/hcloud/actions/client.py index 91e7d9b..70fa0bb 100644 --- a/hcloud/actions/client.py +++ b/hcloud/actions/client.py @@ -29,7 +29,7 @@ def wait_until_finished(self, max_retries=100): class ActionsClient(ClientEntityBase): - results_list_attribute_name = 'actions' + results_list_attribute_name = "actions" def get_by_id(self, id): # type: (int) -> BoundAction @@ -39,15 +39,18 @@ def get_by_id(self, id): :return: :class:`BoundAction ` """ - response = self._client.request(url="/actions/{action_id}".format(action_id=id), method="GET") - return BoundAction(self, response['action']) - - def get_list(self, - status=None, # type: Optional[List[str]] - sort=None, # type: Optional[List[str]] - page=None, # type: Optional[int] - per_page=None, # type: Optional[int] - ): + response = self._client.request( + url="/actions/{action_id}".format(action_id=id), method="GET" + ) + return BoundAction(self, response["action"]) + + def get_list( + self, + status=None, # type: Optional[List[str]] + sort=None, # type: Optional[List[str]] + page=None, # type: Optional[int] + per_page=None, # type: Optional[int] + ): # type: (...) -> PageResults[List[BoundAction]] """Get a list of actions from this account @@ -72,7 +75,9 @@ def get_list(self, params["per_page"] = per_page response = self._client.request(url="/actions", method="GET", params=params) - actions = [BoundAction(self, action_data) for action_data in response['actions']] + actions = [ + BoundAction(self, action_data) for action_data in response["actions"] + ] return self._add_meta_to_result(actions, response) def get_all(self, status=None, sort=None): diff --git a/hcloud/actions/domain.py b/hcloud/actions/domain.py index 352991d..e40c62a 100644 --- a/hcloud/actions/domain.py +++ b/hcloud/actions/domain.py @@ -16,6 +16,7 @@ class Action(BaseDomain): :param resources: Resources the action relates to :param error: Error message for the action if error occurred, otherwise None. """ + STATUS_RUNNING = "running" """Action Status running""" STATUS_SUCCESS = "success" @@ -31,19 +32,19 @@ class Action(BaseDomain): "resources", "error", "started", - "finished" + "finished", ) def __init__( - self, - id, - command=None, - status=None, - progress=None, - started=None, - finished=None, - resources=None, - error=None + self, + id, + command=None, + status=None, + progress=None, + started=None, + finished=None, + resources=None, + error=None, ): self.id = id self.command = command diff --git a/hcloud/certificates/client.py b/hcloud/certificates/client.py index bdadb62..d94e550 100644 --- a/hcloud/certificates/client.py +++ b/hcloud/certificates/client.py @@ -2,7 +2,12 @@ from hcloud.actions.client import BoundAction from hcloud.core.client import ClientEntityBase, BoundModelBase, GetEntityByNameMixin -from hcloud.certificates.domain import Certificate, CreateManagedCertificateResponse, ManagedCertificateStatus, ManagedCertificateError +from hcloud.certificates.domain import ( + Certificate, + CreateManagedCertificateResponse, + ManagedCertificateStatus, + ManagedCertificateError, +) from hcloud.core.domain import add_meta_to_result @@ -10,16 +15,17 @@ class BoundCertificate(BoundModelBase): model = Certificate def __init__(self, client, data, complete=True): - status = data.get('status') + status = data.get("status") if status is not None: - error_data = status.get('error') + error_data = status.get("error") error = None if error_data: - error = ManagedCertificateError(code=error_data['code'], message=error_data['message']) - data['status'] = ManagedCertificateStatus( - issuance=status['issuance'], - renewal=status['renewal'], - error=error) + error = ManagedCertificateError( + code=error_data["code"], message=error_data["message"] + ) + data["status"] = ManagedCertificateStatus( + issuance=status["issuance"], renewal=status["renewal"], error=error + ) super(BoundCertificate, self).__init__(client, data, complete) def get_actions_list(self, status=None, sort=None, page=None, per_page=None): @@ -65,20 +71,20 @@ def update(self, name=None, labels=None): def delete(self): # type: () -> bool """Deletes a certificate. - :return: boolean + :return: boolean """ return self._client.delete(self) def retry_issuance(self): # type: () -> BoundAction """Retry a failed Certificate issuance or renewal. - :return: BoundAction + :return: BoundAction """ return self._client.retry_issuance(self) class CertificatesClient(ClientEntityBase, GetEntityByNameMixin): - results_list_attribute_name = 'certificates' + results_list_attribute_name = "certificates" def get_by_id(self, id): # type: (int) -> BoundCertificate @@ -87,15 +93,18 @@ def get_by_id(self, id): :param id: int :return: :class:`BoundCertificate ` """ - response = self._client.request(url="/certificates/{certificate_id}".format(certificate_id=id), method="GET") - return BoundCertificate(self, response['certificate']) - - def get_list(self, - name=None, # type: Optional[str] - label_selector=None, # type: Optional[str] - page=None, # type: Optional[int] - per_page=None # type: Optional[int] - ): + response = self._client.request( + url="/certificates/{certificate_id}".format(certificate_id=id), method="GET" + ) + return BoundCertificate(self, response["certificate"]) + + def get_list( + self, + name=None, # type: Optional[str] + label_selector=None, # type: Optional[str] + page=None, # type: Optional[int] + per_page=None, # type: Optional[int] + ): # type: (...) -> PageResults[List[BoundCertificate], Meta] """Get a list of certificates @@ -117,14 +126,19 @@ def get_list(self, params["label_selector"] = label_selector if page is not None: - params['page'] = page + params["page"] = page if per_page is not None: - params['per_page'] = per_page + params["per_page"] = per_page - response = self._client.request(url="/certificates", method="GET", params=params) + response = self._client.request( + url="/certificates", method="GET", params=params + ) - certificates = [BoundCertificate(self, certificate_data) for certificate_data in response['certificates']] + certificates = [ + BoundCertificate(self, certificate_data) + for certificate_data in response["certificates"] + ] return self._add_meta_to_result(certificates, response) @@ -138,7 +152,9 @@ def get_all(self, name=None, label_selector=None): Can be used to filter certificates by labels. The response will only contain certificates matching the label selector. :return: List[:class:`BoundCertificate `] """ - return super(CertificatesClient, self).get_all(name=name, label_selector=label_selector) + return super(CertificatesClient, self).get_all( + name=name, label_selector=label_selector + ) def get_by_name(self, name): # type: (str) -> BoundCertificate @@ -165,15 +181,15 @@ def create(self, name, certificate, private_key, labels=None): :return: :class:`BoundCertificate ` """ data = { - 'name': name, - 'certificate': certificate, - 'private_key': private_key, - 'type': Certificate.TYPE_UPLOADED + "name": name, + "certificate": certificate, + "private_key": private_key, + "type": Certificate.TYPE_UPLOADED, } if labels is not None: - data['labels'] = labels + data["labels"] = labels response = self._client.request(url="/certificates", method="POST", json=data) - return BoundCertificate(self, response['certificate']) + return BoundCertificate(self, response["certificate"]) def create_managed(self, name, domain_names, labels=None): # type: (str, List[str], Optional[Dict[str, str]]) -> CreateManagedCertificateResponse @@ -188,15 +204,17 @@ def create_managed(self, name, domain_names, labels=None): :return: :class:`BoundCertificate ` """ data = { - 'name': name, - 'type': Certificate.TYPE_MANAGED, - 'domain_names': domain_names + "name": name, + "type": Certificate.TYPE_MANAGED, + "domain_names": domain_names, } if labels is not None: - data['labels'] = labels + data["labels"] = labels response = self._client.request(url="/certificates", method="POST", json=data) - return CreateManagedCertificateResponse(certificate=BoundCertificate(self, response['certificate']), - action=BoundAction(self._client.actions, response['action'])) + return CreateManagedCertificateResponse( + certificate=BoundCertificate(self, response["certificate"]), + action=BoundAction(self._client.actions, response["action"]), + ) def update(self, certificate, name=None, labels=None): # type: (Certificate, Optional[str], Optional[Dict[str, str]]) -> BoundCertificate @@ -211,18 +229,22 @@ def update(self, certificate, name=None, labels=None): """ data = {} if name is not None: - data['name'] = name + data["name"] = name if labels is not None: - data['labels'] = labels - response = self._client.request(url="/certificates/{certificate_id}".format(certificate_id=certificate.id), - method="PUT", - json=data) - return BoundCertificate(self, response['certificate']) + data["labels"] = labels + response = self._client.request( + url="/certificates/{certificate_id}".format(certificate_id=certificate.id), + method="PUT", + json=data, + ) + return BoundCertificate(self, response["certificate"]) def delete(self, certificate): # type: (Certificate) -> bool - self._client.request(url="/certificates/{certificate_id}".format(certificate_id=certificate.id), - method="DELETE") + self._client.request( + url="/certificates/{certificate_id}".format(certificate_id=certificate.id), + method="DELETE", + ) """Deletes a certificate. :param certificate: :class:`BoundCertificate ` or :class:`Certificate ` @@ -232,7 +254,7 @@ def delete(self, certificate): return True def get_actions_list( - self, certificate, status=None, sort=None, page=None, per_page=None + self, certificate, status=None, sort=None, page=None, per_page=None ): # type: (Certificate, Optional[List[str]], Optional[List[str]], Optional[int], Optional[int]) -> PageResults[List[BoundAction], Meta] """Returns all action objects for a Certificate. @@ -259,7 +281,9 @@ def get_actions_list( params["per_page"] = per_page response = self._client.request( - url="/certificates/{certificate_id}/actions".format(certificate_id=certificate.id), + url="/certificates/{certificate_id}/actions".format( + certificate_id=certificate.id + ), method="GET", params=params, ) @@ -291,6 +315,10 @@ def retry_issuance(self, certificate): :param certificate: :class:`BoundCertificate ` or :class:`Certificate ` :return: :class:`BoundAction ` """ - response = self._client.request(url="/certificates/{certificate_id}/actions/retry".format(certificate_id=certificate.id), - method="POST") - return BoundAction(self._client.actions, response['action']) + response = self._client.request( + url="/certificates/{certificate_id}/actions/retry".format( + certificate_id=certificate.id + ), + method="POST", + ) + return BoundAction(self._client.actions, response["action"]) diff --git a/hcloud/certificates/domain.py b/hcloud/certificates/domain.py index 483e0a1..bde10fe 100644 --- a/hcloud/certificates/domain.py +++ b/hcloud/certificates/domain.py @@ -23,6 +23,7 @@ class Certificate(BaseDomain, DomainIdentityMixin): :param type: str Type of Certificate :param status: ManagedCertificateStatus Current status of a type managed Certificate, always none for type uploaded Certificates """ + __slots__ = ( "id", "name", @@ -34,24 +35,24 @@ class Certificate(BaseDomain, DomainIdentityMixin): "created", "labels", "type", - "status" + "status", ) TYPE_UPLOADED = "uploaded" TYPE_MANAGED = "managed" def __init__( - self, - id=None, - name=None, - certificate=None, - not_valid_before=None, - not_valid_after=None, - domain_names=None, - fingerprint=None, - created=None, - labels=None, - type=None, - status=None, + self, + id=None, + name=None, + certificate=None, + not_valid_before=None, + not_valid_after=None, + domain_names=None, + fingerprint=None, + created=None, + labels=None, + type=None, + status=None, ): self.id = id self.name = name @@ -75,7 +76,7 @@ class ManagedCertificateStatus(BaseDomain): Status of the renewal process of the Certificate :param error: ManagedCertificateError If issuance or renewal reports failure, this property contains information about what happened - """ + """ def __init__(self, issuance=None, renewal=None, error=None): self.issuance = issuance @@ -91,6 +92,7 @@ class ManagedCertificateError(BaseDomain): :param message: Message detailing the error """ + def __init__(self, code=None, message=None): self.code = code self.message = message @@ -104,15 +106,16 @@ class CreateManagedCertificateResponse(BaseDomain): :param action: :class:`BoundAction ` Shows the progress of the certificate creation """ + __slots__ = ( "certificate", "action", ) def __init__( - self, - certificate, # type: BoundCertificate - action, # type: BoundAction + self, + certificate, # type: BoundCertificate + action, # type: BoundAction ): self.certificate = certificate self.action = action diff --git a/hcloud/core/client.py b/hcloud/core/client.py index 917a9cf..f024c9b 100644 --- a/hcloud/core/client.py +++ b/hcloud/core/client.py @@ -16,35 +16,46 @@ def __init__(self, client): def _is_list_attribute_implemented(self): if self.results_list_attribute_name is None: raise NotImplementedError( - "in order to get results list, 'results_list_attribute_name' attribute of {} has to be specified". format(self.__class__.__name__) + "in order to get results list, 'results_list_attribute_name' attribute of {} has to be specified".format( + self.__class__.__name__ + ) ) - def _add_meta_to_result(self, - results, # type: List[BoundModelBase] - response # type: json - ): + def _add_meta_to_result( + self, + results, # type: List[BoundModelBase] + response, # type: json + ): # type: (...) -> PageResult self._is_list_attribute_implemented() return add_meta_to_result(results, response, self.results_list_attribute_name) - def _get_all(self, - list_function, # type: function - results_list_attribute_name, # type: str - *args, - **kwargs - ): + def _get_all( + self, + list_function, # type: function + results_list_attribute_name, # type: str + *args, + **kwargs + ): # type (...) -> List[BoundModelBase] page = 1 results = [] while page: - page_result = list_function(page=page, per_page=self.max_per_page, *args, **kwargs) + page_result = list_function( + page=page, per_page=self.max_per_page, *args, **kwargs + ) result = getattr(page_result, results_list_attribute_name) if result: results.extend(result) meta = page_result.meta - if meta and meta.pagination and meta.pagination.next_page and meta.pagination.next_page: + if ( + meta + and meta.pagination + and meta.pagination.next_page + and meta.pagination.next_page + ): page = meta.pagination.next_page else: page = None @@ -54,14 +65,16 @@ def _get_all(self, def get_all(self, *args, **kwargs): # type: (...) -> List[BoundModelBase] self._is_list_attribute_implemented() - return self._get_all(self.get_list, self.results_list_attribute_name, *args, **kwargs) + return self._get_all( + self.get_list, self.results_list_attribute_name, *args, **kwargs + ) def get_actions(self, *args, **kwargs): # type: (...) -> List[BoundModelBase] - if not hasattr(self, 'get_actions_list'): - raise ValueError('this endpoint does not support get_actions method') + if not hasattr(self, "get_actions_list"): + raise ValueError("this endpoint does not support get_actions method") - return self._get_all(self.get_actions_list, 'actions', *args, **kwargs) + return self._get_all(self.get_actions_list, "actions", *args, **kwargs) class GetEntityByNameMixin(object): @@ -80,6 +93,7 @@ def get_by_name(self, name): class BoundModelBase(object): """Bound Model Base""" + model = None def __init__(self, client, data={}, complete=True): @@ -107,8 +121,7 @@ def __getattr__(self, name): return value def reload(self): - """Reloads the model and tries to get all data from the APIx - """ + """Reloads the model and tries to get all data from the APIx""" bound_model = self._client.get_by_id(self.data_model.id) self.data_model = bound_model.data_model self.complete = True diff --git a/hcloud/core/domain.py b/hcloud/core/domain.py index 9e6e2a6..1703ae2 100644 --- a/hcloud/core/domain.py +++ b/hcloud/core/domain.py @@ -34,7 +34,15 @@ class Pagination(BaseDomain): "total_entries", ) - def __init__(self, page, per_page, previous_page=None, next_page=None, last_page=None, total_entries=None): + def __init__( + self, + page, + per_page, + previous_page=None, + next_page=None, + last_page=None, + total_entries=None, + ): self.page = page self.per_page = per_page self.previous_page = previous_page @@ -45,9 +53,7 @@ def __init__(self, page, per_page, previous_page=None, next_page=None, last_page class Meta(BaseDomain): - __slots__ = ( - "pagination", - ) + __slots__ = ("pagination",) def __init__( self, @@ -60,7 +66,7 @@ def parse_meta(cls, json_content): meta = None if json_content and "meta" in json_content: meta = cls() - pagination_json = json_content['meta'].get("pagination") + pagination_json = json_content["meta"].get("pagination") if pagination_json: pagination = Pagination(**pagination_json) meta.pagination = pagination @@ -69,9 +75,6 @@ def parse_meta(cls, json_content): def add_meta_to_result(result, json_content, attr_name): # type: (List[BoundModelBase], json, string) -> PageResult - class_name = 'PageResults{0}'.format(attr_name.capitalize()) - PageResults = namedtuple(class_name, [attr_name, 'meta']) - return PageResults(**{ - attr_name: result, - 'meta': Meta.parse_meta(json_content) - }) + class_name = "PageResults{0}".format(attr_name.capitalize()) + PageResults = namedtuple(class_name, [attr_name, "meta"]) + return PageResults(**{attr_name: result, "meta": Meta.parse_meta(json_content)}) diff --git a/hcloud/datacenters/client.py b/hcloud/datacenters/client.py index 779ce56..7154890 100644 --- a/hcloud/datacenters/client.py +++ b/hcloud/datacenters/client.py @@ -12,24 +12,39 @@ class BoundDatacenter(BoundModelBase): def __init__(self, client, data): location = data.get("location") if location is not None: - data['location'] = BoundLocation(client._client.locations, location) + data["location"] = BoundLocation(client._client.locations, location) server_types = data.get("server_types") if server_types is not None: - available = [BoundServerType(client._client.server_types, {"id": server_type}, complete=False) for - server_type in server_types['available']] - supported = [BoundServerType(client._client.server_types, {"id": server_type}, complete=False) for - server_type in server_types['supported']] - available_for_migration = [BoundServerType(client._client.server_types, {"id": server_type}, complete=False) - for server_type in server_types['available_for_migration']] - data['server_types'] = DatacenterServerTypes(available=available, supported=supported, - available_for_migration=available_for_migration) + available = [ + BoundServerType( + client._client.server_types, {"id": server_type}, complete=False + ) + for server_type in server_types["available"] + ] + supported = [ + BoundServerType( + client._client.server_types, {"id": server_type}, complete=False + ) + for server_type in server_types["supported"] + ] + available_for_migration = [ + BoundServerType( + client._client.server_types, {"id": server_type}, complete=False + ) + for server_type in server_types["available_for_migration"] + ] + data["server_types"] = DatacenterServerTypes( + available=available, + supported=supported, + available_for_migration=available_for_migration, + ) super(BoundDatacenter, self).__init__(client, data) class DatacentersClient(ClientEntityBase, GetEntityByNameMixin): - results_list_attribute_name = 'datacenters' + results_list_attribute_name = "datacenters" def get_by_id(self, id): # type: (int) -> BoundDatacenter @@ -38,14 +53,17 @@ def get_by_id(self, id): :param id: int :return: :class:`BoundDatacenter ` """ - response = self._client.request(url="/datacenters/{datacenter_id}".format(datacenter_id=id), method="GET") - return BoundDatacenter(self, response['datacenter']) - - def get_list(self, - name=None, # type: Optional[str] - page=None, # type: Optional[int] - per_page=None # type: Optional[int] - ): + response = self._client.request( + url="/datacenters/{datacenter_id}".format(datacenter_id=id), method="GET" + ) + return BoundDatacenter(self, response["datacenter"]) + + def get_list( + self, + name=None, # type: Optional[str] + page=None, # type: Optional[int] + per_page=None, # type: Optional[int] + ): # type: (...) -> PageResults[List[BoundDatacenter], Meta] """Get a list of datacenters @@ -62,14 +80,17 @@ def get_list(self, params["name"] = name if page is not None: - params['page'] = page + params["page"] = page if per_page is not None: - params['per_page'] = per_page + params["per_page"] = per_page response = self._client.request(url="/datacenters", method="GET", params=params) - datacenters = [BoundDatacenter(self, datacenter_data) for datacenter_data in response['datacenters']] + datacenters = [ + BoundDatacenter(self, datacenter_data) + for datacenter_data in response["datacenters"] + ] return self._add_meta_to_result(datacenters, response) diff --git a/hcloud/datacenters/domain.py b/hcloud/datacenters/domain.py index aeea319..1335adc 100644 --- a/hcloud/datacenters/domain.py +++ b/hcloud/datacenters/domain.py @@ -11,6 +11,7 @@ class Datacenter(BaseDomain, DomainIdentityMixin): :param location: :class:`BoundLocation ` :param server_types: :class:`DatacenterServerTypes ` """ + __slots__ = ( "id", "name", @@ -20,12 +21,7 @@ class Datacenter(BaseDomain, DomainIdentityMixin): ) def __init__( - self, - id=None, - name=None, - description=None, - location=None, - server_types=None + self, id=None, name=None, description=None, location=None, server_types=None ): self.id = id self.name = name @@ -44,11 +40,8 @@ class DatacenterServerTypes: :param available_for_migration: List[:class:`BoundServerTypes `] All available for migration (change type) server types for this datacenter """ - __slots__ = ( - "available", - "supported", - "available_for_migration" - ) + + __slots__ = ("available", "supported", "available_for_migration") def __init__(self, available, supported, available_for_migration): self.available = available diff --git a/hcloud/firewalls/client.py b/hcloud/firewalls/client.py index c156d81..7679773 100644 --- a/hcloud/firewalls/client.py +++ b/hcloud/firewalls/client.py @@ -3,32 +3,59 @@ from hcloud.core.client import BoundModelBase, ClientEntityBase, GetEntityByNameMixin from hcloud.core.domain import add_meta_to_result -from hcloud.firewalls.domain import Firewall, CreateFirewallResponse, FirewallRule, FirewallResource, \ - FirewallResourceLabelSelector +from hcloud.firewalls.domain import ( + Firewall, + CreateFirewallResponse, + FirewallRule, + FirewallResource, + FirewallResourceLabelSelector, +) class BoundFirewall(BoundModelBase): model = Firewall def __init__(self, client, data, complete=True): - rules = data.get('rules', []) + rules = data.get("rules", []) if rules: - rules = [FirewallRule(direction=rule["direction"], source_ips=rule["source_ips"], - destination_ips=rule["destination_ips"], protocol=rule['protocol'], port=rule["port"], description=rule["description"]) - for rule in rules] - data['rules'] = rules - - applied_to = data.get('applied_to', []) + rules = [ + FirewallRule( + direction=rule["direction"], + source_ips=rule["source_ips"], + destination_ips=rule["destination_ips"], + protocol=rule["protocol"], + port=rule["port"], + description=rule["description"], + ) + for rule in rules + ] + data["rules"] = rules + + applied_to = data.get("applied_to", []) if applied_to: from hcloud.servers.client import BoundServer + ats = [] for a in applied_to: if a["type"] == FirewallResource.TYPE_SERVER: - ats.append(FirewallResource(type=a["type"], server=BoundServer(client._client.servers, a["server"], - complete=False))) + ats.append( + FirewallResource( + type=a["type"], + server=BoundServer( + client._client.servers, a["server"], complete=False + ), + ) + ) elif a["type"] == FirewallResource.TYPE_LABEL_SELECTOR: - ats.append(FirewallResource(type=a["type"], label_selector=FirewallResourceLabelSelector(selector=a['label_selector']['selector']))) - data['applied_to'] = ats + ats.append( + FirewallResource( + type=a["type"], + label_selector=FirewallResourceLabelSelector( + selector=a["label_selector"]["selector"] + ), + ) + ) + data["applied_to"] = ats super(BoundFirewall, self).__init__(client, data, complete) @@ -108,15 +135,16 @@ def remove_from_resources(self, resources): class FirewallsClient(ClientEntityBase, GetEntityByNameMixin): - results_list_attribute_name = 'firewalls' - - def get_actions_list(self, - firewall, # type: Firewall - status=None, # type: Optional[List[str]] - sort=None, # type: Optional[List[str]] - page=None, # type: Optional[int] - per_page=None # type: Optional[int] - ): + results_list_attribute_name = "firewalls" + + def get_actions_list( + self, + firewall, # type: Firewall + status=None, # type: Optional[List[str]] + sort=None, # type: Optional[List[str]] + page=None, # type: Optional[int] + per_page=None, # type: Optional[int] + ): # type: (...) -> PageResults[List[BoundAction], Meta] """Returns all action objects for a Firewall. @@ -141,16 +169,22 @@ def get_actions_list(self, if per_page is not None: params["per_page"] = per_page response = self._client.request( - url="/firewalls/{firewall_id}/actions".format(firewall_id=firewall.id), method="GET", - params=params) - actions = [BoundAction(self._client.actions, action_data) for action_data in response['actions']] - return add_meta_to_result(actions, response, 'actions') - - def get_actions(self, - firewall, # type: Firewall - status=None, # type: Optional[List[str]] - sort=None, # type: Optional[List[str]] - ): + url="/firewalls/{firewall_id}/actions".format(firewall_id=firewall.id), + method="GET", + params=params, + ) + actions = [ + BoundAction(self._client.actions, action_data) + for action_data in response["actions"] + ] + return add_meta_to_result(actions, response, "actions") + + def get_actions( + self, + firewall, # type: Firewall + status=None, # type: Optional[List[str]] + sort=None, # type: Optional[List[str]] + ): # type: (...) -> List[BoundAction] """Returns all action objects for a Firewall. @@ -162,7 +196,9 @@ def get_actions(self, :return: List[:class:`BoundAction `] """ - return super(FirewallsClient, self).get_actions(firewall, status=status, sort=sort) + return super(FirewallsClient, self).get_actions( + firewall, status=status, sort=sort + ) def get_by_id(self, id): # type: (int) -> BoundFirewall @@ -171,16 +207,19 @@ def get_by_id(self, id): :param id: int :return: :class:`BoundFirewall ` """ - response = self._client.request(url="/firewalls/{firewall_id}".format(firewall_id=id), method="GET") - return BoundFirewall(self, response['firewall']) - - def get_list(self, - label_selector=None, # type: Optional[str] - page=None, # type: Optional[int] - per_page=None, # type: Optional[int] - name=None, # type: Optional[str] - sort=None, # type: Optional[List[str]] - ): + response = self._client.request( + url="/firewalls/{firewall_id}".format(firewall_id=id), method="GET" + ) + return BoundFirewall(self, response["firewall"]) + + def get_list( + self, + label_selector=None, # type: Optional[str] + page=None, # type: Optional[int] + per_page=None, # type: Optional[int] + name=None, # type: Optional[str] + sort=None, # type: Optional[List[str]] + ): # type: (...) -> PageResults[List[BoundFirewall]] """Get a list of floating ips from this account @@ -199,17 +238,20 @@ def get_list(self, params = {} if label_selector is not None: - params['label_selector'] = label_selector + params["label_selector"] = label_selector if page is not None: - params['page'] = page + params["page"] = page if per_page is not None: - params['per_page'] = per_page + params["per_page"] = per_page if name is not None: - params['name'] = name + params["name"] = name if sort is not None: - params['sort'] = sort + params["sort"] = sort response = self._client.request(url="/firewalls", method="GET", params=params) - firewalls = [BoundFirewall(self, firewall_data) for firewall_data in response['firewalls']] + firewalls = [ + BoundFirewall(self, firewall_data) + for firewall_data in response["firewalls"] + ] return self._add_meta_to_result(firewalls, response) @@ -225,7 +267,9 @@ def get_all(self, label_selector=None, name=None, sort=None): Choices: id name created (You can add one of ":asc", ":desc" to modify sort order. ( ":asc" is default)) :return: List[:class:`BoundFirewall `] """ - return super(FirewallsClient, self).get_all(label_selector=label_selector, name=name, sort=sort) + return super(FirewallsClient, self).get_all( + label_selector=label_selector, name=name, sort=sort + ) def get_by_name(self, name): # type: (str) -> BoundFirewall @@ -237,12 +281,13 @@ def get_by_name(self, name): """ return super(FirewallsClient, self).get_by_name(name) - def create(self, - name, # type: str - rules=None, # type: Optional[List[FirewallRule]] - labels=None, # type: Optional[str] - resources=None, # type: Optional[List[FirewallResource]] - ): + def create( + self, + name, # type: str + rules=None, # type: Optional[List[FirewallRule]] + labels=None, # type: Optional[str] + resources=None, # type: Optional[List[FirewallResource]] + ): # type: (...) -> CreateFirewallResponse """Creates a new Firewall. @@ -255,29 +300,28 @@ def create(self, :return: :class:`CreateFirewallResponse ` """ - data = { - 'name': name - } + data = {"name": name} if labels is not None: - data['labels'] = labels + data["labels"] = labels if rules is not None: data.update({"rules": []}) for rule in rules: - data['rules'].append(rule.to_payload()) + data["rules"].append(rule.to_payload()) if resources is not None: data.update({"apply_to": []}) for resource in resources: - data['apply_to'].append(resource.to_payload()) + data["apply_to"].append(resource.to_payload()) response = self._client.request(url="/firewalls", json=data, method="POST") actions = [] - if response.get('actions') is not None: - actions = [BoundAction(self._client.actions, _) for _ in response['actions']] + if response.get("actions") is not None: + actions = [ + BoundAction(self._client.actions, _) for _ in response["actions"] + ] result = CreateFirewallResponse( - firewall=BoundFirewall(self, response['firewall']), - actions=actions + firewall=BoundFirewall(self, response["firewall"]), actions=actions ) return result @@ -294,13 +338,16 @@ def update(self, firewall, labels=None, name=None): """ data = {} if labels is not None: - data['labels'] = labels + data["labels"] = labels if name is not None: - data['name'] = name + data["name"] = name - response = self._client.request(url="/firewalls/{firewall_id}".format(firewall_id=firewall.id), - method="PUT", json=data) - return BoundFirewall(self, response['firewall']) + response = self._client.request( + url="/firewalls/{firewall_id}".format(firewall_id=firewall.id), + method="PUT", + json=data, + ) + return BoundFirewall(self, response["firewall"]) def delete(self, firewall): # type: (Firewall) -> bool @@ -309,8 +356,10 @@ def delete(self, firewall): :param firewall: :class:`BoundFirewall ` or :class:`Firewall ` :return: boolean """ - self._client.request(url="/firewalls/{firewall_id}".format(firewall_id=firewall.id), - method="DELETE") + self._client.request( + url="/firewalls/{firewall_id}".format(firewall_id=firewall.id), + method="DELETE", + ) # Return always true, because the API does not return an action for it. When an error occurs a HcloudAPIException will be raised return True @@ -322,15 +371,17 @@ def set_rules(self, firewall, rules): :param rules: List[:class:`FirewallRule `] :return: List[:class:`BoundAction `] """ - data = { - "rules": [] - } + data = {"rules": []} for rule in rules: - data['rules'].append(rule.to_payload()) + data["rules"].append(rule.to_payload()) response = self._client.request( - url="/firewalls/{firewall_id}/actions/set_rules".format(firewall_id=firewall.id), - method="POST", json=data) - return [BoundAction(self._client.actions, _) for _ in response['actions']] + url="/firewalls/{firewall_id}/actions/set_rules".format( + firewall_id=firewall.id + ), + method="POST", + json=data, + ) + return [BoundAction(self._client.actions, _) for _ in response["actions"]] def apply_to_resources(self, firewall, resources): # type: (Firewall, List[FirewallResource]) -> List[BoundAction] @@ -340,15 +391,17 @@ def apply_to_resources(self, firewall, resources): :param resources: List[:class:`FirewallResource `] :return: List[:class:`BoundAction `] """ - data = { - "apply_to": [] - } + data = {"apply_to": []} for resource in resources: - data['apply_to'].append(resource.to_payload()) + data["apply_to"].append(resource.to_payload()) response = self._client.request( - url="/firewalls/{firewall_id}/actions/apply_to_resources".format(firewall_id=firewall.id), - method="POST", json=data) - return [BoundAction(self._client.actions, _) for _ in response['actions']] + url="/firewalls/{firewall_id}/actions/apply_to_resources".format( + firewall_id=firewall.id + ), + method="POST", + json=data, + ) + return [BoundAction(self._client.actions, _) for _ in response["actions"]] def remove_from_resources(self, firewall, resources): # type: (Firewall, List[FirewallResource]) -> List[BoundAction] @@ -358,12 +411,14 @@ def remove_from_resources(self, firewall, resources): :param resources: List[:class:`FirewallResource `] :return: List[:class:`BoundAction `] """ - data = { - "remove_from": [] - } + data = {"remove_from": []} for resource in resources: - data['remove_from'].append(resource.to_payload()) + data["remove_from"].append(resource.to_payload()) response = self._client.request( - url="/firewalls/{firewall_id}/actions/remove_from_resources".format(firewall_id=firewall.id), - method="POST", json=data) - return [BoundAction(self._client.actions, _) for _ in response['actions']] + url="/firewalls/{firewall_id}/actions/remove_from_resources".format( + firewall_id=firewall.id + ), + method="POST", + json=data, + ) + return [BoundAction(self._client.actions, _) for _ in response["actions"]] diff --git a/hcloud/firewalls/domain.py b/hcloud/firewalls/domain.py index d53237a..bcdcf07 100644 --- a/hcloud/firewalls/domain.py +++ b/hcloud/firewalls/domain.py @@ -20,23 +20,11 @@ class Firewall(BaseDomain): :param created: datetime Point in time when the image was created """ - __slots__ = ( - "id", - "name", - "labels", - "rules", - "applied_to", - "created" - ) + + __slots__ = ("id", "name", "labels", "rules", "applied_to", "created") def __init__( - self, - id=None, - name=None, - labels=None, - rules=None, - applied_to=None, - created=None + self, id=None, name=None, labels=None, rules=None, applied_to=None, created=None ): self.id = id self.name = name @@ -63,13 +51,14 @@ class FirewallRule: :param description: str Short description of the firewall rule """ + __slots__ = ( "direction", "port", "protocol", "source_ips", "destination_ips", - "description" + "description", ) DIRECTION_IN = "in" @@ -89,13 +78,13 @@ class FirewallRule: """Firewall Rule Protocol GRE""" def __init__( - self, - direction, # type: str - protocol, # type: str - source_ips, # type: List[str] - port=None, # type: Optional[str] - destination_ips=None, # type: Optional[List[str]] - description=None, # type: Optional[str] + self, + direction, # type: str + protocol, # type: str + source_ips, # type: List[str] + port=None, # type: Optional[str] + destination_ips=None, # type: Optional[List[str]] + description=None, # type: Optional[str] ): self.direction = direction self.port = port @@ -129,11 +118,8 @@ class FirewallResource: :param label_selector: Optional[FirewallResourceLabelSelector] Label Selector for Servers the Firewall should be applied to """ - __slots__ = ( - "type", - "server", - "label_selector" - ) + + __slots__ = ("type", "server", "label_selector") TYPE_SERVER = "server" """Firewall Used By Type Server""" @@ -141,11 +127,10 @@ class FirewallResource: """Firewall Used By Type label_selector""" def __init__( - self, - type, # type: str - server=None, # type: Optional[Server] - label_selector=None, # type: Optional[FirewallResourceLabelSelector] - + self, + type, # type: str + server=None, # type: Optional[Server] + label_selector=None, # type: Optional[FirewallResourceLabelSelector] ): self.type = type self.server = server @@ -159,7 +144,9 @@ def to_payload(self): payload.update({"server": {"id": self.server.id}}) if self.label_selector is not None: - payload.update({"label_selector": {"selector": self.label_selector.selector}}) + payload.update( + {"label_selector": {"selector": self.label_selector.selector}} + ) return payload @@ -181,15 +168,13 @@ class CreateFirewallResponse(BaseDomain): :param actions: List[:class:`BoundAction `] The Action which shows the progress of the Firewall Creation """ - __slots__ = ( - "firewall", - "actions" - ) + + __slots__ = ("firewall", "actions") def __init__( - self, - firewall, # type: BoundFirewall - actions, # type: BoundAction + self, + firewall, # type: BoundFirewall + actions, # type: BoundAction ): self.firewall = firewall self.actions = actions diff --git a/hcloud/floating_ips/client.py b/hcloud/floating_ips/client.py index fc69f0c..6283cb6 100644 --- a/hcloud/floating_ips/client.py +++ b/hcloud/floating_ips/client.py @@ -12,13 +12,18 @@ class BoundFloatingIP(BoundModelBase): def __init__(self, client, data, complete=True): from hcloud.servers.client import BoundServer + server = data.get("server") if server is not None: - data['server'] = BoundServer(client._client.servers, {"id": server}, complete=False) + data["server"] = BoundServer( + client._client.servers, {"id": server}, complete=False + ) home_location = data.get("home_location") if home_location is not None: - data['home_location'] = BoundLocation(client._client.locations, home_location) + data["home_location"] = BoundLocation( + client._client.locations, home_location + ) super(BoundFloatingIP, self).__init__(client, data, complete) @@ -26,15 +31,15 @@ def get_actions_list(self, status=None, sort=None, page=None, per_page=None): # type: (Optional[List[str]], Optional[List[str]], Optional[int], Optional[int]) -> PageResult[BoundAction, Meta] """Returns all action objects for a Floating IP. - :param status: List[str] (optional) - Response will have only actions with specified statuses. Choices: `running` `success` `error` - :param sort: List[str] (optional) - Specify how the results are sorted. Choices: `id` `id:asc` `id:desc` `command` `command:asc` `command:desc` `status` `status:asc` `status:desc` `progress` `progress:asc` `progress:desc` `started` `started:asc` `started:desc` `finished` `finished:asc` `finished:desc` - :param page: int (optional) - Specifies the page to fetch - :param per_page: int (optional) - Specifies how many results are returned by page - :return: (List[:class:`BoundAction `], :class:`Meta `) + :param status: List[str] (optional) + Response will have only actions with specified statuses. Choices: `running` `success` `error` + :param sort: List[str] (optional) + Specify how the results are sorted. Choices: `id` `id:asc` `id:desc` `command` `command:asc` `command:desc` `status` `status:asc` `status:desc` `progress` `progress:asc` `progress:desc` `started` `started:asc` `started:desc` `finished` `finished:asc` `finished:desc` + :param page: int (optional) + Specifies the page to fetch + :param per_page: int (optional) + Specifies how many results are returned by page + :return: (List[:class:`BoundAction `], :class:`Meta `) """ return self._client.get_actions_list(self, status, sort, page, per_page) @@ -115,15 +120,16 @@ def change_dns_ptr(self, ip, dns_ptr): class FloatingIPsClient(ClientEntityBase, GetEntityByNameMixin): - results_list_attribute_name = 'floating_ips' - - def get_actions_list(self, - floating_ip, # type: FloatingIP - status=None, # type: Optional[List[str]] - sort=None, # type: Optional[List[str]] - page=None, # type: Optional[int] - per_page=None # type: Optional[int] - ): + results_list_attribute_name = "floating_ips" + + def get_actions_list( + self, + floating_ip, # type: FloatingIP + status=None, # type: Optional[List[str]] + sort=None, # type: Optional[List[str]] + page=None, # type: Optional[int] + per_page=None, # type: Optional[int] + ): # type: (...) -> PageResults[List[BoundAction], Meta] """Returns all action objects for a Floating IP. @@ -148,16 +154,24 @@ def get_actions_list(self, if per_page is not None: params["per_page"] = per_page response = self._client.request( - url="/floating_ips/{floating_ip_id}/actions".format(floating_ip_id=floating_ip.id), method="GET", - params=params) - actions = [BoundAction(self._client.actions, action_data) for action_data in response['actions']] - return add_meta_to_result(actions, response, 'actions') - - def get_actions(self, - floating_ip, # type: FloatingIP - status=None, # type: Optional[List[str]] - sort=None, # type: Optional[List[str]] - ): + url="/floating_ips/{floating_ip_id}/actions".format( + floating_ip_id=floating_ip.id + ), + method="GET", + params=params, + ) + actions = [ + BoundAction(self._client.actions, action_data) + for action_data in response["actions"] + ] + return add_meta_to_result(actions, response, "actions") + + def get_actions( + self, + floating_ip, # type: FloatingIP + status=None, # type: Optional[List[str]] + sort=None, # type: Optional[List[str]] + ): # type: (...) -> List[BoundAction] """Returns all action objects for a Floating IP. @@ -169,7 +183,9 @@ def get_actions(self, :return: List[:class:`BoundAction `] """ - return super(FloatingIPsClient, self).get_actions(floating_ip, status=status, sort=sort) + return super(FloatingIPsClient, self).get_actions( + floating_ip, status=status, sort=sort + ) def get_by_id(self, id): # type: (int) -> BoundFloatingIP @@ -178,15 +194,18 @@ def get_by_id(self, id): :param id: int :return: :class:`BoundFloatingIP ` """ - response = self._client.request(url="/floating_ips/{floating_ip_id}".format(floating_ip_id=id), method="GET") - return BoundFloatingIP(self, response['floating_ip']) - - def get_list(self, - label_selector=None, # type: Optional[str] - page=None, # type: Optional[int] - per_page=None, # type: Optional[int] - name=None, # type: Optional[str] - ): + response = self._client.request( + url="/floating_ips/{floating_ip_id}".format(floating_ip_id=id), method="GET" + ) + return BoundFloatingIP(self, response["floating_ip"]) + + def get_list( + self, + label_selector=None, # type: Optional[str] + page=None, # type: Optional[int] + per_page=None, # type: Optional[int] + name=None, # type: Optional[str] + ): # type: (...) -> PageResults[List[BoundFloatingIP]] """Get a list of floating ips from this account @@ -203,16 +222,21 @@ def get_list(self, params = {} if label_selector is not None: - params['label_selector'] = label_selector + params["label_selector"] = label_selector if page is not None: - params['page'] = page + params["page"] = page if per_page is not None: - params['per_page'] = per_page + params["per_page"] = per_page if name is not None: - params['name'] = name + params["name"] = name - response = self._client.request(url="/floating_ips", method="GET", params=params) - floating_ips = [BoundFloatingIP(self, floating_ip_data) for floating_ip_data in response['floating_ips']] + response = self._client.request( + url="/floating_ips", method="GET", params=params + ) + floating_ips = [ + BoundFloatingIP(self, floating_ip_data) + for floating_ip_data in response["floating_ips"] + ] return self._add_meta_to_result(floating_ips, response) @@ -226,7 +250,9 @@ def get_all(self, label_selector=None, name=None): Can be used to filter networks by their name. :return: List[:class:`BoundFloatingIP `] """ - return super(FloatingIPsClient, self).get_all(label_selector=label_selector, name=name) + return super(FloatingIPsClient, self).get_all( + label_selector=label_selector, name=name + ) def get_by_name(self, name): # type: (str) -> BoundFloatingIP @@ -238,14 +264,15 @@ def get_by_name(self, name): """ return super(FloatingIPsClient, self).get_by_name(name) - def create(self, - type, # type: str - description=None, # type: Optional[str] - labels=None, # type: Optional[str] - home_location=None, # type: Optional[Location] - server=None, # type: Optional[Server] - name=None, # type: Optional[str] - ): + def create( + self, + type, # type: str + description=None, # type: Optional[str] + labels=None, # type: Optional[str] + home_location=None, # type: Optional[Location] + server=None, # type: Optional[Server] + name=None, # type: Optional[str] + ): # type: (...) -> CreateFloatingIPResponse """Creates a new Floating IP assigned to a server. @@ -262,29 +289,26 @@ def create(self, :return: :class:`CreateFloatingIPResponse ` """ - data = { - 'type': type - } + data = {"type": type} if description is not None: - data['description'] = description + data["description"] = description if labels is not None: - data['labels'] = labels + data["labels"] = labels if home_location is not None: - data['home_location'] = home_location.id_or_name + data["home_location"] = home_location.id_or_name if server is not None: - data['server'] = server.id + data["server"] = server.id if name is not None: - data['name'] = name + data["name"] = name response = self._client.request(url="/floating_ips", json=data, method="POST") action = None - if response.get('action') is not None: - action = BoundAction(self._client.actions, response['action']) + if response.get("action") is not None: + action = BoundAction(self._client.actions, response["action"]) result = CreateFloatingIPResponse( - floating_ip=BoundFloatingIP(self, response['floating_ip']), - action=action + floating_ip=BoundFloatingIP(self, response["floating_ip"]), action=action ) return result @@ -303,15 +327,18 @@ def update(self, floating_ip, description=None, labels=None, name=None): """ data = {} if description is not None: - data['description'] = description + data["description"] = description if labels is not None: - data['labels'] = labels + data["labels"] = labels if name is not None: - data['name'] = name + data["name"] = name - response = self._client.request(url="/floating_ips/{floating_ip_id}".format(floating_ip_id=floating_ip.id), - method="PUT", json=data) - return BoundFloatingIP(self, response['floating_ip']) + response = self._client.request( + url="/floating_ips/{floating_ip_id}".format(floating_ip_id=floating_ip.id), + method="PUT", + json=data, + ) + return BoundFloatingIP(self, response["floating_ip"]) def delete(self, floating_ip): # type: (FloatingIP) -> bool @@ -320,8 +347,10 @@ def delete(self, floating_ip): :param floating_ip: :class:`BoundFloatingIP ` or :class:`FloatingIP ` :return: boolean """ - self._client.request(url="/floating_ips/{floating_ip_id}".format(floating_ip_id=floating_ip.id), - method="DELETE") + self._client.request( + url="/floating_ips/{floating_ip_id}".format(floating_ip_id=floating_ip.id), + method="DELETE", + ) # Return always true, because the API does not return an action for it. When an error occurs a HcloudAPIException will be raised return True @@ -339,9 +368,13 @@ def change_protection(self, floating_ip, delete=None): data.update({"delete": delete}) response = self._client.request( - url="/floating_ips/{floating_ip_id}/actions/change_protection".format(floating_ip_id=floating_ip.id), - method="POST", json=data) - return BoundAction(self._client.actions, response['action']) + url="/floating_ips/{floating_ip_id}/actions/change_protection".format( + floating_ip_id=floating_ip.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) def assign(self, floating_ip, server): # type: (FloatingIP, Server) -> BoundAction @@ -353,9 +386,13 @@ def assign(self, floating_ip, server): :return: :class:`BoundAction ` """ response = self._client.request( - url="/floating_ips/{floating_ip_id}/actions/assign".format(floating_ip_id=floating_ip.id), method="POST", - json={"server": server.id}) - return BoundAction(self._client.actions, response['action']) + url="/floating_ips/{floating_ip_id}/actions/assign".format( + floating_ip_id=floating_ip.id + ), + method="POST", + json={"server": server.id}, + ) + return BoundAction(self._client.actions, response["action"]) def unassign(self, floating_ip): # type: (FloatingIP) -> BoundAction @@ -365,8 +402,12 @@ def unassign(self, floating_ip): :return: :class:`BoundAction ` """ response = self._client.request( - url="/floating_ips/{floating_ip_id}/actions/unassign".format(floating_ip_id=floating_ip.id), method="POST") - return BoundAction(self._client.actions, response['action']) + url="/floating_ips/{floating_ip_id}/actions/unassign".format( + floating_ip_id=floating_ip.id + ), + method="POST", + ) + return BoundAction(self._client.actions, response["action"]) def change_dns_ptr(self, floating_ip, ip, dns_ptr): # type: (FloatingIP, str, str) -> BoundAction @@ -380,6 +421,10 @@ def change_dns_ptr(self, floating_ip, ip, dns_ptr): :return: :class:`BoundAction ` """ response = self._client.request( - url="/floating_ips/{floating_ip_id}/actions/change_dns_ptr".format(floating_ip_id=floating_ip.id), - method="POST", json={"ip": ip, "dns_ptr": dns_ptr}) - return BoundAction(self._client.actions, response['action']) + url="/floating_ips/{floating_ip_id}/actions/change_dns_ptr".format( + floating_ip_id=floating_ip.id + ), + method="POST", + json={"ip": ip, "dns_ptr": dns_ptr}, + ) + return BoundAction(self._client.actions, response["action"]) diff --git a/hcloud/floating_ips/domain.py b/hcloud/floating_ips/domain.py index 63a402a..bd5bf30 100644 --- a/hcloud/floating_ips/domain.py +++ b/hcloud/floating_ips/domain.py @@ -32,6 +32,7 @@ class FloatingIP(BaseDomain): :param name: str Name of the Floating IP """ + __slots__ = ( "id", "type", @@ -44,7 +45,7 @@ class FloatingIP(BaseDomain): "protection", "labels", "name", - "created" + "created", ) def __init__( @@ -60,7 +61,7 @@ def __init__( protection=None, labels=None, created=None, - name=None + name=None, ): self.id = id self.type = type @@ -84,15 +85,13 @@ class CreateFloatingIPResponse(BaseDomain): :param action: :class:`BoundAction ` The Action which shows the progress of the Floating IP Creation """ - __slots__ = ( - "floating_ip", - "action" - ) + + __slots__ = ("floating_ip", "action") def __init__( - self, - floating_ip, # type: BoundFloatingIP - action, # type: BoundAction + self, + floating_ip, # type: BoundFloatingIP + action, # type: BoundAction ): self.floating_ip = floating_ip self.action = action diff --git a/hcloud/hcloud.py b/hcloud/hcloud.py index dd669ef..db02702 100644 --- a/hcloud/hcloud.py +++ b/hcloud/hcloud.py @@ -25,6 +25,7 @@ class APIException(Exception): """There was an error while performing an API Request""" + def __init__(self, code, message, details): self.code = code self.message = message @@ -39,9 +40,16 @@ class Client(object): _version = VERSION _retry_wait_time = 0.5 - __user_agent_prefix = 'hcloud-python' - - def __init__(self, token, api_endpoint="https://api.hetzner.cloud/v1", application_name=None, application_version=None, poll_interval=1): + __user_agent_prefix = "hcloud-python" + + def __init__( + self, + token, + api_endpoint="https://api.hetzner.cloud/v1", + application_name=None, + application_version=None, + poll_interval=1, + ): """Create an new Client instance :param token: str @@ -148,23 +156,30 @@ def _get_user_agent(self): The user agent of this hcloud-python instance """ if self._application_name is not None and self._application_version is None: - return "{application_name} {prefix}/{version}".format(application_name=self._application_name, - prefix=self.__user_agent_prefix, - version=self._version) - elif self._application_name is not None and self._application_version is not None: + return "{application_name} {prefix}/{version}".format( + application_name=self._application_name, + prefix=self.__user_agent_prefix, + version=self._version, + ) + elif ( + self._application_name is not None and self._application_version is not None + ): return "{application_name}/{application_version} {prefix}/{version}".format( application_name=self._application_name, application_version=self._application_version, prefix=self.__user_agent_prefix, - version=self._version) + version=self._version, + ) else: - return "{prefix}/{version}".format(prefix=self.__user_agent_prefix, version=self._version) + return "{prefix}/{version}".format( + prefix=self.__user_agent_prefix, version=self._version + ) def _get_headers(self): headers = { "User-Agent": self._get_user_agent(), - "Authorization": "Bearer {token}".format(token=self.token) + "Authorization": "Bearer {token}".format(token=self.token), } return headers @@ -172,16 +187,14 @@ def _raise_exception_from_response(self, response): raise APIException( code=response.status_code, message=response.reason, - details={ - 'content': response.content - } + details={"content": response.content}, ) def _raise_exception_from_json_content(self, json_content): raise APIException( - code=json_content['error']['code'], - message=json_content['error']['message'], - details=json_content['error']['details'] + code=json_content["error"]["code"], + message=json_content["error"]["message"], + details=json_content["error"]["details"], ) def request(self, method, url, tries=1, **kwargs): @@ -197,10 +210,7 @@ def request(self, method, url, tries=1, **kwargs): :rtype: requests.Response """ response = self._requests_session.request( - method, - self._api_endpoint + url, - headers=self._get_headers(), - **kwargs + method, self._api_endpoint + url, headers=self._get_headers(), **kwargs ) json_content = response.content @@ -212,7 +222,7 @@ def request(self, method, url, tries=1, **kwargs): if not response.ok: if json_content: - if json_content['error']['code'] == "rate_limit_exceeded" and tries < 5: + if json_content["error"]["code"] == "rate_limit_exceeded" and tries < 5: time.sleep(tries * self._retry_wait_time) tries = tries + 1 return self.request(method, url, tries, **kwargs) diff --git a/hcloud/images/client.py b/hcloud/images/client.py index a21653c..4b37a5f 100644 --- a/hcloud/images/client.py +++ b/hcloud/images/client.py @@ -11,12 +11,17 @@ class BoundImage(BoundModelBase): def __init__(self, client, data): from hcloud.servers.client import BoundServer + created_from = data.get("created_from") if created_from is not None: - data['created_from'] = BoundServer(client._client.servers, created_from, complete=False) + data["created_from"] = BoundServer( + client._client.servers, created_from, complete=False + ) bound_to = data.get("bound_to") if bound_to is not None: - data['bound_to'] = BoundServer(client._client.servers, {"id": bound_to}, complete=False) + data["bound_to"] = BoundServer( + client._client.servers, {"id": bound_to}, complete=False + ) super(BoundImage, self).__init__(client, data) @@ -34,7 +39,9 @@ def get_actions_list(self, sort=None, page=None, per_page=None, status=None): Specifies how many results are returned by page :return: (List[:class:`BoundAction `], :class:`Meta `) """ - return self._client.get_actions_list(self, sort=sort, page=page, per_page=per_page, status=status) + return self._client.get_actions_list( + self, sort=sort, page=page, per_page=per_page, status=status + ) def get_actions(self, sort=None, status=None): # type: (Optional[List[str]], Optional[List[str]]) -> List[BoundAction] @@ -83,15 +90,16 @@ def change_protection(self, delete=None): class ImagesClient(ClientEntityBase, GetEntityByNameMixin): - results_list_attribute_name = 'images' - - def get_actions_list(self, - image, # type: Image - sort=None, # type: Optional[List[str]] - page=None, # type: Optional[int] - per_page=None, # type: Optional[int] - status=None, # type: Optional[List[str]] - ): + results_list_attribute_name = "images" + + def get_actions_list( + self, + image, # type: Image + sort=None, # type: Optional[List[str]] + page=None, # type: Optional[int] + per_page=None, # type: Optional[int] + status=None, # type: Optional[List[str]] + ): # type: (...) -> PageResults[List[BoundAction], Meta] """Returns a list of action objects for an image. @@ -115,15 +123,23 @@ def get_actions_list(self, params["page"] = page if per_page is not None: params["per_page"] = per_page - response = self._client.request(url="/images/{image_id}/actions".format(image_id=image.id), method="GET", params=params) - actions = [BoundAction(self._client.actions, action_data) for action_data in response['actions']] - return add_meta_to_result(actions, response, 'actions') - - def get_actions(self, - image, # type: Image - sort=None, # type: Optional[List[str]] - status=None, # type: Optional[List[str]] - ): + response = self._client.request( + url="/images/{image_id}/actions".format(image_id=image.id), + method="GET", + params=params, + ) + actions = [ + BoundAction(self._client.actions, action_data) + for action_data in response["actions"] + ] + return add_meta_to_result(actions, response, "actions") + + def get_actions( + self, + image, # type: Image + sort=None, # type: Optional[List[str]] + status=None, # type: Optional[List[str]] + ): # type: (...) -> List[BoundAction] """Returns all action objects for an image. @@ -143,20 +159,23 @@ def get_by_id(self, id): :param id: int :return: :class:`BoundImage PageResults[List[BoundImage]] """Get all images @@ -182,37 +201,38 @@ def get_list(self, """ params = {} if name is not None: - params['name'] = name + params["name"] = name if label_selector is not None: - params['label_selector'] = label_selector + params["label_selector"] = label_selector if bound_to is not None: - params['bound_to'] = bound_to + params["bound_to"] = bound_to if type is not None: - params['type'] = type + params["type"] = type if sort is not None: - params['sort'] = sort + params["sort"] = sort if page is not None: - params['page'] = page + params["page"] = page if per_page is not None: - params['per_page'] = per_page + params["per_page"] = per_page if status is not None: - params['status'] = per_page + params["status"] = per_page if include_deprecated is not None: - params['include_deprecated'] = include_deprecated + params["include_deprecated"] = include_deprecated response = self._client.request(url="/images", method="GET", params=params) - images = [BoundImage(self, image_data) for image_data in response['images']] + images = [BoundImage(self, image_data) for image_data in response["images"]] return self._add_meta_to_result(images, response) - def get_all(self, - name=None, # type: Optional[str] - label_selector=None, # type: Optional[str] - bound_to=None, # type: Optional[List[str]] - type=None, # type: Optional[List[str]] - sort=None, # type: Optional[List[str]] - status=None, # type: Optional[List[str]] - include_deprecated=None # type: Optional[bool] - ): + def get_all( + self, + name=None, # type: Optional[str] + label_selector=None, # type: Optional[str] + bound_to=None, # type: Optional[List[str]] + type=None, # type: Optional[List[str]] + sort=None, # type: Optional[List[str]] + status=None, # type: Optional[List[str]] + include_deprecated=None, # type: Optional[bool] + ): # type: (...) -> List[BoundImage] """Get all images @@ -232,7 +252,15 @@ def get_all(self, Include deprecated images in the response. Default: False :return: List[:class:`BoundImage `] """ - return super(ImagesClient, self).get_all(name=name, label_selector=label_selector, bound_to=bound_to, type=type, sort=sort, status=status, include_deprecated=include_deprecated) + return super(ImagesClient, self).get_all( + name=name, + label_selector=label_selector, + bound_to=bound_to, + type=type, + sort=sort, + status=status, + include_deprecated=include_deprecated, + ) def get_by_name(self, name): # type: (str) -> BoundImage @@ -265,8 +293,10 @@ def update(self, image, description=None, type=None, labels=None): data.update({"type": type}) if labels is not None: data.update({"labels": labels}) - response = self._client.request(url="/images/{image_id}".format(image_id=image.id), method="PUT", json=data) - return BoundImage(self, response['image']) + response = self._client.request( + url="/images/{image_id}".format(image_id=image.id), method="PUT", json=data + ) + return BoundImage(self, response["image"]) def delete(self, image): # type: (Image) -> bool @@ -275,7 +305,9 @@ def delete(self, image): :param :class:`BoundImage ` or :class:`Image ` :return: bool """ - self._client.request(url="/images/{image_id}".format(image_id=image.id), method="DELETE") + self._client.request( + url="/images/{image_id}".format(image_id=image.id), method="DELETE" + ) # Return allays true, because the API does not return an action for it. When an error occurs a APIException will be raised return True @@ -292,5 +324,11 @@ def change_protection(self, image, delete=None): if delete is not None: data.update({"delete": delete}) - response = self._client.request(url="/images/{image_id}/actions/change_protection".format(image_id=image.id), method="POST", json=data) - return BoundAction(self._client.actions, response['action']) + response = self._client.request( + url="/images/{image_id}/actions/change_protection".format( + image_id=image.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) diff --git a/hcloud/images/domain.py b/hcloud/images/domain.py index 44e6545..cd65673 100644 --- a/hcloud/images/domain.py +++ b/hcloud/images/domain.py @@ -57,28 +57,27 @@ class Image(BaseDomain, DomainIdentityMixin): "protection", "labels", "created", - "deprecated" + "deprecated", ) def __init__( - self, - id=None, - name=None, - type=None, - created=None, - description=None, - image_size=None, - disk_size=None, - deprecated=None, - bound_to=None, - os_flavor=None, - os_version=None, - rapid_deploy=None, - created_from=None, - protection=None, - labels=None, - status=None - + self, + id=None, + name=None, + type=None, + created=None, + description=None, + image_size=None, + disk_size=None, + deprecated=None, + bound_to=None, + os_flavor=None, + os_version=None, + rapid_deploy=None, + created_from=None, + protection=None, + labels=None, + status=None, ): self.id = id self.name = name @@ -106,15 +105,13 @@ class CreateImageResponse(BaseDomain): :param action: :class:`BoundAction ` The Action which shows the progress of the Floating IP Creation """ - __slots__ = ( - "action", - "image" - ) + + __slots__ = ("action", "image") def __init__( - self, - action, # type: BoundAction - image # type: BoundImage + self, + action, # type: BoundAction + image, # type: BoundImage ): self.action = action self.image = image diff --git a/hcloud/isos/client.py b/hcloud/isos/client.py index 03af56f..b763743 100644 --- a/hcloud/isos/client.py +++ b/hcloud/isos/client.py @@ -9,7 +9,7 @@ class BoundIso(BoundModelBase): class IsosClient(ClientEntityBase, GetEntityByNameMixin): - results_list_attribute_name = 'isos' + results_list_attribute_name = "isos" def get_by_id(self, id): # type: (int) -> BoundIso @@ -18,14 +18,17 @@ def get_by_id(self, id): :param id: int :return: :class:`BoundIso ` """ - response = self._client.request(url="/isos/{iso_id}".format(iso_id=id), method="GET") - return BoundIso(self, response['iso']) + response = self._client.request( + url="/isos/{iso_id}".format(iso_id=id), method="GET" + ) + return BoundIso(self, response["iso"]) - def get_list(self, - name=None, # type: Optional[str] - page=None, # type: Optional[int] - per_page=None, # type: Optional[int] - ): + def get_list( + self, + name=None, # type: Optional[str] + page=None, # type: Optional[int] + per_page=None, # type: Optional[int] + ): # type: (...) -> PageResults[List[BoundIso], Meta] """Get a list of ISOs @@ -39,14 +42,14 @@ def get_list(self, """ params = {} if name is not None: - params['name'] = name + params["name"] = name if page is not None: - params['page'] = page + params["page"] = page if per_page is not None: - params['per_page'] = per_page + params["per_page"] = per_page response = self._client.request(url="/isos", method="GET", params=params) - isos = [BoundIso(self, iso_data) for iso_data in response['isos']] + isos = [BoundIso(self, iso_data) for iso_data in response["isos"]] return self._add_meta_to_result(isos, response) def get_all(self, name=None): diff --git a/hcloud/isos/domain.py b/hcloud/isos/domain.py index dced800..aea06b3 100644 --- a/hcloud/isos/domain.py +++ b/hcloud/isos/domain.py @@ -19,13 +19,7 @@ class Iso(BaseDomain, DomainIdentityMixin): ISO 8601 timestamp of deprecation, None if ISO is still available. After the deprecation time it will no longer be possible to attach the ISO to servers. """ - __slots__ = ( - "id", - "name", - "type", - "description", - "deprecated" - ) + __slots__ = ("id", "name", "type", "description", "deprecated") def __init__( self, diff --git a/hcloud/load_balancer_types/client.py b/hcloud/load_balancer_types/client.py index 6ff208a..341650a 100644 --- a/hcloud/load_balancer_types/client.py +++ b/hcloud/load_balancer_types/client.py @@ -7,7 +7,7 @@ class BoundLoadBalancerType(BoundModelBase): class LoadBalancerTypesClient(ClientEntityBase, GetEntityByNameMixin): - results_list_attribute_name = 'load_balancer_types' + results_list_attribute_name = "load_balancer_types" def get_by_id(self, id): # type: (int) -> load_balancer_types.client.BoundLoadBalancerType @@ -16,8 +16,13 @@ def get_by_id(self, id): :param id: int :return: :class:`BoundLoadBalancerType ` """ - response = self._client.request(url="/load_balancer_types/{load_balancer_type_id}".format(load_balancer_type_id=id), method="GET") - return BoundLoadBalancerType(self, response['load_balancer_type']) + response = self._client.request( + url="/load_balancer_types/{load_balancer_type_id}".format( + load_balancer_type_id=id + ), + method="GET", + ) + return BoundLoadBalancerType(self, response["load_balancer_type"]) def get_list(self, name=None, page=None, per_page=None): # type: (Optional[str], Optional[int], Optional[int]) -> PageResults[List[BoundLoadBalancerType], Meta] @@ -33,14 +38,19 @@ def get_list(self, name=None, page=None, per_page=None): """ params = {} if name is not None: - params['name'] = name + params["name"] = name if page is not None: - params['page'] = page + params["page"] = page if per_page is not None: - params['per_page'] = per_page + params["per_page"] = per_page - response = self._client.request(url="/load_balancer_types", method="GET", params=params) - load_balancer_types = [BoundLoadBalancerType(self, load_balancer_type_data) for load_balancer_type_data in response['load_balancer_types']] + response = self._client.request( + url="/load_balancer_types", method="GET", params=params + ) + load_balancer_types = [ + BoundLoadBalancerType(self, load_balancer_type_data) + for load_balancer_type_data in response["load_balancer_types"] + ] return self._add_meta_to_result(load_balancer_types, response) def get_all(self, name=None): diff --git a/hcloud/load_balancer_types/domain.py b/hcloud/load_balancer_types/domain.py index 70ed0ff..3356679 100644 --- a/hcloud/load_balancer_types/domain.py +++ b/hcloud/load_balancer_types/domain.py @@ -32,19 +32,19 @@ class LoadBalancerType(BaseDomain, DomainIdentityMixin): "max_services", "max_targets", "max_assigned_certificates", - "prices" + "prices", ) def __init__( - self, - id=None, - name=None, - description=None, - max_connections=None, - max_services=None, - max_targets=None, - max_assigned_certificates=None, - prices=None + self, + id=None, + name=None, + description=None, + max_connections=None, + max_services=None, + max_targets=None, + max_assigned_certificates=None, + prices=None, ): self.id = id self.name = name diff --git a/hcloud/load_balancers/client.py b/hcloud/load_balancers/client.py index 4b13897..22a8985 100644 --- a/hcloud/load_balancers/client.py +++ b/hcloud/load_balancers/client.py @@ -10,10 +10,22 @@ from hcloud.core.domain import add_meta_to_result from hcloud.actions.client import BoundAction -from hcloud.load_balancers.domain import LoadBalancer, IPv4Address, IPv6Network, PublicNetwork, PrivateNet, \ - CreateLoadBalancerResponse, LoadBalancerTarget, LoadBalancerService, LoadBalancerServiceHttp, \ - LoadBalancerHealthCheck, LoadBalancerHealtCheckHttp, LoadBalancerAlgorithm, LoadBalancerTargetLabelSelector, \ - LoadBalancerTargetIP +from hcloud.load_balancers.domain import ( + LoadBalancer, + IPv4Address, + IPv6Network, + PublicNetwork, + PrivateNet, + CreateLoadBalancerResponse, + LoadBalancerTarget, + LoadBalancerService, + LoadBalancerServiceHttp, + LoadBalancerHealthCheck, + LoadBalancerHealtCheckHttp, + LoadBalancerAlgorithm, + LoadBalancerTargetLabelSelector, + LoadBalancerTargetIP, +) class BoundLoadBalancer(BoundModelBase): @@ -22,20 +34,30 @@ class BoundLoadBalancer(BoundModelBase): def __init__(self, client, data, complete=True): algorithm = data.get("algorithm") if algorithm: - data['algorithm'] = LoadBalancerAlgorithm(type=algorithm['type']) + data["algorithm"] = LoadBalancerAlgorithm(type=algorithm["type"]) public_net = data.get("public_net") if public_net: - ipv4_address = IPv4Address(**public_net['ipv4']) - ipv6_network = IPv6Network(**public_net['ipv6']) - data['public_net'] = PublicNetwork(ipv4=ipv4_address, ipv6=ipv6_network, enabled=public_net['enabled']) + ipv4_address = IPv4Address.from_dict(public_net["ipv4"]) + ipv6_network = IPv6Network.from_dict(public_net["ipv6"]) + data["public_net"] = PublicNetwork( + ipv4=ipv4_address, ipv6=ipv6_network, enabled=public_net["enabled"] + ) private_nets = data.get("private_net") if private_nets: - private_nets = [PrivateNet( - network=BoundNetwork(client._client.networks, {"id": private_net['network']}, complete=False), - ip=private_net['ip']) for private_net in private_nets] - data['private_net'] = private_nets + private_nets = [ + PrivateNet( + network=BoundNetwork( + client._client.networks, + {"id": private_net["network"]}, + complete=False, + ), + ip=private_net["ip"], + ) + for private_net in private_nets + ] + data["private_net"] = private_nets targets = data.get("targets") if targets: @@ -43,55 +65,73 @@ def __init__(self, client, data, complete=True): for target in targets: tmp_target = LoadBalancerTarget(type=target["type"]) if target["type"] == "server": - tmp_target.server = BoundServer(client._client.servers, data=target['server'], complete=False) + tmp_target.server = BoundServer( + client._client.servers, data=target["server"], complete=False + ) tmp_target.use_private_ip = target["use_private_ip"] elif target["type"] == "label_selector": tmp_target.label_selector = LoadBalancerTargetLabelSelector( - selector=target['label_selector']['selector']) + selector=target["label_selector"]["selector"] + ) tmp_target.use_private_ip = target["use_private_ip"] elif target["type"] == "ip": - tmp_target.ip = LoadBalancerTargetIP(ip=target['ip']['ip']) + tmp_target.ip = LoadBalancerTargetIP(ip=target["ip"]["ip"]) tmp_targets.append(tmp_target) - data['targets'] = tmp_targets + data["targets"] = tmp_targets services = data.get("services") if services: tmp_services = [] for service in services: - tmp_service = LoadBalancerService(protocol=service["protocol"], listen_port=service["listen_port"], - destination_port=service["destination_port"], - proxyprotocol=service["proxyprotocol"]) + tmp_service = LoadBalancerService( + protocol=service["protocol"], + listen_port=service["listen_port"], + destination_port=service["destination_port"], + proxyprotocol=service["proxyprotocol"], + ) if service["protocol"] != "tcp": - tmp_service.http = LoadBalancerServiceHttp(sticky_sessions=service['http']['sticky_sessions'], - redirect_http=service['http']['redirect_http'], - cookie_name=service['http']['cookie_name'], - cookie_lifetime=service['http']['cookie_lifetime']) + tmp_service.http = LoadBalancerServiceHttp( + sticky_sessions=service["http"]["sticky_sessions"], + redirect_http=service["http"]["redirect_http"], + cookie_name=service["http"]["cookie_name"], + cookie_lifetime=service["http"]["cookie_lifetime"], + ) tmp_service.http.certificates = [ - BoundCertificate(client._client.certificates, {"id": certificate}, complete=False) for - certificate in - service['http']['certificates']] - - tmp_service.health_check = LoadBalancerHealthCheck(protocol=service['health_check']['protocol'], - port=service['health_check']['port'], - interval=service['health_check']['interval'], - retries=service['health_check']['retries'], - timeout=service['health_check']['timeout']) + BoundCertificate( + client._client.certificates, + {"id": certificate}, + complete=False, + ) + for certificate in service["http"]["certificates"] + ] + + tmp_service.health_check = LoadBalancerHealthCheck( + protocol=service["health_check"]["protocol"], + port=service["health_check"]["port"], + interval=service["health_check"]["interval"], + retries=service["health_check"]["retries"], + timeout=service["health_check"]["timeout"], + ) if tmp_service.health_check.protocol != "tcp": tmp_service.health_check.http = LoadBalancerHealtCheckHttp( - domain=service['health_check']['http']['domain'], path=service['health_check']['http']['path'], - response=service['health_check']['http']['response'], - tls=service['health_check']['http']['tls'], - status_codes=service['health_check']['http']['status_codes']) + domain=service["health_check"]["http"]["domain"], + path=service["health_check"]["http"]["path"], + response=service["health_check"]["http"]["response"], + tls=service["health_check"]["http"]["tls"], + status_codes=service["health_check"]["http"]["status_codes"], + ) tmp_services.append(tmp_service) - data['services'] = tmp_services + data["services"] = tmp_services load_balancer_type = data.get("load_balancer_type") if load_balancer_type is not None: - data['load_balancer_type'] = BoundLoadBalancerType(client._client.load_balancer_types, load_balancer_type) + data["load_balancer_type"] = BoundLoadBalancerType( + client._client.load_balancer_types, load_balancer_type + ) location = data.get("location") if location is not None: - data['location'] = BoundLocation(client._client.locations, location) + data["location"] = BoundLocation(client._client.locations, location) super(BoundLoadBalancer, self).__init__(client, data, complete) @@ -99,12 +139,12 @@ def update(self, name=None, labels=None): # type: (Optional[str], Optional[Dict[str, str]]) -> BoundLoadBalancer """Updates a Load Balancer. You can update a Load Balancers name and a Load Balancers labels. - :param name: str (optional) - New name to set - :param labels: Dict[str, str] (optional) - User-defined labels (key-value pairs) - :return: :class:`BoundLoadBalancer ` - """ + :param name: str (optional) + New name to set + :param labels: Dict[str, str] (optional) + User-defined labels (key-value pairs) + :return: :class:`BoundLoadBalancer ` + """ return self._client.update(self, name, labels) def delete(self): @@ -271,16 +311,17 @@ def get_by_id(self, id): :return: :class:`BoundLoadBalancer ` """ response = self._client.request( - url="/load_balancers/{load_balancer_id}".format(load_balancer_id=id), method="GET" + url="/load_balancers/{load_balancer_id}".format(load_balancer_id=id), + method="GET", ) return BoundLoadBalancer(self, response["load_balancer"]) def get_list( - self, - name=None, # type: Optional[str] - label_selector=None, # type: Optional[str] - page=None, # type: Optional[int] - per_page=None, # type: Optional[int] + self, + name=None, # type: Optional[str] + label_selector=None, # type: Optional[str] + page=None, # type: Optional[int] + per_page=None, # type: Optional[int] ): # type: (...) -> PageResults[List[BoundLoadBalancer], Meta] """Get a list of Load Balancers from this account @@ -305,10 +346,13 @@ def get_list( if per_page is not None: params["per_page"] = per_page - response = self._client.request(url="/load_balancers", method="GET", params=params) + response = self._client.request( + url="/load_balancers", method="GET", params=params + ) ass_load_balancers = [ - BoundLoadBalancer(self, load_balancer_data) for load_balancer_data in response["load_balancers"] + BoundLoadBalancer(self, load_balancer_data) + for load_balancer_data in response["load_balancers"] ] return self._add_meta_to_result(ass_load_balancers, response) @@ -337,17 +381,17 @@ def get_by_name(self, name): return super(LoadBalancersClient, self).get_by_name(name) def create( - self, - name, # type: str - load_balancer_type, # type: LoadBalancerType - algorithm=None, # type: Optional[LoadBalancerAlgorithm] - services=None, # type: Optional[List[LoadBalancerService]] - targets=None, # type: Optional[List[LoadBalancerTarget]] - labels=None, # type: Optional[Dict[str, str]] - location=None, # type: Optional[Location] - network_zone=None, # type: Optional[str] - public_interface=None, # type: Optional[bool] - network=None # type: Optional[Union[Network,BoundNetwork]] + self, + name, # type: str + load_balancer_type, # type: LoadBalancerType + algorithm=None, # type: Optional[LoadBalancerAlgorithm] + services=None, # type: Optional[List[LoadBalancerService]] + targets=None, # type: Optional[List[LoadBalancerTarget]] + labels=None, # type: Optional[Dict[str, str]] + location=None, # type: Optional[Location] + network_zone=None, # type: Optional[str] + public_interface=None, # type: Optional[bool] + network=None, # type: Optional[Union[Network,BoundNetwork]] ): # type: (...) -> CreateLoadBalancerResponse: """Creates a Load Balancer . @@ -394,14 +438,16 @@ def create( for target in targets: target_data = { "type": target.type, - "use_private_ip": target.use_private_ip + "use_private_ip": target.use_private_ip, } if target.type == "server": - target_data['server'] = {"id": target.server.id} + target_data["server"] = {"id": target.server.id} elif target.type == "label_selector": - target_data['label_selector'] = {"selector": target.label_selector.selector} + target_data["label_selector"] = { + "selector": target.label_selector.selector + } elif target.type == "ip": - target_data['ip'] = {"ip": target.ip.ip} + target_data["ip"] = {"ip": target.ip.ip} target_list.append(target_data) data["targets"] = target_list @@ -413,8 +459,10 @@ def create( response = self._client.request(url="/load_balancers", method="POST", json=data) - return CreateLoadBalancerResponse(load_balancer=BoundLoadBalancer(self, response["load_balancer"]), - action=BoundAction(self._client.actions, response['action'])) + return CreateLoadBalancerResponse( + load_balancer=BoundLoadBalancer(self, response["load_balancer"]), + action=BoundAction(self._client.actions, response["action"]), + ) def update(self, load_balancer, name=None, labels=None): # type:(LoadBalancer, Optional[str], Optional[Dict[str, str]]) -> BoundLoadBalancer @@ -433,7 +481,9 @@ def update(self, load_balancer, name=None, labels=None): if labels is not None: data.update({"labels": labels}) response = self._client.request( - url="/load_balancers/{load_balancer_id}".format(load_balancer_id=load_balancer.id), + url="/load_balancers/{load_balancer_id}".format( + load_balancer_id=load_balancer.id + ), method="PUT", json=data, ) @@ -447,12 +497,15 @@ def delete(self, load_balancer): :return: boolean """ self._client.request( - url="/load_balancers/{load_balancer_id}".format(load_balancer_id=load_balancer.id), method="DELETE" + url="/load_balancers/{load_balancer_id}".format( + load_balancer_id=load_balancer.id + ), + method="DELETE", ) return True def get_actions_list( - self, load_balancer, status=None, sort=None, page=None, per_page=None + self, load_balancer, status=None, sort=None, page=None, per_page=None ): # type: (LoadBalancer, Optional[List[str]], Optional[List[str]], Optional[int], Optional[int]) -> PageResults[List[BoundAction], Meta] """Returns all action objects for a Load Balancer. @@ -479,7 +532,9 @@ def get_actions_list( params["per_page"] = per_page response = self._client.request( - url="/load_balancers/{load_balancer_id}/actions".format(load_balancer_id=load_balancer.id), + url="/load_balancers/{load_balancer_id}/actions".format( + load_balancer_id=load_balancer.id + ), method="GET", params=params, ) @@ -516,9 +571,13 @@ def add_service(self, load_balancer, service): data = self.get_service_parameters(service) response = self._client.request( - url="/load_balancers/{load_balancer_id}/actions/add_service".format(load_balancer_id=load_balancer.id), - method="POST", json=data) - return BoundAction(self._client.actions, response['action']) + url="/load_balancers/{load_balancer_id}/actions/add_service".format( + load_balancer_id=load_balancer.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) def get_service_parameters(self, service): data = {} @@ -545,7 +604,7 @@ def get_service_parameters(self, service): certificate_ids.append(certificate.id) data["http"]["certificates"] = certificate_ids if service.health_check is not None: - data['health_check'] = { + data["health_check"] = { "protocol": service.health_check.protocol, "port": service.health_check.port, "interval": service.health_check.interval, @@ -564,17 +623,25 @@ def get_service_parameters(self, service): if service.health_check.retries is not None: data["health_check"]["retries"] = service.health_check.retries if service.health_check.http is not None: - data['health_check']['http'] = {} + data["health_check"]["http"] = {} if service.health_check.http.domain is not None: - data['health_check']['http']['domain'] = service.health_check.http.domain + data["health_check"]["http"][ + "domain" + ] = service.health_check.http.domain if service.health_check.http.path is not None: - data['health_check']['http']['path'] = service.health_check.http.path + data["health_check"]["http"][ + "path" + ] = service.health_check.http.path if service.health_check.http.response is not None: - data['health_check']['http']['response'] = service.health_check.http.response + data["health_check"]["http"][ + "response" + ] = service.health_check.http.response if service.health_check.http.status_codes is not None: - data['health_check']['http']['status_codes'] = service.health_check.http.status_codes + data["health_check"]["http"][ + "status_codes" + ] = service.health_check.http.status_codes if service.health_check.http.tls is not None: - data['health_check']['http']['tls'] = service.health_check.http.tls + data["health_check"]["http"]["tls"] = service.health_check.http.tls return data def update_service(self, load_balancer, service): @@ -589,9 +656,12 @@ def update_service(self, load_balancer, service): data = self.get_service_parameters(service) response = self._client.request( url="/load_balancers/{load_balancer_id}/actions/update_service".format( - load_balancer_id=load_balancer.id), - method="POST", json=data) - return BoundAction(self._client.actions, response['action']) + load_balancer_id=load_balancer.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) def delete_service(self, load_balancer, service): # type: (Union[LoadBalancer, BoundLoadBalancer], LoadBalancerService) -> List[BoundAction] @@ -607,9 +677,13 @@ def delete_service(self, load_balancer, service): } response = self._client.request( - url="/load_balancers/{load_balancer_id}/actions/delete_service".format(load_balancer_id=load_balancer.id), - method="POST", json=data) - return BoundAction(self._client.actions, response['action']) + url="/load_balancers/{load_balancer_id}/actions/delete_service".format( + load_balancer_id=load_balancer.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) def add_target(self, load_balancer, target): # type: (Union[LoadBalancer, BoundLoadBalancer], LoadBalancerTarget) -> List[BoundAction] @@ -620,21 +694,22 @@ def add_target(self, load_balancer, target): The LoadBalancerTarget you want to add to the Load Balancer :return: :class:`BoundAction ` """ - data = { - "type": target.type, - "use_private_ip": target.use_private_ip - } + data = {"type": target.type, "use_private_ip": target.use_private_ip} if target.type == "server": - data['server'] = {"id": target.server.id} + data["server"] = {"id": target.server.id} elif target.type == "label_selector": - data['label_selector'] = {"selector": target.label_selector.selector} + data["label_selector"] = {"selector": target.label_selector.selector} elif target.type == "ip": - data['ip'] = {"ip": target.ip.ip} + data["ip"] = {"ip": target.ip.ip} response = self._client.request( - url="/load_balancers/{load_balancer_id}/actions/add_target".format(load_balancer_id=load_balancer.id), - method="POST", json=data) - return BoundAction(self._client.actions, response['action']) + url="/load_balancers/{load_balancer_id}/actions/add_target".format( + load_balancer_id=load_balancer.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) def remove_target(self, load_balancer, target): # type: (Union[LoadBalancer, BoundLoadBalancer], LoadBalancerTarget) -> List[BoundAction] @@ -649,16 +724,20 @@ def remove_target(self, load_balancer, target): "type": target.type, } if target.type == "server": - data['server'] = {"id": target.server.id} + data["server"] = {"id": target.server.id} elif target.type == "label_selector": - data['label_selector'] = {"selector": target.label_selector.selector} + data["label_selector"] = {"selector": target.label_selector.selector} elif target.type == "ip": - data['ip'] = {"ip": target.ip.ip} + data["ip"] = {"ip": target.ip.ip} response = self._client.request( - url="/load_balancers/{load_balancer_id}/actions/remove_target".format(load_balancer_id=load_balancer.id), - method="POST", json=data) - return BoundAction(self._client.actions, response['action']) + url="/load_balancers/{load_balancer_id}/actions/remove_target".format( + load_balancer_id=load_balancer.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) def change_algorithm(self, load_balancer, algorithm): # type: (Union[LoadBalancer, BoundLoadBalancer], Optional[bool]) -> BoundAction @@ -672,9 +751,13 @@ def change_algorithm(self, load_balancer, algorithm): data = {"type": algorithm.type} response = self._client.request( - url="/load_balancers/{load_balancer_id}/actions/change_algorithm".format(load_balancer_id=load_balancer.id), - method="POST", json=data) - return BoundAction(self._client.actions, response['action']) + url="/load_balancers/{load_balancer_id}/actions/change_algorithm".format( + load_balancer_id=load_balancer.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) def change_protection(self, load_balancer, delete=None): # type: (Union[LoadBalancer, BoundLoadBalancer], Optional[bool]) -> BoundAction @@ -691,15 +774,19 @@ def change_protection(self, load_balancer, delete=None): response = self._client.request( url="/load_balancers/{load_balancer_id}/actions/change_protection".format( - load_balancer_id=load_balancer.id), - method="POST", json=data) - return BoundAction(self._client.actions, response['action']) - - def attach_to_network(self, - load_balancer, # type: Union[LoadBalancer, BoundLoadBalancer] - network, # type: Union[Network, BoundNetwork] - ip=None # type: Optional[str] - ): + load_balancer_id=load_balancer.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) + + def attach_to_network( + self, + load_balancer, # type: Union[LoadBalancer, BoundLoadBalancer] + network, # type: Union[Network, BoundNetwork] + ip=None, # type: Optional[str] + ): """Attach a Load Balancer to a Network. :param load_balancer: :class:` ` or :class:`LoadBalancer ` @@ -714,9 +801,12 @@ def attach_to_network(self, response = self._client.request( url="/load_balancers/{load_balancer_id}/actions/attach_to_network".format( - load_balancer_id=load_balancer.id), - method="POST", json=data) - return BoundAction(self._client.actions, response['action']) + load_balancer_id=load_balancer.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) def detach_from_network(self, load_balancer, network): # type: (Union[LoadBalancer, BoundLoadBalancer], Union[Network,BoundNetwork]) -> BoundAction @@ -731,13 +821,16 @@ def detach_from_network(self, load_balancer, network): } response = self._client.request( url="/load_balancers/{load_balancer_id}/actions/detach_from_network".format( - load_balancer_id=load_balancer.id), method="POST", - json=data) - return BoundAction(self._client.actions, response['action']) + load_balancer_id=load_balancer.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) def enable_public_interface(self, load_balancer): # type: (Union[LoadBalancer, BoundLoadBalancer]) -> BoundAction - """ Enables the public interface of a Load Balancer. + """Enables the public interface of a Load Balancer. :param load_balancer: :class:` ` or :class:`LoadBalancer ` @@ -746,13 +839,15 @@ def enable_public_interface(self, load_balancer): response = self._client.request( url="/load_balancers/{load_balancer_id}/actions/enable_public_interface".format( - load_balancer_id=load_balancer.id), - method="POST") - return BoundAction(self._client.actions, response['action']) + load_balancer_id=load_balancer.id + ), + method="POST", + ) + return BoundAction(self._client.actions, response["action"]) def disable_public_interface(self, load_balancer): # type: (Union[LoadBalancer, BoundLoadBalancer]) -> BoundAction - """ Disables the public interface of a Load Balancer. + """Disables the public interface of a Load Balancer. :param load_balancer: :class:` ` or :class:`LoadBalancer ` @@ -761,9 +856,11 @@ def disable_public_interface(self, load_balancer): response = self._client.request( url="/load_balancers/{load_balancer_id}/actions/disable_public_interface".format( - load_balancer_id=load_balancer.id), - method="POST") - return BoundAction(self._client.actions, response['action']) + load_balancer_id=load_balancer.id + ), + method="POST", + ) + return BoundAction(self._client.actions, response["action"]) def change_type(self, load_balancer, load_balancer_type): # type: ([LoadBalancer, BoundLoadBalancer], [LoadBalancerType, BoundLoadBalancerType]) ->BoundAction @@ -778,6 +875,10 @@ def change_type(self, load_balancer, load_balancer_type): "load_balancer_type": load_balancer_type.id_or_name, } response = self._client.request( - url="/load_balancers/{load_balancer_id}/actions/change_type".format(load_balancer_id=load_balancer.id), - method="POST", json=data) - return BoundAction(self._client.actions, response['action']) + url="/load_balancers/{load_balancer_id}/actions/change_type".format( + load_balancer_id=load_balancer.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) diff --git a/hcloud/load_balancers/domain.py b/hcloud/load_balancers/domain.py index 6f43e55..f932407 100644 --- a/hcloud/load_balancers/domain.py +++ b/hcloud/load_balancers/domain.py @@ -58,22 +58,22 @@ class LoadBalancer(BaseDomain): ) def __init__( - self, - id, - name=None, - public_net=None, - private_net=None, - location=None, - algorithm=None, - services=None, - load_balancer_type=None, - protection=None, - labels=None, - targets=None, - created=None, - outgoing_traffic=None, - ingoing_traffic=None, - included_traffic=None, + self, + id, + name=None, + public_net=None, + private_net=None, + location=None, + algorithm=None, + services=None, + load_balancer_type=None, + protection=None, + labels=None, + targets=None, + created=None, + outgoing_traffic=None, + ingoing_traffic=None, + included_traffic=None, ): self.id = id self.name = name @@ -109,8 +109,15 @@ class LoadBalancerService(BaseDomain): Configuration for http/https protocols, required when protocol is http/https """ - def __init__(self, protocol=None, listen_port=None, destination_port=None, proxyprotocol=None, health_check=None, - http=None): + def __init__( + self, + protocol=None, + listen_port=None, + destination_port=None, + proxyprotocol=None, + health_check=None, + http=None, + ): self.protocol = protocol self.listen_port = listen_port self.destination_port = destination_port @@ -122,19 +129,26 @@ def __init__(self, protocol=None, listen_port=None, destination_port=None, proxy class LoadBalancerServiceHttp(BaseDomain): """LoadBalancerServiceHttp Domain - :param cookie_name: str - Name of the cookie used for Session Stickness - :param cookie_lifetime: str - Lifetime of the cookie used for Session Stickness - :param certificates: list - IDs of the Certificates to use for TLS/SSL termination by the Load Balancer; empty for TLS/SSL passthrough or if protocol is "http" - :param redirect_http: bool - Redirect traffic from http port 80 to port 443 - :param sticky_sessions: bool - Use sticky sessions. Only available if protocol is "http" or "https". - """ - - def __init__(self, cookie_name=None, cookie_lifetime=None, certificates=None, redirect_http=None, sticky_sessions=None): + :param cookie_name: str + Name of the cookie used for Session Stickness + :param cookie_lifetime: str + Lifetime of the cookie used for Session Stickness + :param certificates: list + IDs of the Certificates to use for TLS/SSL termination by the Load Balancer; empty for TLS/SSL passthrough or if protocol is "http" + :param redirect_http: bool + Redirect traffic from http port 80 to port 443 + :param sticky_sessions: bool + Use sticky sessions. Only available if protocol is "http" or "https". + """ + + def __init__( + self, + cookie_name=None, + cookie_lifetime=None, + certificates=None, + redirect_http=None, + sticky_sessions=None, + ): self.cookie_name = cookie_name self.cookie_lifetime = cookie_lifetime self.certificates = certificates @@ -145,21 +159,29 @@ def __init__(self, cookie_name=None, cookie_lifetime=None, certificates=None, re class LoadBalancerHealthCheck(BaseDomain): """LoadBalancerHealthCheck Domain - :param protocol: str - Protocol of the service Choices: tcp, http, https - :param port: int - Port the healthcheck will be performed on - :param interval: int - Interval we trigger health check in - :param timeout: int - Timeout in sec after a try is assumed as timeout - :param retries: int - Retries we perform until we assume a target as unhealthy - :param http: LoadBalancerHealtCheckHttp - HTTP Config - """ - - def __init__(self, protocol=None, port=None, interval=None, timeout=None, retries=None, http=None): + :param protocol: str + Protocol of the service Choices: tcp, http, https + :param port: int + Port the healthcheck will be performed on + :param interval: int + Interval we trigger health check in + :param timeout: int + Timeout in sec after a try is assumed as timeout + :param retries: int + Retries we perform until we assume a target as unhealthy + :param http: LoadBalancerHealtCheckHttp + HTTP Config + """ + + def __init__( + self, + protocol=None, + port=None, + interval=None, + timeout=None, + retries=None, + http=None, + ): self.protocol = protocol self.port = port self.interval = interval @@ -171,19 +193,21 @@ def __init__(self, protocol=None, port=None, interval=None, timeout=None, retrie class LoadBalancerHealtCheckHttp(BaseDomain): """LoadBalancerHealtCheckHttp Domain - :param domain: str - Domain name to send in HTTP request. Can be null: In that case we will not send a domain name - :param path: str - HTTP Path send in Request - :param response: str - Optional HTTP response to receive in order to pass the health check - :param status_codes: list - List of HTTP status codes to receive in order to pass the health check - :param tls: bool - Type of health check - """ - - def __init__(self, domain=None, path=None, response=None, status_codes=None, tls=None): + :param domain: str + Domain name to send in HTTP request. Can be null: In that case we will not send a domain name + :param path: str + HTTP Path send in Request + :param response: str + Optional HTTP response to receive in order to pass the health check + :param status_codes: list + List of HTTP status codes to receive in order to pass the health check + :param tls: bool + Type of health check + """ + + def __init__( + self, domain=None, path=None, response=None, status_codes=None, tls=None + ): self.domain = domain self.path = path self.response = response @@ -194,19 +218,21 @@ def __init__(self, domain=None, path=None, response=None, status_codes=None, tls class LoadBalancerTarget(BaseDomain): """LoadBalancerTarget Domain - :param type: str - Type of the resource, can be server or label_selector - :param server: Server - Target server - :param label_selector: LoadBalancerTargetLabelSelector - Target label selector - :param ip: LoadBalancerTargetIP - Target IP - :param use_private_ip: bool - use the private IP instead of primary public IP + :param type: str + Type of the resource, can be server or label_selector + :param server: Server + Target server + :param label_selector: LoadBalancerTargetLabelSelector + Target label selector + :param ip: LoadBalancerTargetIP + Target IP + :param use_private_ip: bool + use the private IP instead of primary public IP """ - def __init__(self, type=None, server=None, label_selector=None, ip=None, use_private_ip=None): + def __init__( + self, type=None, server=None, label_selector=None, ip=None, use_private_ip=None + ): self.type = type self.server = server self.label_selector = label_selector @@ -252,17 +278,15 @@ class PublicNetwork(BaseDomain): :param ipv6: :class:`IPv6Network ` :param enabled: boolean """ - __slots__ = ( - "ipv4", - "ipv6", - "enabled" - ) - def __init__(self, - ipv4, # type: IPv4Address - ipv6, # type: IPv6Network - enabled, # type: bool - ): + __slots__ = ("ipv4", "ipv6", "enabled") + + def __init__( + self, + ipv4, # type: IPv4Address + ipv6, # type: IPv6Network + enabled, # type: bool + ): self.ipv4 = ipv4 self.ipv6 = ipv6 self.enabled = enabled @@ -274,13 +298,13 @@ class IPv4Address(BaseDomain): :param ip: str The IPv4 Address """ - __slots__ = ( - "ip", - ) - def __init__(self, - ip, # type: str - ): + __slots__ = ("ip",) + + def __init__( + self, + ip, # type: str + ): self.ip = ip @@ -290,13 +314,13 @@ class IPv6Network(BaseDomain): :param ip: str The IPv6 Network as CIDR Notation """ - __slots__ = ( - "ip", - ) - def __init__(self, - ip, # type: str - ): + __slots__ = ("ip",) + + def __init__( + self, + ip, # type: str + ): self.ip = ip @@ -308,15 +332,17 @@ class PrivateNet(BaseDomain): :param ip: str The main IP Address of the LoadBalancer in the Network """ + __slots__ = ( "network", "ip", ) - def __init__(self, - network, # type: BoundNetwork - ip, # type: str - ): + def __init__( + self, + network, # type: BoundNetwork + ip, # type: str + ): self.network = network self.ip = ip @@ -329,15 +355,16 @@ class CreateLoadBalancerResponse(BaseDomain): :param action: :class:`BoundAction ` Shows the progress of the Load Balancer creation """ + __slots__ = ( "load_balancer", "action", ) def __init__( - self, - load_balancer, # type: BoundLoadBalancer - action, # type: BoundAction + self, + load_balancer, # type: BoundLoadBalancer + action, # type: BoundAction ): self.load_balancer = load_balancer self.action = action diff --git a/hcloud/locations/client.py b/hcloud/locations/client.py index 85f0ea0..e3e0ffa 100644 --- a/hcloud/locations/client.py +++ b/hcloud/locations/client.py @@ -9,7 +9,7 @@ class BoundLocation(BoundModelBase): class LocationsClient(ClientEntityBase, GetEntityByNameMixin): - results_list_attribute_name = 'locations' + results_list_attribute_name = "locations" def get_by_id(self, id): # type: (int) -> locations.client.BoundLocation @@ -18,8 +18,10 @@ def get_by_id(self, id): :param id: int :return: :class:`BoundLocation ` """ - response = self._client.request(url="/locations/{location_id}".format(location_id=id), method="GET") - return BoundLocation(self, response['location']) + response = self._client.request( + url="/locations/{location_id}".format(location_id=id), method="GET" + ) + return BoundLocation(self, response["location"]) def get_list(self, name=None, page=None, per_page=None): # type: (Optional[str], Optional[int], Optional[int]) -> PageResult[List[BoundLocation], Meta] @@ -42,7 +44,10 @@ def get_list(self, name=None, page=None, per_page=None): params["per_page"] = per_page response = self._client.request(url="/locations", method="GET", params=params) - locations = [BoundLocation(self, location_data) for location_data in response['locations']] + locations = [ + BoundLocation(self, location_data) + for location_data in response["locations"] + ] return self._add_meta_to_result(locations, response) def get_all(self, name=None): diff --git a/hcloud/locations/domain.py b/hcloud/locations/domain.py index 63067f5..ee0bb45 100644 --- a/hcloud/locations/domain.py +++ b/hcloud/locations/domain.py @@ -31,19 +31,19 @@ class Location(BaseDomain, DomainIdentityMixin): "city", "latitude", "longitude", - "network_zone" + "network_zone", ) def __init__( - self, - id=None, - name=None, - description=None, - country=None, - city=None, - latitude=None, - longitude=None, - network_zone=None, + self, + id=None, + name=None, + description=None, + country=None, + city=None, + latitude=None, + longitude=None, + network_zone=None, ): self.id = id self.name = name diff --git a/hcloud/networks/client.py b/hcloud/networks/client.py index eafe70d..5adf41b 100644 --- a/hcloud/networks/client.py +++ b/hcloud/networks/client.py @@ -13,18 +13,22 @@ def __init__(self, client, data, complete=True): subnets = data.get("subnets", []) if subnets is not None: subnets = [NetworkSubnet.from_dict(subnet) for subnet in subnets] - data['subnets'] = subnets + data["subnets"] = subnets routes = data.get("routes", []) if routes is not None: routes = [NetworkRoute.from_dict(route) for route in routes] - data['routes'] = routes + data["routes"] = routes from hcloud.servers.client import BoundServer + servers = data.get("servers", []) if servers is not None: - servers = [BoundServer(client._client.servers, {"id": server}, complete=False) for server in servers] - data['servers'] = servers + servers = [ + BoundServer(client._client.servers, {"id": server}, complete=False) + for server in servers + ] + data["servers"] = servers super(BoundNetwork, self).__init__(client, data, complete) @@ -32,12 +36,12 @@ def update(self, name=None, labels=None): # type: (Optional[str], Optional[Dict[str, str]]) -> BoundNetwork """Updates a network. You can update a network’s name and a networks’s labels. - :param name: str (optional) - New name to set - :param labels: Dict[str, str] (optional) - User-defined labels (key-value pairs) - :return: :class:`BoundNetwork ` - """ + :param name: str (optional) + New name to set + :param labels: Dict[str, str] (optional) + User-defined labels (key-value pairs) + :return: :class:`BoundNetwork ` + """ return self._client.update(self, name, labels) def delete(self): @@ -153,11 +157,11 @@ def get_by_id(self, id): return BoundNetwork(self, response["network"]) def get_list( - self, - name=None, # type: Optional[str] - label_selector=None, # type: Optional[str] - page=None, # type: Optional[int] - per_page=None, # type: Optional[int] + self, + name=None, # type: Optional[str] + label_selector=None, # type: Optional[str] + page=None, # type: Optional[int] + per_page=None, # type: Optional[int] ): # type: (...) -> PageResults[List[BoundNetwork], Meta] """Get a list of networks from this account @@ -214,12 +218,12 @@ def get_by_name(self, name): return super(NetworksClient, self).get_by_name(name) def create( - self, - name, # type: str - ip_range, # type: str - subnets=None, # type: Optional[List[NetworkSubnet]] - routes=None, # type: Optional[List[NetworkRoute]] - labels=None, # type: Optional[Dict[str, str]] + self, + name, # type: str + ip_range, # type: str + subnets=None, # type: Optional[List[NetworkSubnet]] + routes=None, # type: Optional[List[NetworkRoute]] + labels=None, # type: Optional[Dict[str, str]] ): """Creates a network with range ip_range. @@ -237,10 +241,19 @@ def create( """ data = {"name": name, "ip_range": ip_range} if subnets is not None: - data["subnets"] = [{'type': subnet.type, 'ip_range': subnet.ip_range, 'network_zone': subnet.network_zone} - for subnet in subnets] + data["subnets"] = [ + { + "type": subnet.type, + "ip_range": subnet.ip_range, + "network_zone": subnet.network_zone, + } + for subnet in subnets + ] if routes is not None: - data["routes"] = [{'destination': route.destination, 'gateway': route.gateway} for route in routes] + data["routes"] = [ + {"destination": route.destination, "gateway": route.gateway} + for route in routes + ] if labels is not None: data["labels"] = labels @@ -284,7 +297,7 @@ def delete(self, network): return True def get_actions_list( - self, network, status=None, sort=None, page=None, per_page=None + self, network, status=None, sort=None, page=None, per_page=None ): # type: (Network, Optional[List[str]], Optional[List[str]], Optional[int], Optional[int]) -> PageResults[List[BoundAction], Meta] """Returns all action objects for a network. @@ -355,9 +368,13 @@ def add_subnet(self, network, subnet): data["vswitch_id"] = subnet.vswitch_id response = self._client.request( - url="/networks/{network_id}/actions/add_subnet".format(network_id=network.id), - method="POST", json=data) - return BoundAction(self._client.actions, response['action']) + url="/networks/{network_id}/actions/add_subnet".format( + network_id=network.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) def delete_subnet(self, network, subnet): # type: (Union[Network, BoundNetwork], NetworkSubnet) -> List[BoundAction] @@ -373,9 +390,13 @@ def delete_subnet(self, network, subnet): } response = self._client.request( - url="/networks/{network_id}/actions/delete_subnet".format(network_id=network.id), - method="POST", json=data) - return BoundAction(self._client.actions, response['action']) + url="/networks/{network_id}/actions/delete_subnet".format( + network_id=network.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) def add_route(self, network, route): # type: (Union[Network, BoundNetwork], NetworkRoute) -> List[BoundAction] @@ -392,9 +413,13 @@ def add_route(self, network, route): } response = self._client.request( - url="/networks/{network_id}/actions/add_route".format(network_id=network.id), - method="POST", json=data) - return BoundAction(self._client.actions, response['action']) + url="/networks/{network_id}/actions/add_route".format( + network_id=network.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) def delete_route(self, network, route): # type: (Union[Network, BoundNetwork], NetworkRoute) -> List[BoundAction] @@ -411,9 +436,13 @@ def delete_route(self, network, route): } response = self._client.request( - url="/networks/{network_id}/actions/delete_route".format(network_id=network.id), - method="POST", json=data) - return BoundAction(self._client.actions, response['action']) + url="/networks/{network_id}/actions/delete_route".format( + network_id=network.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) def change_ip_range(self, network, ip_range): # type: (Union[Network, BoundNetwork], str) -> List[BoundAction] @@ -429,9 +458,13 @@ def change_ip_range(self, network, ip_range): } response = self._client.request( - url="/networks/{network_id}/actions/change_ip_range".format(network_id=network.id), - method="POST", json=data) - return BoundAction(self._client.actions, response['action']) + url="/networks/{network_id}/actions/change_ip_range".format( + network_id=network.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) def change_protection(self, network, delete=None): # type: (Union[Network, BoundNetwork], Optional[bool]) -> BoundAction @@ -447,6 +480,10 @@ def change_protection(self, network, delete=None): data.update({"delete": delete}) response = self._client.request( - url="/networks/{network_id}/actions/change_protection".format(network_id=network.id), - method="POST", json=data) - return BoundAction(self._client.actions, response['action']) + url="/networks/{network_id}/actions/change_protection".format( + network_id=network.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) diff --git a/hcloud/networks/domain.py b/hcloud/networks/domain.py index 4748840..8fc2c4c 100644 --- a/hcloud/networks/domain.py +++ b/hcloud/networks/domain.py @@ -34,20 +34,20 @@ class Network(BaseDomain): "servers", "protection", "labels", - "created" + "created", ) def __init__( - self, - id, - name=None, - created=None, - ip_range=None, - subnets=None, - routes=None, - servers=None, - protection=None, - labels=None, + self, + id, + name=None, + created=None, + ip_range=None, + subnets=None, + routes=None, + servers=None, + protection=None, + labels=None, ): self.id = id self.name = name @@ -74,6 +74,7 @@ class NetworkSubnet(BaseDomain): :param vswitch_id: int ID of the vSwitch. """ + TYPE_SERVER = "server" """Subnet Type server, deprecated, use TYPE_CLOUD instead""" TYPE_CLOUD = "cloud" @@ -82,7 +83,9 @@ class NetworkSubnet(BaseDomain): """Subnet Type vSwitch""" __slots__ = ("type", "ip_range", "network_zone", "gateway", "vswitch_id") - def __init__(self, ip_range, type=None, network_zone=None, gateway=None, vswitch_id=None): + def __init__( + self, ip_range, type=None, network_zone=None, gateway=None, vswitch_id=None + ): self.type = type self.ip_range = ip_range self.network_zone = network_zone @@ -118,9 +121,9 @@ class CreateNetworkResponse(BaseDomain): __slots__ = ("network", "action") def __init__( - self, - network, # type: BoundNetwork - action # type: BoundAction + self, + network, # type: BoundNetwork + action, # type: BoundAction ): self.network = network self.action = action diff --git a/hcloud/server_types/client.py b/hcloud/server_types/client.py index c254857..ab759ae 100644 --- a/hcloud/server_types/client.py +++ b/hcloud/server_types/client.py @@ -7,7 +7,7 @@ class BoundServerType(BoundModelBase): class ServerTypesClient(ClientEntityBase, GetEntityByNameMixin): - results_list_attribute_name = 'server_types' + results_list_attribute_name = "server_types" def get_by_id(self, id): # type: (int) -> server_types.client.BoundServerType @@ -16,8 +16,10 @@ def get_by_id(self, id): :param id: int :return: :class:`BoundServerType ` """ - response = self._client.request(url="/server_types/{server_type_id}".format(server_type_id=id), method="GET") - return BoundServerType(self, response['server_type']) + response = self._client.request( + url="/server_types/{server_type_id}".format(server_type_id=id), method="GET" + ) + return BoundServerType(self, response["server_type"]) def get_list(self, name=None, page=None, per_page=None): # type: (Optional[str], Optional[int], Optional[int]) -> PageResults[List[BoundServerType], Meta] @@ -33,14 +35,19 @@ def get_list(self, name=None, page=None, per_page=None): """ params = {} if name is not None: - params['name'] = name + params["name"] = name if page is not None: - params['page'] = page + params["page"] = page if per_page is not None: - params['per_page'] = per_page + params["per_page"] = per_page - response = self._client.request(url="/server_types", method="GET", params=params) - server_types = [BoundServerType(self, server_type_data) for server_type_data in response['server_types']] + response = self._client.request( + url="/server_types", method="GET", params=params + ) + server_types = [ + BoundServerType(self, server_type_data) + for server_type_data in response["server_types"] + ] return self._add_meta_to_result(server_types, response) def get_all(self, name=None): diff --git a/hcloud/server_types/domain.py b/hcloud/server_types/domain.py index d63d77f..8421a0b 100644 --- a/hcloud/server_types/domain.py +++ b/hcloud/server_types/domain.py @@ -26,6 +26,7 @@ class ServerType(BaseDomain, DomainIdentityMixin): :param deprecated: bool True if server type is deprecated """ + __slots__ = ( "id", "name", @@ -36,7 +37,7 @@ class ServerType(BaseDomain, DomainIdentityMixin): "prices", "storage_type", "cpu_type", - "deprecated" + "deprecated", ) def __init__( @@ -50,7 +51,7 @@ def __init__( prices=None, storage_type=None, cpu_type=None, - deprecated=None + deprecated=None, ): self.id = id self.name = name diff --git a/hcloud/servers/client.py b/hcloud/servers/client.py index 9070ca4..7a8feea 100644 --- a/hcloud/servers/client.py +++ b/hcloud/servers/client.py @@ -6,8 +6,18 @@ from hcloud.firewalls.client import BoundFirewall from hcloud.floating_ips.client import BoundFloatingIP from hcloud.isos.client import BoundIso -from hcloud.servers.domain import Server, CreateServerResponse, ResetPasswordResponse, EnableRescueResponse, \ - RequestConsoleResponse, PublicNetwork, IPv4Address, IPv6Network, PrivateNet, PublicNetworkFirewall +from hcloud.servers.domain import ( + Server, + CreateServerResponse, + ResetPasswordResponse, + EnableRescueResponse, + RequestConsoleResponse, + PublicNetwork, + IPv4Address, + IPv6Network, + PrivateNet, + PublicNetworkFirewall, +) from hcloud.volumes.client import BoundVolume from hcloud.images.domain import CreateImageResponse from hcloud.images.client import BoundImage @@ -22,49 +32,74 @@ class BoundServer(BoundModelBase): def __init__(self, client, data, complete=True): - datacenter = data.get('datacenter') + datacenter = data.get("datacenter") if datacenter is not None: - data['datacenter'] = BoundDatacenter(client._client.datacenters, datacenter) + data["datacenter"] = BoundDatacenter(client._client.datacenters, datacenter) - volumes = data.get('volumes', []) + volumes = data.get("volumes", []) if volumes: - volumes = [BoundVolume(client._client.volumes, {"id": volume}, complete=False) for volume in volumes] - data['volumes'] = volumes + volumes = [ + BoundVolume(client._client.volumes, {"id": volume}, complete=False) + for volume in volumes + ] + data["volumes"] = volumes image = data.get("image", None) if image is not None: - data['image'] = BoundImage(client._client.images, image) + data["image"] = BoundImage(client._client.images, image) iso = data.get("iso", None) if iso is not None: - data['iso'] = BoundIso(client._client.isos, iso) + data["iso"] = BoundIso(client._client.isos, iso) server_type = data.get("server_type") if server_type is not None: - data['server_type'] = BoundServerType(client._client.server_types, server_type) + data["server_type"] = BoundServerType( + client._client.server_types, server_type + ) public_net = data.get("public_net") if public_net: - ipv4_address = IPv4Address(**public_net['ipv4']) - ipv6_network = IPv6Network(**public_net['ipv6']) - floating_ips = [BoundFloatingIP(client._client.floating_ips, {"id": floating_ip}, complete=False) for - floating_ip in public_net['floating_ips']] + ipv4_address = IPv4Address.from_dict(public_net["ipv4"]) + ipv6_network = IPv6Network.from_dict(public_net["ipv6"]) + floating_ips = [ + BoundFloatingIP( + client._client.floating_ips, {"id": floating_ip}, complete=False + ) + for floating_ip in public_net["floating_ips"] + ] firewalls = [ PublicNetworkFirewall( - BoundFirewall(client._client.firewalls, {"id": firewall["id"]}, complete=False), - status=firewall["status"] - ) for firewall in public_net.get("firewalls", []) + BoundFirewall( + client._client.firewalls, {"id": firewall["id"]}, complete=False + ), + status=firewall["status"], + ) + for firewall in public_net.get("firewalls", []) ] - data['public_net'] = PublicNetwork(ipv4=ipv4_address, ipv6=ipv6_network, floating_ips=floating_ips, - firewalls=firewalls) + data["public_net"] = PublicNetwork( + ipv4=ipv4_address, + ipv6=ipv6_network, + floating_ips=floating_ips, + firewalls=firewalls, + ) private_nets = data.get("private_net") if private_nets: - private_nets = [PrivateNet( - network=BoundNetwork(client._client.networks, {"id": private_net['network']}, complete=False), - ip=private_net['ip'], alias_ips=private_net['alias_ips'], mac_address=private_net['mac_address']) for - private_net in private_nets] - data['private_net'] = private_nets + private_nets = [ + PrivateNet( + network=BoundNetwork( + client._client.networks, + {"id": private_net["network"]}, + complete=False, + ), + ip=private_net["ip"], + alias_ips=private_net["alias_ips"], + mac_address=private_net["mac_address"], + ) + for private_net in private_nets + ] + data["private_net"] = private_nets super(BoundServer, self).__init__(client, data, complete) @@ -100,12 +135,12 @@ def update(self, name=None, labels=None): # type: (Optional[str], Optional[Dict[str, str]]) -> BoundServer """Updates a server. You can update a server’s name and a server’s labels. - :param name: str (optional) - New name to set - :param labels: Dict[str, str] (optional) - User-defined labels (key-value pairs) - :return: :class:`BoundServer ` - """ + :param name: str (optional) + New name to set + :param labels: Dict[str, str] (optional) + User-defined labels (key-value pairs) + :return: :class:`BoundServer ` + """ return self._client.update(self, name, labels) def delete(self): @@ -158,7 +193,7 @@ def shutdown(self): def reset_password(self): # type: () -> ResetPasswordResponse - """ Resets the root password. Only works for Linux systems that are running the qemu guest agent. + """Resets the root password. Only works for Linux systems that are running the qemu guest agent. :return: :class:`ResetPasswordResponse ` """ @@ -322,7 +357,7 @@ def change_alias_ips(self, network, alias_ips): class ServersClient(ClientEntityBase, GetEntityByNameMixin): - results_list_attribute_name = 'servers' + results_list_attribute_name = "servers" def get_by_id(self, id): # type: (int) -> BoundServer @@ -331,16 +366,19 @@ def get_by_id(self, id): :param id: int :return: :class:`BoundServer ` """ - response = self._client.request(url="/servers/{server_id}".format(server_id=id), method="GET") - return BoundServer(self, response['server']) - - def get_list(self, - name=None, # type: Optional[str] - label_selector=None, # type: Optional[str] - page=None, # type: Optional[int] - per_page=None, # type: Optional[int] - status=None, # type: Optional[List[str]] - ): + response = self._client.request( + url="/servers/{server_id}".format(server_id=id), method="GET" + ) + return BoundServer(self, response["server"]) + + def get_list( + self, + name=None, # type: Optional[str] + label_selector=None, # type: Optional[str] + page=None, # type: Optional[int] + per_page=None, # type: Optional[int] + status=None, # type: Optional[List[str]] + ): # type: (...) -> PageResults[List[BoundServer], Meta] """Get a list of servers from this account @@ -358,19 +396,21 @@ def get_list(self, """ params = {} if name is not None: - params['name'] = name + params["name"] = name if label_selector is not None: - params['label_selector'] = label_selector + params["label_selector"] = label_selector if status is not None: params["status"] = status if page is not None: - params['page'] = page + params["page"] = page if per_page is not None: - params['per_page'] = per_page + params["per_page"] = per_page response = self._client.request(url="/servers", method="GET", params=params) - ass_servers = [BoundServer(self, server_data) for server_data in response['servers']] + ass_servers = [ + BoundServer(self, server_data) for server_data in response["servers"] + ] return self._add_meta_to_result(ass_servers, response) def get_all(self, name=None, label_selector=None, status=None): @@ -385,7 +425,9 @@ def get_all(self, name=None, label_selector=None, status=None): Can be used to filter servers by their status. The response will only contain servers matching the status. :return: List[:class:`BoundServer `] """ - return super(ServersClient, self).get_all(name=name, label_selector=label_selector, status=status) + return super(ServersClient, self).get_all( + name=name, label_selector=label_selector, status=status + ) def get_by_name(self, name): # type: (str) -> BoundServer @@ -397,21 +439,22 @@ def get_by_name(self, name): """ return super(ServersClient, self).get_by_name(name) - def create(self, - name, # type: str - server_type, # type: ServerType - image, # type: Image - ssh_keys=None, # type: Optional[List[SSHKey]] - volumes=None, # type: Optional[List[Volume]] - firewalls=None, # type: Optional[List[Firewall]] - networks=None, # type: Optional[List[Network]] - user_data=None, # type: Optional[str] - labels=None, # type: Optional[Dict[str, str]] - location=None, # type: Optional[Location] - datacenter=None, # type: Optional[Datacenter] - start_after_create=True, # type: Optional[bool] - automount=None # type: Optional[bool] - ): + def create( + self, + name, # type: str + server_type, # type: ServerType + image, # type: Image + ssh_keys=None, # type: Optional[List[SSHKey]] + volumes=None, # type: Optional[List[Volume]] + firewalls=None, # type: Optional[List[Firewall]] + networks=None, # type: Optional[List[Network]] + user_data=None, # type: Optional[str] + labels=None, # type: Optional[Dict[str, str]] + location=None, # type: Optional[Location] + datacenter=None, # type: Optional[Datacenter] + start_after_create=True, # type: Optional[bool] + automount=None, # type: Optional[bool] + ): # type: (...) -> CreateServerResponse """Creates a new server. Returns preliminary information about the server as well as an action that covers progress of creation. @@ -440,42 +483,47 @@ def create(self, :return: :class:`CreateServerResponse ` """ data = { - 'name': name, - 'server_type': server_type.id_or_name, + "name": name, + "server_type": server_type.id_or_name, "start_after_create": start_after_create, - "image": image.id_or_name + "image": image.id_or_name, } if location is not None: - data['location'] = location.id_or_name + data["location"] = location.id_or_name if datacenter is not None: - data['datacenter'] = datacenter.id_or_name + data["datacenter"] = datacenter.id_or_name if ssh_keys is not None: - data['ssh_keys'] = [ssh_key.id_or_name for ssh_key in ssh_keys] + data["ssh_keys"] = [ssh_key.id_or_name for ssh_key in ssh_keys] if volumes is not None: - data['volumes'] = [volume.id for volume in volumes] + data["volumes"] = [volume.id for volume in volumes] if networks is not None: - data['networks'] = [network.id for network in networks] + data["networks"] = [network.id for network in networks] if firewalls is not None: - data['firewalls'] = [{"firewall": firewall.id} for firewall in firewalls] + data["firewalls"] = [{"firewall": firewall.id} for firewall in firewalls] if user_data is not None: - data['user_data'] = user_data + data["user_data"] = user_data if labels is not None: - data['labels'] = labels + data["labels"] = labels if automount is not None: data["automount"] = automount response = self._client.request(url="/servers", method="POST", json=data) result = CreateServerResponse( - server=BoundServer(self, response['server']), - action=BoundAction(self._client.actions, response['action']), - next_actions=[BoundAction(self._client.actions, action) for action in response['next_actions']], - root_password=response['root_password'] + server=BoundServer(self, response["server"]), + action=BoundAction(self._client.actions, response["action"]), + next_actions=[ + BoundAction(self._client.actions, action) + for action in response["next_actions"] + ], + root_password=response["root_password"], ) return result - def get_actions_list(self, server, status=None, sort=None, page=None, per_page=None): + def get_actions_list( + self, server, status=None, sort=None, page=None, per_page=None + ): # type: (Server, Optional[List[str]], Optional[List[str]], Optional[int], Optional[int]) -> PageResults[List[BoundAction], Meta] """Returns all action objects for a server. @@ -500,10 +548,16 @@ def get_actions_list(self, server, status=None, sort=None, page=None, per_page=N if per_page is not None: params["per_page"] = per_page - response = self._client.request(url="/servers/{server_id}/actions".format(server_id=server.id), method="GET", - params=params) - actions = [BoundAction(self._client.actions, action_data) for action_data in response['actions']] - return add_meta_to_result(actions, response, 'actions') + response = self._client.request( + url="/servers/{server_id}/actions".format(server_id=server.id), + method="GET", + params=params, + ) + actions = [ + BoundAction(self._client.actions, action_data) + for action_data in response["actions"] + ] + return add_meta_to_result(actions, response, "actions") def get_actions(self, server, status=None, sort=None): # type: (Server, Optional[List[str]], Optional[List[str]]) -> List[BoundAction] @@ -534,8 +588,12 @@ def update(self, server, name=None, labels=None): data.update({"name": name}) if labels is not None: data.update({"labels": labels}) - response = self._client.request(url="/servers/{server_id}".format(server_id=server.id), method="PUT", json=data) - return BoundServer(self, response['server']) + response = self._client.request( + url="/servers/{server_id}".format(server_id=server.id), + method="PUT", + json=data, + ) + return BoundServer(self, response["server"]) def delete(self, server): # type: (Server) -> BoundAction @@ -544,8 +602,10 @@ def delete(self, server): :param server: :class:`BoundServer ` or :class:`Server ` :return: :class:`BoundAction ` """ - response = self._client.request(url="/servers/{server_id}".format(server_id=server.id), method="DELETE") - return BoundAction(self._client.actions, response['action']) + response = self._client.request( + url="/servers/{server_id}".format(server_id=server.id), method="DELETE" + ) + return BoundAction(self._client.actions, response["action"]) def power_off(self, server): # type: (Server) -> Action @@ -554,9 +614,11 @@ def power_off(self, server): :param server: :class:`BoundServer ` or :class:`Server ` :return: :class:`BoundAction ` """ - response = self._client.request(url="/servers/{server_id}/actions/poweroff".format(server_id=server.id), - method="POST") - return BoundAction(self._client.actions, response['action']) + response = self._client.request( + url="/servers/{server_id}/actions/poweroff".format(server_id=server.id), + method="POST", + ) + return BoundAction(self._client.actions, response["action"]) def power_on(self, server): # type: (servers.domain.Server) -> actions.domain.Action @@ -565,9 +627,11 @@ def power_on(self, server): :param server: :class:`BoundServer ` or :class:`Server ` :return: :class:`BoundAction ` """ - response = self._client.request(url="/servers/{server_id}/actions/poweron".format(server_id=server.id), - method="POST") - return BoundAction(self._client.actions, response['action']) + response = self._client.request( + url="/servers/{server_id}/actions/poweron".format(server_id=server.id), + method="POST", + ) + return BoundAction(self._client.actions, response["action"]) def reboot(self, server): # type: (servers.domain.Server) -> actions.domain.Action @@ -576,9 +640,11 @@ def reboot(self, server): :param server: :class:`BoundServer ` or :class:`Server ` :return: :class:`BoundAction ` """ - response = self._client.request(url="/servers/{server_id}/actions/reboot".format(server_id=server.id), - method="POST") - return BoundAction(self._client.actions, response['action']) + response = self._client.request( + url="/servers/{server_id}/actions/reboot".format(server_id=server.id), + method="POST", + ) + return BoundAction(self._client.actions, response["action"]) def reset(self, server): # type: (servers.domain.Server) -> actions.domainAction @@ -587,9 +653,11 @@ def reset(self, server): :param server: :class:`BoundServer ` or :class:`Server ` :return: :class:`BoundAction ` """ - response = self._client.request(url="/servers/{server_id}/actions/reset".format(server_id=server.id), - method="POST") - return BoundAction(self._client.actions, response['action']) + response = self._client.request( + url="/servers/{server_id}/actions/reset".format(server_id=server.id), + method="POST", + ) + return BoundAction(self._client.actions, response["action"]) def shutdown(self, server): # type: (servers.domain.Server) -> actions.domainAction @@ -598,21 +666,29 @@ def shutdown(self, server): :param server: :class:`BoundServer ` or :class:`Server ` :return: :class:`BoundAction ` """ - response = self._client.request(url="/servers/{server_id}/actions/shutdown".format(server_id=server.id), - method="POST") - return BoundAction(self._client.actions, response['action']) + response = self._client.request( + url="/servers/{server_id}/actions/shutdown".format(server_id=server.id), + method="POST", + ) + return BoundAction(self._client.actions, response["action"]) def reset_password(self, server): # type: (servers.domain.Server) -> ResetPasswordResponse - """ Resets the root password. Only works for Linux systems that are running the qemu guest agent. + """Resets the root password. Only works for Linux systems that are running the qemu guest agent. :param server: :class:`BoundServer ` or :class:`Server ` :return: :class:`ResetPasswordResponse ` """ - response = self._client.request(url="/servers/{server_id}/actions/reset_password".format(server_id=server.id), - method="POST") - return ResetPasswordResponse(action=BoundAction(self._client.actions, response['action']), - root_password=response['root_password']) + response = self._client.request( + url="/servers/{server_id}/actions/reset_password".format( + server_id=server.id + ), + method="POST", + ) + return ResetPasswordResponse( + action=BoundAction(self._client.actions, response["action"]), + root_password=response["root_password"], + ) def change_type(self, server, server_type, upgrade_disk): # type: (servers.domain.Server, BoundServerType, bool) -> actions.domainAction @@ -625,13 +701,13 @@ def change_type(self, server, server_type, upgrade_disk): If false, do not upgrade the disk. This allows downgrading the server type later. :return: :class:`BoundAction ` """ - data = { - "server_type": server_type.id_or_name, - "upgrade_disk": upgrade_disk - } - response = self._client.request(url="/servers/{server_id}/actions/change_type".format(server_id=server.id), - method="POST", json=data) - return BoundAction(self._client.actions, response['action']) + data = {"server_type": server_type.id_or_name, "upgrade_disk": upgrade_disk} + response = self._client.request( + url="/servers/{server_id}/actions/change_type".format(server_id=server.id), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) def enable_rescue(self, server, type=None, ssh_keys=None): # type: (servers.domain.Server, str, Optional[List[str]]) -> EnableRescueResponse @@ -645,16 +721,21 @@ def enable_rescue(self, server, type=None, ssh_keys=None): Array of SSH key IDs which should be injected into the rescue system. Only available for types: linux64 and linux32. :return: :class:`EnableRescueResponse ` """ - data = { - "type": type - } + data = {"type": type} if ssh_keys is not None: data.update({"ssh_keys": ssh_keys}) - response = self._client.request(url="/servers/{server_id}/actions/enable_rescue".format(server_id=server.id), - method="POST", json=data) - return EnableRescueResponse(action=BoundAction(self._client.actions, response['action']), - root_password=response['root_password']) + response = self._client.request( + url="/servers/{server_id}/actions/enable_rescue".format( + server_id=server.id + ), + method="POST", + json=data, + ) + return EnableRescueResponse( + action=BoundAction(self._client.actions, response["action"]), + root_password=response["root_password"], + ) def disable_rescue(self, server): # type: (servers.domain.Server) -> actions.domainAction @@ -663,9 +744,13 @@ def disable_rescue(self, server): :param server: :class:`BoundServer ` or :class:`Server ` :return: :class:`BoundAction ` """ - response = self._client.request(url="/servers/{server_id}/actions/disable_rescue".format(server_id=server.id), - method="POST") - return BoundAction(self._client.actions, response['action']) + response = self._client.request( + url="/servers/{server_id}/actions/disable_rescue".format( + server_id=server.id + ), + method="POST", + ) + return BoundAction(self._client.actions, response["action"]) def create_image(self, server, description=None, type=None, labels=None): # type: (servers.domain.Server, str, str, Optional[Dict[str, str]]) -> CreateImageResponse @@ -691,10 +776,15 @@ def create_image(self, server, description=None, type=None, labels=None): if labels is not None: data.update({"labels": labels}) - response = self._client.request(url="/servers/{server_id}/actions/create_image".format(server_id=server.id), - method="POST", json=data) - return CreateImageResponse(action=BoundAction(self._client.actions, response['action']), - image=BoundImage(self._client.images, response['image'])) + response = self._client.request( + url="/servers/{server_id}/actions/create_image".format(server_id=server.id), + method="POST", + json=data, + ) + return CreateImageResponse( + action=BoundAction(self._client.actions, response["action"]), + image=BoundImage(self._client.images, response["image"]), + ) def rebuild(self, server, image): # type: (servers.domain.Server, Image) -> actions.domainAction @@ -704,12 +794,13 @@ def rebuild(self, server, image): :param image: :class:`BoundImage ` or :class:`Image ` :return: :class:`BoundAction ` """ - data = { - "image": image.id_or_name - } - response = self._client.request(url="/servers/{server_id}/actions/rebuild".format(server_id=server.id), - method="POST", json=data) - return BoundAction(self._client.actions, response['action']) + data = {"image": image.id_or_name} + response = self._client.request( + url="/servers/{server_id}/actions/rebuild".format(server_id=server.id), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) def enable_backup(self, server): # type: (servers.domain.Server) -> actions.domainAction @@ -718,9 +809,13 @@ def enable_backup(self, server): :param server: :class:`BoundServer ` or :class:`Server ` :return: :class:`BoundAction ` """ - response = self._client.request(url="/servers/{server_id}/actions/enable_backup".format(server_id=server.id), - method="POST") - return BoundAction(self._client.actions, response['action']) + response = self._client.request( + url="/servers/{server_id}/actions/enable_backup".format( + server_id=server.id + ), + method="POST", + ) + return BoundAction(self._client.actions, response["action"]) def disable_backup(self, server): # type: (servers.domain.Server) -> actions.domainAction @@ -729,9 +824,13 @@ def disable_backup(self, server): :param server: :class:`BoundServer ` or :class:`Server ` :return: :class:`BoundAction ` """ - response = self._client.request(url="/servers/{server_id}/actions/disable_backup".format(server_id=server.id), - method="POST") - return BoundAction(self._client.actions, response['action']) + response = self._client.request( + url="/servers/{server_id}/actions/disable_backup".format( + server_id=server.id + ), + method="POST", + ) + return BoundAction(self._client.actions, response["action"]) def attach_iso(self, server, iso): # type: (servers.domain.Server, Iso) -> actions.domainAction @@ -741,12 +840,13 @@ def attach_iso(self, server, iso): :param iso: :class:`BoundIso ` or :class:`Server ` :return: :class:`BoundAction ` """ - data = { - "iso": iso.id_or_name - } - response = self._client.request(url="/servers/{server_id}/actions/attach_iso".format(server_id=server.id), - method="POST", json=data) - return BoundAction(self._client.actions, response['action']) + data = {"iso": iso.id_or_name} + response = self._client.request( + url="/servers/{server_id}/actions/attach_iso".format(server_id=server.id), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) def detach_iso(self, server): # type: (servers.domain.Server) -> actions.domainAction @@ -755,9 +855,11 @@ def detach_iso(self, server): :param server: :class:`BoundServer ` or :class:`Server ` :return: :class:`BoundAction ` """ - response = self._client.request(url="/servers/{server_id}/actions/detach_iso".format(server_id=server.id), - method="POST") - return BoundAction(self._client.actions, response['action']) + response = self._client.request( + url="/servers/{server_id}/actions/detach_iso".format(server_id=server.id), + method="POST", + ) + return BoundAction(self._client.actions, response["action"]) def change_dns_ptr(self, server, ip, dns_ptr): # type: (servers.domain.Server, str, str) -> actions.domainAction @@ -770,13 +872,15 @@ def change_dns_ptr(self, server, ip, dns_ptr): Hostname to set as a reverse DNS PTR entry, will reset to original default value if `None` :return: :class:`BoundAction ` """ - data = { - "ip": ip, - "dns_ptr": dns_ptr - } - response = self._client.request(url="/servers/{server_id}/actions/change_dns_ptr".format(server_id=server.id), - method="POST", json=data) - return BoundAction(self._client.actions, response['action']) + data = {"ip": ip, "dns_ptr": dns_ptr} + response = self._client.request( + url="/servers/{server_id}/actions/change_dns_ptr".format( + server_id=server.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) def change_protection(self, server, delete=None, rebuild=None): # type: (servers.domain.Server, Optional[bool], Optional[bool]) -> actions.domainAction @@ -796,8 +900,13 @@ def change_protection(self, server, delete=None, rebuild=None): data.update({"rebuild": rebuild}) response = self._client.request( - url="/servers/{server_id}/actions/change_protection".format(server_id=server.id), method="POST", json=data) - return BoundAction(self._client.actions, response['action']) + url="/servers/{server_id}/actions/change_protection".format( + server_id=server.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) def request_console(self, server): # type: (servers.domain.Server) -> RequestConsoleResponse @@ -806,10 +915,17 @@ def request_console(self, server): :param server: :class:`BoundServer ` or :class:`Server ` :return: :class:`RequestConsoleResponse ` """ - response = self._client.request(url="/servers/{server_id}/actions/request_console".format(server_id=server.id), - method="POST") - return RequestConsoleResponse(action=BoundAction(self._client.actions, response['action']), - wss_url=response['wss_url'], password=response['password']) + response = self._client.request( + url="/servers/{server_id}/actions/request_console".format( + server_id=server.id + ), + method="POST", + ) + return RequestConsoleResponse( + action=BoundAction(self._client.actions, response["action"]), + wss_url=response["wss_url"], + password=response["password"], + ) def attach_to_network(self, server, network, ip=None, alias_ips=None): # type: (Union[Server,BoundServer], Union[Network,BoundNetwork],Optional[str], Optional[List[str]]) -> BoundAction @@ -831,9 +947,13 @@ def attach_to_network(self, server, network, ip=None, alias_ips=None): if alias_ips is not None: data.update({"alias_ips": alias_ips}) response = self._client.request( - url="/servers/{server_id}/actions/attach_to_network".format(server_id=server.id), method="POST", - json=data) - return BoundAction(self._client.actions, response['action']) + url="/servers/{server_id}/actions/attach_to_network".format( + server_id=server.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) def detach_from_network(self, server, network): # type: (Union[Server,BoundServer], Union[Network,BoundNetwork]) -> BoundAction @@ -847,9 +967,13 @@ def detach_from_network(self, server, network): "network": network.id, } response = self._client.request( - url="/servers/{server_id}/actions/detach_from_network".format(server_id=server.id), method="POST", - json=data) - return BoundAction(self._client.actions, response['action']) + url="/servers/{server_id}/actions/detach_from_network".format( + server_id=server.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) def change_alias_ips(self, server, network, alias_ips): # type: (Union[Server,BoundServer], Union[Network,BoundNetwork], List[str]) -> BoundAction @@ -861,11 +985,12 @@ def change_alias_ips(self, server, network, alias_ips): New alias IPs to set for this server. :return: :class:`BoundAction ` """ - data = { - "network": network.id, - "alias_ips": alias_ips - } + data = {"network": network.id, "alias_ips": alias_ips} response = self._client.request( - url="/servers/{server_id}/actions/change_alias_ips".format(server_id=server.id), method="POST", - json=data) - return BoundAction(self._client.actions, response['action']) + url="/servers/{server_id}/actions/change_alias_ips".format( + server_id=server.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) diff --git a/hcloud/servers/domain.py b/hcloud/servers/domain.py index 81db9bf..3a66995 100644 --- a/hcloud/servers/domain.py +++ b/hcloud/servers/domain.py @@ -44,6 +44,7 @@ class Server(BaseDomain): :param private_net: List[:class:`PrivateNet `] :param firewalls: List[:class:`PublicNetworkFirewall `] """ - __slots__ = ( - "ipv4", - "ipv6", - "floating_ips", - "firewalls" - ) - def __init__(self, - ipv4, # type: IPv4Address - ipv6, # type: IPv6Network - floating_ips, # type: List[BoundFloatingIP] - firewalls=None, # type: List[PublicNetworkFirewall] - ): + __slots__ = ("ipv4", "ipv6", "floating_ips", "firewalls") + + def __init__( + self, + ipv4, # type: IPv4Address + ipv6, # type: IPv6Network + floating_ips, # type: List[BoundFloatingIP] + firewalls=None, # type: List[PublicNetworkFirewall] + ): self.ipv4 = ipv4 self.ipv6 = ipv6 self.floating_ips = floating_ips @@ -266,20 +253,19 @@ class PublicNetworkFirewall(BaseDomain): :param firewall: :class:`BoundFirewall ` :param status: str """ - __slots__ = ( - "firewall", - "status" - ) + + __slots__ = ("firewall", "status") STATUS_APPLIED = "applied" """Public Network Firewall Status applied""" STATUS_PENDING = "pending" """Public Network Firewall Status pending""" - def __init__(self, - firewall, # type: BoundFirewall - status, # type: str - ): + def __init__( + self, + firewall, # type: BoundFirewall + status, # type: str + ): self.firewall = firewall self.status = status @@ -294,17 +280,15 @@ class IPv4Address(BaseDomain): :param dns_ptr: str DNS PTR for the ip """ - __slots__ = ( - "ip", - "blocked", - "dns_ptr" - ) - def __init__(self, - ip, # type: str - blocked, # type: bool - dns_ptr, # type: str - ): + __slots__ = ("ip", "blocked", "dns_ptr") + + def __init__( + self, + ip, # type: str + blocked, # type: bool + dns_ptr, # type: str + ): self.ip = ip self.blocked = blocked self.dns_ptr = dns_ptr @@ -324,19 +308,15 @@ class IPv6Network(BaseDomain): :param network_mask: str The network mask """ - __slots__ = ( - "ip", - "blocked", - "dns_ptr", - "network", - "network_mask" - ) - def __init__(self, - ip, # type: str - blocked, # type: bool - dns_ptr, # type: list - ): + __slots__ = ("ip", "blocked", "dns_ptr", "network", "network_mask") + + def __init__( + self, + ip, # type: str + blocked, # type: bool + dns_ptr, # type: list + ): self.ip = ip self.blocked = blocked self.dns_ptr = dns_ptr @@ -357,19 +337,16 @@ class PrivateNet(BaseDomain): :param mac_address: str The mac address of the interface on the server """ - __slots__ = ( - "network", - "ip", - "alias_ips", - "mac_address" - ) - def __init__(self, - network, # type: BoundNetwork - ip, # type: str - alias_ips, # type: List[str] - mac_address, # type: str - ): + __slots__ = ("network", "ip", "alias_ips", "mac_address") + + def __init__( + self, + network, # type: BoundNetwork + ip, # type: str + alias_ips, # type: List[str] + mac_address, # type: str + ): self.network = network self.ip = ip self.alias_ips = alias_ips diff --git a/hcloud/ssh_keys/client.py b/hcloud/ssh_keys/client.py index ba015c5..d0e7c02 100644 --- a/hcloud/ssh_keys/client.py +++ b/hcloud/ssh_keys/client.py @@ -22,13 +22,13 @@ def update(self, name=None, labels=None): def delete(self): # type: () -> bool """Deletes an SSH key. It cannot be used anymore. - :return: boolean + :return: boolean """ return self._client.delete(self) class SSHKeysClient(ClientEntityBase, GetEntityByNameMixin): - results_list_attribute_name = 'ssh_keys' + results_list_attribute_name = "ssh_keys" def get_by_id(self, id): # type: (int) -> BoundSSHKey @@ -37,16 +37,19 @@ def get_by_id(self, id): :param id: int :return: :class:`BoundSSHKey ` """ - response = self._client.request(url="/ssh_keys/{ssh_key_id}".format(ssh_key_id=id), method="GET") - return BoundSSHKey(self, response['ssh_key']) - - def get_list(self, - name=None, # type: Optional[str] - fingerprint=None, # type: Optional[str] - label_selector=None, # type: Optional[str] - page=None, # type: Optional[int] - per_page=None # type: Optional[int] - ): + response = self._client.request( + url="/ssh_keys/{ssh_key_id}".format(ssh_key_id=id), method="GET" + ) + return BoundSSHKey(self, response["ssh_key"]) + + def get_list( + self, + name=None, # type: Optional[str] + fingerprint=None, # type: Optional[str] + label_selector=None, # type: Optional[str] + page=None, # type: Optional[int] + per_page=None, # type: Optional[int] + ): # type: (...) -> PageResults[List[BoundSSHKey], Meta] """Get a list of SSH keys from the account @@ -64,19 +67,21 @@ def get_list(self, """ params = {} if name is not None: - params['name'] = name + params["name"] = name if fingerprint is not None: - params['fingerprint'] = fingerprint + params["fingerprint"] = fingerprint if label_selector is not None: - params['label_selector'] = label_selector + params["label_selector"] = label_selector if page is not None: - params['page'] = page + params["page"] = page if per_page is not None: - params['per_page'] = per_page + params["per_page"] = per_page response = self._client.request(url="/ssh_keys", method="GET", params=params) - ass_ssh_keys = [BoundSSHKey(self, server_data) for server_data in response['ssh_keys']] + ass_ssh_keys = [ + BoundSSHKey(self, server_data) for server_data in response["ssh_keys"] + ] return self._add_meta_to_result(ass_ssh_keys, response) def get_all(self, name=None, fingerprint=None, label_selector=None): @@ -91,7 +96,9 @@ def get_all(self, name=None, fingerprint=None, label_selector=None): Can be used to filter SSH keys by labels. The response will only contain SSH keys matching the label selector. :return: List[:class:`BoundSSHKey `] """ - return super(SSHKeysClient, self).get_all(name=name, fingerprint=fingerprint, label_selector=label_selector) + return super(SSHKeysClient, self).get_all( + name=name, fingerprint=fingerprint, label_selector=label_selector + ) def get_by_name(self, name): # type: (str) -> SSHKeysClient @@ -126,14 +133,11 @@ def create(self, name, public_key, labels=None): User-defined labels (key-value pairs) :return: :class:`BoundSSHKey ` """ - data = { - 'name': name, - 'public_key': public_key - } + data = {"name": name, "public_key": public_key} if labels is not None: - data['labels'] = labels + data["labels"] = labels response = self._client.request(url="/ssh_keys", method="POST", json=data) - return BoundSSHKey(self, response['ssh_key']) + return BoundSSHKey(self, response["ssh_key"]) def update(self, ssh_key, name=None, labels=None): # type: (SSHKey, Optional[str], Optional[Dict[str, str]]) -> BoundSSHKey @@ -148,16 +152,21 @@ def update(self, ssh_key, name=None, labels=None): """ data = {} if name is not None: - data['name'] = name + data["name"] = name if labels is not None: - data['labels'] = labels - response = self._client.request(url="/ssh_keys/{ssh_key_id}".format(ssh_key_id=ssh_key.id), method="PUT", - json=data) - return BoundSSHKey(self, response['ssh_key']) + data["labels"] = labels + response = self._client.request( + url="/ssh_keys/{ssh_key_id}".format(ssh_key_id=ssh_key.id), + method="PUT", + json=data, + ) + return BoundSSHKey(self, response["ssh_key"]) def delete(self, ssh_key): # type: (SSHKey) -> bool - self._client.request(url="/ssh_keys/{ssh_key_id}".format(ssh_key_id=ssh_key.id), method="DELETE") + self._client.request( + url="/ssh_keys/{ssh_key_id}".format(ssh_key_id=ssh_key.id), method="DELETE" + ) """Deletes an SSH key. It cannot be used anymore. :param ssh_key: :class:`BoundSSHKey ` or :class:`SSHKey ` diff --git a/hcloud/ssh_keys/domain.py b/hcloud/ssh_keys/domain.py index 201c596..c37e63c 100644 --- a/hcloud/ssh_keys/domain.py +++ b/hcloud/ssh_keys/domain.py @@ -20,14 +20,8 @@ class SSHKey(BaseDomain, DomainIdentityMixin): :param created: datetime Point in time when the SSH Key was created """ - __slots__ = ( - "id", - "name", - "fingerprint", - "public_key", - "labels", - "created" - ) + + __slots__ = ("id", "name", "fingerprint", "public_key", "labels", "created") def __init__( self, @@ -36,7 +30,7 @@ def __init__( fingerprint=None, public_key=None, labels=None, - created=None + created=None, ): self.id = id self.name = name diff --git a/hcloud/volumes/client.py b/hcloud/volumes/client.py index 935a8c2..aed318e 100644 --- a/hcloud/volumes/client.py +++ b/hcloud/volumes/client.py @@ -13,12 +13,15 @@ class BoundVolume(BoundModelBase): def __init__(self, client, data, complete=True): location = data.get("location") if location is not None: - data['location'] = BoundLocation(client._client.locations, location) + data["location"] = BoundLocation(client._client.locations, location) from hcloud.servers.client import BoundServer + server = data.get("server") if server is not None: - data['server'] = BoundServer(client._client.servers, {"id": server}, complete=False) + data["server"] = BoundServer( + client._client.servers, {"id": server}, complete=False + ) super(BoundVolume, self).__init__(client, data, complete) def get_actions_list(self, status=None, sort=None, page=None, per_page=None): @@ -51,7 +54,7 @@ def get_actions(self, status=None, sort=None): def update(self, name=None, labels=None): # type: (Optional[str], Optional[Dict[str, str]]) -> BoundAction - """ Updates the volume properties. + """Updates the volume properties. :param name: str (optional) New volume name @@ -109,7 +112,7 @@ def change_protection(self, delete=None): class VolumesClient(ClientEntityBase, GetEntityByNameMixin): - results_list_attribute_name = 'volumes' + results_list_attribute_name = "volumes" def get_by_id(self, id): # type: (int) -> volumes.client.BoundVolume @@ -118,10 +121,14 @@ def get_by_id(self, id): :param id: int :return: :class:`BoundVolume ` """ - response = self._client.request(url="/volumes/{volume_id}".format(volume_id=id), method="GET") - return BoundVolume(self, response['volume']) + response = self._client.request( + url="/volumes/{volume_id}".format(volume_id=id), method="GET" + ) + return BoundVolume(self, response["volume"]) - def get_list(self, name=None, label_selector=None, page=None, per_page=None, status=None): + def get_list( + self, name=None, label_selector=None, page=None, per_page=None, status=None + ): # type: (Optional[str], Optional[str], Optional[int], Optional[int], Optional[List[str]]) -> PageResults[List[BoundVolume], Meta] """Get a list of volumes from this account @@ -139,18 +146,20 @@ def get_list(self, name=None, label_selector=None, page=None, per_page=None, sta """ params = {} if name is not None: - params['name'] = name + params["name"] = name if label_selector is not None: - params['label_selector'] = label_selector + params["label_selector"] = label_selector if status is not None: params["status"] = status if page is not None: - params['page'] = page + params["page"] = page if per_page is not None: - params['per_page'] = per_page + params["per_page"] = per_page response = self._client.request(url="/volumes", method="GET", params=params) - volumes = [BoundVolume(self, volume_data) for volume_data in response['volumes']] + volumes = [ + BoundVolume(self, volume_data) for volume_data in response["volumes"] + ] return self._add_meta_to_result(volumes, response) def get_all(self, label_selector=None, status=None): @@ -163,7 +172,9 @@ def get_all(self, label_selector=None, status=None): Can be used to filter volumes by their status. The response will only contain volumes matching the status. :return: List[:class:`BoundVolume `] """ - return super(VolumesClient, self).get_all(label_selector=label_selector, status=status) + return super(VolumesClient, self).get_all( + label_selector=label_selector, status=status + ) def get_by_name(self, name): # type: (str) -> BoundVolume @@ -175,15 +186,16 @@ def get_by_name(self, name): """ return super(VolumesClient, self).get_by_name(name) - def create(self, - size, # type: int - name, # type: str - labels=None, # type: Optional[str] - location=None, # type: Optional[Location] - server=None, # type: Optional[Server], - automount=None, # type: Optional[bool], - format=None, # type: Optional[str], - ): + def create( + self, + size, # type: int + name, # type: str + labels=None, # type: Optional[str] + location=None, # type: Optional[Location] + server=None, # type: Optional[Server], + automount=None, # type: Optional[bool], + format=None, # type: Optional[str], + ): # type: (...) -> CreateVolumeResponse """Creates a new volume attached to a server. @@ -209,31 +221,36 @@ def create(self, raise ValueError("only one of server or location must be provided") data = { - 'name': name, - 'size': size, + "name": name, + "size": size, } if labels is not None: - data['labels'] = labels + data["labels"] = labels if location is not None: - data['location'] = location.id_or_name + data["location"] = location.id_or_name if server is not None: - data['server'] = server.id + data["server"] = server.id if automount is not None: - data['automount'] = automount + data["automount"] = automount if format is not None: - data['format'] = format + data["format"] = format response = self._client.request(url="/volumes", json=data, method="POST") result = CreateVolumeResponse( - volume=BoundVolume(self, response['volume']), - action=BoundAction(self._client.actions, response['action']), - next_actions=[BoundAction(self._client.actions, action) for action in response['next_actions']] + volume=BoundVolume(self, response["volume"]), + action=BoundAction(self._client.actions, response["action"]), + next_actions=[ + BoundAction(self._client.actions, action) + for action in response["next_actions"] + ], ) return result - def get_actions_list(self, volume, status=None, sort=None, page=None, per_page=None): + def get_actions_list( + self, volume, status=None, sort=None, page=None, per_page=None + ): # type: (Volume, Optional[List[str]], Optional[int], Optional[int]) -> PageResults[List[BoundAction], Meta] """Returns all action objects for a volume. @@ -258,10 +275,16 @@ def get_actions_list(self, volume, status=None, sort=None, page=None, per_page=N if per_page is not None: params["per_page"] = per_page - response = self._client.request(url="/volumes/{volume_id}/actions".format(volume_id=volume.id), method="GET", - params=params) - actions = [BoundAction(self._client.actions, action_data) for action_data in response['actions']] - return add_meta_to_result(actions, response, 'actions') + response = self._client.request( + url="/volumes/{volume_id}/actions".format(volume_id=volume.id), + method="GET", + params=params, + ) + actions = [ + BoundAction(self._client.actions, action_data) + for action_data in response["actions"] + ] + return add_meta_to_result(actions, response, "actions") def get_actions(self, volume, status=None, sort=None): # type: (Union[Volume, BoundVolume], Optional[List[str]]) -> List[BoundAction] @@ -278,7 +301,7 @@ def get_actions(self, volume, status=None, sort=None): def update(self, volume, name=None, labels=None): # type:(Union[Volume, BoundVolume], Optional[str], Optional[Dict[str, str]]) -> BoundVolume - """ Updates the volume properties. + """Updates the volume properties. :param volume: :class:`BoundVolume ` or :class:`Volume ` :param name: str (optional) @@ -292,8 +315,12 @@ def update(self, volume, name=None, labels=None): data.update({"name": name}) if labels is not None: data.update({"labels": labels}) - response = self._client.request(url="/volumes/{volume_id}".format(volume_id=volume.id), method="PUT", json=data) - return BoundVolume(self, response['volume']) + response = self._client.request( + url="/volumes/{volume_id}".format(volume_id=volume.id), + method="PUT", + json=data, + ) + return BoundVolume(self, response["volume"]) def delete(self, volume): # type: (Union[Volume, BoundVolume]) -> BoundAction @@ -302,7 +329,9 @@ def delete(self, volume): :param volume: :class:`BoundVolume ` or :class:`Volume ` :return: boolean """ - self._client.request(url="/volumes/{volume_id}".format(volume_id=volume.id), method="DELETE") + self._client.request( + url="/volumes/{volume_id}".format(volume_id=volume.id), method="DELETE" + ) return True def resize(self, volume, size): @@ -314,9 +343,12 @@ def resize(self, volume, size): New volume size in GB (must be greater than current size) :return: :class:`BoundAction ` """ - data = self._client.request(url="/volumes/{volume_id}/actions/resize".format(volume_id=volume.id), - json={'size': size}, method="POST") - return BoundAction(self._client.actions, data['action']) + data = self._client.request( + url="/volumes/{volume_id}/actions/resize".format(volume_id=volume.id), + json={"size": size}, + method="POST", + ) + return BoundAction(self._client.actions, data["action"]) def attach(self, volume, server, automount=None): # type: (Union[Volume, BoundVolume], Union[Server, BoundServer], Optional[bool]) -> BoundAction @@ -327,13 +359,16 @@ def attach(self, volume, server, automount=None): :param automount: boolean :return: :class:`BoundAction ` """ - data = {'server': server.id} + data = {"server": server.id} if automount is not None: data["automount"] = automount - data = self._client.request(url="/volumes/{volume_id}/actions/attach".format(volume_id=volume.id), json=data, - method="POST") - return BoundAction(self._client.actions, data['action']) + data = self._client.request( + url="/volumes/{volume_id}/actions/attach".format(volume_id=volume.id), + json=data, + method="POST", + ) + return BoundAction(self._client.actions, data["action"]) def detach(self, volume): # type: (Union[Volume, BoundVolume]) -> BoundAction @@ -342,9 +377,11 @@ def detach(self, volume): :param volume: :class:`BoundVolume ` or :class:`Volume ` :return: :class:`BoundAction ` """ - data = self._client.request(url="/volumes/{volume_id}/actions/detach".format(volume_id=volume.id), - method="POST") - return BoundAction(self._client.actions, data['action']) + data = self._client.request( + url="/volumes/{volume_id}/actions/detach".format(volume_id=volume.id), + method="POST", + ) + return BoundAction(self._client.actions, data["action"]) def change_protection(self, volume, delete=None): # type: (Union[Volume, BoundVolume], Optional[bool], Optional[bool]) -> BoundAction @@ -360,6 +397,10 @@ def change_protection(self, volume, delete=None): data.update({"delete": delete}) response = self._client.request( - url="/volumes/{volume_id}/actions/change_protection".format(volume_id=volume.id), - method="POST", json=data) - return BoundAction(self._client.actions, response['action']) + url="/volumes/{volume_id}/actions/change_protection".format( + volume_id=volume.id + ), + method="POST", + json=data, + ) + return BoundAction(self._client.actions, response["action"]) diff --git a/hcloud/volumes/domain.py b/hcloud/volumes/domain.py index ea01c45..137f3df 100644 --- a/hcloud/volumes/domain.py +++ b/hcloud/volumes/domain.py @@ -30,6 +30,7 @@ class Volume(BaseDomain, DomainIdentityMixin): :param format: str, None Filesystem of the volume if formatted on creation, None if not formatted on creation. """ + STATUS_CREATING = "creating" """Volume Status creating""" STATUS_AVAILABLE = "available" @@ -46,23 +47,22 @@ class Volume(BaseDomain, DomainIdentityMixin): "protection", "labels", "status", - "created" + "created", ) def __init__( - self, - id, - name=None, - server=None, - created=None, - location=None, - size=None, - linux_device=None, - format=None, - protection=None, - labels=None, - status=None - + self, + id, + name=None, + server=None, + created=None, + location=None, + size=None, + linux_device=None, + format=None, + protection=None, + labels=None, + status=None, ): self.id = id self.name = name @@ -87,17 +87,14 @@ class CreateVolumeResponse(BaseDomain): :param next_actions: List[:class:`BoundAction `] List of actions that are performed after the creation, like attaching to a server """ - __slots__ = ( - "volume", - "action", - "next_actions" - ) + + __slots__ = ("volume", "action", "next_actions") def __init__( - self, - volume, # type: BoundVolume - action, # type: BoundAction - next_actions, # type: List[BoundAction] + self, + volume, # type: BoundVolume + action, # type: BoundAction + next_actions, # type: List[BoundAction] ): self.volume = volume self.action = action diff --git a/requirements/test.txt b/requirements/test.txt index d81c9bf..5e90782 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -5,3 +5,4 @@ isort==4.3.4 mock==2.0.0 pytest tox==3.23.1 +black==21.7b0 diff --git a/setup.py b/setup.py index 04dd851..13f42bc 100644 --- a/setup.py +++ b/setup.py @@ -5,24 +5,15 @@ from setuptools import setup, find_packages -with open('README.rst') as readme_file: +with open("README.rst") as readme_file: readme = readme_file.read() -with open('CHANGELOG.rst') as changelog_file: +with open("CHANGELOG.rst") as changelog_file: changelog = changelog_file.read() -requirements = [ - "future>=0.17.1,<1", - "python-dateutil>=2.7.5,<3", - "requests>=2.20,<3" -] +requirements = ["future>=0.17.1,<1", "python-dateutil>=2.7.5,<3", "requests>=2.20,<3"] -extras_require = { - 'docs': [ - "Sphinx==1.8.1", - "sphinx-rtd-theme==0.4.2" - ] -} +extras_require = {"docs": ["Sphinx==1.8.1", "sphinx-rtd-theme==0.4.2"]} version = {} with open("hcloud/__version__.py") as fp: @@ -30,31 +21,31 @@ setup( author="Hetzner Cloud GmbH", - author_email='support-cloud@hetzner.com', + author_email="support-cloud@hetzner.com", classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Natural Language :: English', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Natural Language :: English", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", ], - python_requires='!=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <3.11', + python_requires="!=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <3.11", description="Official Hetzner Cloud python library", install_requires=requirements, extras_require=extras_require, license="MIT license", - long_description=readme + '\n\n' + changelog, + long_description=readme + "\n\n" + changelog, include_package_data=True, - keywords='hcloud hetzner cloud', - name='hcloud', + keywords="hcloud hetzner cloud", + name="hcloud", packages=find_packages(exclude=["examples", "tests*", "docs"]), - test_suite='tests', - url='https://github.com/hetznercloud/hcloud-python', - version=version['VERSION'], + test_suite="tests", + url="https://github.com/hetznercloud/hcloud-python", + version=version["VERSION"], zip_safe=False, ) diff --git a/tests/unit/actions/conftest.py b/tests/unit/actions/conftest.py index 811277c..2fbd3c5 100644 --- a/tests/unit/actions/conftest.py +++ b/tests/unit/actions/conftest.py @@ -12,16 +12,8 @@ def generic_action_list(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 42, - "type": "server" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 42, "type": "server"}], + "error": {"code": "action_failed", "message": "Action failed"}, }, { "id": 2, @@ -30,17 +22,9 @@ def generic_action_list(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 42, - "type": "server" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } - } + "resources": [{"id": 42, "type": "server"}], + "error": {"code": "action_failed", "message": "Action failed"}, + }, ] } @@ -55,16 +39,8 @@ def running_action(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 42, - "type": "server" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 42, "type": "server"}], + "error": {"code": "action_failed", "message": "Action failed"}, } } @@ -79,16 +55,8 @@ def successfully_action(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 42, - "type": "server" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 42, "type": "server"}], + "error": {"code": "action_failed", "message": "Action failed"}, } } @@ -103,15 +71,7 @@ def failed_action(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 42, - "type": "server" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 42, "type": "server"}], + "error": {"code": "action_failed", "message": "Action failed"}, } } diff --git a/tests/unit/actions/test_client.py b/tests/unit/actions/test_client.py index 8cf97cd..d16ec4a 100644 --- a/tests/unit/actions/test_client.py +++ b/tests/unit/actions/test_client.py @@ -8,15 +8,22 @@ class TestBoundAction(object): @pytest.fixture() def bound_running_action(self, mocked_requests): - return BoundAction(client=ActionsClient(client=mocked_requests), data=dict(id=14, status=Action.STATUS_RUNNING)) - - def test_wait_until_finished(self, bound_running_action, mocked_requests, running_action, successfully_action): + return BoundAction( + client=ActionsClient(client=mocked_requests), + data=dict(id=14, status=Action.STATUS_RUNNING), + ) + + def test_wait_until_finished( + self, bound_running_action, mocked_requests, running_action, successfully_action + ): mocked_requests.request.side_effect = [running_action, successfully_action] bound_running_action.wait_until_finished() assert bound_running_action.status == "success" assert mocked_requests.request.call_count == 2 - def test_wait_until_finished_with_error(self, bound_running_action, mocked_requests, running_action, failed_action): + def test_wait_until_finished_with_error( + self, bound_running_action, mocked_requests, running_action, failed_action + ): mocked_requests.request.side_effect = [running_action, failed_action] with pytest.raises(ActionFailedException) as exception_info: bound_running_action.wait_until_finished() @@ -24,8 +31,14 @@ def test_wait_until_finished_with_error(self, bound_running_action, mocked_reque assert bound_running_action.status == "error" assert exception_info.value.action.id == 2 - def test_wait_until_finished_max_retries(self, bound_running_action, mocked_requests, running_action, successfully_action): - mocked_requests.request.side_effect = [running_action, running_action, successfully_action] + def test_wait_until_finished_max_retries( + self, bound_running_action, mocked_requests, running_action, successfully_action + ): + mocked_requests.request.side_effect = [ + running_action, + running_action, + successfully_action, + ] with pytest.raises(ActionTimeoutException) as exception_info: bound_running_action.wait_until_finished(max_retries=1) @@ -35,7 +48,6 @@ def test_wait_until_finished_max_retries(self, bound_running_action, mocked_requ class TestActionsClient(object): - @pytest.fixture() def actions_client(self): return ActionsClient(client=mock.MagicMock()) @@ -43,25 +55,23 @@ def actions_client(self): def test_get_by_id(self, actions_client, generic_action): actions_client._client.request.return_value = generic_action action = actions_client.get_by_id(1) - actions_client._client.request.assert_called_with(url="/actions/1", method="GET") + actions_client._client.request.assert_called_with( + url="/actions/1", method="GET" + ) assert action._client is actions_client assert action.id == 1 assert action.command == "stop_server" @pytest.mark.parametrize( "params", - [ - {}, - {"status": ["active"], - "sort": ["status"], - "page": 2, - "per_page": 10} - ] + [{}, {"status": ["active"], "sort": ["status"], "page": 2, "per_page": 10}], ) def test_get_list(self, actions_client, generic_action_list, params): actions_client._client.request.return_value = generic_action_list result = actions_client.get_list(**params) - actions_client._client.request.assert_called_with(url="/actions", method="GET", params=params) + actions_client._client.request.assert_called_with( + url="/actions", method="GET", params=params + ) assert result.meta is None @@ -79,21 +89,16 @@ def test_get_list(self, actions_client, generic_action_list, params): assert action2.id == 2 assert action2.command == "stop_server" - @pytest.mark.parametrize( - "params", - [ - {}, - {"status": ["active"], - "sort": ["status"]} - ] - ) + @pytest.mark.parametrize("params", [{}, {"status": ["active"], "sort": ["status"]}]) def test_get_all(self, actions_client, generic_action_list, params): actions_client._client.request.return_value = generic_action_list actions = actions_client.get_all(**params) params.update({"page": 1, "per_page": 50}) - actions_client._client.request.assert_called_with(url="/actions", method="GET", params=params) + actions_client._client.request.assert_called_with( + url="/actions", method="GET", params=params + ) assert len(actions) == 2 diff --git a/tests/unit/actions/test_domain.py b/tests/unit/actions/test_domain.py index 761b942..5278964 100644 --- a/tests/unit/actions/test_domain.py +++ b/tests/unit/actions/test_domain.py @@ -5,8 +5,13 @@ class TestAction(object): - def test_started_finished_is_datetime(self): - action = Action(id=1, started="2016-01-30T23:50+00:00", finished="2016-03-30T23:50+00:00") - assert action.started == datetime.datetime(2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0)) - assert action.finished == datetime.datetime(2016, 3, 30, 23, 50, tzinfo=tzoffset(None, 0)) + action = Action( + id=1, started="2016-01-30T23:50+00:00", finished="2016-03-30T23:50+00:00" + ) + assert action.started == datetime.datetime( + 2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0) + ) + assert action.finished == datetime.datetime( + 2016, 3, 30, 23, 50, tzinfo=tzoffset(None, 0) + ) diff --git a/tests/unit/certificates/conftest.py b/tests/unit/certificates/conftest.py index 7a2acd5..5fdc5b5 100644 --- a/tests/unit/certificates/conftest.py +++ b/tests/unit/certificates/conftest.py @@ -13,26 +13,14 @@ def certificate_response(): "created": "2019-01-08T12:10:00+00:00", "not_valid_before": "2019-01-08T10:00:00+00:00", "not_valid_after": "2019-07-08T09:59:59+00:00", - "domain_names": [ - "example.com", - "webmail.example.com", - "www.example.com" - ], + "domain_names": ["example.com", "webmail.example.com", "www.example.com"], "fingerprint": "03:c7:55:9b:2a:d1:04:17:09:f6:d0:7f:18:34:63:d4:3e:5f", "status": { "issuance": "failed", "renewal": "scheduled", - "error": { - "code": "error_code", - "message": "error message" - } + "error": {"code": "error_code", "message": "error message"}, }, - "used_by": [ - { - "id": 42, - "type": "server" - } - ] + "used_by": [{"id": 42, "type": "server"}], } } @@ -49,23 +37,10 @@ def create_managed_certificate_response(): "created": "2019-01-08T12:10:00+00:00", "not_valid_before": "2019-01-08T10:00:00+00:00", "not_valid_after": "2019-07-08T09:59:59+00:00", - "domain_names": [ - "example.com", - "webmail.example.com", - "www.example.com" - ], + "domain_names": ["example.com", "webmail.example.com", "www.example.com"], "fingerprint": "03:c7:55:9b:2a:d1:04:17:09:f6:d0:7f:18:34:63:d4:3e:5f", - "status": { - "issuance": "pending", - "renewal": "scheduled", - "error": None - }, - "used_by": [ - { - "id": 42, - "type": "load_balancer" - } - ] + "status": {"issuance": "pending", "renewal": "scheduled", "error": None}, + "used_by": [{"id": 42, "type": "load_balancer"}], }, "action": { "id": 14, @@ -74,18 +49,9 @@ def create_managed_certificate_response(): "progress": 100, "started": "2021-01-30T23:55:00+00:00", "finished": "2021-01-30T23:57:00+00:00", - "resources": [ - { - "id": 896, - "type": "certificate" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } - - } + "resources": [{"id": 896, "type": "certificate"}], + "error": {"code": "action_failed", "message": "Action failed"}, + }, } @@ -105,16 +71,11 @@ def two_certificates_response(): "domain_names": [ "example.com", "webmail.example.com", - "www.example.com" + "www.example.com", ], "fingerprint": "03:c7:55:9b:2a:d1:04:17:09:f6:d0:7f:18:34:63:d4:3e:5f", "status": None, - "used_by": [ - { - "id": 42, - "type": "load_balancer" - } - ] + "used_by": [{"id": 42, "type": "load_balancer"}], }, { "id": 2324, @@ -128,17 +89,12 @@ def two_certificates_response(): "domain_names": [ "example.com", "webmail.example.com", - "www.example.com" + "www.example.com", ], "fingerprint": "03:c7:55:9b:2a:d1:04:17:09:f6:d0:7f:18:34:63:d4:3e:5f", "status": None, - "used_by": [ - { - "id": 42, - "type": "load_balancer" - } - ] - } + "used_by": [{"id": 42, "type": "load_balancer"}], + }, ] } @@ -159,16 +115,11 @@ def one_certificates_response(): "domain_names": [ "example.com", "webmail.example.com", - "www.example.com" + "www.example.com", ], "fingerprint": "03:c7:55:9b:2a:d1:04:17:09:f6:d0:7f:18:34:63:d4:3e:5f", "status": None, - "used_by": [ - { - "id": 42, - "type": "load_balancer" - } - ] + "used_by": [{"id": 42, "type": "load_balancer"}], } ] } @@ -186,20 +137,10 @@ def response_update_certificate(): "created": "2019-01-08T12:10:00+00:00", "not_valid_before": "2019-01-08T10:00:00+00:00", "not_valid_after": "2019-07-08T09:59:59+00:00", - "domain_names": [ - "example.com", - "webmail.example.com", - "www.example.com" - ], + "domain_names": ["example.com", "webmail.example.com", "www.example.com"], "fingerprint": "03:c7:55:9b:2a:d1:04:17:09:f6:d0:7f:18:34:63:d4:3e:5f", "status": None, - "used_by": [ - { - "id": 42, - "type": "load_balancer" - } - ] - + "used_by": [{"id": 42, "type": "load_balancer"}], } } @@ -215,16 +156,8 @@ def response_get_actions(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 14, - "type": "certificate" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 14, "type": "certificate"}], + "error": {"code": "action_failed", "message": "Action failed"}, } ] } @@ -240,15 +173,7 @@ def response_retry_issuance_action(): "progress": 0, "started": "2016-01-30T23:50+00:00", "finished": None, - "resources": [ - { - "id": 42, - "type": "certificate" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 42, "type": "certificate"}], + "error": {"code": "action_failed", "message": "Action failed"}, } } diff --git a/tests/unit/certificates/test_client.py b/tests/unit/certificates/test_client.py index 1e840d2..b2acd4e 100644 --- a/tests/unit/certificates/test_client.py +++ b/tests/unit/certificates/test_client.py @@ -7,25 +7,19 @@ class TestBoundCertificate(object): - @pytest.fixture() def bound_certificate(self, hetzner_client): return BoundCertificate(client=hetzner_client.certificates, data=dict(id=14)) - @pytest.mark.parametrize( - "params", - [ - { - "page": 1, - "per_page": 10}, - {} - - ] - ) - def test_get_actions_list(self, hetzner_client, bound_certificate, response_get_actions, params): + @pytest.mark.parametrize("params", [{"page": 1, "per_page": 10}, {}]) + def test_get_actions_list( + self, hetzner_client, bound_certificate, response_get_actions, params + ): hetzner_client.request.return_value = response_get_actions result = bound_certificate.get_actions_list(**params) - hetzner_client.request.assert_called_with(url="/certificates/14/actions", method="GET", params=params) + hetzner_client.request.assert_called_with( + url="/certificates/14/actions", method="GET", params=params + ) actions = result.actions assert result.meta is None @@ -39,9 +33,11 @@ def test_get_actions(self, hetzner_client, bound_certificate, response_get_actio hetzner_client.request.return_value = response_get_actions actions = bound_certificate.get_actions() - params = {'page': 1, 'per_page': 50} + params = {"page": 1, "per_page": 50} - hetzner_client.request.assert_called_with(url="/certificates/14/actions", method="GET", params=params) + hetzner_client.request.assert_called_with( + url="/certificates/14/actions", method="GET", params=params + ) assert len(actions) == 1 assert isinstance(actions[0], BoundAction) @@ -50,14 +46,16 @@ def test_get_actions(self, hetzner_client, bound_certificate, response_get_actio def test_bound_certificate_init(self, certificate_response): bound_certificate = BoundCertificate( - client=mock.MagicMock(), - data=certificate_response['certificate'] + client=mock.MagicMock(), data=certificate_response["certificate"] ) assert bound_certificate.id == 2323 assert bound_certificate.name == "My Certificate" assert bound_certificate.type == "managed" - assert bound_certificate.fingerprint == "03:c7:55:9b:2a:d1:04:17:09:f6:d0:7f:18:34:63:d4:3e:5f" + assert ( + bound_certificate.fingerprint + == "03:c7:55:9b:2a:d1:04:17:09:f6:d0:7f:18:34:63:d4:3e:5f" + ) assert bound_certificate.certificate == "-----BEGIN CERTIFICATE-----\n..." assert len(bound_certificate.domain_names) == 3 assert bound_certificate.domain_names[0] == "example.com" @@ -69,10 +67,14 @@ def test_bound_certificate_init(self, certificate_response): assert bound_certificate.status.error.code == "error_code" assert bound_certificate.status.error.message == "error message" - def test_update(self, hetzner_client, bound_certificate, response_update_certificate): + def test_update( + self, hetzner_client, bound_certificate, response_update_certificate + ): hetzner_client.request.return_value = response_update_certificate certificate = bound_certificate.update(name="New name") - hetzner_client.request.assert_called_with(url="/certificates/14", method="PUT", json={"name": "New name"}) + hetzner_client.request.assert_called_with( + url="/certificates/14", method="PUT", json={"name": "New name"} + ) assert certificate.id == 2323 assert certificate.name == "New name" @@ -80,21 +82,26 @@ def test_update(self, hetzner_client, bound_certificate, response_update_certifi def test_delete(self, hetzner_client, bound_certificate, generic_action): hetzner_client.request.return_value = generic_action delete_success = bound_certificate.delete() - hetzner_client.request.assert_called_with(url="/certificates/14", method="DELETE") + hetzner_client.request.assert_called_with( + url="/certificates/14", method="DELETE" + ) assert delete_success is True - def test_retry_issuance(self, hetzner_client, bound_certificate, response_retry_issuance_action): + def test_retry_issuance( + self, hetzner_client, bound_certificate, response_retry_issuance_action + ): hetzner_client.request.return_value = response_retry_issuance_action action = bound_certificate.retry_issuance() - hetzner_client.request.assert_called_with(url="/certificates/14/actions/retry", method="POST") + hetzner_client.request.assert_called_with( + url="/certificates/14/actions/retry", method="POST" + ) assert action.id == 14 assert action.command == "issue_certificate" class TestCertificatesClient(object): - @pytest.fixture() def certificates_client(self): return CertificatesClient(client=mock.MagicMock()) @@ -102,7 +109,9 @@ def certificates_client(self): def test_get_by_id(self, certificates_client, certificate_response): certificates_client._client.request.return_value = certificate_response certificate = certificates_client.get_by_id(1) - certificates_client._client.request.assert_called_with(url="/certificates/1", method="GET") + certificates_client._client.request.assert_called_with( + url="/certificates/1", method="GET" + ) assert certificate._client is certificates_client assert certificate.id == 2323 assert certificate.name == "My Certificate" @@ -110,15 +119,22 @@ def test_get_by_id(self, certificates_client, certificate_response): @pytest.mark.parametrize( "params", [ - {'name': "My Certificate", "label_selector": "k==v", 'page': 1, 'per_page': 10}, - {'name': ""}, - {} - ] + { + "name": "My Certificate", + "label_selector": "k==v", + "page": 1, + "per_page": 10, + }, + {"name": ""}, + {}, + ], ) def test_get_list(self, certificates_client, two_certificates_response, params): certificates_client._client.request.return_value = two_certificates_response result = certificates_client.get_list(**params) - certificates_client._client.request.assert_called_with(url="/certificates", method="GET", params=params) + certificates_client._client.request.assert_called_with( + url="/certificates", method="GET", params=params + ) certificates = result.certificates assert len(certificates) == 2 @@ -135,18 +151,16 @@ def test_get_list(self, certificates_client, two_certificates_response, params): assert certificates2.name == "My website cert" @pytest.mark.parametrize( - "params", - [ - {'name': "My Certificate", 'label_selector': "label1"}, - {} - ] + "params", [{"name": "My Certificate", "label_selector": "label1"}, {}] ) def test_get_all(self, certificates_client, two_certificates_response, params): certificates_client._client.request.return_value = two_certificates_response certificates = certificates_client.get_all(**params) - params.update({'page': 1, 'per_page': 50}) - certificates_client._client.request.assert_called_with(url="/certificates", method="GET", params=params) + params.update({"page": 1, "per_page": 50}) + certificates_client._client.request.assert_called_with( + url="/certificates", method="GET", params=params + ) assert len(certificates) == 2 @@ -165,8 +179,10 @@ def test_get_by_name(self, certificates_client, one_certificates_response): certificates_client._client.request.return_value = one_certificates_response certificates = certificates_client.get_by_name("My Certificate") - params = {'name': "My Certificate"} - certificates_client._client.request.assert_called_with(url="/certificates", method="GET", params=params) + params = {"name": "My Certificate"} + certificates_client._client.request.assert_called_with( + url="/certificates", method="GET", params=params + ) assert certificates._client is certificates_client assert certificates.id == 2323 @@ -174,55 +190,92 @@ def test_get_by_name(self, certificates_client, one_certificates_response): def test_create(self, certificates_client, certificate_response): certificates_client._client.request.return_value = certificate_response - certificate = certificates_client.create(name="My Certificate", certificate="-----BEGIN CERTIFICATE-----\n...", - private_key="-----BEGIN PRIVATE KEY-----\n...") - certificates_client._client.request.assert_called_with(url="/certificates", method="POST", - json={"name": "My Certificate", - "certificate": "-----BEGIN CERTIFICATE-----\n...", - "private_key": "-----BEGIN PRIVATE KEY-----\n...", - "type": "uploaded"}) + certificate = certificates_client.create( + name="My Certificate", + certificate="-----BEGIN CERTIFICATE-----\n...", + private_key="-----BEGIN PRIVATE KEY-----\n...", + ) + certificates_client._client.request.assert_called_with( + url="/certificates", + method="POST", + json={ + "name": "My Certificate", + "certificate": "-----BEGIN CERTIFICATE-----\n...", + "private_key": "-----BEGIN PRIVATE KEY-----\n...", + "type": "uploaded", + }, + ) assert certificate.id == 2323 assert certificate.name == "My Certificate" - def test_create_managed(self, certificates_client, create_managed_certificate_response): - certificates_client._client.request.return_value = create_managed_certificate_response - create_managed_certificate_rsp = certificates_client.create_managed(name="My Certificate", - domain_names=["example.com", - "*.example.org"]) - certificates_client._client.request.assert_called_with(url="/certificates", method="POST", - json={"name": "My Certificate", - "domain_names": ["example.com", "*.example.org"], - "type": "managed"}) + def test_create_managed( + self, certificates_client, create_managed_certificate_response + ): + certificates_client._client.request.return_value = ( + create_managed_certificate_response + ) + create_managed_certificate_rsp = certificates_client.create_managed( + name="My Certificate", domain_names=["example.com", "*.example.org"] + ) + certificates_client._client.request.assert_called_with( + url="/certificates", + method="POST", + json={ + "name": "My Certificate", + "domain_names": ["example.com", "*.example.org"], + "type": "managed", + }, + ) assert create_managed_certificate_rsp.certificate.id == 2323 assert create_managed_certificate_rsp.certificate.name == "My Certificate" assert create_managed_certificate_rsp.action.id == 14 assert create_managed_certificate_rsp.action.command == "issue_certificate" - @pytest.mark.parametrize("certificate", [Certificate(id=1), BoundCertificate(mock.MagicMock(), dict(id=1))]) - def test_update(self, certificates_client, certificate, response_update_certificate): + @pytest.mark.parametrize( + "certificate", + [Certificate(id=1), BoundCertificate(mock.MagicMock(), dict(id=1))], + ) + def test_update( + self, certificates_client, certificate, response_update_certificate + ): certificates_client._client.request.return_value = response_update_certificate certificate = certificates_client.update(certificate, name="New name") - certificates_client._client.request.assert_called_with(url="/certificates/1", method="PUT", - json={"name": "New name"}) + certificates_client._client.request.assert_called_with( + url="/certificates/1", method="PUT", json={"name": "New name"} + ) assert certificate.id == 2323 assert certificate.name == "New name" - @pytest.mark.parametrize("certificate", [Certificate(id=1), BoundCertificate(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "certificate", + [Certificate(id=1), BoundCertificate(mock.MagicMock(), dict(id=1))], + ) def test_delete(self, certificates_client, certificate, generic_action): certificates_client._client.request.return_value = generic_action delete_success = certificates_client.delete(certificate) - certificates_client._client.request.assert_called_with(url="/certificates/1", method="DELETE") + certificates_client._client.request.assert_called_with( + url="/certificates/1", method="DELETE" + ) assert delete_success is True - @pytest.mark.parametrize("certificate", [Certificate(id=1), BoundCertificate(mock.MagicMock(), dict(id=1))]) - def test_retry_issuance(self, certificates_client, certificate, response_retry_issuance_action): - certificates_client._client.request.return_value = response_retry_issuance_action + @pytest.mark.parametrize( + "certificate", + [Certificate(id=1), BoundCertificate(mock.MagicMock(), dict(id=1))], + ) + def test_retry_issuance( + self, certificates_client, certificate, response_retry_issuance_action + ): + certificates_client._client.request.return_value = ( + response_retry_issuance_action + ) action = certificates_client.retry_issuance(certificate) - certificates_client._client.request.assert_called_with(url="/certificates/1/actions/retry", method="POST") + certificates_client._client.request.assert_called_with( + url="/certificates/1/actions/retry", method="POST" + ) assert action.id == 14 assert action.command == "issue_certificate" diff --git a/tests/unit/certificates/test_domain.py b/tests/unit/certificates/test_domain.py index bc6ae96..e558aa3 100644 --- a/tests/unit/certificates/test_domain.py +++ b/tests/unit/certificates/test_domain.py @@ -5,9 +5,19 @@ class TestCertificate(object): - def test_created_is_datetime(self): - certificate = Certificate(id=1, created="2016-01-30T23:50+00:00", not_valid_after="2016-01-30T23:50+00:00", not_valid_before="2016-01-30T23:50+00:00") - assert certificate.created == datetime.datetime(2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0)) - assert certificate.not_valid_after == datetime.datetime(2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0)) - assert certificate.not_valid_before == datetime.datetime(2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0)) + certificate = Certificate( + id=1, + created="2016-01-30T23:50+00:00", + not_valid_after="2016-01-30T23:50+00:00", + not_valid_before="2016-01-30T23:50+00:00", + ) + assert certificate.created == datetime.datetime( + 2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0) + ) + assert certificate.not_valid_after == datetime.datetime( + 2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0) + ) + assert certificate.not_valid_before == datetime.datetime( + 2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0) + ) diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index 9c3e1f0..17c9d62 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -3,9 +3,9 @@ from hcloud import Client -@pytest.fixture(autouse=True, scope='function') +@pytest.fixture(autouse=True, scope="function") def mocked_requests(): - patcher = mock.patch('hcloud.hcloud.requests') + patcher = mock.patch("hcloud.hcloud.requests") mocked_requests = patcher.start() yield mocked_requests patcher.stop() @@ -21,16 +21,8 @@ def generic_action(): "progress": 0, "started": "2016-01-30T23:50+00:00", "finished": None, - "resources": [ - { - "id": 42, - "type": "server" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 42, "type": "server"}], + "error": {"code": "action_failed", "message": "Action failed"}, } } diff --git a/tests/unit/core/test_client.py b/tests/unit/core/test_client.py index 05f2df3..feabf82 100644 --- a/tests/unit/core/test_client.py +++ b/tests/unit/core/test_client.py @@ -5,8 +5,7 @@ from hcloud.core.domain import add_meta_to_result, BaseDomain -class TestBoundModelBase(): - +class TestBoundModelBase: @pytest.fixture() def bound_model_class(self): class Model(BaseDomain): @@ -28,33 +27,49 @@ def client(self): return client def test_get_exists_model_attribute_complete_model(self, bound_model_class, client): - bound_model = bound_model_class(client=client, data={"id": 1, "name": "name", "description": "my_description"}) + bound_model = bound_model_class( + client=client, + data={"id": 1, "name": "name", "description": "my_description"}, + ) description = bound_model.description client.get_by_id.assert_not_called() assert description == "my_description" - def test_get_non_exists_model_attribute_complete_model(self, bound_model_class, client): - bound_model = bound_model_class(client=client, data={"id": 1, "name": "name", "description": "description"}) + def test_get_non_exists_model_attribute_complete_model( + self, bound_model_class, client + ): + bound_model = bound_model_class( + client=client, data={"id": 1, "name": "name", "description": "description"} + ) with pytest.raises(AttributeError): bound_model.content client.get_by_id.assert_not_called() - def test_get_exists_model_attribute_incomplete_model(self, bound_model_class, client): + def test_get_exists_model_attribute_incomplete_model( + self, bound_model_class, client + ): bound_model = bound_model_class(client=client, data={"id": 101}, complete=False) - client.get_by_id.return_value = bound_model_class(client=client, data={"id": 101, "name": "name", "description": "super_description"}) + client.get_by_id.return_value = bound_model_class( + client=client, + data={"id": 101, "name": "name", "description": "super_description"}, + ) description = bound_model.description client.get_by_id.assert_called_once_with(101) assert description == "super_description" assert bound_model.complete is True - def test_get_filled_model_attribute_incomplete_model(self, bound_model_class, client): + def test_get_filled_model_attribute_incomplete_model( + self, bound_model_class, client + ): bound_model = bound_model_class(client=client, data={"id": 101}, complete=False) id = bound_model.id client.get_by_id.assert_not_called() assert id == 101 assert bound_model.complete is False - def test_get_non_exists_model_attribute_incomplete_model(self, bound_model_class, client): + def test_get_non_exists_model_attribute_incomplete_model( + self, bound_model_class, client + ): bound_model = bound_model_class(client=client, data={"id": 1}, complete=False) with pytest.raises(AttributeError): bound_model.content @@ -62,18 +77,20 @@ def test_get_non_exists_model_attribute_incomplete_model(self, bound_model_class assert bound_model.complete is False -class TestClientEntityBase(): - +class TestClientEntityBase: @pytest.fixture() def client_class_constructor(self): def constructor(json_content_function): class CandiesClient(ClientEntityBase): - results_list_attribute_name = 'candies' + results_list_attribute_name = "candies" def get_list(self, status, page=None, per_page=None): json_content = json_content_function(page) - results = [(r, page, status, per_page) for r in json_content['candies']] + results = [ + (r, page, status, per_page) for r in json_content["candies"] + ] return self._add_meta_to_result(results, json_content) + return CandiesClient(mock.MagicMock()) return constructor @@ -82,11 +99,13 @@ def get_list(self, status, page=None, per_page=None): def client_class_with_actions_constructor(self): def constructor(json_content_function): class CandiesClient(ClientEntityBase): - def get_actions_list(self, status, page=None, per_page=None): json_content = json_content_function(page) - results = [(r, page, status, per_page) for r in json_content['actions']] - return add_meta_to_result(results, json_content, 'actions') + results = [ + (r, page, status, per_page) for r in json_content["actions"] + ] + return add_meta_to_result(results, json_content, "actions") + return CandiesClient(mock.MagicMock()) return constructor @@ -106,13 +125,7 @@ def json_content_function(p): def test_get_all_no_next_page(self, client_class_constructor): json_content = { "candies": [1, 2], - "meta": { - "pagination": { - "page": 1, - "per_page": 11, - "next_page": None - } - } + "meta": {"pagination": {"page": 1, "per_page": 11, "next_page": None}}, } def json_content_function(p): @@ -132,18 +145,23 @@ def json_content_function(p): "pagination": { "page": p, "per_page": 11, - "next_page": p + 1 if p < 3 else None + "next_page": p + 1 if p < 3 else None, } - } + }, } candies_client = client_class_constructor(json_content_function) result = candies_client.get_all(status="sweet") - assert result == [(11, 1, "sweet", 50), (21, 1, "sweet", 50), - (12, 2, "sweet", 50), (22, 2, "sweet", 50), - (13, 3, "sweet", 50), (23, 3, "sweet", 50)] + assert result == [ + (11, 1, "sweet", 50), + (21, 1, "sweet", 50), + (12, 2, "sweet", 50), + (22, 2, "sweet", 50), + (13, 3, "sweet", 50), + (23, 3, "sweet", 50), + ] def test_get_actions_no_method(self, client_class_constructor): json_content = {"candies": [1, 2]} @@ -156,7 +174,7 @@ def json_content_function(p): with pytest.raises(ValueError) as exception_info: candies_client.get_actions() error = exception_info.value - assert str(error) == 'this endpoint does not support get_actions method' + assert str(error) == "this endpoint does not support get_actions method" def test_get_actions_ok(self, client_class_with_actions_constructor): def json_content_function(p): @@ -166,20 +184,27 @@ def json_content_function(p): "pagination": { "page": p, "per_page": 11, - "next_page": p + 1 if p < 3 else None + "next_page": p + 1 if p < 3 else None, } - } + }, } candies_client = client_class_with_actions_constructor(json_content_function) result = candies_client.get_actions(status="sweet") - assert result == [(11, 1, "sweet", 50), (21, 1, "sweet", 50), - (12, 2, "sweet", 50), (22, 2, "sweet", 50), - (13, 3, "sweet", 50), (23, 3, "sweet", 50)] - - def test_raise_exception_if_list_attribute_is_not_implemented(self, client_class_with_actions_constructor): + assert result == [ + (11, 1, "sweet", 50), + (21, 1, "sweet", 50), + (12, 2, "sweet", 50), + (22, 2, "sweet", 50), + (13, 3, "sweet", 50), + (23, 3, "sweet", 50), + ] + + def test_raise_exception_if_list_attribute_is_not_implemented( + self, client_class_with_actions_constructor + ): def json_content_function(p): return { "actions": [10 + p, 20 + p], @@ -187,9 +212,9 @@ def json_content_function(p): "pagination": { "page": p, "per_page": 11, - "next_page": p + 1 if p < 3 else None + "next_page": p + 1 if p < 3 else None, } - } + }, } candies_client = client_class_with_actions_constructor(json_content_function) @@ -198,20 +223,24 @@ def json_content_function(p): candies_client.get_all() error = exception_info.value - assert str(error) == "in order to get results list, 'results_list_attribute_name' attribute of CandiesClient has to be specified" + assert ( + str(error) + == "in order to get results list, 'results_list_attribute_name' attribute of CandiesClient has to be specified" + ) -class TestGetEntityByNameMixin(): +class TestGetEntityByNameMixin: @pytest.fixture() def client_class_constructor(self): def constructor(json_content_function): class CandiesClient(ClientEntityBase, GetEntityByNameMixin): - results_list_attribute_name = 'candies' + results_list_attribute_name = "candies" def get_list(self, name, page=None, per_page=None): json_content = json_content_function(page) - results = json_content['candies'] + results = json_content["candies"] return self._add_meta_to_result(results, json_content) + return CandiesClient(mock.MagicMock()) return constructor diff --git a/tests/unit/core/test_domain.py b/tests/unit/core/test_domain.py index 7ed979f..988f54b 100644 --- a/tests/unit/core/test_domain.py +++ b/tests/unit/core/test_domain.py @@ -1,20 +1,23 @@ import pytest from dateutil.parser import isoparse -from hcloud.core.domain import BaseDomain, DomainIdentityMixin, Meta, Pagination, add_meta_to_result +from hcloud.core.domain import ( + BaseDomain, + DomainIdentityMixin, + Meta, + Pagination, + add_meta_to_result, +) class TestMeta(object): - @pytest.mark.parametrize("json_content", [None, "", {}]) def test_parse_meta_empty_json(self, json_content): result = Meta.parse_meta(json_content) assert result is None def test_parse_meta_json_no_paginaton(self): - json_content = { - "meta": {} - } + json_content = {"meta": {}} result = Meta.parse_meta(json_content) assert isinstance(result, Meta) assert result.pagination is None @@ -28,7 +31,7 @@ def test_parse_meta_json_ok(self): "previous_page": 1, "next_page": 3, "last_page": 10, - "total_entries": 100 + "total_entries": 100, } } } @@ -50,7 +53,7 @@ def test_add_meta_to_result(self): "previous_page": 1, "next_page": 3, "last_page": 10, - "total_entries": 100 + "total_entries": 100, } } } @@ -72,14 +75,14 @@ def __init__(self, id=None, name=None): class TestDomainIdentityMixin(object): - @pytest.mark.parametrize( "domain,expected_result", [ (SomeDomain(id=1, name="name"), 1), (SomeDomain(id=1), 1), (SomeDomain(name="name"), "name"), - ]) + ], + ) def test_id_or_name_ok(self, domain, expected_result): assert domain.id_or_name == expected_result @@ -102,23 +105,31 @@ def __init__(self, id, name="name1", started=None): class TestBaseDomain(object): - @pytest.mark.parametrize( "data_dict,expected_result", [ - ({"id": 1}, - {"id": 1, "name": "name1", "started": None} - ), - ({"id": 2, "name": "name2"}, - {"id": 2, "name": "name2", "started": None} - ), - ({"id": 3, "foo": "boo", "description": "new"}, - {"id": 3, "name": "name1", "started": None} - ), - ({"id": 4, "foo": "boo", "description": "new", "name": "name-name3", "started": "2016-01-30T23:50+00:00"}, - {"id": 4, "name": "name-name3", "started": isoparse("2016-01-30T23:50+00:00")} - ), - ]) + ({"id": 1}, {"id": 1, "name": "name1", "started": None}), + ({"id": 2, "name": "name2"}, {"id": 2, "name": "name2", "started": None}), + ( + {"id": 3, "foo": "boo", "description": "new"}, + {"id": 3, "name": "name1", "started": None}, + ), + ( + { + "id": 4, + "foo": "boo", + "description": "new", + "name": "name-name3", + "started": "2016-01-30T23:50+00:00", + }, + { + "id": 4, + "name": "name-name3", + "started": isoparse("2016-01-30T23:50+00:00"), + }, + ), + ], + ) def test_from_dict_ok(self, data_dict, expected_result): model = ActionDomain.from_dict(data_dict) for k, v in expected_result.items(): diff --git a/tests/unit/datacenters/conftest.py b/tests/unit/datacenters/conftest.py index 8fac826..f775869 100644 --- a/tests/unit/datacenters/conftest.py +++ b/tests/unit/datacenters/conftest.py @@ -15,25 +15,13 @@ def datacenter_response(): "country": "DE", "city": "Falkenstein", "latitude": 50.47612, - "longitude": 12.370071 + "longitude": 12.370071, }, "server_types": { - "supported": [ - 1, - 2, - 3 - ], - "available": [ - 1, - 2, - 3 - ], - "available_for_migration": [ - 1, - 2, - 3 - ] - } + "supported": [1, 2, 3], + "available": [1, 2, 3], + "available_for_migration": [1, 2, 3], + }, } } @@ -53,25 +41,13 @@ def two_datacenters_response(): "country": "DE", "city": "Falkenstein", "latitude": 50.47612, - "longitude": 12.370071 + "longitude": 12.370071, }, "server_types": { - "supported": [ - 1, - 2, - 3 - ], - "available": [ - 1, - 2, - 3 - ], - "available_for_migration": [ - 1, - 2, - 3 - ] - } + "supported": [1, 2, 3], + "available": [1, 2, 3], + "available_for_migration": [1, 2, 3], + }, }, { "id": 2, @@ -84,28 +60,16 @@ def two_datacenters_response(): "country": "DE", "city": "Nuremberg", "latitude": 49.452102, - "longitude": 11.076665 + "longitude": 11.076665, }, "server_types": { - "supported": [ - 1, - 2, - 3 - ], - "available": [ - 1, - 2, - 3 - ], - "available_for_migration": [ - 1, - 2, - 3 - ] - } + "supported": [1, 2, 3], + "available": [1, 2, 3], + "available_for_migration": [1, 2, 3], + }, }, ], - "recommendation": 1 + "recommendation": 1, } @@ -124,26 +88,14 @@ def one_datacenters_response(): "country": "DE", "city": "Falkenstein", "latitude": 50.47612, - "longitude": 12.370071 + "longitude": 12.370071, }, "server_types": { - "supported": [ - 1, - 2, - 3 - ], - "available": [ - 1, - 2, - 3 - ], - "available_for_migration": [ - 1, - 2, - 3 - ] - } + "supported": [1, 2, 3], + "available": [1, 2, 3], + "available_for_migration": [1, 2, 3], + }, } ], - "recommendation": 1 + "recommendation": 1, } diff --git a/tests/unit/datacenters/test_client.py b/tests/unit/datacenters/test_client.py index 45a21d0..3e24e92 100644 --- a/tests/unit/datacenters/test_client.py +++ b/tests/unit/datacenters/test_client.py @@ -7,11 +7,9 @@ class TestBoundDatacenter(object): - def test_bound_datacenter_init(self, datacenter_response): bound_datacenter = BoundDatacenter( - client=mock.MagicMock(), - data=datacenter_response['datacenter'] + client=mock.MagicMock(), data=datacenter_response["datacenter"] ) assert bound_datacenter.id == 1 @@ -43,15 +41,20 @@ def test_bound_datacenter_init(self, datacenter_response): assert len(bound_datacenter.server_types.available_for_migration) == 3 assert bound_datacenter.server_types.available_for_migration[0].id == 1 - assert bound_datacenter.server_types.available_for_migration[0].complete is False + assert ( + bound_datacenter.server_types.available_for_migration[0].complete is False + ) assert bound_datacenter.server_types.available_for_migration[1].id == 2 - assert bound_datacenter.server_types.available_for_migration[1].complete is False + assert ( + bound_datacenter.server_types.available_for_migration[1].complete is False + ) assert bound_datacenter.server_types.available_for_migration[2].id == 3 - assert bound_datacenter.server_types.available_for_migration[2].complete is False + assert ( + bound_datacenter.server_types.available_for_migration[2].complete is False + ) class TestDatacentersClient(object): - @pytest.fixture() def datacenters_client(self): return DatacentersClient(client=mock.MagicMock()) @@ -59,16 +62,22 @@ def datacenters_client(self): def test_get_by_id(self, datacenters_client, datacenter_response): datacenters_client._client.request.return_value = datacenter_response datacenter = datacenters_client.get_by_id(1) - datacenters_client._client.request.assert_called_with(url="/datacenters/1", method="GET") + datacenters_client._client.request.assert_called_with( + url="/datacenters/1", method="GET" + ) assert datacenter._client is datacenters_client assert datacenter.id == 1 assert datacenter.name == "fsn1-dc8" - @pytest.mark.parametrize("params", [{'name': "fsn1", "page": 1, "per_page": 10}, {'name': ""}, {}]) + @pytest.mark.parametrize( + "params", [{"name": "fsn1", "page": 1, "per_page": 10}, {"name": ""}, {}] + ) def test_get_list(self, datacenters_client, two_datacenters_response, params): datacenters_client._client.request.return_value = two_datacenters_response result = datacenters_client.get_list(**params) - datacenters_client._client.request.assert_called_with(url="/datacenters", method="GET", params=params) + datacenters_client._client.request.assert_called_with( + url="/datacenters", method="GET", params=params + ) datacenters = result.datacenters assert result.meta is None @@ -88,13 +97,15 @@ def test_get_list(self, datacenters_client, two_datacenters_response, params): assert datacenter2.name == "nbg1-dc3" assert isinstance(datacenter2.location, BoundLocation) - @pytest.mark.parametrize("params", [{'name': "fsn1"}, {}]) + @pytest.mark.parametrize("params", [{"name": "fsn1"}, {}]) def test_get_all(self, datacenters_client, two_datacenters_response, params): datacenters_client._client.request.return_value = two_datacenters_response datacenters = datacenters_client.get_all(**params) params.update({"page": 1, "per_page": 50}) - datacenters_client._client.request.assert_called_with(url="/datacenters", method="GET", params=params) + datacenters_client._client.request.assert_called_with( + url="/datacenters", method="GET", params=params + ) assert len(datacenters) == 2 @@ -116,7 +127,9 @@ def test_get_by_name(self, datacenters_client, one_datacenters_response): datacenter = datacenters_client.get_by_name("fsn1-dc8") params = {"name": "fsn1-dc8"} - datacenters_client._client.request.assert_called_with(url="/datacenters", method="GET", params=params) + datacenters_client._client.request.assert_called_with( + url="/datacenters", method="GET", params=params + ) assert datacenter._client is datacenters_client assert datacenter.id == 1 diff --git a/tests/unit/firewalls/conftest.py b/tests/unit/firewalls/conftest.py index 553be9e..9bee2d8 100644 --- a/tests/unit/firewalls/conftest.py +++ b/tests/unit/firewalls/conftest.py @@ -15,12 +15,12 @@ def response_create_firewall(): "source_ips": [ "28.239.13.1/32", "28.239.14.0/24", - "ff21:1eac:9a3b:ee58:5ca:990c:8bc9:c03b/128" + "ff21:1eac:9a3b:ee58:5ca:990c:8bc9:c03b/128", ], "destination_ips": [], "protocol": "tcp", "port": "80", - "description": None + "description": None, }, { "direction": "out", @@ -28,70 +28,46 @@ def response_create_firewall(): "destination_ips": [ "28.239.13.1/32", "28.239.14.0/24", - "ff21:1eac:9a3b:ee58:5ca:990c:8bc9:c03b/128" + "ff21:1eac:9a3b:ee58:5ca:990c:8bc9:c03b/128", ], "protocol": "tcp", "port": "80", - "description": "allow http out" - } + "description": "allow http out", + }, ], "applied_to": [ - { - "server": { - "id": 42 - }, - "type": "server" - }, + {"server": {"id": 42}, "type": "server"}, { "type": "label_selector", - "label_selector": { - "selector": "key==value" - } - } - ] + "label_selector": {"selector": "key==value"}, + }, + ], }, "actions": [ { "command": "set_firewall_rules", - "error": { - "code": "action_failed", - "message": "Action failed" - }, + "error": {"code": "action_failed", "message": "Action failed"}, "finished": "2016-01-30T23:56:00+00:00", "id": 13, "progress": 100, - "resources": [ - { - "id": 38, - "type": "firewall" - } - ], + "resources": [{"id": 38, "type": "firewall"}], "started": "2016-01-30T23:55:00+00:00", - "status": "success" + "status": "success", }, { "command": "apply_firewall", - "error": { - "code": "action_failed", - "message": "Action failed" - }, + "error": {"code": "action_failed", "message": "Action failed"}, "finished": "2016-01-30T23:56:00+00:00", "id": 14, "progress": 100, "resources": [ - { - "id": 42, - "type": "server" - }, - { - "id": 38, - "type": "firewall" - } + {"id": 42, "type": "server"}, + {"id": 38, "type": "firewall"}, ], "started": "2016-01-30T23:55:00+00:00", - "status": "success" - } - ] + "status": "success", + }, + ], } @@ -109,12 +85,12 @@ def firewall_response(): "source_ips": [ "28.239.13.1/32", "28.239.14.0/24", - "ff21:1eac:9a3b:ee58:5ca:990c:8bc9:c03b/128" + "ff21:1eac:9a3b:ee58:5ca:990c:8bc9:c03b/128", ], "destination_ips": [], "protocol": "tcp", "port": "80", - "description": "allow http in" + "description": "allow http in", }, { "direction": "out", @@ -122,27 +98,20 @@ def firewall_response(): "destination_ips": [ "28.239.13.1/32", "28.239.14.0/24", - "ff21:1eac:9a3b:ee58:5ca:990c:8bc9:c03b/128" + "ff21:1eac:9a3b:ee58:5ca:990c:8bc9:c03b/128", ], "protocol": "tcp", "port": "80", - "description": "allow http out" - } + "description": "allow http out", + }, ], "applied_to": [ - { - "server": { - "id": 42 - }, - "type": "server" - }, + {"server": {"id": 42}, "type": "server"}, { "type": "label_selector", - "label_selector": { - "selector": "key==value" - } - } - ] + "label_selector": {"selector": "key==value"}, + }, + ], } } @@ -162,22 +131,15 @@ def two_firewalls_response(): "source_ips": [ "28.239.13.1/32", "28.239.14.0/24", - "ff21:1eac:9a3b:ee58:5ca:990c:8bc9:c03b/128" + "ff21:1eac:9a3b:ee58:5ca:990c:8bc9:c03b/128", ], "destination_ips": [], "protocol": "tcp", "port": "80", - "description": "allow http in" + "description": "allow http in", } ], - "applied_to": [ - { - "server": { - "id": 42 - }, - "type": "server" - } - ] + "applied_to": [{"server": {"id": 42}, "type": "server"}], }, { "id": 39, @@ -191,22 +153,15 @@ def two_firewalls_response(): "source_ips": [ "28.239.13.1/32", "28.239.14.0/24", - "ff21:1eac:9a3b:ee58:5ca:990c:8bc9:c03b/128" + "ff21:1eac:9a3b:ee58:5ca:990c:8bc9:c03b/128", ], "protocol": "tcp", "port": "443", - "description": "allow https in" + "description": "allow https in", } ], - "applied_to": [ - { - "server": { - "id": 42 - }, - "type": "server" - } - ] - } + "applied_to": [{"server": {"id": 42}, "type": "server"}], + }, ] } @@ -227,21 +182,14 @@ def one_firewalls_response(): "source_ips": [ "28.239.13.1/32", "28.239.14.0/24", - "ff21:1eac:9a3b:ee58:5ca:990c:8bc9:c03b/128" + "ff21:1eac:9a3b:ee58:5ca:990c:8bc9:c03b/128", ], "protocol": "tcp", "port": "80", - "description": "allow http in" + "description": "allow http in", } ], - "applied_to": [ - { - "server": { - "id": 42 - }, - "type": "server" - } - ] + "applied_to": [{"server": {"id": 42}, "type": "server"}], }, ] } @@ -261,22 +209,15 @@ def response_update_firewall(): "source_ips": [ "28.239.13.1/32", "28.239.14.0/24", - "ff21:1eac:9a3b:ee58:5ca:990c:8bc9:c03b/128" + "ff21:1eac:9a3b:ee58:5ca:990c:8bc9:c03b/128", ], "destination_ips": [], "protocol": "tcp", "port": "80", - "description": "allow http in" + "description": "allow http in", } ], - "applied_to": [ - { - "server": { - "id": 42 - }, - "type": "server" - } - ] + "applied_to": [{"server": {"id": 42}, "type": "server"}], } } @@ -292,16 +233,8 @@ def response_get_actions(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 42, - "type": "firewall" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 42, "type": "firewall"}], + "error": {"code": "action_failed", "message": "Action failed"}, } ] } @@ -318,16 +251,8 @@ def response_set_rules(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 38, - "type": "firewall" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 38, "type": "firewall"}], + "error": {"code": "action_failed", "message": "Action failed"}, }, { "id": 14, @@ -337,19 +262,10 @@ def response_set_rules(): "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", "resources": [ - { - "id": 38, - "type": "firewall" - }, - { - "id": 42, - "type": "server" - } + {"id": 38, "type": "firewall"}, + {"id": 42, "type": "server"}, ], - "error": { - "code": "action_failed", - "message": "Action failed" - } - } + "error": {"code": "action_failed", "message": "Action failed"}, + }, ] } diff --git a/tests/unit/firewalls/test_client.py b/tests/unit/firewalls/test_client.py index 34520ab..ab564ea 100644 --- a/tests/unit/firewalls/test_client.py +++ b/tests/unit/firewalls/test_client.py @@ -3,20 +3,23 @@ from hcloud.firewalls.client import FirewallsClient, BoundFirewall from hcloud.actions.client import BoundAction -from hcloud.firewalls.domain import Firewall, FirewallRule, FirewallResource, FirewallResourceLabelSelector +from hcloud.firewalls.domain import ( + Firewall, + FirewallRule, + FirewallResource, + FirewallResourceLabelSelector, +) from hcloud.servers.domain import Server class TestBoundFirewall(object): - @pytest.fixture() def bound_firewall(self, hetzner_client): return BoundFirewall(client=hetzner_client.firewalls, data=dict(id=1)) def test_bound_firewall_init(self, firewall_response): bound_firewall = BoundFirewall( - client=mock.MagicMock(), - data=firewall_response['firewall'] + client=mock.MagicMock(), data=firewall_response["firewall"] ) assert bound_firewall.id == 38 @@ -42,7 +45,7 @@ def test_bound_firewall_init(self, firewall_response): assert firewall_in_rule.source_ips == [ "28.239.13.1/32", "28.239.14.0/24", - "ff21:1eac:9a3b:ee58:5ca:990c:8bc9:c03b/128" + "ff21:1eac:9a3b:ee58:5ca:990c:8bc9:c03b/128", ] assert isinstance(firewall_in_rule.destination_ips, list) assert len(firewall_in_rule.destination_ips) == 0 @@ -60,23 +63,21 @@ def test_bound_firewall_init(self, firewall_response): assert firewall_out_rule.destination_ips == [ "28.239.13.1/32", "28.239.14.0/24", - "ff21:1eac:9a3b:ee58:5ca:990c:8bc9:c03b/128" + "ff21:1eac:9a3b:ee58:5ca:990c:8bc9:c03b/128", ] assert firewall_out_rule.description == "allow http out" @pytest.mark.parametrize( - "params", - [ - {}, - {"sort": ["created"], - "page": 1, - "per_page": 2} - ] + "params", [{}, {"sort": ["created"], "page": 1, "per_page": 2}] ) - def test_get_actions_list(self, hetzner_client, bound_firewall, response_get_actions, params): + def test_get_actions_list( + self, hetzner_client, bound_firewall, response_get_actions, params + ): hetzner_client.request.return_value = response_get_actions result = bound_firewall.get_actions_list(**params) - hetzner_client.request.assert_called_with(url="/firewalls/1/actions", method="GET", params=params) + hetzner_client.request.assert_called_with( + url="/firewalls/1/actions", method="GET", params=params + ) actions = result.actions assert result.meta is None @@ -86,20 +87,18 @@ def test_get_actions_list(self, hetzner_client, bound_firewall, response_get_act assert actions[0].id == 13 assert actions[0].command == "set_firewall_rules" - @pytest.mark.parametrize( - "params", - [ - {}, - {"sort": ["created"]} - ] - ) - def test_get_actions(self, hetzner_client, bound_firewall, response_get_actions, params): + @pytest.mark.parametrize("params", [{}, {"sort": ["created"]}]) + def test_get_actions( + self, hetzner_client, bound_firewall, response_get_actions, params + ): hetzner_client.request.return_value = response_get_actions actions = bound_firewall.get_actions(**params) - params.update({'page': 1, "per_page": 50}) + params.update({"page": 1, "per_page": 50}) - hetzner_client.request.assert_called_with(url="/firewalls/1/actions", method="GET", params=params) + hetzner_client.request.assert_called_with( + url="/firewalls/1/actions", method="GET", params=params + ) assert len(actions) == 1 assert isinstance(actions[0], BoundAction) @@ -108,9 +107,14 @@ def test_get_actions(self, hetzner_client, bound_firewall, response_get_actions, def test_update(self, hetzner_client, bound_firewall, response_update_firewall): hetzner_client.request.return_value = response_update_firewall - firewall = bound_firewall.update(name="New Corporate Intranet Protection", labels={}) - hetzner_client.request.assert_called_with(url="/firewalls/1", method="PUT", - json={"name": "New Corporate Intranet Protection", "labels": {}}) + firewall = bound_firewall.update( + name="New Corporate Intranet Protection", labels={} + ) + hetzner_client.request.assert_called_with( + url="/firewalls/1", + method="PUT", + json={"name": "New Corporate Intranet Protection", "labels": {}}, + ) assert firewall.id == 38 assert firewall.name == "New Corporate Intranet Protection" @@ -123,50 +127,68 @@ def test_delete(self, hetzner_client, bound_firewall): def test_set_rules(self, hetzner_client, bound_firewall, response_set_rules): hetzner_client.request.return_value = response_set_rules - actions = bound_firewall.set_rules([ - FirewallRule(direction=FirewallRule.DIRECTION_IN, protocol=FirewallRule.PROTOCOL_ICMP, - source_ips=["0.0.0.0/0", "::/0"], description="New firewall description")]) - hetzner_client.request.assert_called_with(url="/firewalls/1/actions/set_rules", method="POST", json={ - "rules": [{"direction": "in", "protocol": "icmp", "source_ips": ["0.0.0.0/0", "::/0"], "description": "New firewall description"}]}) + actions = bound_firewall.set_rules( + [ + FirewallRule( + direction=FirewallRule.DIRECTION_IN, + protocol=FirewallRule.PROTOCOL_ICMP, + source_ips=["0.0.0.0/0", "::/0"], + description="New firewall description", + ) + ] + ) + hetzner_client.request.assert_called_with( + url="/firewalls/1/actions/set_rules", + method="POST", + json={ + "rules": [ + { + "direction": "in", + "protocol": "icmp", + "source_ips": ["0.0.0.0/0", "::/0"], + "description": "New firewall description", + } + ] + }, + ) assert actions[0].id == 13 assert actions[0].progress == 100 - def test_apply_to_resources(self, hetzner_client, bound_firewall, response_set_rules): + def test_apply_to_resources( + self, hetzner_client, bound_firewall, response_set_rules + ): hetzner_client.request.return_value = response_set_rules actions = bound_firewall.apply_to_resources( - [FirewallResource(type=FirewallResource.TYPE_SERVER, server=Server(id=5))]) + [FirewallResource(type=FirewallResource.TYPE_SERVER, server=Server(id=5))] + ) hetzner_client.request.assert_called_with( url="/firewalls/1/actions/apply_to_resources", method="POST", - json={ - "apply_to": [ - {"type": "server", "server": {"id": 5}} - ] - }) + json={"apply_to": [{"type": "server", "server": {"id": 5}}]}, + ) assert actions[0].id == 13 assert actions[0].progress == 100 - def test_remove_from_resources(self, hetzner_client, bound_firewall, response_set_rules): + def test_remove_from_resources( + self, hetzner_client, bound_firewall, response_set_rules + ): hetzner_client.request.return_value = response_set_rules actions = bound_firewall.remove_from_resources( - [FirewallResource(type=FirewallResource.TYPE_SERVER, server=Server(id=5))]) + [FirewallResource(type=FirewallResource.TYPE_SERVER, server=Server(id=5))] + ) hetzner_client.request.assert_called_with( url="/firewalls/1/actions/remove_from_resources", method="POST", - json={ - "remove_from": [ - {"type": "server", "server": {"id": 5}} - ] - }) + json={"remove_from": [{"type": "server", "server": {"id": 5}}]}, + ) assert actions[0].id == 13 assert actions[0].progress == 100 class TestFirewallsClient(object): - @pytest.fixture() def firewalls_client(self): return FirewallsClient(client=mock.MagicMock()) @@ -174,7 +196,9 @@ def firewalls_client(self): def test_get_by_id(self, firewalls_client, firewall_response): firewalls_client._client.request.return_value = firewall_response firewall = firewalls_client.get_by_id(1) - firewalls_client._client.request.assert_called_with(url="/firewalls/1", method="GET") + firewalls_client._client.request.assert_called_with( + url="/firewalls/1", method="GET" + ) assert firewall._client is firewalls_client assert firewall.id == 38 assert firewall.name == "Corporate Intranet Protection" @@ -183,20 +207,22 @@ def test_get_by_id(self, firewalls_client, firewall_response): "params", [ { - 'name': "Corporate Intranet Protection", + "name": "Corporate Intranet Protection", "sort": "id", "label_selector": "k==v", "page": 1, - "per_page": 10 + "per_page": 10, }, - {'name': ""}, - {} - ] + {"name": ""}, + {}, + ], ) def test_get_list(self, firewalls_client, two_firewalls_response, params): firewalls_client._client.request.return_value = two_firewalls_response result = firewalls_client.get_list(**params) - firewalls_client._client.request.assert_called_with(url="/firewalls", method="GET", params=params) + firewalls_client._client.request.assert_called_with( + url="/firewalls", method="GET", params=params + ) firewalls = result.firewalls assert result.meta is None @@ -218,12 +244,12 @@ def test_get_list(self, firewalls_client, two_firewalls_response, params): "params", [ { - 'name': "Corporate Intranet Protection", + "name": "Corporate Intranet Protection", "sort": "id", "label_selector": "k==v", }, - {} - ] + {}, + ], ) def test_get_all(self, firewalls_client, two_firewalls_response, params): firewalls_client._client.request.return_value = two_firewalls_response @@ -231,7 +257,9 @@ def test_get_all(self, firewalls_client, two_firewalls_response, params): params.update({"page": 1, "per_page": 50}) - firewalls_client._client.request.assert_called_with(url="/firewalls", method="GET", params=params) + firewalls_client._client.request.assert_called_with( + url="/firewalls", method="GET", params=params + ) assert len(firewalls) == 2 @@ -252,17 +280,23 @@ def test_get_by_name(self, firewalls_client, one_firewalls_response): params = {"name": "Corporate Intranet Protection"} - firewalls_client._client.request.assert_called_with(url="/firewalls", method="GET", params=params) + firewalls_client._client.request.assert_called_with( + url="/firewalls", method="GET", params=params + ) assert firewall._client is firewalls_client assert firewall.id == 38 assert firewall.name == "Corporate Intranet Protection" - @pytest.mark.parametrize("firewall", [Firewall(id=1), BoundFirewall(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "firewall", [Firewall(id=1), BoundFirewall(mock.MagicMock(), dict(id=1))] + ) def test_get_actions_list(self, firewalls_client, firewall, response_get_actions): firewalls_client._client.request.return_value = response_get_actions result = firewalls_client.get_actions_list(firewall) - firewalls_client._client.request.assert_called_with(url="/firewalls/1/actions", method="GET", params={}) + firewalls_client._client.request.assert_called_with( + url="/firewalls/1/actions", method="GET", params={} + ) actions = result.actions assert result.meta is None @@ -278,42 +312,39 @@ def test_create(self, firewalls_client, response_create_firewall): firewalls_client._client.request.return_value = response_create_firewall response = firewalls_client.create( "Corporate Intranet Protection", - rules=[FirewallRule(direction=FirewallRule.DIRECTION_IN, protocol=FirewallRule.PROTOCOL_ICMP, - source_ips=["0.0.0.0/0"])], + rules=[ + FirewallRule( + direction=FirewallRule.DIRECTION_IN, + protocol=FirewallRule.PROTOCOL_ICMP, + source_ips=["0.0.0.0/0"], + ) + ], resources=[ - FirewallResource(type=FirewallResource.TYPE_SERVER, server=Server(id=4711)), - FirewallResource(type=FirewallResource.TYPE_LABEL_SELECTOR, label_selector=FirewallResourceLabelSelector(selector="key==value")) - ] + FirewallResource( + type=FirewallResource.TYPE_SERVER, server=Server(id=4711) + ), + FirewallResource( + type=FirewallResource.TYPE_LABEL_SELECTOR, + label_selector=FirewallResourceLabelSelector(selector="key==value"), + ), + ], ) firewalls_client._client.request.assert_called_with( url="/firewalls", method="POST", json={ - 'name': "Corporate Intranet Protection", - 'rules': [ - { - "direction": "in", - "protocol": "icmp", - "source_ips": [ - "0.0.0.0/0" - ] - } + "name": "Corporate Intranet Protection", + "rules": [ + {"direction": "in", "protocol": "icmp", "source_ips": ["0.0.0.0/0"]} ], "apply_to": [ - { - "type": "server", - "server": { - "id": 4711 - } - }, + {"type": "server", "server": {"id": 4711}}, { "type": "label_selector", - "label_selector": { - "selector": "key==value" - } - } + "label_selector": {"selector": "key==value"}, + }, ], - } + }, ) bound_firewall = response.firewall @@ -326,67 +357,102 @@ def test_create(self, firewalls_client, response_create_firewall): assert len(actions) == 2 - @pytest.mark.parametrize("firewall", [Firewall(id=38), BoundFirewall(mock.MagicMock(), dict(id=38))]) + @pytest.mark.parametrize( + "firewall", [Firewall(id=38), BoundFirewall(mock.MagicMock(), dict(id=38))] + ) def test_update(self, firewalls_client, firewall, response_update_firewall): firewalls_client._client.request.return_value = response_update_firewall - firewall = firewalls_client.update(firewall, name="New Corporate Intranet Protection", labels={}) - firewalls_client._client.request.assert_called_with(url="/firewalls/38", method="PUT", - json={"name": "New Corporate Intranet Protection", - "labels": {}}) + firewall = firewalls_client.update( + firewall, name="New Corporate Intranet Protection", labels={} + ) + firewalls_client._client.request.assert_called_with( + url="/firewalls/38", + method="PUT", + json={"name": "New Corporate Intranet Protection", "labels": {}}, + ) assert firewall.id == 38 assert firewall.name == "New Corporate Intranet Protection" - @pytest.mark.parametrize("firewall", [Firewall(id=1), BoundFirewall(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "firewall", [Firewall(id=1), BoundFirewall(mock.MagicMock(), dict(id=1))] + ) def test_set_rules(self, firewalls_client, firewall, response_set_rules): firewalls_client._client.request.return_value = response_set_rules - actions = firewalls_client.set_rules(firewall, [ - FirewallRule(direction=FirewallRule.DIRECTION_IN, protocol=FirewallRule.PROTOCOL_ICMP, - source_ips=["0.0.0.0/0", "::/0"])]) - firewalls_client._client.request.assert_called_with(url="/firewalls/1/actions/set_rules", method="POST", json={ - "rules": [{"direction": "in", "protocol": "icmp", "source_ips": ["0.0.0.0/0", "::/0"]}]}) + actions = firewalls_client.set_rules( + firewall, + [ + FirewallRule( + direction=FirewallRule.DIRECTION_IN, + protocol=FirewallRule.PROTOCOL_ICMP, + source_ips=["0.0.0.0/0", "::/0"], + ) + ], + ) + firewalls_client._client.request.assert_called_with( + url="/firewalls/1/actions/set_rules", + method="POST", + json={ + "rules": [ + { + "direction": "in", + "protocol": "icmp", + "source_ips": ["0.0.0.0/0", "::/0"], + } + ] + }, + ) assert actions[0].id == 13 assert actions[0].progress == 100 - @pytest.mark.parametrize("firewall", [Firewall(id=1), BoundFirewall(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "firewall", [Firewall(id=1), BoundFirewall(mock.MagicMock(), dict(id=1))] + ) def test_delete(self, firewalls_client, firewall): delete_success = firewalls_client.delete(firewall) - firewalls_client._client.request.assert_called_with(url="/firewalls/1", method="DELETE") + firewalls_client._client.request.assert_called_with( + url="/firewalls/1", method="DELETE" + ) assert delete_success is True - @pytest.mark.parametrize("firewall", [Firewall(id=1), BoundFirewall(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "firewall", [Firewall(id=1), BoundFirewall(mock.MagicMock(), dict(id=1))] + ) def test_apply_to_resources(self, firewalls_client, firewall, response_set_rules): firewalls_client._client.request.return_value = response_set_rules - actions = firewalls_client.apply_to_resources(firewall, [ - FirewallResource(type=FirewallResource.TYPE_SERVER, server=Server(id=5))]) + actions = firewalls_client.apply_to_resources( + firewall, + [FirewallResource(type=FirewallResource.TYPE_SERVER, server=Server(id=5))], + ) firewalls_client._client.request.assert_called_with( url="/firewalls/1/actions/apply_to_resources", method="POST", - json={ - "apply_to": [ - {"type": "server", "server": {"id": 5}} - ] - }) + json={"apply_to": [{"type": "server", "server": {"id": 5}}]}, + ) assert actions[0].id == 13 assert actions[0].progress == 100 - @pytest.mark.parametrize("firewall", [Firewall(id=1), BoundFirewall(mock.MagicMock(), dict(id=1))]) - def test_remove_from_resources(self, firewalls_client, firewall, response_set_rules): + @pytest.mark.parametrize( + "firewall", [Firewall(id=1), BoundFirewall(mock.MagicMock(), dict(id=1))] + ) + def test_remove_from_resources( + self, firewalls_client, firewall, response_set_rules + ): firewalls_client._client.request.return_value = response_set_rules - actions = firewalls_client.remove_from_resources(firewall, [ - FirewallResource(type=FirewallResource.TYPE_SERVER, server=Server(id=5))]) + actions = firewalls_client.remove_from_resources( + firewall, + [FirewallResource(type=FirewallResource.TYPE_SERVER, server=Server(id=5))], + ) firewalls_client._client.request.assert_called_with( url="/firewalls/1/actions/remove_from_resources", - method="POST", json={ - "remove_from": [ - {"type": "server", "server": {"id": 5}} - ] - }) + method="POST", + json={"remove_from": [{"type": "server", "server": {"id": 5}}]}, + ) assert actions[0].id == 13 assert actions[0].progress == 100 diff --git a/tests/unit/firewalls/test_domain.py b/tests/unit/firewalls/test_domain.py index 9468a07..a4edc73 100644 --- a/tests/unit/firewalls/test_domain.py +++ b/tests/unit/firewalls/test_domain.py @@ -5,7 +5,8 @@ class TestFirewall(object): - def test_created_is_datetime(self): firewall = Firewall(id=1, created="2016-01-30T23:50+00:00") - assert firewall.created == datetime.datetime(2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0)) + assert firewall.created == datetime.datetime( + 2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0) + ) diff --git a/tests/unit/floating_ips/conftest.py b/tests/unit/floating_ips/conftest.py index 6bdd635..d4641e8 100644 --- a/tests/unit/floating_ips/conftest.py +++ b/tests/unit/floating_ips/conftest.py @@ -12,12 +12,7 @@ def floating_ip_response(): "ip": "131.232.99.1", "type": "ipv4", "server": 42, - "dns_ptr": [ - { - "ip": "2001:db8::1", - "dns_ptr": "server.example.com" - } - ], + "dns_ptr": [{"ip": "2001:db8::1", "dns_ptr": "server.example.com"}], "home_location": { "id": 1, "name": "fsn1", @@ -25,13 +20,11 @@ def floating_ip_response(): "country": "DE", "city": "Falkenstein", "latitude": 50.47612, - "longitude": 12.370071 + "longitude": 12.370071, }, "blocked": False, - "protection": { - "delete": False - }, - "labels": {} + "protection": {"delete": False}, + "labels": {}, } } @@ -48,12 +41,7 @@ def one_floating_ips_response(): "ip": "131.232.99.1", "type": "ipv4", "server": 42, - "dns_ptr": [ - { - "ip": "2001:db8::1", - "dns_ptr": "server.example.com" - } - ], + "dns_ptr": [{"ip": "2001:db8::1", "dns_ptr": "server.example.com"}], "home_location": { "id": 1, "name": "fsn1", @@ -61,13 +49,11 @@ def one_floating_ips_response(): "country": "DE", "city": "Falkenstein", "latitude": 50.47612, - "longitude": 12.370071 + "longitude": 12.370071, }, "blocked": False, - "protection": { - "delete": False - }, - "labels": {} + "protection": {"delete": False}, + "labels": {}, }, ] } @@ -85,12 +71,7 @@ def two_floating_ips_response(): "ip": "131.232.99.1", "type": "ipv4", "server": 42, - "dns_ptr": [ - { - "ip": "2001:db8::1", - "dns_ptr": "server.example.com" - } - ], + "dns_ptr": [{"ip": "2001:db8::1", "dns_ptr": "server.example.com"}], "home_location": { "id": 1, "name": "fsn1", @@ -98,13 +79,11 @@ def two_floating_ips_response(): "country": "DE", "city": "Falkenstein", "latitude": 50.47612, - "longitude": 12.370071 + "longitude": 12.370071, }, "blocked": False, - "protection": { - "delete": False - }, - "labels": {} + "protection": {"delete": False}, + "labels": {}, }, { "id": 4712, @@ -114,12 +93,7 @@ def two_floating_ips_response(): "ip": "131.232.99.2", "type": "ipv4", "server": 42, - "dns_ptr": [ - { - "ip": "2001:db8::1", - "dns_ptr": "server.example.com" - } - ], + "dns_ptr": [{"ip": "2001:db8::1", "dns_ptr": "server.example.com"}], "home_location": { "id": 1, "name": "fsn1", @@ -127,14 +101,12 @@ def two_floating_ips_response(): "country": "DE", "city": "Falkenstein", "latitude": 50.47612, - "longitude": 12.370071 + "longitude": 12.370071, }, "blocked": False, - "protection": { - "delete": False - }, - "labels": {} - } + "protection": {"delete": False}, + "labels": {}, + }, ] } @@ -150,12 +122,7 @@ def floating_ip_create_response(): "ip": "131.232.99.1", "type": "ipv4", "server": 42, - "dns_ptr": [ - { - "ip": "2001:db8::1", - "dns_ptr": "server.example.com" - } - ], + "dns_ptr": [{"ip": "2001:db8::1", "dns_ptr": "server.example.com"}], "home_location": { "id": 1, "name": "fsn1", @@ -163,13 +130,11 @@ def floating_ip_create_response(): "country": "DE", "city": "Falkenstein", "latitude": 50.47612, - "longitude": 12.370071 + "longitude": 12.370071, }, "blocked": False, - "protection": { - "delete": False - }, - "labels": {} + "protection": {"delete": False}, + "labels": {}, }, "action": { "id": 13, @@ -178,17 +143,9 @@ def floating_ip_create_response(): "progress": 0, "started": "2016-01-30T23:50+00:00", "finished": None, - "resources": [ - { - "id": 42, - "type": "server" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } - } + "resources": [{"id": 42, "type": "server"}], + "error": {"code": "action_failed", "message": "Action failed"}, + }, } @@ -203,12 +160,7 @@ def response_update_floating_ip(): "ip": "131.232.99.1", "type": "ipv4", "server": 42, - "dns_ptr": [ - { - "ip": "2001:db8::1", - "dns_ptr": "server.example.com" - } - ], + "dns_ptr": [{"ip": "2001:db8::1", "dns_ptr": "server.example.com"}], "home_location": { "id": 1, "name": "fsn1", @@ -216,13 +168,11 @@ def response_update_floating_ip(): "country": "DE", "city": "Falkenstein", "latitude": 50.47612, - "longitude": 12.370071 + "longitude": 12.370071, }, "blocked": False, - "protection": { - "delete": False - }, - "labels": {} + "protection": {"delete": False}, + "labels": {}, } } @@ -238,16 +188,8 @@ def response_get_actions(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 42, - "type": "server" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 42, "type": "server"}], + "error": {"code": "action_failed", "message": "Action failed"}, } ] } diff --git a/tests/unit/floating_ips/test_client.py b/tests/unit/floating_ips/test_client.py index ba77659..e8adcca 100644 --- a/tests/unit/floating_ips/test_client.py +++ b/tests/unit/floating_ips/test_client.py @@ -11,15 +11,13 @@ class TestBoundFloatingIP(object): - @pytest.fixture() def bound_floating_ip(self, hetzner_client): return BoundFloatingIP(client=hetzner_client.floating_ips, data=dict(id=14)) def test_bound_floating_ip_init(self, floating_ip_response): bound_floating_ip = BoundFloatingIP( - client=mock.MagicMock(), - data=floating_ip_response['floating_ip'] + client=mock.MagicMock(), data=floating_ip_response["floating_ip"] ) assert bound_floating_ip.id == 4711 @@ -46,19 +44,29 @@ def test_bound_floating_ip_init(self, floating_ip_response): def test_get_actions(self, hetzner_client, bound_floating_ip, response_get_actions): hetzner_client.request.return_value = response_get_actions actions = bound_floating_ip.get_actions(sort="id") - hetzner_client.request.assert_called_with(url="/floating_ips/14/actions", method="GET", - params={"sort": "id", 'page': 1, 'per_page': 50}) + hetzner_client.request.assert_called_with( + url="/floating_ips/14/actions", + method="GET", + params={"sort": "id", "page": 1, "per_page": 50}, + ) assert len(actions) == 1 assert isinstance(actions[0], BoundAction) assert actions[0].id == 13 assert actions[0].command == "assign_floating_ip" - def test_update(self, hetzner_client, bound_floating_ip, response_update_floating_ip): + def test_update( + self, hetzner_client, bound_floating_ip, response_update_floating_ip + ): hetzner_client.request.return_value = response_update_floating_ip - floating_ip = bound_floating_ip.update(description="New description", name="New name") - hetzner_client.request.assert_called_with(url="/floating_ips/14", method="PUT", - json={"description": "New description", "name": "New name"}) + floating_ip = bound_floating_ip.update( + description="New description", name="New name" + ) + hetzner_client.request.assert_called_with( + url="/floating_ips/14", + method="PUT", + json={"description": "New description", "name": "New name"}, + ) assert floating_ip.id == 4711 assert floating_ip.description == "New description" @@ -67,28 +75,32 @@ def test_update(self, hetzner_client, bound_floating_ip, response_update_floatin def test_delete(self, hetzner_client, bound_floating_ip, generic_action): hetzner_client.request.return_value = generic_action delete_success = bound_floating_ip.delete() - hetzner_client.request.assert_called_with(url="/floating_ips/14", method="DELETE") + hetzner_client.request.assert_called_with( + url="/floating_ips/14", method="DELETE" + ) assert delete_success is True def test_change_protection(self, hetzner_client, bound_floating_ip, generic_action): hetzner_client.request.return_value = generic_action action = bound_floating_ip.change_protection(True) - hetzner_client.request.assert_called_with(url="/floating_ips/14/actions/change_protection", method="POST", - json={"delete": True}) + hetzner_client.request.assert_called_with( + url="/floating_ips/14/actions/change_protection", + method="POST", + json={"delete": True}, + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("server", - (Server(id=1), BoundServer(mock.MagicMock(), dict(id=1)))) + @pytest.mark.parametrize( + "server", (Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))) + ) def test_assign(self, hetzner_client, bound_floating_ip, server, generic_action): hetzner_client.request.return_value = generic_action action = bound_floating_ip.assign(server) hetzner_client.request.assert_called_with( - url="/floating_ips/14/actions/assign", - method="POST", - json={"server": 1} + url="/floating_ips/14/actions/assign", method="POST", json={"server": 1} ) assert action.id == 1 assert action.progress == 0 @@ -97,8 +109,7 @@ def test_unassign(self, hetzner_client, bound_floating_ip, generic_action): hetzner_client.request.return_value = generic_action action = bound_floating_ip.unassign() hetzner_client.request.assert_called_with( - url="/floating_ips/14/actions/unassign", - method="POST" + url="/floating_ips/14/actions/unassign", method="POST" ) assert action.id == 1 assert action.progress == 0 @@ -109,14 +120,13 @@ def test_change_dns_ptr(self, hetzner_client, bound_floating_ip, generic_action) hetzner_client.request.assert_called_with( url="/floating_ips/14/actions/change_dns_ptr", method="POST", - json={"ip": "1.2.3.4", "dns_ptr": "server02.example.com"} + json={"ip": "1.2.3.4", "dns_ptr": "server02.example.com"}, ) assert action.id == 1 assert action.progress == 0 class TestFloatingIPsClient(object): - @pytest.fixture() def floating_ips_client(self): return FloatingIPsClient(client=mock.MagicMock()) @@ -124,7 +134,9 @@ def floating_ips_client(self): def test_get_by_id(self, floating_ips_client, floating_ip_response): floating_ips_client._client.request.return_value = floating_ip_response bound_floating_ip = floating_ips_client.get_by_id(1) - floating_ips_client._client.request.assert_called_with(url="/floating_ips/1", method="GET") + floating_ips_client._client.request.assert_called_with( + url="/floating_ips/1", method="GET" + ) assert bound_floating_ip._client is floating_ips_client assert bound_floating_ip.id == 4711 assert bound_floating_ip.description == "Web Frontend" @@ -132,18 +144,24 @@ def test_get_by_id(self, floating_ips_client, floating_ip_response): def test_get_by_name(self, floating_ips_client, one_floating_ips_response): floating_ips_client._client.request.return_value = one_floating_ips_response bound_floating_ip = floating_ips_client.get_by_name("Web Frontend") - floating_ips_client._client.request.assert_called_with(url="/floating_ips", method="GET", - params={"name": "Web Frontend"}) + floating_ips_client._client.request.assert_called_with( + url="/floating_ips", method="GET", params={"name": "Web Frontend"} + ) assert bound_floating_ip._client is floating_ips_client assert bound_floating_ip.id == 4711 assert bound_floating_ip.name == "Web Frontend" assert bound_floating_ip.description == "Web Frontend" - @pytest.mark.parametrize("params", [{'label_selector': "label1", 'page': 1, 'per_page': 10}, {'name': ""}, {}]) + @pytest.mark.parametrize( + "params", + [{"label_selector": "label1", "page": 1, "per_page": 10}, {"name": ""}, {}], + ) def test_get_list(self, floating_ips_client, two_floating_ips_response, params): floating_ips_client._client.request.return_value = two_floating_ips_response result = floating_ips_client.get_list(**params) - floating_ips_client._client.request.assert_called_with(url="/floating_ips", method="GET", params=params) + floating_ips_client._client.request.assert_called_with( + url="/floating_ips", method="GET", params=params + ) bound_floating_ips = result.floating_ips assert result.meta is None @@ -161,14 +179,16 @@ def test_get_list(self, floating_ips_client, two_floating_ips_response, params): assert bound_floating_ip2.id == 4712 assert bound_floating_ip2.description == "Web Backend" - @pytest.mark.parametrize("params", [{'label_selector': "label1"}, {}]) + @pytest.mark.parametrize("params", [{"label_selector": "label1"}, {}]) def test_get_all(self, floating_ips_client, two_floating_ips_response, params): floating_ips_client._client.request.return_value = two_floating_ips_response bound_floating_ips = floating_ips_client.get_all(**params) - params.update({'page': 1, 'per_page': 50}) + params.update({"page": 1, "per_page": 50}) - floating_ips_client._client.request.assert_called_with(url="/floating_ips", method="GET", params=params) + floating_ips_client._client.request.assert_called_with( + url="/floating_ips", method="GET", params=params + ) assert len(bound_floating_ips) == 2 @@ -194,10 +214,10 @@ def test_create_with_location(self, floating_ips_client, floating_ip_response): url="/floating_ips", method="POST", json={ - 'description': "Web Frontend", - 'type': "ipv6", - 'home_location': "location" - } + "description": "Web Frontend", + "type": "ipv6", + "home_location": "location", + }, ) bound_floating_ip = response.floating_ip @@ -208,22 +228,20 @@ def test_create_with_location(self, floating_ips_client, floating_ip_response): assert bound_floating_ip.description == "Web Frontend" assert action is None - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) - def test_create_with_server(self, floating_ips_client, server, floating_ip_create_response): + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) + def test_create_with_server( + self, floating_ips_client, server, floating_ip_create_response + ): floating_ips_client._client.request.return_value = floating_ip_create_response response = floating_ips_client.create( - type="ipv6", - description="Web Frontend", - server=server + type="ipv6", description="Web Frontend", server=server ) floating_ips_client._client.request.assert_called_with( url="/floating_ips", method="POST", - json={ - 'description': "Web Frontend", - 'type': "ipv6", - 'server': 1 - } + json={"description": "Web Frontend", "type": "ipv6", "server": 1}, ) bound_floating_ip = response.floating_ip action = response.action @@ -233,22 +251,24 @@ def test_create_with_server(self, floating_ips_client, server, floating_ip_creat assert bound_floating_ip.description == "Web Frontend" assert action.id == 13 - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) - def test_create_with_name(self, floating_ips_client, server, floating_ip_create_response): + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) + def test_create_with_name( + self, floating_ips_client, server, floating_ip_create_response + ): floating_ips_client._client.request.return_value = floating_ip_create_response response = floating_ips_client.create( - type="ipv6", - description="Web Frontend", - name="Web Frontend" + type="ipv6", description="Web Frontend", name="Web Frontend" ) floating_ips_client._client.request.assert_called_with( url="/floating_ips", method="POST", json={ - 'description': "Web Frontend", - 'type': "ipv6", - 'name': "Web Frontend" - } + "description": "Web Frontend", + "type": "ipv6", + "name": "Web Frontend", + }, ) bound_floating_ip = response.floating_ip action = response.action @@ -259,12 +279,17 @@ def test_create_with_name(self, floating_ips_client, server, floating_ip_create_ assert bound_floating_ip.name == "Web Frontend" assert action.id == 13 - @pytest.mark.parametrize("floating_ip", [FloatingIP(id=1), BoundFloatingIP(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "floating_ip", [FloatingIP(id=1), BoundFloatingIP(mock.MagicMock(), dict(id=1))] + ) def test_get_actions(self, floating_ips_client, floating_ip, response_get_actions): floating_ips_client._client.request.return_value = response_get_actions actions = floating_ips_client.get_actions(floating_ip) - floating_ips_client._client.request.assert_called_with(url="/floating_ips/1/actions", method="GET", - params={'page': 1, 'per_page': 50}) + floating_ips_client._client.request.assert_called_with( + url="/floating_ips/1/actions", + method="GET", + params={"page": 1, "per_page": 50}, + ) assert len(actions) == 1 assert isinstance(actions[0], BoundAction) @@ -273,70 +298,98 @@ def test_get_actions(self, floating_ips_client, floating_ip, response_get_action assert actions[0].id == 13 assert actions[0].command == "assign_floating_ip" - @pytest.mark.parametrize("floating_ip", [FloatingIP(id=1), BoundFloatingIP(mock.MagicMock(), dict(id=1))]) - def test_update(self, floating_ips_client, floating_ip, response_update_floating_ip): + @pytest.mark.parametrize( + "floating_ip", [FloatingIP(id=1), BoundFloatingIP(mock.MagicMock(), dict(id=1))] + ) + def test_update( + self, floating_ips_client, floating_ip, response_update_floating_ip + ): floating_ips_client._client.request.return_value = response_update_floating_ip - floating_ip = floating_ips_client.update(floating_ip, description="New description", name="New name") - floating_ips_client._client.request.assert_called_with(url="/floating_ips/1", method="PUT", - json={"description": "New description", - "name": "New name"}) + floating_ip = floating_ips_client.update( + floating_ip, description="New description", name="New name" + ) + floating_ips_client._client.request.assert_called_with( + url="/floating_ips/1", + method="PUT", + json={"description": "New description", "name": "New name"}, + ) assert floating_ip.id == 4711 assert floating_ip.description == "New description" assert floating_ip.name == "New name" - @pytest.mark.parametrize("floating_ip", [FloatingIP(id=1), BoundFloatingIP(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "floating_ip", [FloatingIP(id=1), BoundFloatingIP(mock.MagicMock(), dict(id=1))] + ) def test_change_protection(self, floating_ips_client, floating_ip, generic_action): floating_ips_client._client.request.return_value = generic_action action = floating_ips_client.change_protection(floating_ip, True) - floating_ips_client._client.request.assert_called_with(url="/floating_ips/1/actions/change_protection", - method="POST", json={"delete": True}) + floating_ips_client._client.request.assert_called_with( + url="/floating_ips/1/actions/change_protection", + method="POST", + json={"delete": True}, + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("floating_ip", [FloatingIP(id=1), BoundFloatingIP(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "floating_ip", [FloatingIP(id=1), BoundFloatingIP(mock.MagicMock(), dict(id=1))] + ) def test_delete(self, floating_ips_client, floating_ip, generic_action): floating_ips_client._client.request.return_value = generic_action delete_success = floating_ips_client.delete(floating_ip) - floating_ips_client._client.request.assert_called_with(url="/floating_ips/1", method="DELETE") + floating_ips_client._client.request.assert_called_with( + url="/floating_ips/1", method="DELETE" + ) assert delete_success is True - @pytest.mark.parametrize("server,floating_ip", - [(Server(id=1), FloatingIP(id=12)), - (BoundServer(mock.MagicMock(), dict(id=1)), - BoundFloatingIP(mock.MagicMock(), dict(id=12)))]) + @pytest.mark.parametrize( + "server,floating_ip", + [ + (Server(id=1), FloatingIP(id=12)), + ( + BoundServer(mock.MagicMock(), dict(id=1)), + BoundFloatingIP(mock.MagicMock(), dict(id=12)), + ), + ], + ) def test_assign(self, floating_ips_client, server, floating_ip, generic_action): floating_ips_client._client.request.return_value = generic_action action = floating_ips_client.assign(floating_ip, server) floating_ips_client._client.request.assert_called_with( - url="/floating_ips/12/actions/assign", - method="POST", - json={"server": 1} + url="/floating_ips/12/actions/assign", method="POST", json={"server": 1} ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("floating_ip", [FloatingIP(id=12), BoundFloatingIP(mock.MagicMock(), dict(id=12))]) + @pytest.mark.parametrize( + "floating_ip", + [FloatingIP(id=12), BoundFloatingIP(mock.MagicMock(), dict(id=12))], + ) def test_unassign(self, floating_ips_client, floating_ip, generic_action): floating_ips_client._client.request.return_value = generic_action action = floating_ips_client.unassign(floating_ip) floating_ips_client._client.request.assert_called_with( - url="/floating_ips/12/actions/unassign", - method="POST" + url="/floating_ips/12/actions/unassign", method="POST" ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("floating_ip", [FloatingIP(id=12), BoundFloatingIP(mock.MagicMock(), dict(id=12))]) + @pytest.mark.parametrize( + "floating_ip", + [FloatingIP(id=12), BoundFloatingIP(mock.MagicMock(), dict(id=12))], + ) def test_change_dns_ptr(self, floating_ips_client, floating_ip, generic_action): floating_ips_client._client.request.return_value = generic_action - action = floating_ips_client.change_dns_ptr(floating_ip, "1.2.3.4", "server02.example.com") + action = floating_ips_client.change_dns_ptr( + floating_ip, "1.2.3.4", "server02.example.com" + ) floating_ips_client._client.request.assert_called_with( url="/floating_ips/12/actions/change_dns_ptr", method="POST", - json={"ip": "1.2.3.4", "dns_ptr": "server02.example.com"} + json={"ip": "1.2.3.4", "dns_ptr": "server02.example.com"}, ) assert action.id == 1 assert action.progress == 0 diff --git a/tests/unit/floating_ips/test_domain.py b/tests/unit/floating_ips/test_domain.py index 5d96aa1..167540a 100644 --- a/tests/unit/floating_ips/test_domain.py +++ b/tests/unit/floating_ips/test_domain.py @@ -5,7 +5,8 @@ class TestFloatingIP(object): - def test_created_is_datetime(self): floatingIP = FloatingIP(id=1, created="2016-01-30T23:50+00:00") - assert floatingIP.created == datetime.datetime(2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0)) + assert floatingIP.created == datetime.datetime( + 2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0) + ) diff --git a/tests/unit/images/conftest.py b/tests/unit/images/conftest.py index 511237f..0c3e56b 100644 --- a/tests/unit/images/conftest.py +++ b/tests/unit/images/conftest.py @@ -13,19 +13,14 @@ def image_response(): "image_size": 2.3, "disk_size": 10, "created": "2016-01-30T23:50+00:00", - "created_from": { - "id": 1, - "name": "Server" - }, + "created_from": {"id": 1, "name": "Server"}, "bound_to": 1, "os_flavor": "ubuntu", "os_version": "16.04", "rapid_deploy": False, - "protection": { - "delete": False - }, + "protection": {"delete": False}, "deprecated": "2018-02-28T00:00:00+00:00", - "labels": {} + "labels": {}, } } @@ -43,19 +38,14 @@ def two_images_response(): "image_size": 2.3, "disk_size": 10, "created": "2016-01-30T23:50+00:00", - "created_from": { - "id": 1, - "name": "Server" - }, + "created_from": {"id": 1, "name": "Server"}, "bound_to": None, "os_flavor": "ubuntu", "os_version": "16.04", "rapid_deploy": False, - "protection": { - "delete": False - }, + "protection": {"delete": False}, "deprecated": "2018-02-28T00:00:00+00:00", - "labels": {} + "labels": {}, }, { "id": 4712, @@ -66,20 +56,15 @@ def two_images_response(): "image_size": 2.3, "disk_size": 10, "created": "2016-01-30T23:50+00:00", - "created_from": { - "id": 1, - "name": "Server" - }, + "created_from": {"id": 1, "name": "Server"}, "bound_to": None, "os_flavor": "ubuntu", "os_version": "16.04", "rapid_deploy": False, - "protection": { - "delete": False - }, + "protection": {"delete": False}, "deprecated": "2018-02-28T00:00:00+00:00", - "labels": {} - } + "labels": {}, + }, ] } @@ -97,19 +82,14 @@ def one_images_response(): "image_size": 2.3, "disk_size": 10, "created": "2016-01-30T23:50+00:00", - "created_from": { - "id": 1, - "name": "Server" - }, + "created_from": {"id": 1, "name": "Server"}, "bound_to": None, "os_flavor": "ubuntu", "os_version": "16.04", "rapid_deploy": False, - "protection": { - "delete": False - }, + "protection": {"delete": False}, "deprecated": "2018-02-28T00:00:00+00:00", - "labels": {} + "labels": {}, }, ] } @@ -127,19 +107,14 @@ def response_update_image(): "image_size": 2.3, "disk_size": 10, "created": "2016-01-30T23:50+00:00", - "created_from": { - "id": 1, - "name": "Server" - }, + "created_from": {"id": 1, "name": "Server"}, "bound_to": None, "os_flavor": "ubuntu", "os_version": "16.04", "rapid_deploy": False, - "protection": { - "delete": False - }, + "protection": {"delete": False}, "deprecated": "2018-02-28T00:00:00+00:00", - "labels": {} + "labels": {}, } } @@ -155,16 +130,8 @@ def response_get_actions(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 42, - "type": "image" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 42, "type": "image"}], + "error": {"code": "action_failed", "message": "Action failed"}, } ] } diff --git a/tests/unit/images/test_client.py b/tests/unit/images/test_client.py index e951d90..521ad1f 100644 --- a/tests/unit/images/test_client.py +++ b/tests/unit/images/test_client.py @@ -10,16 +10,12 @@ class TestBoundImage(object): - @pytest.fixture() def bound_image(self, hetzner_client): return BoundImage(client=hetzner_client.images, data=dict(id=14)) def test_bound_image_init(self, image_response): - bound_image = BoundImage( - client=mock.MagicMock(), - data=image_response['image'] - ) + bound_image = BoundImage(client=mock.MagicMock(), data=image_response["image"]) assert bound_image.id == 4711 assert bound_image.type == "snapshot" @@ -28,11 +24,15 @@ def test_bound_image_init(self, image_response): assert bound_image.description == "Ubuntu 20.04 Standard 64 bit" assert bound_image.image_size == 2.3 assert bound_image.disk_size == 10 - assert bound_image.created == datetime.datetime(2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0)) + assert bound_image.created == datetime.datetime( + 2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0) + ) assert bound_image.os_flavor == "ubuntu" assert bound_image.os_version == "16.04" assert bound_image.rapid_deploy is False - assert bound_image.deprecated == datetime.datetime(2018, 2, 28, 0, 0, tzinfo=tzoffset(None, 0)) + assert bound_image.deprecated == datetime.datetime( + 2018, 2, 28, 0, 0, tzinfo=tzoffset(None, 0) + ) assert isinstance(bound_image.created_from, BoundServer) assert bound_image.created_from.id == 1 @@ -44,18 +44,16 @@ def test_bound_image_init(self, image_response): assert bound_image.bound_to.complete is False @pytest.mark.parametrize( - "params", - [ - {}, - {"sort": ["status"], - "page": 1, - "per_page": 2} - ] + "params", [{}, {"sort": ["status"], "page": 1, "per_page": 2}] ) - def test_get_actions_list(self, hetzner_client, bound_image, response_get_actions, params): + def test_get_actions_list( + self, hetzner_client, bound_image, response_get_actions, params + ): hetzner_client.request.return_value = response_get_actions result = bound_image.get_actions_list(**params) - hetzner_client.request.assert_called_with(url="/images/14/actions", method="GET", params=params) + hetzner_client.request.assert_called_with( + url="/images/14/actions", method="GET", params=params + ) actions = result.actions assert result.meta is None @@ -65,20 +63,18 @@ def test_get_actions_list(self, hetzner_client, bound_image, response_get_action assert actions[0].id == 13 assert actions[0].command == "change_protection" - @pytest.mark.parametrize( - "params", - [ - {}, - {"sort": ["status"]} - ] - ) - def test_get_actions(self, hetzner_client, bound_image, response_get_actions, params): + @pytest.mark.parametrize("params", [{}, {"sort": ["status"]}]) + def test_get_actions( + self, hetzner_client, bound_image, response_get_actions, params + ): hetzner_client.request.return_value = response_get_actions actions = bound_image.get_actions(**params) - params.update({'page': 1, "per_page": 50}) + params.update({"page": 1, "per_page": 50}) - hetzner_client.request.assert_called_with(url="/images/14/actions", method="GET", params=params) + hetzner_client.request.assert_called_with( + url="/images/14/actions", method="GET", params=params + ) assert len(actions) == 1 assert isinstance(actions[0], BoundAction) @@ -87,8 +83,18 @@ def test_get_actions(self, hetzner_client, bound_image, response_get_actions, pa def test_update(self, hetzner_client, bound_image, response_update_image): hetzner_client.request.return_value = response_update_image - image = bound_image.update(description="My new Image description", type="snapshot", labels={}) - hetzner_client.request.assert_called_with(url="/images/14", method="PUT", json={"description": "My new Image description", "type": "snapshot", "labels": {}}) + image = bound_image.update( + description="My new Image description", type="snapshot", labels={} + ) + hetzner_client.request.assert_called_with( + url="/images/14", + method="PUT", + json={ + "description": "My new Image description", + "type": "snapshot", + "labels": {}, + }, + ) assert image.id == 4711 assert image.description == "My new Image description" @@ -103,14 +109,17 @@ def test_delete(self, hetzner_client, bound_image, generic_action): def test_change_protection(self, hetzner_client, bound_image, generic_action): hetzner_client.request.return_value = generic_action action = bound_image.change_protection(True) - hetzner_client.request.assert_called_with(url="/images/14/actions/change_protection", method="POST", json={"delete": True}) + hetzner_client.request.assert_called_with( + url="/images/14/actions/change_protection", + method="POST", + json={"delete": True}, + ) assert action.id == 1 assert action.progress == 0 class TestImagesClient(object): - @pytest.fixture() def images_client(self): return ImagesClient(client=mock.MagicMock()) @@ -127,23 +136,25 @@ def test_get_by_id(self, images_client, image_response): "params", [ { - 'name': "ubuntu-20.04", + "name": "ubuntu-20.04", "type": "system", "sort": "id", "bound_to": "1", "label_selector": "k==v", "page": 1, - "per_page": 10 + "per_page": 10, }, - {'name': ""}, - {'include_deprecated': True}, - {} - ] + {"name": ""}, + {"include_deprecated": True}, + {}, + ], ) def test_get_list(self, images_client, two_images_response, params): images_client._client.request.return_value = two_images_response result = images_client.get_list(**params) - images_client._client.request.assert_called_with(url="/images", method="GET", params=params) + images_client._client.request.assert_called_with( + url="/images", method="GET", params=params + ) images = result.images assert result.meta is None @@ -165,15 +176,15 @@ def test_get_list(self, images_client, two_images_response, params): "params", [ { - 'name': "ubuntu-20.04", + "name": "ubuntu-20.04", "type": "system", "sort": "id", "bound_to": "1", "label_selector": "k==v", }, - {'include_deprecated': True}, - {} - ] + {"include_deprecated": True}, + {}, + ], ) def test_get_all(self, images_client, two_images_response, params): images_client._client.request.return_value = two_images_response @@ -181,7 +192,9 @@ def test_get_all(self, images_client, two_images_response, params): params.update({"page": 1, "per_page": 50}) - images_client._client.request.assert_called_with(url="/images", method="GET", params=params) + images_client._client.request.assert_called_with( + url="/images", method="GET", params=params + ) assert len(images) == 2 @@ -202,17 +215,23 @@ def test_get_by_name(self, images_client, one_images_response): params = {"name": "ubuntu-20.04"} - images_client._client.request.assert_called_with(url="/images", method="GET", params=params) + images_client._client.request.assert_called_with( + url="/images", method="GET", params=params + ) assert image._client is images_client assert image.id == 4711 assert image.name == "ubuntu-20.04" - @pytest.mark.parametrize("image", [Image(id=1), BoundImage(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "image", [Image(id=1), BoundImage(mock.MagicMock(), dict(id=1))] + ) def test_get_actions_list(self, images_client, image, response_get_actions): images_client._client.request.return_value = response_get_actions result = images_client.get_actions_list(image) - images_client._client.request.assert_called_with(url="/images/1/actions", method="GET", params={}) + images_client._client.request.assert_called_with( + url="/images/1/actions", method="GET", params={} + ) actions = result.actions assert result.meta is None @@ -224,28 +243,50 @@ def test_get_actions_list(self, images_client, image, response_get_actions): assert actions[0].id == 13 assert actions[0].command == "change_protection" - @pytest.mark.parametrize("image", [Image(id=1), BoundImage(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "image", [Image(id=1), BoundImage(mock.MagicMock(), dict(id=1))] + ) def test_update(self, images_client, image, response_update_image): images_client._client.request.return_value = response_update_image - image = images_client.update(image, description="My new Image description", type="snapshot", labels={}) - images_client._client.request.assert_called_with(url="/images/1", method="PUT", json={"description": "My new Image description", "type": "snapshot", "labels": {}}) + image = images_client.update( + image, description="My new Image description", type="snapshot", labels={} + ) + images_client._client.request.assert_called_with( + url="/images/1", + method="PUT", + json={ + "description": "My new Image description", + "type": "snapshot", + "labels": {}, + }, + ) assert image.id == 4711 assert image.description == "My new Image description" - @pytest.mark.parametrize("image", [Image(id=1), BoundImage(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "image", [Image(id=1), BoundImage(mock.MagicMock(), dict(id=1))] + ) def test_change_protection(self, images_client, image, generic_action): images_client._client.request.return_value = generic_action action = images_client.change_protection(image, True) - images_client._client.request.assert_called_with(url="/images/1/actions/change_protection", method="POST", json={"delete": True}) + images_client._client.request.assert_called_with( + url="/images/1/actions/change_protection", + method="POST", + json={"delete": True}, + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("image", [Image(id=1), BoundImage(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "image", [Image(id=1), BoundImage(mock.MagicMock(), dict(id=1))] + ) def test_delete(self, images_client, image, generic_action): images_client._client.request.return_value = generic_action delete_success = images_client.delete(image) - images_client._client.request.assert_called_with(url="/images/1", method="DELETE") + images_client._client.request.assert_called_with( + url="/images/1", method="DELETE" + ) assert delete_success is True diff --git a/tests/unit/images/test_domain.py b/tests/unit/images/test_domain.py index 6df24e2..733d45b 100644 --- a/tests/unit/images/test_domain.py +++ b/tests/unit/images/test_domain.py @@ -5,7 +5,8 @@ class TestImage(object): - def test_created_is_datetime(self): image = Image(id=1, created="2016-01-30T23:50+00:00") - assert image.created == datetime.datetime(2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0)) + assert image.created == datetime.datetime( + 2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0) + ) diff --git a/tests/unit/isos/conftest.py b/tests/unit/isos/conftest.py index f45aab7..4c27b01 100644 --- a/tests/unit/isos/conftest.py +++ b/tests/unit/isos/conftest.py @@ -9,7 +9,7 @@ def iso_response(): "name": "FreeBSD-11.0-RELEASE-amd64-dvd1", "description": "FreeBSD 11.0 x64", "type": "public", - "deprecated": "2018-02-28T00:00:00+00:00" + "deprecated": "2018-02-28T00:00:00+00:00", } } @@ -23,15 +23,15 @@ def two_isos_response(): "name": "FreeBSD-11.0-RELEASE-amd64-dvd1", "description": "FreeBSD 11.0 x64", "type": "public", - "deprecated": "2018-02-28T00:00:00+00:00" + "deprecated": "2018-02-28T00:00:00+00:00", }, { "id": 4712, "name": "FreeBSD-11.0-RELEASE-amd64-dvd1", "description": "FreeBSD 11.0 x64", "type": "public", - "deprecated": "2018-02-28T00:00:00+00:00" - } + "deprecated": "2018-02-28T00:00:00+00:00", + }, ] } @@ -45,7 +45,7 @@ def one_isos_response(): "name": "FreeBSD-11.0-RELEASE-amd64-dvd1", "description": "FreeBSD 11.0 x64", "type": "public", - "deprecated": "2018-02-28T00:00:00+00:00" + "deprecated": "2018-02-28T00:00:00+00:00", } ] } diff --git a/tests/unit/isos/test_client.py b/tests/unit/isos/test_client.py index d0a29e4..32a2a51 100644 --- a/tests/unit/isos/test_client.py +++ b/tests/unit/isos/test_client.py @@ -7,26 +7,23 @@ class TestBoundIso(object): - @pytest.fixture() def bound_iso(self, hetzner_client): return BoundIso(client=hetzner_client.isos, data=dict(id=14)) def test_bound_iso_init(self, iso_response): - bound_iso = BoundIso( - client=mock.MagicMock(), - data=iso_response['iso'] - ) + bound_iso = BoundIso(client=mock.MagicMock(), data=iso_response["iso"]) assert bound_iso.id == 4711 assert bound_iso.name == "FreeBSD-11.0-RELEASE-amd64-dvd1" assert bound_iso.description == "FreeBSD 11.0 x64" assert bound_iso.type == "public" - assert bound_iso.deprecated == datetime.datetime(2018, 2, 28, 0, 0, tzinfo=tzoffset(None, 0)) + assert bound_iso.deprecated == datetime.datetime( + 2018, 2, 28, 0, 0, tzinfo=tzoffset(None, 0) + ) class TestIsosClient(object): - @pytest.fixture() def isos_client(self): return IsosClient(client=mock.MagicMock()) @@ -43,16 +40,16 @@ def test_get_by_id(self, isos_client, iso_response): "params", [ {}, - {'name': ""}, - {'name': "FreeBSD-11.0-RELEASE-amd64-dvd1", - 'page': 1, - 'per_page': 2} - ] + {"name": ""}, + {"name": "FreeBSD-11.0-RELEASE-amd64-dvd1", "page": 1, "per_page": 2}, + ], ) def test_get_list(self, isos_client, two_isos_response, params): isos_client._client.request.return_value = two_isos_response result = isos_client.get_list(**params) - isos_client._client.request.assert_called_with(url="/isos", method="GET", params=params) + isos_client._client.request.assert_called_with( + url="/isos", method="GET", params=params + ) isos = result.isos assert result.meta is None @@ -71,19 +68,17 @@ def test_get_list(self, isos_client, two_isos_response, params): assert isos2.name == "FreeBSD-11.0-RELEASE-amd64-dvd1" @pytest.mark.parametrize( - "params", - [ - {}, - {'name': "FreeBSD-11.0-RELEASE-amd64-dvd1"} - ] + "params", [{}, {"name": "FreeBSD-11.0-RELEASE-amd64-dvd1"}] ) def test_get_all(self, isos_client, two_isos_response, params): isos_client._client.request.return_value = two_isos_response isos = isos_client.get_all(**params) - params.update({'page': 1, 'per_page': 50}) + params.update({"page": 1, "per_page": 50}) - isos_client._client.request.assert_called_with(url="/isos", method="GET", params=params) + isos_client._client.request.assert_called_with( + url="/isos", method="GET", params=params + ) assert len(isos) == 2 @@ -102,9 +97,11 @@ def test_get_by_name(self, isos_client, one_isos_response): isos_client._client.request.return_value = one_isos_response iso = isos_client.get_by_name("FreeBSD-11.0-RELEASE-amd64-dvd1") - params = {'name': "FreeBSD-11.0-RELEASE-amd64-dvd1"} + params = {"name": "FreeBSD-11.0-RELEASE-amd64-dvd1"} - isos_client._client.request.assert_called_with(url="/isos", method="GET", params=params) + isos_client._client.request.assert_called_with( + url="/isos", method="GET", params=params + ) assert iso._client is isos_client assert iso.id == 4711 diff --git a/tests/unit/isos/test_domain.py b/tests/unit/isos/test_domain.py index af1377a..6396a98 100644 --- a/tests/unit/isos/test_domain.py +++ b/tests/unit/isos/test_domain.py @@ -5,7 +5,8 @@ class TestIso(object): - def test_deprecated_is_datetime(self): iso = Iso(id=1, deprecated="2016-01-30T23:50+00:00") - assert iso.deprecated == datetime.datetime(2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0)) + assert iso.deprecated == datetime.datetime( + 2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0) + ) diff --git a/tests/unit/load_balancer_types/conftest.py b/tests/unit/load_balancer_types/conftest.py index 8ef5254..7e159c2 100644 --- a/tests/unit/load_balancer_types/conftest.py +++ b/tests/unit/load_balancer_types/conftest.py @@ -14,17 +14,17 @@ def load_balancer_type_response(): "max_assigned_certificates": 1, "deprecated": None, "prices": [ - { - "location": "fsn1", - "price_hourly": { - "net": "1.0000000000", - "gross": "1.1900000000000000" - }, - "price_monthly": { - "net": "1.0000000000", - "gross": "1.1900000000000000" - } - } + { + "location": "fsn1", + "price_hourly": { + "net": "1.0000000000", + "gross": "1.1900000000000000", + }, + "price_monthly": { + "net": "1.0000000000", + "gross": "1.1900000000000000", + }, + } ], } } @@ -48,12 +48,12 @@ def two_load_balancer_types_response(): "location": "fsn1", "price_hourly": { "net": "1.0000000000", - "gross": "1.1900000000000000" + "gross": "1.1900000000000000", }, "price_monthly": { "net": "1.0000000000", - "gross": "1.1900000000000000" - } + "gross": "1.1900000000000000", + }, } ], }, @@ -71,15 +71,15 @@ def two_load_balancer_types_response(): "location": "fsn1", "price_hourly": { "net": "1.0000000000", - "gross": "1.1900000000000000" + "gross": "1.1900000000000000", }, "price_monthly": { "net": "1.0000000000", - "gross": "1.1900000000000000" - } + "gross": "1.1900000000000000", + }, } ], - } + }, ] } @@ -102,12 +102,12 @@ def one_load_balancer_types_response(): "location": "fsn1", "price_hourly": { "net": "1.0000000000", - "gross": "1.1900000000000000" + "gross": "1.1900000000000000", }, "price_monthly": { "net": "1.0000000000", - "gross": "1.1900000000000000" - } + "gross": "1.1900000000000000", + }, } ], } diff --git a/tests/unit/load_balancer_types/test_client.py b/tests/unit/load_balancer_types/test_client.py index 446026d..565ce61 100644 --- a/tests/unit/load_balancer_types/test_client.py +++ b/tests/unit/load_balancer_types/test_client.py @@ -11,18 +11,30 @@ def load_balancer_types_client(self): return LoadBalancerTypesClient(client=mock.MagicMock()) def test_get_by_id(self, load_balancer_types_client, load_balancer_type_response): - load_balancer_types_client._client.request.return_value = load_balancer_type_response + load_balancer_types_client._client.request.return_value = ( + load_balancer_type_response + ) load_balancer_type = load_balancer_types_client.get_by_id(1) - load_balancer_types_client._client.request.assert_called_with(url="/load_balancer_types/1", method="GET") + load_balancer_types_client._client.request.assert_called_with( + url="/load_balancer_types/1", method="GET" + ) assert load_balancer_type._client is load_balancer_types_client assert load_balancer_type.id == 1 assert load_balancer_type.name == "LB11" - @pytest.mark.parametrize("params", [{'name': "LB11", 'page': 1, 'per_page': 10}, {'name': ""}, {}]) - def test_get_list(self, load_balancer_types_client, two_load_balancer_types_response, params): - load_balancer_types_client._client.request.return_value = two_load_balancer_types_response + @pytest.mark.parametrize( + "params", [{"name": "LB11", "page": 1, "per_page": 10}, {"name": ""}, {}] + ) + def test_get_list( + self, load_balancer_types_client, two_load_balancer_types_response, params + ): + load_balancer_types_client._client.request.return_value = ( + two_load_balancer_types_response + ) result = load_balancer_types_client.get_list(**params) - load_balancer_types_client._client.request.assert_called_with(url="/load_balancer_types", method="GET", params=params) + load_balancer_types_client._client.request.assert_called_with( + url="/load_balancer_types", method="GET", params=params + ) load_balancer_types = result.load_balancer_types assert result.meta is None @@ -40,14 +52,20 @@ def test_get_list(self, load_balancer_types_client, two_load_balancer_types_resp assert load_balancer_types2.id == 2 assert load_balancer_types2.name == "LB21" - @pytest.mark.parametrize("params", [{'name': "LB21"}]) - def test_get_all(self, load_balancer_types_client, two_load_balancer_types_response, params): - load_balancer_types_client._client.request.return_value = two_load_balancer_types_response + @pytest.mark.parametrize("params", [{"name": "LB21"}]) + def test_get_all( + self, load_balancer_types_client, two_load_balancer_types_response, params + ): + load_balancer_types_client._client.request.return_value = ( + two_load_balancer_types_response + ) load_balancer_types = load_balancer_types_client.get_all(**params) - params.update({'page': 1, 'per_page': 50}) + params.update({"page": 1, "per_page": 50}) - load_balancer_types_client._client.request.assert_called_with(url="/load_balancer_types", method="GET", params=params) + load_balancer_types_client._client.request.assert_called_with( + url="/load_balancer_types", method="GET", params=params + ) assert len(load_balancer_types) == 2 @@ -62,13 +80,19 @@ def test_get_all(self, load_balancer_types_client, two_load_balancer_types_respo assert load_balancer_types2.id == 2 assert load_balancer_types2.name == "LB21" - def test_get_by_name(self, load_balancer_types_client, one_load_balancer_types_response): - load_balancer_types_client._client.request.return_value = one_load_balancer_types_response + def test_get_by_name( + self, load_balancer_types_client, one_load_balancer_types_response + ): + load_balancer_types_client._client.request.return_value = ( + one_load_balancer_types_response + ) load_balancer_type = load_balancer_types_client.get_by_name("LB21") - params = {'name': "LB21"} + params = {"name": "LB21"} - load_balancer_types_client._client.request.assert_called_with(url="/load_balancer_types", method="GET", params=params) + load_balancer_types_client._client.request.assert_called_with( + url="/load_balancer_types", method="GET", params=params + ) assert load_balancer_type._client is load_balancer_types_client assert load_balancer_type.id == 2 diff --git a/tests/unit/load_balancers/conftest.py b/tests/unit/load_balancers/conftest.py index 79c71c8..9a7286b 100644 --- a/tests/unit/load_balancers/conftest.py +++ b/tests/unit/load_balancers/conftest.py @@ -17,7 +17,7 @@ def response_load_balancer(): "city": "Falkenstein", "latitude": 50.47612, "longitude": 12.370071, - "network_zone": "eu-central" + "network_zone": "eu-central", }, "load_balancer_type": { "id": 1, @@ -33,18 +33,16 @@ def response_load_balancer(): "location": "fsn-1", "price_hourly": { "net": "1.0000000000", - "gross": "1.1900000000000000" + "gross": "1.1900000000000000", }, "price_monthly": { "net": "1.0000000000", - "gross": "1.1900000000000000" - } + "gross": "1.1900000000000000", + }, } - ] - }, - "protection": { - "delete": False + ], }, + "protection": {"delete": False}, "labels": {}, "created": "2016-01-30T23:50:00+00:00", "outgoing_traffic": 123456, @@ -59,11 +57,9 @@ def response_load_balancer(): "http": { "cookie_name": "HCLBSTICKY", "cookie_lifetime": 300, - "certificates": [ - 897 - ], + "certificates": [897], "redirect_http": True, - "sticky_sessions": True + "sticky_sessions": True, }, "health_check": { "protocol": "http", @@ -74,34 +70,23 @@ def response_load_balancer(): "http": { "domain": "example.com", "path": "/", - "response": "{\"status\": \"ok\"}", - "status_codes": [ - 200 - ], - "tls": False - } - } + "response": '{"status": "ok"}', + "status_codes": [200], + "tls": False, + }, + }, } ], "targets": [ { "type": "server", - "server": { - "id": 80 - }, - "health_status": [ - { - "listen_port": 443, - "status": "healthy" - } - ], + "server": {"id": 80}, + "health_status": [{"listen_port": 443, "status": "healthy"}], "label_selector": None, - "use_private_ip": False + "use_private_ip": False, } ], - "algorithm": { - "type": "round_robin" - } + "algorithm": {"type": "round_robin"}, } } @@ -126,19 +111,17 @@ def response_create_load_balancer(): "location": "fsn-1", "price_hourly": { "net": "1.0000000000", - "gross": "1.1900000000000000" + "gross": "1.1900000000000000", }, "price_monthly": { "net": "1.0000000000", - "gross": "1.1900000000000000" - } + "gross": "1.1900000000000000", + }, } - ] + ], }, "network_zone": "eu-central", - "algorithm": { - "type": "round_robin" - }, + "algorithm": {"type": "round_robin"}, "outgoing_traffic": 123456, "ingoing_traffic": 123456, "included_traffic": 654321, @@ -151,11 +134,9 @@ def response_create_load_balancer(): "http": { "cookie_name": "HCLBSTICKY", "cookie_lifetime": 300, - "certificates": [ - 897 - ], + "certificates": [897], "redirect_http": True, - "sticky_sessions": True + "sticky_sessions": True, }, "health_check": { "protocol": "http", @@ -166,25 +147,21 @@ def response_create_load_balancer(): "http": { "domain": "example.com", "path": "/", - "response": "{\"status\": \"ok\"}", - "status_codes": [ - 200 - ], - "tls": False - } - } + "response": '{"status": "ok"}', + "status_codes": [200], + "tls": False, + }, + }, } ], "targets": [ { "type": "server", - "server": { - "id": 80 - }, + "server": {"id": 80}, "label_selector": None, - "use_private_ip": False + "use_private_ip": False, } - ] + ], }, "action": { "id": 1, @@ -193,16 +170,8 @@ def response_create_load_balancer(): "progress": 0, "started": "2016-01-30T23:50+00:00", "finished": None, - "resources": [ - { - "id": 42, - "type": "server" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 42, "type": "server"}], + "error": {"code": "action_failed", "message": "Action failed"}, }, } @@ -223,7 +192,7 @@ def response_update_load_balancer(): "city": "Falkenstein", "latitude": 50.47612, "longitude": 12.370071, - "network_zone": "eu-central" + "network_zone": "eu-central", }, "outgoing_traffic": 123456, "ingoing_traffic": 123456, @@ -242,21 +211,17 @@ def response_update_load_balancer(): "location": "fsn-1", "price_hourly": { "net": "1.0000000000", - "gross": "1.1900000000000000" + "gross": "1.1900000000000000", }, "price_monthly": { "net": "1.0000000000", - "gross": "1.1900000000000000" - } + "gross": "1.1900000000000000", + }, } - ] - }, - "protection": { - "delete": False - }, - "labels": { - "labelkey": "value" + ], }, + "protection": {"delete": False}, + "labels": {"labelkey": "value"}, "created": "2016-01-30T23:50:00+00:00", "services": [ { @@ -267,11 +232,9 @@ def response_update_load_balancer(): "http": { "cookie_name": "HCLBSTICKY", "cookie_lifetime": 300, - "certificates": [ - 897 - ], + "certificates": [897], "redirect_http": True, - "sticky_sessions": True + "sticky_sessions": True, }, "health_check": { "protocol": "http", @@ -282,34 +245,23 @@ def response_update_load_balancer(): "http": { "domain": "example.com", "path": "/", - "response": "{\"status\": \"ok\"}", - "status_codes": [ - 200 - ], - "tls": False - } - } + "response": '{"status": "ok"}', + "status_codes": [200], + "tls": False, + }, + }, } ], "targets": [ { "type": "server", - "server": { - "id": 80 - }, + "server": {"id": 80}, "use_private_ip": False, - "health_status": [ - { - "listen_port": 443, - "status": "healthy" - } - ], - "label_selector": None + "health_status": [{"listen_port": 443, "status": "healthy"}], + "label_selector": None, } ], - "algorithm": { - "type": "round_robin" - } + "algorithm": {"type": "round_robin"}, } } @@ -331,7 +283,7 @@ def response_simple_load_balancers(): "city": "Falkenstein", "latitude": 50.47612, "longitude": 12.370071, - "network_zone": "eu-central" + "network_zone": "eu-central", }, "outgoing_traffic": 123456, "ingoing_traffic": 123456, @@ -350,18 +302,16 @@ def response_simple_load_balancers(): "location": "fsn-1", "price_hourly": { "net": "1.0000000000", - "gross": "1.1900000000000000" + "gross": "1.1900000000000000", }, "price_monthly": { "net": "1.0000000000", - "gross": "1.1900000000000000" - } + "gross": "1.1900000000000000", + }, } - ] - }, - "protection": { - "delete": False + ], }, + "protection": {"delete": False}, "labels": {}, "created": "2016-01-30T23:50:00+00:00", "services": [ @@ -374,10 +324,8 @@ def response_simple_load_balancers(): "sticky_sessions": True, "cookie_name": "HCLBSTICKY", "cookie_lifetime": 300, - "certificates": [ - 897 - ], - "redirect_http": True + "certificates": [897], + "redirect_http": True, }, "health_check": { "protocol": "http", @@ -388,34 +336,23 @@ def response_simple_load_balancers(): "http": { "domain": "example.com", "path": "/", - "response": "{\"status\": \"ok\"}", - "status_codes": [ - 200 - ], - "tls": False - } - } + "response": '{"status": "ok"}', + "status_codes": [200], + "tls": False, + }, + }, } ], "targets": [ { "type": "server", - "server": { - "id": 80 - }, + "server": {"id": 80}, "use_private_ip": False, - "health_status": [ - { - "listen_port": 443, - "status": "healthy" - } - ], - "label_selector": None + "health_status": [{"listen_port": 443, "status": "healthy"}], + "label_selector": None, } ], - "algorithm": { - "type": "round_robin" - } + "algorithm": {"type": "round_robin"}, }, { "id": 4712, @@ -430,7 +367,7 @@ def response_simple_load_balancers(): "city": "Falkenstein", "latitude": 50.47612, "longitude": 12.370071, - "network_zone": "eu-central" + "network_zone": "eu-central", }, "load_balancer_type": { "id": 1, @@ -446,18 +383,16 @@ def response_simple_load_balancers(): "location": "fsn-1", "price_hourly": { "net": "1.0000000000", - "gross": "1.1900000000000000" + "gross": "1.1900000000000000", }, "price_monthly": { "net": "1.0000000000", - "gross": "1.1900000000000000" - } + "gross": "1.1900000000000000", + }, } - ] - }, - "protection": { - "delete": False + ], }, + "protection": {"delete": False}, "labels": {}, "created": "2016-01-30T23:50:00+00:00", "outgoing_traffic": 123456, @@ -473,10 +408,8 @@ def response_simple_load_balancers(): "sticky_sessions": True, "cookie_name": "HCLBSTICKY", "cookie_lifetime": 300, - "certificates": [ - 897 - ], - "redirect_http": True + "certificates": [897], + "redirect_http": True, }, "health_check": { "protocol": "http", @@ -487,35 +420,24 @@ def response_simple_load_balancers(): "http": { "domain": "example.com", "path": "/", - "response": "{\"status\": \"ok\"}", - "status_codes": [ - 200 - ], - "tls": False - } - } + "response": '{"status": "ok"}', + "status_codes": [200], + "tls": False, + }, + }, } ], "targets": [ { "type": "server", - "server": { - "id": 80 - }, - "health_status": [ - { - "listen_port": 443, - "status": "healthy" - } - ], + "server": {"id": 80}, + "health_status": [{"listen_port": 443, "status": "healthy"}], "label_selector": None, - "use_private_ip": False + "use_private_ip": False, } ], - "algorithm": { - "type": "round_robin" - } - } + "algorithm": {"type": "round_robin"}, + }, ] } @@ -530,16 +452,8 @@ def response_add_service(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 4711, - "type": "load_balancer" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 4711, "type": "load_balancer"}], + "error": {"code": "action_failed", "message": "Action failed"}, } } @@ -554,16 +468,8 @@ def response_delete_service(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 4711, - "type": "load_balancer" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 4711, "type": "load_balancer"}], + "error": {"code": "action_failed", "message": "Action failed"}, } } @@ -578,16 +484,8 @@ def response_add_target(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 4711, - "type": "load_balancer" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 4711, "type": "load_balancer"}], + "error": {"code": "action_failed", "message": "Action failed"}, } } @@ -602,16 +500,8 @@ def response_remove_target(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 4711, - "type": "load_balancer" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 4711, "type": "load_balancer"}], + "error": {"code": "action_failed", "message": "Action failed"}, } } @@ -626,16 +516,8 @@ def response_update_service(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 4711, - "type": "load_balancer" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 4711, "type": "load_balancer"}], + "error": {"code": "action_failed", "message": "Action failed"}, } } @@ -650,16 +532,8 @@ def response_change_algorithm(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 4711, - "type": "load_balancer" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 4711, "type": "load_balancer"}], + "error": {"code": "action_failed", "message": "Action failed"}, } } @@ -674,16 +548,8 @@ def response_change_protection(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 4711, - "type": "load_balancer" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 4711, "type": "load_balancer"}], + "error": {"code": "action_failed", "message": "Action failed"}, } } @@ -698,16 +564,8 @@ def response_enable_public_interface(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 4711, - "type": "load_balancer" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 4711, "type": "load_balancer"}], + "error": {"code": "action_failed", "message": "Action failed"}, } } @@ -722,16 +580,8 @@ def response_disable_public_interface(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 4711, - "type": "load_balancer" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 4711, "type": "load_balancer"}], + "error": {"code": "action_failed", "message": "Action failed"}, } } @@ -746,16 +596,8 @@ def response_attach_load_balancer_to_network(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 4711, - "type": "load_balancer" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 4711, "type": "load_balancer"}], + "error": {"code": "action_failed", "message": "Action failed"}, } } @@ -770,16 +612,8 @@ def response_detach_from_network(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 4711, - "type": "load_balancer" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 4711, "type": "load_balancer"}], + "error": {"code": "action_failed", "message": "Action failed"}, } } @@ -795,16 +629,8 @@ def response_get_actions(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 14, - "type": "load_balancer" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 14, "type": "load_balancer"}], + "error": {"code": "action_failed", "message": "Action failed"}, } ] } diff --git a/tests/unit/load_balancers/test_client.py b/tests/unit/load_balancers/test_client.py index 334bcc3..c38eb01 100644 --- a/tests/unit/load_balancers/test_client.py +++ b/tests/unit/load_balancers/test_client.py @@ -8,8 +8,15 @@ from hcloud.load_balancers.client import BoundLoadBalancer, LoadBalancersClient -from hcloud.load_balancers.domain import LoadBalancerAlgorithm, LoadBalancerHealthCheck, \ - LoadBalancerService, LoadBalancerTarget, LoadBalancer, LoadBalancerTargetIP, LoadBalancerTargetLabelSelector +from hcloud.load_balancers.domain import ( + LoadBalancerAlgorithm, + LoadBalancerHealthCheck, + LoadBalancerService, + LoadBalancerTarget, + LoadBalancer, + LoadBalancerTargetIP, + LoadBalancerTargetLabelSelector, +) from hcloud.actions.client import BoundAction @@ -20,27 +27,21 @@ def bound_load_balancer(self, hetzner_client): def test_bound_load_balancer_init(self, response_load_balancer): bound_load_balancer = BoundLoadBalancer( - client=mock.MagicMock(), - data=response_load_balancer['load_balancer'] + client=mock.MagicMock(), data=response_load_balancer["load_balancer"] ) assert bound_load_balancer.id == 4711 - assert bound_load_balancer.name == 'Web Frontend' - - @pytest.mark.parametrize( - "params", - [ - { - "page": 1, - "per_page": 10}, - {} + assert bound_load_balancer.name == "Web Frontend" - ] - ) - def test_get_actions_list(self, hetzner_client, bound_load_balancer, response_get_actions, params): + @pytest.mark.parametrize("params", [{"page": 1, "per_page": 10}, {}]) + def test_get_actions_list( + self, hetzner_client, bound_load_balancer, response_get_actions, params + ): hetzner_client.request.return_value = response_get_actions result = bound_load_balancer.get_actions_list(**params) - hetzner_client.request.assert_called_with(url="/load_balancers/14/actions", method="GET", params=params) + hetzner_client.request.assert_called_with( + url="/load_balancers/14/actions", method="GET", params=params + ) actions = result.actions assert result.meta is None @@ -50,30 +51,34 @@ def test_get_actions_list(self, hetzner_client, bound_load_balancer, response_ge assert actions[0].id == 13 assert actions[0].command == "change_protection" - @pytest.mark.parametrize( - "params", - [ - {} - ] - ) - def test_get_actions(self, hetzner_client, bound_load_balancer, response_get_actions, params): + @pytest.mark.parametrize("params", [{}]) + def test_get_actions( + self, hetzner_client, bound_load_balancer, response_get_actions, params + ): hetzner_client.request.return_value = response_get_actions actions = bound_load_balancer.get_actions(**params) - params.update({'page': 1, 'per_page': 50}) + params.update({"page": 1, "per_page": 50}) - hetzner_client.request.assert_called_with(url="/load_balancers/14/actions", method="GET", params=params) + hetzner_client.request.assert_called_with( + url="/load_balancers/14/actions", method="GET", params=params + ) assert len(actions) == 1 assert isinstance(actions[0], BoundAction) assert actions[0].id == 13 assert actions[0].command == "change_protection" - def test_update(self, hetzner_client, bound_load_balancer, response_update_load_balancer): + def test_update( + self, hetzner_client, bound_load_balancer, response_update_load_balancer + ): hetzner_client.request.return_value = response_update_load_balancer load_balancer = bound_load_balancer.update(name="new-name", labels={}) - hetzner_client.request.assert_called_with(url="/load_balancers/14", method="PUT", - json={"name": "new-name", "labels": {}}) + hetzner_client.request.assert_called_with( + url="/load_balancers/14", + method="PUT", + json={"name": "new-name", "labels": {}}, + ) assert load_balancer.id == 4711 assert load_balancer.name == "new-name" @@ -81,136 +86,235 @@ def test_update(self, hetzner_client, bound_load_balancer, response_update_load_ def test_delete(self, hetzner_client, generic_action, bound_load_balancer): hetzner_client.request.return_value = generic_action delete_success = bound_load_balancer.delete() - hetzner_client.request.assert_called_with(url="/load_balancers/14", method="DELETE") + hetzner_client.request.assert_called_with( + url="/load_balancers/14", method="DELETE" + ) assert delete_success is True - def test_add_service(self, hetzner_client, response_add_service, bound_load_balancer): + def test_add_service( + self, hetzner_client, response_add_service, bound_load_balancer + ): hetzner_client.request.return_value = response_add_service service = LoadBalancerService(listen_port=80, protocol="http") action = bound_load_balancer.add_service(service) hetzner_client.request.assert_called_with( - json={'protocol': 'http', 'listen_port': 80}, - url="/load_balancers/14/actions/add_service", method="POST") + json={"protocol": "http", "listen_port": 80}, + url="/load_balancers/14/actions/add_service", + method="POST", + ) assert action.id == 13 assert action.progress == 100 assert action.command == "add_service" - def test_delete_service(self, hetzner_client, response_delete_service, bound_load_balancer): + def test_delete_service( + self, hetzner_client, response_delete_service, bound_load_balancer + ): hetzner_client.request.return_value = response_delete_service service = LoadBalancerService(listen_port=12) action = bound_load_balancer.delete_service(service) - hetzner_client.request.assert_called_with(json={'listen_port': 12}, - url="/load_balancers/14/actions/delete_service", method="POST") + hetzner_client.request.assert_called_with( + json={"listen_port": 12}, + url="/load_balancers/14/actions/delete_service", + method="POST", + ) assert action.id == 13 assert action.progress == 100 assert action.command == "delete_service" - @pytest.mark.parametrize("target,params", [ - (LoadBalancerTarget(type="server", server=Server(id=1), use_private_ip=True), {'server': {"id": 1}}), - (LoadBalancerTarget(type="ip", ip=LoadBalancerTargetIP(ip="127.0.0.1")), {'ip': {"ip": "127.0.0.1"}}), - (LoadBalancerTarget(type="label_selector", label_selector=LoadBalancerTargetLabelSelector(selector="abc=def")), {'label_selector': {"selector": "abc=def"}}) - ]) - def test_add_target(self, hetzner_client, response_add_target, bound_load_balancer, target, params): + @pytest.mark.parametrize( + "target,params", + [ + ( + LoadBalancerTarget( + type="server", server=Server(id=1), use_private_ip=True + ), + {"server": {"id": 1}}, + ), + ( + LoadBalancerTarget(type="ip", ip=LoadBalancerTargetIP(ip="127.0.0.1")), + {"ip": {"ip": "127.0.0.1"}}, + ), + ( + LoadBalancerTarget( + type="label_selector", + label_selector=LoadBalancerTargetLabelSelector(selector="abc=def"), + ), + {"label_selector": {"selector": "abc=def"}}, + ), + ], + ) + def test_add_target( + self, hetzner_client, response_add_target, bound_load_balancer, target, params + ): hetzner_client.request.return_value = response_add_target action = bound_load_balancer.add_target(target) - params.update({'type': target.type, 'use_private_ip': target.use_private_ip}) - hetzner_client.request.assert_called_with(json=params, - url="/load_balancers/14/actions/add_target", method="POST") + params.update({"type": target.type, "use_private_ip": target.use_private_ip}) + hetzner_client.request.assert_called_with( + json=params, url="/load_balancers/14/actions/add_target", method="POST" + ) assert action.id == 13 assert action.progress == 100 assert action.command == "add_target" - @pytest.mark.parametrize("target,params", [ - (LoadBalancerTarget(type="server", server=Server(id=1), use_private_ip=True), {'server': {"id": 1}}), - (LoadBalancerTarget(type="ip", ip=LoadBalancerTargetIP(ip="127.0.0.1")), {'ip': {"ip": "127.0.0.1"}}), - (LoadBalancerTarget(type="label_selector", label_selector=LoadBalancerTargetLabelSelector(selector="abc=def")), {'label_selector': {"selector": "abc=def"}}) - ]) - def test_remove_target(self, hetzner_client, response_remove_target, bound_load_balancer, target, params): + @pytest.mark.parametrize( + "target,params", + [ + ( + LoadBalancerTarget( + type="server", server=Server(id=1), use_private_ip=True + ), + {"server": {"id": 1}}, + ), + ( + LoadBalancerTarget(type="ip", ip=LoadBalancerTargetIP(ip="127.0.0.1")), + {"ip": {"ip": "127.0.0.1"}}, + ), + ( + LoadBalancerTarget( + type="label_selector", + label_selector=LoadBalancerTargetLabelSelector(selector="abc=def"), + ), + {"label_selector": {"selector": "abc=def"}}, + ), + ], + ) + def test_remove_target( + self, + hetzner_client, + response_remove_target, + bound_load_balancer, + target, + params, + ): hetzner_client.request.return_value = response_remove_target action = bound_load_balancer.remove_target(target) - params.update({'type': target.type}) - hetzner_client.request.assert_called_with(json=params, - url="/load_balancers/14/actions/remove_target", method="POST") + params.update({"type": target.type}) + hetzner_client.request.assert_called_with( + json=params, url="/load_balancers/14/actions/remove_target", method="POST" + ) assert action.id == 13 assert action.progress == 100 assert action.command == "remove_target" - def test_update_service(self, hetzner_client, response_update_service, bound_load_balancer): + def test_update_service( + self, hetzner_client, response_update_service, bound_load_balancer + ): hetzner_client.request.return_value = response_update_service - new_health_check = LoadBalancerHealthCheck(protocol='http', port=13, interval=1, timeout=1, retries=1) + new_health_check = LoadBalancerHealthCheck( + protocol="http", port=13, interval=1, timeout=1, retries=1 + ) service = LoadBalancerService(listen_port=12, health_check=new_health_check) action = bound_load_balancer.update_service(service) - hetzner_client.request.assert_called_with(json={'listen_port': 12, - 'health_check': {'protocol': 'http', 'port': 13, 'interval': 1, - 'timeout': 1, 'retries': 1}}, - url="/load_balancers/14/actions/update_service", method="POST") + hetzner_client.request.assert_called_with( + json={ + "listen_port": 12, + "health_check": { + "protocol": "http", + "port": 13, + "interval": 1, + "timeout": 1, + "retries": 1, + }, + }, + url="/load_balancers/14/actions/update_service", + method="POST", + ) assert action.id == 13 assert action.progress == 100 assert action.command == "update_service" - def test_change_algorithm(self, hetzner_client, response_change_algorithm, bound_load_balancer): + def test_change_algorithm( + self, hetzner_client, response_change_algorithm, bound_load_balancer + ): hetzner_client.request.return_value = response_change_algorithm algorithm = LoadBalancerAlgorithm(type="round_robin") action = bound_load_balancer.change_algorithm(algorithm) - hetzner_client.request.assert_called_with(json={'type': 'round_robin'}, - url="/load_balancers/14/actions/change_algorithm", method="POST") + hetzner_client.request.assert_called_with( + json={"type": "round_robin"}, + url="/load_balancers/14/actions/change_algorithm", + method="POST", + ) assert action.id == 13 assert action.progress == 100 assert action.command == "change_algorithm" - def test_change_protection(self, hetzner_client, response_change_protection, bound_load_balancer): + def test_change_protection( + self, hetzner_client, response_change_protection, bound_load_balancer + ): hetzner_client.request.return_value = response_change_protection action = bound_load_balancer.change_protection(delete=True) - hetzner_client.request.assert_called_with(json={'delete': True}, - url="/load_balancers/14/actions/change_protection", method="POST") + hetzner_client.request.assert_called_with( + json={"delete": True}, + url="/load_balancers/14/actions/change_protection", + method="POST", + ) assert action.id == 13 assert action.progress == 100 assert action.command == "change_protection" - def test_enable_public_interface(self, response_enable_public_interface, hetzner_client, bound_load_balancer): + def test_enable_public_interface( + self, response_enable_public_interface, hetzner_client, bound_load_balancer + ): hetzner_client.request.return_value = response_enable_public_interface action = bound_load_balancer.enable_public_interface() hetzner_client.request.assert_called_with( - url="/load_balancers/14/actions/enable_public_interface", method="POST") + url="/load_balancers/14/actions/enable_public_interface", method="POST" + ) assert action.id == 13 assert action.progress == 100 assert action.command == "enable_public_interface" - def test_disable_public_interface(self, response_disable_public_interface, hetzner_client, bound_load_balancer): + def test_disable_public_interface( + self, response_disable_public_interface, hetzner_client, bound_load_balancer + ): hetzner_client.request.return_value = response_disable_public_interface action = bound_load_balancer.disable_public_interface() hetzner_client.request.assert_called_with( - url="/load_balancers/14/actions/disable_public_interface", method="POST") + url="/load_balancers/14/actions/disable_public_interface", method="POST" + ) assert action.id == 13 assert action.progress == 100 assert action.command == "disable_public_interface" - def test_attach_to_network(self, response_attach_load_balancer_to_network, hetzner_client, bound_load_balancer): + def test_attach_to_network( + self, + response_attach_load_balancer_to_network, + hetzner_client, + bound_load_balancer, + ): hetzner_client.request.return_value = response_attach_load_balancer_to_network action = bound_load_balancer.attach_to_network(Network(id=1)) - hetzner_client.request.assert_called_with(json={"network": 1}, - url="/load_balancers/14/actions/attach_to_network", method="POST") + hetzner_client.request.assert_called_with( + json={"network": 1}, + url="/load_balancers/14/actions/attach_to_network", + method="POST", + ) assert action.id == 13 assert action.progress == 100 assert action.command == "attach_to_network" - def test_detach_from_network(self, response_detach_from_network, hetzner_client, bound_load_balancer): + def test_detach_from_network( + self, response_detach_from_network, hetzner_client, bound_load_balancer + ): hetzner_client.request.return_value = response_detach_from_network action = bound_load_balancer.detach_from_network(Network(id=1)) - hetzner_client.request.assert_called_with(json={"network": 1}, - url="/load_balancers/14/actions/detach_from_network", method="POST") + hetzner_client.request.assert_called_with( + json={"network": 1}, + url="/load_balancers/14/actions/detach_from_network", + method="POST", + ) assert action.id == 13 assert action.progress == 100 @@ -219,14 +323,17 @@ def test_detach_from_network(self, response_detach_from_network, hetzner_client, def test_change_type(self, hetzner_client, bound_load_balancer, generic_action): hetzner_client.request.return_value = generic_action action = bound_load_balancer.change_type(LoadBalancerType(name="lb21")) - hetzner_client.request.assert_called_with(url="/load_balancers/14/actions/change_type", method="POST", json={"load_balancer_type": "lb21"}) + hetzner_client.request.assert_called_with( + url="/load_balancers/14/actions/change_type", + method="POST", + json={"load_balancer_type": "lb21"}, + ) assert action.id == 1 assert action.progress == 0 class TestLoadBalancerslient(object): - @pytest.fixture() def load_balancers_client(self): return LoadBalancersClient(client=mock.MagicMock()) @@ -234,7 +341,9 @@ def load_balancers_client(self): def test_get_by_id(self, load_balancers_client, response_load_balancer): load_balancers_client._client.request.return_value = response_load_balancer bound_load_balancer = load_balancers_client.get_by_id(1) - load_balancers_client._client.request.assert_called_with(url="/load_balancers/1", method="GET") + load_balancers_client._client.request.assert_called_with( + url="/load_balancers/1", method="GET" + ) assert bound_load_balancer._client is load_balancers_client assert bound_load_balancer.id == 4711 assert bound_load_balancer.name == "Web Frontend" @@ -245,15 +354,26 @@ def test_get_by_id(self, load_balancers_client, response_load_balancer): @pytest.mark.parametrize( "params", [ - {'name': "load_balancer1", 'label_selector': "label1", 'page': 1, 'per_page': 10}, - {'name': ""}, - {} - ] + { + "name": "load_balancer1", + "label_selector": "label1", + "page": 1, + "per_page": 10, + }, + {"name": ""}, + {}, + ], ) - def test_get_list(self, load_balancers_client, response_simple_load_balancers, params): - load_balancers_client._client.request.return_value = response_simple_load_balancers + def test_get_list( + self, load_balancers_client, response_simple_load_balancers, params + ): + load_balancers_client._client.request.return_value = ( + response_simple_load_balancers + ) result = load_balancers_client.get_list(**params) - load_balancers_client._client.request.assert_called_with(url="/load_balancers", method="GET", params=params) + load_balancers_client._client.request.assert_called_with( + url="/load_balancers", method="GET", params=params + ) bound_load_balancers = result.load_balancers assert result.meta is None @@ -272,19 +392,21 @@ def test_get_list(self, load_balancers_client, response_simple_load_balancers, p assert bound_load_balancer2.name == "Web Frontend2" @pytest.mark.parametrize( - "params", - [ - {'name': "loadbalancer1", 'label_selector': "label1"}, - {} - ] + "params", [{"name": "loadbalancer1", "label_selector": "label1"}, {}] ) - def test_get_all(self, load_balancers_client, response_simple_load_balancers, params): - load_balancers_client._client.request.return_value = response_simple_load_balancers + def test_get_all( + self, load_balancers_client, response_simple_load_balancers, params + ): + load_balancers_client._client.request.return_value = ( + response_simple_load_balancers + ) bound_load_balancers = load_balancers_client.get_all(**params) - params.update({'page': 1, 'per_page': 50}) + params.update({"page": 1, "per_page": 50}) - load_balancers_client._client.request.assert_called_with(url="/load_balancers", method="GET", params=params) + load_balancers_client._client.request.assert_called_with( + url="/load_balancers", method="GET", params=params + ) assert len(bound_load_balancers) == 2 @@ -300,32 +422,34 @@ def test_get_all(self, load_balancers_client, response_simple_load_balancers, pa assert bound_load_balancer2.name == "Web Frontend2" def test_get_by_name(self, load_balancers_client, response_simple_load_balancers): - load_balancers_client._client.request.return_value = response_simple_load_balancers + load_balancers_client._client.request.return_value = ( + response_simple_load_balancers + ) bound_load_balancer = load_balancers_client.get_by_name("Web Frontend") - params = {'name': "Web Frontend"} + params = {"name": "Web Frontend"} - load_balancers_client._client.request.assert_called_with(url="/load_balancers", method="GET", params=params) + load_balancers_client._client.request.assert_called_with( + url="/load_balancers", method="GET", params=params + ) assert bound_load_balancer._client is load_balancers_client assert bound_load_balancer.id == 4711 assert bound_load_balancer.name == "Web Frontend" def test_create(self, load_balancers_client, response_create_load_balancer): - load_balancers_client._client.request.return_value = response_create_load_balancer + load_balancers_client._client.request.return_value = ( + response_create_load_balancer + ) response = load_balancers_client.create( "my-balancer", load_balancer_type=LoadBalancerType(name="lb11"), - location=Location(id=1) + location=Location(id=1), ) load_balancers_client._client.request.assert_called_with( url="/load_balancers", method="POST", - json={ - 'name': "my-balancer", - 'load_balancer_type': "lb11", - 'location': 1 - } + json={"name": "my-balancer", "load_balancer_type": "lb11", "location": 1}, ) bound_load_balancer = response.load_balancer @@ -334,20 +458,42 @@ def test_create(self, load_balancers_client, response_create_load_balancer): assert bound_load_balancer.id == 1 assert bound_load_balancer.name == "my-balancer" - @pytest.mark.parametrize("load_balancer", [LoadBalancer(id=1), BoundLoadBalancer(mock.MagicMock(), dict(id=1))]) - def test_change_type_with_load_balancer_type_name(self, load_balancers_client, load_balancer, generic_action): + @pytest.mark.parametrize( + "load_balancer", + [LoadBalancer(id=1), BoundLoadBalancer(mock.MagicMock(), dict(id=1))], + ) + def test_change_type_with_load_balancer_type_name( + self, load_balancers_client, load_balancer, generic_action + ): load_balancers_client._client.request.return_value = generic_action - action = load_balancers_client.change_type(load_balancer, LoadBalancerType(name="lb11")) - load_balancers_client._client.request.assert_called_with(url="/load_balancers/1/actions/change_type", method="POST", json={"load_balancer_type": "lb11"}) + action = load_balancers_client.change_type( + load_balancer, LoadBalancerType(name="lb11") + ) + load_balancers_client._client.request.assert_called_with( + url="/load_balancers/1/actions/change_type", + method="POST", + json={"load_balancer_type": "lb11"}, + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("load_balancer", [LoadBalancer(id=1), BoundLoadBalancer(mock.MagicMock(), dict(id=1))]) - def test_change_type_with_load_balancer_type_id(self, load_balancers_client, load_balancer, generic_action): + @pytest.mark.parametrize( + "load_balancer", + [LoadBalancer(id=1), BoundLoadBalancer(mock.MagicMock(), dict(id=1))], + ) + def test_change_type_with_load_balancer_type_id( + self, load_balancers_client, load_balancer, generic_action + ): load_balancers_client._client.request.return_value = generic_action - action = load_balancers_client.change_type(load_balancer, LoadBalancerType(id=1)) - load_balancers_client._client.request.assert_called_with(url="/load_balancers/1/actions/change_type", method="POST", json={"load_balancer_type": 1}) + action = load_balancers_client.change_type( + load_balancer, LoadBalancerType(id=1) + ) + load_balancers_client._client.request.assert_called_with( + url="/load_balancers/1/actions/change_type", + method="POST", + json={"load_balancer_type": 1}, + ) assert action.id == 1 assert action.progress == 0 diff --git a/tests/unit/load_balancers/test_domain.py b/tests/unit/load_balancers/test_domain.py index fffe088..ecd0ecd 100644 --- a/tests/unit/load_balancers/test_domain.py +++ b/tests/unit/load_balancers/test_domain.py @@ -5,7 +5,8 @@ class TestLoadBalancers(object): - def test_created_is_datetime(self): lb = LoadBalancer(id=1, created="2016-01-30T23:50+00:00") - assert lb.created == datetime.datetime(2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0)) + assert lb.created == datetime.datetime( + 2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0) + ) diff --git a/tests/unit/locations/conftest.py b/tests/unit/locations/conftest.py index 74d9405..1ed03ea 100644 --- a/tests/unit/locations/conftest.py +++ b/tests/unit/locations/conftest.py @@ -22,7 +22,6 @@ def two_locations_response(): return { "locations": [ { - "id": 1, "name": "fsn1", "description": "Falkenstein DC Park 1", @@ -31,7 +30,6 @@ def two_locations_response(): "latitude": 50.47612, "longitude": 12.370071, "network_zone": "eu-central", - }, { "id": 2, @@ -42,7 +40,7 @@ def two_locations_response(): "latitude": 49.452102, "longitude": 11.076665, "network_zone": "eu-central", - } + }, ] } @@ -52,7 +50,6 @@ def one_locations_response(): return { "locations": [ { - "id": 1, "name": "fsn1", "description": "Falkenstein DC Park 1", diff --git a/tests/unit/locations/test_client.py b/tests/unit/locations/test_client.py index c34e207..8b4d5ab 100644 --- a/tests/unit/locations/test_client.py +++ b/tests/unit/locations/test_client.py @@ -5,7 +5,6 @@ class TestLocationsClient(object): - @pytest.fixture() def locations_client(self): return LocationsClient(client=mock.MagicMock()) @@ -13,17 +12,23 @@ def locations_client(self): def test_get_by_id(self, locations_client, location_response): locations_client._client.request.return_value = location_response location = locations_client.get_by_id(1) - locations_client._client.request.assert_called_with(url="/locations/1", method="GET") + locations_client._client.request.assert_called_with( + url="/locations/1", method="GET" + ) assert location._client is locations_client assert location.id == 1 assert location.name == "fsn1" assert location.network_zone == "eu-central" - @pytest.mark.parametrize("params", [{'name': "fsn1", "page": 1, "per_page": 10}, {'name': ""}, {}]) + @pytest.mark.parametrize( + "params", [{"name": "fsn1", "page": 1, "per_page": 10}, {"name": ""}, {}] + ) def test_get_list(self, locations_client, two_locations_response, params): locations_client._client.request.return_value = two_locations_response result = locations_client.get_list(**params) - locations_client._client.request.assert_called_with(url="/locations", method="GET", params=params) + locations_client._client.request.assert_called_with( + url="/locations", method="GET", params=params + ) locations = result.locations assert result.meta is None @@ -43,14 +48,16 @@ def test_get_list(self, locations_client, two_locations_response, params): assert location2.name == "nbg1" assert location2.network_zone == "eu-central" - @pytest.mark.parametrize("params", [{'name': "fsn1"}, {}]) + @pytest.mark.parametrize("params", [{"name": "fsn1"}, {}]) def test_get_all(self, locations_client, two_locations_response, params): locations_client._client.request.return_value = two_locations_response locations = locations_client.get_all(**params) - params.update({'page': 1, 'per_page': 50}) + params.update({"page": 1, "per_page": 50}) - locations_client._client.request.assert_called_with(url="/locations", method="GET", params=params) + locations_client._client.request.assert_called_with( + url="/locations", method="GET", params=params + ) assert len(locations) == 2 @@ -71,9 +78,11 @@ def test_get_by_name(self, locations_client, one_locations_response): locations_client._client.request.return_value = one_locations_response location = locations_client.get_by_name("fsn1") - params = {'name': "fsn1"} + params = {"name": "fsn1"} - locations_client._client.request.assert_called_with(url="/locations", method="GET", params=params) + locations_client._client.request.assert_called_with( + url="/locations", method="GET", params=params + ) assert location._client is locations_client assert location.id == 1 diff --git a/tests/unit/networks/conftest.py b/tests/unit/networks/conftest.py index e127e6f..109e3b5 100644 --- a/tests/unit/networks/conftest.py +++ b/tests/unit/networks/conftest.py @@ -14,28 +14,19 @@ def network_response(): "type": "cloud", "ip_range": "10.0.1.0/24", "network_zone": "eu-central", - "gateway": "10.0.0.1" + "gateway": "10.0.0.1", }, { "type": "vswitch", "ip_range": "10.0.3.0/24", "network_zone": "eu-central", - "gateway": "10.0.3.1" - } - ], - "routes": [ - { - "destination": "10.100.1.0/24", - "gateway": "10.0.1.1" - } - ], - "servers": [ - 42 + "gateway": "10.0.3.1", + }, ], - "protection": { - "delete": False - }, - "labels": {} + "routes": [{"destination": "10.100.1.0/24", "gateway": "10.0.1.1"}], + "servers": [42], + "protection": {"delete": False}, + "labels": {}, } } @@ -54,28 +45,19 @@ def two_networks_response(): "type": "cloud", "ip_range": "10.0.1.0/24", "network_zone": "eu-central", - "gateway": "10.0.0.1" + "gateway": "10.0.0.1", }, { "type": "vswitch", "ip_range": "10.0.3.0/24", "network_zone": "eu-central", - "gateway": "10.0.3.1" - } - ], - "routes": [ - { - "destination": "10.100.1.0/24", - "gateway": "10.0.1.1" - } - ], - "servers": [ - 42 + "gateway": "10.0.3.1", + }, ], - "protection": { - "delete": False - }, - "labels": {} + "routes": [{"destination": "10.100.1.0/24", "gateway": "10.0.1.1"}], + "servers": [42], + "protection": {"delete": False}, + "labels": {}, }, { "id": 2, @@ -87,23 +69,14 @@ def two_networks_response(): "type": "cloud", "ip_range": "12.0.1.0/24", "network_zone": "eu-central", - "gateway": "12.0.0.1" + "gateway": "12.0.0.1", } ], - "routes": [ - { - "destination": "12.100.1.0/24", - "gateway": "12.0.1.1" - } - ], - "servers": [ - 45 - ], - "protection": { - "delete": False - }, - "labels": {} - } + "routes": [{"destination": "12.100.1.0/24", "gateway": "12.0.1.1"}], + "servers": [45], + "protection": {"delete": False}, + "labels": {}, + }, ] } @@ -122,28 +95,19 @@ def one_network_response(): "type": "cloud", "ip_range": "10.0.1.0/24", "network_zone": "eu-central", - "gateway": "10.0.0.1" + "gateway": "10.0.0.1", }, { "type": "vswitch", "ip_range": "10.0.3.0/24", "network_zone": "eu-central", - "gateway": "10.0.3.1" - } - ], - "routes": [ - { - "destination": "10.100.1.0/24", - "gateway": "10.0.1.1" - } - ], - "servers": [ - 42 + "gateway": "10.0.3.1", + }, ], - "protection": { - "delete": False - }, - "labels": {} + "routes": [{"destination": "10.100.1.0/24", "gateway": "10.0.1.1"}], + "servers": [42], + "protection": {"delete": False}, + "labels": {}, } ] } @@ -161,23 +125,14 @@ def network_create_response(): "type": "cloud", "ip_range": "10.0.1.0/24", "network_zone": "eu-central", - "gateway": "10.0.0.1" + "gateway": "10.0.0.1", } ], - "routes": [ - { - "destination": "10.100.1.0/24", - "gateway": "10.0.1.1" - } - ], - "servers": [ - 42 - ], - "protection": { - "delete": False - }, + "routes": [{"destination": "10.100.1.0/24", "gateway": "10.0.1.1"}], + "servers": [42], + "protection": {"delete": False}, "labels": {}, - "created": "2016-01-30T23:50:00+00:00" + "created": "2016-01-30T23:50:00+00:00", } } @@ -194,23 +149,14 @@ def response_update_network(): "type": "cloud", "ip_range": "10.0.1.0/24", "network_zone": "eu-central", - "gateway": "10.0.0.1" + "gateway": "10.0.0.1", } ], - "routes": [ - { - "destination": "10.100.1.0/24", - "gateway": "10.0.1.1" - } - ], - "servers": [ - 42 - ], - "protection": { - "delete": False - }, + "routes": [{"destination": "10.100.1.0/24", "gateway": "10.0.1.1"}], + "servers": [42], + "protection": {"delete": False}, "labels": {}, - "created": "2016-01-30T23:50:00+00:00" + "created": "2016-01-30T23:50:00+00:00", } } @@ -226,16 +172,8 @@ def response_get_actions(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 4711, - "type": "network" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 4711, "type": "network"}], + "error": {"code": "action_failed", "message": "Action failed"}, } ] } diff --git a/tests/unit/networks/test_client.py b/tests/unit/networks/test_client.py index 615b0be..0324926 100644 --- a/tests/unit/networks/test_client.py +++ b/tests/unit/networks/test_client.py @@ -9,22 +9,20 @@ class TestBoundNetwork(object): - @pytest.fixture() def bound_network(self, hetzner_client): return BoundNetwork(client=hetzner_client.networks, data=dict(id=14)) def test_bound_network_init(self, network_response): bound_network = BoundNetwork( - client=mock.MagicMock(), - data=network_response['network'] + client=mock.MagicMock(), data=network_response["network"] ) assert bound_network.id == 1 assert bound_network.created == isoparse("2016-01-30T23:50:11+00:00") assert bound_network.name == "mynet" assert bound_network.ip_range == "10.0.0.0/16" - assert bound_network.protection['delete'] is False + assert bound_network.protection["delete"] is False assert len(bound_network.servers) == 1 assert isinstance(bound_network.servers[0], BoundServer) @@ -46,8 +44,11 @@ def test_bound_network_init(self, network_response): def test_get_actions(self, hetzner_client, bound_network, response_get_actions): hetzner_client.request.return_value = response_get_actions actions = bound_network.get_actions(sort="id") - hetzner_client.request.assert_called_with(url="/networks/14/actions", method="GET", - params={"page": 1, "per_page": 50, "sort": "id"}) + hetzner_client.request.assert_called_with( + url="/networks/14/actions", + method="GET", + params={"page": 1, "per_page": 50, "sort": "id"}, + ) assert len(actions) == 1 assert isinstance(actions[0], BoundAction) @@ -57,7 +58,9 @@ def test_get_actions(self, hetzner_client, bound_network, response_get_actions): def test_update(self, hetzner_client, bound_network, response_update_network): hetzner_client.request.return_value = response_update_network network = bound_network.update(name="new-name") - hetzner_client.request.assert_called_with(url="/networks/14", method="PUT", json={"name": "new-name"}) + hetzner_client.request.assert_called_with( + url="/networks/14", method="PUT", json={"name": "new-name"} + ) assert network.id == 4711 assert network.name == "new-name" @@ -72,19 +75,32 @@ def test_delete(self, hetzner_client, bound_network, generic_action): def test_change_protection(self, hetzner_client, bound_network, generic_action): hetzner_client.request.return_value = generic_action action = bound_network.change_protection(True) - hetzner_client.request.assert_called_with(url="/networks/14/actions/change_protection", method="POST", - json={"delete": True}) + hetzner_client.request.assert_called_with( + url="/networks/14/actions/change_protection", + method="POST", + json={"delete": True}, + ) assert action.id == 1 assert action.progress == 0 def test_add_subnet(self, hetzner_client, bound_network, generic_action): hetzner_client.request.return_value = generic_action - subnet = NetworkSubnet(type=NetworkSubnet.TYPE_CLOUD, ip_range="10.0.1.0/24", network_zone="eu-central") + subnet = NetworkSubnet( + type=NetworkSubnet.TYPE_CLOUD, + ip_range="10.0.1.0/24", + network_zone="eu-central", + ) action = bound_network.add_subnet(subnet) - hetzner_client.request.assert_called_with(url="/networks/14/actions/add_subnet", method="POST", - json={"type": NetworkSubnet.TYPE_CLOUD, "ip_range": "10.0.1.0/24", - "network_zone": "eu-central"}) + hetzner_client.request.assert_called_with( + url="/networks/14/actions/add_subnet", + method="POST", + json={ + "type": NetworkSubnet.TYPE_CLOUD, + "ip_range": "10.0.1.0/24", + "network_zone": "eu-central", + }, + ) assert action.id == 1 assert action.progress == 0 @@ -93,8 +109,11 @@ def test_delete_subnet(self, hetzner_client, bound_network, generic_action): hetzner_client.request.return_value = generic_action subnet = NetworkSubnet(ip_range="10.0.1.0/24") action = bound_network.delete_subnet(subnet) - hetzner_client.request.assert_called_with(url="/networks/14/actions/delete_subnet", method="POST", - json={"ip_range": "10.0.1.0/24"}) + hetzner_client.request.assert_called_with( + url="/networks/14/actions/delete_subnet", + method="POST", + json={"ip_range": "10.0.1.0/24"}, + ) assert action.id == 1 assert action.progress == 0 @@ -103,8 +122,11 @@ def test_add_route(self, hetzner_client, bound_network, generic_action): hetzner_client.request.return_value = generic_action route = NetworkRoute(destination="10.100.1.0/24", gateway="10.0.1.1") action = bound_network.add_route(route) - hetzner_client.request.assert_called_with(url="/networks/14/actions/add_route", method="POST", - json={"destination": "10.100.1.0/24", "gateway": "10.0.1.1"}) + hetzner_client.request.assert_called_with( + url="/networks/14/actions/add_route", + method="POST", + json={"destination": "10.100.1.0/24", "gateway": "10.0.1.1"}, + ) assert action.id == 1 assert action.progress == 0 @@ -113,8 +135,11 @@ def test_delete_route(self, hetzner_client, bound_network, generic_action): hetzner_client.request.return_value = generic_action route = NetworkRoute(destination="10.100.1.0/24", gateway="10.0.1.1") action = bound_network.delete_route(route) - hetzner_client.request.assert_called_with(url="/networks/14/actions/delete_route", method="POST", - json={"destination": "10.100.1.0/24", "gateway": "10.0.1.1"}) + hetzner_client.request.assert_called_with( + url="/networks/14/actions/delete_route", + method="POST", + json={"destination": "10.100.1.0/24", "gateway": "10.0.1.1"}, + ) assert action.id == 1 assert action.progress == 0 @@ -122,26 +147,37 @@ def test_delete_route(self, hetzner_client, bound_network, generic_action): def test_change_ip(self, hetzner_client, bound_network, generic_action): hetzner_client.request.return_value = generic_action action = bound_network.change_ip_range("10.0.0.0/12") - hetzner_client.request.assert_called_with(url="/networks/14/actions/change_ip_range", method="POST", - json={"ip_range": "10.0.0.0/12"}) + hetzner_client.request.assert_called_with( + url="/networks/14/actions/change_ip_range", + method="POST", + json={"ip_range": "10.0.0.0/12"}, + ) assert action.id == 1 assert action.progress == 0 class TestNetworksClient(object): - @pytest.fixture() def networks_client(self): return NetworksClient(client=mock.MagicMock()) @pytest.fixture() def network_subnet(self): - return NetworkSubnet(type=NetworkSubnet.TYPE_CLOUD, ip_range="10.0.1.0/24", network_zone="eu-central") + return NetworkSubnet( + type=NetworkSubnet.TYPE_CLOUD, + ip_range="10.0.1.0/24", + network_zone="eu-central", + ) @pytest.fixture() def network_vswitch_subnet(self): - return NetworkSubnet(type=NetworkSubnet.TYPE_VSWITCH, ip_range="10.0.1.0/24", network_zone="eu-central", vswitch_id=123) + return NetworkSubnet( + type=NetworkSubnet.TYPE_VSWITCH, + ip_range="10.0.1.0/24", + network_zone="eu-central", + vswitch_id=123, + ) @pytest.fixture() def network_route(self): @@ -150,23 +186,23 @@ def network_route(self): def test_get_by_id(self, networks_client, network_response): networks_client._client.request.return_value = network_response bound_network = networks_client.get_by_id(1) - networks_client._client.request.assert_called_with(url="/networks/1", method="GET") + networks_client._client.request.assert_called_with( + url="/networks/1", method="GET" + ) assert bound_network._client is networks_client assert bound_network.id == 1 assert bound_network.name == "mynet" @pytest.mark.parametrize( "params", - [ - {'label_selector': "label1", 'page': 1, 'per_page': 10}, - {'name': ""}, - {} - ] + [{"label_selector": "label1", "page": 1, "per_page": 10}, {"name": ""}, {}], ) def test_get_list(self, networks_client, two_networks_response, params): networks_client._client.request.return_value = two_networks_response result = networks_client.get_list(**params) - networks_client._client.request.assert_called_with(url="/networks", method="GET", params=params) + networks_client._client.request.assert_called_with( + url="/networks", method="GET", params=params + ) bound_networks = result.networks assert result.meta is None @@ -184,14 +220,16 @@ def test_get_list(self, networks_client, two_networks_response, params): assert bound_network2.id == 2 assert bound_network2.name == "myanothernet" - @pytest.mark.parametrize("params", [{'label_selector': "label1"}]) + @pytest.mark.parametrize("params", [{"label_selector": "label1"}]) def test_get_all(self, networks_client, two_networks_response, params): networks_client._client.request.return_value = two_networks_response bound_networks = networks_client.get_all(**params) - params.update({'page': 1, 'per_page': 50}) + params.update({"page": 1, "per_page": 50}) - networks_client._client.request.assert_called_with(url="/networks", method="GET", params=params) + networks_client._client.request.assert_called_with( + url="/networks", method="GET", params=params + ) assert len(bound_networks) == 2 @@ -210,9 +248,11 @@ def test_get_by_name(self, networks_client, one_network_response): networks_client._client.request.return_value = one_network_response bound_network = networks_client.get_by_name("mynet") - params = {'name': "mynet"} + params = {"name": "mynet"} - networks_client._client.request.assert_called_with(url="/networks", method="GET", params=params) + networks_client._client.request.assert_called_with( + url="/networks", method="GET", params=params + ) assert bound_network._client is networks_client assert bound_network.id == 1 @@ -220,101 +260,102 @@ def test_get_by_name(self, networks_client, one_network_response): def test_create(self, networks_client, network_create_response): networks_client._client.request.return_value = network_create_response - networks_client.create( - name="mynet", - ip_range="10.0.0.0/8" - ) + networks_client.create(name="mynet", ip_range="10.0.0.0/8") networks_client._client.request.assert_called_with( url="/networks", method="POST", json={ - 'name': "mynet", - 'ip_range': "10.0.0.0/8", - } + "name": "mynet", + "ip_range": "10.0.0.0/8", + }, ) - def test_create_with_subnet(self, networks_client, network_subnet, network_create_response): + def test_create_with_subnet( + self, networks_client, network_subnet, network_create_response + ): networks_client._client.request.return_value = network_create_response networks_client.create( - name="mynet", - ip_range="10.0.0.0/8", - subnets=[network_subnet] + name="mynet", ip_range="10.0.0.0/8", subnets=[network_subnet] ) networks_client._client.request.assert_called_with( url="/networks", method="POST", json={ - 'name': "mynet", - 'ip_range': "10.0.0.0/8", - 'subnets': [ + "name": "mynet", + "ip_range": "10.0.0.0/8", + "subnets": [ { - 'type': NetworkSubnet.TYPE_CLOUD, - 'ip_range': "10.0.1.0/24", - 'network_zone': "eu-central" + "type": NetworkSubnet.TYPE_CLOUD, + "ip_range": "10.0.1.0/24", + "network_zone": "eu-central", } - ] - } + ], + }, ) - def test_create_with_route(self, networks_client, network_route, network_create_response): + def test_create_with_route( + self, networks_client, network_route, network_create_response + ): networks_client._client.request.return_value = network_create_response networks_client.create( - name="mynet", - ip_range="10.0.0.0/8", - routes=[network_route] + name="mynet", ip_range="10.0.0.0/8", routes=[network_route] ) networks_client._client.request.assert_called_with( url="/networks", method="POST", json={ - 'name': "mynet", - 'ip_range': "10.0.0.0/8", - 'routes': [ + "name": "mynet", + "ip_range": "10.0.0.0/8", + "routes": [ { - 'destination': "10.100.1.0/24", - 'gateway': "10.0.1.1", + "destination": "10.100.1.0/24", + "gateway": "10.0.1.1", } - ] - } + ], + }, ) - def test_create_with_route_and_subnet(self, networks_client, network_subnet, network_route, - network_create_response): + def test_create_with_route_and_subnet( + self, networks_client, network_subnet, network_route, network_create_response + ): networks_client._client.request.return_value = network_create_response networks_client.create( name="mynet", ip_range="10.0.0.0/8", subnets=[network_subnet], - routes=[network_route] + routes=[network_route], ) networks_client._client.request.assert_called_with( url="/networks", method="POST", json={ - 'name': "mynet", - 'ip_range': "10.0.0.0/8", - 'subnets': [ + "name": "mynet", + "ip_range": "10.0.0.0/8", + "subnets": [ { - 'type': NetworkSubnet.TYPE_CLOUD, - 'ip_range': "10.0.1.0/24", - 'network_zone': "eu-central" + "type": NetworkSubnet.TYPE_CLOUD, + "ip_range": "10.0.1.0/24", + "network_zone": "eu-central", } ], - 'routes': [ + "routes": [ { - 'destination': "10.100.1.0/24", - 'gateway': "10.0.1.1", + "destination": "10.100.1.0/24", + "gateway": "10.0.1.1", } - ] - } + ], + }, ) - @pytest.mark.parametrize("network", [Network(id=1), BoundNetwork(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "network", [Network(id=1), BoundNetwork(mock.MagicMock(), dict(id=1))] + ) def test_get_actions_list(self, networks_client, network, response_get_actions): networks_client._client.request.return_value = response_get_actions result = networks_client.get_actions_list(network, sort="id") - networks_client._client.request.assert_called_with(url="/networks/1/actions", method="GET", - params={"sort": "id"}) + networks_client._client.request.assert_called_with( + url="/networks/1/actions", method="GET", params={"sort": "id"} + ) actions = result.actions assert len(actions) == 1 @@ -324,96 +365,152 @@ def test_get_actions_list(self, networks_client, network, response_get_actions): assert actions[0].id == 13 assert actions[0].command == "add_subnet" - @pytest.mark.parametrize("network", [Network(id=1), BoundNetwork(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "network", [Network(id=1), BoundNetwork(mock.MagicMock(), dict(id=1))] + ) def test_update(self, networks_client, network, response_update_network): networks_client._client.request.return_value = response_update_network network = networks_client.update(network, name="new-name") - networks_client._client.request.assert_called_with(url="/networks/1", method="PUT", json={"name": "new-name"}) + networks_client._client.request.assert_called_with( + url="/networks/1", method="PUT", json={"name": "new-name"} + ) assert network.id == 4711 assert network.name == "new-name" - @pytest.mark.parametrize("network", [Network(id=1), BoundNetwork(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "network", [Network(id=1), BoundNetwork(mock.MagicMock(), dict(id=1))] + ) def test_change_protection(self, networks_client, network, generic_action): networks_client._client.request.return_value = generic_action action = networks_client.change_protection(network, True) - networks_client._client.request.assert_called_with(url="/networks/1/actions/change_protection", method="POST", - json={"delete": True}) + networks_client._client.request.assert_called_with( + url="/networks/1/actions/change_protection", + method="POST", + json={"delete": True}, + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("network", [Network(id=1), BoundNetwork(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "network", [Network(id=1), BoundNetwork(mock.MagicMock(), dict(id=1))] + ) def test_delete(self, networks_client, network, generic_action): networks_client._client.request.return_value = generic_action delete_success = networks_client.delete(network) - networks_client._client.request.assert_called_with(url="/networks/1", method="DELETE") + networks_client._client.request.assert_called_with( + url="/networks/1", method="DELETE" + ) assert delete_success is True - @pytest.mark.parametrize("network", [Network(id=1), BoundNetwork(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "network", [Network(id=1), BoundNetwork(mock.MagicMock(), dict(id=1))] + ) def test_add_subnet(self, networks_client, network, generic_action, network_subnet): networks_client._client.request.return_value = generic_action action = networks_client.add_subnet(network, network_subnet) - networks_client._client.request.assert_called_with(url="/networks/1/actions/add_subnet", method="POST", - json={"type": NetworkSubnet.TYPE_CLOUD, "ip_range": "10.0.1.0/24", - "network_zone": "eu-central"}) + networks_client._client.request.assert_called_with( + url="/networks/1/actions/add_subnet", + method="POST", + json={ + "type": NetworkSubnet.TYPE_CLOUD, + "ip_range": "10.0.1.0/24", + "network_zone": "eu-central", + }, + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("network", [Network(id=1), BoundNetwork(mock.MagicMock(), dict(id=1))]) - def test_add_subnet_vswitch(self, networks_client, network, generic_action, network_vswitch_subnet): + @pytest.mark.parametrize( + "network", [Network(id=1), BoundNetwork(mock.MagicMock(), dict(id=1))] + ) + def test_add_subnet_vswitch( + self, networks_client, network, generic_action, network_vswitch_subnet + ): networks_client._client.request.return_value = generic_action action = networks_client.add_subnet(network, network_vswitch_subnet) - networks_client._client.request.assert_called_with(url="/networks/1/actions/add_subnet", method="POST", - json={"type": NetworkSubnet.TYPE_VSWITCH, "ip_range": "10.0.1.0/24", - "network_zone": "eu-central", "vswitch_id": 123}) + networks_client._client.request.assert_called_with( + url="/networks/1/actions/add_subnet", + method="POST", + json={ + "type": NetworkSubnet.TYPE_VSWITCH, + "ip_range": "10.0.1.0/24", + "network_zone": "eu-central", + "vswitch_id": 123, + }, + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("network", [Network(id=1), BoundNetwork(mock.MagicMock(), dict(id=1))]) - def test_delete_subnet(self, networks_client, network, generic_action, network_subnet): + @pytest.mark.parametrize( + "network", [Network(id=1), BoundNetwork(mock.MagicMock(), dict(id=1))] + ) + def test_delete_subnet( + self, networks_client, network, generic_action, network_subnet + ): networks_client._client.request.return_value = generic_action action = networks_client.delete_subnet(network, network_subnet) - networks_client._client.request.assert_called_with(url="/networks/1/actions/delete_subnet", method="POST", - json={"ip_range": "10.0.1.0/24"}) + networks_client._client.request.assert_called_with( + url="/networks/1/actions/delete_subnet", + method="POST", + json={"ip_range": "10.0.1.0/24"}, + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("network", [Network(id=1), BoundNetwork(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "network", [Network(id=1), BoundNetwork(mock.MagicMock(), dict(id=1))] + ) def test_add_route(self, networks_client, network, generic_action, network_route): networks_client._client.request.return_value = generic_action action = networks_client.add_route(network, network_route) - networks_client._client.request.assert_called_with(url="/networks/1/actions/add_route", method="POST", - json={"destination": "10.100.1.0/24", "gateway": "10.0.1.1"}) + networks_client._client.request.assert_called_with( + url="/networks/1/actions/add_route", + method="POST", + json={"destination": "10.100.1.0/24", "gateway": "10.0.1.1"}, + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("network", [Network(id=1), BoundNetwork(mock.MagicMock(), dict(id=1))]) - def test_delete_route(self, networks_client, network, generic_action, network_route): + @pytest.mark.parametrize( + "network", [Network(id=1), BoundNetwork(mock.MagicMock(), dict(id=1))] + ) + def test_delete_route( + self, networks_client, network, generic_action, network_route + ): networks_client._client.request.return_value = generic_action action = networks_client.delete_route(network, network_route) - networks_client._client.request.assert_called_with(url="/networks/1/actions/delete_route", method="POST", - json={"destination": "10.100.1.0/24", "gateway": "10.0.1.1"}) + networks_client._client.request.assert_called_with( + url="/networks/1/actions/delete_route", + method="POST", + json={"destination": "10.100.1.0/24", "gateway": "10.0.1.1"}, + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("network", [Network(id=1), BoundNetwork(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "network", [Network(id=1), BoundNetwork(mock.MagicMock(), dict(id=1))] + ) def test_change_ip_range(self, networks_client, network, generic_action): networks_client._client.request.return_value = generic_action action = networks_client.change_ip_range(network, "10.0.0.0/12") - networks_client._client.request.assert_called_with(url="/networks/1/actions/change_ip_range", method="POST", - json={"ip_range": "10.0.0.0/12"}) + networks_client._client.request.assert_called_with( + url="/networks/1/actions/change_ip_range", + method="POST", + json={"ip_range": "10.0.0.0/12"}, + ) assert action.id == 1 assert action.progress == 0 diff --git a/tests/unit/networks/test_domain.py b/tests/unit/networks/test_domain.py index 5f1eac0..84c71d3 100644 --- a/tests/unit/networks/test_domain.py +++ b/tests/unit/networks/test_domain.py @@ -5,7 +5,8 @@ class TestNetwork(object): - def test_created_is_datetime(self): network = Network(id=1, created="2016-01-30T23:50+00:00") - assert network.created == datetime.datetime(2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0)) + assert network.created == datetime.datetime( + 2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0) + ) diff --git a/tests/unit/server_types/conftest.py b/tests/unit/server_types/conftest.py index 61e0d29..dd2fbb2 100644 --- a/tests/unit/server_types/conftest.py +++ b/tests/unit/server_types/conftest.py @@ -16,16 +16,16 @@ def server_type_response(): "location": "fsn1", "price_hourly": { "net": "1.0000000000", - "gross": "1.1900000000000000" + "gross": "1.1900000000000000", }, "price_monthly": { "net": "1.0000000000", - "gross": "1.1900000000000000" - } + "gross": "1.1900000000000000", + }, } ], "storage_type": "local", - "cpu_type": "shared" + "cpu_type": "shared", } } @@ -46,16 +46,16 @@ def two_server_types_response(): "location": "fsn1", "price_hourly": { "net": "1.0000000000", - "gross": "1.1900000000000000" + "gross": "1.1900000000000000", }, "price_monthly": { "net": "1.0000000000", - "gross": "1.1900000000000000" - } + "gross": "1.1900000000000000", + }, } ], "storage_type": "local", - "cpu_type": "shared" + "cpu_type": "shared", }, { "id": 2, @@ -69,28 +69,28 @@ def two_server_types_response(): "location": "fsn1", "price_hourly": { "net": "0.0080000000", - "gross": "0.0095200000000000" + "gross": "0.0095200000000000", }, "price_monthly": { "net": "4.9000000000", - "gross": "5.8310000000000000" - } + "gross": "5.8310000000000000", + }, }, { "location": "nbg1", "price_hourly": { "net": "0.0080000000", - "gross": "0.0095200000000000" + "gross": "0.0095200000000000", }, "price_monthly": { "net": "4.9000000000", - "gross": "5.8310000000000000" - } - } + "gross": "5.8310000000000000", + }, + }, ], "storage_type": "local", - "cpu_type": "shared" - } + "cpu_type": "shared", + }, ] } @@ -111,16 +111,16 @@ def one_server_types_response(): "location": "fsn1", "price_hourly": { "net": "1.0000000000", - "gross": "1.1900000000000000" + "gross": "1.1900000000000000", }, "price_monthly": { "net": "1.0000000000", - "gross": "1.1900000000000000" - } + "gross": "1.1900000000000000", + }, } ], "storage_type": "local", - "cpu_type": "shared" + "cpu_type": "shared", } ] } diff --git a/tests/unit/server_types/test_client.py b/tests/unit/server_types/test_client.py index 3ac1753..a12a3e8 100644 --- a/tests/unit/server_types/test_client.py +++ b/tests/unit/server_types/test_client.py @@ -6,7 +6,6 @@ class TestServerTypesClient(object): - @pytest.fixture() def server_types_client(self): return ServerTypesClient(client=mock.MagicMock()) @@ -14,16 +13,22 @@ def server_types_client(self): def test_get_by_id(self, server_types_client, server_type_response): server_types_client._client.request.return_value = server_type_response server_type = server_types_client.get_by_id(1) - server_types_client._client.request.assert_called_with(url="/server_types/1", method="GET") + server_types_client._client.request.assert_called_with( + url="/server_types/1", method="GET" + ) assert server_type._client is server_types_client assert server_type.id == 1 assert server_type.name == "cx11" - @pytest.mark.parametrize("params", [{'name': "cx11", 'page': 1, 'per_page': 10}, {'name': ""}, {}]) + @pytest.mark.parametrize( + "params", [{"name": "cx11", "page": 1, "per_page": 10}, {"name": ""}, {}] + ) def test_get_list(self, server_types_client, two_server_types_response, params): server_types_client._client.request.return_value = two_server_types_response result = server_types_client.get_list(**params) - server_types_client._client.request.assert_called_with(url="/server_types", method="GET", params=params) + server_types_client._client.request.assert_called_with( + url="/server_types", method="GET", params=params + ) server_types = result.server_types assert result.meta is None @@ -41,14 +46,16 @@ def test_get_list(self, server_types_client, two_server_types_response, params): assert server_types2.id == 2 assert server_types2.name == "cx21" - @pytest.mark.parametrize("params", [{'name': "cx11"}]) + @pytest.mark.parametrize("params", [{"name": "cx11"}]) def test_get_all(self, server_types_client, two_server_types_response, params): server_types_client._client.request.return_value = two_server_types_response server_types = server_types_client.get_all(**params) - params.update({'page': 1, 'per_page': 50}) + params.update({"page": 1, "per_page": 50}) - server_types_client._client.request.assert_called_with(url="/server_types", method="GET", params=params) + server_types_client._client.request.assert_called_with( + url="/server_types", method="GET", params=params + ) assert len(server_types) == 2 @@ -67,9 +74,11 @@ def test_get_by_name(self, server_types_client, one_server_types_response): server_types_client._client.request.return_value = one_server_types_response server_type = server_types_client.get_by_name("cx11") - params = {'name': "cx11"} + params = {"name": "cx11"} - server_types_client._client.request.assert_called_with(url="/server_types", method="GET", params=params) + server_types_client._client.request.assert_called_with( + url="/server_types", method="GET", params=params + ) assert server_type._client is server_types_client assert server_type.id == 1 diff --git a/tests/unit/servers/conftest.py b/tests/unit/servers/conftest.py index 43f77f5..aa7ac0a 100644 --- a/tests/unit/servers/conftest.py +++ b/tests/unit/servers/conftest.py @@ -13,34 +13,22 @@ def response_simple_server(): "ipv4": { "ip": "1.2.3.4", "blocked": False, - "dns_ptr": "server01.example.com" + "dns_ptr": "server01.example.com", }, "ipv6": { "ip": "2001:db8::/64", "blocked": False, - "dns_ptr": [ - { - "ip": "2001:db8::1", - "dns_ptr": "server.example.com" - } - ] + "dns_ptr": [{"ip": "2001:db8::1", "dns_ptr": "server.example.com"}], }, - "floating_ips": [ - 478 - ], - "firewalls": [ - { - "id": 38, - "status": "applied" - } - ] + "floating_ips": [478], + "firewalls": [{"id": 38, "status": "applied"}], }, "private_net": [ { "network": 4711, "ip": "10.1.1.5", "alias_ips": ["10.1.1.8"], - "mac_address": "86:00:ff:2a:7d:e1" + "mac_address": "86:00:ff:2a:7d:e1", } ], "server_type": { @@ -55,16 +43,16 @@ def response_simple_server(): "location": "fsn1", "price_hourly": { "net": "1.0000000000", - "gross": "1.1900000000000000" + "gross": "1.1900000000000000", }, "price_monthly": { "net": "1.0000000000", - "gross": "1.1900000000000000" - } + "gross": "1.1900000000000000", + }, } ], "storage_type": "local", - "cpu_type": "shared" + "cpu_type": "shared", }, "datacenter": { "id": 1, @@ -77,25 +65,13 @@ def response_simple_server(): "country": "DE", "city": "Falkenstein", "latitude": 50.47612, - "longitude": 12.370071 + "longitude": 12.370071, }, "server_types": { - "supported": [ - 1, - 2, - 3 - ], - "available": [ - 1, - 2, - 3 - ], - "available_for_migration": [ - 1, - 2, - 3 - ] - } + "supported": [1, 2, 3], + "available": [1, 2, 3], + "available_for_migration": [1, 2, 3], + }, }, "image": { "id": 4711, @@ -106,20 +82,14 @@ def response_simple_server(): "image_size": 2.3, "disk_size": 10, "created": "2016-01-30T23:50+00:00", - "created_from": { - "id": 1, - "name": "Server" - }, + "created_from": {"id": 1, "name": "Server"}, "bound_to": None, "os_flavor": "ubuntu", "os_version": "16.04", "rapid_deploy": False, - "protection": { - "delete": False, - "rebuild": False - }, + "protection": {"delete": False, "rebuild": False}, "deprecated": "2018-02-28T00:00:00+00:00", - "labels": {} + "labels": {}, }, "iso": None, "rescue_enabled": False, @@ -131,7 +101,7 @@ def response_simple_server(): "primary_disk_size": 20, "protection": {}, "labels": {}, - "volumes": [] + "volumes": [], } } @@ -149,25 +119,15 @@ def response_create_simple_server(): "ipv4": { "ip": "1.2.3.4", "blocked": False, - "dns_ptr": "server01.example.com" + "dns_ptr": "server01.example.com", }, "ipv6": { "ip": "2001:db8::/64", "blocked": False, - "dns_ptr": [ - { - "ip": "2001:db8::1", - "dns_ptr": "server.example.com" - } - ] + "dns_ptr": [{"ip": "2001:db8::1", "dns_ptr": "server.example.com"}], }, "floating_ips": [], - "firewalls": [ - { - "id": 38, - "status": "applied" - } - ] + "firewalls": [{"id": 38, "status": "applied"}], }, "private_net": [], "server_type": { @@ -182,16 +142,16 @@ def response_create_simple_server(): "location": "fsn1", "price_hourly": { "net": "1.0000000000", - "gross": "1.1900000000000000" + "gross": "1.1900000000000000", }, "price_monthly": { "net": "1.0000000000", - "gross": "1.1900000000000000" - } + "gross": "1.1900000000000000", + }, } ], "storage_type": "local", - "cpu_type": "shared" + "cpu_type": "shared", }, "datacenter": { "id": 1, @@ -204,25 +164,13 @@ def response_create_simple_server(): "country": "DE", "city": "Falkenstein", "latitude": 50.47612, - "longitude": 12.370071 + "longitude": 12.370071, }, "server_types": { - "supported": [ - 1, - 2, - 3 - ], - "available": [ - 1, - 2, - 3 - ], - "available_for_migration": [ - 1, - 2, - 3 - ] - } + "supported": [1, 2, 3], + "available": [1, 2, 3], + "available_for_migration": [1, 2, 3], + }, }, "image": { "id": 4711, @@ -233,20 +181,14 @@ def response_create_simple_server(): "image_size": 2.3, "disk_size": 10, "created": "2016-01-30T23:50+00:00", - "created_from": { - "id": 1, - "name": "Server" - }, + "created_from": {"id": 1, "name": "Server"}, "bound_to": None, "os_flavor": "ubuntu", "os_version": "16.04", "rapid_deploy": False, - "protection": { - "delete": False, - "rebuild": False - }, + "protection": {"delete": False, "rebuild": False}, "deprecated": "2018-02-28T00:00:00+00:00", - "labels": {} + "labels": {}, }, "iso": { "id": 4711, @@ -259,7 +201,7 @@ def response_create_simple_server(): "included_traffic": 654321, "protection": {}, "labels": {}, - "volumes": [] + "volumes": [], }, "action": { "id": 1, @@ -268,16 +210,8 @@ def response_create_simple_server(): "progress": 0, "started": "2016-01-30T23:50+00:00", "finished": None, - "resources": [ - { - "id": 42, - "type": "server" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 42, "type": "server"}], + "error": {"code": "action_failed", "message": "Action failed"}, }, "next_actions": [ { @@ -287,19 +221,11 @@ def response_create_simple_server(): "progress": 0, "started": "2016-01-30T23:50+00:00", "finished": None, - "resources": [ - { - "id": 42, - "type": "server" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 42, "type": "server"}], + "error": {"code": "action_failed", "message": "Action failed"}, } ], - "root_password": "YItygq1v3GYjjMomLaKc" + "root_password": "YItygq1v3GYjjMomLaKc", } @@ -315,22 +241,15 @@ def response_update_server(): "ipv4": { "ip": "1.2.3.4", "blocked": False, - "dns_ptr": "server01.example.com" + "dns_ptr": "server01.example.com", }, "ipv6": { "ip": "2001:db8::/64", "blocked": False, - "dns_ptr": [ - { - "ip": "2001:db8::1", - "dns_ptr": "server.example.com" - } - ] + "dns_ptr": [{"ip": "2001:db8::1", "dns_ptr": "server.example.com"}], }, - "floating_ips": [ - 478 - ], - "firewalls": [] + "floating_ips": [478], + "firewalls": [], }, "private_net": [], "server_type": { @@ -345,16 +264,16 @@ def response_update_server(): "location": "fsn1", "price_hourly": { "net": "1.0000000000", - "gross": "1.1900000000000000" + "gross": "1.1900000000000000", }, "price_monthly": { "net": "1.0000000000", - "gross": "1.1900000000000000" - } + "gross": "1.1900000000000000", + }, } ], "storage_type": "local", - "cpu_type": "shared" + "cpu_type": "shared", }, "datacenter": { "id": 1, @@ -367,25 +286,13 @@ def response_update_server(): "country": "DE", "city": "Falkenstein", "latitude": 50.47612, - "longitude": 12.370071 + "longitude": 12.370071, }, "server_types": { - "supported": [ - 1, - 2, - 3 - ], - "available": [ - 1, - 2, - 3 - ], - "available_for_migration": [ - 1, - 2, - 3 - ] - } + "supported": [1, 2, 3], + "available": [1, 2, 3], + "available_for_migration": [1, 2, 3], + }, }, "image": { "id": 4711, @@ -396,26 +303,21 @@ def response_update_server(): "image_size": 2.3, "disk_size": 10, "created": "2016-01-30T23:50+00:00", - "created_from": { - "id": 1, - "name": "Server" - }, + "created_from": {"id": 1, "name": "Server"}, "bound_to": None, "os_flavor": "ubuntu", "os_version": "16.04", "rapid_deploy": False, - "protection": { - "delete": False - }, + "protection": {"delete": False}, "deprecated": "2018-02-28T00:00:00+00:00", - "labels": {} + "labels": {}, }, "iso": { "id": 4711, "name": "FreeBSD-11.0-RELEASE-amd64-dvd1", "description": "FreeBSD 11.0 x64", "type": "public", - "deprecated": "2018-02-28T00:00:00+00:00" + "deprecated": "2018-02-28T00:00:00+00:00", }, "rescue_enabled": False, "locked": False, @@ -423,12 +325,9 @@ def response_update_server(): "outgoing_traffic": 123456, "ingoing_traffic": 123456, "included_traffic": 654321, - "protection": { - "delete": False, - "rebuild": False - }, + "protection": {"delete": False, "rebuild": False}, "labels": {}, - "volumes": [] + "volumes": [], } } @@ -436,252 +335,209 @@ def response_update_server(): @pytest.fixture() def response_simple_servers(): return { - "servers": [{ - "id": 1, - "name": "my-server", - "status": "running", - "created": "2016-01-30T23:50+00:00", - "public_net": { - "ipv4": { - "ip": "1.2.3.4", - "blocked": False, - "dns_ptr": "server01.example.com" - }, - "ipv6": { - "ip": "2001:db8::/64", - "blocked": False, - "dns_ptr": [ - { - "ip": "2001:db8::1", - "dns_ptr": "server.example.com" - } - ] - }, - "floating_ips": [ - 478 - ], - "firewalls": [] - }, - "private_net": [ - { - "network": 4711, - "ip": "10.1.1.5", - "alias_ips": ["10.1.1.8"], - "mac_address": "86:00:ff:2a:7d:e1" - } - ], - "server_type": { + "servers": [ + { "id": 1, - "name": "cx11", - "description": "CX11", - "cores": 1, - "memory": 1, - "disk": 25, - "prices": [ + "name": "my-server", + "status": "running", + "created": "2016-01-30T23:50+00:00", + "public_net": { + "ipv4": { + "ip": "1.2.3.4", + "blocked": False, + "dns_ptr": "server01.example.com", + }, + "ipv6": { + "ip": "2001:db8::/64", + "blocked": False, + "dns_ptr": [ + {"ip": "2001:db8::1", "dns_ptr": "server.example.com"} + ], + }, + "floating_ips": [478], + "firewalls": [], + }, + "private_net": [ { - "location": "fsn1", - "price_hourly": { - "net": "1.0000000000", - "gross": "1.1900000000000000" - }, - "price_monthly": { - "net": "1.0000000000", - "gross": "1.1900000000000000" - } + "network": 4711, + "ip": "10.1.1.5", + "alias_ips": ["10.1.1.8"], + "mac_address": "86:00:ff:2a:7d:e1", } ], - "storage_type": "local", - "cpu_type": "shared" - }, - "datacenter": { - "id": 1, - "name": "fsn1-dc8", - "description": "Falkenstein 1 DC 8", - "location": { + "server_type": { "id": 1, - "name": "fsn1", - "description": "Falkenstein DC Park 1", - "country": "DE", - "city": "Falkenstein", - "latitude": 50.47612, - "longitude": 12.370071 - }, - "server_types": { - "supported": [ - 1, - 2, - 3 - ], - "available": [ - 1, - 2, - 3 - ], - "available_for_migration": [ - 1, - 2, - 3 - ] - } - }, - "image": { - "id": 4711, - "type": "snapshot", - "status": "available", - "name": "ubuntu-20.04", - "description": "Ubuntu 20.04 Standard 64 bit", - "image_size": 2.3, - "disk_size": 10, - "created": "2016-01-30T23:50+00:00", - "created_from": { - "id": 1, - "name": "Server" - }, - "bound_to": None, - "os_flavor": "ubuntu", - "os_version": "16.04", - "rapid_deploy": False, - "protection": { - "delete": False, - "rebuild": False - }, - "deprecated": "2018-02-28T00:00:00+00:00", - "labels": {} - }, - "iso": None, - "rescue_enabled": False, - "locked": False, - "backup_window": "22-02", - "outgoing_traffic": 123456, - "ingoing_traffic": 123456, - "included_traffic": 654321, - "protection": {}, - "labels": {}, - "volumes": [] - }, { - "id": 2, - "name": "my-server2", - "status": "running", - "created": "2016-03-30T23:50+00:00", - "public_net": { - "ipv4": { - "ip": "1.2.3.4", - "blocked": False, - "dns_ptr": "server01.example.com" - }, - "ipv6": { - "ip": "2001:db8::/64", - "blocked": False, - "dns_ptr": [ + "name": "cx11", + "description": "CX11", + "cores": 1, + "memory": 1, + "disk": 25, + "prices": [ { - "ip": "2001:db8::1", - "dns_ptr": "server.example.com" + "location": "fsn1", + "price_hourly": { + "net": "1.0000000000", + "gross": "1.1900000000000000", + }, + "price_monthly": { + "net": "1.0000000000", + "gross": "1.1900000000000000", + }, } - ] + ], + "storage_type": "local", + "cpu_type": "shared", }, - "floating_ips": [ - 478 - ], - "firewalls": [] + "datacenter": { + "id": 1, + "name": "fsn1-dc8", + "description": "Falkenstein 1 DC 8", + "location": { + "id": 1, + "name": "fsn1", + "description": "Falkenstein DC Park 1", + "country": "DE", + "city": "Falkenstein", + "latitude": 50.47612, + "longitude": 12.370071, + }, + "server_types": { + "supported": [1, 2, 3], + "available": [1, 2, 3], + "available_for_migration": [1, 2, 3], + }, + }, + "image": { + "id": 4711, + "type": "snapshot", + "status": "available", + "name": "ubuntu-20.04", + "description": "Ubuntu 20.04 Standard 64 bit", + "image_size": 2.3, + "disk_size": 10, + "created": "2016-01-30T23:50+00:00", + "created_from": {"id": 1, "name": "Server"}, + "bound_to": None, + "os_flavor": "ubuntu", + "os_version": "16.04", + "rapid_deploy": False, + "protection": {"delete": False, "rebuild": False}, + "deprecated": "2018-02-28T00:00:00+00:00", + "labels": {}, + }, + "iso": None, + "rescue_enabled": False, + "locked": False, + "backup_window": "22-02", + "outgoing_traffic": 123456, + "ingoing_traffic": 123456, + "included_traffic": 654321, + "protection": {}, + "labels": {}, + "volumes": [], }, - "private_net": [ - { - "network": 4711, - "ip": "10.1.1.7", - "alias_ips": ["10.1.1.99"], - "mac_address": "86:00:ff:2a:7d:e1" - } - ], - "server_type": { - "id": 1, - "name": "cx11", - "description": "CX11", - "cores": 1, - "memory": 1, - "disk": 25, - "prices": [ + { + "id": 2, + "name": "my-server2", + "status": "running", + "created": "2016-03-30T23:50+00:00", + "public_net": { + "ipv4": { + "ip": "1.2.3.4", + "blocked": False, + "dns_ptr": "server01.example.com", + }, + "ipv6": { + "ip": "2001:db8::/64", + "blocked": False, + "dns_ptr": [ + {"ip": "2001:db8::1", "dns_ptr": "server.example.com"} + ], + }, + "floating_ips": [478], + "firewalls": [], + }, + "private_net": [ { - "location": "fsn1", - "price_hourly": { - "net": "1.0000000000", - "gross": "1.1900000000000000" - }, - "price_monthly": { - "net": "1.0000000000", - "gross": "1.1900000000000000" - } + "network": 4711, + "ip": "10.1.1.7", + "alias_ips": ["10.1.1.99"], + "mac_address": "86:00:ff:2a:7d:e1", } ], - "storage_type": "local", - "cpu_type": "shared" - }, - "datacenter": { - "id": 1, - "name": "fsn1-dc8", - "description": "Falkenstein 1 DC 8", - "location": { + "server_type": { "id": 1, - "name": "fsn1", - "description": "Falkenstein DC Park 1", - "country": "DE", - "city": "Falkenstein", - "latitude": 50.47612, - "longitude": 12.370071 - }, - "server_types": { - "supported": [ - 1, - 2, - 3 - ], - "available": [ - 1, - 2, - 3 + "name": "cx11", + "description": "CX11", + "cores": 1, + "memory": 1, + "disk": 25, + "prices": [ + { + "location": "fsn1", + "price_hourly": { + "net": "1.0000000000", + "gross": "1.1900000000000000", + }, + "price_monthly": { + "net": "1.0000000000", + "gross": "1.1900000000000000", + }, + } ], - "available_for_migration": [ - 1, - 2, - 3 - ] - } - }, - "image": { - "id": 4711, - "type": "snapshot", - "status": "available", - "name": "ubuntu-20.04", - "description": "Ubuntu 20.04 Standard 64 bit", - "image_size": 2.3, - "disk_size": 10, - "created": "2016-01-30T23:50+00:00", - "created_from": { - "id": 1, - "name": "Server" - }, - "bound_to": None, - "os_flavor": "ubuntu", - "os_version": "16.04", - "rapid_deploy": False, - "protection": { - "delete": False, - "rebuild": False + "storage_type": "local", + "cpu_type": "shared", }, - "deprecated": "2018-02-28T00:00:00+00:00", - "labels": {} + "datacenter": { + "id": 1, + "name": "fsn1-dc8", + "description": "Falkenstein 1 DC 8", + "location": { + "id": 1, + "name": "fsn1", + "description": "Falkenstein DC Park 1", + "country": "DE", + "city": "Falkenstein", + "latitude": 50.47612, + "longitude": 12.370071, + }, + "server_types": { + "supported": [1, 2, 3], + "available": [1, 2, 3], + "available_for_migration": [1, 2, 3], + }, + }, + "image": { + "id": 4711, + "type": "snapshot", + "status": "available", + "name": "ubuntu-20.04", + "description": "Ubuntu 20.04 Standard 64 bit", + "image_size": 2.3, + "disk_size": 10, + "created": "2016-01-30T23:50+00:00", + "created_from": {"id": 1, "name": "Server"}, + "bound_to": None, + "os_flavor": "ubuntu", + "os_version": "16.04", + "rapid_deploy": False, + "protection": {"delete": False, "rebuild": False}, + "deprecated": "2018-02-28T00:00:00+00:00", + "labels": {}, + }, + "iso": None, + "rescue_enabled": False, + "locked": False, + "backup_window": "22-02", + "outgoing_traffic": 123456, + "ingoing_traffic": 123456, + "included_traffic": 654321, + "primary_disk_size": 20, + "protection": {}, + "labels": {}, + "volumes": [], }, - "iso": None, - "rescue_enabled": False, - "locked": False, - "backup_window": "22-02", - "outgoing_traffic": 123456, - "ingoing_traffic": 123456, - "included_traffic": 654321, - "primary_disk_size": 20, - "protection": {}, - "labels": {}, - "volumes": [] - }] + ] } @@ -698,34 +554,22 @@ def response_full_server(): "ipv4": { "ip": "1.2.3.4", "blocked": False, - "dns_ptr": "server01.example.com" + "dns_ptr": "server01.example.com", }, "ipv6": { "ip": "2001:db8::/64", "blocked": False, - "dns_ptr": [ - { - "ip": "2001:db8::1", - "dns_ptr": "server.example.com" - } - ] + "dns_ptr": [{"ip": "2001:db8::1", "dns_ptr": "server.example.com"}], }, - "floating_ips": [ - 478 - ], - "firewalls": [ - { - "id": 38, - "status": "applied" - } - ] + "floating_ips": [478], + "firewalls": [{"id": 38, "status": "applied"}], }, "private_net": [ { "network": 4711, "ip": "10.1.1.5", "alias_ips": ["10.1.1.8"], - "mac_address": "86:00:ff:2a:7d:e1" + "mac_address": "86:00:ff:2a:7d:e1", } ], "server_type": { @@ -737,7 +581,7 @@ def response_full_server(): "disk": 25, "prices": [], "storage_type": "local", - "cpu_type": "shared" + "cpu_type": "shared", }, "datacenter": { "id": 1, @@ -750,25 +594,13 @@ def response_full_server(): "country": "DE", "city": "Falkenstein", "latitude": 50.47612, - "longitude": 12.370071 + "longitude": 12.370071, }, "server_types": { - "supported": [ - 1, - 2, - 3 - ], - "available": [ - 1, - 2, - 3 - ], - "available_for_migration": [ - 1, - 2, - 3 - ] - } + "supported": [1, 2, 3], + "available": [1, 2, 3], + "available_for_migration": [1, 2, 3], + }, }, "image": { "id": 4711, @@ -779,26 +611,21 @@ def response_full_server(): "image_size": 2.3, "disk_size": 10, "created": "2016-01-30T23:50+00:00", - "created_from": { - "id": 1, - "name": "Server" - }, + "created_from": {"id": 1, "name": "Server"}, "bound_to": None, "os_flavor": "ubuntu", "os_version": "16.04", "rapid_deploy": False, - "protection": { - "delete": False - }, + "protection": {"delete": False}, "deprecated": "2018-02-28T00:00:00+00:00", - "labels": {} + "labels": {}, }, "iso": { "id": 4711, "name": "FreeBSD-11.0-RELEASE-amd64-dvd1", "description": "FreeBSD 11.0 x64", "type": "public", - "deprecated": "2018-02-28T00:00:00+00:00" + "deprecated": "2018-02-28T00:00:00+00:00", }, "rescue_enabled": False, "locked": False, @@ -808,7 +635,7 @@ def response_full_server(): "included_traffic": 654321, "protection": {}, "labels": {}, - "volumes": [1, 2] + "volumes": [1, 2], } } @@ -823,18 +650,10 @@ def response_server_reset_password(): "progress": 0, "started": "2016-01-30T23:50+00:00", "finished": None, - "resources": [ - { - "id": 42, - "type": "server" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 42, "type": "server"}], + "error": {"code": "action_failed", "message": "Action failed"}, }, - "root_password": "YItygq1v3GYjjMomLaKc" + "root_password": "YItygq1v3GYjjMomLaKc", } @@ -848,18 +667,10 @@ def response_server_enable_rescue(): "progress": 0, "started": "2016-01-30T23:50+00:00", "finished": None, - "resources": [ - { - "id": 42, - "type": "server" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 42, "type": "server"}], + "error": {"code": "action_failed", "message": "Action failed"}, }, - "root_password": "YItygq1v3GYjjMomLaKc" + "root_password": "YItygq1v3GYjjMomLaKc", } @@ -875,19 +686,14 @@ def response_server_create_image(): "image_size": 2.3, "disk_size": 10, "created": "2016-01-30T23:50+00:00", - "created_from": { - "id": 1, - "name": "Server" - }, + "created_from": {"id": 1, "name": "Server"}, "bound_to": None, "os_flavor": "ubuntu", "os_version": "16.04", "rapid_deploy": False, - "protection": { - "delete": False - }, + "protection": {"delete": False}, "deprecated": "2018-02-28T00:00:00+00:00", - "labels": {} + "labels": {}, }, "action": { "id": 1, @@ -896,17 +702,9 @@ def response_server_create_image(): "progress": 0, "started": "2016-01-30T23:50+00:00", "finished": None, - "resources": [ - { - "id": 42, - "type": "server" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } - } + "resources": [{"id": 42, "type": "server"}], + "error": {"code": "action_failed", "message": "Action failed"}, + }, } @@ -922,17 +720,9 @@ def response_server_request_console(): "progress": 0, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 42, - "type": "server" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } - } + "resources": [{"id": 42, "type": "server"}], + "error": {"code": "action_failed", "message": "Action failed"}, + }, } @@ -947,16 +737,8 @@ def response_get_actions(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 42, - "type": "server" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 42, "type": "server"}], + "error": {"code": "action_failed", "message": "Action failed"}, } ] } @@ -973,19 +755,10 @@ def response_attach_to_network(): "started": "2016-01-30T23:50:00+00:00", "finished": None, "resources": [ - { - "id": 42, - "type": "server" - }, - { - "id": 4711, - "type": "network" - } + {"id": 42, "type": "server"}, + {"id": 4711, "type": "network"}, ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "error": {"code": "action_failed", "message": "Action failed"}, } } @@ -1001,19 +774,10 @@ def response_detach_from_network(): "started": "2016-01-30T23:50:00+00:00", "finished": None, "resources": [ - { - "id": 42, - "type": "server" - }, - { - "id": 4711, - "type": "network" - } + {"id": 42, "type": "server"}, + {"id": 4711, "type": "network"}, ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "error": {"code": "action_failed", "message": "Action failed"}, } } @@ -1029,19 +793,10 @@ def response_change_alias_ips(): "started": "2016-01-30T23:50:00+00:00", "finished": None, "resources": [ - { - "id": 42, - "type": "server" - }, - { - "id": 4711, - "type": "network" - } + {"id": 42, "type": "server"}, + {"id": 4711, "type": "network"}, ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "error": {"code": "action_failed", "message": "Action failed"}, } } @@ -1056,16 +811,8 @@ def response_apply_firewall(): "progress": 0, "started": "2016-01-30T23:50:00+00:00", "finished": None, - "resources": [ - { - "id": 42, - "type": "server" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 42, "type": "server"}], + "error": {"code": "action_failed", "message": "Action failed"}, } } @@ -1080,15 +827,7 @@ def response_remove_firewall(): "progress": 0, "started": "2016-01-30T23:50:00+00:00", "finished": None, - "resources": [ - { - "id": 42, - "type": "server" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 42, "type": "server"}], + "error": {"code": "action_failed", "message": "Action failed"}, } } diff --git a/tests/unit/servers/test_client.py b/tests/unit/servers/test_client.py index 5d0c2c6..5ff7f2f 100644 --- a/tests/unit/servers/test_client.py +++ b/tests/unit/servers/test_client.py @@ -7,7 +7,14 @@ from hcloud.isos.client import BoundIso from hcloud.servers.client import ServersClient, BoundServer -from hcloud.servers.domain import Server, PublicNetwork, IPv4Address, IPv6Network, PublicNetworkFirewall, PrivateNet +from hcloud.servers.domain import ( + Server, + PublicNetwork, + IPv4Address, + IPv6Network, + PublicNetworkFirewall, + PrivateNet, +) from hcloud.volumes.client import BoundVolume from hcloud.volumes.domain import Volume from hcloud.images.domain import Image @@ -24,15 +31,13 @@ class TestBoundServer(object): - @pytest.fixture() def bound_server(self, hetzner_client): return BoundServer(client=hetzner_client.servers, data=dict(id=14)) def test_bound_server_init(self, response_full_server): bound_server = BoundServer( - client=mock.MagicMock(), - data=response_full_server['server'] + client=mock.MagicMock(), data=response_full_server["server"] ) assert bound_server.id == 42 @@ -62,12 +67,17 @@ def test_bound_server_init(self, response_full_server): assert bound_server.public_net.floating_ips[0].complete is False assert isinstance(bound_server.datacenter, BoundDatacenter) - assert bound_server.datacenter._client == bound_server._client._client.datacenters + assert ( + bound_server.datacenter._client == bound_server._client._client.datacenters + ) assert bound_server.datacenter.id == 1 assert bound_server.datacenter.complete is True assert isinstance(bound_server.server_type, BoundServerType) - assert bound_server.server_type._client == bound_server._client._client.server_types + assert ( + bound_server.server_type._client + == bound_server._client._client.server_types + ) assert bound_server.server_type.id == 1 assert bound_server.server_type.complete is True @@ -96,7 +106,10 @@ def test_bound_server_init(self, response_full_server): assert len(bound_server.private_net) == 1 assert isinstance(bound_server.private_net[0], PrivateNet) - assert bound_server.private_net[0].network._client == bound_server._client._client.networks + assert ( + bound_server.private_net[0].network._client + == bound_server._client._client.networks + ) assert bound_server.private_net[0].ip == "10.1.1.5" assert bound_server.private_net[0].mac_address == "86:00:ff:2a:7d:e1" assert len(bound_server.private_net[0].alias_ips) == 1 @@ -105,18 +118,23 @@ def test_bound_server_init(self, response_full_server): @pytest.mark.parametrize( "params", [ - {"status": [Server.STATUS_RUNNING], - "sort": "status", - "page": 1, - "per_page": 10}, - {} - - ] + { + "status": [Server.STATUS_RUNNING], + "sort": "status", + "page": 1, + "per_page": 10, + }, + {}, + ], ) - def test_get_actions_list(self, hetzner_client, bound_server, response_get_actions, params): + def test_get_actions_list( + self, hetzner_client, bound_server, response_get_actions, params + ): hetzner_client.request.return_value = response_get_actions result = bound_server.get_actions_list(**params) - hetzner_client.request.assert_called_with(url="/servers/14/actions", method="GET", params=params) + hetzner_client.request.assert_called_with( + url="/servers/14/actions", method="GET", params=params + ) actions = result.actions assert result.meta is None @@ -127,21 +145,19 @@ def test_get_actions_list(self, hetzner_client, bound_server, response_get_actio assert actions[0].command == "start_server" @pytest.mark.parametrize( - "params", - [ - {"status": [Server.STATUS_RUNNING], - "sort": "status"}, - {} - - ] + "params", [{"status": [Server.STATUS_RUNNING], "sort": "status"}, {}] ) - def test_get_actions(self, hetzner_client, bound_server, response_get_actions, params): + def test_get_actions( + self, hetzner_client, bound_server, response_get_actions, params + ): hetzner_client.request.return_value = response_get_actions actions = bound_server.get_actions(**params) - params.update({'page': 1, 'per_page': 50}) + params.update({"page": 1, "per_page": 50}) - hetzner_client.request.assert_called_with(url="/servers/14/actions", method="GET", params=params) + hetzner_client.request.assert_called_with( + url="/servers/14/actions", method="GET", params=params + ) assert len(actions) == 1 assert isinstance(actions[0], BoundAction) @@ -151,8 +167,9 @@ def test_get_actions(self, hetzner_client, bound_server, response_get_actions, p def test_update(self, hetzner_client, bound_server, response_update_server): hetzner_client.request.return_value = response_update_server server = bound_server.update(name="new-name", labels={}) - hetzner_client.request.assert_called_with(url="/servers/14", method="PUT", - json={"name": "new-name", "labels": {}}) + hetzner_client.request.assert_called_with( + url="/servers/14", method="PUT", json={"name": "new-name", "labels": {}} + ) assert server.id == 14 assert server.name == "new-name" @@ -168,7 +185,9 @@ def test_delete(self, hetzner_client, bound_server, generic_action): def test_power_off(self, hetzner_client, bound_server, generic_action): hetzner_client.request.return_value = generic_action action = bound_server.power_off() - hetzner_client.request.assert_called_with(url="/servers/14/actions/poweroff", method="POST") + hetzner_client.request.assert_called_with( + url="/servers/14/actions/poweroff", method="POST" + ) assert action.id == 1 assert action.progress == 0 @@ -176,7 +195,9 @@ def test_power_off(self, hetzner_client, bound_server, generic_action): def test_power_on(self, hetzner_client, bound_server, generic_action): hetzner_client.request.return_value = generic_action action = bound_server.power_on() - hetzner_client.request.assert_called_with(url="/servers/14/actions/poweron", method="POST") + hetzner_client.request.assert_called_with( + url="/servers/14/actions/poweron", method="POST" + ) assert action.id == 1 assert action.progress == 0 @@ -184,7 +205,9 @@ def test_power_on(self, hetzner_client, bound_server, generic_action): def test_reboot(self, hetzner_client, bound_server, generic_action): hetzner_client.request.return_value = generic_action action = bound_server.reboot() - hetzner_client.request.assert_called_with(url="/servers/14/actions/reboot", method="POST") + hetzner_client.request.assert_called_with( + url="/servers/14/actions/reboot", method="POST" + ) assert action.id == 1 assert action.progress == 0 @@ -192,7 +215,9 @@ def test_reboot(self, hetzner_client, bound_server, generic_action): def test_reset(self, hetzner_client, bound_server, generic_action): hetzner_client.request.return_value = generic_action action = bound_server.reset() - hetzner_client.request.assert_called_with(url="/servers/14/actions/reset", method="POST") + hetzner_client.request.assert_called_with( + url="/servers/14/actions/reset", method="POST" + ) assert action.id == 1 assert action.progress == 0 @@ -200,15 +225,21 @@ def test_reset(self, hetzner_client, bound_server, generic_action): def test_shutdown(self, hetzner_client, bound_server, generic_action): hetzner_client.request.return_value = generic_action action = bound_server.shutdown() - hetzner_client.request.assert_called_with(url="/servers/14/actions/shutdown", method="POST") + hetzner_client.request.assert_called_with( + url="/servers/14/actions/shutdown", method="POST" + ) assert action.id == 1 assert action.progress == 0 - def test_reset_password(self, hetzner_client, bound_server, response_server_reset_password): + def test_reset_password( + self, hetzner_client, bound_server, response_server_reset_password + ): hetzner_client.request.return_value = response_server_reset_password response = bound_server.reset_password() - hetzner_client.request.assert_called_with(url="/servers/14/actions/reset_password", method="POST") + hetzner_client.request.assert_called_with( + url="/servers/14/actions/reset_password", method="POST" + ) assert response.action.id == 1 assert response.action.progress == 0 @@ -217,17 +248,25 @@ def test_reset_password(self, hetzner_client, bound_server, response_server_rese def test_change_type(self, hetzner_client, bound_server, generic_action): hetzner_client.request.return_value = generic_action action = bound_server.change_type(ServerType(name="cx11"), upgrade_disk=True) - hetzner_client.request.assert_called_with(url="/servers/14/actions/change_type", method="POST", - json={"server_type": "cx11", "upgrade_disk": True}) + hetzner_client.request.assert_called_with( + url="/servers/14/actions/change_type", + method="POST", + json={"server_type": "cx11", "upgrade_disk": True}, + ) assert action.id == 1 assert action.progress == 0 - def test_enable_rescue(self, hetzner_client, bound_server, response_server_enable_rescue): + def test_enable_rescue( + self, hetzner_client, bound_server, response_server_enable_rescue + ): hetzner_client.request.return_value = response_server_enable_rescue response = bound_server.enable_rescue(type="linux64") - hetzner_client.request.assert_called_with(url="/servers/14/actions/enable_rescue", method="POST", - json={"type": "linux64"}) + hetzner_client.request.assert_called_with( + url="/servers/14/actions/enable_rescue", + method="POST", + json={"type": "linux64"}, + ) assert response.action.id == 1 assert response.action.progress == 0 @@ -236,16 +275,23 @@ def test_enable_rescue(self, hetzner_client, bound_server, response_server_enabl def test_disable_rescue(self, hetzner_client, bound_server, generic_action): hetzner_client.request.return_value = generic_action action = bound_server.disable_rescue() - hetzner_client.request.assert_called_with(url="/servers/14/actions/disable_rescue", method="POST") + hetzner_client.request.assert_called_with( + url="/servers/14/actions/disable_rescue", method="POST" + ) assert action.id == 1 assert action.progress == 0 - def test_create_image(self, hetzner_client, bound_server, response_server_create_image): + def test_create_image( + self, hetzner_client, bound_server, response_server_create_image + ): hetzner_client.request.return_value = response_server_create_image response = bound_server.create_image(description="my image", type="snapshot") - hetzner_client.request.assert_called_with(url="/servers/14/actions/create_image", method="POST", - json={"description": "my image", "type": "snapshot"}) + hetzner_client.request.assert_called_with( + url="/servers/14/actions/create_image", + method="POST", + json={"description": "my image", "type": "snapshot"}, + ) assert response.action.id == 1 assert response.action.progress == 0 @@ -254,8 +300,11 @@ def test_create_image(self, hetzner_client, bound_server, response_server_create def test_rebuild(self, hetzner_client, bound_server, generic_action): hetzner_client.request.return_value = generic_action action = bound_server.rebuild(Image(name="ubuntu-20.04")) - hetzner_client.request.assert_called_with(url="/servers/14/actions/rebuild", method="POST", - json={"image": "ubuntu-20.04"}) + hetzner_client.request.assert_called_with( + url="/servers/14/actions/rebuild", + method="POST", + json={"image": "ubuntu-20.04"}, + ) assert action.id == 1 assert action.progress == 0 @@ -263,7 +312,9 @@ def test_rebuild(self, hetzner_client, bound_server, generic_action): def test_enable_backup(self, hetzner_client, bound_server, generic_action): hetzner_client.request.return_value = generic_action action = bound_server.enable_backup() - hetzner_client.request.assert_called_with(url="/servers/14/actions/enable_backup", method="POST") + hetzner_client.request.assert_called_with( + url="/servers/14/actions/enable_backup", method="POST" + ) assert action.id == 1 assert action.progress == 0 @@ -271,7 +322,9 @@ def test_enable_backup(self, hetzner_client, bound_server, generic_action): def test_disable_backup(self, hetzner_client, bound_server, generic_action): hetzner_client.request.return_value = generic_action action = bound_server.disable_backup() - hetzner_client.request.assert_called_with(url="/servers/14/actions/disable_backup", method="POST") + hetzner_client.request.assert_called_with( + url="/servers/14/actions/disable_backup", method="POST" + ) assert action.id == 1 assert action.progress == 0 @@ -279,8 +332,11 @@ def test_disable_backup(self, hetzner_client, bound_server, generic_action): def test_attach_iso(self, hetzner_client, bound_server, generic_action): hetzner_client.request.return_value = generic_action action = bound_server.attach_iso(Iso(name="FreeBSD-11.0-RELEASE-amd64-dvd1")) - hetzner_client.request.assert_called_with(url="/servers/14/actions/attach_iso", method="POST", - json={"iso": "FreeBSD-11.0-RELEASE-amd64-dvd1"}) + hetzner_client.request.assert_called_with( + url="/servers/14/actions/attach_iso", + method="POST", + json={"iso": "FreeBSD-11.0-RELEASE-amd64-dvd1"}, + ) assert action.id == 1 assert action.progress == 0 @@ -288,7 +344,9 @@ def test_attach_iso(self, hetzner_client, bound_server, generic_action): def test_detach_iso(self, hetzner_client, bound_server, generic_action): hetzner_client.request.return_value = generic_action action = bound_server.detach_iso() - hetzner_client.request.assert_called_with(url="/servers/14/actions/detach_iso", method="POST") + hetzner_client.request.assert_called_with( + url="/servers/14/actions/detach_iso", method="POST" + ) assert action.id == 1 assert action.progress == 0 @@ -296,8 +354,11 @@ def test_detach_iso(self, hetzner_client, bound_server, generic_action): def test_change_dns_ptr(self, hetzner_client, bound_server, generic_action): hetzner_client.request.return_value = generic_action action = bound_server.change_dns_ptr("1.2.3.4", "example.com") - hetzner_client.request.assert_called_with(url="/servers/14/actions/change_dns_ptr", method="POST", - json={"ip": "1.2.3.4", "dns_ptr": "example.com"}) + hetzner_client.request.assert_called_with( + url="/servers/14/actions/change_dns_ptr", + method="POST", + json={"ip": "1.2.3.4", "dns_ptr": "example.com"}, + ) assert action.id == 1 assert action.progress == 0 @@ -305,51 +366,87 @@ def test_change_dns_ptr(self, hetzner_client, bound_server, generic_action): def test_change_protection(self, hetzner_client, bound_server, generic_action): hetzner_client.request.return_value = generic_action action = bound_server.change_protection(True, True) - hetzner_client.request.assert_called_with(url="/servers/14/actions/change_protection", method="POST", - json={"delete": True, "rebuild": True}) + hetzner_client.request.assert_called_with( + url="/servers/14/actions/change_protection", + method="POST", + json={"delete": True, "rebuild": True}, + ) assert action.id == 1 assert action.progress == 0 - def test_request_console(self, hetzner_client, bound_server, response_server_request_console): + def test_request_console( + self, hetzner_client, bound_server, response_server_request_console + ): hetzner_client.request.return_value = response_server_request_console response = bound_server.request_console() - hetzner_client.request.assert_called_with(url="/servers/14/actions/request_console", method="POST") + hetzner_client.request.assert_called_with( + url="/servers/14/actions/request_console", method="POST" + ) assert response.action.id == 1 assert response.action.progress == 0 - assert response.wss_url == "wss://console.hetzner.cloud/?server_id=1&token=3db32d15-af2f-459c-8bf8-dee1fd05f49c" + assert ( + response.wss_url + == "wss://console.hetzner.cloud/?server_id=1&token=3db32d15-af2f-459c-8bf8-dee1fd05f49c" + ) assert response.password == "9MQaTg2VAGI0FIpc10k3UpRXcHj2wQ6x" - @pytest.mark.parametrize("network", [Network(id=4711), BoundNetwork(mock.MagicMock(), dict(id=4711))]) - def test_attach_to_network(self, hetzner_client, bound_server, network, response_attach_to_network): + @pytest.mark.parametrize( + "network", [Network(id=4711), BoundNetwork(mock.MagicMock(), dict(id=4711))] + ) + def test_attach_to_network( + self, hetzner_client, bound_server, network, response_attach_to_network + ): hetzner_client.request.return_value = response_attach_to_network - action = bound_server.attach_to_network(network, "10.0.1.1", ["10.0.1.2", "10.0.1.3"]) - hetzner_client.request.assert_called_with(url="/servers/14/actions/attach_to_network", method="POST", - json={"network": 4711, "ip": "10.0.1.1", - "alias_ips": ["10.0.1.2", "10.0.1.3"]}) + action = bound_server.attach_to_network( + network, "10.0.1.1", ["10.0.1.2", "10.0.1.3"] + ) + hetzner_client.request.assert_called_with( + url="/servers/14/actions/attach_to_network", + method="POST", + json={ + "network": 4711, + "ip": "10.0.1.1", + "alias_ips": ["10.0.1.2", "10.0.1.3"], + }, + ) assert action.id == 1 assert action.progress == 0 assert action.command == "attach_to_network" - @pytest.mark.parametrize("network", [Network(id=4711), BoundNetwork(mock.MagicMock(), dict(id=4711))]) - def test_detach_from_network(self, hetzner_client, bound_server, network, response_detach_from_network): + @pytest.mark.parametrize( + "network", [Network(id=4711), BoundNetwork(mock.MagicMock(), dict(id=4711))] + ) + def test_detach_from_network( + self, hetzner_client, bound_server, network, response_detach_from_network + ): hetzner_client.request.return_value = response_detach_from_network action = bound_server.detach_from_network(network) - hetzner_client.request.assert_called_with(url="/servers/14/actions/detach_from_network", method="POST", - json={"network": 4711}) + hetzner_client.request.assert_called_with( + url="/servers/14/actions/detach_from_network", + method="POST", + json={"network": 4711}, + ) assert action.id == 1 assert action.progress == 0 assert action.command == "detach_from_network" - @pytest.mark.parametrize("network", [Network(id=4711), BoundNetwork(mock.MagicMock(), dict(id=4711))]) - def test_change_alias_ips(self, hetzner_client, bound_server, network, response_change_alias_ips): + @pytest.mark.parametrize( + "network", [Network(id=4711), BoundNetwork(mock.MagicMock(), dict(id=4711))] + ) + def test_change_alias_ips( + self, hetzner_client, bound_server, network, response_change_alias_ips + ): hetzner_client.request.return_value = response_change_alias_ips action = bound_server.change_alias_ips(network, ["10.0.1.2", "10.0.1.3"]) - hetzner_client.request.assert_called_with(url="/servers/14/actions/change_alias_ips", method="POST", - json={"network": 4711, "alias_ips": ["10.0.1.2", "10.0.1.3"]}) + hetzner_client.request.assert_called_with( + url="/servers/14/actions/change_alias_ips", + method="POST", + json={"network": 4711, "alias_ips": ["10.0.1.2", "10.0.1.3"]}, + ) assert action.id == 1 assert action.progress == 0 @@ -357,7 +454,6 @@ def test_change_alias_ips(self, hetzner_client, bound_server, network, response_ class TestServersClient(object): - @pytest.fixture() def servers_client(self): return ServersClient(client=mock.MagicMock()) @@ -365,7 +461,9 @@ def servers_client(self): def test_get_by_id(self, servers_client, response_simple_server): servers_client._client.request.return_value = response_simple_server bound_server = servers_client.get_by_id(1) - servers_client._client.request.assert_called_with(url="/servers/1", method="GET") + servers_client._client.request.assert_called_with( + url="/servers/1", method="GET" + ) assert bound_server._client is servers_client assert bound_server.id == 1 assert bound_server.name == "my-server" @@ -373,15 +471,17 @@ def test_get_by_id(self, servers_client, response_simple_server): @pytest.mark.parametrize( "params", [ - {'name': "server1", 'label_selector': "label1", 'page': 1, 'per_page': 10}, - {'name': ""}, - {} - ] + {"name": "server1", "label_selector": "label1", "page": 1, "per_page": 10}, + {"name": ""}, + {}, + ], ) def test_get_list(self, servers_client, response_simple_servers, params): servers_client._client.request.return_value = response_simple_servers result = servers_client.get_list(**params) - servers_client._client.request.assert_called_with(url="/servers", method="GET", params=params) + servers_client._client.request.assert_called_with( + url="/servers", method="GET", params=params + ) bound_servers = result.servers assert result.meta is None @@ -400,19 +500,17 @@ def test_get_list(self, servers_client, response_simple_servers, params): assert bound_server2.name == "my-server2" @pytest.mark.parametrize( - "params", - [ - {'name': "server1", 'label_selector': "label1"}, - {} - ] + "params", [{"name": "server1", "label_selector": "label1"}, {}] ) def test_get_all(self, servers_client, response_simple_servers, params): servers_client._client.request.return_value = response_simple_servers bound_servers = servers_client.get_all(**params) - params.update({'page': 1, 'per_page': 50}) + params.update({"page": 1, "per_page": 50}) - servers_client._client.request.assert_called_with(url="/servers", method="GET", params=params) + servers_client._client.request.assert_called_with( + url="/servers", method="GET", params=params + ) assert len(bound_servers) == 2 @@ -431,32 +529,36 @@ def test_get_by_name(self, servers_client, response_simple_servers): servers_client._client.request.return_value = response_simple_servers bound_server = servers_client.get_by_name("my-server") - params = {'name': "my-server"} + params = {"name": "my-server"} - servers_client._client.request.assert_called_with(url="/servers", method="GET", params=params) + servers_client._client.request.assert_called_with( + url="/servers", method="GET", params=params + ) assert bound_server._client is servers_client assert bound_server.id == 1 assert bound_server.name == "my-server" - def test_create_with_datacenter(self, servers_client, response_create_simple_server): + def test_create_with_datacenter( + self, servers_client, response_create_simple_server + ): servers_client._client.request.return_value = response_create_simple_server response = servers_client.create( "my-server", server_type=ServerType(name="cx11"), image=Image(id=4711), - datacenter=Datacenter(id=1) + datacenter=Datacenter(id=1), ) servers_client._client.request.assert_called_with( url="/servers", method="POST", json={ - 'name': "my-server", - 'server_type': "cx11", - 'image': 4711, - 'datacenter': 1, - "start_after_create": True - } + "name": "my-server", + "server_type": "cx11", + "image": 4711, + "datacenter": 1, + "start_after_create": True, + }, ) bound_server = response.server @@ -471,18 +573,18 @@ def test_create_with_location(self, servers_client, response_create_simple_serve "my-server", server_type=ServerType(name="cx11"), image=Image(name="ubuntu-20.04"), - location=Location(name="fsn1") + location=Location(name="fsn1"), ) servers_client._client.request.assert_called_with( url="/servers", method="POST", json={ - 'name': "my-server", - 'server_type': "cx11", - 'image': "ubuntu-20.04", - 'location': "fsn1", - "start_after_create": True - } + "name": "my-server", + "server_type": "cx11", + "image": "ubuntu-20.04", + "location": "fsn1", + "start_after_create": True, + }, ) bound_server = response.server @@ -505,18 +607,18 @@ def test_create_with_volumes(self, servers_client, response_create_simple_server server_type=ServerType(name="cx11"), image=Image(id=4711), volumes=volumes, - start_after_create=False + start_after_create=False, ) servers_client._client.request.assert_called_with( url="/servers", method="POST", json={ - 'name': "my-server", - 'server_type': "cx11", - 'image': 4711, - 'volumes': [1, 2], - "start_after_create": False - } + "name": "my-server", + "server_type": "cx11", + "image": 4711, + "volumes": [1, 2], + "start_after_create": False, + }, ) bound_server = response.server @@ -545,18 +647,18 @@ def test_create_with_networks(self, servers_client, response_create_simple_serve server_type=ServerType(name="cx11"), image=Image(id=4711), networks=networks, - start_after_create=False + start_after_create=False, ) servers_client._client.request.assert_called_with( url="/servers", method="POST", json={ - 'name': "my-server", - 'server_type': "cx11", - 'image': 4711, - 'networks': [1, 2], - "start_after_create": False - } + "name": "my-server", + "server_type": "cx11", + "image": 4711, + "networks": [1, 2], + "start_after_create": False, + }, ) bound_server = response.server @@ -585,18 +687,18 @@ def test_create_with_firewalls(self, servers_client, response_create_simple_serv server_type=ServerType(name="cx11"), image=Image(id=4711), firewalls=firewalls, - start_after_create=False + start_after_create=False, ) servers_client._client.request.assert_called_with( url="/servers", method="POST", json={ - 'name': "my-server", - 'server_type': "cx11", - 'image': 4711, - 'firewalls': [{"firewall": 1}, {"firewall": 2}], - "start_after_create": False - } + "name": "my-server", + "server_type": "cx11", + "image": 4711, + "firewalls": [{"firewall": 1}, {"firewall": 2}], + "start_after_create": False, + }, ) bound_server = response.server @@ -617,11 +719,15 @@ def test_create_with_firewalls(self, servers_client, response_create_simple_serv assert next_actions[0].id == 13 - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) def test_get_actions_list(self, servers_client, server, response_get_actions): servers_client._client.request.return_value = response_get_actions result = servers_client.get_actions_list(server) - servers_client._client.request.assert_called_with(url="/servers/1/actions", method="GET", params={}) + servers_client._client.request.assert_called_with( + url="/servers/1/actions", method="GET", params={} + ) actions = result.actions assert result.meta is None @@ -633,249 +739,396 @@ def test_get_actions_list(self, servers_client, server, response_get_actions): assert actions[0].id == 13 assert actions[0].command == "start_server" - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) def test_update(self, servers_client, server, response_update_server): servers_client._client.request.return_value = response_update_server server = servers_client.update(server, name="new-name", labels={}) - servers_client._client.request.assert_called_with(url="/servers/1", method="PUT", - json={"name": "new-name", "labels": {}}) + servers_client._client.request.assert_called_with( + url="/servers/1", method="PUT", json={"name": "new-name", "labels": {}} + ) assert server.id == 14 assert server.name == "new-name" - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) def test_delete(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.delete(server) - servers_client._client.request.assert_called_with(url="/servers/1", method="DELETE") + servers_client._client.request.assert_called_with( + url="/servers/1", method="DELETE" + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) def test_power_off(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.power_off(server) - servers_client._client.request.assert_called_with(url="/servers/1/actions/poweroff", method="POST") + servers_client._client.request.assert_called_with( + url="/servers/1/actions/poweroff", method="POST" + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) def test_power_on(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.power_on(server) - servers_client._client.request.assert_called_with(url="/servers/1/actions/poweron", method="POST") + servers_client._client.request.assert_called_with( + url="/servers/1/actions/poweron", method="POST" + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) def test_reboot(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.reboot(server) - servers_client._client.request.assert_called_with(url="/servers/1/actions/reboot", method="POST") + servers_client._client.request.assert_called_with( + url="/servers/1/actions/reboot", method="POST" + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) def test_reset(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.reset(server) - servers_client._client.request.assert_called_with(url="/servers/1/actions/reset", method="POST") + servers_client._client.request.assert_called_with( + url="/servers/1/actions/reset", method="POST" + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) def test_shutdown(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.shutdown(server) - servers_client._client.request.assert_called_with(url="/servers/1/actions/shutdown", method="POST") + servers_client._client.request.assert_called_with( + url="/servers/1/actions/shutdown", method="POST" + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) - def test_reset_password(self, servers_client, server, response_server_reset_password): + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) + def test_reset_password( + self, servers_client, server, response_server_reset_password + ): servers_client._client.request.return_value = response_server_reset_password response = servers_client.reset_password(server) - servers_client._client.request.assert_called_with(url="/servers/1/actions/reset_password", method="POST") + servers_client._client.request.assert_called_with( + url="/servers/1/actions/reset_password", method="POST" + ) assert response.action.id == 1 assert response.action.progress == 0 assert response.root_password == "YItygq1v3GYjjMomLaKc" - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) - def test_change_type_with_server_type_name(self, servers_client, server, generic_action): + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) + def test_change_type_with_server_type_name( + self, servers_client, server, generic_action + ): servers_client._client.request.return_value = generic_action - action = servers_client.change_type(server, ServerType(name="cx11"), upgrade_disk=True) - servers_client._client.request.assert_called_with(url="/servers/1/actions/change_type", method="POST", - json={"server_type": "cx11", "upgrade_disk": True}) + action = servers_client.change_type( + server, ServerType(name="cx11"), upgrade_disk=True + ) + servers_client._client.request.assert_called_with( + url="/servers/1/actions/change_type", + method="POST", + json={"server_type": "cx11", "upgrade_disk": True}, + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) - def test_change_type_with_server_type_id(self, servers_client, server, generic_action): + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) + def test_change_type_with_server_type_id( + self, servers_client, server, generic_action + ): servers_client._client.request.return_value = generic_action action = servers_client.change_type(server, ServerType(id=1), upgrade_disk=True) - servers_client._client.request.assert_called_with(url="/servers/1/actions/change_type", method="POST", - json={"server_type": 1, "upgrade_disk": True}) + servers_client._client.request.assert_called_with( + url="/servers/1/actions/change_type", + method="POST", + json={"server_type": 1, "upgrade_disk": True}, + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) def test_change_type_with_blank_server_type(self, servers_client, server): with pytest.raises(ValueError) as e: servers_client.change_type(server, ServerType(), upgrade_disk=True) assert str(e.value) == "id or name must be set" servers_client._client.request.assert_not_called() - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) def test_enable_rescue(self, servers_client, server, response_server_enable_rescue): servers_client._client.request.return_value = response_server_enable_rescue response = servers_client.enable_rescue(server, "linux64", [2323]) - servers_client._client.request.assert_called_with(url="/servers/1/actions/enable_rescue", method="POST", - json={"type": "linux64", "ssh_keys": [2323]}) + servers_client._client.request.assert_called_with( + url="/servers/1/actions/enable_rescue", + method="POST", + json={"type": "linux64", "ssh_keys": [2323]}, + ) assert response.action.id == 1 assert response.action.progress == 0 assert response.root_password == "YItygq1v3GYjjMomLaKc" - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) def test_disable_rescue(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.disable_rescue(server) - servers_client._client.request.assert_called_with(url="/servers/1/actions/disable_rescue", method="POST") + servers_client._client.request.assert_called_with( + url="/servers/1/actions/disable_rescue", method="POST" + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) def test_create_image(self, servers_client, server, response_server_create_image): servers_client._client.request.return_value = response_server_create_image - response = servers_client.create_image(server, description="my image", type="snapshot", labels={"key": "value"}) - servers_client._client.request.assert_called_with(url="/servers/1/actions/create_image", method="POST", - json={"description": "my image", "type": "snapshot", - "labels": {"key": "value"}}) + response = servers_client.create_image( + server, description="my image", type="snapshot", labels={"key": "value"} + ) + servers_client._client.request.assert_called_with( + url="/servers/1/actions/create_image", + method="POST", + json={ + "description": "my image", + "type": "snapshot", + "labels": {"key": "value"}, + }, + ) assert response.action.id == 1 assert response.action.progress == 0 assert response.image.description == "my image" - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) def test_rebuild(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.rebuild(server, Image(name="ubuntu-20.04")) - servers_client._client.request.assert_called_with(url="/servers/1/actions/rebuild", method="POST", - json={"image": "ubuntu-20.04"}) + servers_client._client.request.assert_called_with( + url="/servers/1/actions/rebuild", + method="POST", + json={"image": "ubuntu-20.04"}, + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) def test_enable_backup(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.enable_backup(server) - servers_client._client.request.assert_called_with(url="/servers/1/actions/enable_backup", method="POST") + servers_client._client.request.assert_called_with( + url="/servers/1/actions/enable_backup", method="POST" + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) def test_disable_backup(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.disable_backup(server) - servers_client._client.request.assert_called_with(url="/servers/1/actions/disable_backup", method="POST") + servers_client._client.request.assert_called_with( + url="/servers/1/actions/disable_backup", method="POST" + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) def test_attach_iso(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action - action = servers_client.attach_iso(server, Iso(name="FreeBSD-11.0-RELEASE-amd64-dvd1")) - servers_client._client.request.assert_called_with(url="/servers/1/actions/attach_iso", method="POST", - json={"iso": "FreeBSD-11.0-RELEASE-amd64-dvd1"}) + action = servers_client.attach_iso( + server, Iso(name="FreeBSD-11.0-RELEASE-amd64-dvd1") + ) + servers_client._client.request.assert_called_with( + url="/servers/1/actions/attach_iso", + method="POST", + json={"iso": "FreeBSD-11.0-RELEASE-amd64-dvd1"}, + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) def test_detach_iso(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.detach_iso(server) - servers_client._client.request.assert_called_with(url="/servers/1/actions/detach_iso", method="POST") + servers_client._client.request.assert_called_with( + url="/servers/1/actions/detach_iso", method="POST" + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) def test_change_dns_ptr(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.change_dns_ptr(server, "1.2.3.4", "example.com") - servers_client._client.request.assert_called_with(url="/servers/1/actions/change_dns_ptr", method="POST", - json={"ip": "1.2.3.4", "dns_ptr": "example.com"}) + servers_client._client.request.assert_called_with( + url="/servers/1/actions/change_dns_ptr", + method="POST", + json={"ip": "1.2.3.4", "dns_ptr": "example.com"}, + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) def test_change_protection(self, servers_client, server, generic_action): servers_client._client.request.return_value = generic_action action = servers_client.change_protection(server, True, True) - servers_client._client.request.assert_called_with(url="/servers/1/actions/change_protection", method="POST", - json={"delete": True, "rebuild": True}) + servers_client._client.request.assert_called_with( + url="/servers/1/actions/change_protection", + method="POST", + json={"delete": True, "rebuild": True}, + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) - def test_request_console(self, servers_client, server, response_server_request_console): + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) + def test_request_console( + self, servers_client, server, response_server_request_console + ): servers_client._client.request.return_value = response_server_request_console response = servers_client.request_console(server) - servers_client._client.request.assert_called_with(url="/servers/1/actions/request_console", method="POST") + servers_client._client.request.assert_called_with( + url="/servers/1/actions/request_console", method="POST" + ) assert response.action.id == 1 assert response.action.progress == 0 - assert response.wss_url == "wss://console.hetzner.cloud/?server_id=1&token=3db32d15-af2f-459c-8bf8-dee1fd05f49c" + assert ( + response.wss_url + == "wss://console.hetzner.cloud/?server_id=1&token=3db32d15-af2f-459c-8bf8-dee1fd05f49c" + ) assert response.password == "9MQaTg2VAGI0FIpc10k3UpRXcHj2wQ6x" - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) - @pytest.mark.parametrize("network", [Network(id=4711), BoundNetwork(mock.MagicMock(), dict(id=4711))]) - def test_attach_to_network(self, servers_client, server, network, response_attach_to_network): + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) + @pytest.mark.parametrize( + "network", [Network(id=4711), BoundNetwork(mock.MagicMock(), dict(id=4711))] + ) + def test_attach_to_network( + self, servers_client, server, network, response_attach_to_network + ): servers_client._client.request.return_value = response_attach_to_network - action = servers_client.attach_to_network(server, network, "10.0.1.1", ["10.0.1.2", "10.0.1.3"]) - servers_client._client.request.assert_called_with(url="/servers/1/actions/attach_to_network", method="POST", - json={"network": 4711, "ip": "10.0.1.1", - "alias_ips": ["10.0.1.2", "10.0.1.3"]}) + action = servers_client.attach_to_network( + server, network, "10.0.1.1", ["10.0.1.2", "10.0.1.3"] + ) + servers_client._client.request.assert_called_with( + url="/servers/1/actions/attach_to_network", + method="POST", + json={ + "network": 4711, + "ip": "10.0.1.1", + "alias_ips": ["10.0.1.2", "10.0.1.3"], + }, + ) assert action.id == 1 assert action.progress == 0 assert action.command == "attach_to_network" - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) - @pytest.mark.parametrize("network", [Network(id=4711), BoundNetwork(mock.MagicMock(), dict(id=4711))]) - def test_detach_from_network(self, servers_client, server, network, response_detach_from_network): + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) + @pytest.mark.parametrize( + "network", [Network(id=4711), BoundNetwork(mock.MagicMock(), dict(id=4711))] + ) + def test_detach_from_network( + self, servers_client, server, network, response_detach_from_network + ): servers_client._client.request.return_value = response_detach_from_network action = servers_client.detach_from_network(server, network) - servers_client._client.request.assert_called_with(url="/servers/1/actions/detach_from_network", method="POST", - json={"network": 4711}) + servers_client._client.request.assert_called_with( + url="/servers/1/actions/detach_from_network", + method="POST", + json={"network": 4711}, + ) assert action.id == 1 assert action.progress == 0 assert action.command == "detach_from_network" - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) - @pytest.mark.parametrize("network", [Network(id=4711), BoundNetwork(mock.MagicMock(), dict(id=4711))]) - def test_change_alias_ips(self, servers_client, server, network, response_change_alias_ips): + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) + @pytest.mark.parametrize( + "network", [Network(id=4711), BoundNetwork(mock.MagicMock(), dict(id=4711))] + ) + def test_change_alias_ips( + self, servers_client, server, network, response_change_alias_ips + ): servers_client._client.request.return_value = response_change_alias_ips - action = servers_client.change_alias_ips(server, network, ["10.0.1.2", "10.0.1.3"]) - servers_client._client.request.assert_called_with(url="/servers/1/actions/change_alias_ips", method="POST", - json={"network": 4711, "alias_ips": ["10.0.1.2", "10.0.1.3"]}) + action = servers_client.change_alias_ips( + server, network, ["10.0.1.2", "10.0.1.3"] + ) + servers_client._client.request.assert_called_with( + url="/servers/1/actions/change_alias_ips", + method="POST", + json={"network": 4711, "alias_ips": ["10.0.1.2", "10.0.1.3"]}, + ) assert action.id == 1 assert action.progress == 0 diff --git a/tests/unit/servers/test_domain.py b/tests/unit/servers/test_domain.py index 222d6c0..9bd1b39 100644 --- a/tests/unit/servers/test_domain.py +++ b/tests/unit/servers/test_domain.py @@ -5,7 +5,8 @@ class TestServer(object): - def test_created_is_datetime(self): server = Server(id=1, created="2016-01-30T23:50+00:00") - assert server.created == datetime.datetime(2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0)) + assert server.created == datetime.datetime( + 2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0) + ) diff --git a/tests/unit/ssh_keys/conftest.py b/tests/unit/ssh_keys/conftest.py index e2ec4ac..1b45c5f 100644 --- a/tests/unit/ssh_keys/conftest.py +++ b/tests/unit/ssh_keys/conftest.py @@ -10,7 +10,7 @@ def ssh_key_response(): "fingerprint": "b7:2f:30:a0:2f:6c:58:6c:21:04:58:61:ba:06:3b:2f", "public_key": "ssh-rsa AAAjjk76kgf...Xt", "labels": {}, - "created": "2016-01-30T23:50:00+00:00" + "created": "2016-01-30T23:50:00+00:00", } } @@ -25,7 +25,7 @@ def two_ssh_keys_response(): "fingerprint": "b7:2f:30:a0:2f:6c:58:6c:21:04:58:61:ba:06:3b:2f", "public_key": "ssh-rsa AAAjjk76kgf...Xt", "labels": {}, - "created": "2016-01-30T23:50:00+00:00" + "created": "2016-01-30T23:50:00+00:00", }, { "id": 2324, @@ -33,8 +33,8 @@ def two_ssh_keys_response(): "fingerprint": "b7:2f:30:a0:2f:6c:58:6c:21:04:58:61:ba:06:3b:2f", "public_key": "ssh-rsa AAAjjk76kgf...Xt", "labels": {}, - "created": "2016-01-30T23:50:00+00:00" - } + "created": "2016-01-30T23:50:00+00:00", + }, ] } @@ -48,7 +48,7 @@ def one_ssh_keys_response(): "name": "SSH-Key", "fingerprint": "b7:2f:30:a0:2f:6c:58:6c:21:04:58:61:ba:06:3b:2f", "public_key": "ssh-rsa AAAjjk76kgf...Xt", - "labels": {} + "labels": {}, } ] } @@ -63,6 +63,6 @@ def response_update_ssh_key(): "fingerprint": "b7:2f:30:a0:2f:6c:58:6c:21:04:58:61:ba:06:3b:2f", "public_key": "ssh-rsa AAAjjk76kgf...Xt", "labels": {}, - "created": "2016-01-30T23:50:00+00:00" + "created": "2016-01-30T23:50:00+00:00", } } diff --git a/tests/unit/ssh_keys/test_client.py b/tests/unit/ssh_keys/test_client.py index 622ccc1..6562304 100644 --- a/tests/unit/ssh_keys/test_client.py +++ b/tests/unit/ssh_keys/test_client.py @@ -6,26 +6,29 @@ class TestBoundSSHKey(object): - @pytest.fixture() def bound_ssh_key(self, hetzner_client): return BoundSSHKey(client=hetzner_client.ssh_keys, data=dict(id=14)) def test_bound_ssh_key_init(self, ssh_key_response): bound_ssh_key = BoundSSHKey( - client=mock.MagicMock(), - data=ssh_key_response['ssh_key'] + client=mock.MagicMock(), data=ssh_key_response["ssh_key"] ) assert bound_ssh_key.id == 2323 assert bound_ssh_key.name == "My ssh key" - assert bound_ssh_key.fingerprint == "b7:2f:30:a0:2f:6c:58:6c:21:04:58:61:ba:06:3b:2f" + assert ( + bound_ssh_key.fingerprint + == "b7:2f:30:a0:2f:6c:58:6c:21:04:58:61:ba:06:3b:2f" + ) assert bound_ssh_key.public_key == "ssh-rsa AAAjjk76kgf...Xt" def test_update(self, hetzner_client, bound_ssh_key, response_update_ssh_key): hetzner_client.request.return_value = response_update_ssh_key ssh_key = bound_ssh_key.update(name="New name") - hetzner_client.request.assert_called_with(url="/ssh_keys/14", method="PUT", json={"name": "New name"}) + hetzner_client.request.assert_called_with( + url="/ssh_keys/14", method="PUT", json={"name": "New name"} + ) assert ssh_key.id == 2323 assert ssh_key.name == "New name" @@ -39,7 +42,6 @@ def test_delete(self, hetzner_client, bound_ssh_key, generic_action): class TestSSHKeysClient(object): - @pytest.fixture() def ssh_keys_client(self): return SSHKeysClient(client=mock.MagicMock()) @@ -47,7 +49,9 @@ def ssh_keys_client(self): def test_get_by_id(self, ssh_keys_client, ssh_key_response): ssh_keys_client._client.request.return_value = ssh_key_response ssh_key = ssh_keys_client.get_by_id(1) - ssh_keys_client._client.request.assert_called_with(url="/ssh_keys/1", method="GET") + ssh_keys_client._client.request.assert_called_with( + url="/ssh_keys/1", method="GET" + ) assert ssh_key._client is ssh_keys_client assert ssh_key.id == 2323 assert ssh_key.name == "My ssh key" @@ -55,15 +59,23 @@ def test_get_by_id(self, ssh_keys_client, ssh_key_response): @pytest.mark.parametrize( "params", [ - {'name': "My ssh key", "fingerprint": "b7:2f:30:a0:2f:6c:58:6c:21:04:58:61:ba:06:3b:2f", "label_selector": "k==v", 'page': 1, 'per_page': 10}, - {'name': ""}, - {} - ] + { + "name": "My ssh key", + "fingerprint": "b7:2f:30:a0:2f:6c:58:6c:21:04:58:61:ba:06:3b:2f", + "label_selector": "k==v", + "page": 1, + "per_page": 10, + }, + {"name": ""}, + {}, + ], ) def test_get_list(self, ssh_keys_client, two_ssh_keys_response, params): ssh_keys_client._client.request.return_value = two_ssh_keys_response result = ssh_keys_client.get_list(**params) - ssh_keys_client._client.request.assert_called_with(url="/ssh_keys", method="GET", params=params) + ssh_keys_client._client.request.assert_called_with( + url="/ssh_keys", method="GET", params=params + ) ssh_keys = result.ssh_keys assert len(ssh_keys) == 2 @@ -80,18 +92,16 @@ def test_get_list(self, ssh_keys_client, two_ssh_keys_response, params): assert ssh_keys2.name == "SSH-Key" @pytest.mark.parametrize( - "params", - [ - {'name': "My ssh key", 'label_selector': "label1"}, - {} - ] + "params", [{"name": "My ssh key", "label_selector": "label1"}, {}] ) def test_get_all(self, ssh_keys_client, two_ssh_keys_response, params): ssh_keys_client._client.request.return_value = two_ssh_keys_response ssh_keys = ssh_keys_client.get_all(**params) - params.update({'page': 1, 'per_page': 50}) - ssh_keys_client._client.request.assert_called_with(url="/ssh_keys", method="GET", params=params) + params.update({"page": 1, "per_page": 50}) + ssh_keys_client._client.request.assert_called_with( + url="/ssh_keys", method="GET", params=params + ) assert len(ssh_keys) == 2 @@ -110,8 +120,10 @@ def test_get_by_name(self, ssh_keys_client, one_ssh_keys_response): ssh_keys_client._client.request.return_value = one_ssh_keys_response ssh_keys = ssh_keys_client.get_by_name("SSH-Key") - params = {'name': "SSH-Key"} - ssh_keys_client._client.request.assert_called_with(url="/ssh_keys", method="GET", params=params) + params = {"name": "SSH-Key"} + ssh_keys_client._client.request.assert_called_with( + url="/ssh_keys", method="GET", params=params + ) assert ssh_keys._client is ssh_keys_client assert ssh_keys.id == 2323 @@ -119,10 +131,14 @@ def test_get_by_name(self, ssh_keys_client, one_ssh_keys_response): def test_get_by_fingerprint(self, ssh_keys_client, one_ssh_keys_response): ssh_keys_client._client.request.return_value = one_ssh_keys_response - ssh_keys = ssh_keys_client.get_by_fingerprint("b7:2f:30:a0:2f:6c:58:6c:21:04:58:61:ba:06:3b:2f") + ssh_keys = ssh_keys_client.get_by_fingerprint( + "b7:2f:30:a0:2f:6c:58:6c:21:04:58:61:ba:06:3b:2f" + ) - params = {'fingerprint': "b7:2f:30:a0:2f:6c:58:6c:21:04:58:61:ba:06:3b:2f"} - ssh_keys_client._client.request.assert_called_with(url="/ssh_keys", method="GET", params=params) + params = {"fingerprint": "b7:2f:30:a0:2f:6c:58:6c:21:04:58:61:ba:06:3b:2f"} + ssh_keys_client._client.request.assert_called_with( + url="/ssh_keys", method="GET", params=params + ) assert ssh_keys._client is ssh_keys_client assert ssh_keys.id == 2323 @@ -130,25 +146,39 @@ def test_get_by_fingerprint(self, ssh_keys_client, one_ssh_keys_response): def test_create(self, ssh_keys_client, ssh_key_response): ssh_keys_client._client.request.return_value = ssh_key_response - ssh_key = ssh_keys_client.create(name="My ssh key", public_key="ssh-rsa AAAjjk76kgf...Xt") - ssh_keys_client._client.request.assert_called_with(url="/ssh_keys", method="POST", json={"name": "My ssh key", "public_key": "ssh-rsa AAAjjk76kgf...Xt"}) + ssh_key = ssh_keys_client.create( + name="My ssh key", public_key="ssh-rsa AAAjjk76kgf...Xt" + ) + ssh_keys_client._client.request.assert_called_with( + url="/ssh_keys", + method="POST", + json={"name": "My ssh key", "public_key": "ssh-rsa AAAjjk76kgf...Xt"}, + ) assert ssh_key.id == 2323 assert ssh_key.name == "My ssh key" - @pytest.mark.parametrize("ssh_key", [SSHKey(id=1), BoundSSHKey(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "ssh_key", [SSHKey(id=1), BoundSSHKey(mock.MagicMock(), dict(id=1))] + ) def test_update(self, ssh_keys_client, ssh_key, response_update_ssh_key): ssh_keys_client._client.request.return_value = response_update_ssh_key ssh_key = ssh_keys_client.update(ssh_key, name="New name") - ssh_keys_client._client.request.assert_called_with(url="/ssh_keys/1", method="PUT", json={"name": "New name"}) + ssh_keys_client._client.request.assert_called_with( + url="/ssh_keys/1", method="PUT", json={"name": "New name"} + ) assert ssh_key.id == 2323 assert ssh_key.name == "New name" - @pytest.mark.parametrize("ssh_key", [SSHKey(id=1), BoundSSHKey(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "ssh_key", [SSHKey(id=1), BoundSSHKey(mock.MagicMock(), dict(id=1))] + ) def test_delete(self, ssh_keys_client, ssh_key, generic_action): ssh_keys_client._client.request.return_value = generic_action delete_success = ssh_keys_client.delete(ssh_key) - ssh_keys_client._client.request.assert_called_with(url="/ssh_keys/1", method="DELETE") + ssh_keys_client._client.request.assert_called_with( + url="/ssh_keys/1", method="DELETE" + ) assert delete_success is True diff --git a/tests/unit/ssh_keys/test_domain.py b/tests/unit/ssh_keys/test_domain.py index b327986..c19a37e 100644 --- a/tests/unit/ssh_keys/test_domain.py +++ b/tests/unit/ssh_keys/test_domain.py @@ -5,7 +5,8 @@ class TestSSHKey(object): - def test_created_is_datetime(self): sshKey = SSHKey(id=1, created="2016-01-30T23:50+00:00") - assert sshKey.created == datetime.datetime(2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0)) + assert sshKey.created == datetime.datetime( + 2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0) + ) diff --git a/tests/unit/test_hcloud.py b/tests/unit/test_hcloud.py index 0e20b2c..c680ec1 100644 --- a/tests/unit/test_hcloud.py +++ b/tests/unit/test_hcloud.py @@ -9,10 +9,9 @@ class TestHetznerClient(object): - @pytest.fixture() def client(self): - Client._version = '0.0.0' + Client._version = "0.0.0" client = Client(token="project_token") client._requests_session = MagicMock() @@ -22,7 +21,7 @@ def client(self): def response(self): response = requests.Response() response.status_code = 200 - response._content = json.dumps({"result": "data"}).encode('utf-8') + response._content = json.dumps({"result": "data"}).encode("utf-8") return response @pytest.fixture() @@ -32,15 +31,10 @@ def fail_response(self, response): "code": "invalid_input", "message": "invalid input in field 'broken_field': is too long", "details": { - "fields": [ - { - "name": "broken_field", - "messages": ["is too long"] - } - ] - } + "fields": [{"name": "broken_field", "messages": ["is too long"]}] + }, } - response._content = json.dumps({"error": error}).encode('utf-8') + response._content = json.dumps({"error": error}).encode("utf-8") return response @pytest.fixture() @@ -49,11 +43,9 @@ def rate_limit_response(self, response): error = { "code": "rate_limit_exceeded", "message": "limit of 10 requests per hour reached", - "details": { - - } + "details": {}, } - response._content = json.dumps({"error": error}).encode('utf-8') + response._content = json.dumps({"error": error}).encode("utf-8") return response def test__get_user_agent(self, client): @@ -66,7 +58,11 @@ def test__get_user_agent_with_application_name(self, client): assert user_agent == "my-app hcloud-python/0.0.0" def test__get_user_agent_with_application_name_and_version(self, client): - client = Client(token="project_token", application_name="my-app", application_version="1.0.0") + client = Client( + token="project_token", + application_name="my-app", + application_version="1.0.0", + ) user_agent = client._get_user_agent() assert user_agent == "my-app/1.0.0 hcloud-python/0.0.0" @@ -74,30 +70,39 @@ def test__get_headers(self, client): headers = client._get_headers() assert headers == { "User-Agent": "hcloud-python/0.0.0", - "Authorization": "Bearer project_token" + "Authorization": "Bearer project_token", } def test_request_library_mocked(self, client): response = client.request("POST", "url", params={"1": 2}) - assert response.__class__.__name__ == 'MagicMock' + assert response.__class__.__name__ == "MagicMock" def test_request_ok(self, client, response): client._requests_session.request.return_value = response - response = client.request("POST", "/servers", params={"argument": "value"}, timeout=2) + response = client.request( + "POST", "/servers", params={"argument": "value"}, timeout=2 + ) client._requests_session.request.assert_called_once() - assert client._requests_session.request.call_args[0] == ('POST', 'https://api.hetzner.cloud/v1/servers') - assert client._requests_session.request.call_args[1]['params'] == {'argument': 'value'} - assert client._requests_session.request.call_args[1]['timeout'] == 2 + assert client._requests_session.request.call_args[0] == ( + "POST", + "https://api.hetzner.cloud/v1/servers", + ) + assert client._requests_session.request.call_args[1]["params"] == { + "argument": "value" + } + assert client._requests_session.request.call_args[1]["timeout"] == 2 assert response == {"result": "data"} def test_request_fails(self, client, fail_response): client._requests_session.request.return_value = fail_response with pytest.raises(APIException) as exception_info: - client.request("POST", "http://url.com", params={"argument": "value"}, timeout=2) + client.request( + "POST", "http://url.com", params={"argument": "value"}, timeout=2 + ) error = exception_info.value assert error.code == "invalid_input" assert error.message == "invalid input in field 'broken_field': is too long" - assert error.details['fields'][0]['name'] == "broken_field" + assert error.details["fields"][0]["name"] == "broken_field" def test_request_500(self, client, fail_response): fail_response.status_code = 500 @@ -105,30 +110,36 @@ def test_request_500(self, client, fail_response): fail_response._content = "Internal Server Error" client._requests_session.request.return_value = fail_response with pytest.raises(APIException) as exception_info: - client.request("POST", "http://url.com", params={"argument": "value"}, timeout=2) + client.request( + "POST", "http://url.com", params={"argument": "value"}, timeout=2 + ) error = exception_info.value assert error.code == 500 assert error.message == "Internal Server Error" - assert error.details['content'] == "Internal Server Error" + assert error.details["content"] == "Internal Server Error" def test_request_broken_json_200(self, client, response): - content = "{'key': 'value'".encode('utf-8') + content = "{'key': 'value'".encode("utf-8") response.reason = "OK" response._content = content client._requests_session.request.return_value = response with pytest.raises(APIException) as exception_info: - client.request("POST", "http://url.com", params={"argument": "value"}, timeout=2) + client.request( + "POST", "http://url.com", params={"argument": "value"}, timeout=2 + ) error = exception_info.value assert error.code == 200 assert error.message == "OK" - assert error.details['content'] == content + assert error.details["content"] == content def test_request_empty_content_200(self, client, response): content = "" response.reason = "OK" response._content = content client._requests_session.request.return_value = response - response = client.request("POST", "http://url.com", params={"argument": "value"}, timeout=2) + response = client.request( + "POST", "http://url.com", params={"argument": "value"}, timeout=2 + ) assert response == "" def test_request_500_empty_content(self, client, fail_response): @@ -137,7 +148,9 @@ def test_request_500_empty_content(self, client, fail_response): fail_response._content = "" client._requests_session.request.return_value = fail_response with pytest.raises(APIException) as exception_info: - client.request("POST", "http://url.com", params={"argument": "value"}, timeout=2) + client.request( + "POST", "http://url.com", params={"argument": "value"}, timeout=2 + ) error = exception_info.value assert error.code == 500 assert error.message == "Internal Server Error" @@ -148,7 +161,9 @@ def test_request_limit(self, client, rate_limit_response): client._retry_wait_time = 0 client._requests_session.request.return_value = rate_limit_response with pytest.raises(APIException) as exception_info: - client.request("POST", "http://url.com", params={"argument": "value"}, timeout=2) + client.request( + "POST", "http://url.com", params={"argument": "value"}, timeout=2 + ) error = exception_info.value assert client._requests_session.request.call_count == 5 assert error.code == "rate_limit_exceeded" @@ -158,8 +173,10 @@ def test_request_limit_then_success(self, client, rate_limit_response): client._retry_wait_time = 0 response = requests.Response() response.status_code = 200 - response._content = json.dumps({"result": "data"}).encode('utf-8') + response._content = json.dumps({"result": "data"}).encode("utf-8") client._requests_session.request.side_effect = [rate_limit_response, response] - client.request("POST", "http://url.com", params={"argument": "value"}, timeout=2) + client.request( + "POST", "http://url.com", params={"argument": "value"}, timeout=2 + ) assert client._requests_session.request.call_count == 2 diff --git a/tests/unit/volumes/conftest.py b/tests/unit/volumes/conftest.py index 7476b5d..e4a5254 100644 --- a/tests/unit/volumes/conftest.py +++ b/tests/unit/volumes/conftest.py @@ -16,16 +16,14 @@ def volume_response(): "country": "DE", "city": "Falkenstein", "latitude": 50.47612, - "longitude": 12.370071 + "longitude": 12.370071, }, "size": 42, "linux_device": "/dev/disk/by-id/scsi-0HC_Volume_4711", - "protection": { - "delete": False - }, + "protection": {"delete": False}, "format": "xfs", "labels": {}, - "status": "available" + "status": "available", } } @@ -46,16 +44,14 @@ def two_volumes_response(): "country": "DE", "city": "Falkenstein", "latitude": 50.47612, - "longitude": 12.370071 + "longitude": 12.370071, }, "size": 42, "linux_device": "/dev/disk/by-id/scsi-0HC_Volume_4711", - "protection": { - "delete": False - }, + "protection": {"delete": False}, "format": "xfs", "labels": {}, - "status": "available" + "status": "available", }, { "id": 2, @@ -69,17 +65,15 @@ def two_volumes_response(): "country": "DE", "city": "Falkenstein", "latitude": 50.47612, - "longitude": 12.370071 + "longitude": 12.370071, }, "size": 42, "linux_device": "/dev/disk/by-id/scsi-0HC_Volume_4711", - "protection": { - "delete": False - }, + "protection": {"delete": False}, "format": "xfs", "labels": {}, - "status": "available" - } + "status": "available", + }, ] } @@ -100,16 +94,14 @@ def one_volumes_response(): "country": "DE", "city": "Falkenstein", "latitude": 50.47612, - "longitude": 12.370071 + "longitude": 12.370071, }, "size": 42, "linux_device": "/dev/disk/by-id/scsi-0HC_Volume_4711", - "protection": { - "delete": False - }, + "protection": {"delete": False}, "format": "xfs", "labels": {}, - "status": "available" + "status": "available", } ] } @@ -130,16 +122,14 @@ def volume_create_response(): "country": "DE", "city": "Falkenstein", "latitude": 50.47612, - "longitude": 12.370071 + "longitude": 12.370071, }, "size": 42, "linux_device": "/dev/disk/by-id/scsi-0HC_Volume_4711", - "protection": { - "delete": False - }, + "protection": {"delete": False}, "format": "xfs", "labels": {}, - "status": "available" + "status": "available", }, "action": { "id": 13, @@ -148,16 +138,8 @@ def volume_create_response(): "progress": 0, "started": "2016-01-30T23:50+00:00", "finished": None, - "resources": [ - { - "id": 42, - "type": "server" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 42, "type": "server"}], + "error": {"code": "action_failed", "message": "Action failed"}, }, "next_actions": [ { @@ -167,18 +149,10 @@ def volume_create_response(): "progress": 0, "started": "2016-01-30T23:50+00:00", "finished": None, - "resources": [ - { - "id": 42, - "type": "server" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 42, "type": "server"}], + "error": {"code": "action_failed", "message": "Action failed"}, } - ] + ], } @@ -197,16 +171,14 @@ def response_update_volume(): "country": "DE", "city": "Falkenstein", "latitude": 50.47612, - "longitude": 12.370071 + "longitude": 12.370071, }, "format": "xfs", "size": 42, "linux_device": "/dev/disk/by-id/scsi-0HC_Volume_4711", - "protection": { - "delete": False - }, + "protection": {"delete": False}, "labels": {}, - "status": "available" + "status": "available", } } @@ -222,16 +194,8 @@ def response_get_actions(): "progress": 100, "started": "2016-01-30T23:55:00+00:00", "finished": "2016-01-30T23:56:00+00:00", - "resources": [ - { - "id": 42, - "type": "server" - } - ], - "error": { - "code": "action_failed", - "message": "Action failed" - } + "resources": [{"id": 42, "type": "server"}], + "error": {"code": "action_failed", "message": "Action failed"}, } ] } diff --git a/tests/unit/volumes/test_client.py b/tests/unit/volumes/test_client.py index fb05a1b..a075ad5 100644 --- a/tests/unit/volumes/test_client.py +++ b/tests/unit/volumes/test_client.py @@ -12,15 +12,13 @@ class TestBoundVolume(object): - @pytest.fixture() def bound_volume(self, hetzner_client): return BoundVolume(client=hetzner_client.volumes, data=dict(id=14)) def test_bound_volume_init(self, volume_response): bound_volume = BoundVolume( - client=mock.MagicMock(), - data=volume_response['volume'] + client=mock.MagicMock(), data=volume_response["volume"] ) assert bound_volume.id == 1 @@ -46,7 +44,11 @@ def test_bound_volume_init(self, volume_response): def test_get_actions(self, hetzner_client, bound_volume, response_get_actions): hetzner_client.request.return_value = response_get_actions actions = bound_volume.get_actions(sort="id") - hetzner_client.request.assert_called_with(url="/volumes/14/actions", method="GET", params={"page": 1, "per_page": 50, "sort": "id"}) + hetzner_client.request.assert_called_with( + url="/volumes/14/actions", + method="GET", + params={"page": 1, "per_page": 50, "sort": "id"}, + ) assert len(actions) == 1 assert isinstance(actions[0], BoundAction) @@ -56,7 +58,9 @@ def test_get_actions(self, hetzner_client, bound_volume, response_get_actions): def test_update(self, hetzner_client, bound_volume, response_update_volume): hetzner_client.request.return_value = response_update_volume volume = bound_volume.update(name="new-name") - hetzner_client.request.assert_called_with(url="/volumes/14", method="PUT", json={"name": "new-name"}) + hetzner_client.request.assert_called_with( + url="/volumes/14", method="PUT", json={"name": "new-name"} + ) assert volume.id == 4711 assert volume.name == "new-name" @@ -71,33 +75,39 @@ def test_delete(self, hetzner_client, bound_volume, generic_action): def test_change_protection(self, hetzner_client, bound_volume, generic_action): hetzner_client.request.return_value = generic_action action = bound_volume.change_protection(True) - hetzner_client.request.assert_called_with(url="/volumes/14/actions/change_protection", method="POST", json={"delete": True}) + hetzner_client.request.assert_called_with( + url="/volumes/14/actions/change_protection", + method="POST", + json={"delete": True}, + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("server", - (Server(id=1), BoundServer(mock.MagicMock(), dict(id=1)))) + @pytest.mark.parametrize( + "server", (Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))) + ) def test_attach(self, hetzner_client, bound_volume, server, generic_action): hetzner_client.request.return_value = generic_action action = bound_volume.attach(server) hetzner_client.request.assert_called_with( - url="/volumes/14/actions/attach", - method="POST", - json={"server": 1} + url="/volumes/14/actions/attach", method="POST", json={"server": 1} ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("server", - (Server(id=1), BoundServer(mock.MagicMock(), dict(id=1)))) - def test_attach_with_automount(self, hetzner_client, bound_volume, server, generic_action): + @pytest.mark.parametrize( + "server", (Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))) + ) + def test_attach_with_automount( + self, hetzner_client, bound_volume, server, generic_action + ): hetzner_client.request.return_value = generic_action action = bound_volume.attach(server, False) hetzner_client.request.assert_called_with( url="/volumes/14/actions/attach", method="POST", - json={"server": 1, "automount": False} + json={"server": 1, "automount": False}, ) assert action.id == 1 assert action.progress == 0 @@ -106,8 +116,7 @@ def test_detach(self, hetzner_client, bound_volume, generic_action): hetzner_client.request.return_value = generic_action action = bound_volume.detach() hetzner_client.request.assert_called_with( - url="/volumes/14/actions/detach", - method="POST" + url="/volumes/14/actions/detach", method="POST" ) assert action.id == 1 assert action.progress == 0 @@ -116,16 +125,13 @@ def test_resize(self, hetzner_client, bound_volume, generic_action): hetzner_client.request.return_value = generic_action action = bound_volume.resize(50) hetzner_client.request.assert_called_with( - url="/volumes/14/actions/resize", - method="POST", - json={"size": 50} + url="/volumes/14/actions/resize", method="POST", json={"size": 50} ) assert action.id == 1 assert action.progress == 0 class TestVolumesClient(object): - @pytest.fixture() def volumes_client(self): return VolumesClient(client=mock.MagicMock()) @@ -133,23 +139,23 @@ def volumes_client(self): def test_get_by_id(self, volumes_client, volume_response): volumes_client._client.request.return_value = volume_response bound_volume = volumes_client.get_by_id(1) - volumes_client._client.request.assert_called_with(url="/volumes/1", method="GET") + volumes_client._client.request.assert_called_with( + url="/volumes/1", method="GET" + ) assert bound_volume._client is volumes_client assert bound_volume.id == 1 assert bound_volume.name == "database-storage" @pytest.mark.parametrize( "params", - [ - {'label_selector': "label1", 'page': 1, 'per_page': 10}, - {'name': ""}, - {} - ] + [{"label_selector": "label1", "page": 1, "per_page": 10}, {"name": ""}, {}], ) def test_get_list(self, volumes_client, two_volumes_response, params): volumes_client._client.request.return_value = two_volumes_response result = volumes_client.get_list(**params) - volumes_client._client.request.assert_called_with(url="/volumes", method="GET", params=params) + volumes_client._client.request.assert_called_with( + url="/volumes", method="GET", params=params + ) bound_volumes = result.volumes assert result.meta is None @@ -167,14 +173,16 @@ def test_get_list(self, volumes_client, two_volumes_response, params): assert bound_volume2.id == 2 assert bound_volume2.name == "vault-storage" - @pytest.mark.parametrize("params", [{'label_selector': "label1"}]) + @pytest.mark.parametrize("params", [{"label_selector": "label1"}]) def test_get_all(self, volumes_client, two_volumes_response, params): volumes_client._client.request.return_value = two_volumes_response bound_volumes = volumes_client.get_all(**params) - params.update({'page': 1, 'per_page': 50}) + params.update({"page": 1, "per_page": 50}) - volumes_client._client.request.assert_called_with(url="/volumes", method="GET", params=params) + volumes_client._client.request.assert_called_with( + url="/volumes", method="GET", params=params + ) assert len(bound_volumes) == 2 @@ -193,9 +201,11 @@ def test_get_by_name(self, volumes_client, one_volumes_response): volumes_client._client.request.return_value = one_volumes_response bound_volume = volumes_client.get_by_name("database-storage") - params = {'name': "database-storage"} + params = {"name": "database-storage"} - volumes_client._client.request.assert_called_with(url="/volumes", method="GET", params=params) + volumes_client._client.request.assert_called_with( + url="/volumes", method="GET", params=params + ) assert bound_volume._client is volumes_client assert bound_volume.id == 1 @@ -208,18 +218,18 @@ def test_create_with_location(self, volumes_client, volume_create_response): "database-storage", location=Location(name="location"), automount=False, - format="xfs" + format="xfs", ) volumes_client._client.request.assert_called_with( url="/volumes", method="POST", json={ - 'name': "database-storage", - 'size': 100, - 'location': "location", - 'automount': False, - 'format': "xfs" - } + "name": "database-storage", + "size": 100, + "location": "location", + "automount": False, + "format": "xfs", + }, ) bound_volume = response.volume @@ -233,55 +243,56 @@ def test_create_with_location(self, volumes_client, volume_create_response): assert action.id == 13 assert next_actions[0].command == "start_server" - @pytest.mark.parametrize("server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "server", [Server(id=1), BoundServer(mock.MagicMock(), dict(id=1))] + ) def test_create_with_server(self, volumes_client, server, volume_create_response): volumes_client._client.request.return_value = volume_create_response volumes_client.create( - 100, - "database-storage", - server=server, - automount=False, - format="xfs" + 100, "database-storage", server=server, automount=False, format="xfs" ) volumes_client._client.request.assert_called_with( url="/volumes", method="POST", json={ - 'name': "database-storage", - 'size': 100, - 'server': 1, - 'automount': False, - 'format': "xfs" - } + "name": "database-storage", + "size": 100, + "server": 1, + "automount": False, + "format": "xfs", + }, ) def test_create_negative_size(self, volumes_client): with pytest.raises(ValueError) as e: volumes_client.create( - -100, - "database-storage", - location=Location(name="location") + -100, "database-storage", location=Location(name="location") ) assert str(e.value) == "size must be greater than 0" volumes_client._client.request.assert_not_called() - @pytest.mark.parametrize("location,server", [(None, None), ("location", Server(id=1))]) - def test_create_wrong_location_server_combination(self, volumes_client, location, server): + @pytest.mark.parametrize( + "location,server", [(None, None), ("location", Server(id=1))] + ) + def test_create_wrong_location_server_combination( + self, volumes_client, location, server + ): with pytest.raises(ValueError) as e: volumes_client.create( - 100, - "database-storage", - location=location, - server=server + 100, "database-storage", location=location, server=server ) assert str(e.value) == "only one of server or location must be provided" volumes_client._client.request.assert_not_called() - @pytest.mark.parametrize("volume", [Volume(id=1), BoundVolume(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "volume", [Volume(id=1), BoundVolume(mock.MagicMock(), dict(id=1))] + ) def test_get_actions_list(self, volumes_client, volume, response_get_actions): volumes_client._client.request.return_value = response_get_actions result = volumes_client.get_actions_list(volume, sort="id") - volumes_client._client.request.assert_called_with(url="/volumes/1/actions", method="GET", params={"sort": "id"}) + volumes_client._client.request.assert_called_with( + url="/volumes/1/actions", method="GET", params={"sort": "id"} + ) actions = result.actions assert len(actions) == 1 @@ -291,65 +302,85 @@ def test_get_actions_list(self, volumes_client, volume, response_get_actions): assert actions[0].id == 13 assert actions[0].command == "attach_volume" - @pytest.mark.parametrize("volume", [Volume(id=1), BoundVolume(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "volume", [Volume(id=1), BoundVolume(mock.MagicMock(), dict(id=1))] + ) def test_update(self, volumes_client, volume, response_update_volume): volumes_client._client.request.return_value = response_update_volume volume = volumes_client.update(volume, name="new-name") - volumes_client._client.request.assert_called_with(url="/volumes/1", method="PUT", json={"name": "new-name"}) + volumes_client._client.request.assert_called_with( + url="/volumes/1", method="PUT", json={"name": "new-name"} + ) assert volume.id == 4711 assert volume.name == "new-name" - @pytest.mark.parametrize("volume", [Volume(id=1), BoundVolume(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "volume", [Volume(id=1), BoundVolume(mock.MagicMock(), dict(id=1))] + ) def test_change_protection(self, volumes_client, volume, generic_action): volumes_client._client.request.return_value = generic_action action = volumes_client.change_protection(volume, True) - volumes_client._client.request.assert_called_with(url="/volumes/1/actions/change_protection", method="POST", json={"delete": True}) + volumes_client._client.request.assert_called_with( + url="/volumes/1/actions/change_protection", + method="POST", + json={"delete": True}, + ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("volume", [Volume(id=1), BoundVolume(mock.MagicMock(), dict(id=1))]) + @pytest.mark.parametrize( + "volume", [Volume(id=1), BoundVolume(mock.MagicMock(), dict(id=1))] + ) def test_delete(self, volumes_client, volume, generic_action): volumes_client._client.request.return_value = generic_action delete_success = volumes_client.delete(volume) - volumes_client._client.request.assert_called_with(url="/volumes/1", method="DELETE") + volumes_client._client.request.assert_called_with( + url="/volumes/1", method="DELETE" + ) assert delete_success is True - @pytest.mark.parametrize("server,volume", - [(Server(id=1), Volume(id=12)), - (BoundServer(mock.MagicMock(), dict(id=1)), BoundVolume(mock.MagicMock(), dict(id=12)))]) + @pytest.mark.parametrize( + "server,volume", + [ + (Server(id=1), Volume(id=12)), + ( + BoundServer(mock.MagicMock(), dict(id=1)), + BoundVolume(mock.MagicMock(), dict(id=12)), + ), + ], + ) def test_attach(self, volumes_client, server, volume, generic_action): volumes_client._client.request.return_value = generic_action action = volumes_client.attach(volume, server) volumes_client._client.request.assert_called_with( - url="/volumes/12/actions/attach", - method="POST", - json={"server": 1} + url="/volumes/12/actions/attach", method="POST", json={"server": 1} ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("volume", [Volume(id=12), BoundVolume(mock.MagicMock(), dict(id=12))]) + @pytest.mark.parametrize( + "volume", [Volume(id=12), BoundVolume(mock.MagicMock(), dict(id=12))] + ) def test_detach(self, volumes_client, volume, generic_action): volumes_client._client.request.return_value = generic_action action = volumes_client.detach(volume) volumes_client._client.request.assert_called_with( - url="/volumes/12/actions/detach", - method="POST" + url="/volumes/12/actions/detach", method="POST" ) assert action.id == 1 assert action.progress == 0 - @pytest.mark.parametrize("volume", [Volume(id=12), BoundVolume(mock.MagicMock(), dict(id=12))]) + @pytest.mark.parametrize( + "volume", [Volume(id=12), BoundVolume(mock.MagicMock(), dict(id=12))] + ) def test_resize(self, volumes_client, volume, generic_action): volumes_client._client.request.return_value = generic_action action = volumes_client.resize(volume, 50) volumes_client._client.request.assert_called_with( - url="/volumes/12/actions/resize", - method="POST", - json={"size": 50} + url="/volumes/12/actions/resize", method="POST", json={"size": 50} ) assert action.id == 1 assert action.progress == 0 diff --git a/tests/unit/volumes/test_domain.py b/tests/unit/volumes/test_domain.py index 100b988..6388628 100644 --- a/tests/unit/volumes/test_domain.py +++ b/tests/unit/volumes/test_domain.py @@ -5,7 +5,8 @@ class TestVolume(object): - def test_created_is_datetime(self): volume = Volume(id=1, created="2016-01-30T23:50+00:00") - assert volume.created == datetime.datetime(2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0)) + assert volume.created == datetime.datetime( + 2016, 1, 30, 23, 50, tzinfo=tzoffset(None, 0) + ) diff --git a/tox.ini b/tox.ini index 23f6700..d3d8780 100644 --- a/tox.ini +++ b/tox.ini @@ -6,6 +6,11 @@ basepython = python deps = flake8==3.6.0 commands = flake8 hcloud tests setup.py +[testenv:black] +basepython = python +deps = black==21.7b0 +commands = black . --check --diff + [testenv] passenv = FAKE_API_ENDPOINT deps =