Source code for fauxfactory.factories.internet
"""Methods related to generating internet related values."""
import random
import re
from fauxfactory.constants import SCHEMES, SUBDOMAINS, TLDS, VALID_NETMASKS
from fauxfactory.helpers import check_validation
from .choices import gen_choice
from .strings import gen_alpha
random.seed()
[docs]
def gen_domain(name=None, subdomain=None, tlds=None):
"""Generate a random domain name.
:param str name: Name for your host.
:param str subdomain: Name for the subdomain.
:param str tlds: Top Level Domain Server.
:returns: A random domain name.
:rtype: str
"""
# Generate a new name if needed
if name is None:
name = gen_alpha(8).lower()
# Obtain a random subdomain if needed
if subdomain is None:
subdomain = gen_choice(SUBDOMAINS)
# Obtain a random top level domain if needed
if tlds is None:
tlds = gen_choice(TLDS)
return f"{name}.{subdomain}.{tlds}"
[docs]
@check_validation
def gen_email(name=None, domain=None, tlds=None):
"""Generate a random email address.
:param str name: Email name.
:param str domain: Domain name.
:param str tlds: Top Level Domain Server.
:returns: An email address.
:rtype: str
"""
# Generate a new name if needed
if name is None:
name = gen_alpha(8)
# Obtain a random domain if needed
if domain is None:
domain = gen_choice(SUBDOMAINS)
# Obtain a random top level domain if needed
if tlds is None:
tlds = gen_choice(TLDS)
email = f"{name}@{domain}.{tlds}"
return email
[docs]
@check_validation
def gen_ipaddr(ip3=False, ipv6=False, prefix=()):
"""Generate a random IP address.
You can also specify an IP address prefix if you are interested in
local network address generation, etc.
:param bool ip3: Whether to generate a 3 or 4 group IP.
:param bool ipv6: Whether to generate IPv6 or IPv4
:param list prefix: A prefix to be used for an IP (e.g. [10, 0, 1]). It
must be an iterable with strings or integers. Can be left
unspecified or empty.
:returns: An IP address.
:rtype: str
:raises: ``ValueError`` if ``prefix`` would lead to no random fields at
all. This means the length that triggers the ``ValueError`` is 4 for
regular IPv4, 3 for IPv4 with ip3 and 8 for IPv6. It will be raised in
any case the prefix length reaches or exceeds those values.
"""
# Set the lengths of the randomly generated sections
if ipv6:
rng = 8
elif ip3:
rng = 3
else:
rng = 4
prefix = [str(field) for field in prefix]
# Prefix reduces number of random fields generated, so subtract the length
# of it from the rng to keep the IP address have correct number of fields
rng -= len(prefix)
if rng == 0:
raise ValueError(f"Prefix {prefix!r} would lead to no randomness at all")
if rng < 0:
raise ValueError(f"Prefix {prefix!r} is too long for this configuration")
if ipv6:
# StackOverflow.com questions: generate-random-ipv6-address
random_fields = [f"{random.randint(0, 2 ** 16 - 1):x}" for _ in range(rng)]
ipaddr = ":".join(prefix + random_fields)
else:
random_fields = [str(random.randrange(0, 255, 1)) for _ in range(rng)]
ipaddr = ".".join(prefix + random_fields)
if ip3:
ipaddr = ipaddr + ".0"
return ipaddr
[docs]
@check_validation
def gen_mac(delimiter=":", multicast=None, locally=None):
"""Generate a random MAC address.
For more information about how unicast or multicast and globally unique and
locally administered MAC addresses are generated check this link
https://en.wikipedia.org/wiki/MAC_address.
:param str delimiter: Valid MAC delimiter (e.g ':', '-').
:param bool multicast: Indicates if the generated MAC address should be
unicast or multicast. If no value is provided a random one will be
chosen.
:param bool locally: Indicates if the generated MAC address should be
globally unique or locally administered. If no value is provided a
random one will be chosen.
:returns: A random MAC address.
:rtype: str
"""
if delimiter not in [":", "-"]:
raise ValueError(f"Delimiter is not a valid option: {delimiter}")
if multicast is None:
multicast = bool(random.randint(0, 1))
if locally is None:
locally = bool(random.randint(0, 1))
first_octet = random.randint(0, 255)
if multicast:
# Ensure that the first least significant bit is 1
first_octet |= 0b00000001
else:
# Ensure that the first least significant bit is 0
first_octet &= 0b11111110
if locally:
# Ensure that the second least significant bit is 1
first_octet |= 0b00000010
else:
# Ensure that the second least significant bit is 0
first_octet &= 0b11111101
octets = [first_octet]
octets.extend(random.randint(0, 255) for _ in range(5))
mac = delimiter.join([f"{octet:02x}" for octet in octets])
return mac
[docs]
@check_validation
def gen_netmask(min_cidr=1, max_cidr=31):
"""Generate a random valid netmask.
For more info: http://www.iplocation.net/tools/netmask.php
:param int min_cidr: Inferior CIDR limit
:param int max_cidr: Superior CIDR limit
:returns: The netmask is chosen from
:data:`fauxfactory.constants.VALID_NETMASKS` respecting the CIDR range
:rtype: str
:raises: ``ValueError`` if ``min_cidr`` or ``max_cidr`` have an invalid
value. For example, ``max_cidr`` cannot be 33.
"""
if min_cidr < 0:
raise ValueError(f"min_cidr must be 0 or greater, but is {min_cidr}")
if max_cidr >= len(VALID_NETMASKS):
raise ValueError(
f"max_cidr must be less than {len(VALID_NETMASKS)}, " f"but is {max_cidr}"
)
return VALID_NETMASKS[random.randint(min_cidr, max_cidr)]
[docs]
@check_validation
def gen_url(scheme=None, subdomain=None, tlds=None):
"""Generate a random URL address.
:param str scheme: Either http, https or ftp.
:param str subdomain: A valid subdomain
:param str tlds: A qualified top level domain name (e.g. 'com', 'net')
:raises: ``ValueError`` if arguments are not valid.
:returns: A random URL address.
:rtype: str
"""
# Regex for subdomain names
subdomainator = re.compile(r"^[a-zA-Z0-9][-\w.~]*$")
# Regex for URL scheme
schemenator = re.compile(r"^(https?|ftp)$")
# Regex for TLDS
tldsnator = re.compile(r"^[a-zA-Z]{1,3}$")
if scheme:
if schemenator.match(scheme) is None:
raise ValueError(f"Protocol {scheme} is not valid.")
else:
scheme = gen_choice(SCHEMES)
if subdomain:
if subdomainator.match(subdomain) is None:
raise ValueError(f"Subdomain {subdomain} is invalid.")
else:
subdomain = gen_choice(SUBDOMAINS)
if tlds:
if tldsnator.match(tlds) is None:
raise ValueError(f"TLDS name {tlds} is invalid.")
else:
tlds = gen_choice(TLDS)
url = f"{scheme}://{subdomain}.{tlds}"
return url
__all__ = tuple(name for name in locals() if name.startswith("gen_"))
def __dir__():
return __all__