annet 3.18.0__py3-none-any.whl → 3.20.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.
- annet/adapters/netbox/common/storage_base.py +31 -2
- annet/adapters/netbox/common/storage_opts.py +21 -0
- annet/adapters/netbox/provider.py +2 -1
- annet/adapters/netbox/v37/storage.py +7 -2
- annet/adapters/netbox/v41/storage.py +8 -2
- annet/adapters/netbox/v42/storage.py +7 -3
- annet/cli_args.py +7 -0
- annet/generators/__init__.py +5 -6
- annet/generators/annotate.py +37 -0
- annet/generators/base.py +12 -3
- annet/generators/entire.py +11 -12
- annet/generators/jsonfragment.py +6 -17
- annet/generators/partial.py +32 -52
- annet/generators/result.py +14 -23
- {annet-3.18.0.dist-info → annet-3.20.0.dist-info}/METADATA +3 -2
- {annet-3.18.0.dist-info → annet-3.20.0.dist-info}/RECORD +21 -20
- {annet-3.18.0.dist-info → annet-3.20.0.dist-info}/WHEEL +0 -0
- {annet-3.18.0.dist-info → annet-3.20.0.dist-info}/entry_points.txt +0 -0
- {annet-3.18.0.dist-info → annet-3.20.0.dist-info}/licenses/AUTHORS +0 -0
- {annet-3.18.0.dist-info → annet-3.20.0.dist-info}/licenses/LICENSE +0 -0
- {annet-3.18.0.dist-info → annet-3.20.0.dist-info}/top_level.txt +0 -0
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import ssl
|
|
2
2
|
from ipaddress import ip_interface
|
|
3
3
|
from logging import getLogger
|
|
4
|
-
from typing import Any, Optional, List, Union, Dict, cast, Generic, TypeVar
|
|
4
|
+
from typing import Any, Callable, Optional, List, Union, Dict, cast, Generic, TypeVar
|
|
5
|
+
|
|
6
|
+
from requests import Session
|
|
7
|
+
|
|
8
|
+
from requests_cache import CachedSession, SQLiteCache
|
|
5
9
|
|
|
6
10
|
from annetbox.v37 import models as api_models
|
|
7
11
|
|
|
@@ -45,6 +49,7 @@ class BaseNetboxStorage(
|
|
|
45
49
|
token = ""
|
|
46
50
|
self.exact_host_filter = False
|
|
47
51
|
threads = 1
|
|
52
|
+
session_factory = None
|
|
48
53
|
if opts:
|
|
49
54
|
if opts.insecure:
|
|
50
55
|
ctx = ssl.create_default_context()
|
|
@@ -55,7 +60,17 @@ class BaseNetboxStorage(
|
|
|
55
60
|
threads = opts.threads
|
|
56
61
|
self.exact_host_filter = opts.exact_host_filter
|
|
57
62
|
self.all_hosts_filter = opts.all_hosts_filter
|
|
58
|
-
|
|
63
|
+
|
|
64
|
+
if opts.cache_path:
|
|
65
|
+
session_factory = cached_requests_session(opts)
|
|
66
|
+
|
|
67
|
+
self.netbox = self._init_adapter(
|
|
68
|
+
url=url,
|
|
69
|
+
token=token,
|
|
70
|
+
ssl_context=ctx,
|
|
71
|
+
threads=threads,
|
|
72
|
+
session_factory=session_factory,
|
|
73
|
+
)
|
|
59
74
|
self._all_fqdns: Optional[list[str]] = None
|
|
60
75
|
self._id_devices: dict[int, NetboxDeviceT] = {}
|
|
61
76
|
self._name_devices: dict[str, NetboxDeviceT] = {}
|
|
@@ -67,6 +82,7 @@ class BaseNetboxStorage(
|
|
|
67
82
|
token: str,
|
|
68
83
|
ssl_context: Optional[ssl.SSLContext],
|
|
69
84
|
threads: int,
|
|
85
|
+
session_factory: Callable[[Session], Session] | None = None,
|
|
70
86
|
) -> NetboxAdapter[NetboxDeviceT, InterfaceT, IpAddressT, PrefixT, FHRPGroupT, FHRPGroupAssignmentT]:
|
|
71
87
|
raise NotImplementedError()
|
|
72
88
|
|
|
@@ -259,3 +275,16 @@ def parse_glob(exact_host_filter: bool, query: NetboxQuery) -> dict[str, list[st
|
|
|
259
275
|
else:
|
|
260
276
|
query_groups["name__ic"] = [_hostname_dot_hack(name) for name in names]
|
|
261
277
|
return query_groups
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def cached_requests_session(opts: NetboxStorageOpts) -> Callable[[Session], Session]:
|
|
281
|
+
def session_factory(session: Session) -> Session:
|
|
282
|
+
backend = SQLiteCache(db_path=opts.cache_path)
|
|
283
|
+
if opts.recache:
|
|
284
|
+
backend.clear()
|
|
285
|
+
return CachedSession.wrap(
|
|
286
|
+
session,
|
|
287
|
+
backend=backend,
|
|
288
|
+
expire_after=opts.cache_ttl,
|
|
289
|
+
)
|
|
290
|
+
return session_factory
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from typing import Any, Optional
|
|
3
|
+
from datetime import timedelta
|
|
3
4
|
from .query import parse_query
|
|
4
5
|
|
|
5
6
|
DEFAULT_URL = "http://localhost"
|
|
@@ -14,6 +15,9 @@ class NetboxStorageOpts:
|
|
|
14
15
|
exact_host_filter: bool = False,
|
|
15
16
|
threads: int = 1,
|
|
16
17
|
all_hosts_filter: dict[str, list[str]] | None = None,
|
|
18
|
+
cache_path: str = "",
|
|
19
|
+
cache_ttl: timedelta = timedelta(0),
|
|
20
|
+
recache: bool = False,
|
|
17
21
|
):
|
|
18
22
|
self.url = url
|
|
19
23
|
self.token = token
|
|
@@ -21,6 +25,9 @@ class NetboxStorageOpts:
|
|
|
21
25
|
self.exact_host_filter = exact_host_filter
|
|
22
26
|
self.threads = threads
|
|
23
27
|
self.all_hosts_filter: dict[str, list[str]] = all_hosts_filter or {}
|
|
28
|
+
self.cache_path = cache_path
|
|
29
|
+
self.cache_ttl = cache_ttl
|
|
30
|
+
self.recache = recache
|
|
24
31
|
|
|
25
32
|
@classmethod
|
|
26
33
|
def parse_params(cls, conf_params: Optional[dict[str, str]], cli_opts: Any):
|
|
@@ -41,6 +48,17 @@ class NetboxStorageOpts:
|
|
|
41
48
|
exact_host_filter = exact_host_filter_env in ("true", "1", "t")
|
|
42
49
|
else:
|
|
43
50
|
exact_host_filter = bool(conf_params.get("exact_host_filter") or False)
|
|
51
|
+
|
|
52
|
+
if cache_path := os.getenv("NETBOX_CACHE_PATH"):
|
|
53
|
+
cache_path = cache_path
|
|
54
|
+
else:
|
|
55
|
+
cache_path = str(conf_params.get("cache_path", ""))
|
|
56
|
+
|
|
57
|
+
if cache_ttl := os.getenv("NETBOX_CACHE_TTL"):
|
|
58
|
+
cache_ttl = timedelta(seconds=int(cache_ttl))
|
|
59
|
+
else:
|
|
60
|
+
cache_ttl = timedelta(seconds=conf_params.get("cache_ttl", 0))
|
|
61
|
+
|
|
44
62
|
return cls(
|
|
45
63
|
url=url,
|
|
46
64
|
token=token,
|
|
@@ -48,4 +66,7 @@ class NetboxStorageOpts:
|
|
|
48
66
|
exact_host_filter=exact_host_filter,
|
|
49
67
|
threads=int(threads),
|
|
50
68
|
all_hosts_filter=all_hosts_filter,
|
|
69
|
+
cache_path=cache_path,
|
|
70
|
+
cache_ttl=cache_ttl,
|
|
71
|
+
recache=cli_opts.recache,
|
|
51
72
|
)
|
|
@@ -46,7 +46,8 @@ def storage_factory(opts: NetboxStorageOpts) -> Storage:
|
|
|
46
46
|
|
|
47
47
|
class NetboxProvider(StorageProvider, AdapterWithName, AdapterWithConfig):
|
|
48
48
|
def __init__(self, url: Optional[str] = None, token: Optional[str] = None, insecure: bool = False,
|
|
49
|
-
exact_host_filter: bool = False, threads: int = 1, all_hosts_filter: dict[str, list[str]] | None = None
|
|
49
|
+
exact_host_filter: bool = False, threads: int = 1, all_hosts_filter: dict[str, list[str]] | None = None,
|
|
50
|
+
cache_path: str = "", cache_ttl: int = 0):
|
|
50
51
|
self.url = url
|
|
51
52
|
self.token = token
|
|
52
53
|
self.insecure = insecure
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import ssl
|
|
2
|
+
from typing import Callable
|
|
3
|
+
|
|
4
|
+
from requests import Session
|
|
2
5
|
|
|
3
6
|
from adaptix import P
|
|
4
7
|
from adaptix.conversion import get_converter, link_function, link_constant, link
|
|
@@ -23,8 +26,9 @@ class NetboxV37Adapter(NetboxAdapter[
|
|
|
23
26
|
token: str,
|
|
24
27
|
ssl_context: ssl.SSLContext | None,
|
|
25
28
|
threads: int,
|
|
29
|
+
session_factory: Callable[[Session], Session] | None,
|
|
26
30
|
):
|
|
27
|
-
self.netbox = client_sync.NetboxV37(url=url, token=token, ssl_context=ssl_context, threads=threads)
|
|
31
|
+
self.netbox = client_sync.NetboxV37(url=url, token=token, ssl_context=ssl_context, threads=threads, session_factory=session_factory)
|
|
28
32
|
self.convert_device = get_converter(
|
|
29
33
|
api_models.Device,
|
|
30
34
|
NetboxDeviceV37,
|
|
@@ -120,5 +124,6 @@ class NetboxStorageV37(BaseNetboxStorage[
|
|
|
120
124
|
token: str,
|
|
121
125
|
ssl_context: ssl.SSLContext | None,
|
|
122
126
|
threads: int,
|
|
127
|
+
session_factory: Callable[[Session], Session] | None = None,
|
|
123
128
|
) -> NetboxAdapter[NetboxDeviceV37, InterfaceV37, IpAddressV37, PrefixV37, FHRPGroupV37, FHRPGroupAssignmentV37]:
|
|
124
|
-
return NetboxV37Adapter(self, url, token, ssl_context, threads)
|
|
129
|
+
return NetboxV37Adapter(self, url, token, ssl_context, threads, session_factory)
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import ssl
|
|
2
|
+
from typing import Callable
|
|
3
|
+
|
|
4
|
+
from requests import Session
|
|
5
|
+
|
|
2
6
|
from adaptix import P
|
|
3
7
|
from adaptix.conversion import get_converter, link, link_constant, link_function
|
|
4
8
|
from annetbox.v41 import client_sync
|
|
@@ -24,8 +28,9 @@ class NetboxV41Adapter(NetboxAdapter[
|
|
|
24
28
|
token: str,
|
|
25
29
|
ssl_context: ssl.SSLContext | None,
|
|
26
30
|
threads: int,
|
|
31
|
+
session_factory: Callable[[Session], Session] | None,
|
|
27
32
|
):
|
|
28
|
-
self.netbox = client_sync.NetboxV41(url=url, token=token, ssl_context=ssl_context, threads=threads)
|
|
33
|
+
self.netbox = client_sync.NetboxV41(url=url, token=token, ssl_context=ssl_context, threads=threads, session_factory=session_factory)
|
|
29
34
|
self.convert_device = get_converter(
|
|
30
35
|
api_models.Device,
|
|
31
36
|
NetboxDeviceV41,
|
|
@@ -122,5 +127,6 @@ class NetboxStorageV41(BaseNetboxStorage[
|
|
|
122
127
|
token: str,
|
|
123
128
|
ssl_context: ssl.SSLContext | None,
|
|
124
129
|
threads: int,
|
|
130
|
+
session_factory: Callable[[Session], Session] | None = None,
|
|
125
131
|
) -> NetboxAdapter[NetboxDeviceV41, InterfaceV41, IpAddressV41, PrefixV41, FHRPGroupV41, FHRPGroupAssignmentV41]:
|
|
126
|
-
return NetboxV41Adapter(self, url, token, ssl_context, threads)
|
|
132
|
+
return NetboxV41Adapter(self, url, token, ssl_context, threads, session_factory)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import ssl
|
|
2
|
-
from typing import Optional
|
|
2
|
+
from typing import Callable, Optional
|
|
3
|
+
|
|
4
|
+
from requests import Session
|
|
3
5
|
|
|
4
6
|
from adaptix import P
|
|
5
7
|
from adaptix.conversion import get_converter, link, link_constant, link_function
|
|
@@ -25,8 +27,9 @@ class NetboxV42Adapter(NetboxAdapter[
|
|
|
25
27
|
token: str,
|
|
26
28
|
ssl_context: ssl.SSLContext | None,
|
|
27
29
|
threads: int,
|
|
30
|
+
session_factory: Callable[[Session], Session] | None,
|
|
28
31
|
):
|
|
29
|
-
self.netbox = client_sync.NetboxV42(url=url, token=token, ssl_context=ssl_context, threads=threads)
|
|
32
|
+
self.netbox = client_sync.NetboxV42(url=url, token=token, ssl_context=ssl_context, threads=threads, session_factory=session_factory)
|
|
30
33
|
self.convert_device = get_converter(
|
|
31
34
|
api_models.Device,
|
|
32
35
|
NetboxDeviceV42,
|
|
@@ -136,11 +139,12 @@ class NetboxStorageV42(BaseNetboxStorage[
|
|
|
136
139
|
token: str,
|
|
137
140
|
ssl_context: ssl.SSLContext | None,
|
|
138
141
|
threads: int,
|
|
142
|
+
session_factory: Callable[[Session], Session] | None = None,
|
|
139
143
|
) -> NetboxAdapter[
|
|
140
144
|
NetboxDeviceV42, InterfaceV42, IpAddressV42, PrefixV42,
|
|
141
145
|
FHRPGroupV41, FHRPGroupAssignmentV41,
|
|
142
146
|
]:
|
|
143
|
-
return NetboxV42Adapter(self, url, token, ssl_context, threads)
|
|
147
|
+
return NetboxV42Adapter(self, url, token, ssl_context, threads, session_factory)
|
|
144
148
|
|
|
145
149
|
def resolve_all_vlans(self) -> list[Vlan]:
|
|
146
150
|
if self._all_vlans is None:
|
annet/cli_args.py
CHANGED
|
@@ -140,6 +140,12 @@ opt_tolerate_fails = Arg(
|
|
|
140
140
|
help="Show errors without interrupting the generation"
|
|
141
141
|
)
|
|
142
142
|
|
|
143
|
+
opt_recache = Arg(
|
|
144
|
+
"--recache", default=False,
|
|
145
|
+
help="Force expiration of storage's local cache if it is supported"
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
|
|
143
149
|
# При параллельном запуске и включённом --tolerate-fails код возврата
|
|
144
150
|
# всегда нулевой. Это не позволяет нам легко понять, прошла ли генерация
|
|
145
151
|
# успешно для всех устройств. С этим флажком код будет ненулевой, если
|
|
@@ -353,6 +359,7 @@ opt_selected_context_name = Arg(
|
|
|
353
359
|
|
|
354
360
|
# ====
|
|
355
361
|
class CacheOptions(ArgGroup):
|
|
362
|
+
recache = opt_recache
|
|
356
363
|
no_mesh = False
|
|
357
364
|
|
|
358
365
|
|
annet/generators/__init__.py
CHANGED
|
@@ -26,11 +26,12 @@ from annet.types import (
|
|
|
26
26
|
)
|
|
27
27
|
from annet.vendors import registry_connector, tabparser
|
|
28
28
|
|
|
29
|
+
from .annotate import AbstractAnnotateFormatter, annotate_formatter_connector
|
|
29
30
|
from .base import BaseGenerator
|
|
30
31
|
from .base import ParamsList as ParamsList
|
|
31
32
|
from .base import TextGenerator as TextGenerator
|
|
32
33
|
from .entire import Entire
|
|
33
|
-
from .exceptions import GeneratorError, NotSupportedDevice
|
|
34
|
+
from .exceptions import GeneratorError, InvalidValueFromGenerator, NotSupportedDevice
|
|
34
35
|
from .jsonfragment import JSONFragment
|
|
35
36
|
from .partial import PartialGenerator
|
|
36
37
|
from .perf import GeneratorPerfMesurer
|
|
@@ -165,11 +166,10 @@ def _run_partial_generator(gen: "PartialGenerator", run_args: GeneratorPartialRu
|
|
|
165
166
|
safe_config = odict()
|
|
166
167
|
|
|
167
168
|
if not gen.supports_device(device):
|
|
168
|
-
logger.
|
|
169
|
+
logger.debug("generator %s is not supported for device %s", gen, device.hostname)
|
|
169
170
|
return None
|
|
170
171
|
|
|
171
|
-
span
|
|
172
|
-
if span:
|
|
172
|
+
if span := tracing_connector.get().get_current_span():
|
|
173
173
|
tracing_connector.get().set_device_attributes(span, run_args.device)
|
|
174
174
|
tracing_connector.get().set_dimensions_attributes(span, gen, run_args.device)
|
|
175
175
|
span.set_attributes({
|
|
@@ -184,8 +184,7 @@ def _run_partial_generator(gen: "PartialGenerator", run_args: GeneratorPartialRu
|
|
|
184
184
|
logger.info("Generating PARTIAL ...")
|
|
185
185
|
try:
|
|
186
186
|
output = gen(device, run_args.annotate)
|
|
187
|
-
except NotSupportedDevice:
|
|
188
|
-
# это исключение нужно передать выше в оригинальном виде
|
|
187
|
+
except NotSupportedDevice: # это исключение нужно передать выше в оригинальном виде
|
|
189
188
|
raise
|
|
190
189
|
except Exception as err:
|
|
191
190
|
filename, lineno = gen.get_running_line()
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
from types import GeneratorType
|
|
3
|
+
|
|
4
|
+
from annet.connectors import Connector
|
|
5
|
+
|
|
6
|
+
from .base import BaseGenerator
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AbstractAnnotateFormatter(abc.ABC):
|
|
10
|
+
def __init__(self, gen: BaseGenerator):
|
|
11
|
+
self.gen = gen
|
|
12
|
+
self._annotation_module = ".".join(gen.__class__.__module__.split(".")[-2:])
|
|
13
|
+
|
|
14
|
+
@abc.abstractmethod
|
|
15
|
+
def make_annotation(self, running_gen: GeneratorType) -> str:
|
|
16
|
+
raise NotImplementedError
|
|
17
|
+
|
|
18
|
+
def get_running_line(self, running_gen: GeneratorType) -> tuple[str, int]:
|
|
19
|
+
if not running_gen or not running_gen.gi_frame:
|
|
20
|
+
return repr(running_gen), -1
|
|
21
|
+
return self._annotation_module, running_gen.gi_frame.f_lineno
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class DefaultAnnotateFormatter(AbstractAnnotateFormatter):
|
|
25
|
+
def make_annotation(self, running_gen: GeneratorType) -> str:
|
|
26
|
+
return "%s:%d" % self.get_running_line(running_gen)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class _AnnotateFormatterConnector(Connector[AbstractAnnotateFormatter]):
|
|
30
|
+
name = "AnnotateFormatterConnector"
|
|
31
|
+
ep_name = "annotate_formatter"
|
|
32
|
+
|
|
33
|
+
def _get_default(self) -> type[AbstractAnnotateFormatter]:
|
|
34
|
+
return DefaultAnnotateFormatter
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
annotate_formatter_connector = _AnnotateFormatterConnector()
|
annet/generators/base.py
CHANGED
|
@@ -2,15 +2,20 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import abc
|
|
4
4
|
import contextlib
|
|
5
|
+
import re
|
|
5
6
|
import textwrap
|
|
6
|
-
from typing import
|
|
7
|
+
from typing import List, Union
|
|
7
8
|
|
|
8
9
|
from annet import tracing
|
|
9
|
-
from annet.vendors import tabparser
|
|
10
10
|
from annet.tracing import tracing_connector
|
|
11
|
+
from annet.vendors import tabparser
|
|
12
|
+
|
|
11
13
|
from .exceptions import InvalidValueFromGenerator
|
|
12
14
|
|
|
13
15
|
|
|
16
|
+
NONE_SEARCHER = re.compile(r"\bNone\b")
|
|
17
|
+
|
|
18
|
+
|
|
14
19
|
class DefaultBlockIfCondition:
|
|
15
20
|
pass
|
|
16
21
|
|
|
@@ -53,11 +58,15 @@ def _split_and_strip(text):
|
|
|
53
58
|
# =====
|
|
54
59
|
class BaseGenerator:
|
|
55
60
|
TYPE: str
|
|
56
|
-
TAGS: List[str]
|
|
61
|
+
TAGS: List[str] = []
|
|
57
62
|
|
|
58
63
|
def supports_device(self, device) -> bool: # pylint: disable=unused-argument
|
|
59
64
|
return True
|
|
60
65
|
|
|
66
|
+
@classmethod
|
|
67
|
+
def get_aliases(cls) -> set[str]:
|
|
68
|
+
return {cls.__name__, *cls.TAGS}
|
|
69
|
+
|
|
61
70
|
|
|
62
71
|
class TreeGenerator(BaseGenerator):
|
|
63
72
|
def __init__(self, indent=" "):
|
annet/generators/entire.py
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import pkgutil
|
|
4
|
-
import re
|
|
5
4
|
import types
|
|
6
|
-
from typing import FrozenSet, Iterable, List, Optional,
|
|
5
|
+
from typing import FrozenSet, Iterable, List, Optional, Union
|
|
7
6
|
|
|
8
7
|
from annet.lib import flatten, mako_render
|
|
9
8
|
|
|
10
|
-
from .base import BaseGenerator, _filter_str
|
|
11
|
-
from .exceptions import
|
|
9
|
+
from .base import NONE_SEARCHER, BaseGenerator, _filter_str
|
|
10
|
+
from .exceptions import InvalidValueFromGenerator
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
class Entire(BaseGenerator):
|
|
@@ -62,10 +61,6 @@ class Entire(BaseGenerator):
|
|
|
62
61
|
|
|
63
62
|
# =====
|
|
64
63
|
|
|
65
|
-
@classmethod
|
|
66
|
-
def get_aliases(cls) -> Set[str]:
|
|
67
|
-
return {cls.__name__, *cls.TAGS}
|
|
68
|
-
|
|
69
64
|
def __call__(self, device):
|
|
70
65
|
self.__device = device
|
|
71
66
|
parts = []
|
|
@@ -73,15 +68,19 @@ class Entire(BaseGenerator):
|
|
|
73
68
|
if isinstance(run_res, str):
|
|
74
69
|
run_res = (run_res,)
|
|
75
70
|
if run_res is None or not isinstance(run_res, (tuple, types.GeneratorType)):
|
|
76
|
-
raise Exception("generator %s returns %s" % (
|
|
77
|
-
|
|
71
|
+
raise Exception("generator %s returns %s" % (self.__class__.__name__, type(run_res)))
|
|
72
|
+
|
|
78
73
|
for text in run_res:
|
|
79
74
|
if isinstance(text, tuple):
|
|
80
75
|
text = " ".join(map(_filter_str, flatten(text)))
|
|
81
|
-
|
|
82
|
-
|
|
76
|
+
if NONE_SEARCHER.search(text):
|
|
77
|
+
raise InvalidValueFromGenerator(
|
|
78
|
+
"Found 'None' in yield result: %s" % text
|
|
79
|
+
)
|
|
83
80
|
parts.append(text)
|
|
81
|
+
|
|
84
82
|
ret = "\n".join(parts)
|
|
85
83
|
if self.ENSURE_END_NEWLINE and not ret.endswith("\n"):
|
|
86
84
|
ret += "\n"
|
|
85
|
+
|
|
87
86
|
return ret
|
annet/generators/jsonfragment.py
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import contextlib
|
|
4
|
-
from typing import
|
|
5
|
-
Any,
|
|
6
|
-
Dict,
|
|
7
|
-
List,
|
|
8
|
-
Optional,
|
|
9
|
-
Set,
|
|
10
|
-
Union,
|
|
11
|
-
)
|
|
4
|
+
from typing import Any, Optional, Union
|
|
12
5
|
|
|
13
6
|
from annet.storage import Device, Storage
|
|
7
|
+
|
|
14
8
|
from .base import TreeGenerator, _filter_str
|
|
15
9
|
|
|
16
10
|
|
|
@@ -18,13 +12,12 @@ class JSONFragment(TreeGenerator):
|
|
|
18
12
|
"""Generates parts of JSON config file."""
|
|
19
13
|
|
|
20
14
|
TYPE = "JSON_FRAGMENT"
|
|
21
|
-
TAGS: List[str] = []
|
|
22
15
|
|
|
23
16
|
def __init__(self, storage: Storage):
|
|
24
17
|
super().__init__()
|
|
25
18
|
self.storage = storage
|
|
26
|
-
self._json_config:
|
|
27
|
-
self._config_pointer:
|
|
19
|
+
self._json_config: dict[str, Any] = {}
|
|
20
|
+
self._config_pointer: list[str] = []
|
|
28
21
|
|
|
29
22
|
# if two generators edit same file, commands from generator with greater `reload_prio` will be used
|
|
30
23
|
if not hasattr(self, "reload_prio"):
|
|
@@ -36,11 +29,7 @@ class JSONFragment(TreeGenerator):
|
|
|
36
29
|
def path(self, device: Device) -> Optional[str]:
|
|
37
30
|
raise NotImplementedError("Required PATH for JSON_FRAGMENT generator")
|
|
38
31
|
|
|
39
|
-
|
|
40
|
-
def get_aliases(cls) -> Set[str]:
|
|
41
|
-
return {cls.__name__, *cls.TAGS}
|
|
42
|
-
|
|
43
|
-
def acl(self, device: Device) -> Union[str, List[str]]:
|
|
32
|
+
def acl(self, device: Device) -> Union[str, list[str]]:
|
|
44
33
|
"""
|
|
45
34
|
Restrict the generator to a specified ACL using JSON Pointer syntax.
|
|
46
35
|
|
|
@@ -48,7 +37,7 @@ class JSONFragment(TreeGenerator):
|
|
|
48
37
|
"""
|
|
49
38
|
raise NotImplementedError("Required ACL for JSON_FRAGMENT generator")
|
|
50
39
|
|
|
51
|
-
def acl_safe(self, device: Device) -> Union[str,
|
|
40
|
+
def acl_safe(self, device: Device) -> Union[str, list[str]]:
|
|
52
41
|
"""
|
|
53
42
|
Restrict the generator to a specified safe ACL using JSON Pointer syntax.
|
|
54
43
|
|
annet/generators/partial.py
CHANGED
|
@@ -1,32 +1,23 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
from annet.lib import (
|
|
12
|
-
add_annotation,
|
|
13
|
-
flatten,
|
|
14
|
-
)
|
|
15
|
-
from .base import TreeGenerator, _filter_str
|
|
16
|
-
from .exceptions import NotSupportedDevice
|
|
3
|
+
from typing import Iterable, Union
|
|
4
|
+
|
|
5
|
+
from annet.lib import add_annotation, flatten
|
|
6
|
+
|
|
7
|
+
from .annotate import AbstractAnnotateFormatter, annotate_formatter_connector
|
|
8
|
+
from .base import NONE_SEARCHER, TreeGenerator, _filter_str
|
|
9
|
+
from .exceptions import InvalidValueFromGenerator
|
|
17
10
|
|
|
18
11
|
|
|
19
12
|
class PartialGenerator(TreeGenerator):
|
|
20
13
|
TYPE = "PARTIAL"
|
|
21
|
-
TAGS: List[str] = []
|
|
22
14
|
|
|
23
15
|
def __init__(self, storage):
|
|
24
16
|
super().__init__()
|
|
25
17
|
self.storage = storage
|
|
26
|
-
self._annotate = False
|
|
27
18
|
self._running_gen = None
|
|
19
|
+
self._annotate: AbstractAnnotateFormatter = annotate_formatter_connector.get(self)
|
|
28
20
|
self._annotations = []
|
|
29
|
-
self._annotation_module = self.__class__.__module__ or ""
|
|
30
21
|
|
|
31
22
|
def supports_device(self, device) -> bool:
|
|
32
23
|
if self.__class__.run is PartialGenerator.run:
|
|
@@ -35,19 +26,19 @@ class PartialGenerator(TreeGenerator):
|
|
|
35
26
|
return True
|
|
36
27
|
|
|
37
28
|
def acl(self, device):
|
|
38
|
-
acl_func
|
|
39
|
-
if acl_func:
|
|
29
|
+
if acl_func := self._get_vendor_func(device.hw.vendor, "acl"):
|
|
40
30
|
return acl_func(device)
|
|
31
|
+
return None
|
|
41
32
|
|
|
42
33
|
def acl_safe(self, device):
|
|
43
|
-
acl_func
|
|
44
|
-
if acl_func:
|
|
34
|
+
if acl_func := self._get_vendor_func(device.hw.vendor, "acl_safe"):
|
|
45
35
|
return acl_func(device)
|
|
36
|
+
return None
|
|
46
37
|
|
|
47
|
-
def run(self, device) -> Iterable[Union[str, tuple]]:
|
|
48
|
-
run_func
|
|
49
|
-
if run_func:
|
|
38
|
+
def run(self, device) -> Iterable[Union[str, tuple]] | None:
|
|
39
|
+
if run_func := self._get_vendor_func(device.hw.vendor, "run"):
|
|
50
40
|
return run_func(device)
|
|
41
|
+
return None
|
|
51
42
|
|
|
52
43
|
def get_user_runner(self, device):
|
|
53
44
|
if self.__class__.run is not PartialGenerator.run:
|
|
@@ -56,26 +47,15 @@ class PartialGenerator(TreeGenerator):
|
|
|
56
47
|
|
|
57
48
|
def _get_vendor_func(self, vendor: str, func_name: str):
|
|
58
49
|
attr_name = f"{func_name}_{vendor}"
|
|
59
|
-
|
|
60
|
-
return getattr(self, attr_name)
|
|
61
|
-
return None
|
|
50
|
+
return getattr(self, attr_name, None)
|
|
62
51
|
|
|
63
52
|
# =====
|
|
64
53
|
|
|
65
|
-
|
|
66
|
-
def get_aliases(cls) -> Set[str]:
|
|
67
|
-
return {cls.__name__, *cls.TAGS}
|
|
68
|
-
|
|
69
|
-
def __call__(self, device, annotate=False):
|
|
54
|
+
def __call__(self, device, annotate: bool = False):
|
|
70
55
|
self._indents = []
|
|
71
56
|
self._rows = []
|
|
72
|
-
self._running_gen = self.run(device)
|
|
73
|
-
self._annotate = annotate
|
|
74
|
-
|
|
75
|
-
if annotate and self.__class__.__module__:
|
|
76
|
-
self._annotation_module = ".".join(
|
|
77
|
-
self.__class__.__module__.split(".")[-2:])
|
|
78
57
|
|
|
58
|
+
self._running_gen = self.run(device)
|
|
79
59
|
for text in self._running_gen:
|
|
80
60
|
if isinstance(text, tuple):
|
|
81
61
|
text = " ".join(map(_filter_str, flatten(text)))
|
|
@@ -83,9 +63,12 @@ class PartialGenerator(TreeGenerator):
|
|
|
83
63
|
text = _filter_str(text)
|
|
84
64
|
self._append_text(text)
|
|
85
65
|
|
|
86
|
-
for row in self._rows:
|
|
87
|
-
|
|
88
|
-
|
|
66
|
+
for (row, annotation) in zip(self._rows, self._annotations):
|
|
67
|
+
if NONE_SEARCHER.search(row):
|
|
68
|
+
raise InvalidValueFromGenerator(
|
|
69
|
+
"Found 'None' in yield result: %s" % add_annotation(row, annotation)
|
|
70
|
+
)
|
|
71
|
+
|
|
89
72
|
if annotate:
|
|
90
73
|
generated_rows = (
|
|
91
74
|
add_annotation(x, y)
|
|
@@ -93,23 +76,20 @@ class PartialGenerator(TreeGenerator):
|
|
|
93
76
|
)
|
|
94
77
|
else:
|
|
95
78
|
generated_rows = self._rows
|
|
96
|
-
|
|
79
|
+
|
|
80
|
+
return "\n".join((*generated_rows, ""))
|
|
97
81
|
|
|
98
82
|
def _append_text(self, text):
|
|
99
83
|
def annotation_cb(row):
|
|
100
|
-
|
|
101
|
-
|
|
84
|
+
self._annotations.append(
|
|
85
|
+
self._annotate.make_annotation(self._running_gen)
|
|
86
|
+
)
|
|
102
87
|
return row
|
|
103
88
|
|
|
104
|
-
self._append_text_cb(
|
|
105
|
-
text,
|
|
106
|
-
annotation_cb if self._annotate else None
|
|
107
|
-
)
|
|
89
|
+
self._append_text_cb(text, row_cb=annotation_cb)
|
|
108
90
|
|
|
109
|
-
def get_running_line(self):
|
|
110
|
-
|
|
111
|
-
return (repr(self._running_gen), -1)
|
|
112
|
-
return self._annotation_module, self._running_gen.gi_frame.f_lineno
|
|
91
|
+
def get_running_line(self) -> tuple[str, int]:
|
|
92
|
+
return self._annotate.get_running_line(self._running_gen)
|
|
113
93
|
|
|
114
94
|
@classmethod
|
|
115
95
|
def literal(cls, item):
|
annet/generators/result.py
CHANGED
|
@@ -2,19 +2,10 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import textwrap
|
|
4
4
|
from collections import OrderedDict as odict
|
|
5
|
-
from typing import
|
|
6
|
-
Any,
|
|
7
|
-
Callable,
|
|
8
|
-
Dict,
|
|
9
|
-
Optional,
|
|
10
|
-
Sequence,
|
|
11
|
-
Tuple,
|
|
12
|
-
)
|
|
5
|
+
from typing import Any, Callable, Optional, Sequence
|
|
13
6
|
|
|
14
7
|
from annet.annlib import jsontools
|
|
15
|
-
from annet.lib import
|
|
16
|
-
merge_dicts,
|
|
17
|
-
)
|
|
8
|
+
from annet.lib import merge_dicts
|
|
18
9
|
from annet.reference import RefMatcher, RefTracker
|
|
19
10
|
from annet.types import (
|
|
20
11
|
GeneratorEntireResult,
|
|
@@ -24,7 +15,7 @@ from annet.types import (
|
|
|
24
15
|
|
|
25
16
|
|
|
26
17
|
def _combine_acl_text(
|
|
27
|
-
partial_results:
|
|
18
|
+
partial_results: dict[str, GeneratorPartialResult],
|
|
28
19
|
acl_getter: Callable[[GeneratorPartialResult], str]
|
|
29
20
|
) -> str:
|
|
30
21
|
acl_text = ""
|
|
@@ -43,9 +34,9 @@ class RunGeneratorResult:
|
|
|
43
34
|
"""
|
|
44
35
|
|
|
45
36
|
def __init__(self):
|
|
46
|
-
self.partial_results:
|
|
47
|
-
self.entire_results:
|
|
48
|
-
self.json_fragment_results:
|
|
37
|
+
self.partial_results: dict[str, GeneratorPartialResult] = {}
|
|
38
|
+
self.entire_results: dict[str, GeneratorEntireResult] = {}
|
|
39
|
+
self.json_fragment_results: dict[str, GeneratorJSONFragmentResult] = {}
|
|
49
40
|
self.ref_track: RefTracker = RefTracker()
|
|
50
41
|
self.ref_matcher: RefMatcher = RefMatcher()
|
|
51
42
|
|
|
@@ -62,14 +53,14 @@ class RunGeneratorResult:
|
|
|
62
53
|
def add_json_fragment(self, result: GeneratorJSONFragmentResult) -> None:
|
|
63
54
|
self.json_fragment_results[result.name] = result
|
|
64
55
|
|
|
65
|
-
def config_tree(self, safe: bool = False) ->
|
|
56
|
+
def config_tree(self, safe: bool = False) -> dict[str, Any]: # OrderedDict
|
|
66
57
|
tree = odict()
|
|
67
58
|
for gr in self.partial_results.values():
|
|
68
59
|
config = gr.safe_config if safe else gr.config
|
|
69
60
|
tree = merge_dicts(tree, config)
|
|
70
61
|
return tree
|
|
71
62
|
|
|
72
|
-
def new_files(self, safe: bool = False) ->
|
|
63
|
+
def new_files(self, safe: bool = False) -> dict[str, tuple[str, str]]:
|
|
73
64
|
files = {}
|
|
74
65
|
for gr in self.entire_results.values():
|
|
75
66
|
if not safe or gr.is_safe:
|
|
@@ -84,14 +75,14 @@ class RunGeneratorResult:
|
|
|
84
75
|
|
|
85
76
|
def new_json_fragment_files(
|
|
86
77
|
self,
|
|
87
|
-
old_files:
|
|
78
|
+
old_files: dict[str, Optional[str]],
|
|
88
79
|
use_acl: bool = True,
|
|
89
80
|
safe: bool = False,
|
|
90
81
|
filters: Sequence[str] | None = None,
|
|
91
|
-
) ->
|
|
82
|
+
) -> dict[str, tuple[Any, Optional[str]]]:
|
|
92
83
|
# TODO: safe
|
|
93
|
-
files:
|
|
94
|
-
reload_prios:
|
|
84
|
+
files: dict[str, tuple[Any, Optional[str]]] = {}
|
|
85
|
+
reload_prios: dict[str, int] = {}
|
|
95
86
|
for generator_result in self.json_fragment_results.values():
|
|
96
87
|
filepath = generator_result.path
|
|
97
88
|
if filepath not in files:
|
|
@@ -105,7 +96,7 @@ class RunGeneratorResult:
|
|
|
105
96
|
result_acl = generator_result.acl_safe
|
|
106
97
|
else:
|
|
107
98
|
result_acl = None
|
|
108
|
-
previous_config:
|
|
99
|
+
previous_config: dict[str, Any] = files[filepath][0]
|
|
109
100
|
new_fragment = generator_result.config
|
|
110
101
|
new_config = jsontools.apply_json_fragment(
|
|
111
102
|
previous_config, new_fragment,
|
|
@@ -126,7 +117,7 @@ class RunGeneratorResult:
|
|
|
126
117
|
files[filepath] = (new_config, reload_cmd)
|
|
127
118
|
return files
|
|
128
119
|
|
|
129
|
-
def perf_mesures(self) ->
|
|
120
|
+
def perf_mesures(self) -> dict[str, dict[str, int]]:
|
|
130
121
|
mesures = {}
|
|
131
122
|
for gr in self.partial_results.values():
|
|
132
123
|
mesures[gr.name] = {"total": gr.perf.total,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: annet
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.20.0
|
|
4
4
|
Summary: annet
|
|
5
5
|
Home-page: https://github.com/annetutil/annet
|
|
6
6
|
License: MIT
|
|
@@ -22,7 +22,8 @@ Requires-Dist: adaptix==3.0.0b7
|
|
|
22
22
|
Requires-Dist: dataclass-rest==0.4
|
|
23
23
|
Requires-Dist: ordered-set>=4.1.0
|
|
24
24
|
Provides-Extra: netbox
|
|
25
|
-
Requires-Dist: annetbox[sync]>=0.
|
|
25
|
+
Requires-Dist: annetbox[sync]>=0.9.0; extra == "netbox"
|
|
26
|
+
Requires-Dist: requests-cache>=1.2.1; extra == "netbox"
|
|
26
27
|
Dynamic: home-page
|
|
27
28
|
Dynamic: license
|
|
28
29
|
Dynamic: license-file
|
|
@@ -3,7 +3,7 @@ annet/annet.py,sha256=vyQ__n5hkjub3aWO8tksHPoUSbTeK97MyMcR_U8_BSU,1016
|
|
|
3
3
|
annet/argparse.py,sha256=v1MfhjR0B8qahza0WinmXClpR8UiDFhmwDDWtNroJPA,12855
|
|
4
4
|
annet/bgp_models.py,sha256=roSDKhxzcg9N8iEh9zI4Jww1vOObWcwRVzMl9FJnh1M,14046
|
|
5
5
|
annet/cli.py,sha256=shq3hHzrTxFL3x1_zTOR43QHo0JYs8QSwyOvGtL86Co,12733
|
|
6
|
-
annet/cli_args.py,sha256=
|
|
6
|
+
annet/cli_args.py,sha256=GwFSEJDUZMzUtXo6NBs_1B7tlyFhaaKRfcgmRUpAkfI,13881
|
|
7
7
|
annet/connectors.py,sha256=aoiDVLPizx8CW2p8SAwGCzyO_WW8H9xc2aujbGC4bDg,4882
|
|
8
8
|
annet/deploy.py,sha256=toIaR2QLvLJxpdeXoJhZzKdXfhn784ciTNZlMGT9huo,7709
|
|
9
9
|
annet/deploy_ui.py,sha256=XsN1i7E9cNp1SAf1YBwhEBuwN91MvlNMSrLhnQrumA8,28672
|
|
@@ -28,7 +28,7 @@ annet/adapters/fetchers/stub/fetcher.py,sha256=FzpkIzPJBQVuNNSdXKoGzkALmIGMgo2gm
|
|
|
28
28
|
annet/adapters/file/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
29
|
annet/adapters/file/provider.py,sha256=Raw5DzsGS8I9XcKNeMuk5O3dPxqeRSCNmuB5JwClRqY,7687
|
|
30
30
|
annet/adapters/netbox/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
31
|
-
annet/adapters/netbox/provider.py,sha256=
|
|
31
|
+
annet/adapters/netbox/provider.py,sha256=UY9_5cRWQaieNkzerCmm67a4Nnokg1kilAoP314GU14,2467
|
|
32
32
|
annet/adapters/netbox/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
33
|
annet/adapters/netbox/common/adapter.py,sha256=1rR9PZAU72hIreozWFVb9CKpFVjfUH_i9kQEbaNiEUI,2639
|
|
34
34
|
annet/adapters/netbox/common/client.py,sha256=PaxHG4W9H8_uunIwMBNYkLq4eQJYoO6p6gY-ciQs7Nc,2563
|
|
@@ -36,20 +36,20 @@ annet/adapters/netbox/common/manufacturer.py,sha256=9jTfzwx5XmETrjSbIJu_FhNaByaU
|
|
|
36
36
|
annet/adapters/netbox/common/models.py,sha256=nMruBugAKNY8D63rqUnPYyMYGMIU-haxX0vnfxLGNWc,8990
|
|
37
37
|
annet/adapters/netbox/common/query.py,sha256=mz5oOn5vjU-lCV48TedvtXZ14GtBXU3jpcXa_cNawWg,1949
|
|
38
38
|
annet/adapters/netbox/common/status_client.py,sha256=POaqiQJ0jPcqUQH-X_fWHVnKB7TBYveNriaT0eNTlfI,769
|
|
39
|
-
annet/adapters/netbox/common/storage_base.py,sha256=
|
|
40
|
-
annet/adapters/netbox/common/storage_opts.py,sha256=
|
|
39
|
+
annet/adapters/netbox/common/storage_base.py,sha256=mdteEWxZAlw6re5FPciB5FoV2nAGnqozQdx-iNX-T80,10601
|
|
40
|
+
annet/adapters/netbox/common/storage_opts.py,sha256=pDtkFpfVIoRLBruMYNuIC34XpZe9aRrAygy2cOVpqyU,2800
|
|
41
41
|
annet/adapters/netbox/v24/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
42
42
|
annet/adapters/netbox/v24/models.py,sha256=RH2ooUPHOtHT0q1ZQE7v23FgmcsGenzzSgJyft13o1k,7605
|
|
43
43
|
annet/adapters/netbox/v24/storage.py,sha256=zptzrW4aZUv_exuGw0DqQPm_kXZR3DwL4zRHYL6twTk,6219
|
|
44
44
|
annet/adapters/netbox/v37/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
45
|
annet/adapters/netbox/v37/models.py,sha256=LTjotRcTYWUR3KFvdg3LjBhek4OQblOvJr5yvP9AAPg,1940
|
|
46
|
-
annet/adapters/netbox/v37/storage.py,sha256=
|
|
46
|
+
annet/adapters/netbox/v37/storage.py,sha256=DKPCIucpND8M7ebhfhm6lWCcVYif0vtcaJ0mZu22YCU,5362
|
|
47
47
|
annet/adapters/netbox/v41/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
48
48
|
annet/adapters/netbox/v41/models.py,sha256=RI8QHpNIcrXNubis1rUFJ1j9bL881fz4meLXvAY8Yi0,2197
|
|
49
|
-
annet/adapters/netbox/v41/storage.py,sha256=
|
|
49
|
+
annet/adapters/netbox/v41/storage.py,sha256=ZMvNJbXb1XN8WKcAY2cTL_Ybyjk_QOwbxzD93do9DXM,5417
|
|
50
50
|
annet/adapters/netbox/v42/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
51
51
|
annet/adapters/netbox/v42/models.py,sha256=JNrBMeZ1SznjRzaqKNBP5jtHEKHN40X1V-BlgrMpKwE,2054
|
|
52
|
-
annet/adapters/netbox/v42/storage.py,sha256=
|
|
52
|
+
annet/adapters/netbox/v42/storage.py,sha256=Dg6kiSOVXO2ApXXgQGRdrE4GLd8EkeeRhE6aGxHGvMU,6325
|
|
53
53
|
annet/annlib/__init__.py,sha256=fT1l4xV5fqqg8HPw9HqmZVN2qwS8i6X1aIm2zGDjxKY,252
|
|
54
54
|
annet/annlib/command.py,sha256=GsgzQ8oFiHFan1Tfyo340rWgfhyU4_sCKJGhBm2jG6Y,1258
|
|
55
55
|
annet/annlib/diff.py,sha256=MZ6eQAU3cadQp8KaSE6uAYFtcfMDCIe_eNuVROnYkCk,4496
|
|
@@ -78,15 +78,16 @@ annet/annlib/rulebook/common.py,sha256=6A3sOkOanDRTuR7F426zakShGaGKRBmBLDCnqBbBJ
|
|
|
78
78
|
annet/api/__init__.py,sha256=5YzScmeCDsHiDhtT3RwY_lMuikRZ6o7CVrlnJCln2A8,34116
|
|
79
79
|
annet/configs/context.yml,sha256=RVLrKLIHpCty7AGwOnmqf7Uu0iZQCn-AjYhophDJer8,259
|
|
80
80
|
annet/configs/logging.yaml,sha256=EUagfir99QqA73Scc3k7sfQccbU3E1SvEQdyhLFtCl4,997
|
|
81
|
-
annet/generators/__init__.py,sha256=
|
|
82
|
-
annet/generators/
|
|
83
|
-
annet/generators/
|
|
81
|
+
annet/generators/__init__.py,sha256=jxQJ5rLeXHiWGJgwhqygmBgCJsxc6oG-E9gDI9LzLog,16818
|
|
82
|
+
annet/generators/annotate.py,sha256=TG7ozOkQmjiz7BVAKRrXfvuekGBR5Wl1nKmA4PLkG_g,1188
|
|
83
|
+
annet/generators/base.py,sha256=qvvxKFzvgJWGBUcw8_bK1oFKTc4AQotN4CCuICWHXSk,3850
|
|
84
|
+
annet/generators/entire.py,sha256=H_xQ33GH8P696fnKBFFJs9NQcdX9h-gV3D-jJYtpX0U,2823
|
|
84
85
|
annet/generators/exceptions.py,sha256=GPXTBgn2xZ3Ev_bdOPlfCLGRC1kQHe_dEq88S-uyi5s,151
|
|
85
|
-
annet/generators/jsonfragment.py,sha256=
|
|
86
|
-
annet/generators/partial.py,sha256=
|
|
86
|
+
annet/generators/jsonfragment.py,sha256=H_hmZTHwnm_cToUbBNQRLf_1LlOZgLuXpSWpCVZ177o,4212
|
|
87
|
+
annet/generators/partial.py,sha256=lm6uCTUDgGq7MFPmnAOzGochNwu7nUVy7x2dvW9OkBI,3167
|
|
87
88
|
annet/generators/perf.py,sha256=IaAcfEVtX7UNO11VOCXzp-FPj_tOx_CDQ34HGThCn4c,2225
|
|
88
89
|
annet/generators/ref.py,sha256=QVdeL8po1D0kBsVLOpCjFR81D8yNTk-kaQj5WUM4hng,438
|
|
89
|
-
annet/generators/result.py,sha256=
|
|
90
|
+
annet/generators/result.py,sha256=XnVaCsRVAKxlARM7jFERu5KzGmWFrJJJ_FcMuqp7mwQ,5136
|
|
90
91
|
annet/generators/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
91
92
|
annet/generators/common/initial.py,sha256=qYBxXFhyOPy34cxc6hsIXseod-lYCmmbuNHpM0uteY0,1244
|
|
92
93
|
annet/mesh/__init__.py,sha256=lcgdnBIxc2MAN7Er1bcErEKPqrjWO4uIp_1FldMXTYg,557
|
|
@@ -208,8 +209,8 @@ annet/vendors/library/optixtrans.py,sha256=VdME69Ca4HAEgoaKN21fZxnmmsqqaxOe_HZja
|
|
|
208
209
|
annet/vendors/library/pc.py,sha256=vfv31_NPi7M-4AUDL89UcpawK2E6xvCpELA209cd1ho,1086
|
|
209
210
|
annet/vendors/library/ribbon.py,sha256=DDOBq-_-FL9dCxqXs2inEWZ-pvw-dJ-A-prA7cKMhec,1216
|
|
210
211
|
annet/vendors/library/routeros.py,sha256=iQa7m_4wjuvcgBOI9gyZwlw1BvzJfOkvUbyoEk-NI9I,1254
|
|
211
|
-
annet-3.
|
|
212
|
-
annet-3.
|
|
212
|
+
annet-3.20.0.dist-info/licenses/AUTHORS,sha256=rh3w5P6gEgqmuC-bw-HB68vBCr-yIBFhVL0PG4hguLs,878
|
|
213
|
+
annet-3.20.0.dist-info/licenses/LICENSE,sha256=yPxl7dno02Pw7gAcFPIFONzx_gapwDoPXsIsh6Y7lC0,1079
|
|
213
214
|
annet_generators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
214
215
|
annet_generators/example/__init__.py,sha256=OJ77uj8axc-FIyIu_Xdcnzmde3oQW5mk5qbODkhuVc8,355
|
|
215
216
|
annet_generators/example/hostname.py,sha256=RloLzNVetEoWPLITzfJ13Nk3CC0yi-cZB1RTd6dnuhI,2541
|
|
@@ -222,8 +223,8 @@ annet_generators/rpl_example/generator.py,sha256=EWah19gOH8G-QyNyWqxCqdRi0BK7GbM
|
|
|
222
223
|
annet_generators/rpl_example/items.py,sha256=HPgxScDvSqJPdz0c2SppDrH82DZYC4zUaniQwcWmh4A,1176
|
|
223
224
|
annet_generators/rpl_example/mesh.py,sha256=z_WgfDZZ4xnyh3cSf75igyH09hGvtexEVwy1gCD_DzA,288
|
|
224
225
|
annet_generators/rpl_example/route_policy.py,sha256=z6nPb0VDeQtKD1NIg9sFvmUxBD5tVs2frfNIuKdM-5c,2318
|
|
225
|
-
annet-3.
|
|
226
|
-
annet-3.
|
|
227
|
-
annet-3.
|
|
228
|
-
annet-3.
|
|
229
|
-
annet-3.
|
|
226
|
+
annet-3.20.0.dist-info/METADATA,sha256=HLKfcTZGcmRvrYEwMMntQjHeVCTXS9BqVp1kEtiNtqA,906
|
|
227
|
+
annet-3.20.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
228
|
+
annet-3.20.0.dist-info/entry_points.txt,sha256=5lIaDGlGi3l6QQ2ry2jZaqViP5Lvt8AmsegdD0Uznck,192
|
|
229
|
+
annet-3.20.0.dist-info/top_level.txt,sha256=QsoTZBsUtwp_FEcmRwuN8QITBmLOZFqjssRfKilGbP8,23
|
|
230
|
+
annet-3.20.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|