Skip to main content

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 {...} patterns
  • pattern_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

  1. Limit Pattern Count: Keep the number of variable patterns reasonable to avoid combinatorial explosion
  2. Use Meaningful Options: Create patterns that produce meaningful variations
  3. Process Lazily: Use the generator directly when dealing with large result sets
  4. 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_range instead of just range to avoid conflicts)
  • Uses keyword arguments for options instead of object parameters
  • The compile tagged 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

spintaxpy-1.0.1.tar.gz (16.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

spintaxpy-1.0.1-py3-none-any.whl (11.0 kB view details)

Uploaded Python 3

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

Hashes for spintaxpy-1.0.1.tar.gz
Algorithm Hash digest
SHA256 200800db933d4e85dc9e3d638931e12ec70928b29546cc67cb3fd168151393e6
MD5 ea01852fec161b5929d3802b65b16dda
BLAKE2b-256 871bbb6ae4677ba2f75e8b944c16e362e19740b5060c792f7540ce181feec5ab

See more details on using hashes here.

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

Hashes for spintaxpy-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 410caa58c9c6714e4dfad6e5e420305803db6cca5c3bc6d8e476032968d2aa67
MD5 4ff0c2651aff3147d5de8bfd0c3509ad
BLAKE2b-256 7812687b1052a3e142bb57f7abc6360fa92ba97af9fb5e781fcaa73c7902b583

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page