• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

crashvb / docker-registry-client-async / 4006410034

pending completion
4006410034

Pull #32

github

GitHub
Merge 4001ff095 into 58922d658
Pull Request #32: Fixed image resolution for familiar references

1 of 1 new or added line in 1 file covered. (100.0%)

541 of 757 relevant lines covered (71.47%)

2.14 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

74.29
/docker_registry_client_async/utils.py
1
#!/usr/bin/env python
2

3
"""Utility classes."""
3✔
4

5
import hashlib
3✔
6
import os
3✔
7

8
from functools import wraps, partial
3✔
9

10
import asyncio
3✔
11

12
from aiohttp import ClientResponse
3✔
13

14
from .formattedsha256 import FormattedSHA256
3✔
15
from .typing import UtilsChunkToFile
3✔
16

17
# https://github.com/docker/docker-py/blob/master/docker/constants.py
18
CHUNK_SIZE = int(os.environ.get("DRCA_CHUNK_SIZE", 2097152))
3✔
19

20

21
def async_wrap(func):
3✔
22
    """Decorates a given function for execution via an executor."""
23
    # https://dev.to/0xbf/turn-sync-function-to-async-python-tips-58nn
24
    @wraps(func)
3✔
25
    async def run_in_executor(*args, loop=None, executor=None, **kwargs):
3✔
26
        if loop is None:
3✔
27
            loop = asyncio.get_event_loop()
3✔
28
        partial_func = partial(func, *args, **kwargs)
3✔
29
        return await loop.run_in_executor(executor, partial_func)
3✔
30

31
    return run_in_executor
3✔
32

33

34
async def be_kind_rewind(file, *, file_is_async: bool = True):
3✔
35
    """
36
    Reset the file position (offset) to the absolute beginning.
37
    Args:
38
        file: The file for which to reset the offset.
39
        file_is_async: If True, all file IO operations will be awaited.
40
    """
41
    if file_is_async:
3✔
42
        coroutine = file.seek(0)
3✔
43
    else:
44
        coroutine = async_wrap(file.seek)(0)
3✔
45
    await coroutine
3✔
46

47

48
async def chunk_to_file(
3✔
49
    client_response: ClientResponse, file, *, file_is_async: bool = True
50
) -> UtilsChunkToFile:
51
    """
52
    Asynchronously stores file chunks to a given file.
53

54
    Args:
55
        client_response: The client response from which to read the file chunks.
56
        file: The file to which to store the file chunks.
57
        file_is_async: If True, all file IO operations will be awaited.
58

59
    Returns:
60
        dict:
61
            client_response: The underlying client response.
62
            digest: The digest value of the chunked data.
63
            size: The byte size of the chunked data in bytes.
64
    """
65
    # https://docs.aiohttp.org/en/stable/streams.html
66
    hasher = hashlib.sha256()
×
67
    size = 0
×
68
    # TODO: Do we need to use a max chunk size here (i.e. switch from iter_chunks() to iter_chunked)?
69
    coroutine = file.write if file_is_async else async_wrap(file.write)
×
70
    async for chunk, _ in client_response.content.iter_chunks():
×
71
        await coroutine(chunk)
×
72
        hasher.update(chunk)
×
73
        size += len(chunk)
×
74

75
    await be_kind_rewind(file, file_is_async=file_is_async)
×
76

77
    return UtilsChunkToFile(
×
78
        client_response=client_response,
79
        digest=FormattedSHA256(hasher.hexdigest()),
80
        size=size,
81
    )
82

83

84
def must_be_equal(
3✔
85
    expected,
86
    actual,
87
    msg: str = "Actual value does not match expected value",
88
    *,
89
    error_type=RuntimeError,
90
):
91
    """
92
    Compares two values and raises an exception if they are not equal.
93

94
    Args:
95
        expected: The expected value.
96
        actual: The actual value.
97
        msg: Message describing the context of the comparison.
98
        error_type: The type of exception to be raised if not equal.
99
    """
100
    if actual != expected:
3✔
101
        raise error_type(f"{msg}: {actual} != {expected}")
3✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc