annet 0.15.2__py3-none-any.whl → 0.15.3__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,6 +1,8 @@
1
1
  import os
2
2
  from typing import Any
3
3
 
4
+ DEFAULT_URL = "http://localhost"
5
+
4
6
 
5
7
  class NetboxStorageOpts:
6
8
  def __init__(self, url: str, token: str):
@@ -9,7 +11,6 @@ class NetboxStorageOpts:
9
11
 
10
12
  @classmethod
11
13
  def parse_params(cls, conf_params: dict[str, str] | None, cli_opts: Any):
12
- return cls(
13
- url=os.getenv("NETBOX_URL", "http://localhost"),
14
- token=os.getenv("NETBOX_TOKEN", "").strip(),
15
- )
14
+ url = os.getenv("NETBOX_URL") or conf_params.get("url") or DEFAULT_URL
15
+ token = os.getenv("NETBOX_TOKEN", "").strip() or conf_params.get("token") or ""
16
+ return cls(url=url, token=token)
@@ -1,6 +1,9 @@
1
+ from typing import Dict, Any, Optional
2
+
1
3
  from dataclass_rest.exceptions import ClientError
2
4
 
3
5
  from annet.storage import StorageProvider, Storage
6
+ from annet.connectors import AdapterWithName, AdapterWithConfig, T
4
7
  from .common.status_client import NetboxStatusClient
5
8
  from .common.storage_opts import NetboxStorageOpts
6
9
  from .common.query import NetboxQuery
@@ -23,7 +26,14 @@ def storage_factory(opts: NetboxStorageOpts) -> Storage:
23
26
  raise ValueError(f"Unsupported version: {status.netbox_version}")
24
27
 
25
28
 
26
- class NetboxProvider(StorageProvider):
29
+ class NetboxProvider(StorageProvider, AdapterWithName, AdapterWithConfig):
30
+ def __init__(self, url: Optional[str] = None, token: Optional[str] = None):
31
+ self.url = url
32
+ self.token = token
33
+
34
+ def with_config(self, **kwargs: Dict[str, Any]) -> T:
35
+ return NetboxProvider(**kwargs)
36
+
27
37
  def storage(self):
28
38
  return storage_factory
29
39
 
annet/annlib/tabparser.py CHANGED
@@ -490,10 +490,11 @@ class RosFormatter(CommonFormatter):
490
490
  rows.append((row, None, row_context))
491
491
 
492
492
  prev_prow = None
493
+ prev_prow_context = {}
493
494
  for sub_config, row_group in itertools.groupby(rows, lambda x: x[1]):
494
495
  if sub_config is None:
495
496
  if prev_prow:
496
- yield prev_prow
497
+ yield prev_prow, prev_prow_context
497
498
  yield BlockBegin, None
498
499
  for row, _, row_context in row_group:
499
500
  yield row, row_context
@@ -502,7 +503,7 @@ class RosFormatter(CommonFormatter):
502
503
  else:
503
504
  for row, _, row_context in row_group:
504
505
  if context and context.parent and context.parent.row:
505
- prev_prow = context.parent.row
506
+ prev_prow, prev_prow_context = context.parent.current
506
507
  prow = f"{context.parent.row} {row}"
507
508
  else:
508
509
  prow = row
annet/api/__init__.py CHANGED
@@ -218,8 +218,8 @@ def log_host_progress_cb(pool: Parallel, task_result: TaskResult):
218
218
  stacklevel=2,
219
219
  )
220
220
  args = cast(cli_args.QueryOptions, pool.args[0])
221
- connector, connector_opts = get_storage()
222
- storage_opts = connector.opts().parse_params(connector_opts, args)
221
+ connector = get_storage()
222
+ storage_opts = connector.opts().parse_params({}, args)
223
223
  with connector.storage()(storage_opts) as storage:
224
224
  fqdns = storage.resolve_fdnds_by_query(args.query)
225
225
  PoolProgressLogger(device_fqdns=fqdns)(pool, task_result)
@@ -260,7 +260,7 @@ def patch(args: cli_args.ShowPatchOptions, loader: ann_gen.Loader):
260
260
  """ Сгенерировать патч для устройств """
261
261
  global live_configs # pylint: disable=global-statement
262
262
  if args.config == "running":
