trigger 2.2.6__tar.gz → 2.3.1__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.
Files changed (78) hide show
  1. {trigger-2.2.6/trigger.egg-info → trigger-2.3.1}/PKG-INFO +2 -2
  2. {trigger-2.2.6 → trigger-2.3.1}/pyproject.toml +2 -2
  3. {trigger-2.2.6 → trigger-2.3.1}/trigger/acl/ios.py +2 -2
  4. {trigger-2.2.6 → trigger-2.3.1}/trigger/acl/support.py +104 -58
  5. {trigger-2.2.6 → trigger-2.3.1}/trigger/acl/tools.py +5 -6
  6. {trigger-2.2.6 → trigger-2.3.1}/trigger/cmds.py +9 -7
  7. {trigger-2.2.6 → trigger-2.3.1}/trigger/conf/global_settings.py +4 -4
  8. {trigger-2.2.6 → trigger-2.3.1}/trigger/netdevices/__init__.py +1 -1
  9. {trigger-2.2.6 → trigger-2.3.1}/trigger/netscreen.py +5 -5
  10. {trigger-2.2.6 → trigger-2.3.1/trigger.egg-info}/PKG-INFO +2 -2
  11. {trigger-2.2.6 → trigger-2.3.1}/trigger.egg-info/requires.txt +1 -1
  12. {trigger-2.2.6 → trigger-2.3.1}/AUTHORS.md +0 -0
  13. {trigger-2.2.6 → trigger-2.3.1}/LICENSE.md +0 -0
  14. {trigger-2.2.6 → trigger-2.3.1}/README.md +0 -0
  15. {trigger-2.2.6 → trigger-2.3.1}/setup.cfg +0 -0
  16. {trigger-2.2.6 → trigger-2.3.1}/tests/test_acl.py +0 -0
  17. {trigger-2.2.6 → trigger-2.3.1}/tests/test_acl_db.py +0 -0
  18. {trigger-2.2.6 → trigger-2.3.1}/tests/test_acl_queue.py +0 -0
  19. {trigger-2.2.6 → trigger-2.3.1}/tests/test_changemgmt.py +0 -0
  20. {trigger-2.2.6 → trigger-2.3.1}/tests/test_except.py +0 -0
  21. {trigger-2.2.6 → trigger-2.3.1}/tests/test_netdevices.py +0 -0
  22. {trigger-2.2.6 → trigger-2.3.1}/tests/test_scripts.py +0 -0
  23. {trigger-2.2.6 → trigger-2.3.1}/tests/test_tacacsrc.py +0 -0
  24. {trigger-2.2.6 → trigger-2.3.1}/tests/test_templates.py +0 -0
  25. {trigger-2.2.6 → trigger-2.3.1}/tests/test_twister.py +0 -0
  26. {trigger-2.2.6 → trigger-2.3.1}/tests/test_twister2.py +0 -0
  27. {trigger-2.2.6 → trigger-2.3.1}/tests/test_utils.py +0 -0
  28. {trigger-2.2.6 → trigger-2.3.1}/trigger/__init__.py +0 -0
  29. {trigger-2.2.6 → trigger-2.3.1}/trigger/acl/__init__.py +0 -0
  30. {trigger-2.2.6 → trigger-2.3.1}/trigger/acl/autoacl.py +0 -0
  31. {trigger-2.2.6 → trigger-2.3.1}/trigger/acl/db.py +0 -0
  32. {trigger-2.2.6 → trigger-2.3.1}/trigger/acl/dicts.py +0 -0
  33. {trigger-2.2.6 → trigger-2.3.1}/trigger/acl/grammar.py +0 -0
  34. {trigger-2.2.6 → trigger-2.3.1}/trigger/acl/junos.py +0 -0
  35. {trigger-2.2.6 → trigger-2.3.1}/trigger/acl/models.py +0 -0
  36. {trigger-2.2.6 → trigger-2.3.1}/trigger/acl/parser.py +0 -0
  37. {trigger-2.2.6 → trigger-2.3.1}/trigger/acl/queue.py +0 -0
  38. {trigger-2.2.6 → trigger-2.3.1}/trigger/bin/__init__.py +0 -0
  39. {trigger-2.2.6 → trigger-2.3.1}/trigger/bin/acl.py +0 -0
  40. {trigger-2.2.6 → trigger-2.3.1}/trigger/bin/acl_script.py +0 -0
  41. {trigger-2.2.6 → trigger-2.3.1}/trigger/bin/aclconv.py +0 -0
  42. {trigger-2.2.6 → trigger-2.3.1}/trigger/bin/check_access.py +0 -0
  43. {trigger-2.2.6 → trigger-2.3.1}/trigger/bin/check_syntax.py +0 -0
  44. {trigger-2.2.6 → trigger-2.3.1}/trigger/bin/fe.py +0 -0
  45. {trigger-2.2.6 → trigger-2.3.1}/trigger/bin/find_access.py +0 -0
  46. {trigger-2.2.6 → trigger-2.3.1}/trigger/bin/gnng.py +0 -0
  47. {trigger-2.2.6 → trigger-2.3.1}/trigger/bin/gong.py +0 -0
  48. {trigger-2.2.6 → trigger-2.3.1}/trigger/bin/load_acl.py +0 -0
  49. {trigger-2.2.6 → trigger-2.3.1}/trigger/bin/load_config.py +0 -0
  50. {trigger-2.2.6 → trigger-2.3.1}/trigger/bin/netdev.py +0 -0
  51. {trigger-2.2.6 → trigger-2.3.1}/trigger/bin/optimizer.py +0 -0
  52. {trigger-2.2.6 → trigger-2.3.1}/trigger/bin/run_cmds.py +0 -0
  53. {trigger-2.2.6 → trigger-2.3.1}/trigger/changemgmt/__init__.py +0 -0
  54. {trigger-2.2.6 → trigger-2.3.1}/trigger/changemgmt/bounce.py +0 -0
  55. {trigger-2.2.6 → trigger-2.3.1}/trigger/conf/__init__.py +0 -0
  56. {trigger-2.2.6 → trigger-2.3.1}/trigger/contrib/__init__.py +0 -0
  57. {trigger-2.2.6 → trigger-2.3.1}/trigger/exceptions.py +0 -0
  58. {trigger-2.2.6 → trigger-2.3.1}/trigger/gorc.py +0 -0
  59. {trigger-2.2.6 → trigger-2.3.1}/trigger/netdevices/loader.py +0 -0
  60. {trigger-2.2.6 → trigger-2.3.1}/trigger/packages/__init__.py +0 -0
  61. {trigger-2.2.6 → trigger-2.3.1}/trigger/packages/peewee.py +0 -0
  62. {trigger-2.2.6 → trigger-2.3.1}/trigger/rancid.py +0 -0
  63. {trigger-2.2.6 → trigger-2.3.1}/trigger/tacacsrc.py +0 -0
  64. {trigger-2.2.6 → trigger-2.3.1}/trigger/twister.py +0 -0
  65. {trigger-2.2.6 → trigger-2.3.1}/trigger/twister2.py +0 -0
  66. {trigger-2.2.6 → trigger-2.3.1}/trigger/utils/__init__.py +0 -0
  67. {trigger-2.2.6 → trigger-2.3.1}/trigger/utils/cli.py +0 -0
  68. {trigger-2.2.6 → trigger-2.3.1}/trigger/utils/importlib.py +0 -0
  69. {trigger-2.2.6 → trigger-2.3.1}/trigger/utils/network.py +0 -0
  70. {trigger-2.2.6 → trigger-2.3.1}/trigger/utils/rcs.py +0 -0
  71. {trigger-2.2.6 → trigger-2.3.1}/trigger/utils/templates.py +0 -0
  72. {trigger-2.2.6 → trigger-2.3.1}/trigger/utils/url.py +0 -0
  73. {trigger-2.2.6 → trigger-2.3.1}/trigger/utils/xmltodict.py +0 -0
  74. {trigger-2.2.6 → trigger-2.3.1}/trigger.egg-info/SOURCES.txt +0 -0
  75. {trigger-2.2.6 → trigger-2.3.1}/trigger.egg-info/dependency_links.txt +0 -0
  76. {trigger-2.2.6 → trigger-2.3.1}/trigger.egg-info/entry_points.txt +0 -0
  77. {trigger-2.2.6 → trigger-2.3.1}/trigger.egg-info/top_level.txt +0 -0
  78. {trigger-2.2.6 → trigger-2.3.1}/twisted/plugins/trigger_xmlrpc.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: trigger
