annet 0.16.0__tar.gz → 0.16.2__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.

Potentially problematic release.


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

Files changed (149) hide show
  1. {annet-0.16.0/annet.egg-info → annet-0.16.2}/PKG-INFO +1 -1
  2. {annet-0.16.0 → annet-0.16.2}/annet/adapters/netbox/common/models.py +7 -6
  3. {annet-0.16.0 → annet-0.16.2}/annet/adapters/netbox/common/storage_opts.py +2 -2
  4. {annet-0.16.0 → annet-0.16.2}/annet/adapters/netbox/provider.py +5 -3
  5. {annet-0.16.0 → annet-0.16.2}/annet/annlib/netdev/devdb/data/devdb.json +1 -0
  6. {annet-0.16.0 → annet-0.16.2}/annet/cli.py +2 -2
  7. {annet-0.16.0 → annet-0.16.2}/annet/connectors.py +14 -10
  8. {annet-0.16.0 → annet-0.16.2}/annet/deploy.py +1 -1
  9. {annet-0.16.0 → annet-0.16.2/annet.egg-info}/PKG-INFO +1 -1
  10. {annet-0.16.0 → annet-0.16.2}/AUTHORS +0 -0
  11. {annet-0.16.0 → annet-0.16.2}/LICENSE +0 -0
  12. {annet-0.16.0 → annet-0.16.2}/MANIFEST.in +0 -0
  13. {annet-0.16.0 → annet-0.16.2}/README.md +0 -0
  14. {annet-0.16.0 → annet-0.16.2}/annet/__init__.py +0 -0
  15. {annet-0.16.0 → annet-0.16.2}/annet/adapters/__init__.py +0 -0
  16. {annet-0.16.0 → annet-0.16.2}/annet/adapters/netbox/__init__.py +0 -0
  17. {annet-0.16.0 → annet-0.16.2}/annet/adapters/netbox/common/__init__.py +0 -0
  18. {annet-0.16.0 → annet-0.16.2}/annet/adapters/netbox/common/client.py +0 -0
  19. {annet-0.16.0 → annet-0.16.2}/annet/adapters/netbox/common/manufacturer.py +0 -0
  20. {annet-0.16.0 → annet-0.16.2}/annet/adapters/netbox/common/query.py +0 -0
  21. {annet-0.16.0 → annet-0.16.2}/annet/adapters/netbox/common/status_client.py +0 -0
  22. {annet-0.16.0 → annet-0.16.2}/annet/adapters/netbox/v24/__init__.py +0 -0
  23. {annet-0.16.0 → annet-0.16.2}/annet/adapters/netbox/v24/storage.py +0 -0
  24. {annet-0.16.0 → annet-0.16.2}/annet/adapters/netbox/v37/__init__.py +0 -0
  25. {annet-0.16.0 → annet-0.16.2}/annet/adapters/netbox/v37/storage.py +0 -0
  26. {annet-0.16.0 → annet-0.16.2}/annet/annet.py +0 -0
  27. {annet-0.16.0 → annet-0.16.2}/annet/annlib/__init__.py +0 -0
  28. {annet-0.16.0 → annet-0.16.2}/annet/annlib/command.py +0 -0
  29. {annet-0.16.0 → annet-0.16.2}/annet/annlib/diff.py +0 -0
  30. {annet-0.16.0 → annet-0.16.2}/annet/annlib/errors.py +0 -0
  31. {annet-0.16.0 → annet-0.16.2}/annet/annlib/filter_acl.py +0 -0
  32. {annet-0.16.0 → annet-0.16.2}/annet/annlib/jsontools.py +0 -0
  33. {annet-0.16.0 → annet-0.16.2}/annet/annlib/lib.py +0 -0
  34. {annet-0.16.0 → annet-0.16.2}/annet/annlib/netdev/__init__.py +0 -0
  35. {annet-0.16.0 → annet-0.16.2}/annet/annlib/netdev/db.py +0 -0
  36. {annet-0.16.0 → annet-0.16.2}/annet/annlib/netdev/devdb/__init__.py +0 -0
  37. {annet-0.16.0 → annet-0.16.2}/annet/annlib/netdev/views/__init__.py +0 -0
  38. {annet-0.16.0 → annet-0.16.2}/annet/annlib/netdev/views/dump.py +0 -0
  39. {annet-0.16.0 → annet-0.16.2}/annet/annlib/netdev/views/hardware.py +0 -0
  40. {annet-0.16.0 → annet-0.16.2}/annet/annlib/output.py +0 -0
  41. {annet-0.16.0 → annet-0.16.2}/annet/annlib/patching.py +0 -0
  42. {annet-0.16.0 → annet-0.16.2}/annet/annlib/rbparser/__init__.py +0 -0
  43. {annet-0.16.0 → annet-0.16.2}/annet/annlib/rbparser/acl.py +0 -0
  44. {annet-0.16.0 → annet-0.16.2}/annet/annlib/rbparser/deploying.py +0 -0
  45. {annet-0.16.0 → annet-0.16.2}/annet/annlib/rbparser/ordering.py +0 -0
  46. {annet-0.16.0 → annet-0.16.2}/annet/annlib/rbparser/platform.py +0 -0
  47. {annet-0.16.0 → annet-0.16.2}/annet/annlib/rbparser/syntax.py +0 -0
  48. {annet-0.16.0 → annet-0.16.2}/annet/annlib/rulebook/__init__.py +0 -0
  49. {annet-0.16.0 → annet-0.16.2}/annet/annlib/rulebook/common.py +0 -0
  50. {annet-0.16.0 → annet-0.16.2}/annet/annlib/tabparser.py +0 -0
  51. {annet-0.16.0 → annet-0.16.2}/annet/annlib/types.py +0 -0
  52. {annet-0.16.0 → annet-0.16.2}/annet/api/__init__.py +0 -0
  53. {annet-0.16.0 → annet-0.16.2}/annet/argparse.py +0 -0
  54. {annet-0.16.0 → annet-0.16.2}/annet/cli_args.py +0 -0
  55. {annet-0.16.0 → annet-0.16.2}/annet/configs/context.yml +0 -0
  56. {annet-0.16.0 → annet-0.16.2}/annet/configs/logging.yaml +0 -0
  57. {annet-0.16.0 → annet-0.16.2}/annet/diff.py +0 -0
  58. {annet-0.16.0 → annet-0.16.2}/annet/executor.py +0 -0
  59. {annet-0.16.0 → annet-0.16.2}/annet/filtering.py +0 -0
  60. {annet-0.16.0 → annet-0.16.2}/annet/gen.py +0 -0
  61. {annet-0.16.0 → annet-0.16.2}/annet/generators/__init__.py +0 -0
  62. {annet-0.16.0 → annet-0.16.2}/annet/generators/base.py +0 -0
  63. {annet-0.16.0 → annet-0.16.2}/annet/generators/common/__init__.py +0 -0
  64. {annet-0.16.0 → annet-0.16.2}/annet/generators/common/initial.py +0 -0
  65. {annet-0.16.0 → annet-0.16.2}/annet/generators/entire.py +0 -0
  66. {annet-0.16.0 → annet-0.16.2}/annet/generators/exceptions.py +0 -0
  67. {annet-0.16.0 → annet-0.16.2}/annet/generators/jsonfragment.py +0 -0
  68. {annet-0.16.0 → annet-0.16.2}/annet/generators/partial.py +0 -0
  69. {annet-0.16.0 → annet-0.16.2}/annet/generators/perf.py +0 -0
  70. {annet-0.16.0 → annet-0.16.2}/annet/generators/ref.py +0 -0
  71. {annet-0.16.0 → annet-0.16.2}/annet/generators/result.py +0 -0
  72. {annet-0.16.0 → annet-0.16.2}/annet/hardware.py +0 -0
  73. {annet-0.16.0 → annet-0.16.2}/annet/implicit.py +0 -0
  74. {annet-0.16.0 → annet-0.16.2}/annet/lib.py +0 -0
  75. {annet-0.16.0 → annet-0.16.2}/annet/output.py +0 -0
  76. {annet-0.16.0 → annet-0.16.2}/annet/parallel.py +0 -0
  77. {annet-0.16.0 → annet-0.16.2}/annet/patching.py +0 -0
  78. {annet-0.16.0 → annet-0.16.2}/annet/reference.py +0 -0
  79. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/__init__.py +0 -0
  80. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/arista/__init__.py +0 -0
  81. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/arista/iface.py +0 -0
  82. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/aruba/__init__.py +0 -0
  83. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/aruba/ap_env.py +0 -0
  84. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/aruba/misc.py +0 -0
  85. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/b4com/__init__.py +0 -0
  86. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/b4com/file.py +0 -0
  87. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/cisco/__init__.py +0 -0
  88. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/cisco/iface.py +0 -0
  89. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/cisco/misc.py +0 -0
  90. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/cisco/vlandb.py +0 -0
  91. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/common.py +0 -0
  92. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/deploying.py +0 -0
  93. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/huawei/__init__.py +0 -0
  94. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/huawei/aaa.py +0 -0
  95. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/huawei/bgp.py +0 -0
  96. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/huawei/iface.py +0 -0
  97. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/huawei/misc.py +0 -0
  98. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/huawei/vlandb.py +0 -0
  99. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/juniper/__init__.py +0 -0
  100. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/nexus/__init__.py +0 -0
  101. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/nexus/iface.py +0 -0
  102. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/patching.py +0 -0
  103. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/ribbon/__init__.py +0 -0
  104. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/arista.deploy +0 -0
  105. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/arista.order +0 -0
  106. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/arista.rul +0 -0
  107. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/aruba.deploy +0 -0
  108. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/aruba.order +0 -0
  109. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/aruba.rul +0 -0
  110. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/b4com.deploy +0 -0
  111. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/b4com.order +0 -0
  112. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/b4com.rul +0 -0
  113. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/cisco.deploy +0 -0
  114. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/cisco.order +0 -0
  115. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/cisco.rul +0 -0
  116. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/huawei.deploy +0 -0
  117. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/huawei.order +0 -0
  118. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/huawei.rul +0 -0
  119. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/juniper.rul +0 -0
  120. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/nexus.deploy +0 -0
  121. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/nexus.order +0 -0
  122. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/nexus.rul +0 -0
  123. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/nokia.rul +0 -0
  124. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/optixtrans.deploy +0 -0
  125. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/optixtrans.order +0 -0
  126. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/optixtrans.rul +0 -0
  127. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/pc.deploy +0 -0
  128. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/pc.order +0 -0
  129. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/pc.rul +0 -0
  130. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/ribbon.deploy +0 -0
  131. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/ribbon.rul +0 -0
  132. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/routeros.order +0 -0
  133. {annet-0.16.0 → annet-0.16.2}/annet/rulebook/texts/routeros.rul +0 -0
  134. {annet-0.16.0 → annet-0.16.2}/annet/storage.py +0 -0
  135. {annet-0.16.0 → annet-0.16.2}/annet/tabparser.py +0 -0
  136. {annet-0.16.0 → annet-0.16.2}/annet/text_term_format.py +0 -0
  137. {annet-0.16.0 → annet-0.16.2}/annet/tracing.py +0 -0
  138. {annet-0.16.0 → annet-0.16.2}/annet/types.py +0 -0
  139. {annet-0.16.0 → annet-0.16.2}/annet.egg-info/SOURCES.txt +0 -0
  140. {annet-0.16.0 → annet-0.16.2}/annet.egg-info/dependency_links.txt +0 -0
  141. {annet-0.16.0 → annet-0.16.2}/annet.egg-info/entry_points.txt +0 -0
  142. {annet-0.16.0 → annet-0.16.2}/annet.egg-info/requires.txt +0 -0
  143. {annet-0.16.0 → annet-0.16.2}/annet.egg-info/top_level.txt +0 -0
  144. {annet-0.16.0 → annet-0.16.2}/annet_generators/__init__.py +0 -0
  145. {annet-0.16.0 → annet-0.16.2}/annet_generators/example/__init__.py +0 -0
  146. {annet-0.16.0 → annet-0.16.2}/annet_generators/example/lldp.py +0 -0
  147. {annet-0.16.0 → annet-0.16.2}/requirements.txt +0 -0
  148. {annet-0.16.0 → annet-0.16.2}/setup.cfg +0 -0
  149. {annet-0.16.0 → annet-0.16.2}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: annet
