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.2

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.2-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.2-cp313-cp313-musllinux_1_2_i686.whl (2.9 MB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ i686

ididi-1.5.2-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.2-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.2-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.2-cp312-cp312-musllinux_1_2_i686.whl (2.9 MB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ i686

ididi-1.5.2-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.2-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.2-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.2-cp311-cp311-musllinux_1_2_i686.whl (2.8 MB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ i686

ididi-1.5.2-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.2-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.2-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.2-cp310-cp310-musllinux_1_2_i686.whl (2.6 MB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ i686

ididi-1.5.2-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.2-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.2-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.2-cp39-cp39-musllinux_1_2_i686.whl (2.6 MB view details)

Uploaded CPython 3.9musllinux: musl 1.2+ i686

ididi-1.5.2-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.2-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.2-cp313-cp313-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for ididi-1.5.2-cp313-cp313-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 8718486d8bb5d9c30fde710bf0cd353be20406d5f5ddd11541695c62e007a7e4
MD5 1d32c6c1bb4f8fc721acd01e33de7d06
BLAKE2b-256 d443868fd4ab4db99e31272c37a5e3999c26ac0c99b4545de387011137c9d08b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.2-cp313-cp313-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 c118cc95079eb18396518b9bf466de9f96c601140cab18a5cd18c3a2001e5f71
MD5 38370f41f8ec7ae5d0274c0fc549418b
BLAKE2b-256 90b4e41add3f64c609d462b43bf5c2c76c9c70a970b9602c8362ce06db06508a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 ccd2230ebb79c474d1f831bd55e762d4a0f20baf4973af6564af9a8059de62f1
MD5 41a87d74dc57e2b86cacf022d879185e
BLAKE2b-256 78da2ba39b3d09247b3994623abc8eff963f3f0d1fecb47c18d37532c8558cd0

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 fec0a3bd320358f60e667a43c75d0268fc1758ddb01feda1733a520aef74a9da
MD5 4ab7cb45a9c19abb8c2ad09526293154
BLAKE2b-256 285d32f6812afc0d88bd7bbffd5703887ba5b0183ecda690a17e38240798ba71

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.2-cp312-cp312-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 3f95a5d1f6361b2bdce7bfc83fd9a1e7b3855d7306aeb53f91e67b28dd4b0674
MD5 0288cec19ad56ecb9fcc6ef2a277ef21
BLAKE2b-256 7a7834a9ee6d2068b4fe1f7b559313b7bf205f54459909b620246cc3ec5be851

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.2-cp312-cp312-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 9146bb3530f78dbc080d1f7e9103c5881dbcfd1a0b5192219157249e124aeb77
MD5 a19615ca03ad0381ef3e01c6705bcfe7
BLAKE2b-256 877798322037c4998a3d3034637a0984cedd6f056d8bc4c118584c1b839fd190

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a166b1927470b12419de953bb889fa316a5882e89c762cdd7ae176ac020efa3a
MD5 358584f766cfb414dbac49e94aca3182
BLAKE2b-256 89bd924fdc1504716d8a289766bb61c47089bc440cf9b160ba869a0afb53a344

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 d375c88c00d088573105e59383103bbb3b0508129bcd70daa8ecb3e3acb6144a
MD5 7c1dd28e60847f0d63b7e7186fdb4c04
BLAKE2b-256 1733275abd1fe12b4d2cdf269d6f3c0ac2433d553bec6e202481ab9866bf49b7

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.2-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 5d05e3db7feb791bebd5100abe51648d0c6fd4eab018290c9cdd996809650bac
MD5 80debdaa0b8e5ae1904c848761c259f6
BLAKE2b-256 48124dbb9edf4d71649c2073c18b1ed51f3437e758c5a4e6daa522edbd9a0a11

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.2-cp311-cp311-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 00e21484adaca83b3276586361fedb82149b29fce9f65db9c465245fbe96d5b6
MD5 47fd6254025054efb4c1280699bb0a5b
BLAKE2b-256 6e3748acb74d090ba0c06d6e3302442d3996f4355421d1897d5dbcfa6ebcc23f

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 4f44384f93462a22ba15c5ee30f4e8fa8a4e6b5f4ae3e5af2b2a78ce92648b01
MD5 b88c95329d1684e9ac43ed376ccf7e2d
BLAKE2b-256 ef4e57803769d4c0683e66d10ab394f997611618b3966e83cd28698d7cd11168

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 ce6782c025888a78431059097c201f7eaa1fa2f7282adea781585251ea422df1
MD5 efb16b58ebe9c582576f7984b809a4d9
BLAKE2b-256 46da02076726aa0fb470478581e1a21988e74a4bdc85e95a4c49c650b5eec6b0

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.2-cp310-cp310-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 c6776cb051ff5e2c1d573ad7646fa8d87b34a5752ab2ecf1e051adb012c16ff0
MD5 f88f54f3d8d1574b1b49055c071e6a61
BLAKE2b-256 1c197118de06ebc3e18334aac5ddced857ea536d58d6b65e9bb6bd5df297ede7

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.2-cp310-cp310-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 8bf355200a50df5ca5c262e0c21c226f76ae49e7e141344ebef38c3097e8e886
MD5 12acf16f9065f3fe438cc8d2d583283b
BLAKE2b-256 545d3fd7b727cea3682f272453c622cd6379c3b28c881261227e6d481720d07e

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 2291d10116ec646f19cab66ae128bb4326c34baa6088902064ee0df348df806b
MD5 5adb61966b1d918aae94c7ebd8b244e8
BLAKE2b-256 bf96ad3f65b137a9fb4d809448f64a3bad7e1600415677538e0d188d1049470d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 56faef9b7f9b13a88acae788a438062d5fd8d6a935cab98a338438ea79b485f9
MD5 5ea2d6c29a060401fb07627a6a825983
BLAKE2b-256 33f19110f8172180a243463b6f0062af77bb0523b81c599229800547e4157e57

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.2-cp39-cp39-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 ecccefc1e59a71a42a19fc58d6ea6392e91443c60f9966746e4ebbbadcb048db
MD5 b859ee57877ec4c9dae9e2dfd3f08b2d
BLAKE2b-256 8d84fb3fb1b9652662f90ec47540144369214da1413f9b7e3203da03c62c48d5

See more details on using hashes here.

File details

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

File metadata

  • Download URL: ididi-1.5.2-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.2-cp39-cp39-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 e5166e5158afbeabde08b59593cb25d0bdbdaba27f44701192ba5eadfcd55f22
MD5 c3bb46bdf62a0898a8ec047fb0ec7d7d
BLAKE2b-256 a588fe73fefccfcaf6ef3b4ad26dd3872dbc0dfd91f411549b74979ed5378992

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 75399cf7106ef9b910e63541a1fc3bad3688cb688cb11c50b87d8c2e56bc15e2
MD5 874a24701b3f1f6231e03a79e75e567a
BLAKE2b-256 d4b42ce6c3e3f67781b5c6b5e33e44d19738368040a586ad600af535c388948d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ididi-1.5.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 b7f433d4c0f421c8856cda0289a5d79f48ae0df4027136a5443b40a47d49c840
MD5 1bcc0afa137afd23edcd548d7d1edce7
BLAKE2b-256 89a8c5e4064c7f8f3a5b899f2d602b679f205c6027b84902119ca133b7824a05

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