mrkeyoor.com_
Sun 20 Sept 11:44 UTC
PyPIDataupdated 20 Sept 2026

smart-open review

smart-open 8.0.1 makes remote objects look like Python file handles. Its open function reads and writes local paths, S3, Google Cloud Storage, Azure Blob Storage, HDFS, WebHDFS, and SSH-family URIs, while HTTP is read-only. Iteration and chunked reads let callers consume a large object without first loading all of it, and filename suffixes can select gzip, bzip2, xz, zstd, or LZ4 compression. The 8.0.1 patch fixes the compression_kwargs documentation, lists transport dependencies in built-in help, and fills missing major-version migration notes. Our Python 3.12 import completed in 0.49 seconds and the package shipped py.typed.

Verdict

smart-open 8.0.1 installed in 0.2 seconds and occupied 2 MB in our sandbox, with a 0.49-second import and no pip-audit findings. It fits code that wants one streaming file handle across local and remote objects; choose fsspec once listing, globbing, deletion, or caching enters the requirement.

We installed it

Lab card: what happened when we installed smart-openScreenshot of smart-open documentation
Install✓ · 0.2s2 packages on disk · 2 MB
Importimport smart_open in 0.49s · pure Python · py.typed · requires Python <4.0,>=3.10
Known vulns0(pip-audit)

Answers from our run

Does smart-open install cleanly?

Yes. In a fresh container with an empty cache, pip install smart-open finished in 0.2s, leaving 2 packages and 2 MB on disk. pip-audit reported no known vulnerabilities.

What does smart-open need to run?

Python <4.0,>=3.10, and nothing compiled: it is pure Python. In our run import smart_open succeeded in 0.49s, and the package ships py.typed for type checkers.

smart-open or fsspec: which should you use?

fsspec: Choose it when the same backend abstraction also needs listing, globbing, deletion, caching, or filesystem objects. smart-open 8.0.1 installed in 0.2 seconds and occupied 2 MB in our sandbox, with a 0.49-second import and no pip-audit findings.

When should you not use smart-open?

The application needs list, glob, delete, rename, or directory semantics; fsspec and s3fs expose filesystem operations that smart-open's open function does not

API stability3/5The central smart_open.open call and file-handle behavior remain familiar, but version 8 removed several compatibility shims: smart_open.smart_open, the top-level s3_iter_bucket alias, concurrency.create_pool, and old custom-endpoint URI forms. The repository maintains a MIGRATING document across major releases, and 8.0.1 repaired gaps for versions 2, 4, and 7. Teams crossing a major should search imports and URI construction rather than assuming open is the only affected name.
Docs3/5The README gives executable examples for local files, S3, GCS, Azure, HDFS, HTTP, explicit clients, multipart choices, compression overrides, and custom compressors. Version 8.0.1 also puts missing external dependencies into help.txt and corrects the compression_kwargs docstring. Detailed parameters live in a generated text reference and help('smart_open') instead of a structured documentation site, which makes an unfamiliar transport slower to scan.
Maintenance5/5Version 8.0.1 shipped on 2026-07-15 and the repository was pushed on 2026-08-04. The patch repaired migration history, compression documentation, and transport dependency help after the version 8 cleanup. GitHub displayed only 3 open issues and pull requests combined alongside 3,457 stars. The small queue and recent release are good signs, though a low open count says nothing by itself about how many people can maintain every cloud SDK integration.
Ecosystem4/5The stored package count is 18,044,772 weekly downloads, and GitHub showed 3,457 stars during research. Extras connect the same open call to S3, GCS, Azure, HTTP, SSH, WebHDFS, zstd, and LZ4, while local files fall back to Python's built-in behavior. That range is useful for streaming, but it remains narrower than fsspec because discovery, directory operations, caching, and higher-level dataframe integration are outside its main interface.

Use it if

  • One reader or writer must accept local paths in development and cloud object URIs in deployed jobs
  • Large text or binary objects should be processed through iteration or bounded reads instead of one full download
  • Compression should follow .gz, .bz2, .xz, .zst, or .lz4 suffixes while the caller keeps a file-object API
  • S3 upload code only needs a stream and can avoid repeated boto3 file-wrapper plumbing
Skip it if

Setup reality

We installed smart-open 8.0.1 on Python 3.12 in 0.2 seconds. The clean environment contained 2 packages and used 2 MB afterward; pip-audit found 0 known vulnerabilities. Our package inspection counted 26 direct dependencies, requires Python 3.10 or newer, and identified a pure-Python MIT package with py.typed. import smart_open worked in 0.49 seconds.

A successful import does not prove a transport is ready. Install the matching extra, such as smart_open[s3] for boto3 or smart_open[gcs] for google-cloud-storage. Version 8.0.1's help now names dependencies that extras do not cover: HTTP Kerberos needs requests-kerberos, SSH GSSAPI needs Paramiko's gssapi extra, and hdfs or viewfs URIs shell out to an hdfs executable on PATH.

Credentials come from each transport SDK. S3 can use boto3's normal environment, profile, and instance-role chain; custom endpoints and retry settings belong on a client passed through transport_params. Azure examples construct a BlobServiceClient and pass it the same way. Keep secrets out of URIs because URLs can reach logs and tracebacks. HTTP and HTTPS only read, while write behavior varies across the object stores.

