algopy/faker.py
import os
import random
import string
import uuid
from datetime import datetime, timedelta
class Faker:
class Misc:
@classmethod
def __init__(cls, extra_words: list = None):
"""
Initialize the Misc class with optional extra words for random text generation.
:param extra_words: List of additional words to include in the random text generation.
"""
cls.words = [
"Lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing", "elit", "sed", "do", "eiusmod",
"tempor", "incididunt", "ut", "labore", "et", "dolore", "magna", "aliqua", "Ut", "enim", "ad", "minim",
"veniam", "quis", "nostrud", "exercitation", "ullamco", "laboris", "nisi", "ut", "aliquip", "ex", "ea",
"commodo", "consequat", "Duis", "aute", "irure", "dolor", "in", "reprehenderit", "in", "voluptate",
"velit", "esse", "cillum", "dolore", "eu", "fugiat", "nulla", "pariatur", "Excepteur", "sint",
"occaecat", "cupidatat", "non", "proident", "sunt", "in", "culpa", "qui", "officia", "deserunt",
"mollit", "anim", "id", "est", "laborum"
]
if extra_words:
cls.words.extend(extra_words)
@staticmethod
def generate_barcode(amount: int = 1, length: int = 12) -> list[str]:
"""
Generate a list of random barcodes.
:param amount: Number of barcodes to generate.
:param length: Length of each barcode.
:return: List of generated barcodes.
"""
return [''.join(random.choices(string.digits, k=length)) for _ in range(amount)]
@staticmethod
def generate_uuid(amount: int = 1, version: int = 4, namespace: uuid.UUID = uuid.uuid1(),
name: str = os.name) -> list[str]:
"""
Generate a list of UUIDs.
:param amount: Number of UUIDs to generate.
:param version: Version of the UUID to generate (1, 3, 4, or 5).
:param namespace: Namespace for UUID versions 3 and 5.
:param name: Name for UUID versions 3 and 5.
:return: List of generated UUIDs.
:raises ValueError: If an invalid UUID version is provided or required arguments are missing.
"""
if version not in [1, 3, 4, 5]:
raise ValueError("Invalid UUID version. Use 1, 3, 4, or 5.")
if version in [3, 5] and (namespace is None or name is None):
raise ValueError(f"UUID version {version} requires 'namespace' and 'name' arguments")
uuid_func = {
1: uuid.uuid1,
3: lambda: uuid.uuid3(namespace, name),
4: uuid.uuid4,
5: lambda: uuid.uuid5(namespace, name)
}.get(version)
if uuid_func is None:
raise ValueError(f"Invalid UUID version: {version}")
return [str(uuid_func()) for _ in range(amount)]
@classmethod
def generate_random_text(cls, amount: int = 1, length: int = 100) -> list[str]:
"""
Generate a list of random text strings.
:param amount: Number of text strings to generate.
:param length: Number of words in each text string.
:return: List of generated random text strings.
"""
if not hasattr(cls, 'words'):
cls.__init__()
return [' '.join(random.choices(cls.words, k=length)) for _ in range(amount)]
class Financial:
@staticmethod
def __luhn_checksum(card_number: str) -> int:
"""
Calculate the Luhn checksum for a card number.
:param card_number: Card number to calculate the checksum for.
:return: Luhn checksum.
"""
def digits_of(n):
return [int(d) for d in str(n)]
digits = digits_of(card_number)
odd_digits = digits[-1::-2]
even_digits = digits[-2::-2]
checksum = sum(odd_digits)
for d in even_digits:
checksum += sum(digits_of(d * 2))
return checksum % 10
@classmethod
def __generate_compliant_number(cls, length: int) -> str:
"""
Generate a Luhn-compliant card number of a specified length.
:param length: Length of the card number to generate.
:return: Generated Luhn-compliant card number.
"""
number = ''.join(random.choices(string.digits, k=length - 1))
checksum = cls.__luhn_checksum(number + '0')
check_digit = (10 - checksum) % 10
return number + str(check_digit)
@classmethod
def credit_card(cls, amount: int = 1) -> list[dict[str, str]]:
"""
Generate a list of random credit card details.
:param amount: Number of credit card details to generate.
:return: List of generated credit card details.
"""
credit_cards = []
for _ in range(amount):
credit_card_number = cls.__generate_compliant_number(16)
cvv = ''.join(random.choices(string.digits, k=3))
expiration_date = f"{random.randint(1, 12):02d}/{random.randint(22, 30):02d}"
credit_cards.append({
"card_number": credit_card_number,
"cvv": cvv,
"expiration_date": expiration_date
})
return credit_cards
@staticmethod
def bank_account(amount: int = 1) -> list[dict[str, str]]:
"""
Generate a list of random bank account details.
:param amount: Number of bank account details to generate.
:return: List of generated bank account details.
"""
bank_accounts = []
for _ in range(amount):
bank_account_number = ''.join(random.choices(string.digits, k=12))
bank_routing_number = ''.join(random.choices(string.digits, k=8))
bank_routing_number += str(
(10 - sum(int(digit) for digit in bank_routing_number) % 10) % 10) # Check digit
bank_accounts.append({
"account_number": bank_account_number,
"routing_number": bank_routing_number
})
return bank_accounts
class Personal:
@classmethod
def __init__(cls, extra_data: dict = None):
"""
Initialize the Personal class with optional extra data for name, address, and email generation.
:param extra_data: Dictionary containing additional data for first names, last names, cities, countries, street names, and domains.
"""
cls.first_names = ["John", "Jane", "Alice", "Bob", "Charlie", "David", "Eve", "Frank", "Grace", "Hank"]
cls.last_names = ["Doe", "Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia", "Miller", "Davis", "Martinez"]
cls.cities = ["New York", "Los Angeles", "Chicago", "Houston", "Phoenix", "Philadelphia", "San Antonio", "San Diego", "Dallas", "San Jose"]
cls.countries = ["USA", "Canada", "Mexico", "UK", "Germany", "France", "Italy", "Spain", "Australia", "Japan"]
cls.street_names = ["Main", "Broadway", "Market", "Elm", "Maple", "Oak", "Pine", "Cedar", "Birch", "Walnut"]
cls.domains = ["example.com", "test.com", "demo.com", "fake.com", "sample.com", "mock.com", "dummy.com", "faux.com", "simulated.com", "placeholder.com"]
if extra_data:
cls.first_names.extend(extra_data.get("extra_first_names", []))
cls.last_names.extend(extra_data.get("extra_last_names", []))
cls.cities.extend(extra_data.get("extra_cities", []))
cls.countries.extend(extra_data.get("extra_countries", []))
cls.street_names.extend(extra_data.get("extra_street_names", []))
cls.domains.extend(extra_data.get("extra_domains", []))
@classmethod
def name(cls, format: str = None, amount: int = 1) -> list[str]:
"""
Generate a list of random names.
Format string can contain {first_name} and {last_name} placeholders.
Example format: "{first_name} {last_name}".
:param format: Optional format string for the names, using {first_name} and {last_name} as placeholders.
:param amount: Number of names to generate.
:return: List of generated names.
"""
return [format.replace("{first_name}", random.choice(cls.first_names)).replace("{last_name}", random.choice(
cls.last_names)) if format else f"{random.choice(cls.first_names)} {random.choice(cls.last_names)}" for
_
in range(amount)]
@classmethod
def address(cls, format: str = None, amount: int = 1) -> list[str]:
"""
Generate a list of random addresses.
Format string can contain {street_address}, {city}, {country}, and {postal_code} placeholders.
Example format: "{street_address}, {city}, {country} {postal_code}".
:param format: Optional format string for the addresses, using {street_address}, {city}, {country}, and {postal_code} as placeholders.
:param amount: Number of addresses to generate.
:return: List of generated addresses.
"""
if not hasattr(cls, 'street_names'):
cls.__init__()
addresses = []
for _ in range(amount):
address = cls.__helper_address()
if format:
formatted_address = format
for key, value in address.items():
formatted_address = formatted_address.replace(f"{{{key}}}", value)
addresses.append(formatted_address)
else:
addresses.append(address)
return addresses
@classmethod
def __helper_address(cls):
address = {
"street_address": f"{random.randint(1, 9999)} {random.choice(cls.street_names)} St",
"city": random.choice(cls.cities),
"country": random.choice(cls.countries),
"postal_code": f"{random.randint(10000, 99999)}"
}
return address
@staticmethod
def phone_number(format: str = None, amount: int = 1) -> list[str]:
"""
Generate a list of random phone numbers.
Format string can contain {phone_number} as a placeholder.
Example format: "John's phone number is {phone_number}".
:param format: Optional format string for the phone numbers, using {phone_number} as a placeholder.
:param amount: Number of phone numbers to generate.
:return: List of generated phone numbers.
"""
return [format.replace("{phone_number}",
f"{random.randint(100, 999)}-{random.randint(100, 999)}-{random.randint(1000, 9999)}") if format else f"{random.randint(100, 999)}-{random.randint(100, 999)}-{random.randint(1000, 9999)}"
for _ in range(amount)]
@classmethod
def email(cls, format: str = None, amount: int = 1) -> list[str]:
"""
Generate a list of random email addresses.
Format string can contain {email} as a placeholder.
Example format: "John's email is {email}"
:param format: Optional format string for the email addresses, using {email} as a placeholder.
:param amount: Number of email addresses to generate.
:return: List of generated email addresses.
"""
if not hasattr(cls, 'first_names') or not hasattr(cls, 'last_names') or not hasattr(cls, 'domains'):
cls.__init__()
return [format.replace("{email}",
f"{random.choice(cls.first_names).lower()}.{random.choice(cls.last_names).lower()}@{random.choice(cls.domains)}") if format else f"{random.choice(cls.first_names).lower()}.{random.choice(cls.last_names).lower()}@{random.choice(cls.domains)}"
for _ in range(amount)]
@staticmethod
def date(format: str = None, amount: int = 1) -> list[str]:
"""
Generate a list of random dates.
Format string should be in the strftime format.
Example format: "%Y-%m-%d".
:param format: Optional format string for the dates.
:param amount: Number of dates to generate.
:return: List of generated dates.
"""
dates = []
for _ in range(amount):
start_date = datetime.now()
end_date = start_date + timedelta(days=365)
date = start_date + (end_date - start_date) * random.random()
dates.append(date.strftime(format) if format else date.strftime("%Y-%m-%d"))
return dates
class Business:
@classmethod
def __init__(cls, extra_company_names: list = None, extra_job_titles: list = None):
"""
Initialize the Business class with optional extra data for company names and job titles.
:param extra_company_names: List of additional company names.
:param extra_job_titles: List of additional job titles.
"""
cls.company_names = ["TechCorp", "InnovateX", "AlphaSolutions", "BetaWorks", "GammaEnterprises"]
cls.job_titles = ["Software Engineer", "Data Scientist", "Product Manager", "Designer", "QA Engineer"]
if extra_company_names:
cls.company_names.extend(extra_company_names)
if extra_job_titles:
cls.job_titles.extend(extra_job_titles)
@classmethod
def company_name(cls, amount: int = 1) -> list[str]:
"""
Generate a list of random company names.
:param amount: Number of company names to generate.
:return: List of generated company names.
"""
if not hasattr(cls, 'company_names'):
cls.__init__()
return [str(random.choice(cls.company_names)) for _ in range(amount)]
@classmethod
def job_title(cls, amount: int = 1) -> list[str]:
"""
Generate a list of random job titles.
:param amount: Number of job titles to generate.
:return: List of generated job titles.
"""
return [str(random.choice(cls.job_titles)) for _ in range(amount)]
@staticmethod
def employee_id(amount: int = 1, characters_to_use: str = (string.ascii_uppercase + string.digits)) -> list[str]:
"""
Generate a list of random employee IDs.
:param amount: Number of employee IDs to generate.
:param characters_to_use: Characters to use for generating the employee IDs.
:return: List of generated employee IDs.
"""
return [''.join(random.choices(characters_to_use, k=8)) for _ in range(amount)]
class Product:
@classmethod
def __init__(cls, extra_product_names: list = None, extra_product_categories: list = None):
"""
Initialize the Product class with optional extra data for product names and categories.
:param extra_product_names: List of additional product names.
:param extra_product_categories: List of additional product categories.
"""
cls.product_names = ["Widget", "Gadget", "Thingamajig", "Doodad", "Gizmo"]
cls.product_categories = ["Electronics", "Home", "Toys", "Clothing", "Sports"]
if extra_product_names:
cls.product_names.extend(extra_product_names)
if extra_product_categories:
cls.product_categories.extend(extra_product_categories)
@classmethod
def generate_product_name(cls, amount: int = 1) -> list[str]:
"""
Generate a list of random product names.
:param amount: Number of product names to generate.
:return: List of generated product names.
"""
if not hasattr(cls, 'product_names'):
cls.__init__()
return [str(random.choice(cls.product_names)) for _ in range(amount)]
@classmethod
def generate_product_category(cls, amount: int = 1) -> list[str]:
"""
Generate a list of random product categories.
:param amount: Number of product categories to generate.
:return: List of generated product categories.
"""
if not hasattr(cls, 'product_categories'):
cls.__init__()
return [str(random.choice(cls.product_categories)) for _ in range(amount)]
@staticmethod
def generate_price(amount: int = 1, min_price: float = 1.0, max_price: float = 100.0) -> list[float]:
"""
Generate a list of random prices within a specified range.
:param amount: Number of prices to generate.
:param min_price: Minimum price value.
:param max_price: Maximum price value.
:return: List of generated prices.
"""
return [round(random.uniform(min_price, max_price), 2) for _ in range(amount)]
class Internet:
"""
A class to generate various types of internet-related fake data.
"""
@classmethod
def __init__(cls, extra_domains: list = None):
"""
Initialize the Internet class with optional extra domains.
:param extra_domains: List of additional domains to include.
"""
cls.domains = ["example.com", "test.com", "sample.org", "demo.net", "fake.com",
"mock.org", "example.net", "test.org", "sample.com", "demo.net"]
if extra_domains:
cls.domains.extend(extra_domains)
@staticmethod
def generate_username(amount: int = 1, size: int = 8,
charset: str = string.ascii_letters) -> list[str]:
"""
Generate a list of random usernames.
:param amount: Number of usernames to generate.
:param size: Length of each username.
:param charset: Characters to use for generating the usernames.
:return: List of generated usernames.
"""
return [''.join(random.choices(charset, k=size)) for _ in range(amount)]
@staticmethod
def generate_password(amount: int = 1, size: int = 12,
charset: str = (string.ascii_letters + string.digits + string.punctuation)) -> list[str]:
"""
Generate a list of random passwords.
:param amount: Number of passwords to generate.
:param size: Length of each password.
:param charset: Characters to use for generating the passwords.
:return: List of generated passwords.
"""
return [''.join(random.choices(charset, k=size)) for _ in range(amount)]
@staticmethod
def generate_ip_address(amount: int = 1, version=4) -> list[str]:
"""
Generate a list of random IP addresses.
:param amount: Number of IP addresses to generate.
:param version: IP version (4 or 6).
:return: List of generated IP addresses.
"""
ip_addresses = []
for _ in range(amount):
if version == 4:
ip_addresses.append('.'.join(str(random.randint(0, 255)) for _ in range(4)))
elif version == 6:
ip_addresses.append(':'.join(''.join(random.choices('0123456789abcdef', k=4)) for _ in range(8)))
else:
raise ValueError("Invalid IP version. Use 4 or 6.")
return ip_addresses
@classmethod
def generate_url(cls, amount: int = 1, format: str = None) -> list[str]:
"""
Generate a list of random URLs.
Format string can contain {domain} and {path} placeholders.
Example format: "https://{domain}/{path}".
:param amount: Number of URLs to generate.
:param format: Optional format string for the URLs, using {domain} and {path} as placeholders.
:return: List of generated URLs.
"""
if not hasattr(cls, 'domains'):
cls.__init__()
urls = []
for _ in range(amount):
domain = random.choice(cls.domains)
path = ''.join(random.choices(string.ascii_letters + string.digits, k=10))
url = f"https://{domain}/{path}"
if format:
url = format.replace("{domain}", domain).replace("{path}", path)
urls.append(url)
return urls