annet 3.10.0__py3-none-any.whl → 3.11.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of annet might be problematic. Click here for more details.

@@ -1,10 +1,11 @@
1
1
  import functools
2
2
  import json
3
3
  import re
4
- from os import path
4
+ from pathlib import Path
5
5
  from typing import Any, Dict
6
6
 
7
7
  from annet.annlib.netdev.db import find_true_sequences, get_db
8
+ from annet.lib import get_context
8
9
 
9
10
 
10
11
  @functools.lru_cache(None)
@@ -23,6 +24,7 @@ def _prepare_db() -> Dict[str, Any]:
23
24
  from library.python import resource
24
25
  raw = json.loads(resource.resfs_read("contrib/python/annet/annet/annlib/netdev/devdb/data/devdb.json").decode("utf-8"))
25
26
  except ImportError:
26
- with open(path.join(path.dirname(__file__), "data", "devdb.json"), "r") as f:
27
+ devdb_file = Path(get_context().get("devdb", {}).get("path", Path(__file__).parent / "data" / "devdb.json"))
28
+ with devdb_file.open("r", encoding="utf-8") as f:
27
29
  raw = json.load(f)
28
30
  return {tuple(seq.split(".")): re.compile(regexp) for (seq, regexp) in raw.items()}
@@ -1,7 +1,7 @@
1
1
  # pylint: disable=unused-argument
2
2
 
3
3
  from annet.annlib.types import Op
4
- from annet.executor import CommandList, Command
4
+ from annet.annlib.command import Command, CommandList
5
5
 
6
6
 
7
7
  def apply(hw, do_commit, do_finalize, **_):
@@ -64,8 +64,36 @@ class FormatterContext:
64
64
  return self.next and self.next[0]
65
65
 
66
66
 
67
+ class NotUniquePatch:
68
+ def __init__(self):
69
+ """In the case of comments, odict is not suitable: there may be several identical edit and exit"""
70
+ self._items = []
71
+ self._keys = set()
72
+
73
+ def __setitem__(self, key, value):
74
+ self._keys.add(key)
75
+ self._items.append((key, value))
76
+
77
+ def keys(self):
78
+ return list(self)
79
+
80
+ def items(self):
81
+ return self._items
82
+
83
+ def __contains__(self, item):
84
+ return item in self._keys
85
+
86
+ def __iter__(self):
87
+ return iter(item[0] for item in self._items)
88
+
89
+ def __bool__(self) -> bool:
90
+ return bool(self._items)
91
+
92
+
67
93
  # =====
68
94
  class CommonFormatter:
95
+ cmd_path_cls = odict
96
+
69
97
  def __init__(self, indent=" "):
70
98
  self._indent = indent
71
99
  self._block_begin = ""
@@ -96,7 +124,7 @@ class CommonFormatter:
96
124
  )
97
125
 
98
126
  def cmd_paths(self, patch: "PatchTree") -> odict:
99
- ret = odict()
127
+ ret = self.cmd_path_cls()
100
128
  path = []
101
129
  for row, context in self.blocks_and_context(patch, is_patch=True):
102
130
  if row is BlockBegin:
@@ -222,7 +250,20 @@ class BlockExitFormatter(CommonFormatter):
222
250
  yield exit_statement, last_row_context
223
251
 
224
252
 
253
+ class HuaweiPatch(NotUniquePatch):
254
+ policy_end_blocks = ("end-list", "endif", "end-filter")
255
+
256
+ def __setitem__(self, key, value):
257
+ if not key:
258
+ return
259
+
260
+ if key not in self or (key[0].startswith("xpl") and key[-1] in self.policy_end_blocks):
261
+ super().__setitem__(key, value)
262
+
263
+
225
264
  class HuaweiFormatter(BlockExitFormatter):
265
+ cmd_path_cls = HuaweiPatch
266
+
226
267
  def __init__(self, indent=" "):
