spectrochempy.Project

class Project(*args, argnames=None, name=None, **meta)[source]

Lightweight hierarchical container for datasets and subprojects.

Project owns child objects (NDDataset and nested Project instances) with strict single-parent ownership. It enforces:

  • Single-parent ownership — a child has at most one parent, and moving a child between projects is an ownership transfer.

  • Acyclic hierarchy — self-insertion and ancestor insertion are rejected with ValueError.

  • Explicit duplicate rejection — adding a child whose name already exists in the project raises ValueError.

  • Key/name identity — after insertion or replacement, project[key].name == key.

Project is a dataset container, not a workspace, workflow engine, provenance graph, or generic object store.

Parameters:
  • *args (Series of objects, optional) – Argument type will be interpreted correctly if they are of type NDDataset or Project. This is optional, as they can be added later.

  • argnames (list, optional) – If not None, this list gives the names associated to each object passed as args. It MUST be the same length as the number of args, or an error will be raised. If None, the internal name of each object will be used instead.

  • name (str, optional) – The name of the project. If the name is not provided, it will be generated automatically.

  • **meta (dict) – Any other attributes to describe the project.

See also

NDDataset

The main object containing arrays.

Examples

>>> import spectrochempy as scp
>>> myproj = scp.Project(name='project_1')
>>> ds = scp.NDDataset([1., 2., 3.], name='dataset_1')
>>> myproj.add_dataset(ds)
>>> print(myproj)
Project project_1:
    ⤷ dataset_1 (dataset)

Attributes Summary

allitems

All items contained in this project (list).

allnames

Names of all objects contained in this project (list).

datasets

Datasets included in this project excluding those located in subprojects.

datasets_names

Names of all dataset included in this project.

filename

Get current filename for this dataset.

filetype

Type of current file.

has_defined_name

True if the name was explicitly provided by the user (bool).

id

Readonly object identifier (str).

meta

Metadata for the project (meta).

name

A user-friendly name for the project.

parent

Parent project of this subproject, or None when this is a root project (project).

projects

Subprojects included in this project (list).

projects_names

Names of all subprojects included in this project (list).

suffix

Filename suffix.

Methods Summary

add_dataset(dataset[, name])

Add a single dataset to the current project.

add_datasets(*datasets)

Add several datasets to the current project.

add_project(proj[, name])

Add a subproject to the current project.

add_projects(*projects)

Add one or more subprojects to the current project.

clear_datasets()

Remove all datasets from the project.

clear_projects()

Remove all subprojects from the current project.

copy([deep])

Make a copy of the current project.

dump(filename, **kwargs)

Save the current object into compressed native spectrochempy format.

load(filename, **kwargs)

Open data from a '.scp' (NDDataset) or '.pscp' (Project) file.

loads(js, Any])

Deserialize dataset from JSON.

remove_dataset(name)

Remove a dataset from the project and reset its parent to None.

remove_project(name)

Remove a subproject from the current project and reset its parent to None.

save(**kwargs)

Save dataset in native .scp format.

save_as(filename, **kwargs)

Save the current NDDataset in SpectroChemPy format (.scp).

Attributes Documentation

allitems

All items contained in this project (list).

allnames

Names of all objects contained in this project (list).

datasets

Datasets included in this project excluding those located in subprojects.

(list).

datasets_names

Names of all dataset included in this project.

(does not return those located in sub-folders) (list).

filename

Get current filename for this dataset.

filetype

Type of current file.

has_defined_name

True if the name was explicitly provided by the user (bool).

id

Readonly object identifier (str).

meta

Metadata for the project (meta).

meta contains all attribute except the name, id and parent of the current project.

name

A user-friendly name for the project.

The default is automatically generated (str).

parent

Parent project of this subproject, or None when this is a root project (project).

projects

Subprojects included in this project (list).

projects_names

Names of all subprojects included in this project (list).

suffix

Filename suffix.

Read Only property - automatically set when the filename is updated if it has a suffix, else give the default suffix for the given type of object.

Methods Documentation

add_dataset(dataset, name=None)[source]

Add a single dataset to the current project.

The dataset is attached to this project as its parent, and its .name is set to the entry key (matching the key/name identity invariant). If a child with the same name already exists in the project (datasets and subprojects share a single namespace), a ValueError is raised.

Parameters:
  • dataset (NDDataset) – Dataset to add.

  • name (str, optional) – Entry key in the project. If not provided, defaults to dataset.name. When provided, dataset.name is overwritten to match this value.

Raises:

ValueError – If a child named name already exists in this project.

See also

add_datasets

Add several datasets to the current project.

Examples