263
- fetcher = annet.deploy.fetcher_connector.get()
263
+ fetcher = annet.deploy.get_fetcher()
264
264
  live_configs = fetcher.fetch(loader.devices, processes=args.parallel)
265
265
  stdin = args.stdin(filter_acl=args.filter_acl, config=args.config)
266
266
 
@@ -434,7 +434,7 @@ class CliDeployerJob(DeployerJob):
434
434
  self.cmd_lines.extend(["= %s " % device.hostname, ""])
435
435
  self.cmd_lines.extend(map(itemgetter(-1), cmds))
436
436
  self.cmd_lines.append("")
437
- deployer_driver = annet.deploy.driver_connector.get()
437
+ deployer_driver = annet.deploy.get_deployer()
438
438
  self.deploy_cmds[device] = deployer_driver.apply_deploy_rulebook(
439
439
  device.hw, cmds,
440
440
  do_commit=not self.args.dont_commit
@@ -494,7 +494,7 @@ class PCDeployerJob(DeployerJob):
494
494
  "generator_types": generator_types,
495
495
  }
496
496
  self.diffs[device] = upload_files
497
- deployer_driver = annet.deploy.driver_connector.get()
497
+ deployer_driver = annet.deploy.get_deployer()
498
498
  before, after = deployer_driver.build_configuration_cmdlist(device.hw)
499
499
  for cmd in deployer_driver.build_exit_cmdlist(device.hw):
500
500
  after.add_cmd(cmd)
annet/cli.py CHANGED
@@ -15,7 +15,7 @@ import yaml
15
15
  from contextlog import get_logger
16
16
  from valkit.python import valid_logging_level
17
17
 
18
- from annet.deploy import driver_connector, fetcher_connector
18
+ from annet.deploy import get_fetcher, get_deployer
19
19
  from annet import api, cli_args, filtering, generators
20
20
  from annet.api import collapse_texts, Deployer
21
21
  from annet.argparse import ArgParser, subcommand
@@ -68,8 +68,8 @@ def get_loader(gen_args: cli_args.GenOptions, args: cli_args.QueryOptionsBase):
68
68
  exit_stack = ExitStack()
69
69
  storages = []
70
70
  with exit_stack:
71
- connector, connector_opts = get_storage()
72
- storage_opts = connector.opts().parse_params(connector_opts, args)
71
+ connector, conf_params = get_storage()
72
+ storage_opts = connector.opts().parse_params(conf_params, args)
73
73
  storages.append(exit_stack.enter_context(connector.storage()(storage_opts)))
74
74
  yield Loader(*storages, args=gen_args, no_empty_warning=args.query.is_empty())
75
75
 
@@ -233,8 +233,8 @@ def deploy(args: cli_args.DeployOptions):
233
233
 
234
234
  deployer = Deployer(args)
235
235
  filterer = filtering.filterer_connector.get()
236
- fetcher = fetcher_connector.get()
237
- deploy_driver = driver_connector.get()
236
+ fetcher = get_fetcher()
237
+ deploy_driver = get_deployer()
238
238
 
239
239
  with get_loader(args, args) as loader:
