Cassini API

Core

class cassini.core.Meta(file: Path)

Like a dictionary, except linked to a json file on disk. Caches the value of the json in itself.

Parameters:

file (Path) – File Meta object stores information about.

property age: float

time in secs since last fetch

fetch() Dict[str, dict | list | tuple | str | int | float | bool | None]

Fetches values from the meta file and updates them into self._cache.

Notes

This doesn’t overwrite self._cache with meta contents, but updates it. Meaning new stuff to file won’t be overwritten, it’ll just be loaded.

get(key: str, default: Any | None = None) Any

Like dict.get

keys() KeysView[str]

like dict.keys

refresh() None

Check age of cache, if stale then re-fetch

write() None

Overwrite contents of cache into file

class cassini.core.TierBase(*args: str, **kwargs: Dict[str, Any])

Base class for creating Tiers

Parameters:

*identifiers (str) – sequence of strings that identify this tier. With the final identifier being unique.

rank

Class attribute, specifying the rank of this Tier

Type:

int

id_regex

Class attribute, regex that defines a group that matches the id of a Tier object from a name… except the name isn’t the full name, but with parent names stripped, see examples basically!

Type:

str

hierarchy

Class attribute, hierarchy of `Tier`s.

Type:

list

description

returns the description found in a Tier _instance’s meta file

Type:

str

started

return a datetime parsed using config.DATE_FORMAT found in meta file

Type:

datetime

conclusion

return the conclusion found in a Tier _instance’s meta file.

Type:

str

rank

(class attribute) rank of this Tier class (not to be set directly)

Type:

int

id_regex

(class attribute) regex used to restrict form of Tier object ids. Should contain 1 group that captures the id.

Type:

str

gui_cls
(class attribute) The class called upon initialisation to use as gui for this object. Constructor should take self

as first argument.

Type:

Any

add_highlight(name: str, data: List[Dict[str, Dict[str, Any]]], overwrite: bool = True) None

Add a highlight to self.highlights_file.

This is usually done behind the scenes using the %%hlt My Title magic.

Parameters:
  • name (str) – Name of highlight (also taken as the title).

  • data (list) – list of data and metadata that can be passed to IPython.display.publish_display_data to render.

  • overwrite (bool) – If False will raise an exception if a highlight of the same name exists. Default is True

cache_file

Path to where cache file for this Tier object will be.

Returns:

cache_file – Defaults to self.parent.folder / self._meta_folder_name / (self.name + ‘.cache’)

Return type:

Path

cache_result(name: str, data: List[Dict[str, Dict[str, Any]]], overwrite: bool = True) None

Cache a result in self.cache_file.

This is usually done behind the scenes using the %%cache magic.

Parameters:
  • name (str) – name used as key in JSON for this cached result. When using %%cache this is a hash of the cell text

  • data (dict) – list of data and metadata that can be passed to IPython.display.publish_display_data to render.

  • overwrite (bool) – If False will raise an exception if a cached result of the same name exists. Default is True

children_df(*, include: List[str] | None = None, exclude: List[str] | None) DataFrame | None

Build an UnescapedDataFrame containing rows from each child of this Tier. Columns are inferred from contents of meta files.

Parameters:
  • include (Sequence[str]) – names of columns to include in children DataFrame

  • exclude (Sequence[str]) – names of columns to drop from children DataFrame

Notes

Parameters include and exclude are mutually exclusive.

Returns:

df – DataFrame containing Tier’s children. If no children then returns None.

Return type:

UnescapedDataFrame, None

exists() bool

returns True if this Tier object has already been setup (e.g. by self.setup_files)

file

Path to where .ipynb file for this Tier instance will be.

Returns:

file – Defaults to self.parent.folder / (self.name + ‘.ipynb’).

Return type:

Path

folder

Path to folder where the contents of this Tier lives.

Defaults to self.parent.folder / self.name.

get_cached() Dict[str, List[Dict[str, Dict[str, Any]]]] | None

Retrieve cached output from self.cache_file.

Keys are a hash of text from cell that created this output.

