nbforager 0.5.0__tar.gz → 0.6.0__tar.gz
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.
- {nbforager-0.5.0 → nbforager-0.6.0}/PKG-INFO +6 -6
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/api/base_c.py +2 -2
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/api/connector.py +1 -1
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/foragers/base_fa.py +1 -3
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/foragers/circuits.py +2 -3
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/foragers/core.py +2 -3
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/foragers/dcim.py +2 -3
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/foragers/extras.py +2 -3
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/foragers/forager.py +1 -14
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/foragers/ipam.py +2 -3
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/foragers/tenancy.py +2 -3
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/foragers/users.py +2 -3
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/foragers/virtualization.py +2 -3
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/foragers/wireless.py +2 -3
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/nb_forager.py +9 -33
- {nbforager-0.5.0 → nbforager-0.6.0}/pyproject.toml +26 -21
- nbforager-0.5.0/nbforager/py_tree.py +0 -266
- {nbforager-0.5.0 → nbforager-0.6.0}/LICENSE.txt +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/README.rst +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/__init__.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/api/__init__.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/api/base_ac.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/api/circuits.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/api/core.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/api/dcim.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/api/extended_get.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/api/extras.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/api/ip_addresses.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/api/ipam.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/api/plugins_ca.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/api/status.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/api/tenancy.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/api/users.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/api/virtualization.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/api/wireless.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/exceptions.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/foragers/__init__.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/foragers/ipv4.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/foragers/joiner.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/helpers.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/log.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/messages.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/nb_api.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/nb_cache.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/nb_tree.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/parser/__init__.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/parser/nb_custom.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/parser/nb_parser.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/parser/nb_value.py +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/py.typed +0 -0
- {nbforager-0.5.0 → nbforager-0.6.0}/nbforager/types_.py +0 -0
@@ -1,8 +1,7 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.3
|
2
2
|
Name: nbforager
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.6.0
|
4
4
|
Summary: Python package designed to assist in working with the Netbox REST API. The filter parameters are identical to those in the Web UI filter form. It replaces brief data with full information, and Netbox objects are represented as a recursive multidimensional dictionary.
|
5
|
-
Home-page: https://github.com/vladimirs-git/nbforager
|
6
5
|
License: Apache-2.0
|
7
6
|
Keywords: netbox
|
8
7
|
Author: Vladimirs Prusakovs
|
@@ -18,18 +17,19 @@ Classifier: Programming Language :: Python :: 3.9
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.10
|
19
18
|
Classifier: Programming Language :: Python :: 3.11
|
20
19
|
Classifier: Programming Language :: Python :: 3.12
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
21
21
|
Provides-Extra: test
|
22
22
|
Requires-Dist: ciscoconfparse (>=1.9,<2.0)
|
23
23
|
Requires-Dist: netports (>=0.14,<1.0.0)
|
24
24
|
Requires-Dist: pydantic (>=2,<3)
|
25
|
-
Requires-Dist: pynetbox (>=7.3.3,<8.0.0)
|
26
25
|
Requires-Dist: requests (>=2,<3)
|
27
26
|
Requires-Dist: tabulate (>=0.9.0,<0.10.0)
|
28
27
|
Requires-Dist: tomli (==2.0.1)
|
29
28
|
Requires-Dist: vhelpers (>=0.3,<1.0.0)
|
30
29
|
Project-URL: Bug Tracker, https://github.com/vladimirs-git/nbforager/issues
|
31
|
-
Project-URL: Download URL, https://github.com/vladimirs-git/nbforager/archive/refs/tags/0.
|
32
|
-
Project-URL:
|
30
|
+
Project-URL: Download URL, https://github.com/vladimirs-git/nbforager/archive/refs/tags/0.6.0.tar.gz
|
31
|
+
Project-URL: homepage, https://github.com/vladimirs-git/nbforager
|
32
|
+
Project-URL: repository, https://github.com/vladimirs-git/nbforager
|
33
33
|
Description-Content-Type: text/x-rst
|
34
34
|
|
35
35
|
|
@@ -355,12 +355,12 @@ class BaseC:
|
|
355
355
|
:return: Max limit value, update params_d["limit"] value
|
356
356
|
"""
|
357
357
|
limit = 0
|
358
|
-
if limit_ := vdict.pop(params_d, key="limit") or []:
|
358
|
+
if limit_ := list(vdict.pop(data=params_d, key="limit") or []):
|
359
359
|
limit = int(limit_[0])
|
360
360
|
if not limit:
|
361
361
|
limit = self.limit
|
362
362
|
max_limit = 0
|
363
|
-
if max_limit_ := vdict.pop(params_d, key="max_limit") or []:
|
363
|
+
if max_limit_ := list(vdict.pop(data=params_d, key="max_limit") or []):
|
364
364
|
max_limit = int(max_limit_[0])
|
365
365
|
if max_limit and max_limit < limit:
|
366
366
|
limit = max_limit
|
@@ -4,14 +4,13 @@ from nbforager import helpers as h
|
|
4
4
|
from nbforager.api import ConnectorA
|
5
5
|
from nbforager.nb_api import NbApi
|
6
6
|
from nbforager.nb_tree import NbTree
|
7
|
-
from nbforager.py_tree import PyTree
|
8
7
|
from nbforager.types_ import LStr
|
9
8
|
|
10
9
|
|
11
10
|
class BaseAF:
|
12
11
|
"""Base for Application Foragers."""
|
13
12
|
|
14
|
-
def __init__(self, api: NbApi, root: NbTree, tree: NbTree
|
13
|
+
def __init__(self, api: NbApi, root: NbTree, tree: NbTree):
|
15
14
|
"""Init BaseAF.
|
16
15
|
|
17
16
|
:param root: Dictionary where data from Netbox needs to be saved.
|
@@ -19,7 +18,6 @@ class BaseAF:
|
|
19
18
|
self.api = api
|
20
19
|
self.root: NbTree = root
|
21
20
|
self.tree: NbTree = tree
|
22
|
-
self.pynb: PyTree = pynb
|
23
21
|
self.app: str = h.attr_name(self)
|
24
22
|
self.connector: ConnectorA = getattr(api, self.app) # connector to application
|
25
23
|
|
@@ -6,20 +6,19 @@ from nbforager.foragers.base_fa import BaseAF
|
|
6
6
|
from nbforager.foragers.forager import Forager
|
7
7
|
from nbforager.nb_api import NbApi
|
8
8
|
from nbforager.nb_tree import NbTree
|
9
|
-
from nbforager.py_tree import PyTree
|
10
9
|
|
11
10
|
|
12
11
|
class CircuitsAF(BaseAF):
|
13
12
|
"""Circuits Forager."""
|
14
13
|
|
15
|
-
def __init__(self, api: NbApi, root: NbTree, tree: NbTree
|
14
|
+
def __init__(self, api: NbApi, root: NbTree, tree: NbTree):
|
16
15
|
"""Init CircuitsAF.
|
17
16
|
|
18
17
|
:param api: NbApi object, connector to Netbox API.
|
19
18
|
:param root: NbTree object where raw data from Netbox needs to be saved.
|
20
19
|
:param tree: NbTree object where transformed data from Netbox needs to be saved.
|
21
20
|
"""
|
22
|
-
super().__init__(api, root, tree
|
21
|
+
super().__init__(api, root, tree)
|
23
22
|
self.circuit_terminations = self.CircuitTerminationsF(self)
|
24
23
|
self.circuit_types = self.CircuitTypesF(self)
|
25
24
|
self.circuits = self.CircuitsF(self)
|
@@ -6,20 +6,19 @@ from nbforager.foragers.base_fa import BaseAF
|
|
6
6
|
from nbforager.foragers.forager import Forager
|
7
7
|
from nbforager.nb_api import NbApi
|
8
8
|
from nbforager.nb_tree import NbTree
|
9
|
-
from nbforager.py_tree import PyTree
|
10
9
|
|
11
10
|
|
12
11
|
class CoreAF(BaseAF):
|
13
12
|
"""Core Forager."""
|
14
13
|
|
15
|
-
def __init__(self, api: NbApi, root: NbTree, tree: NbTree
|
14
|
+
def __init__(self, api: NbApi, root: NbTree, tree: NbTree):
|
16
15
|
"""Init CoreAF.
|
17
16
|
|
18
17
|
:param api: NbApi object, connector to Netbox API.
|
19
18
|
:param root: NbTree object where raw data from Netbox needs to be saved.
|
20
19
|
:param tree: NbTree object where transformed data from Netbox needs to be saved.
|
21
20
|
"""
|
22
|
-
super().__init__(api, root, tree
|
21
|
+
super().__init__(api, root, tree)
|
23
22
|
self.data_files = self.DataFilesF(self)
|
24
23
|
self.data_sources = self.DataSourcesF(self)
|
25
24
|
self.jobs = self.JobsF(self)
|
@@ -6,20 +6,19 @@ from nbforager.foragers.base_fa import BaseAF
|
|
6
6
|
from nbforager.foragers.forager import Forager
|
7
7
|
from nbforager.nb_api import NbApi
|
8
8
|
from nbforager.nb_tree import NbTree
|
9
|
-
from nbforager.py_tree import PyTree
|
10
9
|
|
11
10
|
|
12
11
|
class DcimAF(BaseAF):
|
13
12
|
"""DCIM Forager."""
|
14
13
|
|
15
|
-
def __init__(self, api: NbApi, root: NbTree, tree: NbTree
|
14
|
+
def __init__(self, api: NbApi, root: NbTree, tree: NbTree):
|
16
15
|
"""Init DcimAF.
|
17
16
|
|
18
17
|
:param api: NbApi object, connector to Netbox API.
|
19
18
|
:param root: NbTree object where raw data from Netbox needs to be saved.
|
20
19
|
:param tree: NbTree object where transformed data from Netbox needs to be saved.
|
21
20
|
"""
|
22
|
-
super().__init__(api, root, tree
|
21
|
+
super().__init__(api, root, tree)
|
23
22
|
self.cable_terminations = self.CableTerminationsF(self)
|
24
23
|
self.cables = self.CablesF(self)
|
25
24
|
# connected_device, is not model
|
@@ -6,20 +6,19 @@ from nbforager.foragers.base_fa import BaseAF
|
|
6
6
|
from nbforager.foragers.forager import Forager
|
7
7
|
from nbforager.nb_api import NbApi
|
8
8
|
from nbforager.nb_tree import NbTree
|
9
|
-
from nbforager.py_tree import PyTree
|
10
9
|
|
11
10
|
|
12
11
|
class ExtrasAF(BaseAF):
|
13
12
|
"""Extras Forager."""
|
14
13
|
|
15
|
-
def __init__(self, api: NbApi, root: NbTree, tree: NbTree
|
14
|
+
def __init__(self, api: NbApi, root: NbTree, tree: NbTree):
|
16
15
|
"""Init ExtrasAF.
|
17
16
|
|
18
17
|
:param api: NbApi object, connector to Netbox API.
|
19
18
|
:param root: NbTree object where raw data from Netbox needs to be saved.
|
20
19
|
:param tree: NbTree object where transformed data from Netbox needs to be saved.
|
21
20
|
"""
|
22
|
-
super().__init__(api, root, tree
|
21
|
+
super().__init__(api, root, tree)
|
23
22
|
self.bookmarks = self.BookmarksF(self)
|
24
23
|
self.config_contexts = self.ConfigContextsF(self)
|
25
24
|
self.config_templates = self.ConfigTemplatesF(self)
|
@@ -16,8 +16,7 @@ from nbforager import nb_tree
|
|
16
16
|
from nbforager.nb_api import NbApi
|
17
17
|
from nbforager.nb_tree import NbTree
|
18
18
|
from nbforager.parser import nb_parser
|
19
|
-
from nbforager.
|
20
|
-
from nbforager.types_ import LDAny, DiDAny, LStr, LT2StrDAny, DList, LDList, DiAny, SInt, DAny
|
19
|
+
from nbforager.types_ import LDAny, DiDAny, LStr, LT2StrDAny, DList, LDList, SInt, DAny
|
21
20
|
|
22
21
|
|
23
22
|
class Forager:
|
@@ -40,7 +39,6 @@ class Forager:
|
|
40
39
|
self.root_d: DiDAny = getattr(getattr(self.root, app), model)
|
41
40
|
self.tree: NbTree = forager_a.tree
|
42
41
|
self.tree_d: DiDAny = getattr(getattr(self.tree, app), model)
|
43
|
-
self.pynb: PyTree = forager_a.pynb
|
44
42
|
|
45
43
|
def __repr__(self) -> str:
|
46
44
|
"""__repr__."""
|
@@ -340,17 +338,6 @@ class Forager:
|
|
340
338
|
data["_nested"] = False
|
341
339
|
model_d[idx] = data
|
342
340
|
|
343
|
-
def _get_pynb_data(self, path: str) -> DiAny:
|
344
|
-
"""Get data in self pynb by app/model path.
|
345
|
-
|
346
|
-
:param path: The app/model path.
|
347
|
-
|
348
|
-
:return: The model data.
|
349
|
-
"""
|
350
|
-
app, model = h.path_to_attrs(path)
|
351
|
-
data = getattr(getattr(self.pynb, app), model)
|
352
|
-
return data
|
353
|
-
|
354
341
|
def _get_root_data(self, path: str) -> DiDAny:
|
355
342
|
"""Get data in self root by app/model path.
|
356
343
|
|
@@ -6,20 +6,19 @@ from nbforager.foragers.base_fa import BaseAF
|
|
6
6
|
from nbforager.foragers.forager import Forager
|
7
7
|
from nbforager.nb_api import NbApi
|
8
8
|
from nbforager.nb_tree import NbTree
|
9
|
-
from nbforager.py_tree import PyTree
|
10
9
|
|
11
10
|
|
12
11
|
class IpamAF(BaseAF):
|
13
12
|
"""IPAM Forager."""
|
14
13
|
|
15
|
-
def __init__(self, api: NbApi, root: NbTree, tree: NbTree
|
14
|
+
def __init__(self, api: NbApi, root: NbTree, tree: NbTree):
|
16
15
|
"""Init IpamAF.
|
17
16
|
|
18
17
|
:param api: NbApi object, connector to Netbox API.
|
19
18
|
:param root: NbTree object where raw data from Netbox needs to be saved.
|
20
19
|
:param tree: NbTree object where transformed data from Netbox needs to be saved.
|
21
20
|
"""
|
22
|
-
super().__init__(api, root, tree
|
21
|
+
super().__init__(api, root, tree)
|
23
22
|
self.aggregates = self.AggregatesF(self)
|
24
23
|
self.asn_ranges = self.AsnRangesF(self)
|
25
24
|
self.asns = self.AsnsF(self)
|
@@ -6,20 +6,19 @@ from nbforager.foragers.base_fa import BaseAF
|
|
6
6
|
from nbforager.foragers.forager import Forager
|
7
7
|
from nbforager.nb_api import NbApi
|
8
8
|
from nbforager.nb_tree import NbTree
|
9
|
-
from nbforager.py_tree import PyTree
|
10
9
|
|
11
10
|
|
12
11
|
class TenancyAF(BaseAF):
|
13
12
|
"""Tenancy Forager."""
|
14
13
|
|
15
|
-
def __init__(self, api: NbApi, root: NbTree, tree: NbTree
|
14
|
+
def __init__(self, api: NbApi, root: NbTree, tree: NbTree):
|
16
15
|
"""Init TenancyAF.
|
17
16
|
|
18
17
|
:param api: NbApi object, connector to Netbox API.
|
19
18
|
:param root: NbTree object where raw data from Netbox needs to be saved.
|
20
19
|
:param tree: NbTree object where transformed data from Netbox needs to be saved.
|
21
20
|
"""
|
22
|
-
super().__init__(api, root, tree
|
21
|
+
super().__init__(api, root, tree)
|
23
22
|
self.contact_assignments = self.ContactAssignmentsF(self)
|
24
23
|
self.contact_groups = self.ContactGroupsF(self)
|
25
24
|
self.contact_roles = self.ContactRolesF(self)
|
@@ -6,20 +6,19 @@ from nbforager.foragers.base_fa import BaseAF
|
|
6
6
|
from nbforager.foragers.forager import Forager
|
7
7
|
from nbforager.nb_api import NbApi
|
8
8
|
from nbforager.nb_tree import NbTree
|
9
|
-
from nbforager.py_tree import PyTree
|
10
9
|
|
11
10
|
|
12
11
|
class UsersAF(BaseAF):
|
13
12
|
"""Users Forager."""
|
14
13
|
|
15
|
-
def __init__(self, api: NbApi, root: NbTree, tree: NbTree
|
14
|
+
def __init__(self, api: NbApi, root: NbTree, tree: NbTree):
|
16
15
|
"""Init UsersAF.
|
17
16
|
|
18
17
|
:param api: NbApi object, connector to Netbox API.
|
19
18
|
:param root: NbTree object where raw data from Netbox needs to be saved.
|
20
19
|
:param tree: NbTree object where transformed data from Netbox needs to be saved.
|
21
20
|
"""
|
22
|
-
super().__init__(api, root, tree
|
21
|
+
super().__init__(api, root, tree)
|
23
22
|
# config: is not DiDAny
|
24
23
|
self.groups = self.GroupsF(self)
|
25
24
|
self.permissions = self.PermissionsF(self)
|
@@ -6,20 +6,19 @@ from nbforager.foragers.base_fa import BaseAF
|
|
6
6
|
from nbforager.foragers.forager import Forager
|
7
7
|
from nbforager.nb_api import NbApi
|
8
8
|
from nbforager.nb_tree import NbTree
|
9
|
-
from nbforager.py_tree import PyTree
|
10
9
|
|
11
10
|
|
12
11
|
class VirtualizationAF(BaseAF):
|
13
12
|
"""Virtualization Virtualization."""
|
14
13
|
|
15
|
-
def __init__(self, api: NbApi, root: NbTree, tree: NbTree
|
14
|
+
def __init__(self, api: NbApi, root: NbTree, tree: NbTree):
|
16
15
|
"""Init VirtualizationAF.
|
17
16
|
|
18
17
|
:param api: NbApi object, connector to Netbox API.
|
19
18
|
:param root: NbTree object where raw data from Netbox needs to be saved.
|
20
19
|
:param tree: NbTree object where transformed data from Netbox needs to be saved.
|
21
20
|
"""
|
22
|
-
super().__init__(api, root, tree
|
21
|
+
super().__init__(api, root, tree)
|
23
22
|
self.cluster_groups = self.ClusterGroupsF(self)
|
24
23
|
self.cluster_types = self.ClusterTypesF(self)
|
25
24
|
self.clusters = self.ClustersF(self)
|
@@ -6,20 +6,19 @@ from nbforager.foragers.base_fa import BaseAF
|
|
6
6
|
from nbforager.foragers.forager import Forager
|
7
7
|
from nbforager.nb_api import NbApi
|
8
8
|
from nbforager.nb_tree import NbTree
|
9
|
-
from nbforager.py_tree import PyTree
|
10
9
|
|
11
10
|
|
12
11
|
class WirelessAF(BaseAF):
|
13
12
|
"""Wireless Forager."""
|
14
13
|
|
15
|
-
def __init__(self, api: NbApi, root: NbTree, tree: NbTree
|
14
|
+
def __init__(self, api: NbApi, root: NbTree, tree: NbTree):
|
16
15
|
"""Init WirelessAF.
|
17
16
|
|
18
17
|
:param api: NbApi object, connector to Netbox API.
|
19
18
|
:param root: NbTree object where raw data from Netbox needs to be saved.
|
20
19
|
:param tree: NbTree object where transformed data from Netbox needs to be saved.
|
21
20
|
"""
|
22
|
-
super().__init__(api, root, tree
|
21
|
+
super().__init__(api, root, tree)
|
23
22
|
self.wireless_lan_groups = self.WirelessLanGroupsF(self)
|
24
23
|
self.wireless_lans = self.WirelessLansF(self)
|
25
24
|
self.wireless_links = self.WirelessLinksF(self)
|
@@ -10,8 +10,6 @@ from copy import deepcopy
|
|
10
10
|
from datetime import datetime
|
11
11
|
from pathlib import Path
|
12
12
|
|
13
|
-
import pynetbox
|
14
|
-
from pynetbox.core.endpoint import Endpoint
|
15
13
|
from vhelpers import vstr
|
16
14
|
|
17
15
|
from nbforager import nb_tree
|
@@ -30,7 +28,6 @@ from nbforager.nb_api import NbApi
|
|
30
28
|
from nbforager.nb_cache import NbCache
|
31
29
|
from nbforager.nb_tree import NbTree
|
32
30
|
from nbforager.parser.nb_value import NbValue
|
33
|
-
from nbforager.py_tree import PyTree
|
34
31
|
from nbforager.types_ import LStr, DAny, DiDAny, ODLStr, ODDAny
|
35
32
|
|
36
33
|
|
@@ -130,8 +127,6 @@ class NbForager:
|
|
130
127
|
:ivar obj root: :py:class:`NbTree` object that holds raw Netbox objects.
|
131
128
|
It is data source for the tree.
|
132
129
|
:ivar obj tree: :py:class:`NbTree` object that holds joined Netbox objects.
|
133
|
-
:ivar obj pynb: :py:class:`PyTree` object that holds pynetbox objects,
|
134
|
-
documented on https://pynetbox.readthedocs.io/
|
135
130
|
:ivar dict status: Result from Netbox status endpoint. Netbox version.
|
136
131
|
|
137
132
|
Application/model foragers:
|
@@ -168,24 +163,22 @@ class NbForager:
|
|
168
163
|
# data
|
169
164
|
self.root: NbTree = NbTree() # original data
|
170
165
|
self.tree: NbTree = NbTree() # data with joined objects within itself
|
171
|
-
self.pynb: PyTree = PyTree() # data with pynetbox objects
|
172
166
|
self.status: DAny = {} # updated Netbox status data
|
173
167
|
|
174
168
|
self.api = NbApi(**kwargs)
|
175
|
-
self.pyapi = pynetbox.api(url=f"{scheme}://{host}", token=token)
|
176
169
|
self.cache: str = make_cache_path(cache, **kwargs)
|
177
170
|
self.msgs = Messages(name=self.api.host)
|
178
171
|
|
179
172
|
# application foragers
|
180
|
-
self.circuits = CircuitsAF(self.api, self.root, self.tree
|
181
|
-
self.core = CoreAF(self.api, self.root, self.tree
|
182
|
-
self.dcim = DcimAF(self.api, self.root, self.tree
|
183
|
-
self.extras = ExtrasAF(self.api, self.root, self.tree
|
184
|
-
self.ipam = IpamAF(self.api, self.root, self.tree
|
185
|
-
self.tenancy = TenancyAF(self.api, self.root, self.tree
|
186
|
-
self.users = UsersAF(self.api, self.root, self.tree
|
187
|
-
self.virtualization = VirtualizationAF(self.api, self.root, self.tree
|
188
|
-
self.wireless = WirelessAF(self.api, self.root, self.tree
|
173
|
+
self.circuits = CircuitsAF(self.api, self.root, self.tree)
|
174
|
+
self.core = CoreAF(self.api, self.root, self.tree)
|
175
|
+
self.dcim = DcimAF(self.api, self.root, self.tree)
|
176
|
+
self.extras = ExtrasAF(self.api, self.root, self.tree)
|
177
|
+
self.ipam = IpamAF(self.api, self.root, self.tree)
|
178
|
+
self.tenancy = TenancyAF(self.api, self.root, self.tree)
|
179
|
+
self.users = UsersAF(self.api, self.root, self.tree)
|
180
|
+
self.virtualization = VirtualizationAF(self.api, self.root, self.tree)
|
181
|
+
self.wireless = WirelessAF(self.api, self.root, self.tree)
|
189
182
|
|
190
183
|
def __repr__(self) -> str:
|
191
184
|
"""__repr__."""
|
@@ -280,23 +273,6 @@ class NbForager:
|
|
280
273
|
status = {}
|
281
274
|
self.status = status
|
282
275
|
|
283
|
-
def join_pynb(self) -> None:
|
284
|
-
"""Create self.pynb objects based on self.root dictionaries.
|
285
|
-
|
286
|
-
:return: PyTree object with the pynetbox objects.
|
287
|
-
|
288
|
-
:rtype: PyTree
|
289
|
-
"""
|
290
|
-
for app in self.root.apps(): # pylint: disable=R1702
|
291
|
-
for model in getattr(self.root, app).models():
|
292
|
-
objects_d = getattr(getattr(self.root, app), model)
|
293
|
-
for id_, nb_object in objects_d.items():
|
294
|
-
endpoint: Endpoint = getattr(pynetbox.core.app.App(self.pyapi, app), model)
|
295
|
-
class_ = endpoint.return_obj
|
296
|
-
obj = class_(nb_object, self.pyapi, endpoint)
|
297
|
-
data = getattr(getattr(self.pynb, app), model)
|
298
|
-
data[id_] = obj
|
299
|
-
|
300
276
|
def join_tree(self, dcim: bool = False, ipam: bool = False) -> None:
|
301
277
|
"""Assemble Netbox objects in NbForager.tree within itself.
|
302
278
|
|
@@ -1,12 +1,10 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "nbforager"
|
3
|
-
version = "0.
|
3
|
+
version = "0.6.0"
|
4
4
|
description = "Python package designed to assist in working with the Netbox REST API. The filter parameters are identical to those in the Web UI filter form. It replaces brief data with full information, and Netbox objects are represented as a recursive multidimensional dictionary."
|
5
5
|
authors = ["Vladimirs Prusakovs <vladimir.prusakovs@gmail.com>"]
|
6
6
|
readme = "README.rst"
|
7
7
|
license = "Apache-2.0"
|
8
|
-
homepage = "https://github.com/vladimirs-git/nbforager"
|
9
|
-
repository = "https://github.com/vladimirs-git/nbforager"
|
10
8
|
keywords = ["netbox"]
|
11
9
|
classifiers = [
|
12
10
|
"Development Status :: 5 - Production/Stable",
|
@@ -15,34 +13,45 @@ classifiers = [
|
|
15
13
|
"Programming Language :: Python :: 3.8",
|
16
14
|
"Natural Language :: English",
|
17
15
|
]
|
16
|
+
|
17
|
+
[tool.poetry.urls]
|
18
|
+
homepage = "https://github.com/vladimirs-git/nbforager"
|
19
|
+
repository = "https://github.com/vladimirs-git/nbforager"
|
20
|
+
"Bug Tracker" = "https://github.com/vladimirs-git/nbforager/issues"
|
21
|
+
"Download URL" = "https://github.com/vladimirs-git/nbforager/archive/refs/tags/0.6.0.tar.gz"
|
22
|
+
|
18
23
|
[tool.poetry.dependencies]
|
19
24
|
python = "^3.8"
|
20
25
|
#
|
21
26
|
ciscoconfparse = "^1.9"
|
22
27
|
netports = ">=0.14,<1.0.0"
|
23
28
|
pydantic = "^2"
|
24
|
-
pynetbox = "^7.3.3"
|
25
29
|
requests = "^2"
|
26
30
|
tabulate = "^0.9.0"
|
27
31
|
tomli = "2.0.1"
|
28
32
|
vhelpers = ">=0.3,<1.0.0"
|
29
33
|
|
34
|
+
[tool.poetry.group.test.dependencies]
|
35
|
+
dictdiffer = "^0.9.0"
|
36
|
+
pytest = "^8.3.5"
|
37
|
+
pytest-mock = "^3.14.0"
|
38
|
+
requests-mock = "^1.12.1"
|
39
|
+
|
40
|
+
[tool.poetry.group.docs.dependencies]
|
41
|
+
readthedocs-sphinx-search = "^0.3.1"
|
42
|
+
sphinx = "7.1.2"
|
43
|
+
sphinx-rtd-theme = "^1.3.0"
|
44
|
+
sphinxnotes-strike = "^1.2"
|
45
|
+
|
30
46
|
[tool.poetry.group.dev.dependencies]
|
31
|
-
dictdiffer = "0.9.0"
|
32
|
-
mypy = "^1.14.1"
|
33
47
|
poetry = "^1.8.3"
|
48
|
+
#
|
49
|
+
mypy = "^1.14.1"
|
34
50
|
pygments = "^2.16.1"
|
35
51
|
pylint = "^3.2.7"
|
36
|
-
pytest = "^8.3.4"
|
37
52
|
pytest-cov = "^5.0.0"
|
38
|
-
pytest-mock = "^3.14.0"
|
39
|
-
readthedocs-sphinx-search = "^0.3.1"
|
40
|
-
requests-mock = "^1.12.1"
|
41
53
|
restructuredtext-lint = "^1.4.0"
|
42
54
|
ruff = "^0.9.9"
|
43
|
-
sphinx = "7.1.2"
|
44
|
-
sphinx-rtd-theme = "^1.3.0"
|
45
|
-
sphinxnotes-strike = "^1.2"
|
46
55
|
twine = "^4.0.2"
|
47
56
|
types-pyyaml = "^6.0.12.12"
|
48
57
|
types-requests = "^2.31.0.9"
|
@@ -55,10 +64,6 @@ nbforager = ["py.typed"]
|
|
55
64
|
[tool.poetry.extras]
|
56
65
|
test = ["pytest"]
|
57
66
|
|
58
|
-
[tool.poetry.urls]
|
59
|
-
"Bug Tracker" = "https://github.com/vladimirs-git/nbforager/issues"
|
60
|
-
"Download URL" = "https://github.com/vladimirs-git/nbforager/archive/refs/tags/0.5.0.tar.gz"
|
61
|
-
|
62
67
|
[tool.pylint]
|
63
68
|
disable = "fixme"
|
64
69
|
max-args = 10
|
@@ -67,9 +72,9 @@ max-line-length = 100
|
|
67
72
|
max-locals = 20
|
68
73
|
max-nested-blocks = 6
|
69
74
|
|
70
|
-
|
71
|
-
|
72
|
-
|
75
|
+
[tool.pylint.message_control]
|
76
|
+
enable = ["too-many-arguments"]
|
77
|
+
max-args = 10
|
73
78
|
|
74
79
|
[tool.pylint."tests.*"]
|
75
80
|
disable = [
|
@@ -86,9 +91,9 @@ disable = [
|
|
86
91
|
|
87
92
|
[tool.mypy]
|
88
93
|
python_version = "3.8"
|
94
|
+
exclude = ["_notes"]
|
89
95
|
|
90
96
|
[[tool.mypy.overrides]]
|
91
|
-
module = "pynetbox.*"
|
92
97
|
ignore_missing_imports = true
|
93
98
|
|
94
99
|
[tool.ruff]
|
@@ -1,266 +0,0 @@
|
|
1
|
-
"""Tree of pynetbox model objects."""
|
2
|
-
|
3
|
-
from typing import Dict
|
4
|
-
|
5
|
-
from pydantic import BaseModel, Field, ConfigDict
|
6
|
-
from pynetbox.core.response import Record # type: ignore
|
7
|
-
from pynetbox.models.circuits import Circuits, CircuitTerminations # type: ignore
|
8
|
-
from pynetbox.models.dcim import ( # type: ignore
|
9
|
-
Cables,
|
10
|
-
ConsolePorts,
|
11
|
-
ConsoleServerPorts,
|
12
|
-
DeviceTypes,
|
13
|
-
Devices,
|
14
|
-
FrontPorts,
|
15
|
-
Interfaces,
|
16
|
-
PowerOutlets,
|
17
|
-
PowerPorts,
|
18
|
-
RackReservations,
|
19
|
-
Racks,
|
20
|
-
RearPorts,
|
21
|
-
VirtualChassis,
|
22
|
-
)
|
23
|
-
from pynetbox.models.extras import ConfigContexts, ObjectChanges # type: ignore
|
24
|
-
from pynetbox.models.ipam import ( # type: ignore
|
25
|
-
Aggregates,
|
26
|
-
IpAddresses,
|
27
|
-
IpRanges,
|
28
|
-
Prefixes,
|
29
|
-
Vlans,
|
30
|
-
VlanGroups,
|
31
|
-
AsnRanges,
|
32
|
-
)
|
33
|
-
from pynetbox.models.users import Users, Permissions # type: ignore
|
34
|
-
from pynetbox.models.virtualization import VirtualMachines # type: ignore
|
35
|
-
from pynetbox.models.wireless import WirelessLans # type: ignore
|
36
|
-
|
37
|
-
DiRecord = Dict[int, Record]
|
38
|
-
# circuits
|
39
|
-
DiCircuits = Dict[int, Circuits]
|
40
|
-
DiCircuitTerminations = Dict[int, CircuitTerminations]
|
41
|
-
# dcim
|
42
|
-
DiCables = Dict[int, Cables]
|
43
|
-
DiConsolePorts = Dict[int, ConsolePorts]
|
44
|
-
DiConsoleServerPorts = Dict[int, ConsoleServerPorts]
|
45
|
-
DiDeviceTypes = Dict[int, DeviceTypes]
|
46
|
-
DiDevices = Dict[int, Devices]
|
47
|
-
DiFrontPorts = Dict[int, FrontPorts]
|
48
|
-
DiInterfaces = Dict[int, Interfaces]
|
49
|
-
DiPowerOutlets = Dict[int, PowerOutlets]
|
50
|
-
DiPowerPorts = Dict[int, PowerPorts]
|
51
|
-
DiRackReservations = Dict[int, RackReservations]
|
52
|
-
DiRacks = Dict[int, Racks]
|
53
|
-
DiRearPorts = Dict[int, RearPorts]
|
54
|
-
DiVirtualChassis = Dict[int, VirtualChassis]
|
55
|
-
# extras
|
56
|
-
DiConfigContexts = Dict[int, ConfigContexts]
|
57
|
-
DiObjectChanges = Dict[int, ObjectChanges]
|
58
|
-
# ipam
|
59
|
-
DiAggregates = Dict[int, Aggregates]
|
60
|
-
DiIpAddresses = Dict[int, IpAddresses]
|
61
|
-
DiIpRanges = Dict[int, IpRanges]
|
62
|
-
DiPrefixes = Dict[int, Prefixes]
|
63
|
-
DiVlans = Dict[int, Vlans]
|
64
|
-
DiVlanGroups = Dict[int, VlanGroups]
|
65
|
-
DiAsnRanges = Dict[int, AsnRanges]
|
66
|
-
# users
|
67
|
-
DiUsers = Dict[int, Users]
|
68
|
-
DiPermissions = Dict[int, Permissions]
|
69
|
-
# virtualization
|
70
|
-
DiVirtualMachines = Dict[int, VirtualMachines]
|
71
|
-
# wireless
|
72
|
-
DiWirelessLans = Dict[int, WirelessLans]
|
73
|
-
|
74
|
-
|
75
|
-
# noinspection DuplicatedCode
|
76
|
-
class CircuitsM(BaseModel):
|
77
|
-
"""Base for Circuits application."""
|
78
|
-
|
79
|
-
model_config = ConfigDict(arbitrary_types_allowed=True)
|
80
|
-
|
81
|
-
circuit_terminations: DiCircuitTerminations = Field(default={})
|
82
|
-
circuit_types: DiRecord = Field(default={})
|
83
|
-
circuits: DiCircuits = Field(default={})
|
84
|
-
provider_accounts: DiRecord = Field(default={})
|
85
|
-
provider_networks: DiRecord = Field(default={})
|
86
|
-
providers: DiRecord = Field(default={})
|
87
|
-
|
88
|
-
|
89
|
-
class CoreM(BaseModel):
|
90
|
-
"""Base for Core application."""
|
91
|
-
|
92
|
-
model_config = ConfigDict(arbitrary_types_allowed=True)
|
93
|
-
|
94
|
-
data_files: DiRecord = Field(default={})
|
95
|
-
data_sources: DiRecord = Field(default={})
|
96
|
-
jobs: DiRecord = Field(default={})
|
97
|
-
|
98
|
-
|
99
|
-
class DcimM(BaseModel):
|
100
|
-
"""Base for DCIM application."""
|
101
|
-
|
102
|
-
model_config = ConfigDict(arbitrary_types_allowed=True)
|
103
|
-
|
104
|
-
cable_terminations: DiRecord = Field(default={})
|
105
|
-
cables: DiCables = Field(default={})
|
106
|
-
# connected_device, is not model
|
107
|
-
console_port_templates: DiRecord = Field(default={})
|
108
|
-
console_ports: DiConsolePorts = Field(default={})
|
109
|
-
console_server_port_templates: DiRecord = Field(default={})
|
110
|
-
console_server_ports: DiConsoleServerPorts = Field(default={})
|
111
|
-
device_bay_templates: DiRecord = Field(default={})
|
112
|
-
device_bays: DiRecord = Field(default={})
|
113
|
-
device_roles: DiRecord = Field(default={})
|
114
|
-
device_types: DiDeviceTypes = Field(default={})
|
115
|
-
devices: DiDevices = Field(default={})
|
116
|
-
front_port_templates: DiRecord = Field(default={})
|
117
|
-
front_ports: DiFrontPorts = Field(default={})
|
118
|
-
interface_templates: DiRecord = Field(default={})
|
119
|
-
interfaces: DiInterfaces = Field(default={})
|
120
|
-
inventory_item_roles: DiRecord = Field(default={})
|
121
|
-
inventory_item_templates: DiRecord = Field(default={})
|
122
|
-
inventory_items: DiRecord = Field(default={})
|
123
|
-
locations: DiRecord = Field(default={})
|
124
|
-
manufacturers: DiRecord = Field(default={})
|
125
|
-
module_bay_templates: DiRecord = Field(default={})
|
126
|
-
module_bays: DiRecord = Field(default={})
|
127
|
-
module_types: DiRecord = Field(default={})
|
128
|
-
modules: DiRecord = Field(default={})
|
129
|
-
platforms: DiRecord = Field(default={})
|
130
|
-
power_feeds: DiRecord = Field(default={})
|
131
|
-
power_outlet_templates: DiRecord = Field(default={})
|
132
|
-
power_outlets: DiPowerOutlets = Field(default={})
|
133
|
-
power_panels: DiRecord = Field(default={})
|
134
|
-
power_port_templates: DiRecord = Field(default={})
|
135
|
-
power_ports: DiPowerPorts = Field(default={})
|
136
|
-
rack_reservations: DiRackReservations = Field(default={})
|
137
|
-
rack_roles: DiRecord = Field(default={})
|
138
|
-
racks: DiRacks = Field(default={})
|
139
|
-
rear_port_templates: DiRecord = Field(default={})
|
140
|
-
rear_ports: DiRearPorts = Field(default={})
|
141
|
-
regions: DiRecord = Field(default={})
|
142
|
-
site_groups: DiRecord = Field(default={})
|
143
|
-
sites: DiRecord = Field(default={})
|
144
|
-
virtual_chassis: DiVirtualChassis = Field(default={})
|
145
|
-
virtual_device_contexts: DiRecord = Field(default={})
|
146
|
-
|
147
|
-
|
148
|
-
class ExtrasM(BaseModel):
|
149
|
-
"""Base for extras application."""
|
150
|
-
|
151
|
-
model_config = ConfigDict(arbitrary_types_allowed=True)
|
152
|
-
|
153
|
-
bookmarks: DiRecord = Field(default={})
|
154
|
-
config_contexts: DiConfigContexts = Field(default={})
|
155
|
-
config_templates: DiRecord = Field(default={})
|
156
|
-
content_types: DiRecord = Field(default={})
|
157
|
-
custom_field_choice_sets: DiRecord = Field(default={})
|
158
|
-
custom_fields: DiRecord = Field(default={})
|
159
|
-
custom_links: DiRecord = Field(default={})
|
160
|
-
export_templates: DiRecord = Field(default={})
|
161
|
-
image_attachments: DiRecord = Field(default={})
|
162
|
-
journal_entries: DiRecord = Field(default={})
|
163
|
-
object_changes: DiObjectChanges = Field(default={})
|
164
|
-
reports: DiRecord = Field(default={})
|
165
|
-
saved_filters: DiRecord = Field(default={})
|
166
|
-
scripts: DiRecord = Field(default={})
|
167
|
-
tags: DiRecord = Field(default={})
|
168
|
-
webhooks: DiRecord = Field(default={})
|
169
|
-
|
170
|
-
|
171
|
-
class IpamM(BaseModel):
|
172
|
-
"""Base for IPAM application."""
|
173
|
-
|
174
|
-
model_config = ConfigDict(arbitrary_types_allowed=True)
|
175
|
-
|
176
|
-
aggregates: DiAggregates = Field(default={})
|
177
|
-
asn_ranges: DiAsnRanges = Field(default={})
|
178
|
-
asns: DiRecord = Field(default={})
|
179
|
-
fhrp_group_assignments: DiRecord = Field(default={})
|
180
|
-
fhrp_groups: DiRecord = Field(default={})
|
181
|
-
ip_addresses: DiIpAddresses = Field(default={})
|
182
|
-
ip_ranges: DiIpRanges = Field(default={})
|
183
|
-
l2vpn_terminations: DiRecord = Field(default={}) # v3.5
|
184
|
-
l2vpns: DiRecord = Field(default={}) # v3.5
|
185
|
-
prefixes: DiPrefixes = Field(default={})
|
186
|
-
rirs: DiRecord = Field(default={})
|
187
|
-
roles: DiRecord = Field(default={})
|
188
|
-
route_targets: DiRecord = Field(default={})
|
189
|
-
service_templates: DiRecord = Field(default={})
|
190
|
-
services: DiRecord = Field(default={})
|
191
|
-
vlan_groups: DiVlanGroups = Field(default={})
|
192
|
-
vlans: DiVlans = Field(default={})
|
193
|
-
vrfs: DiRecord = Field(default={})
|
194
|
-
|
195
|
-
|
196
|
-
# noinspection DuplicatedCode
|
197
|
-
class TenancyM(BaseModel):
|
198
|
-
"""Base for Tenancy application."""
|
199
|
-
|
200
|
-
model_config = ConfigDict(arbitrary_types_allowed=True)
|
201
|
-
|
202
|
-
contact_assignments: DiRecord = Field(default={})
|
203
|
-
contact_groups: DiRecord = Field(default={})
|
204
|
-
contact_roles: DiRecord = Field(default={})
|
205
|
-
contacts: DiRecord = Field(default={})
|
206
|
-
tenant_groups: DiRecord = Field(default={})
|
207
|
-
tenants: DiRecord = Field(default={})
|
208
|
-
|
209
|
-
|
210
|
-
class UsersM(BaseModel):
|
211
|
-
"""Base for Users application."""
|
212
|
-
|
213
|
-
model_config = ConfigDict(arbitrary_types_allowed=True)
|
214
|
-
|
215
|
-
# config: is not DiRecord
|
216
|
-
groups: DiRecord = Field(default={})
|
217
|
-
permissions: DiPermissions = Field(default={})
|
218
|
-
tokens: DiRecord = Field(default={})
|
219
|
-
users: DiUsers = Field(default={})
|
220
|
-
|
221
|
-
|
222
|
-
class VirtualizationM(BaseModel):
|
223
|
-
"""Base for Virtualization application."""
|
224
|
-
|
225
|
-
model_config = ConfigDict(arbitrary_types_allowed=True)
|
226
|
-
|
227
|
-
cluster_groups: DiRecord = Field(default={})
|
228
|
-
cluster_types: DiRecord = Field(default={})
|
229
|
-
clusters: DiRecord = Field(default={})
|
230
|
-
interfaces: DiRecord = Field(default={})
|
231
|
-
virtual_machines: DiVirtualMachines = Field(default={})
|
232
|
-
|
233
|
-
|
234
|
-
class WirelessM(BaseModel):
|
235
|
-
"""Base for Wireless application."""
|
236
|
-
|
237
|
-
model_config = ConfigDict(arbitrary_types_allowed=True)
|
238
|
-
|
239
|
-
wireless_lan_groups: DiRecord = Field(default={})
|
240
|
-
wireless_lans: DiWirelessLans = Field(default={})
|
241
|
-
wireless_links: DiRecord = Field(default={})
|
242
|
-
|
243
|
-
|
244
|
-
class PyTree(BaseModel):
|
245
|
-
"""Structure that holds pynetbox objects.
|
246
|
-
|
247
|
-
Model: PyTree.{app}.{model}[id] = object.
|
248
|
-
Example: PyTree.{app}.{model}[id] = object.
|
249
|
-
|
250
|
-
{app} - Attribute representing application name.
|
251
|
-
{model} - Attribute representing model name.
|
252
|
-
[id] - Unique identifier of Netbox object.
|
253
|
-
object - Pynetbox object, documented on https://pynetbox.readthedocs.io/
|
254
|
-
"""
|
255
|
-
|
256
|
-
model_config = ConfigDict(arbitrary_types_allowed=True)
|
257
|
-
|
258
|
-
circuits: CircuitsM = Field(default=CircuitsM())
|
259
|
-
core: CoreM = Field(default=CoreM())
|
260
|
-
dcim: DcimM = Field(default=DcimM())
|
261
|
-
extras: ExtrasM = Field(default=ExtrasM())
|
262
|
-
ipam: IpamM = Field(default=IpamM())
|
263
|
-
tenancy: TenancyM = Field(default=TenancyM())
|
264
|
-
users: UsersM = Field(default=UsersM())
|
265
|
-
virtualization: VirtualizationM = Field(default=VirtualizationM())
|
266
|
-
wireless: WirelessM = Field(default=WirelessM())
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|