Skip to main content

A dependency injection library for Python, Optimized for serverless applications

Project description

Ididi

Genius simplicity, unmatched power

ididi is 100% test covered and strictly typed.

codecov PyPI version Python Version License Downloads


Documentation: https://raceychan.github.io/ididi

Source Code: https://github.com/raceychan/ididi


Install

ididi requires python >= 3.9

pip install ididi

To view viusal dependency graph, install graphviz

pip install ididi[graphviz]

Features

  • Powerful: Ididi does what alternatives do, and also provides features that others don't.
  • Performant: almost as fast as hard-coded factories, one of the fastest dependency injection framework available.
  • Noninvasive: No / minial changes to your existing code
  • Smart: inject dependency based on type hints, with strong support to typing module.
  • Correct, strictly typed, well-organized exceptions, well-formatted and detail-rich error messages

TypingSupport

ididi has strong support to typing module, includes:

  • TypedDict
  • Unpack
  • NewType
  • Annotated
  • Literal
  • Optional
  • Union

...and more.

Check out tests/features/test_typing_support.py for examples.

Usage

Quick Start

from typing import AsyncGenerator
from ididi import use, entry

async def conn_factory(engine: AsyncEngine) -> AsyncGenerator[AsyncConnection, None]:
    async with engine.begin() as conn:
        yield conn

class UnitOfWork:
    def __init__(self, conn: AsyncConnection=use(conn_factory)):
        self._conn = conn

@entry
async def main(command: CreateUser, uow: UnitOfWork):
    await uow.execute(build_query(command))

# note uow is automatically injected here
await main(CreateUser(name='user'))

To resolve AsyncConnection outside of entry function

from ididi import Graph

dg = Graph()

async with dg.ascope():
    conn = await scope.resolve(conn_factory)

Key Concepts

Marks

ididi provides two marks, use and Ignore, they are convenient shortcut for Graph.node. Technically, they are just metadata carried by typing.Annotated, and should work fine with other Annotated metadata.

use

You can use Graph.node to register a dependent with its factory, here we register dependent Database with its factory db_factory. This means whenver we call dg.resolve(Database), db_factory will be call.

def db_factory() -> Database:
    return Database()

dg = Graph()
dg.node(db_factory)

Alternatively, you can annotate it inside __init__, this allow you to instantiate Graph in a lazy manner.

from ididi import use
class Repository:
    def __init__(self, db: Annotated[Database, use(db_factory)]):
        ...

Ignore

ididi takes a "resolve by default" approach, for dependencies you would like ididi to ignore, you can config ididi to ignore them.

  • Ignore at Graph level
from datetime import datetime
from pathlib import Path

dg = Graph(ignore=(datetime, Path))
  • Ignore at Node level
dg = Graph()
class Clock:
    def __init__(self, dt: datetime): ...

dg.node(Clock, ignore=datetime)

Alternatively, you can mark a dependency using ididi.Ignore,

from ididi import Ignore

class Clock:
    def __init__(self, dt: Ignore[datetime]): ...

Function dependency

Declear a function as a dependency by using Ignore to annotate its return type.

@dataclass
class User:
    name: str
    role: str

def get_user(config: Config) -> Ignore[User]:
    assert isinstance(config, Config)
    return User("user", "admin")

def validate_admin(
    user: Annotated[User, use(get_user)], service: UserService
) -> Ignore[str]:
    assert user.role == "admin"
    assert isinstance(service, UserService)
    return "ok"

class Route:
    def __init__(self, validte_permission: Annotated[str, use(validate_admin)]):
        assert validte_permission == "ok"

assert dg.resolve(validate_admin) == "ok"
assert isinstance(dg.resolve(Route), Route)

Since get_user returns Ignore[User] instead of User, it won't be used as factory to resolve User.

Dependency factory

from ididi import use
from typing import NewType
from datetime import datetime, timezone

UserID = NewType("UserID", str)

def utc_factory() -> datetime:
    return datetime.now(timezone.utc)

def user_id_factory() -> UserID:
    return UserID(str(uuid4()))

class User:
    def __init__(self, user_id: UserID, created_at: Annotated[datetime, use(utc_factory)]):
        self.user_id = user_id
        self.created_at = created_at