Returns:

cached – dictionary with all the cached outputs. In the same form as self.get_highlights(). Returns an empty dict if no cache_file exists.

Return type:

dict

get_child(id: str) TierBase

Get a child according to the given id.

Parameters:

id (str) – id to add self.identifiers to form new Tier object of tier below.

Returns:

child – child Tier object.

Return type:

Type[TierBase]

get_highlights() Dict[str, List[Dict[str, Dict[str, Any]]]] | None

Get dictionary of highlights for this Tier _instance.

This dictionary is in a form that can be rendered in the notebook using IPython.display.publish_display_data see Examples.

This is implemented for you with self.display_highlights().

Returns:

highlights – Get dictionary of highlights for this Tier _instance. If the highlights file doesn’t exist, just returns an empty dict.

Return type:

dict

Examples

>>> wp = project['WP1']
>>> for title, outputs in wp.get_highlights():
...     print("Displaying Highlight:", title)
...     for output in outputs:
...         IPython.display.publish_display_data(**output)
classmethod get_templates() List[Path]

Get all the templates for this Tier.

gui_cls

alias of BaseTierGui

highlights_file

Path to where highlights file for this Tier object should be.

Returns:

highlights_file – Defaults to self.parent.folder / self._meta_folder_name / (self.name + ‘.hlts’)

Return type:

Path

href

href usable in notebook HTML giving link to self.file.

Assumes that os.getcwd() reflects the directory of the currently opened .ipynb (usually true, unless you’re changing working dir).

Does do escaping on the HTML, but is maybe pointless!

Returns:

href – href usable in notebook HTML.

Return type:

str

id

Shortcut for getting final identifier.

Examples

>>> from my_project import project
>>> smpl = project.env('WP2.3c')
>>> smpl.identifiers
['2', '3', 'c']
>>> smpl.id
'c'
identifiers

Read only copy of identifiers that make up this Tier object.

meta_file

Path to where meta file for this Tier object should be.

Returns:

meta_file – Defaults to self.parent.folder / self._meta_folder_name / (self.name + ‘.json’)

Return type:

Path

name

Full name of Tier object. Made by concatenating each parent’s self.name_part_template filled with each parent’s self.id.

Examples

>>> wp = WorkPackage('2')
>>> exp = Experiment('2', '3')
>>> smpl = Sample('2', '3', 'c')
>>> wp.name_part_template.format(wp.id)
WP2
>>> exp.name_part_template.format(exp.id)
.3
>>> smpl.name_part_template.format(smpl.id)
c
>>> smpl.name  # all 3 joined together
WP2.3c
open_folder() None

Open self.folder in explorer

Notes

Only works on Windows machines.

Window is opened via the Jupyter server, not the browser, so if you are not accessing jupyter on localhost then the window won’t open for you!

parent

