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

@@ -102,6 +102,9 @@ class Device(DeviceCls, DumpableView):
102
102
  def add_subif(self, interface: str, subif: int) -> Interface:
103
103
  raise NotImplementedError
104
104
 
105
+ def find_interface(self, name: str) -> Optional[Interface]:
106
+ raise NotImplementedError
107
+
105
108
  def neighbours_fqdns(self) -> list[str]:
106
109
  return []
107
110
 
@@ -281,3 +281,9 @@ class NetboxDevice(Entity):
281
281
  )
282
282
  self.interfaces.append(target_port)
283
283
  return target_port
284
+
285
+ def find_interface(self, name: str) -> Optional[Interface]:
286
+ for iface in self.interfaces:
287
+ if iface.name == name:
288
+ return iface
289
+ return None
@@ -70,8 +70,8 @@
70
70
  "Huawei.EI": "-EI(-|$)",
71
71
  "Huawei.HI": "-HI(-|$)",
72
72
  "Huawei.SI": "-SI(-|$)",
73
- "Huawei.OptiXtrans": " OptiXtrans|DC",
74
- "Huawei.OptiXtrans.DC": " DC",
73
+ "Huawei.OptiXtrans": " (OptiXtrans|DC\\d\\d\\d)",
74
+ "Huawei.OptiXtrans.DC": " DC\\d\\d\\d",
75
75
  "Huawei.OptiXtrans.DC.DC908": " DC908",
76
76
 
77
77
  "Juniper": "^[Jj]uniper",
@@ -116,6 +116,7 @@
116
116
  "PC.Whitebox.Edgecore": "[Ee]dge-?[Cc]ore",
117
117
  "PC.Whitebox.Edgecore.AS": "AS",
118
118
  "PC.Whitebox.Edgecore.AS9736": "AS9736",
119
+ "PC.Whitebox.Edgecore.AS9817": "AS9817",
119
120
  "PC.Whitebox.NVIDIA": "NVIDIA",
120
121
  "PC.Whitebox.NVIDIA.SN": " SN",
121
122
  "PC.Whitebox.NVIDIA.SN.SN5400": " SN5400",
annet/bgp_models.py CHANGED
@@ -286,13 +286,30 @@ def _used_policies(peer: Union[Peer, PeerGroup]) -> Iterable[str]:
286
286
  yield peer.export_policy
287
287
 
288
288
 
289
+ def _used_redistribute_policies(opts: Union[GlobalOptions, VrfOptions]) -> Iterable[str]:
290
+ for red in opts.ipv4_unicast.redistributes:
291
+ if red.policy:
292
+ yield red.policy
293
+ for red in opts.ipv6_unicast.redistributes:
294
+ if red.policy:
295
+ yield red.policy
296
+ for red in opts.ipv4_labeled_unicast.redistributes:
297
+ if red.policy:
298
+ yield red.policy
299
+ for red in opts.ipv6_labeled_unicast.redistributes:
300
+ if red.policy:
301
+ yield red.policy
302
+
303
+
289
304
  def extract_policies(config: BgpConfig) -> Sequence[str]:
290
305
  result: list[str] = []
291
306
  for vrf in config.global_options.vrf.values():
292
307
  for group in vrf.groups:
293
308
  result.extend(_used_policies(group))
309
+ result.extend(_used_redistribute_policies(vrf))
294
310
  for group in config.global_options.groups:
295
311
  result.extend(_used_policies(group))
296
312
  for peer in config.peers:
297
313
  result.extend(_used_policies(peer))
314
+ result.extend(_used_redistribute_policies(config.global_options))
298
315
  return result
annet/mesh/executor.py CHANGED
@@ -124,12 +124,20 @@ class MeshExecutor:
124
124
  # we merge them according to remote fqdn
125
125
  neighbor_peers: dict[PeerKey, Pair] = {}
126
126
  # TODO batch resolve
