From 2830df9ee5357f01afb2d43bd196b10c7eb0f29f Mon Sep 17 00:00:00 2001 From: Aaron Hall Date: Thu, 12 Mar 2020 16:33:16 -0400 Subject: [PATCH 01/13] More mypy, fix a couple of return types --- nixops/backends/__init__.py | 48 +++++++++++++++++------------------- nixops/resources/__init__.py | 12 ++++----- nixops/util.py | 40 ++++++++++++++++-------------- 3 files changed, 50 insertions(+), 50 deletions(-) diff --git a/nixops/backends/__init__.py b/nixops/backends/__init__.py index e2ef1c168..43d6fff9d 100644 --- a/nixops/backends/__init__.py +++ b/nixops/backends/__init__.py @@ -3,7 +3,7 @@ import os import re import subprocess -from typing import Dict, Any, List, Optional +from typing import Dict, Any, List, Optional, Union import nixops.util import nixops.resources import nixops.ssh_util @@ -12,14 +12,12 @@ class MachineDefinition(nixops.resources.ResourceDefinition): """Base class for NixOps machine definitions.""" - def __init__(self, xml, config={}): + def __init__(self, xml, config={}) -> None: nixops.resources.ResourceDefinition.__init__(self, xml, config) - self.encrypted_links_to = set( - [ - e.get("value") - for e in xml.findall("attrs/attr[@name='encryptedLinksTo']/list/string") - ] - ) + self.encrypted_links_to = { + e.get("value") + for e in xml.findall("attrs/attr[@name='encryptedLinksTo']/list/string") + } self.store_keys_on_machine = ( xml.find("attrs/attr[@name='storeKeysOnMachine']/bool").get("value") == "true" @@ -37,7 +35,7 @@ def __init__(self, xml, config={}): == "true" ) - def _extract_key_options(x): + def _extract_key_options(x) -> Dict[str, Any]: opts = {} for (key, xmlType) in ( ("text", "string"), @@ -90,7 +88,7 @@ class MachineState(nixops.resources.ResourceState): # machine was created. state_version: Optional[str] = nixops.util.attr_property("stateVersion", None, str) - def __init__(self, depl, name: str, id: int): + def __init__(self, depl, name: str, id: int) -> None: nixops.resources.ResourceState.__init__(self, depl, name, id) self._ssh_pinged_this_time = False self.ssh = nixops.ssh_util.SSH(self.logger) @@ -100,15 +98,15 @@ def __init__(self, depl, name: str, id: int): self._ssh_private_key_file: Optional[str] = None self.new_toplevel: Optional[str] = None - def prefix_definition(self, attr): + def prefix_definition(self, attr) -> None: return attr @property - def started(self): + def started(self) -> bool: state = self.state return state == self.STARTING or state == self.UP - def set_common_state(self, defn): + def set_common_state(self, defn) -> None: self.store_keys_on_machine = defn.store_keys_on_machine self.keys = defn.keys self.ssh_port = defn.ssh_port @@ -116,15 +114,15 @@ def set_common_state(self, defn): if not self.has_fast_connection: self.ssh.enable_compression() - def stop(self): + def stop(self) -> None: """Stop this machine, if possible.""" self.warn("don't know how to stop machine ‘{0}’".format(self.name)) - def start(self): + def start(self) -> None: """Start this machine, if possible.""" pass - def get_load_avg(self): + def get_load_avg(self) -> Union[List[str], None]: """Get the load averages on the machine.""" try: res = ( @@ -141,13 +139,13 @@ def get_load_avg(self): # FIXME: Move this to ResourceState so that other kinds of # resources can be checked. - def check(self): + def check(self):# TODO -> CheckResult, but supertype ResourceState -> True """Check machine state.""" res = CheckResult() self._check(res) return res - def _check(self, res): + def _check(self, res): # TODO -> None but supertype ResourceState -> True avg = self.get_load_avg() if avg == None: if self.state == self.UP: @@ -199,7 +197,7 @@ def _check(self, res): continue res.failed_units.append(match.group(1)) - def restore(self, defn, backup_id, devices=[]): + def restore(self, defn, backup_id, devices: List=[]): """Restore persistent disks to a given backup, if possible.""" self.warn( "don't know how to restore disks from backup for machine ‘{0}’".format( @@ -223,7 +221,7 @@ def backup(self, defn, backup_id: str, devices: List[str] = []) -> None: "don't know how to make backup of disks for machine ‘{0}’".format(self.name) ) - def reboot(self, hard=False): + def reboot(self, hard: bool=False) -> None: """Reboot this machine.""" self.log("rebooting...") if self.state == self.RESCUE: @@ -237,7 +235,7 @@ def reboot(self, hard=False): self.state = self.STARTING self.ssh.reset() - def reboot_sync(self, hard=False): + def reboot_sync(self, hard: bool=False) -> None: """Reboot this machine and wait until it's up again.""" self.reboot(hard=hard) self.log_start("waiting for the machine to finish rebooting...") @@ -257,13 +255,13 @@ def reboot_sync(self, hard=False): self._ssh_pinged_this_time = True self.send_keys() - def reboot_rescue(self, hard=False): + def reboot_rescue(self, hard: bool=False) -> None: """ Reboot machine into rescue system and wait until it is active. """ self.warn("machine ‘{0}’ doesn't have a rescue" " system.".format(self.name)) - def send_keys(self): + def send_keys(self) -> None: if self.state == self.RESCUE: # Don't send keys when in RESCUE state, because we're most likely # bootstrapping plus we probably don't have /run mounted properly @@ -488,7 +486,7 @@ def get_console_output(self): class CheckResult(object): - def __init__(self): + def __init__(self) -> None: # Whether the resource exists. self.exists = None @@ -513,7 +511,7 @@ def __init__(self): self.load = None # Error messages. - self.messages = [] + self.messages: List[str] = [] # FIXME: add a check whether the active NixOS config on the # machine is correct. diff --git a/nixops/resources/__init__.py b/nixops/resources/__init__.py index 6af3215e6..b632dd773 100644 --- a/nixops/resources/__init__.py +++ b/nixops/resources/__init__.py @@ -3,7 +3,7 @@ import re import nixops.util from threading import Event -from typing import List, Optional, Dict +from typing import List, Optional, Dict, Any from nixops.state import StateDict from nixops.diff import Diff, Handler @@ -73,7 +73,7 @@ def __init__(self, depl, name: str, id): self.logger = depl.logger.get_logger_for(name) self.logger.register_index(self.index) - def _set_attrs(self, attrs): + def _set_attrs(self, attrs) -> None: """Update machine attributes in the state file.""" with self.depl._db: c = self.depl._db.cursor() @@ -89,11 +89,11 @@ def _set_attrs(self, attrs): (self.id, n, v), ) - def _set_attr(self, name, value): + def _set_attr(self, name, value) -> None: """Update one machine attribute in the state file.""" self._set_attrs({name: value}) - def _del_attr(self, name): + def _del_attr(self, name) -> None: """Delete a machine attribute from the state file.""" with self.depl._db: self.depl._db.execute( @@ -101,7 +101,7 @@ def _del_attr(self, name): (self.id, name), ) - def _get_attr(self, name, default=nixops.util.undefined): + def _get_attr(self, name, default=nixops.util.undefined) -> Any: """Get a machine attribute from the state file.""" with self.depl._db: c = self.depl._db.cursor() @@ -201,7 +201,7 @@ def create(self, defn, check, allow_reboot, allow_recreate): """Create or update the resource defined by ‘defn’.""" raise NotImplementedError("create") - def check(self): + def check(self): # TODO this return type is inconsistent with child class MachineState """ Reconcile the state file with the real world infrastructure state. This should not do any provisionning but just sync the state. diff --git a/nixops/util.py b/nixops/util.py index 78fe85fd3..051bf0a04 100644 --- a/nixops/util.py +++ b/nixops/util.py @@ -16,7 +16,7 @@ import logging import atexit import re -from typing import Callable, List, Optional, Any, IO, Union, Mapping, TextIO +from typing import Callable, List, Optional, Any, IO, Union, Mapping, TextIO, Tuple # the following ansi_ imports are for backwards compatability. They # would belong fine in this util.py, but having them in util.py @@ -51,7 +51,7 @@ def check_wait( class CommandFailed(Exception): - def __init__(self, message: str, exitcode: int): + def __init__(self, message: str, exitcode: int) -> None: self.message = message self.exitcode = exitcode @@ -202,7 +202,7 @@ def generate_random_string(length=256) -> str: return base64.b64encode(s).decode() -def make_non_blocking(fd: IO[Any]): +def make_non_blocking(fd: IO[Any]) -> None: fcntl.fcntl(fd, fcntl.F_SETFL, fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK) @@ -243,7 +243,7 @@ def wait_for_tcp_port( timeout: int = -1, open: bool = True, callback: Optional[Callable[[], Any]] = None, -): +) -> bool: """Wait until the specified TCP port is open or closed.""" n = 0 while True: @@ -270,7 +270,7 @@ def _maybe_abspath(s: str) -> str: return os.path.abspath(s) -def abs_nix_path(x): +def abs_nix_path(x) -> str: xs = x.split("=", 1) if len(xs) == 1: return _maybe_abspath(x) @@ -319,7 +319,7 @@ def set(self, x: Any) -> None: return property(get, set) -def create_key_pair(key_name="NixOps auto-generated key", type="ed25519"): +def create_key_pair(key_name="NixOps auto-generated key", type="ed25519") -> Tuple[str, str]: key_dir = tempfile.mkdtemp(prefix="nixops-key-tmp") res = subprocess.call( ["ssh-keygen", "-t", type, "-f", key_dir + "/key", "-N", "", "-C", key_name], @@ -338,30 +338,31 @@ def create_key_pair(key_name="NixOps auto-generated key", type="ed25519"): class SelfDeletingDir(str): - def __init__(self, s: str): + def __init__(self, s: str) -> None: str.__init__(s) atexit.register(self._delete) - def _delete(self): + def _delete(self) -> None: shutil.rmtree(self) class TeeStderr(StringIO): stderr: TextIO - def __init__(self): + def __init__(self) -> None: StringIO.__init__(self) self.stderr = sys.stderr self.logger = logging.getLogger("root") sys.stderr = self - def __del__(self): + def __del__(self) -> None: sys.stderr = self.stderr - def write(self, data): - self.stderr.write(data) + def write(self, data) -> int: + ret = self.stderr.write(data) for l in data.split("\n"): self.logger.warning(l) + return ret def fileno(self) -> int: return self.stderr.fileno() @@ -369,26 +370,27 @@ def fileno(self) -> int: def isatty(self) -> bool: return self.stderr.isatty() - def flush(self): + def flush(self) -> None: return self.stderr.flush() class TeeStdout(StringIO): stdout: TextIO - def __init__(self): + def __init__(self) -> None: StringIO.__init__(self) self.stdout = sys.stdout self.logger = logging.getLogger("root") sys.stdout = self - def __del__(self): + def __del__(self) -> None: sys.stdout = self.stdout - def write(self, data): - self.stdout.write(data) + def write(self, data) -> int: + ret = self.stdout.write(data) for l in data.split("\n"): self.logger.info(l) + return ret def fileno(self) -> int: return self.stdout.fileno() @@ -396,7 +398,7 @@ def fileno(self) -> int: def isatty(self) -> bool: return self.stdout.isatty() - def flush(self): + def flush(self) -> None: return self.stdout.flush() @@ -425,7 +427,7 @@ def enum(**enums): return type("Enum", (), enums) -def write_file(path: str, contents: str): +def write_file(path: str, contents: str) -> None: f = open(path, "w") f.write(contents) f.close() From 78aef4833728bcc6d8e11b1b842d4cc60d03d78c Mon Sep 17 00:00:00 2001 From: "Aaron Hall, MBA" Date: Thu, 12 Mar 2020 22:01:46 -0400 Subject: [PATCH 02/13] Update nixops/util.py Co-Authored-By: Graham Christensen --- nixops/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nixops/util.py b/nixops/util.py index 051bf0a04..7b8f624d1 100644 --- a/nixops/util.py +++ b/nixops/util.py @@ -270,7 +270,7 @@ def _maybe_abspath(s: str) -> str: return os.path.abspath(s) -def abs_nix_path(x) -> str: +def abs_nix_path(x: str) -> str: xs = x.split("=", 1) if len(xs) == 1: return _maybe_abspath(x) From d31e984f3019697496f8ef13c91c8c946051875e Mon Sep 17 00:00:00 2001 From: "Aaron Hall, MBA" Date: Thu, 12 Mar 2020 22:02:05 -0400 Subject: [PATCH 03/13] Update nixops/resources/__init__.py Co-Authored-By: Graham Christensen --- nixops/resources/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nixops/resources/__init__.py b/nixops/resources/__init__.py index b632dd773..f1b58e249 100644 --- a/nixops/resources/__init__.py +++ b/nixops/resources/__init__.py @@ -101,7 +101,7 @@ def _del_attr(self, name) -> None: (self.id, name), ) - def _get_attr(self, name, default=nixops.util.undefined) -> Any: + def _get_attr(self, name: str, default=nixops.util.undefined) -> Any: """Get a machine attribute from the state file.""" with self.depl._db: c = self.depl._db.cursor() From eb938ebfa048352c33d19c879b58715a05be98d4 Mon Sep 17 00:00:00 2001 From: "Aaron Hall, MBA" Date: Thu, 12 Mar 2020 22:02:20 -0400 Subject: [PATCH 04/13] Update nixops/resources/__init__.py Co-Authored-By: Graham Christensen --- nixops/resources/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nixops/resources/__init__.py b/nixops/resources/__init__.py index f1b58e249..d268a5cb3 100644 --- a/nixops/resources/__init__.py +++ b/nixops/resources/__init__.py @@ -89,7 +89,7 @@ def _set_attrs(self, attrs) -> None: (self.id, n, v), ) - def _set_attr(self, name, value) -> None: + def _set_attr(self, name: str, value: Any) -> None: """Update one machine attribute in the state file.""" self._set_attrs({name: value}) From be60a787676ce770e96bd58b799df44bd6d1b95b Mon Sep 17 00:00:00 2001 From: "Aaron Hall, MBA" Date: Thu, 12 Mar 2020 22:02:41 -0400 Subject: [PATCH 05/13] Update nixops/resources/__init__.py Co-Authored-By: Graham Christensen --- nixops/resources/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nixops/resources/__init__.py b/nixops/resources/__init__.py index d268a5cb3..270053fb9 100644 --- a/nixops/resources/__init__.py +++ b/nixops/resources/__init__.py @@ -73,7 +73,7 @@ def __init__(self, depl, name: str, id): self.logger = depl.logger.get_logger_for(name) self.logger.register_index(self.index) - def _set_attrs(self, attrs) -> None: + def _set_attrs(self, attrs: Dict[str, Any]) -> None: """Update machine attributes in the state file.""" with self.depl._db: c = self.depl._db.cursor() From 1a46eac8905752750e052a55c5073b3ae3e6cace Mon Sep 17 00:00:00 2001 From: "Aaron Hall, MBA" Date: Thu, 12 Mar 2020 22:03:20 -0400 Subject: [PATCH 06/13] Update nixops/resources/__init__.py Co-Authored-By: Graham Christensen --- nixops/resources/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nixops/resources/__init__.py b/nixops/resources/__init__.py index 270053fb9..a28198737 100644 --- a/nixops/resources/__init__.py +++ b/nixops/resources/__init__.py @@ -93,7 +93,7 @@ def _set_attr(self, name: str, value: Any) -> None: """Update one machine attribute in the state file.""" self._set_attrs({name: value}) - def _del_attr(self, name) -> None: + def _del_attr(self, name: str) -> None: """Delete a machine attribute from the state file.""" with self.depl._db: self.depl._db.execute( From d19596565e1af4def692a99c314e9ed2a6ed6880 Mon Sep 17 00:00:00 2001 From: "Aaron Hall, MBA" Date: Thu, 12 Mar 2020 22:03:41 -0400 Subject: [PATCH 07/13] Update nixops/backends/__init__.py Co-Authored-By: Graham Christensen --- nixops/backends/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nixops/backends/__init__.py b/nixops/backends/__init__.py index 43d6fff9d..275cac492 100644 --- a/nixops/backends/__init__.py +++ b/nixops/backends/__init__.py @@ -197,7 +197,7 @@ def _check(self, res): # TODO -> None but supertype ResourceState -> True continue res.failed_units.append(match.group(1)) - def restore(self, defn, backup_id, devices: List=[]): + def restore(self, defn, backup_id: str, devices: List[str]=[]): """Restore persistent disks to a given backup, if possible.""" self.warn( "don't know how to restore disks from backup for machine ‘{0}’".format( From 17ce46343f2fa159cfbf79d8240dbc9dcf870efc Mon Sep 17 00:00:00 2001 From: "Aaron Hall, MBA" Date: Thu, 12 Mar 2020 22:22:43 -0400 Subject: [PATCH 08/13] addressing comments, None and str back out one silly None and narrow an Any to str --- nixops/backends/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nixops/backends/__init__.py b/nixops/backends/__init__.py index 275cac492..33ec1b7cb 100644 --- a/nixops/backends/__init__.py +++ b/nixops/backends/__init__.py @@ -35,7 +35,7 @@ def __init__(self, xml, config={}) -> None: == "true" ) - def _extract_key_options(x) -> Dict[str, Any]: + def _extract_key_options(x) -> Dict[str, str]: opts = {} for (key, xmlType) in ( ("text", "string"), @@ -98,7 +98,7 @@ def __init__(self, depl, name: str, id: int) -> None: self._ssh_private_key_file: Optional[str] = None self.new_toplevel: Optional[str] = None - def prefix_definition(self, attr) -> None: + def prefix_definition(self, attr): return attr @property From 2837060a5e604fa272a61ee80a2ef9682eb22292 Mon Sep 17 00:00:00 2001 From: Aaron Hall Date: Thu, 12 Mar 2020 22:51:38 -0400 Subject: [PATCH 09/13] str to Optional[str] for restore id arg type --- nixops/backends/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nixops/backends/__init__.py b/nixops/backends/__init__.py index 33ec1b7cb..45a1f9803 100644 --- a/nixops/backends/__init__.py +++ b/nixops/backends/__init__.py @@ -197,7 +197,7 @@ def _check(self, res): # TODO -> None but supertype ResourceState -> True continue res.failed_units.append(match.group(1)) - def restore(self, defn, backup_id: str, devices: List[str]=[]): + def restore(self, defn, backup_id: Optional[str], devices: List[str]=[]): """Restore persistent disks to a given backup, if possible.""" self.warn( "don't know how to restore disks from backup for machine ‘{0}’".format( From e2229398f2a2a93e45d70bb86be3760f889e2eba Mon Sep 17 00:00:00 2001 From: Aaron Hall Date: Fri, 13 Mar 2020 09:22:35 -0400 Subject: [PATCH 10/13] black these files --- nixops/backends/__init__.py | 12 ++++++------ nixops/resources/__init__.py | 4 +++- nixops/util.py | 4 +++- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/nixops/backends/__init__.py b/nixops/backends/__init__.py index 45a1f9803..4ea7f7d00 100644 --- a/nixops/backends/__init__.py +++ b/nixops/backends/__init__.py @@ -139,13 +139,13 @@ def get_load_avg(self) -> Union[List[str], None]: # FIXME: Move this to ResourceState so that other kinds of # resources can be checked. - def check(self):# TODO -> CheckResult, but supertype ResourceState -> True + def check(self): # TODO -> CheckResult, but supertype ResourceState -> True """Check machine state.""" res = CheckResult() self._check(res) return res - def _check(self, res): # TODO -> None but supertype ResourceState -> True + def _check(self, res): # TODO -> None but supertype ResourceState -> True avg = self.get_load_avg() if avg == None: if self.state == self.UP: @@ -197,7 +197,7 @@ def _check(self, res): # TODO -> None but supertype ResourceState -> True continue res.failed_units.append(match.group(1)) - def restore(self, defn, backup_id: Optional[str], devices: List[str]=[]): + def restore(self, defn, backup_id: Optional[str], devices: List[str] = []): """Restore persistent disks to a given backup, if possible.""" self.warn( "don't know how to restore disks from backup for machine ‘{0}’".format( @@ -221,7 +221,7 @@ def backup(self, defn, backup_id: str, devices: List[str] = []) -> None: "don't know how to make backup of disks for machine ‘{0}’".format(self.name) ) - def reboot(self, hard: bool=False) -> None: + def reboot(self, hard: bool = False) -> None: """Reboot this machine.""" self.log("rebooting...") if self.state == self.RESCUE: @@ -235,7 +235,7 @@ def reboot(self, hard: bool=False) -> None: self.state = self.STARTING self.ssh.reset() - def reboot_sync(self, hard: bool=False) -> None: + def reboot_sync(self, hard: bool = False) -> None: """Reboot this machine and wait until it's up again.""" self.reboot(hard=hard) self.log_start("waiting for the machine to finish rebooting...") @@ -255,7 +255,7 @@ def reboot_sync(self, hard: bool=False) -> None: self._ssh_pinged_this_time = True self.send_keys() - def reboot_rescue(self, hard: bool=False) -> None: + def reboot_rescue(self, hard: bool = False) -> None: """ Reboot machine into rescue system and wait until it is active. """ diff --git a/nixops/resources/__init__.py b/nixops/resources/__init__.py index a28198737..ad096b8e0 100644 --- a/nixops/resources/__init__.py +++ b/nixops/resources/__init__.py @@ -201,7 +201,9 @@ def create(self, defn, check, allow_reboot, allow_recreate): """Create or update the resource defined by ‘defn’.""" raise NotImplementedError("create") - def check(self): # TODO this return type is inconsistent with child class MachineState + def check( + self + ): # TODO this return type is inconsistent with child class MachineState """ Reconcile the state file with the real world infrastructure state. This should not do any provisionning but just sync the state. diff --git a/nixops/util.py b/nixops/util.py index 7b8f624d1..53c64b2c0 100644 --- a/nixops/util.py +++ b/nixops/util.py @@ -319,7 +319,9 @@ def set(self, x: Any) -> None: return property(get, set) -def create_key_pair(key_name="NixOps auto-generated key", type="ed25519") -> Tuple[str, str]: +def create_key_pair( + key_name="NixOps auto-generated key", type="ed25519" +) -> Tuple[str, str]: key_dir = tempfile.mkdtemp(prefix="nixops-key-tmp") res = subprocess.call( ["ssh-keygen", "-t", type, "-f", key_dir + "/key", "-N", "", "-C", key_name], From 5b4813a7058aff7faa7cd38f5fcd364148ea8208 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Fri, 13 Mar 2020 09:35:50 -0400 Subject: [PATCH 11/13] backend: encrypted_links_to: prove that it is a set --- nixops/backends/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nixops/backends/__init__.py b/nixops/backends/__init__.py index 4ea7f7d00..3a8d3d0a0 100644 --- a/nixops/backends/__init__.py +++ b/nixops/backends/__init__.py @@ -3,7 +3,7 @@ import os import re import subprocess -from typing import Dict, Any, List, Optional, Union +from typing import Dict, Any, List, Optional, Union, Set import nixops.util import nixops.resources import nixops.ssh_util @@ -14,7 +14,7 @@ class MachineDefinition(nixops.resources.ResourceDefinition): def __init__(self, xml, config={}) -> None: nixops.resources.ResourceDefinition.__init__(self, xml, config) - self.encrypted_links_to = { + self.encrypted_links_to: Set[str] = { e.get("value") for e in xml.findall("attrs/attr[@name='encryptedLinksTo']/list/string") } From b2e42a14f039feeb54ea51acaf5fbba7fd033a5f Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Fri, 13 Mar 2020 09:37:36 -0400 Subject: [PATCH 12/13] backend: extract_key_options: type ET.Element --- nixops/backends/__init__.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/nixops/backends/__init__.py b/nixops/backends/__init__.py index 3a8d3d0a0..22b5da0bb 100644 --- a/nixops/backends/__init__.py +++ b/nixops/backends/__init__.py @@ -7,7 +7,7 @@ import nixops.util import nixops.resources import nixops.ssh_util - +import xml.etree.ElementTree as ET class MachineDefinition(nixops.resources.ResourceDefinition): """Base class for NixOps machine definitions.""" @@ -35,7 +35,7 @@ def __init__(self, xml, config={}) -> None: == "true" ) - def _extract_key_options(x) -> Dict[str, str]: + def _extract_key_options(x: ET.Element) -> Dict[str, str]: opts = {} for (key, xmlType) in ( ("text", "string"), @@ -47,7 +47,9 @@ def _extract_key_options(x) -> Dict[str, str]: ): elem = x.find("attrs/attr[@name='{0}']/{1}".format(key, xmlType)) if elem is not None: - opts[key] = elem.get("value") + value = elem.get("value") + if value is not None: + opts[key] = value return opts self.keys = { From faa9764beaf98af2f2e73a86954f60664c1f2cb1 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Fri, 13 Mar 2020 09:42:29 -0400 Subject: [PATCH 13/13] Format with black --- nixops/backends/__init__.py | 1 + nixops/resources/__init__.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/nixops/backends/__init__.py b/nixops/backends/__init__.py index 22b5da0bb..6e792f60a 100644 --- a/nixops/backends/__init__.py +++ b/nixops/backends/__init__.py @@ -9,6 +9,7 @@ import nixops.ssh_util import xml.etree.ElementTree as ET + class MachineDefinition(nixops.resources.ResourceDefinition): """Base class for NixOps machine definitions.""" diff --git a/nixops/resources/__init__.py b/nixops/resources/__init__.py index ad096b8e0..04d096516 100644 --- a/nixops/resources/__init__.py +++ b/nixops/resources/__init__.py @@ -202,7 +202,7 @@ def create(self, defn, check, allow_reboot, allow_recreate): raise NotImplementedError("create") def check( - self + self, ): # TODO this return type is inconsistent with child class MachineState """ Reconcile the state file with the real world infrastructure state.