From d3ca49178310086ab34abb56289638a2672facfa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Henrik=20tom=20W=C3=B6rden?= <h.tomwoerden@indiscale.com>
Date: Thu, 11 Feb 2021 17:45:23 +0100
Subject: [PATCH] DOC: added extensive documentation

---
 src/doc/conf.py                           |  12 +-
 src/doc/tutorials/Data-Insertion.rst      | 163 ++++++++++++++++++++++
 src/doc/tutorials/data-model-interface.md |  36 +++++
 src/doc/tutorials/errors.rst              |  53 +++++++
 src/doc/tutorials/first_steps.rst         |   2 +
 src/doc/tutorials/index.rst               |   3 +
 6 files changed, 266 insertions(+), 3 deletions(-)
 create mode 100644 src/doc/tutorials/Data-Insertion.rst
 create mode 100644 src/doc/tutorials/data-model-interface.md
 create mode 100644 src/doc/tutorials/errors.rst

diff --git a/src/doc/conf.py b/src/doc/conf.py
index 9e2924ae..f276f325 100644
--- a/src/doc/conf.py
+++ b/src/doc/conf.py
@@ -182,10 +182,16 @@ epub_exclude_files = ['search.html']
 
 # -- Extension configuration -------------------------------------------------
 
-# -- Options for intersphinx extension ---------------------------------------
+# -- 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/",
+                            None),
+    "caosdb-server": ("https://caosdb.gitlab.io/caosdb-server/", None),
+}
 
