NOTICE: All information contained herein is, and remains
the property of TechnoCore Automate.
ObjRandom provides random number generation and unique code generation
utilities for the Axion platform. It supports both standard random (for
non-security purposes like load distribution) and cryptographically secure
random (for security purposes like token generation).
Inherits from: ObjSupervisor.Supervisor
Generate random integer between min_val and max_val (inclusive).
Parameters:
min_val - Minimum value (default 0)max_val - Maximum value (default 100)secure - Use cryptographically secure random (default False)Returns: Random integer
Example:
obj = ObjRandom()
value = obj.randint(0, 100) # Standard random
secure_value = obj.randint(0, 100, secure=True) # Crypto-secure
Generate random float between min_val and max_val.
Parameters:
min_val - Minimum value (default 0.0)max_val - Maximum value (default 1.0)secure - Use cryptographically secure random (default False)Returns: Random float
Example:
obj = ObjRandom()
percentage = obj.randfloat(0.0, 1.0)
price = obj.randfloat(10.0, 100.0)
Select random item from list.
Parameters:
items - List of items to choose fromsecure - Use cryptographically secure random (default False)Returns: Random item from list
Example:
obj = ObjRandom()
colors = ['red', 'green', 'blue']
color = obj.choice(colors)
Select random item with weighted probability.
Parameters:
items - List of items to choose fromweights - List of weights corresponding to itemsReturns: Randomly selected item based on weights
Example:
obj = ObjRandom()
bureaus = ['EXPERIAN', 'MYDATA', 'TRANSUNION']
weights = [70, 20, 10] # 70% Experian, 20% MyData, 10% TransUnion
selected = obj.weighted_choice(bureaus, weights)
Shuffle list in place.
Parameters:
items - List to shufflesecure - Use cryptographically secure random (default False)Returns: None (shuffles list in place)
Example:
obj = ObjRandom()
cards = ['A', 'K', 'Q', 'J']
obj.shuffle(cards)
Select k unique random items from list.
Parameters:
items - List to sample fromk - Number of items to selectsecure - Use cryptographically secure random (default False)Returns: List of k unique random items
Example:
obj = ObjRandom()
numbers = list(range(1, 50))
winners = obj.sample(numbers, 5) # Pick 5 unique numbers
Generate random code with specified characteristics.
Parameters:
prefix - Optional prefix for codelength - Length of random portion (default 8)charset - Character set: 'numeric', 'alpha', 'alphanumeric', 'hex'Returns: Generated code string
Example:
obj = ObjRandom()
voucher = obj.generate_code("PROMO", 8, "alphanumeric")
# Result: PROMO4X7B9K2L
Generate unique code and store in database.
Generates random codes and checks data_uniquenumber table for uniqueness.
Stores successful codes to prevent duplicates.
Parameters:
prefix - Optional prefix for codelength - Length of random portion (default 8)charset - Character set (default 'numeric')max_attempts - Maximum generation attempts (default 1000)Returns: Generated unique code, or None if max attempts reached
Database Table: data_uniquenumber
Example:
obj = ObjRandom()
unique_code = obj.generate_unique_code("DASH", 6, "numeric")
# Result: DASH123456 (guaranteed unique in database)
Generate batch of unique codes and store in database.
Parameters:
prefix - Optional prefix for codeslength - Length of random portioncount - Number of codes to generatecharset - Character set to useReturns: Number of codes successfully generated
Example:
obj = ObjRandom()
generated = obj.generate_batch("DASH", 6, 1000, "numeric")
print(f"Generated {generated}/1000 unique codes")
Set random seed for reproducible results.
Note: Only affects standard random, not secure random.
Parameters:
seed - Seed value for random number generatorExample:
obj = ObjRandom()
obj.set_seed(42)
# Subsequent calls will produce same sequence
Available charsets for code generation:
numeric - "0123456789"alpha - "ABCDEFGHIJKLMNOPQRSTUVWXYZ"alphanumeric - "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"hex - "0123456789ABCDEF"Use secure=True for:
Use standard random (default) for:
Example:
obj = ObjRandom()
# Security-sensitive: use secure=True
api_key = obj.generate_code("KEY", 32, "alphanumeric") # Always secure
# Load distribution: standard random is fine
bureau_value = obj.randint(0, 100, secure=False)
The generate_unique_code() and generate_batch() methods use the
data_uniquenumber table to track generated codes and ensure uniqueness.
Schema:
CREATE TABLE data_uniquenumber (
Uniquecode VARCHAR(255) PRIMARY KEY,
Created TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
ObjRandom provides persistent RDG (Random Distribution Group) assignment
functionality. Once an ID receives an RDG value, it remains consistent across
all lookups, ensuring predictable routing and distribution.
The def_random table defines RDG configurations for different packages and
use cases, including Time-To-Live (TTL) settings for automatic expiration.
Schema:
CREATE TABLE def_random (
Package VARCHAR(50) NOT NULL,
RDCode VARCHAR(50) NOT NULL,
PrimaryGuid VARCHAR(50) NOT NULL,
RDGFields INT DEFAULT 1,
RDG1_TTL_Hours INT DEFAULT 0,
RDG2_TTL_Hours INT DEFAULT 0,
RDG3_TTL_Hours INT DEFAULT 0,
RDG4_TTL_Hours INT DEFAULT 0,
RDG5_TTL_Hours INT DEFAULT 0,
Description TEXT,
Active CHAR(1) DEFAULT 'Y',
Created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
Updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (Package, RDCode),
INDEX idx_package_active (Package, Active)
) COMMENT='RDG configuration with TTL support. TTL=0 means indefinite.'
Columns:
Package - Package identifier (e.g., 'homechoice', 'fullhouse')RDCode - RDG code identifier (e.g., 'DEFAULT', 'BUREAU_ROUTING')PrimaryGuid - Name of primary key field in data_rdg_xxxx tableRDGFields - Number of RDG fields to create (RDG1, RDG2, RDG3, etc.)RDG1_TTL_Hours - TTL for RDG1 in hours (0 = permanent, >0 = expires)RDG2_TTL_Hours - TTL for RDG2 in hours (0 = permanent, >0 = expires)RDG3_TTL_Hours - TTL for RDG3 in hours (0 = permanent, >0 = expires)RDG4_TTL_Hours - TTL for RDG4 in hours (0 = permanent, >0 = expires)RDG5_TTL_Hours - TTL for RDG5 in hours (0 = permanent, >0 = expires)Description - Human-readable descriptionActive - 'Y'/'1' for active, 'N'/'0' for inactiveExample Configurations:
-- Permanent assignment (TTL=0, never expires)
INSERT INTO def_random (Package, RDCode, PrimaryGuid, RDGFields, RDG1_TTL_Hours, Description, Active)
VALUES ('homechoice', 'DEFAULT', 'idnumber', 1, 0, 'Default RDG - permanent', 'Y');
-- Bureau routing - permanent assignment
INSERT INTO def_random (Package, RDCode, PrimaryGuid, RDGFields, RDG1_TTL_Hours, RDG2_TTL_Hours, Description, Active)
VALUES ('homechoice', 'BUREAU_ROUTING', 'idnumber', 2, 0, 0, 'Bureau routing - permanent', 'Y');
-- 7-day promotional campaign (168 hours)
INSERT INTO def_random (Package, RDCode, PrimaryGuid, RDGFields, RDG1_TTL_Hours, Description, Active)
VALUES ('homechoice', 'PROMO_ROUTING', 'idnumber', 1, 168, 'Weekly promo - 7 day TTL', 'Y');
-- Monthly A/B test with quarterly cohort
INSERT INTO def_random (Package, RDCode, PrimaryGuid, RDGFields, RDG1_TTL_Hours, RDG2_TTL_Hours, Description, Active)
VALUES ('homechoice', 'AB_TEST', 'idnumber', 2, 720, 2160, 'Monthly test + quarterly cohort', 'Y');
Dynamic RDG storage tables are created based on the PrimaryGuid field
from def_random configuration. Each RDG field has a corresponding _Created
timestamp column for TTL tracking.
Table naming: data_rdg_{PrimaryGuid}
Schema (example for data_rdg_idnumber with 2 RDG fields):
CREATE TABLE data_rdg_idnumber (
idnumber VARCHAR(255) NOT NULL,
RDG1 INT DEFAULT NULL,
RDG1_Created TIMESTAMP NULL DEFAULT NULL, -- TTL tracking for RDG1
RDG2 INT DEFAULT NULL,
RDG2_Created TIMESTAMP NULL DEFAULT NULL, -- TTL tracking for RDG2
Created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
Updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (idnumber)
) COMMENT='RDG storage with TTL support'
Column Pairs:
RDG1, RDG2, etc.) has a corresponding timestamp columnRDG1_Created tracks when RDG1 value was generated/regenerated_Created timestamp is stored but not checkedGet RDG configuration from def_random table, including TTL settings.
Parameters:
rdg_code - RDG code identifier (default 'DEFAULT')package - Package name (uses current package if None)Returns: Configuration dict with keys:
PrimaryGuid - Primary key field nameRDGFields - Number of RDG fieldsActive - Active statusRDG1_TTL_Hours - TTL for RDG1 (0 = permanent)RDG2_TTL_Hours - TTL for RDG2 (0 = permanent)RDG3_TTL_Hours - TTL for RDG3 (0 = permanent)RDG4_TTL_Hours - TTL for RDG4 (0 = permanent)RDG5_TTL_Hours - TTL for RDG5 (0 = permanent)Returns None if configuration not found.
Example:
obj = ObjRandom()
config = obj.get_rdg_config('PROMO_ROUTING')
print(f"Primary key: {config['PrimaryGuid']}")
print(f"RDG fields: {config['RDGFields']}")
print(f"RDG1 TTL: {config['RDG1_TTL_Hours']} hours")
if config['RDG1_TTL_Hours'] == 0:
print("RDG1 is permanent (never expires)")
else:
print(f"RDG1 expires after {config['RDG1_TTL_Hours']} hours")
Get RDG table name for given configuration.
Parameters:
rdg_code - RDG code identifier (default 'DEFAULT')package - Package name (uses current package if None)Returns: Table name string (e.g., 'data_rdg_idnumber') or None
Example:
obj = ObjRandom()
table_name = obj.get_rdg_table_name('DEFAULT')
# Result: 'data_rdg_idnumber'
Create RDG table based on configuration. Creates table with RDG1, RDG2, ...
RDGn columns based on RDGFields setting. Each RDG column has a corresponding
_Created timestamp column for TTL support.
Parameters:
rdg_code - RDG code identifier (default 'DEFAULT')package - Package name (uses current package if None)Returns: True if created/exists, False on error
Table Structure:
For RDGFields=2, creates:
- RDG1 INT
- RDG1_Created TIMESTAMP (for TTL tracking)
- RDG2 INT
- RDG2_Created TIMESTAMP (for TTL tracking)
Example:
obj = ObjRandom()
result = obj.create_rdg_table('PROMO_ROUTING')
if result:
print("RDG table ready with TTL support")
Lookup or create RDG value for given ID with Time-To-Live (TTL) support.
Checks if RDG exists and is still valid based on TTL configuration. If expired
or doesn't exist, generates new random value (0-100) and stores it with timestamp.
TTL Behavior:
Expiration Logic:
Parameters:
id_value - ID to lookup (e.g., ID number, account number)rdg_code - RDG code identifier (default 'DEFAULT')rdg_number - RDG field name (default 'RDG1')package - Package name (uses current package if None)Returns: RDG value (0-100) or None on error
Example 1: Permanent RDG (TTL=0)
obj = ObjRandom()
# First lookup: creates new RDG value
rdg1 = obj.lookup_rdg('8901015800082', 'DEFAULT', 'RDG1')
print(f"RDG1: {rdg1}") # Result: RDG1: 45
# Subsequent lookups: always returns same value (permanent)
rdg1 = obj.lookup_rdg('8901015800082', 'DEFAULT', 'RDG1')
print(f"RDG1: {rdg1}") # Result: RDG1: 45 (same forever)
Example 2: Temporary RDG with TTL (7 days = 168 hours)
obj = ObjRandom()
# Hour 0: First lookup creates new RDG
rdg1 = obj.lookup_rdg('8901015800082', 'PROMO_ROUTING', 'RDG1')
print(f"RDG1: {rdg1}") # Result: RDG1: 45
# Hour 100: Within TTL, returns same value
rdg1 = obj.lookup_rdg('8901015800082', 'PROMO_ROUTING', 'RDG1')
print(f"RDG1: {rdg1}") # Result: RDG1: 45 (age: 100h < 168h TTL)
# Hour 169: Expired, generates new value
rdg1 = obj.lookup_rdg('8901015800082', 'PROMO_ROUTING', 'RDG1')
print(f"RDG1: {rdg1}") # Result: RDG1: 78 (regenerated, age > TTL)
Example 3: Multiple RDG fields with different TTLs
obj = ObjRandom()
# RDG1 with 30-day TTL, RDG2 with 90-day TTL
rdg1 = obj.lookup_rdg('8901015800082', 'AB_TEST', 'RDG1') # 30-day TTL
rdg2 = obj.lookup_rdg('8901015800082', 'AB_TEST', 'RDG2') # 90-day TTL
# After 31 days: RDG1 expired and regenerated, RDG2 still valid
Alias for lookup_rdg() for convenience.
Example:
obj = ObjRandom()
rdg = obj.get_rdg('8901015800082') # Same as lookup_rdg()
# Generate batch of 1000 codes for TECHNOCORE company
python factory.core/ObjRandom.py generate TECHNOCORE
# Run random generation test suite
python factory.core/ObjRandom.py test
# Create RDG table for specific configuration
python factory.core/ObjRandom.py create-rdg DEFAULT
python factory.core/ObjRandom.py create-rdg BUREAU_ROUTING
# Lookup RDG value for ID
python factory.core/ObjRandom.py lookup-rdg 8901015800082
python factory.core/ObjRandom.py lookup-rdg 8901015800082 DEFAULT RDG1
python factory.core/ObjRandom.py lookup-rdg 8901015800082 BUREAU_ROUTING RDG2
# Run RDG functionality test
python factory.core/ObjRandom.py test-rdg
Random generation test:
Testing ObjRandom...
Random int (0-100): 42
Random float (0-1): 0.7234
Random choice: B
Weighted choice: A
Generated code: TEST4X7B9K2L
Secure random int: 89
RDG functionality test:
Testing RDG functionality...
Create table: Success
Lookup RDG values for test IDs:
8901015800082: RDG1=45
9001015800083: RDG1=78
8501015800084: RDG1=23
Lookup same IDs again (should return same values):
8901015800082: RDG1=45
9001015800083: RDG1=78
8501015800084: RDG1=23
Simple random-based routing that changes on each call:
from ObjRandom import ObjRandom
class BureauRouter:
def __init__(self, DB=0):
self.random = ObjRandom(DB)
def select_bureau_by_rdg(self, strategies):
rdg_value = self.random.randint(0, 100)
for strategy in strategies:
if strategy["RDG_Start"] <= rdg_value <= strategy["RDG_End"]:
return strategy
return None
Persistent routing that ensures the same ID always goes to the same bureau:
from ObjRandom import ObjRandom
class BureauRouter:
def __init__(self, DB=0):
self.random = ObjRandom(DB)
def select_bureau_by_persistent_rdg(self, id_number, strategies):
"""
Route based on persistent RDG value for ID number.
Same ID number always routes to same bureau.
"""
# Lookup persistent RDG for this ID number
rdg_value = self.random.lookup_rdg(
id_number,
rdg_code='BUREAU_ROUTING',
rdg_number='RDG1'
)
if rdg_value is None:
return None
# Select bureau based on RDG value
for strategy in strategies:
if strategy["RDG_Start"] <= rdg_value <= strategy["RDG_End"]:
return strategy
return None
def route_with_failover(self, id_number):
"""
Route with primary and failover bureau using RDG1 and RDG2.
"""
# Get both RDG values for this ID
rdg1 = self.random.lookup_rdg(
id_number,
'BUREAU_ROUTING',
'RDG1'
)
rdg2 = self.random.lookup_rdg(
id_number,
'BUREAU_ROUTING',
'RDG2'
)
# Select primary bureau based on RDG1
primary_bureau = self.select_bureau(rdg1, self.primary_strategies)
# Select failover bureau based on RDG2
failover_bureau = self.select_bureau(rdg2, self.failover_strategies)
return {
'primary': primary_bureau,
'failover': failover_bureau
}
# Example usage
router = BureauRouter()
# Setup configuration (done once)
router.random.create_rdg_table('BUREAU_ROUTING')
# Route requests - same ID always goes to same bureau
strategies = [
{'BureauCode': 'EXPERIAN', 'RDG_Start': 0, 'RDG_End': 60},
{'BureauCode': 'MYDATA', 'RDG_Start': 61, 'RDG_End': 100}
]
result1 = router.select_bureau_by_persistent_rdg('8901015800082', strategies)
# ID 8901015800082 gets RDG1=45, routes to EXPERIAN
result2 = router.select_bureau_by_persistent_rdg('8901015800082', strategies)
# Same ID still routes to EXPERIAN (RDG1 still =45)
result3 = router.select_bureau_by_persistent_rdg('9001015800083', strategies)
# Different ID gets RDG1=78, routes to MYDATA
obj = ObjRandom()
features = ['feature_a', 'feature_b', 'control']
weights = [10, 10, 80] # 10% A, 10% B, 80% control
selected_feature = obj.weighted_choice(features, weights)
obj = ObjRandom()
for customer in customers:
voucher = obj.generate_unique_code("PROMO2026", 8, "alphanumeric")
if voucher:
customer.assign_voucher(voucher)
random - Python standard library (non-cryptographic)secrets - Python standard library (cryptographic)ObjSupervisor - Axion base class with database accessfactory.core/ObjRandom.py
Part of factory.core, compiled with Cython for performance:
python factory.deploy/ObjCompile.py service core
ObjServiceBureauRouter.py - Uses ObjRandom for load distributionfactory.core/ObjSupervisor.py - Parent classfactory.core/ObjData.py - Database access methods