3
- Version: 0.16.0
3
+ Version: 0.16.2
4
4
  Summary: annet
5
5
  Home-page: https://github.com/annetutil/annet
6
6
  License: MIT
@@ -52,17 +52,17 @@ class DeviceIp(DumpableView):
52
52
  class Prefix(DumpableView):
53
53
  id: int
54
54
  prefix: str
55
- site: Entity | None
56
- vrf: Entity | None
57
- tenant: Entity | None
58
- vlan: Entity | None
59
- role: Entity | None
55
+ site: Optional[Entity]
56
+ vrf: Optional[Entity]
57
+ tenant: Optional[Entity]
58
+ vlan: Optional[Entity]
59
+ role: Optional[Entity]
60
60
  status: Label
61
61
  is_pool: bool
62
62
  custom_fields: dict[str, Any]
63
63
  created: datetime
64
64
  last_updated: datetime
65
- description: str | None = ""
65
+ description: Optional[str] = ""
66
66
 
67
67
  @property
68
68
  def _dump__list_key(self):
@@ -123,6 +123,7 @@ class Interface(Entity):
123
123
  display: str = ""
124
124
  ip_addresses: List[IpAddress] = field(default_factory=list)
125
125
  vrf: Optional[Entity] = None
126
+ mtu: int | None = None
126
127
 
