Skip to main content

A powerful data-generating library.

Project description

COOTA

Project Home Page | Download Page

Detailed Documentation (English) | 详细文档(中文)

Join us | 加入我们


What is COOTA

COOTA(Come Out Of Thin Air) is a powerful data-generating python library. By supporting generator nesting, it allows you to generate a variety of data that shows great randomness. It also supports making generators conform to a certain distribution.

Catalog

[TOC]

Installation

Python Library

Requires Python 3.x.

Windows / Mac OS

pip install coota

Linux

pip3 install coota

Application

Go to 👆🏻download page.

Tutorial

Demo programs can be found under the "tutorial" folder.

Quick Start

Generate a letter using a Generator.

from coota import *


generator = LetterGenerator()
print(generator.generate())

This returns a random letter, for example:

a

See all built-in generators.

Generate data in batches using GeneratorSequence.

from coota import *


string_length = 2
int_range_from = 0
int_range_to = 10 # not included, which means the generator returns a integer x that matches 0 ≤ x < 10
generator_a = StringGenerator(string_length)
generator_b = IntGenerator(start=int_range_from, stop=int_range_to)
generator_sequence = GeneratorSequence("String: ", generator_a, ", Integer: ", generator_b, n=10)
for data in generator_sequence:
    print(data)

This returns 10 groups of data.

String: Pf, Integer: 6
String: YL, Integer: 9
String: kl, Integer: 8
String: xC, Integer: 4
String: lo, Integer: 2
String: on, Integer: 4
String: uE, Integer: 0
String: or, Integer: 3
String: gj, Integer: 8
String: vl, Integer: 0

The default arguments can be generators. For example:

from coota import *


string_length = IntGenerator(start=1, stop=4)
int_range_from = 0
int_range_to = 10
generator_a = StringGenerator(string_length)
generator_b = IntGenerator(start=int_range_from, stop=int_range_to)
generator_sequence = GeneratorSequence("String: ", generator_a, ", Integer: ", generator_b, n=10)
for data in generator_sequence:
    print(data)
String: I, Integer: 5
String: kaK, Integer: 1
String: aCx, Integer: 3
String: I, Integer: 2
String: Ev, Integer: 4
String: RXc, Integer: 4
String: Gh, Integer: 3
String: z, Integer: 6
String: DO, Integer: 3
String: OL, Integer: 2

The nesting depth is not limited. Any default argument like string_length can be a generator. Global arguments like int_range_from and int_range_to can also be generators, but they won't be parsed.

Data Generating

Start Using Generators

Built-in Generators
LetterGenerator
from coota import *


# generate one letter
generator = LetterGenerator()
letter = generator.generate()
print(type(letter), letter)
<class 'str'> L
StringGenerator
from coota import *


# generate a string of 5 letters
string_length = 5

generator = StringGenerator()
string = generator.generate(string_length)
print(type(string), string)
<class 'str'> ieyDW
NumberGenerator
from coota import *


# generate a 10 digit number
number_digit = 10

generator = NumberGenerator()
number = generator.generate(number_digit)   # the first digit of the number cannot be zero except 0, like 012
print(type(number), number)
<class 'str'> 4947421207
LetterAndNumberGenerator
from coota import *


# generate a string of 6 letters and numbers
string_length = 6

generator = LetterAndNumberGenerator()
string = generator.generate(string_length)
print(type(string), string)
<class 'str'> dPgpJ9
IntGenerator
from coota import *


# generate an integer (0 ≤ x < 10)
range_from, range_to = 0, 10

generator = IntGenerator(start=range_from, stop=range_to)
integer = generator.generate()
print(type(integer), integer)
<class 'int'> 9
IntIterable
from coota import *


# create an IntIterable
range_from, range_to = 0, 10
step = 1    # optional, 1 by default

iterable_a = IntIterable(start=range_from, stop=range_to, step=step)
integer_a, integer_b = iterable_a.generate(), iterable_a.generate()
print(type(integer_a), integer_a, integer_b)