127
- for rule in self._registry.lookup_direct(device.fqdn, device.neighbours_fqdns):
127
+ rules = self._registry.lookup_direct(device.fqdn, device.neighbours_fqdns)
128
+ fqdns = {
129
+ rule.name_right if rule.direct_order else rule.name_left
130
+ for rule in rules
131
+ }
132
+ neigbors = {
133
+ d.fqdn: d for d in self._storage.make_devices(list(fqdns))
134
+ }
135
+ for rule in rules:
128
136
  handler_name = self._handler_name(rule.handler)
129
137
  if rule.direct_order:
130
- neighbor_device = self._storage.make_devices([rule.name_right])[0]
138
+ neighbor_device = neigbors[rule.name_right]
131
139
  else:
132
- neighbor_device = self._storage.make_devices([rule.name_left])[0]
140
+ neighbor_device = neigbors[rule.name_left]
133
141
  all_connected_ports = [
134
142
  (p1.name, p2.name)
135
143
  for p1, p2 in self._storage.search_connections(device, neighbor_device)
@@ -200,17 +208,26 @@ class MeshExecutor:
200
208
  # we can have multiple rules for the same pair
201
209
  # we merge them according to remote fqdn
202
210
  connected_peers: dict[PeerKey, Pair] = {}
203
- for rule in self._registry.lookup_indirect(device.fqdn, all_fqdns):
211
+
212
+ rules = self._registry.lookup_indirect(device.fqdn, all_fqdns)
213
+ fqdns = {
214
+ rule.name_right if rule.direct_order else rule.name_left
215
+ for rule in rules
216
+ }
217
+ connected_devices = {
218
+ d.fqdn: d for d in self._storage.make_devices(list(fqdns))
219
+ }
220
+ for rule in rules:
204
221
  session = MeshSession()
205
222
  handler_name = self._handler_name(rule.handler)
206
223
  logger.debug("Running indirect handler: %s", handler_name)
207
224
  if rule.direct_order:
208
- connected_device = self._storage.make_devices([rule.name_right])[0]
225
+ connected_device = connected_devices[rule.name_right]
209
226
  peer_device = IndirectPeer(rule.match_left, device)
210
227
  peer_connected = IndirectPeer(rule.match_right, connected_device)
211
228
  rule.handler(peer_device, peer_connected, session)
212
229
  else:
213
- connected_device = self._storage.make_devices([rule.name_left])[0]
230
+ connected_device = connected_devices[rule.name_left]
214
231
  peer_connected = IndirectPeer(rule.match_left, connected_device)
215
232
  peer_device = IndirectPeer(rule.match_right, device)
216
233
  rule.handler(peer_connected, peer_device, session)
@@ -265,7 +282,7 @@ class MeshExecutor:
265
282
  def _to_bgp_global(self, global_options: GlobalOptionsDTO) -> GlobalOptions:
266
283
  return to_bgp_global_options(global_options)
267
284
 
268
- def _apply_interface_changes(
285
+ def _apply_direct_interface_changes(
269
286
  self, device: Device, neighbor: Device, ports: list[str], changes: InterfaceChanges,
270
287
  ) -> str:
271
288
  # filter ports according to processed in pair
@@ -299,6 +316,24 @@ class MeshExecutor:
299
316
  target_interface.add_addr(changes.addr, changes.vrf)
300
317
  return target_interface.name
301
318
 
319
+ def _apply_indirect_interface_changes(
320
+ self, device: Device, neighbor: Device, ifname: Optional[str], changes: InterfaceChanges,
321
+ ) -> Optional[str]:
322
+ if changes.lag is not None:
323
+ raise ValueError("LAG creation unsupported for indirect peers")
324
+ elif changes.subif is not None:
325
+ target_interface = device.add_subif(ifname, changes.subif)
326
+ elif changes.svi is not None:
327
+ target_interface = device.add_svi(changes.svi)
328
+ elif not ifname:
329
+ return None
330
+ else:
331
+ target_interface = device.find_interface(ifname)
332
+ if not target_interface:
333
+ raise ValueError(f"Interface {ifname} not found for device {device.fqdn}")
334
+ target_interface.add_addr(changes.addr, changes.vrf)
335
+ return target_interface.name
336
+
302
337
  def _apply_virtual_interface_changes(self, device: Device, local: VirtualLocalDTO) -> str:
303
338
  return device.add_svi(local.svi).name # we check if SVI configured in execute method
304
339
 
@@ -308,8 +343,9 @@ class MeshExecutor:
308
343
  global_options = self._to_bgp_global(self._execute_globals(device))
309
344
 
310
345
  peers = []
346
+ target_interface: Optional[str]
311
347
  for direct_pair in self._execute_direct(device):
312
- target_interface = self._apply_interface_changes(
348
+ target_interface = self._apply_direct_interface_changes(
313
349
  device,
314
350
  direct_pair.device,
315
351
  direct_pair.ports,
@@ -325,7 +361,13 @@ class MeshExecutor:
325
361
  peers.append(self._virtual_to_bgp_peer(virtual_pair, target_interface))
326
362
 
327
363
  for connected_pair in self._execute_indirect(device, all_fqdns):
328
- peers.append(self._to_bgp_peer(connected_pair, None))
364
+ target_interface = self._apply_indirect_interface_changes(
365
+ device,
366
+ connected_pair.device,
367
+ getattr(connected_pair.local, "ifname", None),
368
+ to_interface_changes(connected_pair.local),
369
+ )
370
+ peers.append(self._to_bgp_peer(connected_pair, target_interface))
329
371
 
330
372
  return BgpConfig(
331
373
  global_options=global_options,
annet/mesh/peer_models.py CHANGED
@@ -95,6 +95,10 @@ class IndirectPeerDTO(MeshSession, _OptionsDTO):
95
95
  description: str
96
96
  update_source: str
97
97
 
98
+ ifname: Optional[str]
99
+ subif: int
100
+ svi: Optional[int]
101
+
98
102
 
99
103
  class VirtualLocalDTO(_OptionsDTO):
100
104
  asnum: int
@@ -164,7 +164,7 @@ class CommunityListGenerator(PartialGenerator, ABC):
164
164
  yield self._huawei_community_filter(10, community_list, " ".join(members))
165
165
  elif community_list.logic == CommunityLogic.OR:
166
166
  for i, member in enumerate(members):
167
- member_id = (i + 1) * 10 + 5
167
+ member_id = (i + 1) * 10
168
168
  yield self._huawei_community_filter(member_id, community_list, member)
169
169
  else:
170
170
  raise NotImplementedError(f"Community logic {community_list.logic} is not implemented for huawei")
annet/storage.py CHANGED
@@ -168,6 +168,10 @@ class Device(Protocol):
168
168
  """Add sub interface or return existing one"""
169
169
  raise NotImplementedError
170
170
 
171
+ @abc.abstractmethod
172
+ def find_interface(self, name: str) -> Optional[Interface]:
173
+ raise NotImplementedError
174
+
171
175
 
172
176
  def get_storage() -> tuple[StorageProvider, Dict[str, Any]]:
173
177
  connectors = storage_connector.get_all()
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: annet
3
- Version: 0.16.28
3
+ Version: 0.16.30
4
4
  Summary: annet
5
5
  Home-page: https://github.com/annetutil/annet
6
6
  License: MIT
@@ -24,3 +24,9 @@ Requires-Dist: adaptix==3.0.0b7
24
24
  Requires-Dist: dataclass-rest==0.4
25
25
  Provides-Extra: netbox
26
26
  Requires-Dist: annetbox[sync]>=0.1.10; extra == "netbox"
27
+ Dynamic: home-page
28
+ Dynamic: license
29
+ Dynamic: provides-extra
30
+ Dynamic: requires-dist
31
+ Dynamic: requires-python
32
+ Dynamic: summary
@@ -1,7 +1,7 @@
1
1
  annet/__init__.py,sha256=W8kkZ3Axu-6VJwgQ0cn4UeOVNy6jab0cqgHKLQny1D0,2141
2
2
  annet/annet.py,sha256=TMdEuM7GJQ4TjRVmuK3bCTZN-21lxjQ9sXqEdILUuBk,725
3
3
  annet/argparse.py,sha256=v1MfhjR0B8qahza0WinmXClpR8UiDFhmwDDWtNroJPA,12855
4
- annet/bgp_models.py,sha256=pju2KImDhBxU3lkyvP5TfeYuWztYj4i8OfcZqCX3xVY,8823
4
+ annet/bgp_models.py,sha256=5FnXMeIbZJIQRdUk6Jf2f3YlkQSLAgmBH8bq2o94MUM,9457
5
5
  annet/cli.py,sha256=hDpjIr3w47lgQ_CvCQS1SXFDK-SJrf5slbT__5u6GIA,12342
6
6
  annet/cli_args.py,sha256=KQlihxSl-Phhq1-9oJDdNSbIllEX55LlPfH6viEKOuw,13483
7
7
  annet/connectors.py,sha256=-Lghz3PtWCBU8Ohrp0KKQcmm1AUZtN0EnOaZ6IQgCQI,5105
@@ -17,7 +17,7 @@ annet/output.py,sha256=FYMcWCc43-b51KsCiKnXPZHawhgWNoVtY9gRqw__Ce0,7473
17
17
  annet/parallel.py,sha256=hLkzEht0KhzmzUWDdO4QFYQHzhxs3wPlTA8DxbB2ziw,17160
18
18
  annet/patching.py,sha256=nILbY5oJajN0b1j3f0HEJm05H3HVThnWvB7vDVh7UQw,559
19
19
  annet/reference.py,sha256=B8mH8VUMcecPnzULiTVb_kTQ7jQrCL7zp4pfIZQa5fk,4035
20
- annet/storage.py,sha256=eAHEvPbRuKDUJdnkzSrHmW_lBJS3Y0g93Y2VJ4qzifQ,3941
20
+ annet/storage.py,sha256=44f2aHNFOsQMSJwFvGxyu26oRcs3QmS24TKivcfPlxU,4064
21
21
  annet/tabparser.py,sha256=rRzfZSurR5P1eSdVWXMjABvV4PX83NRRQY0CzwabExw,1242
22
22
  annet/text_term_format.py,sha256=CHb6viv45vmYl-SK1A1vyPHGhaEni6jVybBusaQnct8,2813
23
23
  annet/tracing.py,sha256=ndpM-au1c88uBBpOuH_z52qWZL773edYozNyys_wA68,4044
@@ -27,13 +27,13 @@ annet/adapters/fetchers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
27
27
  annet/adapters/fetchers/stub/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
28
  annet/adapters/fetchers/stub/fetcher.py,sha256=bJGNJcvjrxSa4d8gly6NkaRcxoK57zbZhzkW5vq278I,656
29
29
  annet/adapters/file/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
- annet/adapters/file/provider.py,sha256=hfeHHJ4aeTT8p_K5Wj_euwjf0Y1Ir9Qijup6J9wk5RM,6555
30
+ annet/adapters/file/provider.py,sha256=KyHuA5w9E4T3Lxeko8b5M7jRmu7yhTJVLqLkas4ue1A,6654
31
31
  annet/adapters/netbox/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
32
  annet/adapters/netbox/provider.py,sha256=3IrfZ6CfCxf-lTnJlIC2TQ8M_rDxOB_B7HGXZ92vAgA,1643
33
33
  annet/adapters/netbox/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
34
  annet/adapters/netbox/common/client.py,sha256=PaxHG4W9H8_uunIwMBNYkLq4eQJYoO6p6gY-ciQs7Nc,2563
35
35
  annet/adapters/netbox/common/manufacturer.py,sha256=1kmw3YzitXwOh4zitsWfZda4CQiMr4CnAxkUkUm_z3A,1678
36
- annet/adapters/netbox/common/models.py,sha256=JAAtbUB6UOzA3-VF5Fa33XktgKC3C2csareTZnHyqd0,7177
36
+ annet/adapters/netbox/common/models.py,sha256=E-w1ptCpcrJcdAENcgJjXF-sVhUu2_7fZPNaDuhYnuw,7364
37
37
  annet/adapters/netbox/common/query.py,sha256=ziUFM7cUEbEIf3k1szTll4aO-OCUa-2Ogxbebi7Tegs,646
38
38
  annet/adapters/netbox/common/status_client.py,sha256=W4nTb2yvBlJ2UkWUmUhKQ2PaSQb1shjhHj5ebb4s2s4,591
39
39
  annet/adapters/netbox/common/storage_opts.py,sha256=5tt6wxUUJTIzNbOVXMnYBwZedNAIqYlve3YWl6GdbZM,1197
@@ -55,7 +55,7 @@ annet/annlib/types.py,sha256=VHU0CBADfYmO0xzB_c5f-mcuU3dUumuJczQnqGlib9M,852
55
55
  annet/annlib/netdev/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
56
  annet/annlib/netdev/db.py,sha256=fI_u5aya4l61mbYSjj4JwlVfi3s7obt2jqERSuXGRUI,1634
57
57
  annet/annlib/netdev/devdb/__init__.py,sha256=aKYjjLbJebdKBjnGDpVLQdSqrV2JL24spGm58tmMWVU,892
58
- annet/annlib/netdev/devdb/data/devdb.json,sha256=OM3FLBUGPJ_d97Q3hnavj51CoWlilJsoJLkHSzE-nPg,6127
58
+ annet/annlib/netdev/devdb/data/devdb.json,sha256=Zt9pj6h2clMi0i26bGVsx0gqQl8vCSk6iLajIYWeKX4,6192
59
59
  annet/annlib/netdev/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
60
60
  annet/annlib/netdev/views/dump.py,sha256=rIlyvnA3uM8bB_7oq1nS2KDxTp6dQh2hz-FbNhYIpOU,4630
61
61
  annet/annlib/netdev/views/hardware.py,sha256=3JCZLH7deIHhCguwPJTUX-WDvWjG_xt6BdSEZSO6zkQ,4226
@@ -84,10 +84,10 @@ annet/generators/common/initial.py,sha256=qYBxXFhyOPy34cxc6hsIXseod-lYCmmbuNHpM0
84
84
  annet/mesh/__init__.py,sha256=lcgdnBIxc2MAN7Er1bcErEKPqrjWO4uIp_1FldMXTYg,557
85
85
  annet/mesh/basemodel.py,sha256=TXVINzmvKlyxiVcIdOaoewY_c4TvuMstluqfzlbNmPU,4859
86
86
  annet/mesh/device_models.py,sha256=YcL6_vGjnt67BTovN8Eq38U5wGcbJDhqiq8613WpYtQ,3381
87
- annet/mesh/executor.py,sha256=vJaw6cGwOkCQDABK1mkYk67BPAeWArpTHA9jNKtJDc0,14684
87
+ annet/mesh/executor.py,sha256=V5GR_m9T6hVWR5sFY-x4JkS0LpI6UH5Q7HxuhC8KXFE,16299
88
88
  annet/mesh/match_args.py,sha256=CR3kdIV9NGtyk9E2JbcOQ3TRuYEryTWP3m2yCo2VCWg,5751
89
89
  annet/mesh/models_converter.py,sha256=3q2zs7K8S3pfYSUKKRdtl5CJGbeg4TtYxofAVs_MBsk,3085
90
- annet/mesh/peer_models.py,sha256=KgVHXzoLfYweBVDCGDeEA8CuPvaTDe-4kreXyZOLQzM,2670
90
+ annet/mesh/peer_models.py,sha256=uD3h7HWl9_zNdBlQqZCMcjCnzjr8dTbSFqc8216JDu0,2735
91
91
  annet/mesh/port_processor.py,sha256=RHiMS5W8qoDkTKiarQ748bcr8bNx4g_R4Y4vZg2k4TU,478
92
92
  annet/mesh/registry.py,sha256=VvZKZ5ujGcRXvWFP051rr2KoXI8OrTivkhpTOrUm33A,9087
93
93
  annet/rpl/__init__.py,sha256=0kcIktE3AmS0rlm9xzVDf53xk08OeZXgD-6ZLCt_KCs,731
@@ -100,7 +100,7 @@ annet/rpl/routemap.py,sha256=SIyk73OzPp2oH_XwrDv2xczuY2Zt1VsJmB0TT5r7F5g,2593
100
100
  annet/rpl/statement_builder.py,sha256=sVGOYsCV0s_SFQUy2WtUyQqKy5H4MOfmRCJWGj-UOJ4,9403
101
101
  annet/rpl_generators/__init__.py,sha256=ZLWs-flcpyIbdhxSDfNt-ORDrLe8ins25sWdXTWeUoA,748
102
102
  annet/rpl_generators/aspath.py,sha256=kZakwPLfGGiXu9fC6I1z-pvy7Fe-4dy93_-lYcx39_4,2038
103
- annet/rpl_generators/community.py,sha256=8HxeUS2i015lXP7NxVW5EIbFjpg4mdljfQrOIUENtmk,11500
103
+ annet/rpl_generators/community.py,sha256=SWpaOvoQUNISuRm41-IvGPFmntvgFv9ee4zegsMyeo0,11496
104
104
  annet/rpl_generators/cumulus_frr.py,sha256=yMxm264PZq8MnSYQ2jmLv2CSa2Jl2ais_7XBTXKowj0,20053
105
105
  annet/rpl_generators/entities.py,sha256=052ggNCGbEE-m--MdzLJhJ-1ch6IxDsL6xnMH0OHgtg,1491
106
106
  annet/rpl_generators/execute.py,sha256=wS6e6fwcPWywsHB0gBMqZ17eF0s4YOBgDgwPB_cr5Rw,431
@@ -175,10 +175,10 @@ annet_generators/rpl_example/generator.py,sha256=zndIGfV4ZlTxPgAGYs7bMQvTc_tYScO
175
175
  annet_generators/rpl_example/items.py,sha256=Ez1RF5YhcXNCusBmeApIjRL3rBlMazNZd29Gpw1_IsA,766
176
176
  annet_generators/rpl_example/mesh.py,sha256=z_WgfDZZ4xnyh3cSf75igyH09hGvtexEVwy1gCD_DzA,288
177
177
  annet_generators/rpl_example/route_policy.py,sha256=z6nPb0VDeQtKD1NIg9sFvmUxBD5tVs2frfNIuKdM-5c,2318
178
- annet-0.16.28.dist-info/AUTHORS,sha256=rh3w5P6gEgqmuC-bw-HB68vBCr-yIBFhVL0PG4hguLs,878
179
- annet-0.16.28.dist-info/LICENSE,sha256=yPxl7dno02Pw7gAcFPIFONzx_gapwDoPXsIsh6Y7lC0,1079
180
- annet-0.16.28.dist-info/METADATA,sha256=-EflTMHVXM8VDk6NwmYp-DZl-Fzn624B5HNp_JuoIwU,729
181
- annet-0.16.28.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
182
- annet-0.16.28.dist-info/entry_points.txt,sha256=5lIaDGlGi3l6QQ2ry2jZaqViP5Lvt8AmsegdD0Uznck,192
183
- annet-0.16.28.dist-info/top_level.txt,sha256=QsoTZBsUtwp_FEcmRwuN8QITBmLOZFqjssRfKilGbP8,23
184
- annet-0.16.28.dist-info/RECORD,,
178
+ annet-0.16.30.dist-info/AUTHORS,sha256=rh3w5P6gEgqmuC-bw-HB68vBCr-yIBFhVL0PG4hguLs,878
179
+ annet-0.16.30.dist-info/LICENSE,sha256=yPxl7dno02Pw7gAcFPIFONzx_gapwDoPXsIsh6Y7lC0,1079
180
+ annet-0.16.30.dist-info/METADATA,sha256=HEQle9FUcien2kzE20RedAMAzPAfatx1Hw852aelJiA,854
181
+ annet-0.16.30.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
182
+ annet-0.16.30.dist-info/entry_points.txt,sha256=5lIaDGlGi3l6QQ2ry2jZaqViP5Lvt8AmsegdD0Uznck,192
183
+ annet-0.16.30.dist-info/top_level.txt,sha256=QsoTZBsUtwp_FEcmRwuN8QITBmLOZFqjssRfKilGbP8,23
184
+ annet-0.16.30.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.6.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5