127
128
 
128
129
  @dataclass
@@ -1,5 +1,5 @@
1
1
  import os
2
- from typing import Any
2
+ from typing import Any, Optional
3
3
 
4
4
  DEFAULT_URL = "http://localhost"
5
5
 
@@ -10,7 +10,7 @@ class NetboxStorageOpts:
10
10
  self.token = token
11
11
 
12
12
  @classmethod
13
- def parse_params(cls, conf_params: dict[str, str] | None, cli_opts: Any):
13
+ def parse_params(cls, conf_params: Optional[dict[str, str]], cli_opts: Any):
14
14
  url = os.getenv("NETBOX_URL") or conf_params.get("url") or DEFAULT_URL
15
15
  token = os.getenv("NETBOX_TOKEN", "").strip() or conf_params.get("token") or ""
16
16
  return cls(url=url, token=token)
@@ -31,8 +31,9 @@ class NetboxProvider(StorageProvider, AdapterWithName, AdapterWithConfig):
31
31
  self.url = url
32
32
  self.token = token
33
33
 
34
- def with_config(self, **kwargs: Dict[str, Any]) -> T:
35
- return NetboxProvider(**kwargs)
34
+ @classmethod
35
+ def with_config(cls, **kwargs: Dict[str, Any]) -> T:
36
+ return cls(**kwargs)
36
37
 