3
- Version: 2.2.6
3
+ Version: 2.3.1
4
4
  Summary: Network automation toolkit for managing network devices
5
5
  Author-email: Jathan McCollum <jathan@gmail.com>
6
6
  License-Expression: BSD-3-Clause
@@ -13,7 +13,7 @@ Requires-Python: <3.12,>=3.10
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE.md
15
15
  License-File: AUTHORS.md
16
- Requires-Dist: IPy>=1.01
16
+ Requires-Dist: netaddr<2,>=1.0.0
17
17
  Requires-Dist: cryptography>=41.0.0
18
18
  Requires-Dist: Twisted>=22.10.0
19
19
  Requires-Dist: crochet>=2.0.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "trigger"
7
- version = "2.2.6"
7
+ version = "2.3.1"
8
8
  description = "Network automation toolkit for managing network devices"
9
9
  readme = "README.md"
10
10
  license = "BSD-3-Clause"
@@ -18,7 +18,7 @@ classifiers = [
18
18
  "Framework :: Twisted",
19
19
  ]
20
20
  dependencies = [
21
- "IPy>=1.01",
21
+ "netaddr>=1.0.0,<2",
22
22
  "cryptography>=41.0.0",
23
23
  "Twisted>=22.10.0",
24
24
  "crochet>=2.0.0",
@@ -27,7 +27,7 @@ class Remark(Comment): # noqa: F405
27
27
  # Build a table to unwind Cisco's weird inverse netmask.
28
28
  # TODO (jathan): These don't actually get sorted properly, but it doesn't seem
29
29
  # to have mattered up until now. Worth looking into it at some point, though.
30
- inverse_mask_table = dict([(make_inverse_mask(x), x) for x in range(33)]) # noqa: F405
30
+ inverse_mask_table = {str(make_inverse_mask(x)): x for x in range(33)} # noqa: F405
31
31
 
32
32
 
33
33
  def handle_ios_match(a): # noqa: D103, PLR0912
@@ -129,7 +129,7 @@ rules.update( # noqa: F405
129
129
  ),
130
130
  "ipv4_inverse_mask": (
131
131
  literals(inverse_mask_table), # noqa: F405
132
- lambda x: inverse_mask_table[TIP(x)], # noqa: F405
132
+ lambda x: inverse_mask_table[x],
133
133
  ),
134
134
  "kw_ip": ('"ip"', None),
135
135
  S("ios_match"): ( # noqa: F405
@@ -29,15 +29,12 @@ support the various modules for parsing. This file is not meant to by used by it
29
29
  import contextlib
30
30
  from typing import ClassVar
31
31
 
32
- import IPy
32
+ import netaddr
33
33
 
34
34
  from trigger import exceptions
35
35
 
36
36
  from .dicts import * # noqa: F403
37
37
 
38
- # Python 2/3 compatibility
39
- unicode = str
40
-
41
38
  # Temporary resting place for comments, so the rest of the parser can
42
39
  # ignore them. Yes, this makes the library not thread-safe.
43
40
  Comments = []
@@ -130,13 +127,13 @@ def do_dscp_lookup(arg): # noqa: D103
130
127
 
131
128
 
132
129
  def make_inverse_mask(prefixlen):
133
- """Return an IP object of the inverse mask of the CIDR prefix.
130
+ """Return an IP address object of the inverse mask of the CIDR prefix.
134
131
 
135
132
  :param prefixlen:
136
133
  CIDR prefix
137
134
  """
138
135
  inverse_bits = 2 ** (32 - prefixlen) - 1
139
- return TIP(inverse_bits)
136
+ return netaddr.IPAddress(inverse_bits)
140
137
 
141
138
 
142
139
  def strip_comments(tags): # noqa: D103
@@ -431,12 +428,13 @@ class RangeList:
431
428
  return self.data.__iter__()
432
429
 
433
430
 
434
- class TIP(IPy.IP):
435
- """Class based on IPy.IP, but with extensions for Trigger.
431
+ class TIP(netaddr.IPNetwork):
432
+ """Class based on netaddr.IPNetwork, but with extensions for Trigger.
436
433
 
437
434
  Currently, only the only extension is the ability to negate a network
438
435
  block. Only used internally within the parser, as it's not complete
439
- (doesn't interact well with IPy.IP objects). Does not handle IPv6 yet.
436
+ (doesn't interact well with netaddr.IPNetwork objects). Does not handle
437
+ IPv6 yet.
440
438
  """
441
439
 
442
440
  def __init__(self, data, **kwargs): # noqa: D107
@@ -448,7 +446,7 @@ class TIP(IPy.IP):
448
446
  inactive = getattr(data, "inactive", False)
449
447
 
450
448
  # Is data a string?
451
- if isinstance(data, (str, unicode)):
449
+ if isinstance(data, str):
452
450
  d = data.split()
453
451
  # This means we got something like "1.2.3.4 except" or "inactive:
454
452
  # 1.2.3.4'
@@ -471,87 +469,101 @@ class TIP(IPy.IP):
471
469
 
472
470
  self.negated = negated # Set 'negated' variable
473
471
  self.inactive = inactive # Set 'inactive' variable
474
- IPy.IP.__init__(self, data, **kwargs)
475
472
 
476
- # Make it print prefixes for /32, /128 if we're negated or inactive (and
477
- # therefore assuming we're being used in a Juniper ACL.)
478
- if self.negated or self.inactive:
479
- self.NoPrefixForSingleIp = False
473
+ # Expand partial IPv4 addresses like "10/8" → "10.0.0.0/8"
474
+ if isinstance(data, str) and "/" in data:
475
+ parts = data.split("/")
476
+ addr_part = parts[0]
477
+ # Only apply to IPv4 (no colons in address part)
478
+ if ":" not in addr_part:
479
+ octets = addr_part.split(".")
480
+ while len(octets) < 4: # noqa: PLR2004
481
+ octets.append("0")
482
+ data = ".".join(octets) + "/" + parts[1]
483
+
484
+ super().__init__(data, **kwargs)
480
485
 
481
486
  def _compare_to(self, other):
482
487
  """Helper method for comparison. Returns -1, 0, or 1.""" # noqa: D401
483
- # Regular IPy sorts by prefix length before network base, but Juniper
484
- # (our baseline) does not. We also need comparisons to be different for
485
- # negation. Following Juniper's sorting, use IP compare, and then break
488
+ # Following Juniper's sorting, use IP compare, and then break
486
489
  # ties where negated < not negated.
487
- # Python 3: Implement cmp() logic inline
488
- if self.ip < other.ip:
490
+ self_first = self.first
491
+ if hasattr(other, "first"):
492
+ other_first = other.first
493
+ else:
494
+ return NotImplemented
495
+ if self_first < other_first:
489
496
  diff = -1
490
- elif self.ip > other.ip:
497
+ elif self_first > other_first:
491
498
  diff = 1
492
499
  else:
493
500
  diff = 0
494
501
 
495
502
  if diff == 0:
496
503
  # If the same IP, compare by prefixlen
497
- if self.prefixlen() < other.prefixlen():
504
+ if self.prefixlen < other.prefixlen:
498
505
  diff = -1
499
- elif self.prefixlen() > other.prefixlen():
506
+ elif self.prefixlen > other.prefixlen:
500
507
  diff = 1
501
508
  else:
502
509
  diff = 0
503
510
 
504
511
  # If both negated, they're the same
505
- if self.negated == other.negated:
512
+ other_negated = getattr(other, "negated", False)
513
+ if self.negated == other_negated:
506
514
  return diff
507
515
  # Sort to make negated < not negated
508
516
  return -1 if self.negated else 1
509
- # Return the base comparison
510
517
 
511
518
  def __lt__(self, other): # noqa: D105
512
- return self._compare_to(other) < 0
519
+ result = self._compare_to(other)
520
+ if result is NotImplemented:
521
+ return NotImplemented
522
+ return result < 0
513
523
 
514
524
  def __le__(self, other): # noqa: D105
515
- return self._compare_to(other) <= 0
525
+ result = self._compare_to(other)
526
+ if result is NotImplemented:
527
+ return NotImplemented
528
+ return result <= 0
516
529
 
517
530
  def __gt__(self, other): # noqa: D105
518
- return self._compare_to(other) > 0
531
+ result = self._compare_to(other)
532
+ if result is NotImplemented:
533
+ return NotImplemented
534
+ return result > 0
519
535
 
520
536
  def __ge__(self, other): # noqa: D105
521
- return self._compare_to(other) >= 0
537
+ result = self._compare_to(other)
538
+ if result is NotImplemented:
539
+ return NotImplemented
540
+ return result >= 0
522
541
 
523
542
  def __eq__(self, other): # noqa: D105
524
- return self._compare_to(other) == 0
543
+ result = self._compare_to(other)
544
+ if result is NotImplemented:
545
+ return NotImplemented
546
+ return result == 0
525
547
 
526
548
  def __ne__(self, other): # noqa: D105
527
- return self._compare_to(other) != 0
549
+ result = self._compare_to(other)
550
+ if result is NotImplemented:
551
+ return NotImplemented
552
+ return result != 0
528
553
 
529
554
  def __hash__(self): # noqa: D105
530
- # Make TIP hashable for use in sets and as dict keys
531
- # Base hash on IP address, prefix length, and negation status
532
- return hash((str(self.ip), self.prefixlen(), self.negated, self.inactive))
555
+ return hash((self.first, self.prefixlen, self.negated, self.inactive))
533
556
 
534
557
  def __repr__(self): # noqa: D105
535
- # Just stick an 'except' at the end if except is set since we don't
536
- # code to accept this in the constructor really just provided, for now,
537
- # as a debugging aid.
538
- rs = IPy.IP.__repr__(self)
539
- if self.negated:
540
- # Insert ' except' into the repr. (Yes, it's a hack!)
541
- rs = rs.split("'")
542
- rs[1] += " except"
543
- rs = "'".join(rs) # Restore original repr
544
- if self.inactive:
545
- # Insert 'inactive: ' into the repr. (Yes, it's also a hack!)
546
- rs = rs.split("'")
547
- rs[1] = "inactive: " + rs[1]
548
- rs = "'".join(rs) # Restore original repr
549
- return rs
558
+ return f"TIP('{self!s}')"
550
559
 
551
560
  def __str__(self): # noqa: D105
552
- # IPy is not a new-style class, so the following doesn't work:
553
- # return super(TIP, self).__str__() # noqa: ERA001
554
- rs = IPy.IP.__str__(self)
561
+ # Show prefix for all networks, but omit for single hosts (/32, /128)
562
+ # unless negated or inactive (Juniper ACL style needs prefix)
563
+ if self.prefixlen in (32, 128) and not self.negated and not self.inactive:
564
+ rs = str(self.ip)
565
+ else:
566
+ rs = f"{self.network}/{self.prefixlen}"
555
567
  if self.negated:
556
568
  rs += " except"
557
569
  if self.inactive:
@@ -566,9 +578,39 @@ class TIP(IPy.IP):
566
578
  # If one item is negated, it's never contained.
567
579
  if xor:
568
580
  return False
569
- matched = IPy.IP.__contains__(self, item)
581
+ matched = super().__contains__(item)
570
582
  return matched ^ self.negated
571
583
 
584
+ # Prevent netaddr's iteration/subscript protocol from interfering with
585
+ # RangeList, which would otherwise treat TIP as a sequence of integers.
586
+ def __iter__(self): # noqa: D105
587
+ msg = f"'{type(self).__name__}' object is not iterable"
588
+ raise TypeError(msg)
589
+
590
+ def __getitem__(self, index): # noqa: D105
591
+ msg = f"'{type(self).__name__}' object is not subscriptable"
592
+ raise TypeError(msg)
593
+
594
+ def __len__(self): # noqa: D105
595
+ msg = f"'{type(self).__name__}' object has no len()"
596
+ raise TypeError(msg)
597
+
598
+ # Compatibility methods for code that uses IPy-style API
599
+ def net(self):
600
+ """Return the network address as an IPAddress object."""
601
+ return self.network
602
+
603
+ def strNormal(self, mode=0):
604
+ """Return string representation compatible with IPy's strNormal.
605
+
606
+ :param mode:
607
+ 0 = address without prefix for host, with prefix for network
608
+ 1 = address with prefix always
609
+ """
610
+ if mode == 0 and self.prefixlen in (32, 128):
611
+ return str(self.ip)
612
+ return f"{self.network}/{self.prefixlen}"
613
+
572
614
 
573
615
  class Comment:
574
616
  """Container for inline comments."""
@@ -1246,8 +1288,12 @@ class Matches(MyDict):
1246
1288
  return "%s-%s" % pair # noqa: UP031 # Tuples back to ranges.
1247
1289
  except TypeError:
1248
1290
  with contextlib.suppress(AttributeError):
1249
- # Make it print prefixes for /32, /128
1250
- pair.NoPrefixForSingleIp = False
1291
+ # Force prefix display for /32 and /128 in JunOS output
1292
+ if hasattr(pair, "prefixlen") and pair.prefixlen in (32, 128):
1293
+ result = f"{pair.network}/{pair.prefixlen}"
1294
+ if getattr(pair, "negated", False):
1295
+ result += " except"
1296
+ return result
1251
1297
  return str(pair)
1252
1298
 
1253
1299
  def ios_port_str(self, ports):
@@ -1286,12 +1332,12 @@ class Matches(MyDict):
1286
1332
  raise exceptions.VendorSupportLacking(
1287
1333
  msg,
1288
1334
  )
1289
- if addr.prefixlen() == 0:
1335
+ if addr.prefixlen == 0:
1290
1336
  a.append("any")
1291
- elif addr.prefixlen() == 32: # noqa: PLR2004
1337
+ elif addr.prefixlen == 32: # noqa: PLR2004
1292
1338
  a.append(f"host {addr.net()}")
1293
1339
  else:
1294
- inverse_mask = make_inverse_mask(addr.prefixlen())
1340
+ inverse_mask = make_inverse_mask(addr.prefixlen)
1295
1341
  a.append(f"{addr.net()} {inverse_mask}")
1296
1342
  return a
1297
1343
 
@@ -9,9 +9,8 @@ import tempfile
9
9
  from collections import defaultdict
10
10
  from pathlib import Path
11
11
 
12
- import IPy
13
-
14
12
  from trigger.acl.parser import * # noqa: F403
13
+ from trigger.acl.support import TIP
15
14
  from trigger.conf import settings
16
15
 
17
16
  # Defaults
@@ -667,10 +666,10 @@ class ACLScript:
667
666
  def _add_addr(self, to, src):
668
667
  if isinstance(src, list):
669
668
  for x in src:
670
- if IPy.IP(x) not in to:
671
- to.append(IPy.IP(x))
672
- elif IPy.IP(src) not in to:
673
- to.append(IPy.IP(src))
669
+ if TIP(x) not in to:
670
+ to.append(TIP(x))
671
+ elif TIP(src) not in to:
672
+ to.append(TIP(src))
674
673
 
675
674
  def _add_port(self, to, src):
676
675
  if isinstance(src, list):
@@ -11,11 +11,12 @@ import collections
11
11
  import itertools
12
12
  from xml.etree.ElementTree import Element, SubElement
13
13
 
14
- from IPy import IP
14
+ from netaddr import IPNetwork as IP
15
15
  from twisted.internet import defer, task
16
16
  from twisted.python import log
17
17
 
18
18
  from trigger import exceptions
19
+ from trigger.acl.support import TIP
19
20
  from trigger.conf import settings
20
21
  from trigger.netdevices import NetDevices
21
22
  from trigger.utils.templates import (
@@ -808,12 +809,13 @@ class NetACLInfo(Commando):
808
809
  super().__init__(**args)
809
810
 
810
811
  def IPsubnet(self, addr):
811
- """Given '172.20.1.4/24', return IP('172.20.1.0/24')."""
812
- return IP(addr, make_net=True)
812
+ """Given '172.20.1.4/24', return TIP('172.20.1.0/24')."""
813
+ net = IP(addr)
814
+ return TIP(f"{net.network}/{net.prefixlen}")
813
815
 
814
816
  def IPhost(self, addr):
815
- """Given '172.20.1.4/24', return IP('172.20.1.4/32')."""
816
- return IP(addr[: addr.index("/")]) # Only keep before "/"
817
+ """Given '172.20.1.4/24', return TIP('172.20.1.4/32')."""
818
+ return TIP(addr[: addr.index("/")]) # Only keep before "/"
817
819
 
818
820
  # =======================================
819
821
  # Vendor-specific generate (to_)/parse (from_) methods
@@ -1165,14 +1167,14 @@ def _make_ipy(nets):
1165
1167
  """Given a list of 2-tuples of (address, netmask), returns a list of
1166
1168
  IP address objects.
1167
1169
  """ # noqa: D205
1168
- return [IP(addr) for addr, mask in nets]
1170
+ return [TIP(addr) for addr, mask in nets]
1169
1171
 
1170
1172
 
1171
1173
  def _make_cidrs(nets):
1172
1174
  """Given a list of 2-tuples of (address, netmask), returns a list CIDR
1173
1175
  blocks.
1174
1176
  """ # noqa: D205
1175
- return [IP(addr).make_net(mask) for addr, mask in nets]
1177
+ return [TIP(IP(f"{addr}/{mask}").cidr) for addr, mask in nets]
1176
1178
 
1177
1179
 
1178
1180
  def _dump_interfaces(idict):
@@ -9,7 +9,7 @@ import os
9
9
  import socket
10
10
  from pathlib import Path
11
11
 
12
- import IPy
12
+ import netaddr
13
13
 
14
14
  # ===============================
15
15
  # Global Settings
@@ -67,9 +67,9 @@ TFTP_HOST = ""
67
67
  # Add internally owned networks here. All network blocks owned/operated and
68
68
  # considered part of your network should be included.
69
69
  INTERNAL_NETWORKS = [
70
- IPy.IP("10.0.0.0/8"),
71
- IPy.IP("172.16.0.0/12"),
72
- IPy.IP("192.168.0.0/16"),
70
+ netaddr.IPNetwork("10.0.0.0/8"),
71
+ netaddr.IPNetwork("172.16.0.0/12"),
72
+ netaddr.IPNetwork("192.168.0.0/16"),
73
73
  ]
74
74
 
75
75
  # A dictionary keyed by manufacturer name containing a list of the device types
@@ -472,7 +472,7 @@ class NetDevice: # noqa: PLW1641 - mutable object, intentionally unhashable
472
472
  return self.nodeName.split(".", 1)[0]
473
473
 
474
474
  @property
475
- def os(self): # noqa: F811, D102
475
+ def os(self): # noqa: D102
476
476
  vendor_mapping = settings.TEXTFSM_VENDOR_MAPPINGS
477
477
  try:
478
478
  oss = vendor_mapping[self.vendor]
@@ -3,7 +3,7 @@ Broken apart from acl.parser because the approaches are vastly different from ea
3
3
  other.
4
4
  """ # noqa: D205
5
5
 
6
- import IPy
6
+ import netaddr
7
7
 
8
8
  from trigger import exceptions
9
9
  from trigger.acl.parser import (
@@ -555,11 +555,11 @@ class NSAddressBook(NetScreen):
555
555
  self.any = NSAddress(name="ANY")
556
556
 
557
557
  def find(self, address, zone): # noqa: D102
558
- if not self.entries.has_key(zone):
558
+ if zone not in self.entries:
559
559
  return None
560
560
 
561
561
  for nsaddr in self.entries[zone]:
562
- if isinstance(address, IPy.IP):
562
+ if isinstance(address, netaddr.IPNetwork):
563
563
  if nsaddr.addr == address:
564
564
  return nsaddr
565
565
  elif isinstance(address, str):
@@ -646,7 +646,7 @@ class NSAddress(NetScreen):
646
646
  self.zone,
647
647
  self.name,
648
648
  self.addr.strNormal(0),
649
- self.addr.netmask(),
649
+ str(self.addr.netmask),
650
650
  self.comment,
651
651
  )
652
652
  return [output]
@@ -808,7 +808,7 @@ class NSPolicy(NetScreen):
808
808
  addr = TIP(address)
809
809
  found = address_book.find(addr, zone)
810
810
  if not found:
811
- if addr.prefixlen() == 32: # noqa: PLR2004
811
+ if addr.prefixlen == 32: # noqa: PLR2004
812
812
  name = f"h{addr.strNormal(0)}"
813
813
  else:
814
814
  name = f"n{addr.strNormal()}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: trigger
3
- Version: 2.2.6
3
+ Version: 2.3.1
4
4
  Summary: Network automation toolkit for managing network devices
5
5
  Author-email: Jathan McCollum <jathan@gmail.com>
6
6
  License-Expression: BSD-3-Clause
@@ -13,7 +13,7 @@ Requires-Python: <3.12,>=3.10
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE.md
15
15
  License-File: AUTHORS.md
16
- Requires-Dist: IPy>=1.01
16
+ Requires-Dist: netaddr<2,>=1.0.0
17
17
  Requires-Dist: cryptography>=41.0.0
18
18
  Requires-Dist: Twisted>=22.10.0
19
19
  Requires-Dist: crochet>=2.0.0
@@ -1,4 +1,4 @@
1
- IPy>=1.01
1
+ netaddr<2,>=1.0.0
2
2
  cryptography>=41.0.0
3
3
  Twisted>=22.10.0
4
4
  crochet>=2.0.0
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