user = ididi.resolve(User)
assert user.created_at.tzinfo == timezone.utc

[!TIP] Graph.node accepts a wide arrange of types, such as dependent class, sync/async facotry, sync/async resource factory, with typing support.

Scope

Scope is a temporary view of the graph specialized for handling resources.

In a nutshell:

  • Scope can access(read-only) registered singletons and resolved instances of its parent graph
  • Dependents registered/resolved in a scope will stay in the scope.
  • its parent graph can't access its registered singletons and resolved resources.

Using Scope to manage resources

  • Infinite number of nested scope
  • Parent scope can be accssed by its child scopes(within the same context)
  • Resources will be shared across dependents only withint the same scope
  • Resources will be automatically closed when the scope is exited.
  • Classes that implment contextlib.AbstractContextManager or contextlib.AbstractAsyncContextManager are also considered to be resources and can/should be resolved within scope.
  • Scopes are separated by context

[!TIP] If you have two call stack of a1 -> b1 and a2 -> b2, Here a1 and a2 are two calls to the same function a, then, in b1, you can only access scope created by the a1, not a2.

This is particularly useful when you try to separate resources by route, endpoint, request, etc.

Async scope

@dg.node
def get_resource() -> ty.Generator[Resource, None, None]:
    res = Resource()
    with res:
        yield res

@dg.node
async def get_asyncresource() -> ty.Generator[AsyncResource, None, None]:
    res = AsyncResource()
    async with res:
        yield res


with dg.scope() as scope:
    resource = scope.resolve(Resource)

# For async generator
async with dg.ascope() as scope:
    resource = await scope.resolve(AsyncResource)

[!TIP] dg.node will leave your class/factory untouched, i.e., you can use it as a function. e.g. dg.node(get_resource, reuse=False)

Contexted Scope

You can use dg.use_scope to retrive most recent scope, context-wise, this allows your to have access the scope without passing it around, e.g.

async def service_factory():
    async with dg.ascope() as scope:
        service = scope.resolve(Service)
        yield service

@app.get("users")
async def get_user(service: Service = Depends(service_factory))
    await service.create_user(...)

Then somewhere deep in your service.create_user call stack

async def create_and_publish():
    uow = dg.use_scope().resolve(UnitOfWork)
    async with uow.trans():
        user_repo.add_user(user)
        event_store.add(user_created_event)

Here dg.use_scope() would return the same scope you created in your service_factory.

Named Scope

You can create infinite level of scopes by assigning hashable name to scopes

# at the top most entry of a request
async with dg.ascope(request_id) as scope:
    ...

now scope with name request_id is accessible everywhere within the request context

request_scope = dg.use_scope(request_id)

[!NOTE] Two or more scopes with the same name would follow most recent rule.

Nested Nmaed Scope

async with dg.ascope(app_name) as app_scope:
    async with dg.ascope(router_name) as router_scope:
        async with dg.ascope(endpoint_name) as endpoint_scope:
            async with dg.ascope(user_id) as user_scope:
                async with dg.ascope(request_id) as request_scope:
                    ...

For any functions called within the request_scope, you can get the most recent scope with dg.use_scope(), or its parent scopes, i.e. dg.use_scope(app_name) to get app_scope.

Testing

Override class dependency resolution

You can control how ididi resolve a dependency during testing, by register the test double of the dependency using

  • Graph.override
  • entry.replace

Example: For the following dependent

class UserRepository:
    def __init__(self, db: DataBase):
        self.db=db

dg = Graph()
assert isinstance(dg.resolve(UserRepository).db, DataBase)

in you test file,

class FakeDB(DataBase): ...

def db_factory() -> DataBase:
    return FakeDB()


def test_resolve():
    dg = Graph()
    assert isinstance(dg.resolve(db_factory).db, DataBase)

    dg.override(DataBase, db_factory)
    assert isinstance(dg.resolve(UserRepository).db, FakeDB)

Use Graph.override to replace DataBase with its test double.

Override entry dependency resolution

async def test_entry_replace():
    @ididi.entry
    async def create_user(
        user_name: str, user_email: str, service: UserService
    ) -> UserService:
        return service

    class FakeUserService(UserService): ...

    create_user.replace(UserService, FakeUserService)

    res = await create_user("user", "user@email.com")
    assert isinstance(res, FakeUserService)

