summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--paramiko/config.py36
-rw-r--r--tests/test_config.py74
2 files changed, 109 insertions, 1 deletions
diff --git a/paramiko/config.py b/paramiko/config.py
index 21c9dab8..71973533 100644
--- a/paramiko/config.py
+++ b/paramiko/config.py
@@ -119,7 +119,7 @@ class SSHConfig(object):
if self._allowed(config["host"], hostname)
]
- ret = {}
+ ret = SSHConfigDict()
for match in matches:
for key, value in match["config"].items():
if key not in ret:
@@ -291,3 +291,37 @@ class LazyFqdn(object):
# Cache
self.fqdn = fqdn
return self.fqdn
+
+
+class SSHConfigDict(dict):
+ """
+ A dictionary wrapper for ssh host configurations.
+
+ This class introduces some usage niceties for consumers of SSHConfig,
+ specifically around the issue of variable type conversions. This offers
+ as_bool(key) and as_int(key) for the current raw string values in
+ SSHConfig
+ """
+
+ def __init__(self, *args, **kwargs):
+ # Hey, guess what? Python 2's userdict is an old-style class!
+ super(SSHConfigDict, self).__init__(*args, **kwargs)
+
+ def as_bool(self, key):
+ """
+ Express the key as a boolean value.
+
+ Variations on 'yes' or boolean values are accepted.
+ """
+ val = self[key]
+ if isinstance(val, bool):
+ return val
+ return val.lower() == 'yes'
+
+ def as_int(self, key):
+ """
+ Express the key as a true integer, if possible.
+
+ Raises an Error otherwise (following conventional int conversion rules)
+ """
+ return int(self[key])
diff --git a/tests/test_config.py b/tests/test_config.py
new file mode 100644
index 00000000..20f051fc
--- /dev/null
+++ b/tests/test_config.py
@@ -0,0 +1,74 @@
+# This file is part of Paramiko and subject to the license in /LICENSE in this
+# repository
+
+import pytest
+
+from paramiko import config
+from paramiko.util import parse_ssh_config
+from paramiko.py3compat import StringIO
+
+def test_SSHConfigDict_construct_empty():
+ assert not config.SSHConfigDict()
+
+
+def test_SSHConfigDict_construct_from_list():
+ assert config.SSHConfigDict([(1, 2)])[1] == 2
+
+
+def test_SSHConfigDict_construct_from_dict():
+ assert config.SSHConfigDict({1: 2})[1] == 2
+
+
+@pytest.mark.parametrize("true_ish", ("yes", "YES", "Yes", True))
+def test_SSHConfigDict_as_bool_true_ish(true_ish):
+ assert config.SSHConfigDict({"key": true_ish}).as_bool("key") is True
+
+
+@pytest.mark.parametrize("false_ish", ("no", "NO", "No", False))
+def test_SSHConfigDict_as_bool(false_ish):
+ assert config.SSHConfigDict({"key": false_ish}).as_bool("key") is False
+
+
+@pytest.mark.parametrize("int_val", ("42", 42))
+def test_SSHConfigDict_as_int(int_val):
+ assert config.SSHConfigDict({"key": int_val}).as_int("key") == 42
+
+
+@pytest.mark.parametrize("non_int", ("not an int", None, object()))
+def test_SSHConfigDict_as_int_failures(non_int):
+ conf = config.SSHConfigDict({"key": non_int})
+
+ try:
+ int(non_int)
+ except Exception as e:
+ exception_type = type(e)
+
+ with pytest.raises(exception_type):
+ conf.as_int("key")
+
+
+def test_SSHConfig_host_dicts_are_SSHConfigDict_instances():
+ test_config_file = """
+Host *.example.com
+ Port 2222
+
+Host *
+ Port 3333
+ """
+ f = StringIO(test_config_file)
+ config = parse_ssh_config(f)
+ assert config.lookup("foo.example.com").as_int("port") == 2222
+
+
+def test_SSHConfig_wildcard_host_dicts_are_SSHConfigDict_instances():
+ test_config_file = """\
+Host *.example.com
+ Port 2222
+
+Host *
+ Port 3333
+ """
+ f = StringIO(test_config_file)
+ config = parse_ssh_config(f)
+ assert config.lookup("anything-else").as_int("port") == 3333
+