friendly-id


Namefriendly-id JSON
Version 0.6.1 PyPI version JSON
download
home_pageNone
Summaryfriendly-id is a Python library to generate really unique and url friendly IDs based on UUID and base62
upload_time2025-07-25 02:36:29
maintainerNone
docs_urlNone
authorNone
requires_python>=3.9
licenseCopyright 2022 Junlin Zhou Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords friendly-id uuid
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # FriendlyId

[![test friendly-id](https://github.com/edwardzjl/friendly-id/actions/workflows/ci.yml/badge.svg)](https://github.com/edwardzjl/friendly-id/actions/workflows/ci.yml)

Inspired by [FriendlyID](https://github.com/Devskiller/friendly-id)

## What is the FriendlyId library?

The FriendlyID library provides a `UUID` subclass that uses base62 encoding for its string representation. This makes UUIDs more compact and URL-friendly, reducing their length from the standard 36 characters to **at most** 22. An example is shown below:

    UUID                                        FriendlyID

    c3587ec5-0976-497f-8374-61e0c2ea3da5   ->   5wbwf6yUxVBcr48AMbz9cb
    |                                           |
    36 characters                               22 characters or less

**FriendlyID extends the standard UUID class**, providing all the functionality of a regular UUID while displaying as a compact, URL-friendly string by default.

## Key Features

- **Automatic friendly display**: `str(friendly_id)` returns the base62 format
- **Access to both formats**: `.friendly` property for base62, `.standard` property for UUID format
- **Drop-in replacement**: Works with existing code that expects UUID objects
- **Convert from a FriendlyID back to the original UUID format**

## Why use a FriendlyID?

Universal Unique IDs (UUIDs) provide a non-sequential and unique identifier that can be generated separately from the source database. As a result, it is not possible to guess either the previous or next identifier. That's great, but, to achieve this level of security, a UUID is long (128 bits long) and looks ugly (36 alphanumeric characters including four hyphens which are added to make it easier to read the UUID), as in this example: `123e4567-e89b-12d3-a456-426655440000`.

Such a format is:

- Cannot be copied with just two mouse-clicks (you have to select manually the start and end positions)
- difficult to read
- difficult to remember

FriendlyID library solves these problems by extending the standard UUID class and overriding its string representation to use Base62 with alphanumeric characters in the range [0-9A-Za-z] into a compact representation which consists of a **maximum of** 22 characters (but in fact often contains fewer characters).

## Usage

FriendlyId can be installed through PyPI:

```sh
python -m pip install friendly-id
```

### Basic Usage

Generate a random FriendlyID:

```python
from friendly_id import FriendlyID

# Generate a random FriendlyID
fuid = FriendlyID.random()
print(fuid)  # Prints base62 format, e.g., "5wbwf6yUxVBcr48AMbz9cb"
print(f"User ID: {fuid}")  # Perfect for URLs and display
```

Create from existing UUID:

```python
import uuid
from friendly_id import FriendlyID

# Convert existing UUID
regular_uuid = uuid.uuid4()
fuid = FriendlyID.from_uuid(regular_uuid)
print(fuid)  # Base62 format
```

Create from base62 string:

```python
from friendly_id import FriendlyID

# Create from friendly string
fuid = FriendlyID.from_friendly("5wbwf6yUxVBcr48AMbz9cb")
print(fuid.standard)  # c3587ec5-0976-497f-8374-61e0c2ea3da5
```

### Access Different Formats

```python
from friendly_id import FriendlyID

fuid = FriendlyID.random()

# Base62 format (default string representation)
print(str(fuid))       # e.g., "5wbwf6yUxVBcr48AMbz9cb"
print(fuid.friendly)   # Same as str(fuid)

# Standard UUID format
print(fuid.standard)   # e.g., "c3587ec5-0976-497f-8374-61e0c2ea3da5"

# Convert back to regular UUID
regular_uuid = fuid.to_uuid()
print(regular_uuid)    # Standard UUID object
```

### UUID Compatibility

Since FriendlyID extends UUID, it works everywhere a UUID is expected:

```python
import uuid
from friendly_id import FriendlyID

fuid = FriendlyID.random()

# All UUID properties and methods work
print(fuid.version)    # 4
print(fuid.hex)        # Hexadecimal representation
print(fuid.bytes)      # Bytes representation

# Type checking
isinstance(fuid, uuid.UUID)  # True
isinstance(fuid, FriendlyID)  # True

# Equality with regular UUIDs
regular_uuid = uuid.UUID(fuid.standard)
fuid == regular_uuid  # True

# Use in collections
uuid_set = {fuid, regular_uuid}  # Only one item (they're equal)
```

## SQLAlchemy Integration

FriendlyID includes seamless SQLAlchemy integration through an optional extra:

```sh
pip install friendly-id[sqlalchemy]
```

### FriendlyIDType

Stores UUIDs in the database's native UUID format while providing FriendlyID objects in Python:

```python
from friendly_id import FriendlyID
from friendly_id.sqlalchemy_types import FriendlyIDType
from sqlalchemy import Text, create_engine
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column

class Base(DeclarativeBase):
    pass

class User(Base):
    __tablename__ = "users"

    id: Mapped[FriendlyID] = mapped_column(
        FriendlyIDType, primary_key=True, insert_default=FriendlyID.random
    )
    name: Mapped[str] = mapped_column(Text)
    email: Mapped[str] = mapped_column(Text)

# Usage
user = User(name="Alice", email="alice@example.com")
session.add(user)
session.commit()

print(user.id)  # Prints: 5wbwf6yUxVBcr48AMbz9cb (base62 format)
print(user.id.standard)  # Prints: c3587ec5-0976-497f-8374-61e0c2ea3da5

# Query by any format
alice = session.query(User).filter_by(id=user.id).first()  # FriendlyID
alice = session.query(User).filter_by(id=str(user.id)).first()  # base62 string
alice = session.query(User).filter_by(id=user.id.standard).first()  # UUID string
```

### Database Compatibility

FriendlyIDType automatically selects the optimal storage format for each database:

- **PostgreSQL**: Uses native UUID type for optimal performance and indexing
- **MySQL**: Uses CHAR(36) for UUID string storage
- **SQLite**: Uses TEXT for UUID string storage
- **Other databases**: Falls back to string storage

## Pydantic Integration

FriendlyID includes built-in Pydantic support for seamless integration with Pydantic models. Install the optional extra for enhanced features:

```sh
pip install friendly-id[pydantic]
```

**Note**: This library requires Pydantic v2.0 or higher. Pydantic v1 is no longer supported.

### Basic Usage with Pydantic

```python
from pydantic import BaseModel
from friendly_id.pydantic_types import PydanticFriendlyID as FriendlyID

class User(BaseModel):
    id: FriendlyID
    name: str
    email: str

# Create from various input types
user1 = User(id=FriendlyID.random(), name="John", email="john@example.com")
user2 = User(id="5wbwf6yUxVBcr48AMbz9cb", name="Jane", email="jane@example.com")  # base62
user3 = User(id="c3587ec5-0976-497f-8374-61e0c2ea3da5", name="Bob", email="bob@example.com")  # UUID

# Serialization automatically uses base62 format
print(user1.model_dump_json())
# {"id": "7mkedUHZ3nyAx11JWbR91z", "name": "John", "email": "john@example.com"}
```

### Validation Features

FriendlyID automatically validates and converts:
- Existing FriendlyID instances (pass-through)
- Regular UUID objects
- Base62 strings
- Standard UUID strings
- Rejects invalid formats with clear error messages

### JSON Schema Support

FriendlyID provides proper JSON schema for OpenAPI generation:

```python
schema = User.model_json_schema()
# FriendlyID fields include:
# - type: "string"
# - pattern: "^[0-9A-Za-z]+$" (base62 validation)
# - description: "A URL-friendly base62 encoded UUID"
```

## Performance

FriendlyID involves a trade-off between CPU overhead and I/O efficiency:

- **CPU**: ~6x slower base62 encoding (~3 microseconds per ID)
- **I/O**: ~39% bandwidth savings (less than 22 vs 36 characters)
- **Database**: Uses native UUID storage (no storage overhead)

Run the included benchmark to see detailed performance analysis:
```bash
python benchmark.py --count 1000
```

For detailed performance analysis, see [PERFORMANCE.md](PERFORMANCE.md).

## Choosing Between FriendlyID and Standard UUID

FriendlyID presents a clear trade-off: **3 microseconds CPU overhead vs 14 characters I/O savings per ID**.

### Consider FriendlyID when:
- Network bandwidth or data transfer costs are significant
- User-facing URLs and identifiers matter for UX  
- Text-based logging and data export are frequent
- Web APIs where transfer size matters
- Mobile applications with bandwidth constraints

### Consider Standard UUID when:
- High-frequency serialization with minimal I/O
- CPU resources are constrained or critical
- Existing systems require standard UUID format
- Microsecond-level performance is essential
- Real-time systems where every cycle counts

### Evaluation Factors
Consider your application's specific characteristics:
- **I/O vs CPU ratio**: How much network/text processing vs computation?
- **Scale**: Volume of UUID operations vs data transmission
- **Constraints**: CPU limitations vs bandwidth costs
- **User experience**: Does identifier readability matter?
- **Integration**: Compatibility with existing systems

Run the benchmark with your expected workload to get concrete numbers for your specific use case.

## Breaking Changes

**⚠️ Important**: 0.4.0 introduces breaking changes from previous versions:

- `str(FriendlyID)` now returns base62 format instead of standard UUID format
- Use `.standard` property when you need the standard UUID string format
- JSON serialization will use base62 format by default
- Update any code that expects `str(uuid)` to return standard UUID format

## Migration Guide

If you were using the previous functional API:

```python
# Old way (no longer available)
from friendly_id import friendly_id, encode, decode

id_str = friendly_id()
encoded = encode(some_uuid)
decoded = decode(some_string)

# New way
from friendly_id import FriendlyID

id_str = str(FriendlyID.random())
encoded = str(FriendlyID.from_uuid(some_uuid))
decoded = FriendlyID.from_friendly(some_string).to_uuid()
```

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "friendly-id",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": "friendly-id, uuid",
    "author": null,
    "author_email": "Junlin Zhou <jameszhou2108@hotmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/7a/16/616b889e98518b0e3a1e59bd78ba043a0f1c3b2a671a0c2c815d96cf8080/friendly_id-0.6.1.tar.gz",
    "platform": null,
    "description": "# FriendlyId\n\n[![test friendly-id](https://github.com/edwardzjl/friendly-id/actions/workflows/ci.yml/badge.svg)](https://github.com/edwardzjl/friendly-id/actions/workflows/ci.yml)\n\nInspired by [FriendlyID](https://github.com/Devskiller/friendly-id)\n\n## What is the FriendlyId library?\n\nThe FriendlyID library provides a `UUID` subclass that uses base62 encoding for its string representation. This makes UUIDs more compact and URL-friendly, reducing their length from the standard 36 characters to **at most** 22. An example is shown below:\n\n    UUID                                        FriendlyID\n\n    c3587ec5-0976-497f-8374-61e0c2ea3da5   ->   5wbwf6yUxVBcr48AMbz9cb\n    |                                           |\n    36 characters                               22 characters or less\n\n**FriendlyID extends the standard UUID class**, providing all the functionality of a regular UUID while displaying as a compact, URL-friendly string by default.\n\n## Key Features\n\n- **Automatic friendly display**: `str(friendly_id)` returns the base62 format\n- **Access to both formats**: `.friendly` property for base62, `.standard` property for UUID format\n- **Drop-in replacement**: Works with existing code that expects UUID objects\n- **Convert from a FriendlyID back to the original UUID format**\n\n## Why use a FriendlyID?\n\nUniversal Unique IDs (UUIDs) provide a non-sequential and unique identifier that can be generated separately from the source database. As a result, it is not possible to guess either the previous or next identifier. That's great, but, to achieve this level of security, a UUID is long (128 bits long) and looks ugly (36 alphanumeric characters including four hyphens which are added to make it easier to read the UUID), as in this example: `123e4567-e89b-12d3-a456-426655440000`.\n\nSuch a format is:\n\n- Cannot be copied with just two mouse-clicks (you have to select manually the start and end positions)\n- difficult to read\n- difficult to remember\n\nFriendlyID library solves these problems by extending the standard UUID class and overriding its string representation to use Base62 with alphanumeric characters in the range [0-9A-Za-z] into a compact representation which consists of a **maximum of** 22 characters (but in fact often contains fewer characters).\n\n## Usage\n\nFriendlyId can be installed through PyPI:\n\n```sh\npython -m pip install friendly-id\n```\n\n### Basic Usage\n\nGenerate a random FriendlyID:\n\n```python\nfrom friendly_id import FriendlyID\n\n# Generate a random FriendlyID\nfuid = FriendlyID.random()\nprint(fuid)  # Prints base62 format, e.g., \"5wbwf6yUxVBcr48AMbz9cb\"\nprint(f\"User ID: {fuid}\")  # Perfect for URLs and display\n```\n\nCreate from existing UUID:\n\n```python\nimport uuid\nfrom friendly_id import FriendlyID\n\n# Convert existing UUID\nregular_uuid = uuid.uuid4()\nfuid = FriendlyID.from_uuid(regular_uuid)\nprint(fuid)  # Base62 format\n```\n\nCreate from base62 string:\n\n```python\nfrom friendly_id import FriendlyID\n\n# Create from friendly string\nfuid = FriendlyID.from_friendly(\"5wbwf6yUxVBcr48AMbz9cb\")\nprint(fuid.standard)  # c3587ec5-0976-497f-8374-61e0c2ea3da5\n```\n\n### Access Different Formats\n\n```python\nfrom friendly_id import FriendlyID\n\nfuid = FriendlyID.random()\n\n# Base62 format (default string representation)\nprint(str(fuid))       # e.g., \"5wbwf6yUxVBcr48AMbz9cb\"\nprint(fuid.friendly)   # Same as str(fuid)\n\n# Standard UUID format\nprint(fuid.standard)   # e.g., \"c3587ec5-0976-497f-8374-61e0c2ea3da5\"\n\n# Convert back to regular UUID\nregular_uuid = fuid.to_uuid()\nprint(regular_uuid)    # Standard UUID object\n```\n\n### UUID Compatibility\n\nSince FriendlyID extends UUID, it works everywhere a UUID is expected:\n\n```python\nimport uuid\nfrom friendly_id import FriendlyID\n\nfuid = FriendlyID.random()\n\n# All UUID properties and methods work\nprint(fuid.version)    # 4\nprint(fuid.hex)        # Hexadecimal representation\nprint(fuid.bytes)      # Bytes representation\n\n# Type checking\nisinstance(fuid, uuid.UUID)  # True\nisinstance(fuid, FriendlyID)  # True\n\n# Equality with regular UUIDs\nregular_uuid = uuid.UUID(fuid.standard)\nfuid == regular_uuid  # True\n\n# Use in collections\nuuid_set = {fuid, regular_uuid}  # Only one item (they're equal)\n```\n\n## SQLAlchemy Integration\n\nFriendlyID includes seamless SQLAlchemy integration through an optional extra:\n\n```sh\npip install friendly-id[sqlalchemy]\n```\n\n### FriendlyIDType\n\nStores UUIDs in the database's native UUID format while providing FriendlyID objects in Python:\n\n```python\nfrom friendly_id import FriendlyID\nfrom friendly_id.sqlalchemy_types import FriendlyIDType\nfrom sqlalchemy import Text, create_engine\nfrom sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column\n\nclass Base(DeclarativeBase):\n    pass\n\nclass User(Base):\n    __tablename__ = \"users\"\n\n    id: Mapped[FriendlyID] = mapped_column(\n        FriendlyIDType, primary_key=True, insert_default=FriendlyID.random\n    )\n    name: Mapped[str] = mapped_column(Text)\n    email: Mapped[str] = mapped_column(Text)\n\n# Usage\nuser = User(name=\"Alice\", email=\"alice@example.com\")\nsession.add(user)\nsession.commit()\n\nprint(user.id)  # Prints: 5wbwf6yUxVBcr48AMbz9cb (base62 format)\nprint(user.id.standard)  # Prints: c3587ec5-0976-497f-8374-61e0c2ea3da5\n\n# Query by any format\nalice = session.query(User).filter_by(id=user.id).first()  # FriendlyID\nalice = session.query(User).filter_by(id=str(user.id)).first()  # base62 string\nalice = session.query(User).filter_by(id=user.id.standard).first()  # UUID string\n```\n\n### Database Compatibility\n\nFriendlyIDType automatically selects the optimal storage format for each database:\n\n- **PostgreSQL**: Uses native UUID type for optimal performance and indexing\n- **MySQL**: Uses CHAR(36) for UUID string storage\n- **SQLite**: Uses TEXT for UUID string storage\n- **Other databases**: Falls back to string storage\n\n## Pydantic Integration\n\nFriendlyID includes built-in Pydantic support for seamless integration with Pydantic models. Install the optional extra for enhanced features:\n\n```sh\npip install friendly-id[pydantic]\n```\n\n**Note**: This library requires Pydantic v2.0 or higher. Pydantic v1 is no longer supported.\n\n### Basic Usage with Pydantic\n\n```python\nfrom pydantic import BaseModel\nfrom friendly_id.pydantic_types import PydanticFriendlyID as FriendlyID\n\nclass User(BaseModel):\n    id: FriendlyID\n    name: str\n    email: str\n\n# Create from various input types\nuser1 = User(id=FriendlyID.random(), name=\"John\", email=\"john@example.com\")\nuser2 = User(id=\"5wbwf6yUxVBcr48AMbz9cb\", name=\"Jane\", email=\"jane@example.com\")  # base62\nuser3 = User(id=\"c3587ec5-0976-497f-8374-61e0c2ea3da5\", name=\"Bob\", email=\"bob@example.com\")  # UUID\n\n# Serialization automatically uses base62 format\nprint(user1.model_dump_json())\n# {\"id\": \"7mkedUHZ3nyAx11JWbR91z\", \"name\": \"John\", \"email\": \"john@example.com\"}\n```\n\n### Validation Features\n\nFriendlyID automatically validates and converts:\n- Existing FriendlyID instances (pass-through)\n- Regular UUID objects\n- Base62 strings\n- Standard UUID strings\n- Rejects invalid formats with clear error messages\n\n### JSON Schema Support\n\nFriendlyID provides proper JSON schema for OpenAPI generation:\n\n```python\nschema = User.model_json_schema()\n# FriendlyID fields include:\n# - type: \"string\"\n# - pattern: \"^[0-9A-Za-z]+$\" (base62 validation)\n# - description: \"A URL-friendly base62 encoded UUID\"\n```\n\n## Performance\n\nFriendlyID involves a trade-off between CPU overhead and I/O efficiency:\n\n- **CPU**: ~6x slower base62 encoding (~3 microseconds per ID)\n- **I/O**: ~39% bandwidth savings (less than 22 vs 36 characters)\n- **Database**: Uses native UUID storage (no storage overhead)\n\nRun the included benchmark to see detailed performance analysis:\n```bash\npython benchmark.py --count 1000\n```\n\nFor detailed performance analysis, see [PERFORMANCE.md](PERFORMANCE.md).\n\n## Choosing Between FriendlyID and Standard UUID\n\nFriendlyID presents a clear trade-off: **3 microseconds CPU overhead vs 14 characters I/O savings per ID**.\n\n### Consider FriendlyID when:\n- Network bandwidth or data transfer costs are significant\n- User-facing URLs and identifiers matter for UX  \n- Text-based logging and data export are frequent\n- Web APIs where transfer size matters\n- Mobile applications with bandwidth constraints\n\n### Consider Standard UUID when:\n- High-frequency serialization with minimal I/O\n- CPU resources are constrained or critical\n- Existing systems require standard UUID format\n- Microsecond-level performance is essential\n- Real-time systems where every cycle counts\n\n### Evaluation Factors\nConsider your application's specific characteristics:\n- **I/O vs CPU ratio**: How much network/text processing vs computation?\n- **Scale**: Volume of UUID operations vs data transmission\n- **Constraints**: CPU limitations vs bandwidth costs\n- **User experience**: Does identifier readability matter?\n- **Integration**: Compatibility with existing systems\n\nRun the benchmark with your expected workload to get concrete numbers for your specific use case.\n\n## Breaking Changes\n\n**\u26a0\ufe0f Important**: 0.4.0 introduces breaking changes from previous versions:\n\n- `str(FriendlyID)` now returns base62 format instead of standard UUID format\n- Use `.standard` property when you need the standard UUID string format\n- JSON serialization will use base62 format by default\n- Update any code that expects `str(uuid)` to return standard UUID format\n\n## Migration Guide\n\nIf you were using the previous functional API:\n\n```python\n# Old way (no longer available)\nfrom friendly_id import friendly_id, encode, decode\n\nid_str = friendly_id()\nencoded = encode(some_uuid)\ndecoded = decode(some_string)\n\n# New way\nfrom friendly_id import FriendlyID\n\nid_str = str(FriendlyID.random())\nencoded = str(FriendlyID.from_uuid(some_uuid))\ndecoded = FriendlyID.from_friendly(some_string).to_uuid()\n```\n",
    "bugtrack_url": null,
    "license": "Copyright 2022 Junlin Zhou\n        \n        Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n        \n        The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n        \n        THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.",
    "summary": "friendly-id is a Python library to generate really unique and url friendly IDs based on UUID and base62",
    "version": "0.6.1",
    "project_urls": null,
    "split_keywords": [
        "friendly-id",
        " uuid"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "2ed73acb275dd52c5b599ad1aa975b368d93e485a1d36d5c8b878510b0646895",
                "md5": "b3e471e44792ebbf1faaeee276ee677a",
                "sha256": "a645e9e9275802911fe33834d49ca636d1dbd6c89068d7c114d8e720a0a340e5"
            },
            "downloads": -1,
            "filename": "friendly_id-0.6.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "b3e471e44792ebbf1faaeee276ee677a",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 11192,
            "upload_time": "2025-07-25T02:36:27",
            "upload_time_iso_8601": "2025-07-25T02:36:27.895761Z",
            "url": "https://files.pythonhosted.org/packages/2e/d7/3acb275dd52c5b599ad1aa975b368d93e485a1d36d5c8b878510b0646895/friendly_id-0.6.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "7a16616b889e98518b0e3a1e59bd78ba043a0f1c3b2a671a0c2c815d96cf8080",
                "md5": "e4c66ee4d5748fb91a43d15602ea9cb0",
                "sha256": "598be9171700a4feb65f9110dbfc493a4e2b70476b62f691675b9c11f2021282"
            },
            "downloads": -1,
            "filename": "friendly_id-0.6.1.tar.gz",
            "has_sig": false,
            "md5_digest": "e4c66ee4d5748fb91a43d15602ea9cb0",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 20518,
            "upload_time": "2025-07-25T02:36:29",
            "upload_time_iso_8601": "2025-07-25T02:36:29.255376Z",
            "url": "https://files.pythonhosted.org/packages/7a/16/616b889e98518b0e3a1e59bd78ba043a0f1c3b2a671a0c2c815d96cf8080/friendly_id-0.6.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-25 02:36:29",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "friendly-id"
}
        
Elapsed time: 1.07047s