print("Example in the for loop:")
iterable_b = IntIterable(start=range_from, stop=range_to, step=step)
for integer in iterable_b:
    print(type(integer), integer)
<class 'int'> 0 1
Example in the for loop:
<class 'int'> 0
<class 'int'> 1
<class 'int'> 2
<class 'int'> 3
<class 'int'> 4
<class 'int'> 5
<class 'int'> 6
<class 'int'> 7
<class 'int'> 8
<class 'int'> 9
TimeGenerator
from coota.preset import *
import datetime


# generate a datetime from April 1, 2022 to June 1, 2022
# can be either str or datetime.datetime object or integer time stamp
range_from, range_to = "2022-4-1", "2022.6.1"   # optional, the default range is from now to next year
# range_from, range_to = datetime.datetime(year=2022, month=4, day=1), datetime.datetime(year=2022, month=6, day=1)
# range_from, range_to = 1648791336, 1654061736

generator = TimeGenerator(start=range_from, stop=range_to)
time = generator.generate()
print(type(time), time)
<class 'datetime.datetime'> 2022-05-24 18:12:00
EmailGenerator
from coota.preset import *


# generate an email address with a 7-digit name ending with "outlook.com"
domain, name_length = "outlook.com", 7

generator = EmailGenerator(domain=domain)
email = generator.generate(name_length)
print(type(email), email)
<class 'str'> RUSyUY5@outlook.com
QQMailGenerator
from coota.preset import *


# generate a QQMail address with a 13-digit name
name_length = 13

generator = QQMailGenerator()
qqmail = generator.generate(name_length)
print(type(qqmail), qqmail)
<class 'str'> 7160380273761@qq.com
NameGenerator
from coota.preset import *


# generate a name
generator = NameGenerator()
name = generator.generate()
print(type(name), name)
<class 'str'> Nikita
Custom Generators
Generator

See the documentation section for a detailed explanation.

from coota import *


class MyGenerator(Generator):
    def source(self) -> Sequence:
        return "option A", "option B", "option C"

    def make(self, *args) -> Any:
        return self.choice()


my_generator = MyGenerator()
option = my_generator.generate()
print(option)
option C
Iterable Generator

See the documentation section for a detailed explanation.

from coota import *


class MyIterableGenerator(ItertableGenerator):
    def initialize(self) -> None:
        self.set_pointer(0)

    def step(self) -> bool:
        self.set_pointer(self.get_pointer() + 1)
        return self.get_pointer() <= len(self.get_source())

    def source(self) -> Sequence:
        return "A", "B", "C", "D"

    def make(self, *args) -> Any:
        return self.get_source()[self.get_pointer()]


my_iterable_generator = MyIterableGenerator()
for opt in my_iterable_generator:
    print(opt)
A
B
C
D
Different Ways of Passing Arguments
Default Arguments
from coota.preset import *


domain, name_length = "outlook.com", 7

generator = EmailGenerator(domain=domain)
email = generator.generate(name_length)

The above example can be replaced by the following code:

from coota.preset import *


domain, name_length = "outlook.com", 7

generator = EmailGenerator(name_length, domain=domain)
email = generator.generate()

In other words, the arguments given to generate() can be given to the constructor with the same order so that no arguments are necessary in generate(). However, the global arguments for generator can only be given to the constructor. If you don't know much about the argument format of python, the arguments in the form of name=value is are global arguments, the others are default arguments.

Use A Generator as An Argument

For example, you want to generate a random length string:

from coota import *


string_length = IntGenerator(start=1, stop=10)

generator = StringGenerator()
string = generator.generate(string_length)
# or
generator = StringGenerator(string_length)
string = generator.generate()

Data Saving

Generator

Save
from coota import *


path = "generator.g"

generator = LetterGenerator()
save(generator, path)
Load
from coota import *


