|
1 | 1 | """module providing dictionary interface for multi_connection.""" |
2 | 2 |
|
3 | 3 | import logging |
| 4 | +from copy import copy |
4 | 5 | from typing import (TYPE_CHECKING, Dict, ItemsView, KeysView, Optional, Tuple, |
5 | | - Union, ValuesView) |
| 6 | + Union, ValuesView, TypeVar) |
6 | 7 |
|
7 | 8 | if TYPE_CHECKING: |
8 | 9 | from ..local import LocalConnection |
9 | 10 | from ..remote import SSHConnection |
10 | 11 | from .multi_connection import MultiConnection |
11 | 12 |
|
12 | 13 | _CONN = Union[SSHConnection, LocalConnection] |
13 | | - |
| 14 | + _DictInterface1 = TypeVar("_DictInterface1") |
14 | 15 |
|
15 | 16 | log = logging.getLogger(__name__) |
16 | 17 |
|
@@ -47,46 +48,151 @@ def __len__(self) -> int: |
47 | 48 | return len(self._connections) |
48 | 49 |
|
49 | 50 | def keys(self) -> KeysView[str]: |
| 51 | + """Iterate over registered key same as `dict.keys` method. |
| 52 | +
|
| 53 | + Yields |
| 54 | + ------ |
| 55 | + KeysView[str] |
| 56 | + key |
| 57 | + """ |
50 | 58 | return self._connections.keys() |
51 | 59 |
|
52 | 60 | def values(self) -> ValuesView["_CONN"]: |
| 61 | + """Iterate over registered Connections same as `dict.values` method. |
| 62 | +
|
| 63 | + Yields |
| 64 | + ------ |
| 65 | + ValuesView[_CONN] |
| 66 | + `SSHConnection`/`LocalConnection` |
| 67 | + """ |
53 | 68 | return self._connections.values() |
54 | 69 |
|
55 | 70 | def items(self) -> ItemsView[str, "_CONN"]: |
| 71 | + """Iterate over key, Connection pairs same as `dict.items` method. |
| 72 | +
|
| 73 | + Yields |
| 74 | + ------ |
| 75 | + ItemsView[str, _CONN] |
| 76 | + key, `SSHConnection`/`LocalConnection` |
| 77 | + """ |
56 | 78 | return self._connections.items() |
57 | 79 |
|
58 | 80 | def pop(self, key: str, *args) -> "_CONN": |
| 81 | + """Pop one connection from `MultiConnection` object based on key. |
| 82 | +
|
| 83 | + Parameters |
| 84 | + ---------- |
| 85 | + key: str |
| 86 | + key denoting the connection |
| 87 | + default: Any, optional |
| 88 | + optianal value returned if key is not pressent |
| 89 | +
|
| 90 | + Returns |
| 91 | + ------- |
| 92 | + _CONN |
| 93 | + `SSHConnection` or `LocalConnection` object |
| 94 | +
|
| 95 | + Raises |
| 96 | + ------ |
| 97 | + AttributeError |
| 98 | + if the input key is not present among the connections and default |
| 99 | + is not defined. |
| 100 | + """ |
59 | 101 | conn = self._connections.pop(key, *args) |
60 | 102 | self._share_connection.pop(key, *args) |
61 | 103 | return conn |
62 | 104 |
|
63 | 105 | def popitem(self) -> Tuple[str, "_CONN"]: |
| 106 | + """Pops one key, connection pair from `MultiConnection`. |
| 107 | +
|
| 108 | + Returns |
| 109 | + ------- |
| 110 | + Tuple[str, _CONN] |
| 111 | + key, `SSHConnection`/`LocalConnection` pair |
| 112 | + """ |
64 | 113 | key, conn = self._connections.popitem() |
65 | 114 | self._share_connection.pop(key, None) |
66 | 115 | return key, conn |
67 | 116 |
|
68 | 117 | def update(self, other: "MultiConnection"): |
| 118 | + """Updates `Multiconnection` with another `Multiconnection`. |
| 119 | +
|
| 120 | + This only merges underlying dictionaries holding connections |
| 121 | +
|
| 122 | + Parameters |
| 123 | + ---------- |
| 124 | + other : `MultiConnection` |
| 125 | + the added object of same type as self |
| 126 | + """ |
69 | 127 | self._add_multi(other) |
70 | 128 |
|
71 | 129 | def get(self, key: str, *args) -> Optional["_CONN"]: |
| 130 | + """Get one connection from `MultiConnection` object based on key. |
| 131 | +
|
| 132 | + Parameters |
| 133 | + ---------- |
| 134 | + key: str |
| 135 | + key denoting the connection |
| 136 | + default: Any, optional |
| 137 | + optianal value returned if key is not pressent |
| 138 | +
|
| 139 | + Returns |
| 140 | + ------- |
| 141 | + _CONN |
| 142 | + `SSHConnection` or `LocalConnection` object shallow copy |
| 143 | +
|
| 144 | + Raises |
| 145 | + ------ |
| 146 | + AttributeError |
| 147 | + if the input key is not present among the connections and default |
| 148 | + is not defined. |
| 149 | + """ |
72 | 150 | return self._connections.get(key, *args) |
73 | 151 |
|
74 | | - def copy(self): |
75 | | - return self |
| 152 | + def copy(self: "_DictInterface1") -> "_DictInterface1": |
| 153 | + """Get a shallow copy of `MultiConnection`. |
| 154 | +
|
| 155 | + Returns |
| 156 | + ------- |
| 157 | + `MultiConnection` |
| 158 | + MultiConnection object shallow copy |
| 159 | + """ |
| 160 | + return copy(self) |
76 | 161 |
|
77 | 162 | def clear(self): |
| 163 | + """Close and delete all underlying connections.""" |
78 | 164 | self.close() |
79 | 165 | self._connections.clear() |
80 | 166 | self._share_connection.clear() |
81 | 167 | self.pool.shutdown() |
82 | 168 |
|
83 | 169 | def _add_one(self, other: "_CONN", |
84 | 170 | key: Optional[str] = None): |
85 | | - |
| 171 | + """Add one connecction to the undelying dictionary. |
| 172 | +
|
| 173 | + Parameters |
| 174 | + ---------- |
| 175 | + other: _CONN |
| 176 | + `SSHConnection` or `LocalConnection` |
| 177 | + key: Optional[str] |
| 178 | + if used connection is added under this key, else key is extracted |
| 179 | + from `connection.server_name` attribute |
| 180 | +
|
| 181 | + Raises |
| 182 | + ------ |
| 183 | + AttributeError |
| 184 | + if key is already pressent among registered connections |
| 185 | + """ |
86 | 186 | if key is None: |
87 | 187 | key = other.server_name.lower() |
| 188 | + |
| 189 | + if key in self.keys(): |
| 190 | + raise KeyError(f"Cannot register new Connection under key: {key}, " |
| 191 | + f"change Connection.server_name attribute or pass " |
| 192 | + f"in another key") |
88 | 193 | self._connections.update({key: other}) |
89 | 194 |
|
90 | 195 | def _add_multi(self, other: "MultiConnection"): |
| 196 | + """Register multiple new connections.""" |
91 | 197 | self._share_connection.update(other._share_connection) |
92 | 198 | self._connections.update(other._connections) |
0 commit comments