Utils - Snailz Docs

Skip to content

# Utils

Utilities.

## `UniqueIdGenerator`

Generate unique IDs using provided function.

Source code in `src/snailz/utils.py`

    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    class UniqueIdGenerator:
        """Generate unique IDs using provided function."""

        def __init__(self, name: str, func: Callable, limit: int = 10000) -> None:
            """Initialize the unique ID generator.

            Parameters:
                name: A name for this generator (used in error messages)
                func: Function that creates IDs when called
                limit: Maximum number of attempts to find a unique ID
            """
            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=10000)`

Initialize the unique ID generator.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`name` | `str` | A name for this generator (used in error messages) | required
`func` | `Callable` | Function that creates IDs when called | required
`limit` | `int` | Maximum number of attempts to find a unique ID | `10000`

Source code in `src/snailz/utils.py`

    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    def __init__(self, name: str, func: Callable, limit: int = 10000) -> None:
        """Initialize the unique ID generator.

        Parameters:
            name: A name for this generator (used in error messages)
            func: Function that creates IDs when called
            limit: Maximum number of attempts to find a unique ID
        """
        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`

    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    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}")

## `csv_writer(output)`

Wrapper to get line terminator settings right.

Source code in `src/snailz/utils.py`

    55
    56
    57
    58
    def csv_writer(output: TextIO | StringIO) -> Any:
        """Wrapper to get line terminator settings right."""

        return csv.writer(output, lineterminator="\n")

## `fail(msg)`

Print message to standard error and exit with status 1.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`msg` | `str` | The error message to display | required

Source code in `src/snailz/utils.py`

    61
    62
    63
    64
    65
    66
    67
    68
    def fail(msg: str) -> None:
        """Print message to standard error and exit with status 1.

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

## `load_data(parameter_name, filename, cls)`

Construct a Pydantic model from serialized JSON.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`parameter_name` | `str` | Name of the parameter requiring this file (for error messages) | required
`filename` | `str | Path | None` | Path to the JSON file to load (allowed to be None so that checking is done in one place) | required
`cls` | `Type[BaseModel]` | The Pydantic model to instantiate with the loaded data | required

Returns:

Type | Description
--- | ---
`BaseModel` | An instance of cls constructed from the JSON data

Raises:

Type | Description
--- | ---
`IOError` | If the file cannot be read

Source code in `src/snailz/utils.py`

    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    def load_data(
        parameter_name: str, filename: str | Path | None, cls: Type[BaseModel]
    ) -> BaseModel:
        """Construct a Pydantic model from serialized JSON.

        Parameters:
            parameter_name: Name of the parameter requiring this file (for error messages)
            filename: Path to the JSON file to load (allowed to be None so that checking is done in one place)
            cls: The Pydantic model to instantiate with the loaded data

        Returns:
            An instance of cls constructed from the JSON data

        Raises:
            IOError: If the file cannot be read
        """
        assert filename is not None, f"--{parameter_name} is required"
        with open(filename, "r") as reader:
            return cls.model_validate(json.load(reader))

## `report_result(output, result)`

Save or display result as JSON.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`output` | `str | Path | None` | Path to output file, or None to print to stdout | required
`result` | `BaseModel` | The Pydantic model object to serialize as JSON | required

Side effects

Either writes to the specified output file or prints to stdout

Source code in `src/snailz/utils.py`

     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    def report_result(output: str | Path | None, result: BaseModel) -> None:
        """Save or display result as JSON.

        Parameters:
            output: Path to output file, or None to print to stdout
            result: The Pydantic model object to serialize as JSON

        Side effects:
            Either writes to the specified output file or prints to stdout
        """
        result_json = json.dumps(result.model_dump(), default=serialize_values)
        if output:
            with open(output, "w") as writer:
                writer.write(result_json)
        else:
            print(result_json)

## `serialize_values(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`

    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    def serialize_values(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")

## `validate_date(ctx, param, value)`

Validate and convert date string to date object.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`ctx` | `object` | Click context object | required
`param` | `object` | Click parameter being processed | required
`value` | `str | None` | The value to validate | required

Returns:

Type | Description
--- | ---
`date | None` | None if value is None, otherwise a date object

Source code in `src/snailz/utils.py`

    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    def validate_date(ctx: object, param: object, value: str | None) -> date | None:
        """Validate and convert date string to date object.

        Parameters:
            ctx: Click context object
            param: Click parameter being processed
            value: The value to validate

        Returns:
            None if value is None, otherwise a date object
        """
        return None if value is None else date.fromisoformat(value)