37
38
  def storage(self):
38
39
  return storage_factory
@@ -43,5 +44,6 @@ class NetboxProvider(StorageProvider, AdapterWithName, AdapterWithConfig):
43
44
  def query(self):
44
45
  return NetboxQuery
45
46
 
46
- def name(self) -> str:
47
+ @classmethod
48
+ def name(cls) -> str:
47
49
  return "netbox"
@@ -52,6 +52,7 @@
52
52
  "Huawei.CE.CE8800": " CE88\\d\\d",
53
53
  "Huawei.CE.CE8800.CE8850": " CE8850",
54
54
  "Huawei.CE.CE8800.CE8851": " CE8851",
55
+ "Huawei.CE.CE8800.CE8855": " CE8855",
55
56
  "Huawei.CE.CE9800": " CE98\\d\\d",
56
57
  "Huawei.Quidway": " (LS-)?S",
57
58
  "Huawei.Quidway.S2x": "2\\d{3}",
@@ -8,7 +8,7 @@ import subprocess
8
8
  import shutil
9
9
  import sys
10
10
  from contextlib import ExitStack, contextmanager
11
- from typing import Tuple, Iterable
11
+ from typing import Optional, Tuple, Iterable
12
12
 
13
13
  import tabulate
14
14
  import yaml
