Skip to content

Commit

Permalink
prep for first minor release
Browse files Browse the repository at this point in the history
  • Loading branch information
tomvanmele committed Oct 1, 2024
1 parent 485b5d9 commit d0f0caa
Show file tree
Hide file tree
Showing 10 changed files with 234 additions and 38 deletions.
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# COMPAS Session

Session management for COMPAS workflows and tools

> [!WARNING]
> This package is under active development,
> don't use it for anything important for now...
Session management for COMPAS workflows and tools

## Installation

Stable releases can be installed from PyPI.
Expand All @@ -30,4 +30,3 @@ please check out the online documentation here: [COMPAS Session docs](https://bl
## Issue Tracker

If you find a bug or if you have a problem with running the code, please file an issue on the [Issue Tracker](https://github.com/blockresearchgroup/compas_session/issues).

10 changes: 8 additions & 2 deletions docs/api/compas_session.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,11 @@ compas_session
.. currentmodule:: compas_session


.. toctree::
:maxdepth: 1
Classes
=======

.. autosummary::
:toctree: generated/
:nosignatures:

namedsession.NamedSession
10 changes: 0 additions & 10 deletions docs/examples.rst

This file was deleted.

Empty file removed docs/examples/PLACEHOLDER
Empty file.
14 changes: 8 additions & 6 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
compas_session
********************************************************************************

.. rst-class:: lead
.. warning::

This package is under active development and has no stable releases yet.
Its functionality may change frequently...

Session management for COMPAS workflows and tools
.. rst-class:: lead

.. .. figure:: /_images/
:figclass: figure
:class: figure-img img-fluid
This package provides session objects for managing
data exchange between different processes/scripts in project workflows, and between different GUI commands,
and for data persistence in between consecutive sessions.


Table of Contents
Expand All @@ -21,7 +24,6 @@ Table of Contents
Introduction <self>
installation
tutorial
examples
api
license

Expand Down
33 changes: 33 additions & 0 deletions docs/installation.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,36 @@
********************************************************************************
Installation
********************************************************************************

Stable
======

Stable releases are available on PyPI and can be installed with pip.

.. code-block:: bash
pip install compas_session
Latest
======

The latest version can be installed from local source.

.. code-block:: bash
git clone https://github.com/blockresearchgroup/compas_session.git
cd compas_session
pip install -e .
Development
===========

To install `compas_session` for development, install from local source with the "dev" requirements.

.. code-block:: bash
git clone https://github.com/blockresearchgroup/compas_session.git
cd compas_session
pip install -e ".[dev]"
17 changes: 17 additions & 0 deletions docs/tutorial.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
********************************************************************************
Tutorial
********************************************************************************

More info coming soon ...


.. code-block:: python
from compas.datastructures import Mesh
from compas_session.namedsession import NamedSession
session = NamedSession("COMPAS")
scene = session.scene()
mesh = Mesh.from_meshgrid(10, 10)
scene.add(mesh)
scene.record("Add Mesh")
session.dump("session.json")
2 changes: 0 additions & 2 deletions src/compas_session/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from __future__ import print_function

import os


Expand Down
2 changes: 0 additions & 2 deletions src/compas_session/__main__.py

This file was deleted.

179 changes: 166 additions & 13 deletions src/compas_session/namedsession.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
import os
import pathlib
import tempfile
from typing import Any
from typing import Callable
from typing import Optional
from typing import Union

import compas
import compas.data
Expand All @@ -16,6 +20,22 @@ class NamedSessionError(Exception):


class NamedSession:
"""Class representing a data session that can be identified by its name.
The class is implemented such that each named instance is a singleton.
This means that during the lifetime of a program only one instance with a specific can exist,
and that all sessions created with the same name, refer to the same session object instance.
Parameters
----------
name : str
The name of the unique object instance.
basedir : str or Path-like, optional
A "working" directory that serves as the root
for storing (temporary) session data.
"""

_instances = {}
_is_inited = False

Expand All @@ -26,7 +46,11 @@ def __new__(cls, *, name):
cls._instances[name] = instance
return cls._instances[name]

def __init__(self, name=None, basedir=None):
def __init__(
self,
name: Optional[str] = None,
basedir: Optional[Union[str, pathlib.Path]] = None,
) -> None:
if not self._is_inited:
self.name = name
self.data = {}
Expand All @@ -52,27 +76,110 @@ def __getitem__(self, key):
def __setitem__(self, key, value):
self.data[key] = value

def get(self, key, default=None):
def get(self, key: str, default: Any = None) -> Any:
"""Return the value for `key` if `key` is in the session, else return `default` or None.
Parameters
----------
key : str
The identifier of the data value.
default : Any, optional
A default value.
Returns
-------
Any
The session data value corresponding to the key/identifier,
or the default value if no entry with the given key/identifier exists.
"""
if key not in self.data:
return default
return self.data[key]

def set(self, key, value):
def set(self, key: str, value: Any) -> None:
"""Insert `key` in the session, and assign `value` to it.
Parameters
----------
key : str
The session key.
value : Any
The value assigned to `key` in the session.
Returns
-------
None
"""
self.data[key] = value

def setdefault(self, key, factory):
def setdefault(self, key: str, factory: Callable) -> Any:
"""Return the value of `key` in the session.
If `key` doesn't exist in the session, assign and return the result of calling `factory`.
Parameters
----------
key : str
The session key.
factory : Callable
A callable factory object to generate a valu if `key` is missing.
Returns
-------
Any
"""
if key not in self.data:
self.set(key, factory())
return self.get(key)

def open(self, filepath):
def load(self, filepath: Union[str, pathlib.Path]) -> None:
"""Replace the session data with the data of a session stored in a file.
Parameters
----------
filepath : str | Path
Location of the file containing the session data.
Returns
-------
None
"""
self.reset()
self.data = compas.json_load(filepath)

def save(self, filepath):
def dump(self, filepath: Union[str, pathlib.Path]) -> None:
"""Dump the data of the current session into a file.
Parameters
----------
filepath : str | Path
Location of the file containing the session data.
Returns
-------
None
"""
compas.json_dump(self.data, filepath)

def undo(self):
def undo(self) -> bool:
"""Move one step backward in recorded session history.
Returns
-------
bool
True if the state was successfully changed.
False otherwise.
Notes
-----
If there are no remaining backward steps in recorded history,
nothing is done and the function returns False.
"""
if self.current < 0:
print("Nothing to undo!")
return False
Expand All @@ -87,7 +194,21 @@ def undo(self):

return True

def redo(self):
def redo(self) -> bool:
"""Move one step forward in recorded session history.
Returns
-------
bool
True if the state was successfully changed.
False otherwise.
Notes
-----
If there are no remaining forward steps in recorded history,
nothing is done and the function returns False.
"""
if self.current == len(self.history) - 1:
print("Nothing more to redo!")
return False
Expand All @@ -98,22 +219,41 @@ def redo(self):

return True

def record(self, eventname):
def record(self, name: str) -> None:
"""Record the current state of the session into session history.
Parameters
----------
name : str
The name of the current state.
Returns
-------
None
"""
if self.current > -1:
if self.current < len(self.history) - 1:
self.history[:] = self.history[: self.current + 1]

fd, filepath = tempfile.mkstemp(dir=self.tempdir, suffix=".json", text=True)

compas.json_dump(self.data, filepath)
self.history.append((filepath, eventname))
self.history.append((filepath, name))

h = len(self.history)
if h > self.depth:
self.history[:] = self.history[h - self.depth :]
self.current = len(self.history) - 1

def reset(self):
def reset(self) -> None:
"""Reset session history.
Returns
-------
None
"""
self.current = -1
self.depth = 53
for filepath, eventname in self.history:
Expand All @@ -129,8 +269,21 @@ def reset(self):
# Firs-class citizens
# =============================================================================

def scene(self, name=None):
# type: (str | None) -> Scene
def scene(self, name: Optional[str] = None) -> Scene:
"""Return the scene with the given name if it is in the session.
Otherwise create a new scene in the session under the given name and return it.
Parameters
----------
name : str, optional
The name of the scene.
If none is provided, the following name is used ``f"{self.name}.Scene"``.
Returns
-------
:class:`Scene`
"""
name = name or f"{self.name}.Scene"
scene: Scene = self.setdefault(name, factory=Scene)
scene.name = name
Expand Down

0 comments on commit d0f0caa

Please sign in to comment.