Skip to content

Utils

Snailz utilities.

UniqueIdGenerator

Generate unique IDs using provided function.

Source code in src/snailz/utils.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
class UniqueIdGenerator:
    """Generate unique IDs using provided function."""

    def __init__(self, name: str, func: Callable, limit: int = UNIQUE_ID_LIMIT) -> None:
        """Initialize.

        Parameters:
            name: A name for this generator
            func: Function that creates IDs when called
            limit: Maximum number of attempts
        """
        self._name = name
        self._func = func
        self._limit = limit
        self._seen = set()

    def next(self, *args: object) -> str:
        """Get next unique ID.

        Parameters:
            args: Arguments to pass to the ID-generating function

        Returns:
            A unique identifier that hasn't been returned before

        Raises:
            RuntimeError: If unable to generate a unique ID within limit attempts
        """
        for i in range(self._limit):
            ident = self._func(*args)
            if ident in self._seen:
                continue
            self._seen.add(ident)
            return ident
        raise RuntimeError(f"failed to find unique ID for {self._name}")

__init__(name, func, limit=UNIQUE_ID_LIMIT)

Initialize.

Parameters:

Name Type Description Default
name str

A name for this generator

required
func Callable

Function that creates IDs when called

required
limit int

Maximum number of attempts

UNIQUE_ID_LIMIT
Source code in src/snailz/utils.py
33
34
35
36
37
38
39
40
41
42
43
44
def __init__(self, name: str, func: Callable, limit: int = UNIQUE_ID_LIMIT) -> None:
    """Initialize.

    Parameters:
        name: A name for this generator
        func: Function that creates IDs when called
        limit: Maximum number of attempts
    """
    self._name = name
    self._func = func
    self._limit = limit
    self._seen = set()

next(*args)

Get next unique ID.

Parameters:

Name Type Description Default
args object

Arguments to pass to the ID-generating function

()

Returns:

Type Description
str

A unique identifier that hasn't been returned before

Raises:

Type Description
RuntimeError

If unable to generate a unique ID within limit attempts

Source code in src/snailz/utils.py
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
def next(self, *args: object) -> str:
    """Get next unique ID.

    Parameters:
        args: Arguments to pass to the ID-generating function

    Returns:
        A unique identifier that hasn't been returned before

    Raises:
        RuntimeError: If unable to generate a unique ID within limit attempts
    """
    for i in range(self._limit):
        ident = self._func(*args)
        if ident in self._seen:
            continue
        self._seen.add(ident)
        return ident
    raise RuntimeError(f"failed to find unique ID for {self._name}")

display(filepath, data)

Write to a file or to stdout.

Parameters:

Name Type Description Default
filepath str | None

Output filepath or None for stdout

required
data BaseModel | str

what to write

required
Source code in src/snailz/utils.py
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
def display(filepath: str | None, data: BaseModel | str) -> None:
    """Write to a file or to stdout.

    Parameters:
        filepath: Output filepath or None for stdout
        data: what to write
    """
    if isinstance(data, str):
        text = data
    else:
        text = json.dumps(data, indent=2, default=_serialize_json)

    if not filepath:
        print(text)
    else:
        with open(filepath, "w") as writer:
            writer.write(text)

fail(msg)

Report failure and exit.

Parameters:

Name Type Description Default
msg str

Error message to display

required
Source code in src/snailz/utils.py
86
87
88
89
90
91
92
93
def fail(msg: str) -> None:
    """Report failure and exit.

    Parameters:
        msg: Error message to display
    """
    print(msg, file=sys.stderr)
    sys.exit(1)

report(verbose, msg)

Report if verbosity turned on.

Parameters:

Name Type Description Default
verbose bool

Is display on or off?

required
msg str

Message to display

required
Source code in src/snailz/utils.py
 96
 97
 98
 99
100
101
102
103
104
def report(verbose: bool, msg: str) -> None:
    """Report if verbosity turned on.

    Parameters:
        verbose: Is display on or off?
        msg: Message to display
    """
    if verbose:
        print(msg)

to_csv(rows, fields, f_make_row)

Generic converter from list of models to CSV string.

Parameters:

Name Type Description Default
rows list

List of rows to convert.

required
fields list

List of names of columns.

required
f_make_row Callable

Function that converts a row to text.

required

Returns:

Type Description
str

CSV representation of data.

Source code in src/snailz/utils.py
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
def to_csv(rows: list, fields: list, f_make_row: Callable) -> str:
    """Generic converter from list of models to CSV string.

    Parameters:
        rows: List of rows to convert.
        fields: List of names of columns.
        f_make_row: Function that converts a row to text.

    Returns:
        CSV representation of data.
    """

    output = io.StringIO()
    writer = csv.writer(output, lineterminator="\n")
    writer.writerow(fields)
    for r in rows:
        writer.writerow(f_make_row(r))
    return output.getvalue()

_serialize_json(obj)

Custom JSON serializer for JSON conversion.

Parameters:

Name Type Description Default
obj object

The object to serialize

required

Returns:

Type Description
str | dict

String representation of date objects or dict for Pydantic models

Raises:

Type Description
TypeError

If the object type is not supported for serialization

Source code in src/snailz/utils.py
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
def _serialize_json(obj: object) -> str | dict:
    """Custom JSON serializer for JSON conversion.

    Parameters:
        obj: The object to serialize

    Returns:
        String representation of date objects or dict for Pydantic models

    Raises:
        TypeError: If the object type is not supported for serialization
    """
    if isinstance(obj, date):
        return obj.isoformat()
    if isinstance(obj, BaseModel):
        return obj.model_dump()
    raise TypeError(f"Type {type(obj)} not serializable")