@@ -129,7 +129,7 @@ def show_generators(args: cli_args.ShowGeneratorsOptions):
129
129
  """ List applicable generators (for a device if query is set) """
130
130
  arg_gens = cli_args.GenOptions(args)
131
131
  with get_loader(arg_gens, args) as loader:
132
- device: Device | None = None
132
+ device: Optional[Device] = None
133
133
  devices = loader.devices
134
134
  if len(devices) == 1:
135
135
  device = devices[0]
@@ -42,11 +42,11 @@ class Connector(ABC, Generic[T]):
42
42
  res = self._classes[0]
43
43
  return res(*args, **kwargs)
44
44
 
45
- def get_all(self, *args, **kwargs) -> List[T]:
45
+ def get_all(self) -> List[T]:
46
46
  if self._classes is None:
47
47
  self._classes = self._entry_point or [self._get_default()]
48
48
 
49
- return [cls(*args, **kwargs) for cls in self._classes]
49
+ return self._classes.copy()
50
50
 
51
51
  def set(self, cls: Type[T]):
52
52
  if self._classes is not None:
@@ -97,18 +97,20 @@ def load_entry_point_new(group: str) -> List:
97
97
 
98
98
 
99
99
  class AdapterWithConfig(ABC, Generic[T]):
100
+ @classmethod
100
101
  @abstractmethod
101
- def with_config(self, **kwargs: Dict[str, Any]) -> T:
102
+ def with_config(cls, **kwargs: Dict[str, Any]) -> T:
102
103
  pass
103
104
 
104
105
 
105
106
  class AdapterWithName(ABC):
107
+ @classmethod
106
108
  @abstractmethod
107
- def name(self) -> str:
109
+ def name(cls) -> str:
108
110
  pass
109
111
 
110
112
 
111
- def get_connector_from_config(config_key: str, connectors: List[Connector]) -> Tuple[Connector, Dict[str, Any]]:
113
+ def get_connector_from_config(config_key: str, connectors: List[Type[Connector]]) -> Tuple[Connector, Dict[str, Any]]:
112
114
  seen: list[str] = []
113
115
  if not connectors:
114
116
  raise Exception("empty connectors")
@@ -119,8 +121,8 @@ def get_connector_from_config(config_key: str, connectors: List[Connector]) -> T
119
121
  connector_params = context_storage.get("params", {})
120
122
  if adapter_name:
121
123
  for con in connectors:
122
- con_name = connector.__class__.__name__
123
- if isinstance(con, AdapterWithName):
124
+ con_name = connector.__name__
125
+ if issubclass(con, AdapterWithName):
124
126
  con_name = con.name()
125
127
  seen.append(con_name)
126
128
  if adapter_name == con_name:
@@ -136,8 +138,10 @@ def get_connector_from_config(config_key: str, connectors: List[Connector]) -> T
136
138
  connector = connectors[0]
137
139
  if len(connectors) > 1:
138
140
  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
+ if issubclass(connector, AdapterWithConfig):
142
+ connector_ins = connector.with_config(**connector_params)
143
+ else:
144
+ connector_ins = connector()
141
145
  # return connector_params only for storage
142
146
  # TODO: switch storage interface to AdapterWithConfig
143
- return connector, connector_params
147
+ return connector_ins, connector_params
@@ -481,7 +481,7 @@ def make_cmd_params(rule: Dict[str, Any]) -> Dict[str, Any]:
481
481
  }
482
482
 
483
483
 
484
- def make_apply_commands(rule: dict, hw: HardwareView, do_commit: bool, do_finalize: bool, path: str | None = None):
484
+ def make_apply_commands(rule: dict, hw: HardwareView, do_commit: bool, do_finalize: bool, path: Optional[str] = None):
485
485
  apply_logic = rule["attrs"]["apply_logic"]
486
486
  before, after = apply_logic(hw, do_commit=do_commit, do_finalize=do_finalize, path=path)
487
487
  return before, after
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: annet
3
- Version: 0.16.0
3
+ Version: 0.16.2
4
4
  Summary: annet
5
5
  Home-page: https://github.com/annetutil/annet
6
6
  License: MIT
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
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