227
268
  super().__init__(
228
269
  block_exit="quit",
@@ -237,9 +278,8 @@ class HuaweiFormatter(BlockExitFormatter):
237
278
  def split(self, text):
238
279
  # на старых прошивка наблюдается баг с двумя пробелами в этом месте в конфиге
239
280
  # например на VRP V100R006C00SPC500 + V100R006SPH003
240
- policy_end_blocks = ("end-list", "endif", "end-filter")
241
281
  tree = self.split_remove_spaces(text)
242
- tree[:] = filter(lambda x: not str(x).strip().startswith(policy_end_blocks), tree)
282
+ tree[:] = filter(lambda x: not str(x).strip().startswith(HuaweiPatch.policy_end_blocks), tree)
243
283
  return tree
244
284
 
245
285
  def block_exit(self, context: Optional[FormatterContext]):
@@ -256,7 +296,9 @@ class HuaweiFormatter(BlockExitFormatter):
256
296
  return
257
297
 
258
298
  if parent_row.startswith("xpl route-filter"):
259
- if (row.startswith(("if", "elseif")) and row.endswith("then")) and not row_next:
299
+ if (row.startswith(("if", "elseif")) and row.endswith("then")) and (
300
+ not row_next or not row_next.startswith(("elseif", "else"))
301
+ ):
260
302
  yield "endif"
261
303
  elif row == "else":
262
304
  yield "endif"
@@ -407,29 +449,9 @@ class AsrFormatter(BlockExitFormatter):
407
449
  yield from super().block_exit(context)
408
450
 
409
451
 
410
- class JuniperPatch:
411
- def __init__(self):
412
- """In the case of comments, odict is not suitable: there may be several identical edit and exit"""
413
- self._items = []
414
-
415
- def __setitem__(self, key, value):
416
- self._items.append((key, value))
417
-
418
- def keys(self):
419
- return list(self)
420
-
421
- def items(self):
422
- return self._items
423
-
424
- def __iter__(self):
425
- return iter(item[0] for item in self._items)
426
-
427
- def __bool__(self) -> bool:
428
- return bool(self._items)
429
-
430
-
431
452
  class JuniperFormatter(CommonFormatter):
432
453
  patch_set_prefix = "set"
454
+ cmd_path_cls = NotUniquePatch
433
455
 
434
456
  @dataclasses.dataclass
435
457
  class Comment:
@@ -526,7 +548,7 @@ class JuniperFormatter(CommonFormatter):
526
548
  yield line + self._statement_end
527
549
 
528
550
  def cmd_paths(self, patch, _prev=tuple()):
529
- commands = JuniperPatch()
551
+ commands = self.cmd_path_cls()
530
552
 
531
553
  for item in patch.itms:
532
554
  key, childs, context = item.row, item.child, item.context
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: annet
3
- Version: 3.10.0
3
+ Version: 3.11.0
4
4
  Summary: annet
5
5
  Home-page: https://github.com/annetutil/annet
6
6
  License: MIT
@@ -8,7 +8,6 @@ annet/connectors.py,sha256=aoiDVLPizx8CW2p8SAwGCzyO_WW8H9xc2aujbGC4bDg,4882
8
8
  annet/deploy.py,sha256=ZTZcomYm2KJkKMyG6XzZaAMPr-Tduwcv67BhsoLARkY,7673
9
9
  annet/deploy_ui.py,sha256=XsN1i7E9cNp1SAf1YBwhEBuwN91MvlNMSrLhnQrumA8,28672
10
10
  annet/diff.py,sha256=kD_2kxz5wc2TP10xj-BHs6IPq1yNKkXxIco8czjeC6M,9497
11
- annet/executor.py,sha256=INlWAZFLpHurg8GTXclbSzaeSIXgZo4ccmcRulQqr88,5130
12
11
  annet/filtering.py,sha256=ZtqxPsKdV9reZoRxtQyBg22BqyMqd-2SotYcxZ-68AQ,903
13
12
  annet/gen.py,sha256=y9e7P551uJ-thjBS2p-ZRMgwQa8kPF_JAoEXJ3am77Y,30683
14
13
  annet/hardware.py,sha256=O2uadehcavZ10ssPr-db3XYHK8cpbG7C7XFkO-I6r_s,1161
@@ -63,7 +62,7 @@ annet/annlib/patching.py,sha256=1bxlLDRx15GjB6aNk6kAx7t3WPPLHffYvSy7VLGnCig,2150
63
62
  annet/annlib/types.py,sha256=VHU0CBADfYmO0xzB_c5f-mcuU3dUumuJczQnqGlib9M,852
64
63
  annet/annlib/netdev/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
65
64
  annet/annlib/netdev/db.py,sha256=fI_u5aya4l61mbYSjj4JwlVfi3s7obt2jqERSuXGRUI,1634
66
- annet/annlib/netdev/devdb/__init__.py,sha256=aKYjjLbJebdKBjnGDpVLQdSqrV2JL24spGm58tmMWVU,892
65
+ annet/annlib/netdev/devdb/__init__.py,sha256=I-NKzenyjsmUKpmIerQOfZExnnnDpPdNZLdRanyu-Nk,1020
67
66
  annet/annlib/netdev/devdb/data/devdb.json,sha256=HI43va6tlOAFRSRnjXR7Ex32B4ZbRH0yvrjzud2apJM,7198
68
67
  annet/annlib/netdev/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
69
68
  annet/annlib/netdev/views/dump.py,sha256=rIlyvnA3uM8bB_7oq1nS2KDxTp6dQh2hz-FbNhYIpOU,4630
@@ -124,7 +123,7 @@ annet/rulebook/arista/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
124
123
  annet/rulebook/arista/aaa.py,sha256=7fBTwBnz9SOqYbwG8GBeEQTJG0e4uC4HkuZJeMG-kAY,2250
125
124
  annet/rulebook/arista/iface.py,sha256=bgj6a3r__-OE6VyYbSfnD6ps2QJKyX028W7IFJww-UY,720
126
125
  annet/rulebook/aruba/__init__.py,sha256=ILggeID6kNWcDBGzhXm_mebcfkuLSq5prBFU5DyPFs4,500
127
- annet/rulebook/aruba/ap_env.py,sha256=5fUVLhXH4-0DAtv8t0yoqJUibaRMuzF8Q7mGFzNsEN8,4692
126
+ annet/rulebook/aruba/ap_env.py,sha256=jkiDv-tYd6nsOdQPGTrh5XJIZQBNdVNVB25Tw-UbTnc,4698
128
127
  annet/rulebook/aruba/misc.py,sha256=O0p_wsR07gtB8rm1eJvJ7VYnGm5T8Uau_SVKR9FVInI,234
129
128
  annet/rulebook/b4com/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
130
129
  annet/rulebook/b4com/file.py,sha256=zK7RwBk1YaVoDSFSg1u7Pt8u0Fk3nhhu27aJRngemwc,137
@@ -184,7 +183,7 @@ annet/rulebook/texts/routeros.rul,sha256=ipfxjj0mjFef6IsUlupqx4BY_Je_OUb8u_U1019
184
183
  annet/vendors/__init__.py,sha256=gQcDFlKeWDZB6vxJ_MdPWEoE-C5dg-YgXvgGkuV9YLw,569
185
184
  annet/vendors/base.py,sha256=AmM3--gqC-Rpw5Xu_-hqthWZ9EoZRL8x6eOHwadZGbo,1145
186
185
  annet/vendors/registry.py,sha256=LgPg4oxWrgxsfpLpJ6OWEGFmUzlVlHzziSXsZTi82uc,2540
187
- annet/vendors/tabparser.py,sha256=EQrJb0Tz0Lj5byJ8Qr5fayYUCgKDgpJcAz4Smb2kxvs,32374
186
+ annet/vendors/tabparser.py,sha256=BXPYppgJf4OaobFrlpVr7APzG-NY6e0wwgGdp6YsVdU,32953
188
187
  annet/vendors/library/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
189
188
  annet/vendors/library/arista.py,sha256=J4ltZ7sS_TgIECg2U7fizvxwfS4-s35Of0tNDNWWYbE,1302
190
189
  annet/vendors/library/aruba.py,sha256=tvrSFSA43n0uelCv-NLQnqxO01d0y2mrfhncpOX7zoQ,1257
@@ -200,8 +199,8 @@ annet/vendors/library/optixtrans.py,sha256=VdME69Ca4HAEgoaKN21fZxnmmsqqaxOe_HZja
200
199
  annet/vendors/library/pc.py,sha256=vfv31_NPi7M-4AUDL89UcpawK2E6xvCpELA209cd1ho,1086
201
200
  annet/vendors/library/ribbon.py,sha256=DDOBq-_-FL9dCxqXs2inEWZ-pvw-dJ-A-prA7cKMhec,1216
202
201
  annet/vendors/library/routeros.py,sha256=iQa7m_4wjuvcgBOI9gyZwlw1BvzJfOkvUbyoEk-NI9I,1254
203
- annet-3.10.0.dist-info/licenses/AUTHORS,sha256=rh3w5P6gEgqmuC-bw-HB68vBCr-yIBFhVL0PG4hguLs,878
204
- annet-3.10.0.dist-info/licenses/LICENSE,sha256=yPxl7dno02Pw7gAcFPIFONzx_gapwDoPXsIsh6Y7lC0,1079
202
+ annet-3.11.0.dist-info/licenses/AUTHORS,sha256=rh3w5P6gEgqmuC-bw-HB68vBCr-yIBFhVL0PG4hguLs,878
203
+ annet-3.11.0.dist-info/licenses/LICENSE,sha256=yPxl7dno02Pw7gAcFPIFONzx_gapwDoPXsIsh6Y7lC0,1079
205
204
  annet_generators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
206
205
  annet_generators/example/__init__.py,sha256=OJ77uj8axc-FIyIu_Xdcnzmde3oQW5mk5qbODkhuVc8,355
207
206
  annet_generators/example/hostname.py,sha256=RloLzNVetEoWPLITzfJ13Nk3CC0yi-cZB1RTd6dnuhI,2541
@@ -214,8 +213,8 @@ annet_generators/rpl_example/generator.py,sha256=EWah19gOH8G-QyNyWqxCqdRi0BK7GbM
214
213
  annet_generators/rpl_example/items.py,sha256=HPgxScDvSqJPdz0c2SppDrH82DZYC4zUaniQwcWmh4A,1176
215
214
  annet_generators/rpl_example/mesh.py,sha256=z_WgfDZZ4xnyh3cSf75igyH09hGvtexEVwy1gCD_DzA,288
216
215
  annet_generators/rpl_example/route_policy.py,sha256=z6nPb0VDeQtKD1NIg9sFvmUxBD5tVs2frfNIuKdM-5c,2318
217
- annet-3.10.0.dist-info/METADATA,sha256=vNT4cNxluWuvug1t-yfWrqYFXmoijXsZNzXM2UUysUk,816
218
- annet-3.10.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
219
- annet-3.10.0.dist-info/entry_points.txt,sha256=5lIaDGlGi3l6QQ2ry2jZaqViP5Lvt8AmsegdD0Uznck,192
220
- annet-3.10.0.dist-info/top_level.txt,sha256=QsoTZBsUtwp_FEcmRwuN8QITBmLOZFqjssRfKilGbP8,23
221
- annet-3.10.0.dist-info/RECORD,,
216
+ annet-3.11.0.dist-info/METADATA,sha256=uYU_GEvY0GCOzto2G9wko7JhgNLj8tP09uUGSg5nP2s,816
217
+ annet-3.11.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
218
+ annet-3.11.0.dist-info/entry_points.txt,sha256=5lIaDGlGi3l6QQ2ry2jZaqViP5Lvt8AmsegdD0Uznck,192
219
+ annet-3.11.0.dist-info/top_level.txt,sha256=QsoTZBsUtwp_FEcmRwuN8QITBmLOZFqjssRfKilGbP8,23
220
+ annet-3.11.0.dist-info/RECORD,,
annet/executor.py DELETED
@@ -1,172 +0,0 @@
1
- import asyncio
2
- import os
3
- import statistics
4
- from abc import ABC, abstractmethod
5
- from functools import partial
6
- from operator import itemgetter
7
- from typing import Any, List, Optional
8
-
9
- import colorama
10
- from annet.annlib.command import Command, CommandList, Question # noqa: F401
11
-
12
-
13
- class CommandResult(ABC):
14
- @abstractmethod
15
- def get_out(self) -> str:
16
- pass
17
-
18
-
19
- class ExecutorException(Exception):
20
- def __init__(self, *args: List[Any], auxiliary: Optional[Any] = None, **kwargs: object):
21
- self.auxiliary = auxiliary
22
- super().__init__(*args, **kwargs)
23
-
24
- def __repr__(self) -> str:
25
- return "%s(args=%r,auxiliary=%s)" % (self.__class__.__name__, self.args, self.auxiliary)
26
-
27
-
28
- class ExecException(ExecutorException):
29
- def __init__(self, msg: str, cmd: str, res: str, **kwargs):
30
- super().__init__(**kwargs)
31
- self.args = msg, cmd, res
32
- self.kwargs = kwargs
33
- self.msg = msg
34
- self.cmd = cmd
35
- self.res = res
36
-
37
- def __str__(self) -> str:
38
- return str(self.msg)
39
-
40
- def __repr__(self) -> str:
41
- return "%s<%s, %s>" % (self.__class__.__name__, self.msg, self.cmd)
42
-
43
-
44
- class BadCommand(ExecException):
45
- pass
46
-
47
-
48
- class NonzeroRetcode(ExecException):
49
- pass
50
-
51
-
52
- class CommitException(ExecException):
53
- pass
54
-
55
-
56
- def _show_type_summary(caption, items, total, stat_items=None):
57
- if items:
58
- if not stat_items:
59
- stat = ""
60
- else:
61
- avg = statistics.mean(stat_items)
62
- stat = " %(min).1f/%(max).1f/%(avg).1f/%(stdev)s (min/max/avg/stdev)" % dict(
63
- min=min(stat_items),
64
- max=max(stat_items),
65
- avg=avg,
66
- stdev="-" if len(stat_items) < 2 else "%.1f" % statistics.stdev(stat_items, xbar=avg)
67
- )
68
-
69
- print("%-8s %d of %d%s" % (caption, len(items), total, stat))
70
-
71
-
72
- def show_bulk_report(hostnames, res, durations, log_dir):
73
- total = len(hostnames)
74
- if not total:
75
- return
76
-
77
- colorama.init()
78
-
79
- print("\n====== bulk deploy report ======")
80
-
81
- done = [host for (host, hres) in res.items() if not isinstance(hres, Exception)]
82
- cancelled = [host for (host, hres) in res.items() if isinstance(hres, asyncio.CancelledError)]
83
- failed = [host for (host, hres) in res.items() if isinstance(hres, Exception) and host not in cancelled]
84
- lost = [host for host in hostnames if host not in res]
85
- limit = 30
86
-
87
- _show_type_summary("Done :", done, total, [durations[h] for h in done])
88
- _print_limit(done, partial(_print_hostname, style=colorama.Fore.GREEN), limit, total)
89
-
90
- _show_type_summary("Failed :", failed, total, [durations[h] for h in failed])
91
-
92
- _print_limit(failed, partial(_print_failed, res=res), limit, total)
93
-
94
- _show_type_summary("Cancelled :", cancelled, total, [durations[h] for h in cancelled if durations[h] is not None])
95
- _print_limit(cancelled, partial(_print_hostname, style=colorama.Fore.RED), limit, total)
96
-
97
- _show_type_summary("Lost :", lost, total)
98
- _print_limit(lost, _print_hostname, limit, total)
99
-
100
- err_limit = 5
101
- if failed:
102
- errs = {}
103
- for hostname in failed:
104
- fmt_err = _format_exc(res[hostname])
105
- if fmt_err in errs:
106
- errs[fmt_err] += 1
107
- else:
108
- errs[fmt_err] = 1
109
- print("Top errors :")
110
- for fmt_err, n in sorted(errs.items(), key=itemgetter(1), reverse=True)[:err_limit]:
111
- print(" %-4d %s" % (n, fmt_err))
112
- print("\n", end="")
113
-
114
- if log_dir:
115
- print("See deploy logs in %s/\n" % os.path.relpath(log_dir))
116
-
117
-
118
- def _format_exc(exc):
119
- if isinstance(exc, ExecException):
120
- cmd = str(exc.cmd)
121
- if len(cmd) > 50:
122
- cmd = cmd[:50] + "~.."
123
- return "'%s', cmd '%s'" % (exc.msg, cmd)
124
- elif isinstance(exc, ExecutorException):
125
- return "%s%r" % (exc.__class__.__name__, exc.args) # исключить многословный auxiliary
126
- else:
127
- return repr(exc)
128
-
129
-
130
- def _print_hostname(host, style=None):
131
- if style:
132
- host = style + host + colorama.Style.RESET_ALL
133
- print(" %s" % host)
134
-
135
-
136
- def _print_limit(items, printer, limit, total, end="\n"):
137
- if not items:
138
- return
139
- if len(items) > limit and len(items) > total * 0.7:
140
- print(" ... %d hosts" % len(items))
141
- for host in items[:limit]:
142
- printer(host)
143
- if len(items) > limit:
144
- print(" ... %d more hosts" % (len(items) - limit))
145
-
146
- print(end, end="")
147
-
148
-
149
- def _print_failed(host, res):
150
- exc = res[host]
151
- color = colorama.Fore.YELLOW if isinstance(exc, Warning) else colorama.Fore.RED
152
- print(" %s - %s" % (color + host + colorama.Style.RESET_ALL, _format_exc(exc)))
153
-
154
-
155
- class DeferredFileWrite:
156
- def __init__(self, file, mode="r"):
157
- self._file = file
158
- wrapper = {"w": "a", "wb": "ab"}
159
- if mode in wrapper:
160
- self._mode = wrapper[mode]
161
- else:
162
- raise Exception()
163
-
164
- def write(self, data):
165
- with open(self._file, self._mode, encoding="utf-8") as fh:
166
- fh.write(data)
167
-
168
- def close(self):
169
- pass
170
-
171
- def flush(self):
172
- pass
File without changes