annet 0.14.9__py3-none-any.whl → 0.14.10__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.

@@ -21,3 +21,6 @@ class NetboxQuery(Query):
21
21
  def globs(self):
22
22
  # We process every query host as a glob
23
23
  return self.query
24
+
25
+ def is_empty(self) -> bool:
26
+ return len(self.query) == 0
@@ -31,7 +31,7 @@ def compile_row_regexp(row, flags=0):
31
31
  row = row[:-3]
32
32
  elif "~/" in row:
33
33
  # ~/{regex}/ -> {regex}, () не нужны поскольку уже (?:) - non-captured
34
- row = re.sub(r"~/([^/]+)/", r"\1", row)
34
+ row = re.sub(r"~/(((?!~/).)+)/", r"\1", row)
35
35
  else:
36
36
  row += r"(?:\s|$)"
37
37
  row = re.sub(r"\s+", r"\\s+", row)
annet/cli.py CHANGED
@@ -1,25 +1,29 @@
1
1
  import argparse
2
+ import itertools
3
+ import json
2
4
  import operator
3
5
  import os
4
6
  import platform
5
7
  import subprocess
6
8
  import shutil
9
+ import sys
7
10
  from contextlib import ExitStack, contextmanager
8
11
  from typing import Tuple, Iterable
9
12
 
13
+ import tabulate
10
14
  import yaml
11
15
  from contextlog import get_logger
12
16
  from valkit.python import valid_logging_level
13
17
 
14
18
  from annet.deploy import driver_connector, fetcher_connector
15
- from annet import api, cli_args, filtering
19
+ from annet import api, cli_args, filtering, generators
16
20
  from annet.api import collapse_texts, Deployer
17
21
  from annet.argparse import ArgParser, subcommand
18
22
  from annet.diff import gen_sort_diff
19
23
  from annet.gen import Loader, old_raw
20
24
  from annet.lib import get_context_path, repair_context_file
21
25
  from annet.output import output_driver_connector, OutputDriver
22
- from annet.storage import get_storage
26
+ from annet.storage import get_storage, Device
23
27
 
24
28
 
25
29
  def fill_base_args(parser: ArgParser, pkg_name: str, logging_config: str):