path = "generator.g"

generator = load(path)
# or
generator = GeneratorOperator(path).load()

Documentation

General flow path:

pic1

Chooser

class Chooser(object):

abstract:choice()

This method specifies how the chooser selects an item.

@abstractmethod
def choice(self, x: Sequence) -> Any:
Name Usage
x The data source from which the chooser chooses.
return A single item chosen from x.

abstract:choices()

This method specifies how the chooser selects a batch of items.

@abstractmethod
def choices(self, x: Sequence, n: int, weights: Sequence = None) -> Sequence:
Name Usage
x The data source from which the chooser chooses.
n The number of choices.
weights A list of weights for each item when randomly selected.
return A list of items chosen from x.

Association

class Association(object):

__init__()

def __init__(self, the_other_generator: Generator):
Name Usage
the_other_generator The other generator associated with this generator. That generator must generate before this generator.

get_the_other_generator

def get_the_other_generator(self) -> Generator:
Name Usage
return The other generator.

abstract:associate()

This method specifies the association between the output of two generators.

@abstractmethod
def associate(self, generator: Any, the_other_generator_output: Any) -> Any:
Name Usage
generator The generator whose set_association() is called with the association given to.
the_other_generator_output The output generated by the other generator.
return Anything.

GeneratorOutput

class GeneratorOutput(object):

__init__()

def __init__(self, output: Any):
Name Usage
output The output.

get_output()

def get_output(self) -> Any:
Name Usage
return The output.

Generator

class Generator(object):

__init__()

def __init__(self, *default_args, **args):
Name Usage
default_args Given to make() when no arguments are given to generate(). For example, in a GeneratorSequence, generate() is called with no arguments, then the default_args will be given to make(). Required arguments are listed in the specific generators.
args Global arguments for the generator. Required arguments are listed in the specific generators.

_get_weights()

def _get_weights(self) -> Union[Sequence, None]:
Name Usage
return A list of weights for each item when randomly selected.

_set_weights()

def _set_weights(self, weights: Sequence) -> None:
Name Usage
weights A list of weights for each item when randomly selected, whose length must be the same as source returns.
return

_get_source_cache()

def _get_source_cache(self) -> Union[Sequence, None]:
Name Usage
return The cache of the source.

_set_source_cache()

def _set_source_cache(self, source_cache: Sequence) -> None:
Name Usage
source_cahce The cache of the source.
return

_get_last()

def _get_last(self) -> Any:
Name Usage
return Last generated data.

_set_last()

def _set_last(self, last: Any) -> None:
Name Usage
last Last generated data.
return

get_parseable()

def get_parseable(self) -> bool:
Name Usage
return Whether the generator can be parsed as an argument.

set_parseable()

def set_parseable(self, parseable: bool) -> None:
Name Usage
parseable Whether the generator can be parsed as an argument. If false, the generator will be recognized as an argument itself instead of being parsed into an actual output.
return

get_uc()

def get_uc(self) -> bool:
Name Usage
return Whether the generator uses the cache of the source.

set_uc()

def set_uc(self, use_cache: bool) -> None:
Name Usage
use_cache Whether the generator uses the cache of the source. If true, the generator will only call source() once and use the cache instead after that. It's true by default. Set it to false if your source is not always static.
return

get_args()

def get_args(self) -> dict:
Name Usage
return The global arguments of the generator.

get_arg()

def get_arg(self, name: str, required_type: type = object) -> Any:
Name Usage
name The argument's name.
required_type The type of argument you require. If any type of argument is acceptable, set it to object which is also by default.
return The argument's value. It can be None if the argument does not exist or is not of the same type as required.

get_arg_or_default()

def get_arg_or_default(self, name: str, default: Any, required_type: type = object) -> Any:
Name Usage
name The argument's name.
default The default value.
required_type The type of argument you require. If any type of argument is acceptable, set it to object which is also by default.
return The argument's value. The default value will be returned if the argument does not exist or is not of the same type as required.

