A combinatorial string generation library that creates all possible combinations from templates with variable elements
Project description
spintax-py
A combinatorial string generation library that creates all possible combinations from templates with variable elements.
This is a Python implementation of the spintax JavaScript library, providing identical functionality for generating string variations using pattern syntax.
Requirements
- Python 3.6+ (no external runtime dependencies)
- Works anywhere Python runs: scripts, tests, data pipelines, CLIs
Installation
Install from PyPI:
pip install spintaxpy
Or install from source:
pip install .
Quickstart
from spintaxpy import parse, count, choose
print(count("Hello {world|people}!")) # 2 combinations
print(list(parse("Item {1,3}"))) # ['Item 1', 'Item 2', 'Item 3']
pick = choose("{small|large} {box|circle}")
print(pick()) # Random choice, e.g., "large circle"
print(pick(0, 1)) # Deterministic: "small circle"
Basic Usage
from spintaxpy import parse
# Basic usage with choices
variations = parse("Hello, {world|friend|universe}!")
# Iterate through all combinations
for variation in variations:
print(variation)
# Output:
# Hello, world!
# Hello, friend!
# Hello, universe!
# With numerical ranges
counts = parse("Count: {1,5}")
# Generates: "Count: 1", "Count: 2", "Count: 3", "Count: 4", "Count: 5"
# Multiple variables
products = parse("{Product|Service} #{1,3} ({Standard|Premium})")
# Generates all combinations: "Product #1 (Standard)", "Product #1 (Premium)", etc.
# Back references
associations = parse("The {blue|straw|rasp}berries taste like {$0}berries")
# Generates: "The blueberries taste like blueberries",
# "The strawberries taste like strawberries",
# "The raspberries taste like raspberries"
Key Features
- String pattern parsing: Create string variations using intuitive pattern syntax
- Combinatorial expansion: Generate all possible combinations of variable elements
- Memory-efficient: Uses Python generators for lazy evaluation
- Multiple variable types: Choose from predefined options or numerical ranges
- Back references: Reference previously selected choices within the same template
Custom delimiters and separators
All delimiters are configurable so you can embed patterns inside other markup:
# Use [ ] instead of { }
list(parse("Choose [red|blue]", pattern_start="[", pattern_end="]"))
# Change choice/range separators
list(parse("{A;B;C}", separator_choices=";"))
list(parse("{0:10:2}", separator_range=":"))
# Change back reference marker
list(parse("{left|right} and {#0}", back_reference_marker="#"))
Pattern Syntax
Choices
Define choices with the pipe (|) separator:
parse("Color: {red|green|blue}")
# Generates: "Color: red", "Color: green", "Color: blue"
Ranges
Define ranges with comma-separated numbers:
parse("Value: {1,5}")
# Generates: "Value: 1", "Value: 2", "Value: 3", "Value: 4", "Value: 5"
# With step value
parse("Value: {0,10,2}")
# Generates: "Value: 0", "Value: 2", "Value: 4", "Value: 6", "Value: 8", "Value: 10"
Pattern Combinations
Multiple patterns in a template will generate all possible combinations:
parse("{small|large} {box|circle} in {red|blue}")
# Generates 8 combinations of size, shape and color
Back References
Reference previous choices using {$n} where n is the 0-based index:
parse("The {blue|straw|rasp}berries taste like {$0}berries")
# $0 refers to the first choice (blue|straw|rasp)
Whitespace Handling
- In range patterns (containing numbers and commas), all whitespace is ignored
{1,5}is the same as{ 1, 5 }
- In choices patterns (with
|separators), whitespace is preserved as part of the option{option1|option2}is different from{option1 |option2}- In the second case, the first option is "option1 " (with a trailing space)
Advanced Examples
URL Generation
parse("https://example.com/{products|users}/{1,5}")
# Generates:
# https://example.com/products/1
# https://example.com/products/2
# ...
# https://example.com/users/5
API Testing
parse("/api/v{1,3}/{users|items}/{1,100,10}")
# Generates:
# /api/v1/users/1
# /api/v1/users/11
# ...
# /api/v3/items/91
Configuration Generation
parse('{"timeout": {1000,5000,1000}, "retries": {1,3}, "mode": "{strict|lenient}"}')
# Generates valid JSON strings with all combinations of parameters
Iteration Order
When multiple patterns are in a template, combinations are generated by iterating through the rightmost pattern first (inner loop), then the next one to the left, and so on:
list(parse("The color is {red|green|blue}. The letter is {A|B|C}"))
# Produces:
# The color is red. The letter is A
# The color is red. The letter is B
# The color is red. The letter is C
# The color is green. The letter is A
# The color is green. The letter is B
# The color is green. The letter is C
# The color is blue. The letter is A
# The color is blue. The letter is B
# The color is blue. The letter is C
API Reference
parse(template, **options)
Parses a template string with special patterns and returns a generator.
Parameters:
template(str): Template string with{...}patternspattern_start(str, optional): Pattern start delimiter (default:'{')pattern_end(str, optional): Pattern end delimiter (default:'}')separator_range(str, optional): Separator for range patterns (default:',')separator_choices(str, optional): Separator for choices patterns (default:'|')back_reference_marker(str, optional): Marker for back references (default:'$')
Returns: Iterator of all pattern combinations
Example:
for result in parse('Count: {1,5}'):
print(result)
count(template, **options)
Counts the number of combinations for a given string template.
Parameters: Same as parse()
Returns: Total number of combinations (int)
Example:
from spintaxpy import count
count("Hello!") # 1
count("Hello {world|people|nurse}!") # 3
count("{small|large} {box|circle}") # 4
choose(template, **options)
Creates a function that returns a single combination (random or by index).
Parameters: Same as parse()
Returns: Function that accepts indices and returns a single combination
Example:
from spintaxpy import choose
picker = choose("The {red|blue|green} {box|circle}")
picker() # Random combination like "The red box"
picker(0, 1) # Specific combination "The red circle"
picker(2, 0) # "The green box"
For repeatable results, pass explicit indices as shown above or set `random.seed(...)` before calling `picker()` without arguments. Seeding is handy in tests and docs: it makes successive random calls return the same sequence every time your process starts.
```python
import random
from spintaxpy import choose
picker = choose("{alpha|beta} {cat|dog}")
random.seed(42) # Fix the RNG state
print(picker()) # Always "beta dog" with this seed
print(picker()) # Always "alpha dog" with this seed
random.seed(42) # Reset seed -> same sequence again
print(picker()) # "beta dog" (matches first call)
### `spintax_range(start, end, step=1, include_end=True)`
Creates a generator that yields numbers within a specified range.
**Parameters:**
- `start` (float): Starting value (inclusive)
- `end` (float): Ending value (inclusive)
- `step` (float, optional): Increment between values (default: 1)
- `include_end` (bool, optional): Always include the end value (default: True)
**Returns:** RangeGenerator instance
**Example:**
```python
from spintaxpy import spintax_range
list(spintax_range(1, 5)) # [1, 2, 3, 4, 5]
list(spintax_range(0, 10, 3, True)) # [0, 3, 6, 9, 10]
Performance Considerations
Combinatorial Explosion
Be cautious when creating templates with many variable parts, as the number of combinations can grow exponentially:
- 3 variables with 4 options each: 4³ = 64 combinations
- 5 variables with 4 options each: 4⁵ = 1,024 combinations
- 10 variables with 4 options each: 4¹⁰ = 1,048,576 combinations
Processing Large Result Sets
When dealing with extremely large sets of combinations, use the generator directly instead of converting to a list:
# Good - processes one at a time
for combination in parse("..."):
process(combination)
# Bad - loads all into memory
all_combinations = list(parse("..."))
Best Practices
- Limit Pattern Count: Keep the number of variable patterns reasonable to avoid combinatorial explosion
- Use Meaningful Options: Create patterns that produce meaningful variations
- Process Lazily: Use the generator directly when dealing with large result sets
- Test First: Use
count()to check the number of combinations before generating them all
Examples
from spintaxpy import parse, count, choose
# Example 1: Simple greeting variations
greetings = list(parse("Hello, {world|friend|universe}!"))
print(greetings)
# ['Hello, world!', 'Hello, friend!', 'Hello, universe!']
# Example 2: Check combination count first
template = "{small|medium|large} {red|blue|green} {box|circle|triangle}"
print(f"This will generate {count(template)} combinations")
# This will generate 27 combinations
# Example 3: Generate specific combination
picker = choose("Size: {S|M|L|XL}, Color: {Red|Blue|Green}")
print(picker(1, 2)) # Size: M, Color: Green
# Example 4: URL variations for testing
urls = parse("https://api.example.com/v{1,3}/{users|products|orders}")
for url in urls:
print(url)
# https://api.example.com/v1/users
# https://api.example.com/v1/products
# https://api.example.com/v1/orders
# ...
# Example 5: Back references for consistency
sentences = list(parse("I {love|hate} this. Yes, I really {$0} it!"))
print(sentences)
# ['I love this. Yes, I really love it!', 'I hate this. Yes, I really hate it!']
Comparison with JavaScript Version
This Python implementation provides identical functionality to the original JavaScript spintax library. The main differences are:
- Uses Python generators instead of JavaScript iterators
- Function names follow Python conventions (e.g.,
spintax_rangeinstead of justrangeto avoid conflicts) - Uses keyword arguments for options instead of object parameters
- The
compiletagged template function is not included (not applicable in Python)
All core functionality including parse, count, choose, and range work identically to their JavaScript counterparts.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file spintaxpy-1.0.1.tar.gz.
File metadata
- Download URL: spintaxpy-1.0.1.tar.gz
- Upload date:
- Size: 16.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
200800db933d4e85dc9e3d638931e12ec70928b29546cc67cb3fd168151393e6
|
|
| MD5 |
ea01852fec161b5929d3802b65b16dda
|
|
| BLAKE2b-256 |
871bbb6ae4677ba2f75e8b944c16e362e19740b5060c792f7540ce181feec5ab
|
File details
Details for the file spintaxpy-1.0.1-py3-none-any.whl.
File metadata
- Download URL: spintaxpy-1.0.1-py3-none-any.whl
- Upload date:
- Size: 11.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
410caa58c9c6714e4dfad6e5e420305803db6cca5c3bc6d8e476032968d2aa67
|
|
| MD5 |
4ff0c2651aff3147d5de8bfd0c3509ad
|
|
| BLAKE2b-256 |
7812687b1052a3e142bb57f7abc6360fa92ba97af9fb5e781fcaa73c7902b583
|