files_streaming()

Streams a document’s files chunk-by-chunk directly off the still-open connection — without buffering the whole file in memory or in a temporary file. The counterpart to files(), intended for large documents that should be forwarded (e.g. to an HTTP response or another file) without local caching. The current files are retrieved via std.StoreInCacheById.

files_streaming() is a context manager: the (pooled) connection stays borrowed for the lifetime of the with block. On exit the connection is handled safely (see Connection lifecycle).

The job’s response parameters, errors and return_code are available immediately when the with block is entered — before a single file byte is read. Per-file metadata (name, size, extension) is fixed as soon as iter_files() yields the file, i.e. before its first chunk.

1. Signature

  • Sync

  • Async

with ecm.dms.files_streaming(
    model: ECMDocumentModel | int,
    *,
    flags: int = 1,
    convert: StoreInCacheByIdConversion = StoreInCacheByIdConversion.NONE,
    when_cold_then_tiff: bool = False,
    add_annotations: bool = False,
) as response:  # JobStreamingResponse
    ...
async with ecm.dms.files_streaming(
    model: ECMDocumentModel | int,
    *,
    flags: int = 1,
    convert: StoreInCacheByIdConversion = StoreInCacheByIdConversion.NONE,
    when_cold_then_tiff: bool = False,
    add_annotations: bool = False,
) as response:  # AsyncJobStreamingResponse
    ...

2. Parameters

Parameter Type Default Description

model

ECMDocumentModel | int

The document: either an ECMDocumentModel instance (its id is used) or a plain object ID as int.

flags

int

1

Transfer flags: 0 = document files and DIA file, 1 = document files only (default), 2 = DIA file only.

convert

StoreInCacheByIdConversion

NONE

Optional conversion applied before transfer (see files()).

when_cold_then_tiff

bool

False

If True, ASCII COLD files are returned in TIFF format.

add_annotations

bool

False

If True, image annotations are burned into the returned files.

Unlike files(), files_streaming() does not support version_guid. Use files() for historic versions.

3. Return value

The context manager yields a JobStreamingResponse (sync) or AsyncJobStreamingResponse (async).

Table 1. JobStreamingResponse (excerpt)
Member Description

return_code

Server return code of the job (0 = success).

get(name, type, default=None)

Typed access to a response parameter (like JobResult.get).

errors / error_message

List of JobError / concatenated error message.

iter_files()

Iterator over the response files as StreamedResponseFile. Each file must be fully read before the next begins.

abort()

Marks the response as deliberately abandoned (no IncompleteStreamError on exit).

Table 2. StreamedResponseFile (excerpt)
Member Description

name / extension / size

File metadata, known before the first chunk.

iter_chunks(chunk_size=65536)

Iterator over the file bytes in chunks (default 64 KiB). Updates the running SHA-1 digest and reads the file footer at the end.

skip()

Deliberately discards this file (like response.abort()).

4. Connection lifecycle

The with / async with block always protects the connection:

  • Fully consumed → the trailing SHA-1 digest is validated and the connection returns to the pool.

  • Accidentally partial → the connection is invalidated (socket closed) and an IncompleteStreamError is raised (unless the block is already unwinding another exception, which takes precedence).

  • Deliberately aborted via response.abort() / file.skip() → the connection is invalidated, no error.

5. Examples

5.1. Stream a document to a file

  • Sync

  • Async

with ecm.dms.files_streaming(document) as response:
    assert response.return_code == 0
    for attachment in response.iter_files():
        with open(attachment.name, "wb") as out:
            for chunk in attachment.iter_chunks():
                out.write(chunk)  # no RAM/temp buffer
async with ecm.dms.files_streaming(document) as response:
    async for attachment in response.iter_files():
        with open(attachment.name, "wb") as out:
            async for chunk in attachment.iter_chunks():
                out.write(chunk)

5.2. Compute a checksum on the fly

import hashlib

digest = hashlib.sha256()
with ecm.dms.files_streaming(document) as response:
    for attachment in response.iter_files():
        for chunk in attachment.iter_chunks(chunk_size=1024 * 1024):
            digest.update(chunk)
print(digest.hexdigest())

5.3. Deliberate early abort

with ecm.dms.files_streaming(document) as response:
    first = next(response.iter_files())
    header = next(first.iter_chunks())  # only the first bytes
    response.abort()                    # discard the rest on purpose -> no error

6. Comparison with files() and document_stream()

Aspect files() document_stream() files_streaming()

Result type

List of JobResponseFile

bytes (one byte range)

JobStreamingResponse (context manager)

Buffering

RAM or temp file

RAM (the read range)

None — straight off the socket

Multiple files

Yes

No

Yes (file-by-file)

Server job

std.StoreInCacheById

std.GetDocumentStream

std.StoreInCacheById

7. See also