240
240
  return api.deploy(
annet/connectors.py CHANGED
@@ -1,8 +1,9 @@
1
1
  import sys
2
- from abc import ABC
2
+ from abc import ABC, abstractmethod
3
3
  from functools import cached_property
4
4
  from importlib.metadata import entry_points
5
- from typing import Generic, Optional, Type, TypeVar, List
5
+ from typing import Generic, Optional, Type, TypeVar, List, Dict, Any, Tuple
6
+ import warnings
6
7
  from annet.lib import get_context
7
8
 
8
9
  T = TypeVar("T")
@@ -10,8 +11,11 @@ T = TypeVar("T")
10
11
 
11
12
  class Connector(ABC, Generic[T]):
12
13
  name: str
14
+ # legacy
13
15
  ep_name: str
14
16
  ep_group: str = "annet.connectors"
17
+ # right way just to use ep groups
18
+ ep_by_group_only: str = ""
15
19
  _classes: Optional[List[Type[T]]] = None
16
20
 
17
21
  def _get_default(self) -> Type[T]:
@@ -19,18 +23,22 @@ class Connector(ABC, Generic[T]):
19
23
 
20
24
  @cached_property
21
25
  def _entry_point(self) -> List[Type[T]]:
22
- return load_entry_point(self.ep_group, self.ep_name)
26
+ ep = load_entry_point(self.ep_group, self.ep_name)
27
+ if self.ep_by_group_only:
28
+ ep.extend(load_entry_point_new(self.ep_by_group_only))
29
+ return ep
23
30
 
24
31
  def get(self, *args, **kwargs) -> T:
32
+ """
33
+ Returns connector. If more than one is registered returns random and throw warning
34
+ """
25
35
  if self._classes is None:
26
36
  self._classes = self._entry_point or [self._get_default()]
37
+ if not self._classes:
38
+ raise Exception(f"Not found registered class for group={self.ep_group}")
27
39
  if len(self._classes) > 1:
28
- raise RuntimeError(
29
- f"Multiple classes are registered with the same "
30
- f"group={self.ep_group} and name={self.ep_name}: "
31
- f"{[cls for cls in self._classes]}",
32
- )
33
-
40
+ warnings.warn(f"Multiple classes are registered with the group={self.ep_group} but "
41
+ f"{[cls for cls in self._classes]}", UserWarning)
34
42
  res = self._classes[0]
35
43
  return res(*args, **kwargs)
36
44
 
@@ -74,5 +82,62 @@ def load_entry_point(group: str, name: str):
74
82
  else:
75
83
  ep = entry_points(group=group, name=name) # pylint: disable=unexpected-keyword-arg
76
84
  if not ep:
77
- return None
85
+ return []
86
+ return [item.load() for item in ep]
87
+
88
+
89
+ def load_entry_point_new(group: str) -> List:
90
+ if sys.version_info < (3, 10):
91
+ ep = [item for item in entry_points().get(group, [])]
92
+ else:
93
+ ep = entry_points(group=group) # pylint: disable=unexpected-keyword-arg
94
+ if not ep:
95
+ return []
78
96
  return [item.load() for item in ep]
97
+
98
+
99
+ class AdapterWithConfig(ABC, Generic[T]):
100
+ @abstractmethod
101
+ def with_config(self, **kwargs: Dict[str, Any]) -> T:
102
+ pass
103
+
104
+
105
+ class AdapterWithName(ABC):
106
+ @abstractmethod
107
+ def name(self) -> str:
108
+ pass
109
+
110
+
111
+ def get_connector_from_config(config_key: str, connectors: List[Connector]) -> Tuple[Connector, Dict[str, Any]]:
112
+ seen: list[str] = []
113
+ if not connectors:
114
+ raise Exception("empty connectors")
115
+ connector = connectors[0] # default
116
+ connector_params: Dict[str, Any] = {}
117
+ if context_storage := get_context().get(config_key):
118
+ adapter_name = context_storage.get("adapter", None)
119
+ connector_params = context_storage.get("params", {})
120
+ if adapter_name:
121
+ for con in connectors:
122
+ con_name = connector.__class__.__name__
123
+ if isinstance(con, AdapterWithName):
124
+ con_name = con.name()
125
+ seen.append(con_name)
126
+ if adapter_name == con_name:
127
+ connector = con
128
+ break
129
+ else:
130
+ raise Exception("unknown %s %s: seen %s" % (config_key, adapter_name, seen))
131
+ else:
132
+ connector = connectors[0]
133
+ if len(connectors) > 1:
134
+ warnings.warn(f"Please specify adapter for '{config_key}'. Found more than one classes {connectors}", UserWarning)
135
+ else:
136
+ connector = connectors[0]
137
+ if len(connectors) > 1:
138
+ warnings.warn(f"Please specify '{config_key}'. Found more than one classes {connectors}", UserWarning)
139
+ if isinstance(connector, AdapterWithConfig):
140
+ connector = connector.with_config(**connector_params)
141
+ # return connector_params only for storage
142
+ # TODO: switch storage interface to AdapterWithConfig
143
+ return connector, connector_params
annet/deploy.py CHANGED
@@ -6,7 +6,7 @@ import itertools
6
6
  import re
7
7
  from collections import namedtuple
8
8
  from contextlib import contextmanager
9
- from typing import Dict, List, Optional, Type, Any, OrderedDict
9
+ from typing import Dict, List, Optional, Any, OrderedDict, Tuple, Type
10
10
 
11
11
  from contextlog import get_logger
12
12
 
@@ -15,7 +15,7 @@ from annet.annlib.command import Command, Question, CommandList
15
15
  from annet.annlib.netdev.views.hardware import HardwareView
16
16
  from annet.annlib.rbparser.deploying import MakeMessageMatcher, Answer
17
17
  from annet.cli_args import DeployOptions
18
- from annet.connectors import Connector
18
+ from annet.connectors import Connector, get_connector_from_config
19
19
  from annet.output import TextArgs
20
20
  from annet.rulebook import get_rulebook, deploying
21
21
  from annet.storage import Device
@@ -39,17 +39,23 @@ class DeployResult(_DeployResultBase): # noqa: E302
39
39
  class _FetcherConnector(Connector["Fetcher"]):
40
40
  name = "Fetcher"
41
41
  ep_name = "deploy_fetcher"
42
+ ep_by_group_only = "annet.connectors.fetcher"
42
43
 
43
44
  def _get_default(self) -> Type["Fetcher"]:
44
- return StubFetcher
45
+ # if entry points are broken, try to use direct import
46
+ import annet.adapters.fetchers.stub.fetcher as stub_fetcher
47
+ return stub_fetcher.StubFetcher
45
48
 
46
49
 
47
50
  class _DriverConnector(Connector["DeployDriver"]):
48
51
  name = "DeployDriver"
49
52
  ep_name = "deploy_driver"
53
+ ep_by_group_only = "annet.connectors.deployer"
50
54
 
51
55
  def _get_default(self) -> Type["DeployDriver"]:
52
- return StubDeployDriver
56
+ # if entry points are broken, try to use direct import
57
+ import annet.adapters.deployers.stub.deployer as stub_deployer
58
+ return stub_deployer.StubDeployDriver
53
59
 
54
60
 
55
61
  fetcher_connector = _FetcherConnector()
@@ -59,7 +65,7 @@ driver_connector = _DriverConnector()
59
65
  class Fetcher(abc.ABC):
60
66
  @abc.abstractmethod
61
67
  def fetch_packages(self, devices: List[Device],
62
- processes: int = 1, max_slots: int = 0):
68
+ processes: int = 1, max_slots: int = 0) -> Tuple[Dict[Device, str], Dict[Device, Any]]:
63
69
  pass
64
70
 
65
71
  @abc.abstractmethod
@@ -69,15 +75,10 @@ class Fetcher(abc.ABC):
69
75
  pass
70
76
 
71
77
 
72
- class StubFetcher(Fetcher):
73
- def fetch_packages(self, devices: List[Device],
74
- processes: int = 1, max_slots: int = 0):
75
- raise NotImplementedError()
76
-
77
- def fetch(self, devices: List[Device],
78
- files_to_download: Dict[str, List[str]] = None,
79
- processes: int = 1, max_slots: int = 0):
80
- raise NotImplementedError()
78
+ def get_fetcher() -> Fetcher:
79
+ connectors = fetcher_connector.get_all()
80
+ fetcher, _ = get_connector_from_config("fetcher", connectors)
81
+ return fetcher
81
82
 
82
83
 
83
84
  class DeployDriver(abc.ABC):
@@ -86,11 +87,11 @@ class DeployDriver(abc.ABC):
86
87
  pass
87
88
 
88
89
  @abc.abstractmethod
89
- def apply_deploy_rulebook(self, hw, cmd_paths, do_finalize=True, do_commit=True):
90
+ def apply_deploy_rulebook(self, hw: HardwareView, cmd_paths, do_finalize=True, do_commit=True):
90
91
  pass
91
92
 
92
93
  @abc.abstractmethod
93
- def build_configuration_cmdlist(self, hw, do_finalize=True, do_commit=True):
94
+ def build_configuration_cmdlist(self, hw: HardwareView, do_finalize=True, do_commit=True):
94
95
  pass
95
96
 
96
97
  @abc.abstractmethod
@@ -98,18 +99,10 @@ class DeployDriver(abc.ABC):
98
99
  pass
99
100
 
100
101
 