>>> import spectrochempy as scp
>>> ds1 = scp.NDDataset([1, 2, 3])
>>> proj = scp.Project()
>>> proj.add_dataset(ds1, name='Toto')
add_datasets(*datasets)[source]

Add several datasets to the current project.

Each dataset is added via add_dataset. If any dataset name collides with an existing entry, a ValueError is raised and no datasets are added (the first duplicate raises).

Parameters:

*datasets (series of NDDataset) – Datasets to add to the current project. Entry keys are the datasets’ current names.

Raises:

ValueError – If any dataset name already exists in this project.

See also

add_dataset

Add a single dataset to the current project.

Examples

>>> import spectrochempy as scp
>>> ds1 = scp.NDDataset([1, 2, 3])
>>> ds2 = scp.NDDataset([4, 5, 6])
>>> ds3 = scp.NDDataset([7, 8, 9])
>>> proj = scp.Project()
>>> proj.add_datasets(ds1, ds2, ds3)
add_project(proj, name=None)[source]

Add a subproject to the current project.

The subproject is attached to this project as its parent. Its .name is set to the entry key when name differs from the subproject’s current name. If a child with the same name already exists in the project (datasets and subprojects share a single namespace), a ValueError is raised.

Self-insertion and ancestor insertion are rejected with ValueError (cycles are not allowed in the project hierarchy).

Parameters:
  • proj (Project) – Subproject to add.

  • name (str, optional) – Entry key in the project. If not provided, defaults to proj.name. When provided (and different from the current name), proj.name is overwritten to match.

Raises:

ValueError – If a child named name already exists in this project, or if adding the subproject would create a cycle.

See also

add_projects

Add several subprojects at once.

add_projects(*projects)[source]

Add one or more subprojects to the current project.

Each subproject is added via add_project. If any subproject name collides with an existing entry, a ValueError is raised.

Parameters:

*projects (series of Project) – The subprojects to add. Entry keys are the subprojects’ current names.

Raises:

ValueError – If any subproject name already exists in this project.

See also

add_project

Add a single subproject.

clear_datasets()[source]

Remove all datasets from the project.

See also

remove_dataset

Remove a single dataset.

add_dataset

Add a dataset.

clear_projects()[source]

Remove all subprojects from the current project.

See also

remove_project

Remove a single subproject.

add_project

Add a subproject.

copy(deep=True)[source]

Make a copy of the current project.

This method produces a recursive detached copy (every child is a new independent object) when called without arguments (deep=True). In that mode, copied children are re-attached inside the copied tree, so nested datasets and subprojects point to their copied parent. With deep=False it creates a new container whose children are shared references to the original — the children’s parent pointers remain unchanged.

Note

copy.copy(project) and copy.deepcopy(project) both produce a deep copy, matching the default copy(deep=True) behavior. This is intentional per the project copy semantics project copy semantics contract (maintainer repository) and differs from Python’s default shallow copy.copy semantics.

Parameters:

deep (bool, optional) – If True (default), a recursive detached copy is made where every child is a new independent object. If False, a new container is created with shared children.

Returns:

Project

dump(filename, **kwargs)[source]

Save the current object into compressed native spectrochempy format.

Parameters:

filename (str of pathlib object) – File name where to save the current object.

classmethod load(filename: str | pathlib.Path | BinaryIO, **kwargs: Any) -> Any: """ Open data from a '*.scp' (NDDataset) or '*.pscp' (Project) file. Parameters ---------- filename : `str`, `pathlib` or `file` objects The name of the file to read (or a file objects). **kwargs Optional keyword parameters (see Other Parameters). Other Parameters ---------------- content : str, optional The optional content of the file(s) to be loaded as a binary string. allow_unsafe_legacy : bool, optional, default=False Allow loading legacy SCP/PSCP payloads that require pickle-based native persistence. Enable this only for files from known and trusted sources. See Also -------- read : Import dataset from various orgines. save : Save the current dataset. Notes ----- Adapted from `numpy.load` . Examples -------- >>> nd1 = scp.read('irdata/nh4y-activation.spg') >>> f = nd1.save() >>> f.name 'nh4y-activation.scp' >>> nd2 = scp.load(f) Alternatively, this method can be called as a class method of NDDataset or Project object: >>> from spectrochempy import * >>> nd2 = NDDataset.load(f) """ content = kwargs.get("content") allow_unsafe_legacy = kwargs.get("allow_unsafe_legacy", False) resolved_filename = None if content is not None: fid = io.BytesIO(content) else: # be sure to convert filename to a pathlib object with the # default suffix filename = pathclean(filename) suffix = cls().suffix filename = filename.with_suffix(suffix) if kwargs.get("directory") is not None: filename = pathclean(kwargs.get("directory")) / filename if not filename.exists()[source]