get_required_arg()

def get_required_arg(self, name: str, required_type: type = object) -> Any:
Name Usage
name The argument's name.
required_type The type of argument you require. If any type of argument is acceptable, set it to object which is also by default.
return The argument's value.
Exception Case
AttributeError The argument does not exist.
TypeError The argument is not of the same type as required.

get_default_args()

def get_default_args(self) -> tuple:
Name Usage
return The default arguments to be given to make().

get_chooser()

def get_chooser(self) -> Chooser:
Name Usage
return The generator's chooser.

set_chooser()

def set_chooser(self, chooser: Chooser) -> None:
Name Usage
chooser Set the generator's chooser. A DefaultChooser is used by default. If you want to customize the behavior of choosing, you can create your own chooser object and set it in the generator.
return

get_association()

def get_association(self) -> Union[Associatoin, None]:
Name Usage
return The association with the other generator.

set_association()

def set_association(self, association: Association) -> None:
Name Usage
association The association with the other generator.
return

choice()

def choice(self) -> Any:
Name Usage
return One single item chosen from the source by the chooser.

choices()

def choices(self, n: int) -> Sequence:
Name Usage
n The number of items.
return A batch of items chosen from the source by the chooser.

abstract:source()

This method specifies what data the generator may generate.

@abstractmethod
def source(self) -> Sequence:
Name Usage
return The original dataset from which the generator selects.

get_source()

def get_source(self) -> Sequence:
Name Usage
return The same as source() returns. If use_cache is true, returns the source cache instead.

fits()

def fits(self, distribution: Distribution, *args) -> None:
Name Usage
distribution The distribution to which the generator fits.
args Optional arguments for the distribution.
return

abstract:make()

This method specifies how to generate data.

@abstractmethod
def make(self, *args) -> Any:
Name Usage
args Optional arguments.
return Anything.

generate()

def generate(self, *args, parse: bool = True) -> Any:
Name Usage
args Optional arguments given to make().
parse Whether to resolve the generator in parameters and return values. True: return an output. False: return the generator itself.
return Anything.

output()

def output(self, *args, parse: bool = False) -> GeneratorOutput:
Name Usage
args Optional arguments given to make().
parse Whether to resolve the generator in parameters and return values.
return The return value of generate() wrapped as a GeneratorOutput.

IterableGenerator

An IterableGenerator is an ordered iterator, not a selector. It achieves ordering by adding a pointer to the generator.

class ItertableGenerator(Generator):

get_pointer()

def get_pointer(self) -> Any:
Name Usage
return The pointer.

set_pointer()

def set_pointer(self, pointer: Any) -> None:
Name Usage
pointer The pointer which is 0 in default.
return

choice()

def choice(self) -> Any:
Name Usage
return self.get_source()[pointer]. The pointer must be an integer when calling this method.

choices()

def choices(self, n: int) -> Sequence:
Name
n The number of choices.
return self.get_source()[pointer: pointer + n]. The pointer must be an integer when calling this method.

abstract:initialize()

This is a callback used to set initialization operations such as pointers.

@abstractmethod
def initialize(self) -> None:
Name Usage
return

abstract:step()

This method specifies how the iterator iterates.

@abstractmethod
def step(self) -> bool:
Name Usage
return True: continue iteration. False: stop iteration.

Distribution

Distribution can adjust the probability that each item in the source is selected.

abstract:fits()

This method specifies how the probability of each item being selected is distributed.

@abstractmethod
def fits(self, loc: float, scale: float, size: int, *args) -> Sequence: pass
Name Usage
loc The most probable index.
scale Standard deviation.
size The length of the source.
args Optional arguments.
return A list of weights. For example, numpy.ndarray([1, 1.5, 4.0, 10]).

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

coota-1.0.0b2.tar.gz (22.6 kB view hashes)

Uploaded Source

Supported by

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