Source code for nexusLIMS.utils.paths
"""Path manipulation utilities for NexusLIMS."""
import logging
from pathlib import Path
from typing import List, Union
from nexusLIMS.config import settings
_logger = logging.getLogger(__name__)
[docs]
def is_subpath(path: Path, of_paths: Union[Path, List[Path]]):
"""
Return if this path is a subpath of other paths.
Helper function to determine if a given path is a "subpath" of a set of
paths. Useful to help determine which instrument a given file comes from,
given the instruments ``filestore_path`` and the path of the file to test.
Parameters
----------
path
The path of the file (or directory) to test. This will usually be the
absolute path to a file on the local filesystem (to be compared using
the host-specific ``nx_instrument_data_path``.
of_paths
The "higher-level" path to test against (or list thereof). In typical
use, this will be a path joined of an instruments ``filestore_path``
with the root-level ``nx_instrument_data_path``
Returns
-------
result : bool
Whether or not path is a subpath of one of the directories in of_paths
Examples
--------
>>> is_subpath(Path('/path/to/file.dm3'),
... settings.NX_INSTRUMENT_DATA_PATH /
... titan.filestore_path))
True
"""
if isinstance(of_paths, Path):
of_paths = [of_paths]
return any(subpath in path.parents for subpath in of_paths)
[docs]
def join_instrument_filestore_path(filestore_path: str) -> Path:
"""
Safely join NX_INSTRUMENT_DATA_PATH with an instrument's filestore_path.
This helper handles filestore_path values with leading slashes gracefully.
If filestore_path starts with '/', the leading slash is stripped before joining
to ensure the path remains relative to NX_INSTRUMENT_DATA_PATH.
Parameters
----------
filestore_path
The instrument's filestore_path (may contain leading '/')
Returns
-------
pathlib.Path
A resolved Path object: NX_INSTRUMENT_DATA_PATH / filestore_path
Examples
--------
>>> join_instrument_filestore_path("./Titan_STEM")
PosixPath('/mnt/data/Titan_STEM')
>>> join_instrument_filestore_path("/Titan_STEM") # Leading slash stripped
PosixPath('/mnt/data/Titan_STEM')
>>> join_instrument_filestore_path("Titan_STEM")
PosixPath('/mnt/data/Titan_STEM')
"""
# Strip leading slash to ensure relative path behavior
# pathlib treats absolute paths specially - they override the base path
normalized_path = filestore_path.lstrip("/")
return Path(settings.NX_INSTRUMENT_DATA_PATH) / normalized_path
[docs]
def replace_instrument_data_path(path: Path, suffix: str) -> Path:
"""
Given an "NX_INSTRUMENT_DATA_PATH" path, generate equivalent"NX_DATA_PATH" path.
If the given path is not a subpath of "NX_INSTRUMENT_DATA_PATH", a warning will
be logged and the suffix will just be added at the end.
Parameters
----------
path
The input path, which is expected to be a subpath of the
NX_INSTRUMENT_DATA_PATH directory
suffix
Any added suffix to add to the path (useful for appending with a new extension,
such as ``.json``)
Returns
-------
pathlib.Path
A resolved pathlib.Path object pointing to the new path
"""
instr_data_path = Path(str(settings.NX_INSTRUMENT_DATA_PATH))
nexuslims_path = Path(str(settings.NX_DATA_PATH))
if instr_data_path not in path.parents:
_logger.warning(
"%s is not a sub-path of %s", path, str(settings.NX_INSTRUMENT_DATA_PATH)
)
return Path(str(path).replace(str(instr_data_path), str(nexuslims_path)) + suffix)