diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b61b9c3f6bbb5af230f61a7520857d4614948b9..9d211b7e2ad48363cc414f2bd02263bc30c209e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.6.1] - 2021-12-03 ## + +### Fixed ### + +- #50 keyring can be used as password input method again +* #81 compare_entities from apiutils does not compare entity values + ## [0.6.0] - 2021-10-19 ## ### Added ### diff --git a/setup.py b/setup.py index 03ada739d3babe73b5a2262075f2fb2ec6d808db..0eda58e813bb88e3d63b8ad064db362069328dd1 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ from setuptools import find_packages, setup MAJOR = 0 MINOR = 6 -MICRO = 0 +MICRO = 1 PRE = "" # e.g. rc0, alpha.1, 0.beta-23 ISRELEASED = True diff --git a/src/caosdb/apiutils.py b/src/caosdb/apiutils.py index b3d5df698baceacf671c5171430dfa48b3c881b5..21a8cc7ca700a8b119786dbef082db286ead5d57 100644 --- a/src/caosdb/apiutils.py +++ b/src/caosdb/apiutils.py @@ -30,15 +30,15 @@ Some simplified functions for generation of records etc. import sys import tempfile -from collections.abc import Iterable import warnings +from collections.abc import Iterable from subprocess import call from caosdb.common.datatype import (BOOLEAN, DATETIME, DOUBLE, FILE, INTEGER, REFERENCE, TEXT, is_reference) from caosdb.common.models import (Container, Entity, File, Property, Query, - Record, RecordType, get_config, - execute_query) + Record, RecordType, execute_query, + get_config) def new_record(record_type, name=None, description=None, @@ -561,7 +561,23 @@ def getCommitIn(folder): COMPARED = ["name", "role", "datatype", "description", "importance"] -def compare_entities(old_entity, new_entity): +def compare_entities(old_entity: Entity, new_entity: Entity): + """ + Compare two entites. + + Return a tuple of dictionaries, the first index belongs to additional information for old + entity, the second index belongs to additional information for new entity. + + Additional information means in detail: + - Additional parents (a list under key "parents") + - Information about properties: + - Each property lists either an additional property or a property with a changed: + - ... datatype + - ... importance or + - ... value (not implemented yet) + In case of changed information the value listed under the respective key shows the + value that is stored in the respective entity. + """ olddiff = {"properties": {}, "parents": []} newdiff = {"properties": {}, "parents": []} @@ -616,13 +632,16 @@ def compare_entities(old_entity, new_entity): newdiff["properties"][prop.name]["importance"] = \ new_entity.get_importance(prop.name) - if ((prop.datatype is not None and - matching[0].datatype is not None) and - (prop.datatype != matching[0].datatype)): + if (prop.datatype != matching[0].datatype): olddiff["properties"][prop.name]["datatype"] = prop.datatype newdiff["properties"][prop.name]["datatype"] = \ matching[0].datatype + if (prop.value != matching[0].value): + olddiff["properties"][prop.name]["value"] = prop.value + newdiff["properties"][prop.name]["value"] = \ + matching[0].value + if (len(newdiff["properties"][prop.name]) == 0 and len(olddiff["properties"][prop.name]) == 0): newdiff["properties"].pop(prop.name) @@ -700,6 +719,7 @@ def apply_to_ids(entities, func): entities : list of Entity func : function with one parameter. """ + for entity in entities: _apply_to_ids_of_entity(entity, func) diff --git a/src/caosdb/connection/authentication/keyring.py b/src/caosdb/connection/authentication/keyring.py index d8be7ddf030577545230c9111fdad542b6d6e7e2..99d184136c20b23557efea0b54c648095a8d3ab2 100644 --- a/src/caosdb/connection/authentication/keyring.py +++ b/src/caosdb/connection/authentication/keyring.py @@ -28,7 +28,7 @@ retrieve the password. """ import sys -import imp +import importlib from getpass import getpass from caosdb.exceptions import ConfigurationError from .external_credentials_provider import ExternalCredentialsProvider @@ -52,17 +52,13 @@ def get_authentication_provider(): def _get_external_keyring(): try: - fil, pathname, desc = imp.find_module("keyring", sys.path[1:]) - module = imp.load_module("external_keyring", fil, pathname, desc) - return module + return importlib.import_module("keyring") except ImportError: raise RuntimeError( "The keyring password method requires installation of the" "keyring python package. On linux with python < 3.5, " "this requires the installation of dbus-python as a " "system package.") - finally: - fil.close() def _call_keyring(**config): @@ -74,7 +70,6 @@ def _call_keyring(**config): url = config.get("url") username = config.get("username") app = "caosdb — {}".format(url) - password = _call_keyring(app=app, username=username) external_keyring = _get_external_keyring() password = external_keyring.get_password(app, username) if password is None: diff --git a/src/caosdb/yamlapi.py b/src/caosdb/yamlapi.py index 69928af1568bf2150288844d74d606e39d598d0b..80bb4b13e4d1626c5d29c8950f3a22bbb73e0fdb 100644 --- a/src/caosdb/yamlapi.py +++ b/src/caosdb/yamlapi.py @@ -98,7 +98,7 @@ def yaml_to_xml(yamlstr): The string to load the yaml document from. """ - return dict_to_xml(yaml.safe_load(yamlstr)) + return dict_to_xml(yaml.load(yamlstr, Loader=yaml.SafeLoader)) def process(text): diff --git a/unittests/test_apiutils.py b/unittests/test_apiutils.py index 264b4c880022e6fd135426864bf9c5084c047eca..717595d049a5a7c27b644dc6079d02efa1cefb71 100644 --- a/unittests/test_apiutils.py +++ b/unittests/test_apiutils.py @@ -26,11 +26,14 @@ # Test apiutils # A. Schlemmer, 02/2018 -import caosdb as db import pickle import tempfile -from caosdb.apiutils import apply_to_ids, create_id_query, resolve_reference + +import caosdb as db import caosdb.apiutils +from caosdb.apiutils import (apply_to_ids, compare_entities, create_id_query, + resolve_reference) + from .test_property import testrecord @@ -67,7 +70,8 @@ def test_apply_to_ids(): def test_id_query(): ids = [1, 2, 3, 4, 5] - assert create_id_query(ids) == 'FIND ENTITY WITH ID=1 OR ID=2 OR ID=3 OR ID=4 OR ID=5' + assert create_id_query(ids) == 'FIND ENTITY WITH ID=1 OR ID=2 OR ID=3 OR '\ + 'ID=4 OR ID=5' def test_resolve_reference(): @@ -77,8 +81,10 @@ def test_resolve_reference(): prop = db.Property(id=1, datatype=db.REFERENCE, value=100) prop.is_valid = lambda: True items = [200, 300, 400] - prop_list = db.Property(datatype=db.LIST(db.REFERENCE), value=items) - prop_list2 = db.Property(datatype=db.LIST(db.REFERENCE), value=[db.Record(id=500)]) + prop_list = db.Property(datatype=db.LIST(db.REFERENCE), + value=items) + prop_list2 = db.Property(datatype=db.LIST(db.REFERENCE), + value=[db.Record(id=500)]) resolve_reference(prop) resolve_reference(prop_list) resolve_reference(prop_list2) @@ -86,6 +92,7 @@ def test_resolve_reference(): assert isinstance(prop.value, db.Entity) prop_list_ids = [] + for i in prop_list.value: prop_list_ids.append(i.id) assert isinstance(i, db.Entity) @@ -102,3 +109,38 @@ def test_resolve_reference(): # restore retrive_entity_with_id caosdb.apiutils.retrieve_entity_with_id = original_retrieve_entity_with_id + + +def test_compare_entities(): + r1 = db.Record() + r2 = db.Record() + r1.add_parent("bla") + r2.add_parent("bla") + r1.add_parent("lopp") + r1.add_property("test", value=2) + r2.add_property("test", value=2) + r1.add_property("tests", value=3) + r2.add_property("tests", value=45) + r1.add_property("tester", value=3) + r2.add_property("tester", ) + r1.add_property("tests_234234", value=45) + r2.add_property("tests_TT", value=45) + + diff_r1, diff_r2 = compare_entities(r1, r2) + + assert len(diff_r1["parents"]) == 1 + assert len(diff_r2["parents"]) == 0 + assert len(diff_r1["properties"]) == 3 + assert len(diff_r2["properties"]) == 3 + + assert "test" not in diff_r1["properties"] + assert "test" not in diff_r2["properties"] + + assert "tests" in diff_r1["properties"] + assert "tests" in diff_r2["properties"] + + assert "tester" in diff_r1["properties"] + assert "tester" in diff_r2["properties"] + + assert "tests_234234" in diff_r1["properties"] + assert "tests_TT" in diff_r2["properties"] diff --git a/unittests/test_property.py b/unittests/test_property.py index 834b1be582c58c60f70331de9cb0d0d6414fd6c9..7c756117765e510587c00d818e39fb3945d44c53 100644 --- a/unittests/test_property.py +++ b/unittests/test_property.py @@ -24,15 +24,18 @@ # ** end header # """Tests for the Property class.""" +import os + import caosdb as db from caosdb import Entity, Property, Record # pylint: disable=missing-docstring from lxml import etree parser = etree.XMLParser(remove_comments=True) -testrecord = Record._from_xml(Record(), - etree.parse("unittests/test_record.xml", - parser).getroot()) +testrecord = Record._from_xml( + Record(), + etree.parse(os.path.join(os.path.dirname(__file__), "test_record.xml"), + parser).getroot()) def test_is_entity(): @@ -48,7 +51,8 @@ def test_instance_variables(): def test_null_empty_text_value_1(): - assert testrecord.get_property("LISTofTEXT").value == ["One", "Two", "Three", None, ""] + assert testrecord.get_property("LISTofTEXT").value == ["One", "Two", + "Three", None, ""] def test_null_empty_text_value_2():