Compression is inferred from the final suffix unless compression is set explicitly. Wrong suffixes therefore decode the wrong way, and zstd or LZ4 needs its optional package. S3 writes use multipart behavior by default and finish when the handle closes, so use a context manager. Setting multipart_upload to false buffers the object before one upload; supply a temporary-file writebuffer when that object should not sit in memory.

Patterns

Iterate lines from S3 stream-s3-lines

# pip install 'smart_open[s3]'
from smart_open import open

with open('s3://commoncrawl/robots.txt', encoding='utf-8') as source:
    for line in source:
        print(line.rstrip())
        break

The s3 extra installs the transport SDK. The with block closes the ranged reader when the loop exits early.

Write through a configured S3 client write-s3-object

import boto3
import botocore
from smart_open import open

config = botocore.client.Config(max_pool_connections=32)
client = boto3.Session(profile_name='reports').client('s3', config=config)

with open('s3://bucket/report.jsonl', 'wb',
          transport_params={'client': client}) as sink:
    sink.write(b'{"ready": true}\n')

transport_params uses the supplied boto3 client, including its profile, endpoint, retries, and connection pool. Closing the handle completes the upload.

Infer compression from a suffix read-compressed-file

from smart_open import open

with open('s3://bucket/events.jsonl.gz', encoding='utf-8') as source:
    first_line = source.readline()

The .gz suffix selects gzip decompression before text decoding. A misleading object name requires an explicit compression argument.

Force or disable decompression override-compression

from smart_open import open

with open('archive.gzip', compression='.gz', encoding='utf-8') as source:
    text = source.read()

with open('archive.gz', 'rb', compression='disable') as source:
    magic = source.read(2)

compression='.gz' handles a nonstandard suffix. compression='disable' returns the original compressed bytes even when the name ends in .gz.

Set the gzip compression level tune-compression

from smart_open import open

with open(
    's3://bucket/report.txt.gz',
    'wb',
    compression_kwargs={'compresslevel': 6},
) as sink:
    sink.write(b'report contents')

compression_kwargs goes directly to the selected codec. gzip and bzip2 call the option compresslevel; other codecs use different names.

Connect to an S3-compatible service use-custom-s3-endpoint

import boto3
from smart_open import open

client = boto3.client(
    's3',
    endpoint_url='https://objects.example.com',
)
with open('s3://bucket/key.csv',
          transport_params={'client': client}) as source:
    header = source.readline()

Version 8 removed the old URI form that embedded a custom S3 host. Build the client with endpoint_url and pass it through transport_params.

Open one S3 object version read-object-version

from smart_open import open

with open(
    's3://bucket/config.json',
    'rb',
    transport_params={'version_id': '3Lg...'},
) as source:
    payload = source.read()

version_id selects an immutable S3 object version. Without it, the request reads the current version at the time the handle opens.

Buffer a single-part S3 upload on disk buffer-single-upload

import tempfile
from smart_open import open

with tempfile.TemporaryFile() as buffer, open(
    's3://bucket/small.bin',
    'wb',
    transport_params={
        'multipart_upload': False,
        'writebuffer': buffer,
    },
) as sink:
    sink.write(b'payload')

multipart_upload false waits and sends one object request at close. writebuffer replaces the default in-memory buffer with a temporary file.

Read a Google Cloud Storage blob read-gcs-object

# pip install 'smart_open[gcs]'
from smart_open import open

with open('gcs://analytics/events.csv', encoding='utf-8') as source:
    columns = source.readline().rstrip().split(',')

The gcs extra supplies google-cloud-storage. Authentication follows that SDK's application-default credential rules.

Pass an Azure Blob client read-azure-blob

import os
from azure.storage.blob import BlobServiceClient
from smart_open import open

client = BlobServiceClient.from_connection_string(
    os.environ['AZURE_STORAGE_CONNECTION_STRING']
)
with open('azure://reports/daily.csv',
          transport_params={'client': client}) as source:
    header = source.readline()

The Azure transport expects a client through transport_params in the documented example. Install smart_open[azure] before importing BlobServiceClient.

Read a file over SFTP read-sftp-file

# pip install 'smart_open[ssh]'
from smart_open import open

with open('sftp://batch-host/export.csv', encoding='utf-8') as source:
    header = source.readline()

The ssh extra installs Paramiko. Put host, user, and key configuration in SSH settings so credentials do not appear in the URI.

Register an application compression suffix register-compressor

import lzma
from smart_open import open, register_compressor

def open_archive(file_obj, mode, **kwargs):
    return lzma.open(filename=file_obj, mode=mode, **kwargs)

register_compressor('.archive', open_archive)

with open('s3://bucket/data.archive', 'rb') as source:
    payload = source.read()

register_compressor changes the process-wide suffix table. Register once during startup; the callback receives an already-open byte stream.

Alternatives

PackageRegistryPick it when
fsspecPyPIChoose it when the same backend abstraction also needs listing, globbing, deletion, caching, or filesystem objects.
s3fsPyPIChoose it for S3 paths that must work with fsspec consumers and support bucket-level filesystem operations.
boto3PyPIUse the AWS SDK directly when signed URLs, metadata, tags, or bucket APIs matter as much as streaming bytes.
requestsPyPIUse it for HTTP-only downloads when status handling, headers, sessions, and request controls are the main concern.

More data guides

numpy · fsspec · pandas · sqlalchemy · pyarrow · lxml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.