Use entryfunc.replace to replace a dependency with its test double.

Graph.override vs entry.replace

Graph.override applies to the whole graph, entry.replace applies to only the entry function.

More

For more detailed information, check out Documentation

  • Tutorial

  • Usage of factory

  • Visualize the dependency graph

  • Circular Dependency Detection

  • Error context

Project details


Release history Release notifications | RSS feed

Download files

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

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

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

ididi-1.5.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (926.1 kB view details)

Uploaded PyPymanylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

ididi-1.5.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (928.8 kB view details)

Uploaded PyPymanylinux: glibc 2.17+ i686manylinux: glibc 2.5+ i686

ididi-1.5.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (925.3 kB view details)

Uploaded PyPymanylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

ididi-1.5.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (927.7 kB view details)

Uploaded PyPymanylinux: glibc 2.17+ i686manylinux: glibc 2.5+ i686

ididi-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl (3.2 MB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ x86-64

ididi-1.5.0-cp313-cp313-musllinux_1_2_i686.whl (3.1 MB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ i686

ididi-1.5.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.0 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

ididi-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (2.8 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ i686manylinux: glibc 2.5+ i686

ididi-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl (3.2 MB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ x86-64

ididi-1.5.0-cp312-cp312-musllinux_1_2_i686.whl (3.2 MB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ i686

ididi-1.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.0 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

ididi-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (2.8 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ i686manylinux: glibc 2.5+ i686

ididi-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl (3.0 MB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ x86-64

ididi-1.5.0-cp311-cp311-musllinux_1_2_i686.whl (3.0 MB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ i686

ididi-1.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.0 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

ididi-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (2.9 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ i686manylinux: glibc 2.5+ i686

ididi-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl (2.8 MB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ x86-64

ididi-1.5.0-cp310-cp310-musllinux_1_2_i686.whl (2.7 MB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ i686

ididi-1.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.8 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

ididi-1.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (2.7 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ i686manylinux: glibc 2.5+ i686

ididi-1.5.0-cp39-cp39-musllinux_1_2_x86_64.whl (2.8 MB view details)

Uploaded CPython 3.9musllinux: musl 1.2+ x86-64

ididi-1.5.0-cp39-cp39-musllinux_1_2_i686.whl (2.7 MB view details)

Uploaded CPython 3.9musllinux: musl 1.2+ i686

ididi-1.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.8 MB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ x86-64

ididi-1.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (2.7 MB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ i686manylinux: glibc 2.5+ i686

File details

Details for the file ididi-1.5.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for ididi-1.5.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 4ae14d57e289160811abea7e176814fba6f15572b3b11953af9253deab45893e
MD5 b3df5a64d7a6fb52705015aad3afaec1
BLAKE2b-256 5d501c66b18f577d88285775cee5e68559766ece1652014dfcf7ebd61e02ee3e

See more details on using hashes here.

File details

Details for the file ididi-1.5.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for ididi-1.5.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 2c626b767ca0caa32b4d7e36357ea8f7aec683bb3b32b02eea726c640baa01ab
MD5 f182689b5c76d63de9ae70049483a2ef
BLAKE2b-256 af476e67c380678450a3aca3d91dfe0c2008930a83459f36fb38ea207cb831b0

See more details on using hashes here.

File details

Details for the file ididi-1.5.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for ididi-1.5.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 d89c1bb6cb9459abbd53aaebc1530a08af568470e83f3d3d7dea4441c06ede8f
MD5 cdd3704f08bd7b5c810a0261dc2ab3a4
BLAKE2b-256 35bdd7010ff91c58eaa7884f9a6c2bd96802155d36784a7507b75b1de20450be

See more details on using hashes here.

File details

Details for the file ididi-1.5.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for ididi-1.5.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 5c2750255048e1b8338811a0dceddf97d0be557791d9004929921ef84c38d1ab
MD5 72a7c49847e719587282c9e483ba9849
BLAKE2b-256 1133309909d2755806b055e3a15833c4a61ce77aacb29e6eb967b5344968d195

See more details on using hashes here.

File details

Details for the file ididi-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for ididi-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 5512bd382e0201106c52de44d938be90c331fad12566f797b31aa45cf9f7ae76
MD5 ca42f4031c387e2405c5e1bc4f69b019
BLAKE2b-256 3133e10e7b7512a09a9f855e3fb0824bcdddb6f5ec8934624d014e547fd06010

See more details on using hashes here.

File details

Details for the file ididi-1.5.0-cp313-cp313-musllinux_1_2_i686.whl.

File metadata

File hashes

Hashes for ididi-1.5.0-cp313-cp313-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 7fdc724edd74d4c32ca1d13b5dfa873ea3a1921f32c0a568da1e48a334398b17
MD5 6f8311ceb7b04ebf8740883767251747
BLAKE2b-256 dc084853183ade7a8f94fae4f6e5cd47d91d82cb5d2cbd08ad360457fedb2322

See more details on using hashes here.

File details

Details for the file ididi-1.5.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for ididi-1.5.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 c3843df78332e99567847c58bb74fa591185c64ee58365dc120da74f08039b52
MD5 0900dd397e738bc45ddc4e1f9b475c6e
BLAKE2b-256 254bcdb915680b2321560ebe5fd88d63ce25fcb7549df605b2a7816341e78470

See more details on using hashes here.

File details

Details for the file ididi-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for ididi-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 d7dad981e3654f31d2e0f88b2e701c20a62ec820c61dd597da1e9661b619a0e7
MD5 1670deb159a97e5ef832442ea2708153
BLAKE2b-256 aa2f81ee710caf6650640a888ff33135b0d93fca10ff95f6d19fbe01cb26dc40

See more details on using hashes here.

File details

Details for the file ididi-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for ididi-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 1ccc45d03933ba5339253dcc74979c0abc69f2754c0517546a28f45a7358987d
MD5 36e202fb0a6886c33f0bbc7363f9ecbd
BLAKE2b-256 16771c011b2db8479f820381aba9948830a712c21b8d16fd8bc5bc6e3648515e

See more details on using hashes here.

File details

Details for the file ididi-1.5.0-cp312-cp312-musllinux_1_2_i686.whl.

File metadata

File hashes

Hashes for ididi-1.5.0-cp312-cp312-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 0371476ea64d9c9f74b04f00f0e7961c29dc59edcdd25f2e17b021e162a88673
MD5 79785fa9b264cf1572de3279459c932e
BLAKE2b-256 86278e9f1cc604c85053034779ae2bf4b28d0cba52eae080d42c738e2b5a52f1

See more details on using hashes here.

File details

Details for the file ididi-1.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for ididi-1.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 d047df697d668439929efdc7994912ba8603eb5659171455cbff5f925bc3825f
MD5 5d33e8230e7bde386f28b75a493d9397
BLAKE2b-256 0bea6460556eb2933cc6742417ec741427427f48948601ff3404c69edd93a886

See more details on using hashes here.

File details

Details for the file ididi-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for ididi-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 fe2aee7e6cd028aba3b33b8f454356554b610bc0f79ae28cdc105861a8b9e3b0
MD5 921c2e8fb74e055acf4a85070865ab93
BLAKE2b-256 7e27d07e2ea1597eb8db5491d58b91104c65d1c66bb4a5db899e31fbadd2fed9

See more details on using hashes here.

File details

Details for the file ididi-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for ididi-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 02225265c1d6918b7862d39efb067ece0a8db2550a77f69c97e5894ef3d8616d
MD5 d8c3affd7a840057bba2b76df4ba1a65
BLAKE2b-256 b434c4e8a364943eb6cd6314dff7ca599cfecfac7df93b2fb3911e1c83750883

See more details on using hashes here.

File details

Details for the file ididi-1.5.0-cp311-cp311-musllinux_1_2_i686.whl.

File metadata

File hashes

Hashes for ididi-1.5.0-cp311-cp311-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 a3fa4807b337a061bc489f356aa3cc478e4c1a74ccdebce12098b6e5b356aee1
MD5 1657a4dc050f68b9bc8620253a8f2667
BLAKE2b-256 edd2eda1c75015281c2a8f210dc56e74884e4f788403dd84991a554351e0041f

See more details on using hashes here.

File details

Details for the file ididi-1.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for ididi-1.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 30562dbd03a89215208ce2ac2e30d92187eb18cffb0087826637a5564e88473d
MD5 a32a9b4fbf996a7f5bb6c1dfa3c9a056
BLAKE2b-256 53b8e1b57103bfcfe2dd64c0ac3082dcadccf8949d8d4e4c463dc56f234d1419

See more details on using hashes here.

File details

Details for the file ididi-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for ididi-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 ade5ee7f9b817164afbb67ad4fc5914095c070763db47b94bfd6b0ad66ef5a7c
MD5 db77c4b1d255c854f11b4f792728daec
BLAKE2b-256 ed20ae60047dc7c331ef6877536f8f47b9c52a49e0b60a49e0cb718ca8ad3d9b

See more details on using hashes here.

File details

Details for the file ididi-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for ididi-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 3b940b92ac6f73b18e887e70b70114d9269e843aeea9100a0d57f0143c90537a
MD5 1970087c9155354f72fdcef08710d8bb
BLAKE2b-256 9e026eff3142479943e6d44336c20dfb27d4262ef615fcc0d48946e706bef6ad

See more details on using hashes here.

File details

Details for the file ididi-1.5.0-cp310-cp310-musllinux_1_2_i686.whl.

File metadata

File hashes

Hashes for ididi-1.5.0-cp310-cp310-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 d553c416040a08ebb8a087477bc160726f2074cee57dab1ab3aa14cc2b148a70
MD5 03a3f1a9e76ea79d246b1ac2d94b4da8
BLAKE2b-256 b40c93790550020317b738efc72b3d4410deac4d513661aacb3f4742174ce629

See more details on using hashes here.

File details

Details for the file ididi-1.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for ididi-1.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 eeefde570940a3e21db517e881ad4f129a0d47d727ae7e879d9dd6095ca04872
MD5 1cca86410265813b329e1bbf7183a2c9
BLAKE2b-256 c0c9dde5bb55290be2ea93c8e0b9a6850cd110d71ebcd000bb05edeb15f60731

See more details on using hashes here.

File details

Details for the file ididi-1.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for ididi-1.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 1e2f1f793a665184c528bdf16cf3871294667ecd5e96fd9e598807a90414f158
MD5 bffaf2c376d9eb1447cb5ff64f8de37a
BLAKE2b-256 3c192c28b13ef4ff896033e384b5e59dddf70eb685720c2500f3680f5e92c8b9

See more details on using hashes here.

File details

Details for the file ididi-1.5.0-cp39-cp39-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for ididi-1.5.0-cp39-cp39-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 188dfd557127c7de98287f708a25a72f82e314d2d1ba933888261ad635b7385b
MD5 b2082f3f862a5b84600026bc3811b717
BLAKE2b-256 0de2279fb4ee8de6712fe15b122d80ee16baae3687d549e610b4c1aaf3f79d6e

See more details on using hashes here.

File details

Details for the file ididi-1.5.0-cp39-cp39-musllinux_1_2_i686.whl.

File metadata

  • Download URL: ididi-1.5.0-cp39-cp39-musllinux_1_2_i686.whl
  • Upload date:
  • Size: 2.7 MB
  • Tags: CPython 3.9, musllinux: musl 1.2+ i686
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.9.0

File hashes

Hashes for ididi-1.5.0-cp39-cp39-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 5f24b7f056136ec994a257f7d47032902abb983b113b86e476bdb4d28c251cf6
MD5 6aad968b4cc562b5aa6088b9fd5396f5
BLAKE2b-256 a084c32f7f76c08cb3f9176434c357d52691482c65b63d15138dcfcd179b2e00

See more details on using hashes here.

File details

Details for the file ididi-1.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for ididi-1.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 63fc4a799a80581a657018fda933401ab55f18817d1b1ccd19c3ad332f605496
MD5 7ba3366802410520f2123a723ffabcbb
BLAKE2b-256 18832d531a022537345e02ad5d2b4e72d734c26789d10aba84a4bcaa5fdd4027

See more details on using hashes here.

File details

Details for the file ididi-1.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for ididi-1.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 337152f33ba1e76a003d0f6bd8c57e7fb51fb3873eaa970ca691e556a2032af6
MD5 b4aa97eb67b7456ee0b3326877786295
BLAKE2b-256 fc6e580032875e1ddc1c0c596d90efd95a456d2a62d73ef19118872383d6c154

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