diff --git a/CHANGELOG.md b/CHANGELOG.md index 622d5678c38257fecba88e899aa571a731a5b3a9..38b470db9d36675ffcef0b7e1434a08c3be7f407 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed ### +* #53 Documentation of inheritance + ### Security ### ## [0.5.2] - 2021-06-03 ## diff --git a/README.md b/README.md index f81202e0c3cd1a54cefcf4b112a7778bb4ddb8f2..04b34cbc07c98e73740b13200ed83fe067af99d2 100644 --- a/README.md +++ b/README.md @@ -28,14 +28,18 @@ By participating, you are expected to uphold our [Code of Conduct](https://gitla * You found a bug, have a question, or want to request a feature? Please [create an issue](https://gitlab.com/caosdb/caosdb-pylib/-/issues). -* You want to contribute code? Please fork the repository and create a merge -request in GitLab and choose this repository as target. Make sure to select -"Allow commits from members who can merge the target branch" under Contribution -when creating the merge request. This allows our team to work with you on your request. -- If you have a suggestion for the [documentation](https://docs.indiscale.com/caosdb-pylib/), +* You want to contribute code? + * **Forking:** Please fork the repository and create a merge request in GitLab and choose this repository as + target. Make sure to select "Allow commits from members who can merge the target branch" under + Contribution when creating the merge request. This allows our team to work with you on your + request. + * **Code style:** This project adhers to the PEP8 recommendations, you can test your code style + using the `autopep8` tool (`autopep8 -i -r ./`). Please write your doc strings following the + [NumpyDoc](https://numpydoc.readthedocs.io/en/latest/format.html) conventions. +* If you have a suggestion for the [documentation](https://docs.indiscale.com/caosdb-pylib/), the preferred way is also a merge request as describe above (the documentation resides in `src/doc`). However, you can also create an issue for it. -- You can also contact us at **info (AT) caosdb.de** and join the +* You can also contact us at **info (AT) caosdb.de** and join the CaosDB community on [#caosdb:matrix.org](https://matrix.to/#/!unwwlTfOznjEnMMXxf:matrix.org). diff --git a/README_SETUP.md b/README_SETUP.md index 30e53ac1c65763fb52b711a215f682c01d2e570e..9da548395073643c16539cef180c4d6412dd8d46 100644 --- a/README_SETUP.md +++ b/README_SETUP.md @@ -143,10 +143,6 @@ Now would be a good time to continue with the [tutorials](tutorials/index). ## Run Unit Tests tox -## Code Formatting - -autopep8 -i -r ./ - ## Documentation ## Build documentation in `build/` with `make doc`. diff --git a/src/caosdb/__init__.py b/src/caosdb/__init__.py index 4043bbed3283c07d5a1ff7e3dbd77593a7f82fb1..7e06885fe495c1e8c4ccc99b7d0c0f8ff8c34b5b 100644 --- a/src/caosdb/__init__.py +++ b/src/caosdb/__init__.py @@ -49,6 +49,10 @@ from caosdb.common.models import (ACL, ALL, FIX, NONE, OBLIGATORY, RECOMMENDED, from caosdb.configuration import _read_config_files, configure, get_config from caosdb.connection.connection import configure_connection, get_connection from caosdb.exceptions import * -from caosdb.version import version as __version__ +try: + from caosdb.version import version as __version__ +except ModuleNotFoundError: + version = "uninstalled" + __version__ = version _read_config_files() diff --git a/src/caosdb/common/models.py b/src/caosdb/common/models.py index efd4a3e7af55297588bf03f869f18846d991f3f0..6ec49df2722170805fb6230753f36503870a8821 100644 --- a/src/caosdb/common/models.py +++ b/src/caosdb/common/models.py @@ -431,14 +431,39 @@ class Entity(object): def add_parent(self, parent=None, **kwargs): # @ReservedAssignment """Add a parent to this entity. - The first parameter is meant to identify the parent entity. So the method expects an instance of - Entity, an integer or a string here. Even though, by means of the **kwargs parameter you may pass - more parameters to this method. Accepted keywords are: id, name, inheritance. Any other keyword is - ignored right now but this may change in the future. - - @param parent: An entity, an id or a name. - @param **kwargs: Accepted keywords: id, name, inheritance. - @raise UserWarning: If neither a 'parent' parameter, nor the 'id', nor 'name' parameter is passed to this method. + Parameters + ---------- + parent : Entity or int or str or None + The parent entity, either specified by the Entity object + itself, or its id or its name. Default is None. + **kwargs : dict, optional + Additional keyword arguments for specifying the parent by + name or id, and for specifying the mode of inheritance. + + id : int + Integer id of the parent entity. Ignored if `parent` + is not None. + name : str + Name of the parent entity. Ignored if `parent is not + none`. + inheritance : str + One of ``obligatory``, ``recommended``, ``suggested``, or ``fix``. Specifies the + minimum importance which parent properties need to have to be inherited by this + entity. If no `inheritance` is given, no properties will be inherited by the child. + This parameter is case-insensitive. + + Note that the behaviour is currently not yet specified when assigning parents to + Records, it only works for inheritance of RecordTypes (and Properties). + + For more information, it is recommended to look into the + :ref:`data insertion tutorial<tutorial-inheritance-properties>`. + + Raises + ------ + UserWarning + If neither a `parent` parameter, nor the `id`, nor `name` + parameter is passed to this method. + """ name = (kwargs['name'] if 'name' in kwargs else None) pid = (kwargs['id'] if 'id' in kwargs else None) @@ -1435,6 +1460,23 @@ class Property(Entity): property=property, value=value, **copy_kwargs) def add_parent(self, parent=None, **kwargs): + """Add a parent Entity to this Property. + + Parameters + ---------- + parent : Entity or int or str or None, optional + The parent entity + **kwargs : dict, optional + Additional keyword arguments specifying the parent Entity + by id or name, and specifying the inheritance level. See + :py:meth:`Entity.add_parent` for more information. Note + that by default, `inheritance` is set to ``fix``. + + See Also + -------- + Entity.add_parent + + """ copy_kwargs = kwargs.copy() if 'inheritance' not in copy_kwargs: @@ -1513,6 +1555,24 @@ class RecordType(Entity): **copy_kwargs) def add_parent(self, parent=None, **kwargs): + """Add a parent to this RecordType + + Parameters + ---------- + parent : Entity or int or str or None, optional + The parent entity, either specified by the Entity object + itself, or its id or its name. Default is None. + **kwargs : dict, optional + Additional keyword arguments specifying the parent Entity by id or + name, and specifying the inheritance level. See + :py:meth:`Entity.add_parent` for more information. Note + that by default, `inheritance` is set to ``obligatory``. + + See Also + -------- + Entity.add_parent + + """ copy_kwargs = kwargs.copy() if 'inheritance' not in copy_kwargs: diff --git a/src/caosdb/connection/connection.py b/src/caosdb/connection/connection.py index 2cb31f425b14bf382fae32f62af79a4bd6ef0301..9e273a56778737033fda9f342f967f56946b501b 100644 --- a/src/caosdb/connection/connection.py +++ b/src/caosdb/connection/connection.py @@ -41,7 +41,11 @@ from caosdb.exceptions import (CaosDBException, HTTPClientError, HTTPResourceNotFoundError, HTTPServerError, HTTPURITooLongError) -from caosdb.version import version +try: + from caosdb.version import version +except ModuleNotFoundError: + version = "uninstalled" + from pkg_resources import resource_filename from .interface import CaosDBHTTPResponse, CaosDBServerConnection diff --git a/src/caosdb/exceptions.py b/src/caosdb/exceptions.py index f02a4630356726f99d8439fd821b6dd327ab22c7..fdd2e11f1dfb8857f86942df2534d732bad9a793 100644 --- a/src/caosdb/exceptions.py +++ b/src/caosdb/exceptions.py @@ -189,8 +189,8 @@ class TransactionError(CaosDBException): error_t. If direct_children_only is True, only direct children are checked. - Parameters: - ----------- + Parameters + ---------- error_t : EntityError error type to be checked direct_children_only: bool, optional @@ -199,8 +199,8 @@ class TransactionError(CaosDBException): children, i.e., all errors in self.all_errors are used. Default is false. - Returns: - -------- + Returns + ------- has_error : bool True if at least one of the children is of type error_t, False otherwise. diff --git a/src/doc/Makefile b/src/doc/Makefile index 8b533626f6665fa2a3491ea5d319b58740c05299..64219c5957ee963e84f9305685f2ec4e8ed3d761 100644 --- a/src/doc/Makefile +++ b/src/doc/Makefile @@ -45,4 +45,4 @@ doc-help: @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) apidoc: - @$(SPHINXAPIDOC) -o _apidoc $(PY_BASEDIR) --separate + @$(SPHINXAPIDOC) -o _apidoc --separate $(PY_BASEDIR) diff --git a/src/doc/conf.py b/src/doc/conf.py index 1865af123ab1abb2e44e9ae714a229b1383794f0..b05fa1c71c1dcd0b59916594818449d2ebc574bd 100644 --- a/src/doc/conf.py +++ b/src/doc/conf.py @@ -8,16 +8,18 @@ # -- Path setup -------------------------------------------------------------- -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. +# If extensions (or modules to document with autodoc) are in another directory, add these +# directories to sys.path here. This is particularly necessary if this package is installed at a +# different version, for example via `pip install`. # -# import os -# import sys -# sys.path.insert(0, os.path.abspath('../caosdb')) - +# If the directory is relative to the documentation root, use os.path.abspath to make it absolute, +# like shown here. +# +import os +import sys +sys.path.insert(0, os.path.abspath('..')) -import sphinx_rtd_theme +import sphinx_rtd_theme # noqa: E402 # -- Project information ----------------------------------------------------- @@ -29,7 +31,7 @@ author = 'Daniel Hornung' # The short X.Y version version = '0.5.2' # The full version, including alpha/beta/rc tags -#release = '0.5.2-rc2' +# release = '0.5.2-rc2' release = '0.5.2' @@ -184,14 +186,22 @@ epub_exclude_files = ['search.html'] # -- Extension configuration ------------------------------------------------- +# True to prefix each section label with the name of the document it is in, followed by a colon. For +# example, index:Introduction for a section called Introduction that appears in document +# index.rst. Useful for avoiding ambiguity when the same section heading appears in different +# documents. +# +# Note: This stops "normal" links from working, so it should be kept at False. +# autosectionlabel_prefix_document = True + # -- Options for intersphinx ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html#confval-intersphinx_mapping intersphinx_mapping = { "python": ("https://docs.python.org/", None), - "caosdb-mysqlbackend": ("https://caosdb.gitlab.io/caosdb-mysqlbackend/", + "caosdb-mysqlbackend": ("https://docs.indiscale.com/caosdb-mysqlbackend/", None), - "caosdb-server": ("https://caosdb.gitlab.io/caosdb-server/", None), + "caosdb-server": ("https://docs.indiscale.com/caosdb-server/", None), } diff --git a/src/doc/tutorials/Data-Insertion.rst b/src/doc/tutorials/Data-Insertion.rst index 2ead1cc259c807ee12f2459f7e452558eb1b63a2..22fb9461d6916003b2dad496ff3487df335c8dcc 100644 --- a/src/doc/tutorials/Data-Insertion.rst +++ b/src/doc/tutorials/Data-Insertion.rst @@ -4,9 +4,9 @@ Data Insertion Data Models ~~~~~~~~~~~ -Data is stored and structured in CaosDB using a concept of RecordTypes, -Properties, Records etc. If you do not know what these are, please look -at the chapter :any:`caosdb-server:Data Model` . +Data is stored and structured in CaosDB using a concept of RecordTypes, Properties, Records etc. If +you do not know what these are, please look at the chapter :doc:`Data +Model<caosdb-server:Data-Model>` in the CaosDB server documentation. In order to insert some actual data, we need to create a data model using RecordTypes and Properties (You may skip this if you use a CaosDB @@ -35,6 +35,42 @@ two more Properties and a RecordType: container.extend([a, b, epsilon, recordtype]) container.insert() +.. _tutorial-inheritance-properties: + +Inheritance of Properties +------------------------- + +Suppose you want to create a new RecordType “2D_BarkleySimulation†+that denotes spatially extended Barkley simulations. This is a subtype +of the “BarkleySimulation†RecordType above and should have all its +parameters, i.e., properties. It may be assigned more, e.g., spatial +resolution, but we'll omit this for the sake of brevity for now. + +.. code:: python + + rt = db.RecordType(name="2D_BarkleySimulation", + description="Spatially extended Barkley simulation") + # inherit all properties from the BarkleySimulation RecordType + rt.add_parent(name="BarkleySimulation", inheritance="all") + rt.insert() + + print(rt.get_property(name="epsilon").importance) ### rt has a "epsilon" property with the same importance as "BarkleySimulation" + +The parameter ``inheritance=(obligatory|recommended|fix|all|none)`` of +:py:meth:`Entity.add_parent()<caosdb.common.models.Entity.add_parent>` tells the server to assign +all properties of the parent RecordType with the chosen importance (and properties with a higher +importance) to the child RecordType +automatically upon insertion. See the chapter on `importance +<https://docs.indiscale.com/caosdb-server/specification/RecordType.html#importance>`_ in the +documentation of the CaosDB server for more information on the importance and inheritance of +properties. + +.. note:: + + The inherited properties will only be visible after the insertion since they are set by the + CaosDB server, not by the Python client. + + Insert Actual Data ~~~~~~~~~~~~~~~~~~ @@ -108,32 +144,6 @@ Useful is also, that you can insert directly tabular data. With this example file `test.csv <uploads/4f2c8756a26a3984c0af09d206d583e5/test.csv>`__. -Inheritance of Properties -------------------------- - -Given, you want to insert a new RecordType “Fridge temperatur -experiment†as a child of the existing RecordType “Experimentâ€. The -latter may have an obligatory Property “date†(since every experiment is -conducted at some time). It is a natural way of thinking, that every sub -type of “Experiment†also has this obligatory Property—in terms of -object oriented programing the “Fridge temperatur experiment†*inherits* -that Property. - -:: - - rt = h.RecordType(name="Fridge temperatur experiment", - description="RecordType which inherits all obligatory properties from Experiment" - ).add_parent(name="Experiment", inheritance="obligatory").insert() - - print(rt.get_property(name="date").importance) ### rt now has a "date"-property -> this line prints "obligatory" - -The parameter *``inheritance=(obligatory|recommended|fix|all|none)``* of -``add_parent`` tells the server to assign obligatory:: properties of the -parent to the child automatically, recommended:: properties of the -parent to the child automatically, fix:: properties of the parent to the -child automatically, all:: properties of the parent to the child -automatically, none:: of the properties of the parent to child -automatically, File Update -----------