-# Example configuration for intersphinx: refer to the Python standard library.
-intersphinx_mapping = {'https://docs.python.org/': None}
 
 # TODO Which options do we want?
 autodoc_default_options = {
diff --git a/src/doc/tutorials/Data-Insertion.rst b/src/doc/tutorials/Data-Insertion.rst
new file mode 100644
index 00000000..2ead1cc2
--- /dev/null
+++ b/src/doc/tutorials/Data-Insertion.rst
@@ -0,0 +1,163 @@
+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` .
+
+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
+instance that already has the required types). So, let’s create a simple
+Property called “a” of datatype double. This is very easy in pylib:
+
+.. code:: python
+
+   a = db.Property(name="a", datatype=db.DOUBLE)
+
+There are a few basic datatypes: db.INTEGER, db.TEXT. See `data
+type <Specification/Datatype>`__ for a full list.
+
+We can create our own small data model for e.g. a simulation by adding
+two more Properties and a RecordType:
+
+.. code:: python
+
+   b = db.Property(name="b", datatype=db.DOUBLE)
+   epsilon = db.Property(name="epsilon", datatype=db.DOUBLE)
+   recordtype = db.RecordType(name="BarkleySimulation")
+   recordtype.add_property(a)
+   recordtype.add_property(b)
+   recordtype.add_property(epsilon)
+   container = db.Container()
+   container.extend([a, b, epsilon, recordtype])
+   container.insert()
+
+Insert Actual Data
+~~~~~~~~~~~~~~~~~~
+
+Suppose the RecordType “Experiment” and the Property “date” exist in the
+database. You can then create single data Records by using the
+corresponding python class:
+
+.. code:: python
+
+   rec = db.Record()
+   rec.add_parent(name="Experiment")
+   rec.add_property(name="date", value="2020-01-07")
+   rec.insert()
+
+Here, the record has a parent: The RecordType “Experiment”. And a
+Property: date.
+
+Note, that if you want to use a property that is not a primitive
+datatype like db.INTEGER and so on, you need to use the ID of the Entity
+that you are referencing.
+
+.. code:: python
+
+   rec = db.Record()
+   rec.add_parent(name="Experiment")
+   rec.add_property(name="report", value=235507)
+   rec.add_property(name="Analysis", value=230007)
+   rec.insert()
+
+Of course, the IDs 235507 and 230007 need to exist in CaosDB. The first
+example shows how to use a db.REFERENCE Property (report) and the second
+shows that you can use any RecordType as Property to reference a Record
+that has such a parent.
+
+Most Records do not have name however it can absolutely make sense. In
+that case use the name argument when creating it. Another useful feature
+is the fact that properties can have units:
+
+.. code:: python
+
+   rec = db.Record("DeviceNo-AB110")
+   rec.add_parent(name="SlicingMachine")
+   rec.add_property(name="weight", value="1749", unit="kg")
+   rec.insert()
+
+If you are in some kind of analysis you can do this in batch mode with a
+container. E.g. if you have a python list ``analysis_results``:
+
+.. code:: python
+
+   cont = db.Container()
+   for date, result in analysis_results:
+      rec = db.Record()
+      rec.add_parent(name="Experiment")
+      rec.add_property(name="date", value=date)
+      rec.add_property(name="result", value=result)
+      cont.append(rec)
+
+   cont.insert()
+
+Useful is also, that you can insert directly tabular data.
+
+.. code:: python
+
+   from caosadvancedtools.table_converter import from_tsv     
+          
+   recs = from_tsv("test.csv", "Experiment")     
+   print(recs)     
+   recs.insert()  
+
+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
+-----------
+
+Updating an existing file by uploading a new version.
+
+1. Retrieve the file record of interest, e.g. by ID:
+
+.. code:: python
+
+   import caosdb as db
+
+   file_upd = db.File(id=174).retrieve()
+
+2. Set the new local file path. The remote file path is stored in the
+   file object as ``file_upd.path`` while the local path can be found in
+   ``file_upd.file``.
+
+.. code:: python
+
+   file_upd.file = "./supplements.pdf"
+
+3. Update the file:
+
+.. code:: python
+
+   file_upd.update()
diff --git a/src/doc/tutorials/data-model-interface.md b/src/doc/tutorials/data-model-interface.md
new file mode 100644
index 00000000..f6967c57
--- /dev/null
+++ b/src/doc/tutorials/data-model-interface.md
@@ -0,0 +1,36 @@
+# Data Models
+
+
+
+You also want to change the datamodel? Also call
+```bash
+pip3 install --user --no-deps .
+```
+in 
+```bash
+CaosDB/data_models
+```
+
+Change to the appropriate directory
+```bash
+cd CaosDB/data_models
+```
+There are "data models" defined in 
+```bash
+caosdb_models
+```
+having an ending like "_model.py"
+A set of data models is also considered to be a model
+You can create an UML representation of a model or a set of models by calling
+```bash
+./model_interface.py -u model_name [model_name2]
+```
+If you have troubles look at
+```bash
+./model_interface.py -h
+```
+You can change existing models (but be careful! I hope you know what you are doing) or add new ones by changing the appropriate files or adding a new XXXX_model.py
+Once you are done, you can sync your changes with the server
+```bash
+./model_interface.py -s model_name [model_name2]
+```
diff --git a/src/doc/tutorials/errors.rst b/src/doc/tutorials/errors.rst
new file mode 100644
index 00000000..ba386dc3
--- /dev/null
+++ b/src/doc/tutorials/errors.rst
@@ -0,0 +1,53 @@
+
+Error Handling
+--------------
+
+HeartDBException
+~~~~~~~~~~~~~~~~
+
+TransactionError
+~~~~~~~~~~~~~~~~
+
+Every transaction (calling ``insert``, ``update``, ``retrieve``, or
+``delete`` on a container or an entity) may finish with errors. They
+indicate, for instance, that an entity does not exist or that you need
+to specify a data type for your property and much more. If and only if
+one or more errors occur during a transaction a ``TransactionError``
+will be raised by the transaction method. The ``TransactionError`` class
+is a container for all errors which occur during a transaction. It can
+help you to find the crucial problems with your transaction by two
+important methods: \* ``get_errors()`` which returns a list of instances
+of ``EntityError``. \* ``get_entities()`` which returns a list of
+entities in the transaction container which are erroneous.
+
+Additionally, ``print(transaction_error`` prints a tree-like
+representation of all errors regarding the transaction in question.
+
+EntityError
+~~~~~~~~~~~
+
+An ``EntityError`` represents a single error that has been returned by
+the server. You might call \* ``get_entity()`` which returns the entity
+which caused the error. \* ``get_description()`` which returns a
+description of the error. \* ``get_code()`` which returns the error code
+(if specified) or 0 (if not).
+
+In fact, the ``EntityError`` class is a subclass of
+``TransactionError``. So, it inherits the ``get_entities()``. Unless
+overridden by subclasses of ``EntityError``, it return a list with only
+one item—the entity which caused this error. Similarly, unless
+overridden by subclasses, the ``get_errors()`` method returns a list
+with only one item—``[self]``.
+
+Special Errors
+~~~~~~~~~~~~~~
+
+Subclasses of ``EntityError`` for special purposes: \*
+``EntityDoesNotExistError`` \* ``EntityHasNoDataTypeError`` \*
+``UniqueNamesError`` \* ``UnqualifiedParentsError`` - overrides
+``get_entities()``: returns all parent entities with errors. - overrides
+``get_errors()``: returns a list of EntityErrors which have been caused
+by parent entities. \* ``UnqualifiedPropertiesError`` - overrides
+``get_entities()``: returns all properties with errors. - overrides
+``get_errors()``: returns a list of EntityErrors which have been caused
+by properties.
diff --git a/src/doc/tutorials/first_steps.rst b/src/doc/tutorials/first_steps.rst
index 3da05b05..3eb80477 100644
--- a/src/doc/tutorials/first_steps.rst
+++ b/src/doc/tutorials/first_steps.rst
@@ -113,6 +113,8 @@ You can download files (if the LinkAhead server has access to them)
 The file will be saved under target_path.
 If the files are large data files, it is often a better idea to only retrieve the path of the file and access them via a local mount.
 
+
+
 Summary
 -------
 
diff --git a/src/doc/tutorials/index.rst b/src/doc/tutorials/index.rst
index 311f7080..3889edb8 100644
--- a/src/doc/tutorials/index.rst
+++ b/src/doc/tutorials/index.rst
@@ -12,4 +12,7 @@ advanced usage of the Python client.
 
    first_steps
    basic_analysis
+   Data-Insertion
+   errors
+   data-model-interface
 
-- 
GitLab