Storage API
Document storage backends for raw file and page content archival.
Backend Factory
scinr.newton.storage.factory
storage/factory.py — Repository factory.
Call get_storage() to obtain the configured pair of repository implementations. The backend is determined by ScinrConfig (from scinr_config) which reads STORAGE_BACKEND from the environment or from configure().
get_storage
Return the repository implementations for the configured backend.
Returns
tuple[RawFileRepository, PageRepository] A (raw_file_repo, page_repo) pair ready to use.
Raises
ConfigurationError If the storage backend is unknown or misconfigured. If backend='custom' but custom_storage was not provided. StorageError If backend='mongodb' but the MongoDB server is unreachable.
Base Classes
scinr.newton.storage.base
storage/base.py — Abstract repository interfaces.
All storage backends must implement these ABCs so that the rest of the pipeline can remain backend-agnostic.
PageRepository
Bases: ABC
Almacena las páginas convertidas (markdown) de un documento.
delete_pages
abstractmethod
async
Borra todas las páginas asociadas a raw_file_id.
No es un error que no existan páginas para ese raw_file_id
(devuelve 0 en ese caso, sin lanzar excepción).
Parameters
raw_file_id:
ID del :class:~storage.models.RawFileRecord cuyas páginas se
quieren borrar.
Returns
int
Número de páginas borradas (0 si no había ninguna).
get_pages
abstractmethod
async
Recupera todas las páginas de un fichero por su raw_file_id.
Parameters
raw_file_id:
ID del :class:~storage.models.RawFileRecord cuyas páginas se
quieren recuperar.
Returns
list[ConvertedPageRecord]
Lista ordenada por page_index ascendente.
Puede estar vacía si aún no se han almacenado páginas.
store_page
abstractmethod
async
store_page(
raw_file_id: str,
filename: str,
folder_path: str | None,
page_index: int,
markdown: str,
) -> str
Persiste una página y devuelve su page_id (str).
Parameters
raw_file_id:
ID del :class:~storage.models.RawFileRecord al que pertenece
esta página.
filename:
Stem del fichero sin extensión (p.ej. "3.2.P.1").
folder_path:
Ruta relativa de la carpeta contenedora, o None.
page_index:
Índice 0-based de la página, idéntico a
:attr:~converters.base.IntermediatePage.index.
markdown:
Texto completo de la página en formato Markdown.
Returns
str
El page_id: identificador único de la página persistida.
RawFileRepository
Bases: ABC
Almacena el fichero original tal cual fue recibido (binario).
delete
abstractmethod
async
Borra el fichero binario (y su metadata) identificado por raw_file_id.
Debe ser idempotente: si raw_file_id no existe (ya borrado, ID inválido, o llamada repetida), no debe lanzar excepción — solo loggear y no hacer nada.
Parameters
raw_file_id:
ID del :class:~storage.models.RawFileRecord a borrar.
store
abstractmethod
async
Persiste el fichero y devuelve su raw_file_id (str).
Parameters
filename:
Nombre del fichero original (p.ej. "3.2.P.1.pdf").
content:
Contenido binario del fichero.
content_type:
MIME type del fichero (p.ej. "application/pdf").
folder_path:
Ruta relativa de la carpeta contenedora desde la raíz de ingesta,
o None si el fichero está en la raíz.
Returns
str
El raw_file_id: representación en cadena del identificador
único asignado por el backend de almacenamiento.
MongoDB Backend
Client & GridFS
scinr.newton.storage.mongodb.client
storage/mongodb/client.py — Motor async client singleton + GridFS access.
A single :class:~motor.motor_asyncio.AsyncIOMotorClient instance is kept
per process. All repositories in this backend share it to avoid exhausting
connection-pool resources.
Public API
get_client()
Return the singleton Motor client (creates it on first call).
get_db()
Return the configured Motor database object.
get_gridfs_bucket()
Return an :class:~motor.motor_asyncio.AsyncIOMotorGridFSBucket for
binary file storage.
ensure_indexes()
Coroutine — create all required indexes (idempotent). Call once at
application startup.
ensure_indexes
async
Create all required MongoDB indexes (idempotent).
Uses Motor's create_index which maps to a createIndex command
that is a no-op if the index already exists with the same key pattern
and name.
Should be called once at application startup to guarantee optimal query performance from the first request.
get_client
Return the Motor singleton client, creating it on first call.
The client is module-level so that it survives across coroutine calls within the same process and reuses the underlying connection pool.
Returns
AsyncIOMotorClient The shared Motor client instance.
get_db
Return the Motor database object for the configured database.
Returns
AsyncIOMotorDatabase
The Motor database identified by cfg.mongodb_database.
get_gridfs_bucket
Return the GridFS bucket for binary file storage.
The bucket name is read from cfg.mongodb_gridfs_bucket
(default "raw_binaries").
Returns
AsyncIOMotorGridFSBucket GridFS bucket ready for upload/download operations.
Page Repository
scinr.newton.storage.mongodb.pages
storage/mongodb/pages.py — MongoDB implementation of PageRepository.
Converted pages (Markdown text) are stored as plain documents in the
converted_pages collection. Each document maps 1-to-1 to an
:class:~storage.models.ConvertedPageRecord and references its parent
raw file via raw_file_id.
MongoDBPageRepository
Bases: PageRepository
Stores and retrieves converted pages in the converted_pages collection.
Each document in the collection represents a single page of a converted
document. Pages are ordered by page_index which mirrors
:attr:~converters.base.IntermediatePage.index.
delete_pages
async
Delete every converted page belonging to raw_file_id.
Not an error if no pages exist for this raw_file_id — returns
0 in that case rather than raising.
Parameters
raw_file_id:
ID of the :class:~storage.models.RawFileRecord whose pages
should be deleted.
Returns
int
Number of pages deleted (0 if none matched).
get_pages
async
Retrieve all pages for a given raw file, ordered by page index.
Parameters
raw_file_id:
ID of the :class:~storage.models.RawFileRecord whose pages
should be retrieved.
Returns
list[ConvertedPageRecord]
Pages sorted by page_index ascending. Returns an empty list
if no pages have been stored for this raw_file_id.
store_page
async
store_page(
raw_file_id: str,
filename: str,
folder_path: str | None,
page_index: int,
markdown: str,
) -> str
Persist a single converted page in MongoDB.
Parameters
raw_file_id:
ID of the parent :class:~storage.models.RawFileRecord.
filename:
Stem of the source file without extension, e.g. "3.2.P.1".
folder_path:
Relative path of the containing folder, or None.
page_index:
Zero-based page index.
markdown:
Full Markdown text of this page.
Returns
str
The page_id: str(ObjectId) of the newly inserted document.
Raw File Repository
scinr.newton.storage.mongodb.raw_files
storage/mongodb/raw_files.py — MongoDB/GridFS implementation of RawFileRepository.
Binary content is stored in GridFS to support files of arbitrary size
(including PDFs larger than the 16 MB BSON document limit). A lightweight
metadata document is inserted into the raw_files collection so that
records can be queried by checksum, filename, or folder path without
fetching the full binary from GridFS.
MongoDBRawFileRepository
Bases: RawFileRepository
Stores binary files in GridFS with metadata in raw_files.
GridFS splits large files into 255 kB chunks and stores them across
two internal collections (<bucket>.files and <bucket>.chunks),
removing the 16 MB BSON size constraint.
The raw_files collection holds only metadata plus a gridfs_id
reference so callers can retrieve the binary when needed.
delete
async
Delete a raw file's binary (GridFS) and metadata (raw_files).
Idempotent: if raw_file_id is not a valid ObjectId, or no matching
metadata document is found (already deleted, or a repeated call),
this logs a warning and returns without raising. If the metadata
document exists but its GridFS binary is already gone
(gridfs.errors.NoFile), that is also logged and swallowed —
the metadata document is still deleted.
Parameters
raw_file_id:
The raw_file_id (str(ObjectId)) to delete.
store
async
Upload a binary file to GridFS and persist its metadata.
Parameters
filename:
Original filename including extension, e.g. "3.2.P.1.pdf".
content:
Raw binary content of the file.
content_type:
MIME type, e.g. "application/pdf".
folder_path:
Relative path of the containing folder from the ingestion root,
or None for files at the root.
Returns
str
The raw_file_id: str(ObjectId) of the newly inserted
document in the raw_files collection.
Null Backend
scinr.newton.storage.null
storage/null.py — No-op storage repositories for when storage_backend='none'.
These implementations satisfy the RawFileRepository and PageRepository interfaces without performing any I/O. They are used as the default when no storage backend is configured, eliminating the need for None checks throughout the codebase.