diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c8a144dc939f3a58d1f9346929ad5e32d62d213..a407cd214ba120392df9330811984abb09df7b2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed ### +* Updated error-handling tutorial in documentation to reflect the new + error classes + ### Deprecated ### ### Removed ### @@ -28,20 +31,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.5.1] - 2021-02-12 ## -### Added ### - -### Changed ### - -### Deprecated ### - -### Removed ### - ### Fixed ### * #43 - Error with `execute_query` when server doesn't support query caching. -### Security ### - ## [0.5.0] - 2021-02-11 ## ### Added ### @@ -74,18 +67,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 `QueryNotUniqueError` if no or more than one possible candidate is found, respectively. -### Deprecated ### - ### Removed ### * Dynamic exception type `EntityMultiError`. * `get_something` functions from all error object in `exceptions.py` * `AmbiguityException` -### Fixed ### - -### Security ### - ## [0.4.1] - 2021-02-10 ## ### Added ### @@ -95,18 +82,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 entity. * Automated documentation builds: `make doc` -### Changed ### - -### Deprecated ### - -### Removed ### - ### Fixed ### * deepcopy of `_Messages` objects -### Security ### - ## [0.4.0] - 2020-07-17## ### Added ### diff --git a/README_SETUP.md b/README_SETUP.md index 9deadefb27e2a93377bafc59242eacc26057b414..30e53ac1c65763fb52b711a215f682c01d2e570e 100644 --- a/README_SETUP.md +++ b/README_SETUP.md @@ -84,7 +84,7 @@ Typically, you need to change at least the `url` and `username` fields as requir you do not know what to put there, but for the demo instances https://demo.indiscale.com, `username=admin` and `password=caosdb` should work). -### Authentication ## +### Authentication ### The default configuration (that your are asked for your password when ever a connection is created can be changed by setting `password_method`: @@ -109,7 +109,7 @@ The following illustrates the recommended options: #password_method=keyring ``` -### SSL Certificate ## +### SSL Certificate ### In some cases (especially if you are testing CaosDB) you might need to supply an SSL certificate to allow SSL encryption. @@ -118,7 +118,7 @@ an SSL certificate to allow SSL encryption. cacert=/path/to/caosdb.ca.pem ``` -### Further Settings ## +### Further Settings ### As mentioned above, a complete list of options can be found in the [pycaosdb.ini file](https://gitlab.com/caosdb/caosdb-pylib/-/blob/main/examples/pycaosdb.ini) in the examples folder of the source code. @@ -138,7 +138,7 @@ Out[2]: Connection to CaosDB with 501 Records. Note: This setup will ask you for your password whenever a new connection is created. If you do not like this, check out the "Authentication" section in the [configuration documentation](configuration.md). -Now would be a good time to continue with the [tutorials](tutorials.html). +Now would be a good time to continue with the [tutorials](tutorials/index). ## Run Unit Tests tox @@ -147,15 +147,15 @@ tox autopep8 -i -r ./ -## Documentation # +## Documentation ## Build documentation in `build/` with `make doc`. -### Requirements ## +### Requirements ### - `sphinx` - `sphinx-autoapi` - `recommonmark` -### Troubleshooting ## +### Troubleshooting ### If the client is to be executed directly from the `/src` folder, an initial `.\setup.py install --user` must be called. diff --git a/examples/set_permissions.py b/examples/set_permissions.py index 3d9012959fb036705ef9b086af35489238360c14..8162b11bfefb41b1bcdbc74b8e314f99a61d1a4e 100755 --- a/examples/set_permissions.py +++ b/examples/set_permissions.py @@ -25,8 +25,8 @@ As a result, only a specific user or group may access it. -This script assumes that the user specified in the -pycaosdb.ini configuration can create new entities. +This script assumes that the user specified in the pycaosdb.ini +configuration can create new entities. """ @@ -206,7 +206,8 @@ def create_test_entities(): After calling this function, there will be a RecordType "Human Food" with the corresponding Records "Bread", "Tomatoes", and "Twinkies" inserted in the database. """ - rt = db.RecordType(name="Human Food", description="Food that can be eaten only by humans").insert() + rt = db.RecordType( + name="Human Food", description="Food that can be eaten only by humans").insert() food = ("Bread", "Tomatoes", "Twinkies") cont = db.Container() diff --git a/src/doc/Makefile b/src/doc/Makefile index 9841c6618a33ef3148389650d15130e25ec25247..8b533626f6665fa2a3491ea5d319b58740c05299 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) + @$(SPHINXAPIDOC) -o _apidoc $(PY_BASEDIR) --separate diff --git a/src/doc/conf.py b/src/doc/conf.py index 8a3f5b6c273a3b770e853d255d56a80f5b8b12e2..a2bb79dcf0e8730e46c00603ea5380666f2f9b85 100644 --- a/src/doc/conf.py +++ b/src/doc/conf.py @@ -27,9 +27,9 @@ copyright = '2020, IndiScale GmbH' author = 'Daniel Hornung' # The short X.Y version -version = '0.4.0' +version = '0.5.1' # The full version, including alpha/beta/rc tags -release = '0.4.0-rc' +release = '0.5.1-rc' # -- General configuration --------------------------------------------------- @@ -43,6 +43,7 @@ release = '0.4.0-rc' # ones. extensions = [ 'sphinx.ext.autodoc', + 'sphinx.ext.autosectionlabel', 'sphinx.ext.intersphinx', 'sphinx.ext.napoleon', # For Google style docstrings "recommonmark", # For markdown files. diff --git a/src/doc/index.rst b/src/doc/index.rst index 76a2f88f6d31dd9b5f17995b6d54ccc63eb33631..bd29c6c56acf5c173e94ae6471a6aeba56ea4b93 100644 --- a/src/doc/index.rst +++ b/src/doc/index.rst @@ -12,12 +12,12 @@ Welcome to PyCaosDB's documentation! Concepts <concepts> Configuration <configuration> Administration <administration> - API documentation<_apidoc/modules> + API documentation<_apidoc/caosdb> This is the documentation for the Python client library for CaosDB, ``PyCaosDB``. -This documentation helps you to :doc:`get started<getting_started>`, explains the most important -:doc:`concepts<concepts>` and offers a range of :doc:`tutorials<tutorials>`. +This documentation helps you to :doc:`get started<README_SETUP>`, explains the most important +:doc:`concepts<concepts>` and offers a range of :doc:`tutorials<tutorials/index>`. Indices and tables diff --git a/src/doc/tutorials/errors.rst b/src/doc/tutorials/errors.rst index ba386dc31baad1021f01d53b2b12a2623d8278ad..37c53c9b527a0435f9f24ae6c6e71687e73eb963 100644 --- a/src/doc/tutorials/errors.rst +++ b/src/doc/tutorials/errors.rst @@ -1,53 +1,176 @@ Error Handling --------------- +============== -HeartDBException -~~~~~~~~~~~~~~~~ +In case of erroneous transactions, connection problems and a lot of +other cases, PyCaosDB may raise specific errors in order to pinpoint +the problem as precisely as possible. Some of these errors a +representations of errors in the CaosDB server, others stem from +problems that occurred on the client side. + +The errors and exceptions are ordered hierarchically form the most +general exceptions to specific transaction or connection problems. The +most important error types and the hierarchy will be explained in the +following. For more information on specific error types, see also the +:doc:`source code<../_apidoc/caosdb.exceptions>`. + +.. note:: + + Starting from PyCaosDB 0.5, the error handling has changed + significantly. New error classes have been introduced and the + behavior of ``TransactionError`` and ``EntityError`` has been + re-worked. In the following, only the "new" errors are + discussed. Please refer to the documentation of PyCaosDB 0.4.1 and + earlier for the old error handling. + +CaosDBException +---------------- + +``CaosDBException`` is the most generic exception and all other error classes inherit +from this one. Because of its generality, it doesn't tell you much +except that some component of PyCaosDB raised an exception. If you +want to catch all possible CaosDB errors, this is the class to use. 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 +will be raised by the transaction method. The ``TransactionError`` +class is a container for all errors which occur during a +transaction. It usually contains one or more :ref:`entity +errors<EntityError>` which you can inspect in order to learn why the +transaction failed. For this inspection, there are some helpful +attributes and methods provided by the ``TransactionError``: + +* ``entities``: a list of all entities that directly caused at least one error + in this transaction. + +* ``errors``: a list of all ``EntityError`` objects that directly caused the + transaction to fail. + +* ``all_entities``, ``all_errors``: sets of all entities and errors + that, directly or indirectly, caused either this ``TransactionError`` or any of the + ``EntityError`` objects it contains. + +* ``has_error(error_t)``: Check whether an error of type ``error_t`` + occurred during the transaction. + +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). +An ``EntityError`` specifies the entity and the error proper that +caused a transaction to fail. It is never raised on its own but is +contained in a ``TransactionError`` (which may or may not contain +other ``EntityError`` objects) which is then raised. ``EntityError`` +has several :ref:`subclasses<Special Errors>` that further specify the +error that occurred. -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]``. +The ``EntityError`` class is in fact a subclass of +``TransactionError``. Thus, it has the same methods and attributes as +the ``TransactionError`` explained +:ref:`above<TransactionError>`. This is important in case of an +``EntityError`` that was caused by other faulty entities (e.g., broken +parents or properties). In that case these problematic entities and +errors can again be inspected by visiting the ``entities`` and +``errors`` lists as above. 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. +Subclasses of ``EntityError`` for special purposes: + +* ``EntityDoesNotExistError`` + +* ``EntityHasNoDataTypeError`` + +* ``UniqueNamesError`` + +* ``UnqualifiedParentsError`` + +* ``UnqualifiedPropertiesError`` + +* ``ConsistencyError`` + +* ``AuthorizationError`` + +* ``AmbiguousEntityError`` + +BadQueryError +------------- + +A ``BadQueryError`` is raised when a query could not be processed by +the server. In contrast to a ``TransactionError`` it is not +necessarily caused by problematic entities or +containers. ``BadQueryError`` has the two important subclasses +``EmptyUniqueQueryError`` and ``QueryNotUniqueError`` for queries with +``unique=True`` which found no or ambiguous entities, respectively. + +HTTP Errors +----------- + +An ``HTTPClientError`` or an ``HTTPServerError`` is raised in case of +http(s) connection problems caused by the Python client or the CaosDB +server, respectively. There are the following subclasses of +``HTTPClientError`` that are used to specify the connection problem: + +* ``HTTPURITooLongError``: The URI of the request was too long to be + processed by the server. + +* ``HTTPForbiddenError``: You're not allowed to access this resource. + +* ``HTTPResourceNotFoundError``: The requested resource doesn't exist. + +Other Errors +------------ + +There are further subclasses of ``CaosDBException`` that are raised in +case of faulty configurations or other problems. They should be rather +self-explanatory from their names; see the :doc:`source code<../_apidoc/caosdb.exceptions>` +for further information. + +* ``ConfigurationError`` + +* ``LoginFailedError`` + +* ``MismatchingEntitiesError`` + +* ``ServerConfigurationException`` + +Examples +-------- + +.. code-block:: python3 + + import caosdb as db + + def link_and_insert(entity, linked, link=True): + """Link the ENTITY to LINKED and insert it.""" + if link: + entity.add_property(db.Property(name="link", value=linked)) + try: + entity.insert() + except db.TransactionError as tre: + # Unique names problem may be worked around by using another name + if tre.has_error(db.UniqueNamesError): + for ent_error in tre.errors: + if (isinstance(ent_error, db.UniqueNamesError) + and entity in ent_error.entities): + entity.name = entity.name + "_new" # Try again with new name. + link_and_insert(entity, linked, link=False) + break + # Unqualified properties will be handled by the caller + elif tre.has_error(db.UnqualifiedPropertiesError): + for ent_error in tre.errors: + if (isinstance(ent_error, db.UnqualifiedPropertiesError_ + and entity in ent_error.entities): + raise RuntimeError("One of the properties was unqualified: " + str(ent_error)) + # Other problems are not covered by this tutorial + else: + raise NotImplementedError("Unhandled TransactionError: " + str(tre)) diff --git a/src/doc/tutorials/first_steps.rst b/src/doc/tutorials/first_steps.rst index 3eb804776960ba93acb9baf78824f0cf8a06e1f7..34b96bbeca416107fb34feb4707b9ef46fc49fe7 100644 --- a/src/doc/tutorials/first_steps.rst +++ b/src/doc/tutorials/first_steps.rst @@ -2,14 +2,15 @@ First Steps =========== You should have a working connection to a CaosDB instance now. If not, please check out the -:doc:`Getting Started secton</getting_started>`. +:doc:`Getting Started secton</README_SETUP>`. If you are not yet familiar with Records, RecordTypes and Properties used in CaosDB, -please check out the respective part in the `Web Interface Tutorial`_. -You should also know the basics of the CaosDB Query Language (a tutorial is here_). +please check out the respective part in the `Web Interface tutorial`_. +You should also know the basics of the CaosDB Query Language (a tutorial is +`here <https://docs.indiscale.com/caosdb-webui/tutorials/query.html>`_). -We recommend that you connect to the demo instance in order to try out the following -examples. You can do this with +We recommend that you connect to the `demo instance`_ (hosted by `Indiscale`_) in order to try out +the following examples. You can do this with >>> import caosdb as db >>> _ = db.configure_connection( @@ -19,7 +20,7 @@ examples. You can do this with ... password="caosdb") or by using corresponding settings in the configuration file -(see :doc:`Getting Started secton</getting_started>`.). +(see :doc:`Getting Started secton</README_SETUP>`.). However, you can also translate the examples to the data model that you have at hand. Let's start with a simple query. @@ -124,9 +125,6 @@ the result Records and their properties. The next tutorial shows how to make some meaningful use of this. - -.. _here: https://gitlabio.something .. _`demo instance`: https://demo.indiscale.com .. _`IndiScale`: https://indiscale.com -.. _`Web Interface Tutorial`: https://caosdb.gitlab.io/caosdb-webui/tutorials/model.html -.. _here: https://caosdb.gitlab.io/caosdb-webui/tutorials/cql.html +.. _`Web Interface tutorial`: https://docs.indiscale.com/caosdb-webui/tutorials/first_steps.html