Open data from a ‘.scp’ (NDDataset) or ‘.pscp’ (Project) file.

Parameters:
  • filename (str , pathlib or file objects) – The name of the file to read (or a file objects).

  • **kwargs – Optional keyword parameters (see Other Parameters).

Other Parameters:
  • content (str, optional) – The optional content of the file(s) to be loaded as a binary string.

  • allow_unsafe_legacy (bool, optional, default=False) – Allow loading legacy SCP/PSCP payloads that require pickle-based native persistence. Enable this only for files from known and trusted sources.

See also

read

Import dataset from various orgines.

save

Save the current dataset.

Notes

Adapted from numpy.load .

Examples

>>> nd1 = scp.read('irdata/nh4y-activation.spg')
>>> f = nd1.save()
>>> f.name
'nh4y-activation.scp'
>>> nd2 = scp.load(f)

Alternatively, this method can be called as a class method of NDDataset or Project object:

>>> from spectrochempy import *
>>> nd2 = NDDataset.load(f)
classmethod loads(js: dict[str, Any]) -> Any: """ Deserialize dataset from JSON. Parameters ---------- js : dict[str, Any] JSON object to deserialize Returns ------- Any Deserialized dataset object Raises ------ TypeError If JSON cannot be properly deserialized """ from spectrochempy.core.dataset.coord import Coord from spectrochempy.core.dataset.coordset import CoordSet from spectrochempy.core.dataset.nddataset import NDDataset from spectrochempy.core.project.project import Project # ......................... def restore_coordset_state(coordset: CoordSet, val: dict[str, Any]) -> CoordSet: default_index = val.get("default_index") if default_index is None and isinstance(val.get("default"), int)[source]

Deserialize dataset from JSON.

Parameters:

js (dict[str, Any]) – JSON object to deserialize

Returns:

Any – Deserialized dataset object

Raises:

TypeError – If JSON cannot be properly deserialized

remove_dataset(name)[source]

Remove a dataset from the project and reset its parent to None.

Parameters:

name (str) – Name of the dataset to remove.

See also

remove_project

Remove a subproject.

remove_project(name)[source]

Remove a subproject from the current project and reset its parent to None.

Parameters:

name (str) – Name of the project to remove.

See also

remove_dataset

Remove a dataset.

save(**kwargs: Any)[source]

Save dataset in native .scp format.

Parameters:

**kwargs (Any) – Optional arguments passed to save_as()

Returns:

Optional[pathlib.Path] – Path to saved file if successful, None if save failed

save_as(filename: str = "", **kwargs: Any) -> pathlib.Path | None: """ Save the current NDDataset in SpectroChemPy format (.scp). Parameters ---------- filename : str The filename of the file where to save the current dataset. **kwargs Optional keyword parameters (see Other Parameters). Other Parameters ---------------- directory : str, optional If specified, the given `directory` and the `filename` will be appended. See Also -------- save : Save current dataset. write : Export current dataset to different format. Notes ----- Adapted from :class:`numpy.savez` . Examples -------- Read some data from an OMNIC file >>> nd = scp.read_omnic('wodger.spg') >>> assert nd.name == 'wodger' Write it in SpectroChemPy format (.scp) (return a `pathlib` object) >>> filename = nd.save_as('new_wodger') Check the existence of the scp file >>> assert filename.is_file() >>> assert filename.name == 'new_wodger.scp' Remove this file >>> filename.unlink() """ if filename: # we have a filename # by default it use the saved directory filename = pathclean(filename) if self.directory and self.directory != filename.parent: filename = self.directory / filename else: filename = self.directory # suffix must be specified which correspond to the type of the # object to save default_suffix = SCPY_SUFFIX[self._implements()] if filename is not None and not filename.is_dir()[source]

Save the current NDDataset in SpectroChemPy format (.scp).

Parameters:
  • filename (str) – The filename of the file where to save the current dataset.

  • **kwargs – Optional keyword parameters (see Other Parameters).

Other Parameters:

directory (str, optional) – If specified, the given directory and the filename will be appended.

See also

save

Save current dataset.

write

Export current dataset to different format.

Notes

Adapted from numpy.savez .

Examples

Read some data from an OMNIC file

>>> nd = scp.read_omnic('wodger.spg')
>>> assert nd.name == 'wodger'

Write it in SpectroChemPy format (.scp) (return a pathlib object)

>>> filename = nd.save_as('new_wodger')

Check the existence of the scp file

>>> assert filename.is_file()
>>> assert filename.name == 'new_wodger.scp'

Remove this file

>>> filename.unlink()

Examples using spectrochempy.Project

Project creation

Project creation