@@ -60,14 +64,14 @@ def _gen_current_items(
60
64
 
61
65
 
62
66
  @contextmanager
63
- def get_loader(gen_args: cli_args.GenOptions, args: cli_args.QueryOptions):
67
+ def get_loader(gen_args: cli_args.GenOptions, args: cli_args.QueryOptionsBase):
64
68
  exit_stack = ExitStack()
65
69
  storages = []
66
70
  with exit_stack:
67
71
  connector, connector_opts = get_storage()
68
72
  storage_opts = connector.opts().parse_params(connector_opts, args)
69
73
  storages.append(exit_stack.enter_context(connector.storage()(storage_opts)))
70
- yield Loader(*storages, args=gen_args)
74
+ yield Loader(*storages, args=gen_args, no_empty_warning=args.query.is_empty())
71
75
 
72
76
 
73
77
  @subcommand(is_group=True)
@@ -120,6 +124,62 @@ def show_device_dump(args: cli_args.QueryOptions, arg_out: cli_args.FileOutOptio
120
124
  )
121
125
 
122
126
 
127
+ @subcommand(cli_args.ShowGeneratorsOptions, parent=show)
128
+ def show_generators(args: cli_args.ShowGeneratorsOptions):
129
+ """ List applicable generators (for a device if query is set) """
130
+ arg_gens = cli_args.GenOptions(args)
131
+ with get_loader(arg_gens, args) as loader:
132
+ device: Device | None = None
133
+ devices = loader.devices
134
+ if len(devices) == 1:
135
+ device = devices[0]
136
+ elif len(devices) > 1:
137
+ get_logger().error("cannot show generators for more than one device at once")
138
+ sys.exit(1)
139
+ elif len(devices) == 0 and not args.query.is_empty():
140
+ # the error message will be logged in get_loader()
141
+ sys.exit(1)
142
+
143
+ if not device:
144
+ found_generators = loader.iter_all_gens()
145
+ else:
146
+ found_generators = []
147
+ gens = loader.resolve_gens(loader.devices)
148
+ for g in gens.partial[device]:
149
+ acl_func = g.acl_safe if args.acl_safe else g.acl
150
+ if g.supports_device(device) and acl_func(device):
151
+ found_generators.append(g)
152
+ for g in gens.entire[device]:
153
+ if g.supports_device(device) and g.path(device):
154
+ found_generators.append(g)
155
+ for g in gens.json_fragment[device]:
156
+ if g.supports_device(device) and g.path(device) and g.acl(device):
157
+ found_generators.append(g)
158
+
159
+ output_data = []
160
+ for g in found_generators:
161
+ output_data.append({
162
+ "name": g.__class__.__name__,
163
+ "type": g.TYPE,
164
+ "tags": g.TAGS,
165
+ "module": g.__class__.__module__,
166
+ "description": generators.get_description(g.__class__),
167
+ })
168
+
169
+ if args.format == "json":
170
+ print(json.dumps(output_data))
171
+
172
+ elif args.format == "text":
173
+ keyfunc = operator.itemgetter("type")
174
+ for gen_type, gens in itertools.groupby(sorted(output_data, key=keyfunc, reverse=True), keyfunc):
175
+ print(tabulate.tabulate(
176
+ [(g["name"], ", ".join(g["tags"]), g["module"], g["description"]) for g in gens],
177
+ [f"{gen_type}-Class", "Tags", "Module", "Description"],
178
+ tablefmt="orgtbl",
179
+ ))
180
+ print()
181
+
182
+
123
183
  @subcommand(cli_args.ShowGenOptions)
124
184
  def gen(args: cli_args.ShowGenOptions):
125
185
  """ Generate configuration for devices """
annet/gen.py CHANGED
@@ -888,3 +888,6 @@ class Loader:
888
888
 
889
889
  def resolve_gens(self, devices: Iterable[Device]) -> DeviceGenerators:
890
890
  return self._gens.for_devices(devices)
891
+
892
+ def iter_all_gens(self) -> Iterator[BaseGenerator]:
893
+ return self._gens.iter_gens()
annet/implicit.py CHANGED
@@ -132,6 +132,14 @@ def _implicit_tree(device):
132
132
  !neighbor *
133
133
  no shutdown
134
134
  """
135
+ elif device.hw.Cisco:
136
+ if device.hw.Cisco.Catalyst:
137
+ # this configuration is not visible in running-config when enabled
138
+ text += r"""
139
+ # line console aaa config
140
+ !line con 0
141
+ authorization exec default
142
+ """
135
143
  return parse_text(text)
136
144
 
137
145
 
annet/storage.py CHANGED
@@ -75,10 +75,13 @@ class StorageOpts(abc.ABC):
75
75
 
76
76
  class Query(abc.ABC):
77
77
  @classmethod
78
- @abc.abstractclassmethod
78
+ @abc.abstractmethod
79
79
  def new(cls, query: Union[str, Iterable[str]], hosts_range: Optional[slice] = None) -> "Query":
80
80
  pass
81
81
 
82
+ def is_empty(self) -> bool:
83
+ return False
84
+
82
85
 
83
86
  class Device(Protocol):
84
87
  @property
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: annet
3
- Version: 0.14.9
3
+ Version: 0.14.10
4
4
  Summary: annet
5
5
  Home-page: https://github.com/annetutil/annet
6
6
  License: MIT
@@ -1,22 +1,22 @@
1
1
  annet/__init__.py,sha256=oyElxAW97sHgQccGafhaWVBveBn1gSjjdP_xHROaRLg,2139
2
2
  annet/annet.py,sha256=TMdEuM7GJQ4TjRVmuK3bCTZN-21lxjQ9sXqEdILUuBk,725
3
3
  annet/argparse.py,sha256=ZHKQriVCysSnox5stZnYxKLaPKzDjXbShxFyNW6LiiQ,12754
4
- annet/cli.py,sha256=aFFloyl5k2vz8mnm8Q2iwjAOUi4PTFWoVT9JszTkmHo,9969
4
+ annet/cli.py,sha256=yUStwwUKGgGuNw94EvabUEMhBs0YsIsc4omUivst8H0,12366
5
5
  annet/cli_args.py,sha256=_Du9Jhe86F4fsx7u9njjvg25jTdoBsdbTEzbuDFgrFU,13248
6
6
  annet/connectors.py,sha256=Xgr7fNopRhFAYnkiDxhohBtjlFOLY8v0xLExHmVMr00,2511
7
7
  annet/deploy.py,sha256=B8E0P_VvCrS2URjFvgmUiIkHp95g7pAWfmT34igaDeo,18893
8
8
  annet/diff.py,sha256=zLcaCnb4lZRUb7frpH1CstQ3kacRcCblZs1uLG8J5lk,3391
9
9
  annet/executor.py,sha256=FrYAUuh2TpSVX42SlTN_PhuSHmXG4Wj1nieY9Wqv9so,19122
10
10
  annet/filtering.py,sha256=F4ZKUCU3Yb1RlL2zKdyHtVUaWPzjWF4vWyMcdygKNYk,852
11
- annet/gen.py,sha256=jlAkT_phlIYrpOIqVc0GrApWp3Y8zr8lyxnZgIdL2F4,33533
11
+ annet/gen.py,sha256=8IPejduvYXmezUDolLKg4Imt1TxEp0KJ7kSgMtFcaCY,33628
12
12
  annet/hardware.py,sha256=HYPDfji_GdRn5S0_0fl4rvM7byOY9aHxG6VMAtsLaxE,1090
13
- annet/implicit.py,sha256=QigK4uoxvrFho2h9yFjOq1d9rLsC5xFlAU4bKkCuMWk,5139
13
+ annet/implicit.py,sha256=_3eY9NKqpLUm25vlJIP2cHN4gdTgzO6rG6mwCKJYMnQ,5439
14
14
  annet/lib.py,sha256=tQQlxZg1A2Q-tp18PoqBuORQmvP5dAAmAPvP6bBA6a0,3764
15
15
  annet/output.py,sha256=hJNGzL4Z3KgvqaCBkkmuuiXPhb64F1QV8YHkwnfhaaI,6852
16
16
  annet/parallel.py,sha256=hLkzEht0KhzmzUWDdO4QFYQHzhxs3wPlTA8DxbB2ziw,17160
17
17
  annet/patching.py,sha256=nILbY5oJajN0b1j3f0HEJm05H3HVThnWvB7vDVh7UQw,559
18
18
  annet/reference.py,sha256=B8mH8VUMcecPnzULiTVb_kTQ7jQrCL7zp4pfIZQa5fk,4035
19
- annet/storage.py,sha256=-l64yc0UfGR7Aqb3GlW18Kg1SJgIF1k6cf7-Ca4MhBc,3095
19
+ annet/storage.py,sha256=Wr_D_w7JQD08nD2IvC6bcGJLH6Uv62tKznUyWWWVW5Q,3144
20
20
  annet/tabparser.py,sha256=ZjiI43ZVbrpMVR8qNbTbNh_U3oZ26VDc_2Y9wkkDkYA,874
21
21
  annet/text_term_format.py,sha256=CHb6viv45vmYl-SK1A1vyPHGhaEni6jVybBusaQnct8,2813
22
22
  annet/tracing.py,sha256=ndpM-au1c88uBBpOuH_z52qWZL773edYozNyys_wA68,4044
@@ -28,7 +28,7 @@ annet/adapters/netbox/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
28
28
  annet/adapters/netbox/common/client.py,sha256=-lWZmphD-OPuLIHNKhW_h2bnjrVaiyKYAD_MUPasEbo,2483
29
29
  annet/adapters/netbox/common/manufacturer.py,sha256=i-1mXQheS4ORZav1_xYxMuGBWVWQHolZYkEXNdGyf0g,1361
30
30
  annet/adapters/netbox/common/models.py,sha256=Vgxbl_Mm-zOAi2BTlEzDppTTgZjafFEC5F9s_MTd_xU,3263
31
- annet/adapters/netbox/common/query.py,sha256=OgUuF-bvshpoBUkrOs0tsMUAhjTsttzx3VV30ryFl0Y,577
31
+ annet/adapters/netbox/common/query.py,sha256=ziUFM7cUEbEIf3k1szTll4aO-OCUa-2Ogxbebi7Tegs,646
32
32
  annet/adapters/netbox/common/status_client.py,sha256=W4nTb2yvBlJ2UkWUmUhKQ2PaSQb1shjhHj5ebb4s2s4,591
33
33
  annet/adapters/netbox/common/storage_opts.py,sha256=idOm1na_2Axdi4MdLN4tAsPvsp5zBtJYD9j7cUiI-W8,400
34
34
  annet/adapters/netbox/v24/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -58,7 +58,7 @@ annet/annlib/rbparser/acl.py,sha256=RR8yPt6t96_IiyuKVbeZ-3x32cyhBAT2wC1y99oWBO8,
58
58
  annet/annlib/rbparser/deploying.py,sha256=ACT8QNhDAhJx3ZKuGh2nYBOrpdka2qEKuLDxvQAGKLk,1649
59
59
  annet/annlib/rbparser/ordering.py,sha256=DiKqyY8Khz-5MTxNF1GSNtZgtyKwT3YYCXpahIPB6Ps,1779
60
60
  annet/annlib/rbparser/platform.py,sha256=iyqy4A-6vUKM4j6hrOA6tsgWBXk7LcvkFrS2QHgkqho,1231
61
- annet/annlib/rbparser/syntax.py,sha256=eEUmszwPjdw57aofUYNQVcaxHPNV9yx9JNapjYY-BGM,3572
61
+ annet/annlib/rbparser/syntax.py,sha256=iZ7Y-4QQBw4L3UtjEh54qisiRDhobl7HZxFNdP8mi54,3577
62
62
  annet/annlib/rulebook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
63
63
  annet/annlib/rulebook/common.py,sha256=9kCZwZpsH5UliF2OzaN9nLs2eLlz_d__4L7_oZ3SrCw,16054
64
64
  annet/api/__init__.py,sha256=-G9wlYePC3ZgNo1p8r17vmx0WLb3UNvCw3ZJ9UhYJ-I,33169
@@ -124,10 +124,10 @@ annet/rulebook/texts/routeros.rul,sha256=ipfxjj0mjFef6IsUlupqx4BY_Je_OUb8u_U1019
124
124
  annet_generators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
125
125
  annet_generators/example/__init__.py,sha256=zVd8_DrXuOASrNzg2Ab94rPyvJff83L-_HppDFxnUjM,228
126
126
  annet_generators/example/lldp.py,sha256=68CLrK7vxTQQy9XIBxtywuEdBNlIlfXGYj8_wYWs5UI,1146
127
- annet-0.14.9.dist-info/AUTHORS,sha256=rh3w5P6gEgqmuC-bw-HB68vBCr-yIBFhVL0PG4hguLs,878
128
- annet-0.14.9.dist-info/LICENSE,sha256=yPxl7dno02Pw7gAcFPIFONzx_gapwDoPXsIsh6Y7lC0,1079
129
- annet-0.14.9.dist-info/METADATA,sha256=8qSsN16lENPe9EcC4dGlPk2hN8JDX690OlbbBaoQ_pE,694
130
- annet-0.14.9.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
131
- annet-0.14.9.dist-info/entry_points.txt,sha256=yHimujIzR2bwNIbb--MTs_GpXiAve89Egpu2LlgTEkg,119
132
- annet-0.14.9.dist-info/top_level.txt,sha256=QsoTZBsUtwp_FEcmRwuN8QITBmLOZFqjssRfKilGbP8,23
133
- annet-0.14.9.dist-info/RECORD,,
127
+ annet-0.14.10.dist-info/AUTHORS,sha256=rh3w5P6gEgqmuC-bw-HB68vBCr-yIBFhVL0PG4hguLs,878
128
+ annet-0.14.10.dist-info/LICENSE,sha256=yPxl7dno02Pw7gAcFPIFONzx_gapwDoPXsIsh6Y7lC0,1079
129
+ annet-0.14.10.dist-info/METADATA,sha256=OvFvw8iDLiH6ZmTlDQIPwkONw9LHMEIcWldHqTtgAhA,695
130
+ annet-0.14.10.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
131
+ annet-0.14.10.dist-info/entry_points.txt,sha256=yHimujIzR2bwNIbb--MTs_GpXiAve89Egpu2LlgTEkg,119
132
+ annet-0.14.10.dist-info/top_level.txt,sha256=QsoTZBsUtwp_FEcmRwuN8QITBmLOZFqjssRfKilGbP8,23
133
+ annet-0.14.10.dist-info/RECORD,,