101
- class StubDeployDriver(DeployDriver):
102
- async def bulk_deploy(self, deploy_cmds: dict, args: DeployOptions) -> DeployResult:
103
- NotImplementedError()
104
-
105
- def apply_deploy_rulebook(self, hw, cmd_paths, do_finalize=True, do_commit=True):
106
- NotImplementedError()
107
-
108
- def build_configuration_cmdlist(self, hw, do_finalize=True, do_commit=True):
109
- NotImplementedError()
110
-
111
- def build_exit_cmdlist(self, hw):
112
- raise NotImplementedError()
102
+ def get_deployer() -> DeployDriver:
103
+ connectors = fetcher_connector.get_all()
104
+ deployer, _ = get_connector_from_config("deployer", connectors)
105
+ return deployer
113
106
 
114
107
 
115
108
  # ===
annet/filtering.py CHANGED
@@ -7,6 +7,7 @@ from annet.connectors import Connector
7
7
  class _FiltererConnector(Connector["Filterer"]):
8
8
  name = "Filterer"
9
9
  ep_name = "filterer"
10
+ ep_by_group_only = "annet.connectors.filterer"
10
11
 
11
12
  def _get_default(self) -> Type["Filterer"]:
12
13
  return NopFilterer
annet/gen.py CHANGED
@@ -30,7 +30,7 @@ from annet.annlib import jsontools
30
30
  from annet.annlib.rbparser import platform
31
31
  from annet.annlib.rbparser.acl import compile_acl_text
32
32
  from annet.cli_args import DeployOptions, GenOptions, ShowGenOptions
33
- from annet.deploy import fetcher_connector, scrub_config
33
+ from annet.deploy import scrub_config, get_fetcher
34
34
  from annet.filtering import Filterer
