Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/hypothesis/strategies/_internal/ipaddress.py: 38%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

32 statements  

1# This file is part of Hypothesis, which may be found at 

2# https://github.com/HypothesisWorks/hypothesis/ 

3# 

4# Copyright the Hypothesis Authors. 

5# Individual contributors are listed in AUTHORS.rst and the git log. 

6# 

7# This Source Code Form is subject to the terms of the Mozilla Public License, 

8# v. 2.0. If a copy of the MPL was not distributed with this file, You can 

9# obtain one at https://mozilla.org/MPL/2.0/. 

10 

11from ipaddress import IPv4Address, IPv4Network, IPv6Address, IPv6Network, ip_network 

12from typing import Literal, Optional, Union 

13 

14from hypothesis.errors import InvalidArgument 

15from hypothesis.internal.validation import check_type 

16from hypothesis.strategies._internal.core import binary, sampled_from 

17from hypothesis.strategies._internal.numbers import integers 

18from hypothesis.strategies._internal.strategies import SearchStrategy 

19from hypothesis.strategies._internal.utils import defines_strategy 

20 

21# See https://www.iana.org/assignments/iana-ipv4-special-registry/ 

22SPECIAL_IPv4_RANGES = ( 

23 "0.0.0.0/8", 

24 "10.0.0.0/8", 

25 "100.64.0.0/10", 

26 "127.0.0.0/8", 

27 "169.254.0.0/16", 

28 "172.16.0.0/12", 

29 "192.0.0.0/24", 

30 "192.0.0.0/29", 

31 "192.0.0.8/32", 

32 "192.0.0.9/32", 

33 "192.0.0.10/32", 

34 "192.0.0.170/32", 

35 "192.0.0.171/32", 

36 "192.0.2.0/24", 

37 "192.31.196.0/24", 

38 "192.52.193.0/24", 

39 "192.88.99.0/24", 

40 "192.168.0.0/16", 

41 "192.175.48.0/24", 

42 "198.18.0.0/15", 

43 "198.51.100.0/24", 

44 "203.0.113.0/24", 

45 "240.0.0.0/4", 

46 "255.255.255.255/32", 

47) 

48# and https://www.iana.org/assignments/iana-ipv6-special-registry/ 

49SPECIAL_IPv6_RANGES = ( 

50 "::1/128", 

51 "::/128", 

52 "::ffff:0:0/96", 

53 "64:ff9b::/96", 

54 "64:ff9b:1::/48", 

55 "100::/64", 

56 "2001::/23", 

57 "2001::/32", 

58 "2001:1::1/128", 

59 "2001:1::2/128", 

60 "2001:2::/48", 

61 "2001:3::/32", 

62 "2001:4:112::/48", 

63 "2001:10::/28", 

64 "2001:20::/28", 

65 "2001:db8::/32", 

66 "2002::/16", 

67 "2620:4f:8000::/48", 

68 "fc00::/7", 

69 "fe80::/10", 

70) 

71 

72 

73@defines_strategy(force_reusable_values=True) 

74def ip_addresses( 

75 *, 

76 v: Optional[Literal[4, 6]] = None, 

77 network: Optional[Union[str, IPv4Network, IPv6Network]] = None, 

78) -> SearchStrategy[Union[IPv4Address, IPv6Address]]: 

79 r"""Generate IP addresses - ``v=4`` for :class:`~python:ipaddress.IPv4Address`\ es, 

80 ``v=6`` for :class:`~python:ipaddress.IPv6Address`\ es, or leave unspecified 

81 to allow both versions. 

82 

83 ``network`` may be an :class:`~python:ipaddress.IPv4Network` or 

84 :class:`~python:ipaddress.IPv6Network`, or a string representing a network such as 

85 ``"127.0.0.0/24"`` or ``"2001:db8::/32"``. As well as generating addresses within 

86 a particular routable network, this can be used to generate addresses from a 

87 reserved range listed in the 

88 `IANA <https://www.iana.org/assignments/iana-ipv4-special-registry/>`__ 

89 `registries <https://www.iana.org/assignments/iana-ipv6-special-registry/>`__. 

90 

91 If you pass both ``v`` and ``network``, they must be for the same version. 

92 """ 

93 if v is not None: 

94 check_type(int, v, "v") 

95 if v not in (4, 6): 

96 raise InvalidArgument(f"{v=}, but only v=4 or v=6 are valid") 

97 if network is None: 

98 # We use the reserved-address registries to boost the chance 

99 # of generating one of the various special types of address. 

100 four = binary(min_size=4, max_size=4).map(IPv4Address) | sampled_from( 

101 SPECIAL_IPv4_RANGES 

102 ).flatmap(lambda network: ip_addresses(network=network)) 

103 six = binary(min_size=16, max_size=16).map(IPv6Address) | sampled_from( 

104 SPECIAL_IPv6_RANGES 

105 ).flatmap(lambda network: ip_addresses(network=network)) 

106 if v == 4: 

107 return four 

108 if v == 6: 

109 return six 

110 return four | six 

111 if isinstance(network, str): 

112 network = ip_network(network) 

113 check_type((IPv4Network, IPv6Network), network, "network") 

114 assert isinstance(network, (IPv4Network, IPv6Network)) # for Mypy 

115 if v not in (None, network.version): 

116 raise InvalidArgument(f"{v=} is incompatible with {network=}") 

117 addr_type = IPv4Address if network.version == 4 else IPv6Address 

118 return integers(int(network[0]), int(network[-1])).map(addr_type) # type: ignore