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

This version

1.5.1

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.1-cp313-cp313-musllinux_1_2_x86_64.whl (3.0 MB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ x86-64

ididi-1.5.1-cp313-cp313-musllinux_1_2_i686.whl (2.9 MB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ i686

ididi-1.5.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.8 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

ididi-1.5.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (2.7 MB view details)

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

ididi-1.5.1-cp312-cp312-musllinux_1_2_x86_64.whl (3.0 MB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ x86-64

ididi-1.5.1-cp312-cp312-musllinux_1_2_i686.whl (2.9 MB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ i686

ididi-1.5.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.8 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

ididi-1.5.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (2.7 MB view details)

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

ididi-1.5.1-cp311-cp311-musllinux_1_2_x86_64.whl (2.9 MB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ x86-64

ididi-1.5.1-cp311-cp311-musllinux_1_2_i686.whl (2.8 MB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ i686

ididi-1.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.9 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

ididi-1.5.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (2.8 MB view details)

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

ididi-1.5.1-cp310-cp310-musllinux_1_2_x86_64.whl (2.7 MB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ x86-64

ididi-1.5.1-cp310-cp310-musllinux_1_2_i686.whl (2.6 MB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ i686

ididi-1.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.7 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

ididi-1.5.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (2.6 MB view details)

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

ididi-1.5.1-cp39-cp39-musllinux_1_2_x86_64.whl (2.7 MB view details)

Uploaded CPython 3.9musllinux: musl 1.2+ x86-64

ididi-1.5.1-cp39-cp39-musllinux_1_2_i686.whl (2.6 MB view details)

Uploaded CPython 3.9musllinux: musl 1.2+ i686

ididi-1.5.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.7 MB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ x86-64

ididi-1.5.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (2.6 MB view details)

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

File details

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

File metadata

File hashes

Hashes for ididi-1.5.1-cp313-cp313-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 c8a287ff7c229260bb93d58ddbc5ea1952fb96561d77a678f9a87719a2f8a554
MD5 068642066e5030e906d7ec7e668ebe89
BLAKE2b-256 8c06462887bfc703600183896201d0dd316c714933b635540ff11361465bcc50

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.1-cp313-cp313-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 471cf4b2110b07cf11fb5cb64fa88ba7f6bca5bdd40eaf3eb3ca9e1f0e90719e
MD5 5a842d5811d678ab4053d0c3f3f2cc0f
BLAKE2b-256 0537f51fcfbdc4b534ce0507fecf02637176e41e1042c5ff92020a8eca1ad309

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 900a42553406a182ffa827f7f470c3d283cb9dc82ad356fef287ea8b7f2456fa
MD5 9abf418a677d3caf1fbae725cd0261fd
BLAKE2b-256 53b52e8759122792991c40c607c77dc2c7896e1cb0589fc24a3ff2aea9ccb499

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 0a0f38de0e1bf5f1230c327cb29929a4469ee548778e03d26cae1554c6164df3
MD5 cd142d49e9b12cfaf7860ec512a55d2b
BLAKE2b-256 82d7aa73d072b33897bc245684ec757cf00742e41469b9667170382450ffe996

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.1-cp312-cp312-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 9a89e110611d0c9adc65d5795c7f00a14028fcf6dc34d7edce937c302fd8f80e
MD5 babe69fa553fbaae97199f58c19be6b0
BLAKE2b-256 9980799500188e7159184f3512541d596120c567bc356c0881c330f28cb32708

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.1-cp312-cp312-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 8fec05a5c26d2a1701ff7ae336ef87b282cea67cdacadf2fbb441f3806227b31
MD5 131a713557e259f00d36dac5874cf9e3
BLAKE2b-256 490a4c55b3bfdf9fb6bae2c325caa8170e76151a9bf748c05afb5c62a3b596f7

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 59a4e84f0b4a409a82b46b9118e5ce324ddeab78983baceaba65209813bf3ac9
MD5 b840b7eafa46c56dd43a893715ffe6c1
BLAKE2b-256 1c9e57731724f882fb1f7f42e4cf78c4ac37476f1a2ca4950821e77fd347fbda

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 9774b71d8329a4935f5c86ff54b8e39cfd205fc9acd5f0fc80c993c1ea8bf890
MD5 80656c8afe8e1cec5082f30aff140c96
BLAKE2b-256 39290f5385663372d979c42883cc6502eea03dd2f1497dc9c8ae1e39b684b579

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.1-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 3d1c2ae65cabacc35f1b69b367285dde36d88a40f9392232e2410c0fdae9a999
MD5 2c0b7c5f90c82e1c815b212ec35f171b
BLAKE2b-256 7aba7833f3a2be0ac457f4aadd0fa5e116b573c266faf0a5d0584a935dd9cd8f

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.1-cp311-cp311-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 89de34ed02255e5194ee8d878cfe14e631b53f0862034214191803adc8b8085b
MD5 16a23a90d9e501b4a6e3a22d07208520
BLAKE2b-256 7666b4cbce760119f1609c406af36e4d242c71277cfc8dae341a23e06b6ec1ed

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 4df3eb6a1d105259aeccac1e604aa7e21a4ba7aad4c22c33b9b8ddbdd2dbb1fd
MD5 f8c883746f183f170da5fcac00f91ac4
BLAKE2b-256 27254c47ed8f3b410b13ae3309f1228fac5670e65717efc28ca720acb5a63822

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 8e6036369b47fcf4b766f04622697fe6e3928fa96187572079f87472b55cdb0f
MD5 def97efda174b69de6162c7ffef5e014
BLAKE2b-256 90d1fa5db23813f1dac29ab153cccda348193bfcba161cb002310c04c605a123

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.1-cp310-cp310-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 27fc85a40cd44637a29e277201c82295db2c0efa5af3401a9d9a870173c4be54
MD5 64bca08a3f7f581599a37033a3e8db3e
BLAKE2b-256 b763685f3602c2ce2d9a1817ae41254dfd7ed85538ed07a0e73aa66d17a0c792

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.1-cp310-cp310-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 dd8b22d4b846d21f3416468f9eaf07e040f6b942636adc95169498a4cb8cdd16
MD5 c09440d2df8f62fa033067aed5dfc495
BLAKE2b-256 087bf40a2c1956358198105a072991b8295df1b8a24f01282fb0915aca5035e4

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a07c60c96250d7d600786834051b2e737871729371fec605618f841965660610
MD5 ab1e379c87923dc4053ec03bf871cc8a
BLAKE2b-256 ffc8ec74c7b63522a2495d7f21fea5e5e5ee128a24260e555a29885f6fa226f5

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 dadf5bd08ee2fe7d5624caad429f83eea63664f527295417f369ef665c65033e
MD5 a506b2b84b9dd91d6f6c063aa1e9009b
BLAKE2b-256 2140b3a9dd200b647dc1fe98ab8a3af56cafc83bb5fa7efd61b860f6784cd7b9

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.1-cp39-cp39-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 6103aecb3a2401cc61547ed4319b576628d1668c6d32b62d34ecb8f3a7b1891c
MD5 c41850e398b1660f2ea911baef23f74b
BLAKE2b-256 3d2d7cce02474b48ca5703ce03b0bdedde5ab8fb723829d4eaeb381f43910f80

See more details on using hashes here.

File details

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

File metadata

  • Download URL: ididi-1.5.1-cp39-cp39-musllinux_1_2_i686.whl
  • Upload date:
  • Size: 2.6 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.1-cp39-cp39-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 5b5c6e3b17fbb160c9d2262f76c2a916350db92d2090e1e4fc166a72303a8f80
MD5 bdaa1c103beb86f77773559740fb9f0a
BLAKE2b-256 97886dc243ca33997d9fd5728f7e43cd1c49ef4e6e8420516f64ee1dfbfe28c1

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 67ae36ba6ec041ea9d459738c9d10d4364dccfa381acedff73b34e6379f034f2
MD5 ffc0ae6ca0d1aa9f2a2fd54f249f9e01
BLAKE2b-256 347c8c678e5a40f0ce0f0d322c461e5f51f1db7a6e7728946464375ef56221b1

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 d08580297d94eb5fb73b40ac69ad4e72d21e7fbe33212e627d19d96c213f0497
MD5 08edf0b93d82aa90958dd03a53d81bb7
BLAKE2b-256 a8cc03832f59b3f8da95e41d5aaf98ca2fb72481b0ceaed7cb557fc2ffb24a80

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