35
35
  from annet.generators import (
36
36
  BaseGenerator,
@@ -407,7 +407,7 @@ def old_new(
407
407
  if do_files_download and config == "running":
408
408
  files_to_download = _get_files_to_download(devices, gens)
409
409
  devices_with_files = [device for device in devices if device in files_to_download]
410
- fetcher = fetcher_connector.get()
410
+ fetcher = get_fetcher()
411
411
  fetched_packages, failed_packages = fetcher.fetch_packages(devices_with_files)
412
412
 
413
413
  ctx = OldNewDeviceContext(
@@ -808,7 +808,7 @@ def _old_resolve_running(config: str, devices: List[Device]) -> Tuple[Dict[Devic
808
808
  global live_configs # pylint: disable=global-statement
809
809
  if live_configs is None:
810
810
  # предварительно прочесть все конфиги прямо по ssh
811
- fetcher = fetcher_connector.get()
811
+ fetcher = get_fetcher()
812
812
  running, failed_running = fetcher.fetch(devices)
813
813
  else:
814
814
  running, failed_running = live_configs # pylint: disable=unpacking-non-sequence
@@ -826,7 +826,7 @@ def _old_resolve_files(config: str,
826
826
  files_to_download = _get_files_to_download(devices, gens)
827
827
  devices_with_files = [device for device in devices if device in files_to_download]
828
828
  if devices_with_files:
829
- fetcher = fetcher_connector.get()
829
+ fetcher = get_fetcher()
830
830
  downloaded_files, failed_files = fetcher.fetch(devices_with_files,
831
831
  files_to_download=files_to_download)
832
832
  return downloaded_files, failed_files
annet/hardware.py CHANGED
@@ -15,6 +15,7 @@ except ImportError:
15
15
  class _HardwareConnector(Connector["HarwareProvider"]):
16
16
  name = "Hardware"
17
17
  ep_name = "hardware"
18
+ ep_by_group_only = "annet.connectors.hardware"
18
19
 
19
20
 
20
21
  hardware_connector = _HardwareConnector()
annet/output.py CHANGED
@@ -30,6 +30,7 @@ BLACKBOX_FILENAME = "config.cfg"
30
30
  class _DriverConnector(Connector["OutputDriver"]):
31
31
  name = "OutputDriver"
32
32
  ep_name = "output"
33
+ ep_by_group_only = "annet.connectors.output"
33
34
 
34
35
  def _get_default(self) -> Type["OutputDriver"]:
35
36
  return OutputDriverBasic
annet/storage.py CHANGED
@@ -1,11 +1,12 @@
1
1
  import abc
2
2
  from typing import Any, Iterable, Optional, Type, Union, Protocol, Dict
3
- from annet.connectors import Connector, get_context
3
+ from annet.connectors import Connector, get_connector_from_config
4
4
 
5
5
 
6
6
  class _StorageConnector(Connector["StorageProvider"]):
7
- name = "Storage"
8
- ep_name = "storage"
7
+ name = "Storage" # legacy
8
+ ep_name = "storage" # legacy
9
+ ep_by_group_only = "annet.connectors.storage"
9
10
 
10
11
 
11
12
  storage_connector = _StorageConnector()
@@ -128,18 +129,6 @@ class Device(Protocol):
128
129
  pass
129
130
 
130
131
 
131
- def get_storage() -> (Storage, Dict[str, Any]):
132
+ def get_storage() -> tuple[StorageProvider, Dict[str, Any]]:
132
133
  connectors = storage_connector.get_all()
133
- seen: list[str] = []
134
- if context_storage := get_context().get("storage"):
135
- for connector in connectors:
136
- con_name = connector.name()
137
- seen.append(con_name)
138
- if "adapter" not in context_storage:
139
- raise Exception("adapter is not set in %s" % context_storage)
140
- if context_storage["adapter"] == con_name:
141
- return connector, context_storage.get("params", {})
142
- else:
143
- raise Exception("unknown storage %s: seen %s" % (context_storage["adapter"], seen))
144
- else:
145
- return connectors[0], {}
134
+ return get_connector_from_config("storage", connectors)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: annet
3
- Version: 0.15.2
3
+ Version: 0.15.3
4
4
  Summary: annet
5
5
  Home-page: https://github.com/annetutil/annet
6
6
  License: MIT
@@ -1,36 +1,36 @@
1
1
  annet/__init__.py,sha256=oyElxAW97sHgQccGafhaWVBveBn1gSjjdP_xHROaRLg,2139
2
2
  annet/annet.py,sha256=TMdEuM7GJQ4TjRVmuK3bCTZN-21lxjQ9sXqEdILUuBk,725
3
3
  annet/argparse.py,sha256=v1MfhjR0B8qahza0WinmXClpR8UiDFhmwDDWtNroJPA,12855
4
- annet/cli.py,sha256=AcSiqNa5Wk3yJks5LYcXqbYMZuySmQqMQK5hW_-irFw,12363
4
+ annet/cli.py,sha256=ugxI_NFi-yuMn4RIlFKlqCDUurPXlSAa7kR9hkd1OxA,12329
5
5
  annet/cli_args.py,sha256=KQlihxSl-Phhq1-9oJDdNSbIllEX55LlPfH6viEKOuw,13483
6
- annet/connectors.py,sha256=Xgr7fNopRhFAYnkiDxhohBtjlFOLY8v0xLExHmVMr00,2511
7
- annet/deploy.py,sha256=B8E0P_VvCrS2URjFvgmUiIkHp95g7pAWfmT34igaDeo,18893
6
+ annet/connectors.py,sha256=42aqztw-w7T_d4tJcNCG4PIyX41j8WmLMFjxQQtRF6A,5062
7
+ annet/deploy.py,sha256=h5lQK2zI-aL0S67dl3aXabjr0uy-DvfEKR_Rqk02uQQ,18886
8
8
  annet/diff.py,sha256=zLcaCnb4lZRUb7frpH1CstQ3kacRcCblZs1uLG8J5lk,3391
9
9
  annet/executor.py,sha256=FrYAUuh2TpSVX42SlTN_PhuSHmXG4Wj1nieY9Wqv9so,19122
10
- annet/filtering.py,sha256=F4ZKUCU3Yb1RlL2zKdyHtVUaWPzjWF4vWyMcdygKNYk,852
11
- annet/gen.py,sha256=8IPejduvYXmezUDolLKg4Imt1TxEp0KJ7kSgMtFcaCY,33628
12
- annet/hardware.py,sha256=HYPDfji_GdRn5S0_0fl4rvM7byOY9aHxG6VMAtsLaxE,1090
10
+ annet/filtering.py,sha256=ZtqxPsKdV9reZoRxtQyBg22BqyMqd-2SotYcxZ-68AQ,903
11
+ annet/gen.py,sha256=Xy4VyK8pfH97wZ8Zv2bD2SNxhEx9-S93Zp7pQm-VnuU,33592
12
+ annet/hardware.py,sha256=_iR28dWiPtt6ZYdk-qg1sxazkSRJE3ukqKB-fFFfQak,1141
13
13
  annet/implicit.py,sha256=_3eY9NKqpLUm25vlJIP2cHN4gdTgzO6rG6mwCKJYMnQ,5439
14
14
  annet/lib.py,sha256=W6Z9UurcyF1zU3gAd8hIec9yBzeeHzxZEkvf1cIg8KI,4280
15
- annet/output.py,sha256=zAP3XixfSLNL988IF9ttyIbGaN4M6XhO5IhKkD1R-J8,7127
15
+ annet/output.py,sha256=BNPzjuhMa7gSJ8ze_1O-Ey0tTxSyhAiwfztZMQwhMzk,7176
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=Wr_D_w7JQD08nD2IvC6bcGJLH6Uv62tKznUyWWWVW5Q,3144
19
+ annet/storage.py,sha256=lL33L4s63sMTS4n0kzC2mtrhpXAu0RYBvKC6U7I--gs,2706
20
20
  annet/tabparser.py,sha256=dEavhVBd9TEFf2NOW_JpTDcz2rzNtP4siQPceWalpl0,957
21
21
  annet/text_term_format.py,sha256=CHb6viv45vmYl-SK1A1vyPHGhaEni6jVybBusaQnct8,2813
22
22
  annet/tracing.py,sha256=ndpM-au1c88uBBpOuH_z52qWZL773edYozNyys_wA68,4044
23
23
  annet/types.py,sha256=f2HwqoKa6AucwFwDMszoouB6m1B8n6VmdjHMktO30Kc,7175
24
24
  annet/adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
25
  annet/adapters/netbox/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
- annet/adapters/netbox/provider.py,sha256=Gymku2Ad7um4GR9MqzQzm2o2cBLHLhIYbF1Ytl0r0MA,1076
26
+ annet/adapters/netbox/provider.py,sha256=mnvxSy3vTwdEHvzfy_Tfji4J4-BDmiKwkcF0s-EAs2M,1449
27
27
  annet/adapters/netbox/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
28
  annet/adapters/netbox/common/client.py,sha256=-lWZmphD-OPuLIHNKhW_h2bnjrVaiyKYAD_MUPasEbo,2483
29
29
  annet/adapters/netbox/common/manufacturer.py,sha256=K1z2ioP9ZikxjjfSAuAAszZALW0o9w1kLTnW5cR16tU,1412
30
30
  annet/adapters/netbox/common/models.py,sha256=Vgxbl_Mm-zOAi2BTlEzDppTTgZjafFEC5F9s_MTd_xU,3263
31
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
- annet/adapters/netbox/common/storage_opts.py,sha256=idOm1na_2Axdi4MdLN4tAsPvsp5zBtJYD9j7cUiI-W8,400
33
+ annet/adapters/netbox/common/storage_opts.py,sha256=afBMiIOOHFRJLh4KCLPflCCXKxh7D7VX9EL5wxFkuZI,494
34
34
  annet/adapters/netbox/v24/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
35
  annet/adapters/netbox/v24/storage.py,sha256=THI592VLx3ehixsPZQ1Ko3mYIAZQbnDY-toIziqBbL8,6005
36
36
  annet/adapters/netbox/v37/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -44,7 +44,7 @@ annet/annlib/jsontools.py,sha256=J_pToAAXQphP1QFh6uLQH9PnmHO68I5WV64qIQXLeDQ,380
44
44
  annet/annlib/lib.py,sha256=eJ4hcVuQ6pdYBzLs4YKCHFtq45idOfZCYp92XfF7_QI,15317
45
45
  annet/annlib/output.py,sha256=_SjJ6G6bejvnTKqNHw6xeio0FT9oO3OIkLaOC3cEga4,7569
46
46
  annet/annlib/patching.py,sha256=GwG2lT4w-I1Ls3Eswn6SPJLBUVt2M3Ysw1fmXsWamYw,19793
47
- annet/annlib/tabparser.py,sha256=TnDVxJ8PkQzn_IPdwkcantGzckRNIYPQAtlHwo9bnXY,25891
47
+ annet/annlib/tabparser.py,sha256=djxW4d3pozqrNT6ZkrOxIUZkgGiZXHy7JvQSjao5MyY,25964
48
48
  annet/annlib/types.py,sha256=VHU0CBADfYmO0xzB_c5f-mcuU3dUumuJczQnqGlib9M,852
49
49
  annet/annlib/netdev/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
50
  annet/annlib/netdev/db.py,sha256=fI_u5aya4l61mbYSjj4JwlVfi3s7obt2jqERSuXGRUI,1634
@@ -61,7 +61,7 @@ annet/annlib/rbparser/platform.py,sha256=_W84Gt3XwURT2MLngZSmwZbWgqsnbrwzjNgHIHa
61
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
- annet/api/__init__.py,sha256=vh3FVvhghxEEskLM9TuGBSnYDXN5L8iUFBB-iV46WAA,33182
64
+ annet/api/__init__.py,sha256=xC4a-iSQACUZYoBujjZa1CjVWlNqxWpif15zCdvS828,33128
65
65
  annet/configs/context.yml,sha256=jzAQX9WbjFw_nsju8FLCCGfRc4ZXD0Mhb5pvO9emegI,413
66
66
  annet/configs/logging.yaml,sha256=Hu42lRK248dssp9TgkbHCaZNl0E6f4IChGb0XaQnTVo,970
67
67
  annet/generators/__init__.py,sha256=ACMH9UQ4I3uq2b8nDzOn2dgYxreDq4_3ojOGwht0-No,15543
@@ -127,10 +127,10 @@ annet/rulebook/texts/routeros.rul,sha256=ipfxjj0mjFef6IsUlupqx4BY_Je_OUb8u_U1019
127
127
  annet_generators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
128
128
  annet_generators/example/__init__.py,sha256=zVd8_DrXuOASrNzg2Ab94rPyvJff83L-_HppDFxnUjM,228
129
129
  annet_generators/example/lldp.py,sha256=68CLrK7vxTQQy9XIBxtywuEdBNlIlfXGYj8_wYWs5UI,1146
130
- annet-0.15.2.dist-info/AUTHORS,sha256=rh3w5P6gEgqmuC-bw-HB68vBCr-yIBFhVL0PG4hguLs,878
131
- annet-0.15.2.dist-info/LICENSE,sha256=yPxl7dno02Pw7gAcFPIFONzx_gapwDoPXsIsh6Y7lC0,1079
132
- annet-0.15.2.dist-info/METADATA,sha256=zYV7OYVW5PBLs0_QUocznhtW6jKa1QpYr9bY0C9m3lE,694
133
- annet-0.15.2.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
134
- annet-0.15.2.dist-info/entry_points.txt,sha256=yHimujIzR2bwNIbb--MTs_GpXiAve89Egpu2LlgTEkg,119
135
- annet-0.15.2.dist-info/top_level.txt,sha256=QsoTZBsUtwp_FEcmRwuN8QITBmLOZFqjssRfKilGbP8,23
136
- annet-0.15.2.dist-info/RECORD,,
130
+ annet-0.15.3.dist-info/AUTHORS,sha256=rh3w5P6gEgqmuC-bw-HB68vBCr-yIBFhVL0PG4hguLs,878
131
+ annet-0.15.3.dist-info/LICENSE,sha256=yPxl7dno02Pw7gAcFPIFONzx_gapwDoPXsIsh6Y7lC0,1079
132
+ annet-0.15.3.dist-info/METADATA,sha256=HI4F98xkvFiuVsCeVad_NRUv-bhXienBWsFseXeAvcM,694
133
+ annet-0.15.3.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
134
+ annet-0.15.3.dist-info/entry_points.txt,sha256=5lIaDGlGi3l6QQ2ry2jZaqViP5Lvt8AmsegdD0Uznck,192
135
+ annet-0.15.3.dist-info/top_level.txt,sha256=QsoTZBsUtwp_FEcmRwuN8QITBmLOZFqjssRfKilGbP8,23
136
+ annet-0.15.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (74.1.2)
2
+ Generator: setuptools (75.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,5 +1,8 @@
1
1
  [annet.connectors]
2
2
  storage = annet.adapters.netbox.provider:NetboxProvider
3
3
 
4
+ [annet.connectors.storage]
5
+ file = annet.adapters.file.provider:Provider
6
+
4
7
  [console_scripts]
5
8
  annet = annet.annet:main