‘(

Type:

Parent of this Tier _instance, None if has no parent

classmethod parse_name(name: str) Tuple[str, ...]

Ask env.project to parse name.

remove_cached(name: str) None

Remove cached output according to the name provided.

remove_files() None

Deletes files associated with a Tier

remove_highlight(name: str) None

Remove highlight from highlight file. Performed by calling get_highlights(), then deleting the key name from the dictionary, then re-writing the highlights… if you’re interested!

render_template(template_path: Path) str

Render template file passing self as self.short_type and as tier.

Parameters:

template (Path) – path to template file. Must be relative to project.template_folder

Returns:

rendered_text – template rendered with self.

Return type:

str

setup_files(template: Path | None = None, meta: Dict[str, dict | list | tuple | str | int | float | bool | None] | None = None) None

Create all the files needed for a valid Tier object to exist.

This includes its .ipynb file, its parent folder, its own folder and its Meta file.

Will render .ipynb file as Jinja template engine, passing to the template self with names given by self.short_type and tier.

Parameters:
  • template (Path) – path to template file to render to create .ipynb file.

  • meta (MetaDict) – Initial meta values to create the tier with.

Environment

class cassini.environment.CassiniLabApp(**kwargs: Any)

Subclass of jupyterlab.labapp.LabApp that ensures ContentsManager.allow_hidden = True (needed for jupyter_cassini_server)

classmethod initialize_server(argv: Any | None = None) LabServerApp

Patch serverapp to ensure hidden files are allowed, needed for jupyter_cassini_server

class cassini.environment.PathLibEnv(block_start_string: str = '{%', block_end_string: str = '%}', variable_start_string: str = '{{', variable_end_string: str = '}}', comment_start_string: str = '{#', comment_end_string: str = '#}', line_statement_prefix: str | None = None, line_comment_prefix: str | None = None, trim_blocks: bool = False, lstrip_blocks: bool = False, newline_sequence: te.Literal['\n', '\r\n', '\r'] = '\n', keep_trailing_newline: bool = False, extensions: ~typing.Sequence[str | ~typing.Type[Extension]] = (), optimized: bool = True, undefined: ~typing.Type[~jinja2.runtime.Undefined] = <class 'jinja2.runtime.Undefined'>, finalize: ~typing.Callable[[...], ~typing.Any] | None = None, autoescape: bool | ~typing.Callable[[str | None], bool] = False, loader: BaseLoader | None = None, cache_size: int = 400, auto_reload: bool = True, bytecode_cache: BytecodeCache | None = None, enable_async: bool = False)

Subclass of jinja2.Environment to enable using pathlib.Path for template names.

get_template(name: Path | str, parent: str | None = None, globals: MutableMapping[str, Any] | None = None) Template

Load a template by name with loader and return a Template. If the template does not exist a TemplateNotFound exception is raised.

Parameters:
  • name – Name of the template to load. When loading templates from the filesystem, “/” is used as the path separator, even on Windows.

  • parent – The name of the parent template importing this template. join_path() can be used to implement name transformations with this.

  • globals – Extend the environment globals with these extra variables available for all renders of this template. If the template has already been loaded and cached, its globals are updated with any new items.

Changed in version 3.0: If a template is loaded from cache, globals will update the template’s globals instead of ignoring the new values.

Changed in version 2.4: If name is a Template object it is returned unchanged.

class cassini.environment.Project(*args: Any, **kwargs: Any)

Represents your project. Understands your naming convention, and your project hierarchy.

Parameters:
  • hierarchy (List[Type[BaseTier]]) – Sequence of TierBase subclasses representing the hierarchy for this project. i.e. earlier entries are stored in higher level directories.

  • project_folder (Union[str, Path]) – path to home directory. Note this also accepts a path to a file, but will take project_folder.parent in that case. This enables __file__ to be used if you want project_folder to be based in the same dir.

Notes

This class is a singleton i.e. only 1 instance per interpreter can be created.

env(name: str) TierBase

Initialise the global environment to a particular Tier that is retrieved by parsing name.

This will set the value of env.o.

Warning

This should only really be called once (or only with 1 name). Otherwise this could create some unexpected behaviour.

property home: TierBase

Get the home Tier.

launch(app: LabApp | None = None, patch_pythonpath: bool = True) LabApp

Jump off point for a cassini project.

Sets up required files for your project, monkeypatches PYTHONPATH to make your project available throughout and launches a jupyterlab server.

This explicitly associates an instance of the Jupyter server with a particular project.

Parameters:
  • app (LabApp) – A ready made Jupyter Lab app (By defuault will just create a new one).

  • patch_pythonpath (bool) – Add self.project_folder to the PYTHONPATH? (defaults to True)

parse_name(name: str) Tuple[str, ...]

Parses a string that corresponds to a Tier and returns a list of its identifiers.

returns an empty tuple if not a valid name.

Parameters:

name (str) – name to parse

Returns:

identifiers – identifiers extracted from name, empty tuple if None found

Return type:

tuple

Notes

This works in a slightly strange - but robust way!

e.g.

>>> name = 'WP2.3c'

it will loop through each entry in cls.hierarchy (skipping home!), and then perform a search on name with that regex:

>>> WorkPackage.name_part_regex
WP(\d+)
>>> match = re.search(WorkPackage.name_part_regex, name)

If there’s no match, it will return (), if there is, it stores the id part:

>>> wp_id = match.group(1)  # in python group 0 is the whole match
>>> wp_id
2

Then it removes the whole match from the name:

>>> name = name[match.end(0):]
>>> name
.3c

Then it moves on to the next tier

>>> Experiment.name_part_regex
'\.(\d+)'
>>> match = re.search(WorkPackage.name_part_regex, name)

If there’s a match it extracts the id, and substracts the whole string from name and moves on, continuing this loop until it’s gone through the whole hierarchy.

The whole name has to be a valid id, or it will return () e.g.

>>> TierBase.parse_name('WP2.3')
('2', '3')
>>> TierBase.parse_name('WP2.u3')
()
setup_files() TierBase

Setup files needed for this project.

Will put everything you need in project_folder to get going.

template_folder()

Overwritable property providing where templates will be stored for this project.

IPyGui

class cassini.ipygui.BaseTierGui(tier: T)

Mixin to provide nice notebook outputs for Jupyter Notebooks.

children_df(*, include: List[str] | None = None, exclude: List[str] | None = None) UnescapedDataFrame | None

Calls tier.children_df but returns an UnescapedDataFrame instead.

display_highlights() None

Display an ipywidgets.Accordian with this Tier’s highlights.

header(*, include: List[str] | None = None, exclude: List[str] | None = None) DOMWidget

Builds header widget from its components.

Parameters:
  • include (Sequence[str]) – names of components to render in header widget.

  • exclude (Sequence[str]) – names of components not to render in header widget.

Notes

Parameters include and exclude are mutually exclusive.

Returns:

header – Widget that can be displayed containing all the components of this Tier’s header.

Return type:

DOMWidget

new_child() DOMWidget

Widget for creating new child for this Tier.

class cassini.ipygui.InputSequence(done_action: Callable[[...], Any], *children: DOMWidget)

Helper class for creating ‘input sequences’ i.e. a sequency of widgets that you fill in, and then click confirm.

Parameters:
  • done_action (callable) – function to call when confirm is clicked. Each child (see next parameter!) is passed to done_action

  • *children (ipywidget) – widgets to display in order. When confirm clicked, these widget objects are passed to done_action.

as_widget() DOMWidget

Build self into ipywidget

Returns:

widget – widget form of self.

Return type:

DOMWidget

child_updated(change: Any) None

Called when a child is updated, meant to stop you pressing confirm until you’ve entered something into every widget… don’t think it actually works tho!

display() Output

Displays self.as_widget().

Returns:

output – output widget which we displayed into…

Return type:

Output

reset(change: Any) None

Reset the state of the InputSequence. Called when new button clicked.

class cassini.ipygui.UnescapedDataFrame(data=None, index: Axes | None = None, columns: Axes | None = None, dtype: Dtype | None = None, copy: bool | None = None)

Subclass of pd.DataFrame that slightly dangerously does not escape any html in its self._repr_html_ method.

Warning

This class deliberately does not escape HTML for objects it contains. This means you need to trust these objects.

static try_html_repr(obj: object) str

Get text form of obj, first try obj._repr_html_, fallback on str(obj).

Warning

This method does not escape obj._repr_html_. So make sure your reprs are trustworthy!

class cassini.ipygui.WHTML(html: str)

Magic class that takes html text and creates an object that is rendered with that text.

ipywidget.HTML widgets do not get their links XSRF protected, but obj._repr_html_ does!

Warning

This HTML is not escaped, so could do bad stuff!

cassini.ipygui.widgetify(obj: Any) Output

Allows any object to be treated like an ipywidget so it can be used in ipywidget layouts - handy!

cassini.ipygui.widgetify_html(html: str) Output

Required for html which has links rather than ipywidgets HTML widget.

Parameters:

html (str) – HTML to render

Return type:

Output widget containing the HTML

Defaults

class cassini.defaults.tiers.DataSet(*args: str, **kwargs: Dict[str, Any])

DataSet Tier.

The final tier, intended to represent a folder containing a collection of files relating to a particular Sample.

default_template = None
exists() bool

returns True if this Tier object has already been setup (e.g. by self.setup_files)

file

`DataSet`s have no file

folder
classmethod get_templates() List[Path]

Datasets have no templates.

highlights_file

`DataSet`s have no highlights.

href
meta_file

`DataSet`s have no meta.

setup_files(template: Path | None = None, meta=None) None

Create all the files needed for a valid Tier object to exist.

This includes its .ipynb file, its parent folder, its own folder and its Meta file.

Will render .ipynb file as Jinja template engine, passing to the template self with names given by self.short_type and tier.

Parameters:
  • template (Path) – path to template file to render to create .ipynb file.

  • meta (MetaDict) – Initial meta values to create the tier with.

class cassini.defaults.tiers.Experiment(*args: str, **kwargs: Dict[str, Any])

Experiment Tier.

Just below WorkPackage, experiments are intended to be collections of samples and datasets that work towards the goal of the parent WorkPackage.

Each Experiment has a number of samples.

children_df(include: List[str] | None = None, exclude: List[str] | None = None) DataFrame | None

Build an UnescapedDataFrame containing rows from each child of this Tier. Columns are inferred from contents of meta files.

Parameters:
  • include (Sequence[str]) – names of columns to include in children DataFrame

  • exclude (Sequence[str]) – names of columns to drop from children DataFrame

Notes

Parameters include and exclude are mutually exclusive.

Returns:

df – DataFrame containing Tier’s children. If no children then returns None.

Return type:

UnescapedDataFrame, None

gui_cls

alias of ExperimentGui

setup_technique(name: str) None

Convenience method for adding a new technique to this experiment.

Essentially just creates a new folder for it in the appropriate location.

This folder can then be filled with `DataSet`s

property smpls: List[TierBase]

Get a list of this `Experiment`s samples.

property techniques: List[str]

Convenience property for looking up all the techniques that have been performed on samples in this experiment.

Notes

This just checks for the existence of DataSet folders, and not if they have anything in them!

class cassini.defaults.tiers.ExperimentGui(tier: T)
new_dataset() DOMWidget

A handy widget for creating new DataSets.

class cassini.defaults.tiers.Home(*args: str, **kwargs: Dict[str, Any])

Home Tier.

This, or a subclass of this should generally be the first entry in your hierarchy, essentially represents the top level folder in your hierarchy.

Creates the Home.ipynb notebook that allows easy navigation of your project.

exists() bool

returns True if this Tier object has already been setup (e.g. by self.setup_files)

file
folder
gui_cls

alias of HomeGui

highlights_file
meta_file
name
setup_files(template: Path | None = None, meta=None) None

Create all the files needed for a valid Tier object to exist.

This includes its .ipynb file, its parent folder, its own folder and its Meta file.

Will render .ipynb file as Jinja template engine, passing to the template self with names given by self.short_type and tier.

Parameters:
  • template (Path) – path to template file to render to create .ipynb file.

  • meta (MetaDict) – Initial meta values to create the tier with.

class cassini.defaults.tiers.HomeGui(tier: T)
class cassini.defaults.tiers.Sample(*args: str, **kwargs: Dict[str, Any])

Sample Tier.

A Sample is intended to represent some object that you collect data on.

As such, each sample has its own `DataSet`s.

Notes

A Sample id can’t start with a number and can’t contain ‘-’ (dashes), as these confuse the name parser.

property datasets: List[TierBase]

Convenient way of getting a list of `DataSet`s this sample has.

folder
gui_cls

alias of SampleGui

class cassini.defaults.tiers.SampleGui(tier: T)
new_child() DOMWidget

Widget for creating new child for this Tier.

class cassini.defaults.tiers.WorkPackage(*args: str, **kwargs: Dict[str, Any])

WorkPackage Tier.

Intended to contain all the work towards a particular goal. i.e. prove that we can do this.

Next level down are `Experiment`s.

property exps: List[TierBase]

Gets a list of all this `WorkPackage`s experiments.