Skip to content
Snippets Groups Projects
Commit 060ab961 authored by Timm Fitschen's avatar Timm Fitschen
Browse files

Initial Commit

AGPLv3 Veröffentlichung gemäß Dienstanweisung vom 15. August 2018.
parents
No related branches found
No related tags found
No related merge requests found
Showing
with 470 additions and 0 deletions
# dot files
.*
!/.gitignore
# compiled python and dist stuff
*.egg
__pycache__/
*.pyc
*.egg-info/
dist/
build/
This diff is collapsed.
# Welcome
This is the **CaosDB Python Client Library** repository and a part of the
CaosDB project.
# Setup
Please read the [README_SETUP.md](README_SETUP.md) for instructions on how to
setup this code.
# Further Reading
Please refer to the [official gitlab repository of the CaosDB
project](https://gitlab.gwdg.de/bmp-caosdb/caosdb) for more information.
# License
Copyright (C) 2018 Research Group Biomedical Physics, Max Planck Institute for
Dynamics and Self-Organization Göttingen.
All files in this repository are licensed under a [GNU Affero General Public
License](LICENCE.md) (version 3 or later).
# Installation
pip install . --user
pip install tox --user
# Run Unit Tests
tox
# Code Formatting
autopep8 -i -r ./
[pytest]
testpaths = unittests
\ No newline at end of file
[nosetests]
verbosity=2
detailed-errors=1
with-coverage=1
cover-package=caosdb
cover-inclusive=1
cover-branches=1
cover-erase=1
#with-doctest=1
[pycodestyle]
ignore=E501,E121,E123,E126,E226,E24,E704,W503,W504
setup.py 0 → 100755
#!/bin/python
# -*- encoding: utf-8 -*-
#
# ** header v3.0
# This file is a part of the CaosDB Project.
#
# Copyright (C) 2018 Research Group Biomedical Physics,
# Max-Planck-Institute for Dynamics and Self-Organization Göttingen
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# ** end header
#
"""Install and (nose-)test caosdb."""
from setuptools import setup, find_packages
setup(name='PyCaosDB',
version='0.1.0',
description='Python Interface for CaosDB',
author='Timm Fitschen',
author_email='timm.fitschen@ds.mpg.de',
packages=find_packages('src'),
package_dir={'': 'src'},
install_requires=['lxml>=3.6.4', 'coverage>=4.4.2',
'PyYaml>=3.12', 'future'],
extras_require={'keyring': ['keyring>=13.0.0']},
tests_require=["nose>=1.0"],
)
# -*- coding: utf-8 -*-
#
# ** header v3.0
# This file is a part of the CaosDB Project.
#
# Copyright (C) 2018 Research Group Biomedical Physics,
# Max-Planck-Institute for Dynamics and Self-Organization Göttingen
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# ** end header
#
# Import of the connection function (which is used to connect to the DB):
from os.path import expanduser, join
from os import getcwd
from caosdb.configuration import configure, get_config
from caosdb.common import administration
from caosdb.connection.connection import configure_connection, get_connection
# Import of the basic API classes:
from caosdb.common.models import (QueryTemplate, Permissions, ACL, File, Record,
RecordType, Property, Message, Container,
DropOffBox, Entity, Query, Info, LIST,
DOUBLE, REFERENCE, TEXT, DATETIME, INTEGER,
FILE, BOOLEAN, TIMESPAN, OBLIGATORY,
SUGGESTED, RECOMMENDED, FIX, ALL, NONE)
# Import of exceptions
from caosdb.exceptions import *
from caosdb.common.models import (delete, execute_query, raise_errors,
get_global_acl, get_known_permissions)
# Import of convenience methods:
import caosdb.apiutils
configure(expanduser('~/.pycaosdb.ini'))
configure(join(getcwd(), "pycaosdb.ini"))
This diff is collapsed.
# -*- coding: utf-8 -*-
#
# ** header v3.0
# This file is a part of the CaosDB Project.
#
# Copyright (C) 2018 Research Group Biomedical Physics,
# Max-Planck-Institute for Dynamics and Self-Organization Göttingen
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# ** end header
#
"""missing docstring."""
from lxml import etree
from caosdb.exceptions import (ClientErrorException, AuthorizationException,
EntityDoesNotExistError)
from caosdb.connection.connection import get_connection
from caosdb.common.utils import xml2str
def _retrieve_user(name, realm=None, **kwargs):
con = get_connection()
try:
return con._http_request(method="GET", path="User/" + (realm + "/" + name if realm is not None else name), **kwargs).read()
except AuthorizationException as e:
e.msg = "You are not permitted to retrieve this user."
raise
except EntityDoesNotExistError as e:
e.msg = "User does not exist."
raise
def _delete_user(name, **kwargs):
con = get_connection()
try:
return con._http_request(method="DELETE", path="User/" + name, **kwargs).read()
except AuthorizationException as e:
e.msg = "You are not permitted to delete this user."
raise
except EntityDoesNotExistError as e:
e.msg = "User does not exist."
raise
def _update_user(name, realm=None, password=None, status=None,
email=None, entity=None, **kwargs):
con = get_connection()
params = {}
if password is not None:
params["password"] = password
if status is not None:
params["status"] = status
if email is not None:
params["email"] = email
if entity is not None:
params["entity"] = str(entity)
try:
return con.put_form_data(entity_uri_segment="User/" + (realm + "/" + name if realm is not None else name), params=params, **kwargs).read()
except EntityDoesNotExistError as e:
e.msg = "User does not exist."
raise
except AuthorizationException as e:
e.msg = "You are not permitted to update this user."
raise
except ClientErrorException as e:
if e.status == 409:
e.msg = "Entity does not exist."
raise
def _insert_user(name, password=None, status=None, email=None, entity=None, **kwargs):
con = get_connection()
params = {"username": name}
if password is not None:
params["password"] = password
if status is not None:
params["status"] = status
if email is not None:
params["email"] = email
if entity is not None:
params["entity"] = entity
try:
return con.post_form_data(entity_uri_segment="User", params=params, **kwargs).read()
except AuthorizationException as e:
e.msg = "You are not permitted to insert a new user."
raise e
except ClientErrorException as e:
if e.status == 409:
e.msg = "User name is yet in use."
raise e
def _insert_role(name, description, **kwargs):
con = get_connection()
try:
return con.post_form_data(entity_uri_segment="Role", params={"role_name": name, "role_description": description}, **kwargs).read()
except AuthorizationException as e:
e.msg = "You are not permitted to insert a new role."
raise
except ClientErrorException as e:
if e.status == 409:
e.msg = "Role name is already in use. Choose a different name."
raise
def _update_role(name, description, **kwargs):
con = get_connection()
try:
return con.put_form_data(entity_uri_segment="Role/" + name, params={"role_description": description}, **kwargs).read()
except AuthorizationException as e:
e.msg = "You are not permitted to update this role."
raise
except EntityDoesNotExistError as e:
e.msg = "Role does not exist."
raise
def _retrieve_role(name, **kwargs):
con = get_connection()
try:
return con._http_request(method="GET", path="Role/" + name, **kwargs).read()
except AuthorizationException as e:
e.msg = "You are not permitted to retrieve this role."
raise
except EntityDoesNotExistError as e:
e.msg = "Role does not exist."
raise
def _delete_role(name, **kwargs):
con = get_connection()
try:
return con._http_request(method="DELETE", path="Role/" + name, **kwargs).read()
except AuthorizationException as e:
e.msg = "You are not permitted to delete this role."
raise
except EntityDoesNotExistError as e:
e.msg = "Role does not exist."
raise
def _set_roles(username, roles, realm=None, **kwargs):
xml = etree.Element("Roles")
for r in roles:
xml.append(etree.Element("Role", name=r))
body = xml2str(xml)
con = get_connection()
try:
body = con._http_request(method="PUT", path="UserRoles/" + (realm + "/" + username if realm is not None else username), body=body, **kwargs).read()
except AuthorizationException as e:
e.msg = "You are not permitted to set this user's roles."
raise
except EntityDoesNotExistError as e:
e.msg = "User does not exist."
raise
except ClientErrorException as e:
if e.status == 409:
e.msg = "Role does not exist."
raise
ret = set()
for r in etree.fromstring(body)[0]:
if r.tag == "Role":
ret.add(r.get("name"))
return ret
def _get_roles(username, realm=None, **kwargs):
con = get_connection()
try:
body = con._http_request(method="GET", path="UserRoles/" + (realm + "/" + username if realm is not None else username), **kwargs).read()
except AuthorizationException as e:
e.msg = "You are not permitted to retrieve this user's roles."
raise
except EntityDoesNotExistError as e:
e.msg = "User does not exist."
raise
ret = set()
for r in etree.fromstring(body)[0]:
ret.add(r.get("name"))
return ret
def _set_permissions(role, permission_rules, **kwargs):
xml = etree.Element("PermissionRules")
for p in permission_rules:
xml.append(p._to_xml())
body = xml2str(xml)
con = get_connection()
try:
return con._http_request(method="PUT", path="PermissionRules/" + role, body=body, **kwargs).read()
except AuthorizationException as e:
e.msg = "You are not permitted to set this role's permissions."
raise
except EntityDoesNotExistError as e:
e.msg = "Role does not exist."
raise
def _get_permissions(role, **kwargs):
con = get_connection()
try:
return PermissionRule._parse_body(con._http_request(method="GET", path="PermissionRules/" + role, **kwargs).read())
except AuthorizationException as e:
e.msg = "You are not permitted to retrieve this role's permissions."
raise
except EntityDoesNotExistError as e:
e.msg = "Role does not exist."
raise
class PermissionRule():
@staticmethod
def _parse_boolean(bstr):
return str(bstr) in ["True", "true", "TRUE", "yes"]
def __init__(self, action, permission, priority=False):
self._action = action
self._permission = permission
self._priority = PermissionRule._parse_boolean(priority)
def _to_xml(self):
xml = etree.Element(self._action)
xml.set("permission", self._permission)
if self._priority is True:
xml.set("priority", "true")
return xml
@staticmethod
def _parse_element(elem):
return PermissionRule(elem.tag, elem.get(
"permission"), elem.get("priority"))
@staticmethod
def _parse_body(body):
xml = etree.fromstring(body)
ret = set()
for c in xml:
ret.add(PermissionRule._parse_element(c))
return ret
def __str__(self):
return self._action + "(" + self._permission + ")" + \
("P" if self._priority is True else "")
def __repr__(self):
return str(self)
def __hash__(self):
return hash(str(self).lower())
def __eq__(self, other):
return str(other).lower() == str(self).lower()
This diff is collapsed.
# -*- coding: utf-8 -*-
#
# ** header v3.0
# This file is a part of the CaosDB Project.
#
# Copyright (C) 2018 Research Group Biomedical Physics,
# Max-Planck-Institute for Dynamics and Self-Organization Göttingen
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# ** end header
#
"""mising docstring."""
from lxml import etree
from multiprocessing import Lock
from uuid import uuid4
from sys import hexversion
_uuid_lock = Lock()
def xml2str(xml):
return etree.tostring(xml, pretty_print=True, encoding='unicode')
def uuid():
exc = None
ret = None
try:
_uuid_lock.acquire()
ret = uuid4()
except Exception as e:
exc = e
finally:
_uuid_lock.release()
if exc:
raise exc
return ret
def is_int(obj):
try:
int(obj)
return True
except ValueError:
return False
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment