oldaplib 0.3.9__py3-none-any.whl → 0.3.11__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,5 @@
1
1
  import re
2
+ from enum import Flag, auto
2
3
  from functools import partial
3
4
  from typing import Type, Any, Self, cast
4
5
 
@@ -31,6 +32,11 @@ from oldaplib.src.xsd.xsd_qname import Xsd_QName
31
32
 
32
33
  ValueType = LangString | ObservableSet | Xsd
33
34
 
35
+ class SortBy(Flag):
36
+ PROPVAL = auto()
37
+ CREATED = auto()
38
+ LASTMOD = auto()
39
+
34
40
 
35
41
  #@strict
36
42
  class ResourceInstance:
@@ -443,35 +449,47 @@ class ResourceInstance:
443
449
 
444
450
  def get_data_permission(self, context: Context, permission: DataPermission) -> bool:
445
451
  permission_query = context.sparql_context
446
- # language=sparql
447
452
  permission_query += f'''
448
- SELECT (COUNT(?permset) as ?numOfPermsets)
449
- FROM oldap:onto
450
- FROM shared:onto
451
- FROM {self._graph}:onto
452
- FROM NAMED oldap:admin
453
- FROM NAMED {self._graph}:data
454
- WHERE {{
455
- BIND({self._iri.toRdf} as ?iri)
453
+ ASK {{
456
454
  GRAPH {self._graph}:data {{
457
- ?iri oldap:grantsPermission ?permset .
455
+ {self._iri.toRdf} oldap:grantsPermission ?permset .
458
456
  }}
459
- BIND({self._con.userIri.toRdf} as ?user)
460
457
  GRAPH oldap:admin {{
461
- ?user oldap:hasPermissions ?permset .
458
+ {self._con.userIri.toRdf} oldap:hasPermissions ?permset .
462
459
  ?permset oldap:givesPermission ?DataPermission .
463
460
  ?DataPermission oldap:permissionValue ?permval .
464
461
  }}
465
462
  FILTER(?permval >= {permission.numeric.toRdf})
466
463
  }}'''
464
+
467
465
  if self._con.in_transaction():
468
- jsonobj = self._con.transaction_query(permission_query)
466
+ result = self._con.transaction_query(permission_query)
469
467
  else:
470
- jsonobj = self._con.query(permission_query)
471
- res = QueryProcessor(context, jsonobj)
472
- return res[0]['numOfPermsets'] > 0
468
+ result = self._con.query(permission_query)
469
+ return result['boolean']
473
470
 
474
471
  def create(self, indent: int = 0, indent_inc: int = 4) -> str:
472
+ """
473
+ Generates an RDF/SPARQL INSERT DATA query for creating a resource with associated
474
+ metadata and verifies permissions before execution.
475
+
476
+ This method first checks for the necessary permissions to create a resource.
477
+ It assigns metadata such as the creation and modification information if
478
+ the resource name matches specific criteria. It ensures that no resource
479
+ with the same IRI exists before proceeding with the resource creation.
480
+ If a conflict is detected, an error is raised. The method finalizes the
481
+ creation of the resource by executing a SPARQL query in a transactional context.
482
+
483
+ :param indent: The current level of indentation (default is 0).
484
+ :type indent: int
485
+ :param indent_inc: The incremental spaces per indentation level (default is 4).
486
+ :type indent_inc: int
487
+ :return: A string representing the RDF/SPARQL query for creation.
488
+ :rtype: str
489
+ :raises OldapErrorNoPermission: If the user does not have the required permissions to create the resource.
490
+ :raises OldapErrorAlreadyExists: If a resource with the same IRI already exists.
491
+ :raises OldapError: For errors encountered during the SPARQL transaction execution.
492
+ """
475
493
  result, message = self.check_for_permissions(AdminPermission.ADMIN_CREATE)
476
494
  if not result:
477
495
  raise OldapErrorNoPermission(message)
@@ -528,6 +546,19 @@ class ResourceInstance:
528
546
  def read(cls,
529
547
  con: IConnection,
530
548
  iri: Iri) -> Self:
549
+ """
550
+ Reads an object of the specific class type from the RDF data source using the provided connection
551
+ and IRI. Validates that the retrieved RDF data matches the expected class type and ensures proper
552
+ permissions have been granted to access the resource.
553
+
554
+ :param con: The connection object to the data source (IConnection).
555
+ :param iri: The IRI of the resource to read (Iri).
556
+ :return: An object of the invoking class loaded with data from the RDF resource.
557
+
558
+ :raises OldapErrorInconsistency: If an expected QName is not found or if the retrieved object type
559
+ does not match the expected class type.
560
+ :raises OldapErrorNotFound: If the resource associated with the provided IRI is not found.
561
+ """
531
562
  graph = cls.project.projectShortName
532
563
  context = Context(name=con.context_name)
533
564
  sparql = context.sparql_context
@@ -576,6 +607,26 @@ class ResourceInstance:
576
607
  return cls(iri=iri, **kwargs)
577
608
 
578
609
  def update(self, indent: int = 0, indent_inc: int = 4) -> None:
610
+ """
611
+ Updates the current resource by creating and executing SPARQL queries to modify, insert, or
612
+ delete data based on the changeset. This method also verifies user permissions and ensures
613
+ data consistency using timestamps. It commits modifications within a transaction while
614
+ rolling back changes upon encountering errors.
615
+
616
+ The `update` method processes changes in resource attributes specified in a changeset. It
617
+ constructs appropriate SPARQL queries for CREATE, MODIFY, and DELETE actions for each
618
+ field. Additionally, it updates the last modification timestamp for the resource and records
619
+ the user performing the update. If permissions are insufficient or an update fails, the
620
+ transaction is aborted.
621
+
622
+ :param indent: The initial level of indentation for the generated SPARQL queries.
623
+ :type indent: int
624
+ :param indent_inc: The incremental level of indentation for nested sections in SPARQL
625
+ queries.
626
+ :type indent_inc: int
627
+ :return: None
628
+ :rtype: None
629
+ """
579
630
  admin_resources, message = self.check_for_permissions(AdminPermission.ADMIN_RESOURCES)
580
631
 
581
632
  context = Context(name=self._con.context_name)
@@ -703,16 +754,33 @@ class ResourceInstance:
703
754
  self.clear_changeset()
704
755
 
705
756
  def delete(self) -> None:
757
+ """
758
+ Deletes the specified resource represented by the object's IRI from the associated graph
759
+ if the proper permissions are granted and the resource is not in use. This method initiates
760
+ a transactional sequence to ensure data consistency and rollback in case of an error.
761
+ The process includes checking permissions, querying whether the resource is in use,
762
+ and finally issuing a SPARQL DELETE query to remove the resource.
763
+
764
+ Raises appropriate exceptions if the resource is in use, permissions are insufficient,
765
+ or any other transaction-related error occurs.
766
+
767
+ :raises OldapErrorNoPermission: If the user lacks the necessary permissions to
768
+ delete the resource.
769
+ :raises OldapErrorInUse: If the resource is currently in use and cannot be deleted.
770
+ :raises OldapError: If any error occurs during transaction start, query, update,
771
+ or commit phases.
772
+ """
706
773
  admin_resources, message = self.check_for_permissions(AdminPermission.ADMIN_RESOURCES)
707
774
 
708
775
  context = Context(name=self._con.context_name)
709
776
  inuse = context.sparql_context
710
- inuse = f'''
711
- SELECT (COUNT(?res) as ?nres)
712
- WHERE {{
713
- ?res ?prop {self._iri.toRdf} .
777
+ inuse += f"""
778
+ ASK {{
779
+ GRAPH ?g {{
780
+ ?res ?prop {self._iri.toRdf} .
781
+ }}
714
782
  }}
715
- '''
783
+ """
716
784
 
717
785
  context = Context(name=self._con.context_name)
718
786
  sparql = context.sparql_context
@@ -730,9 +798,8 @@ class ResourceInstance:
730
798
  self._con.transaction_abort()
731
799
  raise OldapErrorNoPermission(f'No permission to update resource "{self._iri}"')
732
800
  try:
733
- jsonobj = self._con.transaction_query(inuse)
734
- res = QueryProcessor(context, jsonobj)
735
- if res[0]['nres'] > 0:
801
+ result = self._con.transaction_query(inuse)
802
+ if result['boolean']:
736
803
  raise OldapErrorInUse(f'Resource "{self._iri}" is in use and cannot be deleted.')
737
804
  except OldapError:
738
805
  self._con.transaction_abort()
@@ -748,6 +815,329 @@ class ResourceInstance:
748
815
  self._con.transaction_abort()
749
816
  raise
750
817
 
818
+ @staticmethod
819
+ def read_data(con: IConnection, projectShortName: Xsd_NCName | str, iri: Iri | str) -> dict[Xsd_QName, Any]:
820
+ """
821
+ Reads and processes data from a given IConnection instance based on a specified
822
+ project short name and a resource IRI. This method fetches the data from a graph
823
+ in the RDF database, verifies user permissions, and returns selected data in a
824
+ dictionary format.
825
+
826
+ :param con: The connection object used to query the RDF data.
827
+ :type con: IConnection
828
+ :param projectShortName: The short name of the project used to identify the graph
829
+ in the RDF store. Accepts either Xsd_NCName or a string.
830
+ :param iri: The IRI of the resource being queried. Accepts either Iri or a string.
831
+ :return: A dictionary mapping predicates to their associated values from the
832
+ selected resource.
833
+ :rtype: dict[Xsd_QName, Any]
834
+ :raises OldapErrorInconsistency: If a non-QName predicate is found in the results.
835
+ :raises OldapErrorNotFound: If the resource with the given IRI is not found.
836
+ """
837
+ if not isinstance(iri, Iri):
838
+ iri = Iri(iri, validate=True)
839
+ if not isinstance(projectShortName, Xsd_NCName):
840
+ graph = Xsd_NCName(projectShortName)
841
+ else:
842
+ graph = projectShortName
843
+
844
+ context = Context(name=con.context_name)
845
+ sparql = context.sparql_context
846
+ sparql += f'''
847
+ SELECT ?predicate ?value
848
+ WHERE {{
849
+ GRAPH {graph}:data {{
850
+ {iri.toRdf} ?predicate ?value .
851
+ {iri.toRdf} oldap:grantsPermission ?permset .
852
+ }}
853
+ GRAPH oldap:admin {{
854
+ {con.userIri.toRdf} oldap:hasPermissions ?permset .
855
+ ?permset oldap:givesPermission ?DataPermission .
856
+ ?DataPermission oldap:permissionValue ?permval .
857
+ }}
858
+ FILTER(?permval >= {DataPermission.DATA_VIEW.numeric.toRdf})
859
+ }}
860
+ '''
861
+ jsonres = con.query(sparql)
862
+ res = QueryProcessor(context, jsonres)
863
+ data = {}
864
+ for r in res:
865
+ if r['predicate'].is_qname:
866
+ if not data.get(r['predicate'].as_qname):
867
+ data[r['predicate'].as_qname] = []
868
+ data[str(r['predicate'].as_qname)].append(str(r['value']))
869
+ else:
870
+ raise OldapErrorInconsistency(f"Expected QName as predicate, got {r['predicate']}")
871
+ if not data.get('rdf:type'):
872
+ raise OldapErrorNotFound(f'Resource with iri <{iri}> not found.')
873
+ return data
874
+
875
+ @staticmethod
876
+ def search_fulltext(con: IConnection,
877
+ projectShortName: Xsd_NCName | str,
878
+ s: str,
879
+ resClass: Xsd_QName | str | None = None,
880
+ count_only: bool = False,
881
+ sortBy: SortBy | None = None,
882
+ limit: int = 100,
883
+ offset: int = 0,
884
+ indent: int = 0, indent_inc: int = 4) -> int | dict[Iri, dict[str, Xsd]]:
885
+ """
886
+ Search for entities in a project using a full-text search query, with optional filters and sorting
887
+ based on resource class and properties.
888
+
889
+ :param con: The connection instance to interact with the SPARQL endpoint or database.
890
+ :type con: IConnection
891
+ :param projectShortName: The project short name (identifier). Can be provided as an Xsd_NCName or a
892
+ string. If a string, it is automatically validated and converted to an Xsd_NCName.
893
+ :type projectShortName: Xsd_NCName | str
894
+ :param s: The full-text search query to identify entities matching the specified string values.
895
+ :type s: str
896
+ :param resClass: An optional entity class (Xsd_QName) used to filter results. If provided as a string,
897
+ it is validated and converted to Xsd_QName.
898
+ :type resClass: Xsd_QName | str | None
899
+ :param count_only: If True, only the count of matching entities will be returned. Defaults to False.
900
+ :type count_only: bool
901
+ :param sortBy: Optional sorting criterion for the results, such as creation date, last modification date,
902
+ or property values. Defaults to None.
903
+ :type sortBy: SortBy | None
904
+ :param limit: The maximum number of records to return when count_only is False. Defaults to 100.
905
+ :type limit: int
906
+ :param offset: The number of records to skip for paginated queries. Defaults to 0.
907
+ :type offset: int
908
+ :param indent: Initial indentation level for the generated SPARQL query. Defaults to 0.
909
+ :type indent: int
910
+ :param indent_inc: Incremental indentation used during SPARQL query generation. Defaults to 4.
911
+ :type indent_inc: int
912
+ :return: If count_only is True, an integer representing the count of matching entities. If count_only is
913
+ False, a dictionary with entity IRIs as keys and their respective property-to-value mappings
914
+ as values.
915
+ :rtype: int | dict[Iri, dict[str, Xsd]]
916
+
917
+ The SPARQL generated is as follows
918
+
919
+ ```sparql
920
+ SELECT DISTINCT ?s ?t ?p ?o ?creationDate
921
+ WHERE {
922
+ GRAPH test:data {
923
+ ?s oldap:creationDate ?creationDate .
924
+ ?s ?p ?o .
925
+ ?s rdf:type ?t .
926
+ ?s rdf:type test:Book .
927
+ ?s oldap:grantsPermission ?permset .
928
+ }
929
+ FILTER(isLiteral(?o) && (datatype(?o) = xsd:string || datatype(?o) = rdf:langString || lang(?o) != ""))
930
+ FILTER(CONTAINS(LCASE(STR(?o)), "gaga")) # case-insensitive substring match
931
+ GRAPH oldap:admin {
932
+ <https://orcid.org/0000-0003-1681-4036> oldap:hasPermissions ?permset .
933
+ ?permset oldap:givesPermission ?DataPermission .
934
+ ?DataPermission oldap:permissionValue ?permval .
935
+ }
936
+ FILTER(?permval >= "2"^^xsd:integer)
937
+ }
938
+ ORDER BY ASC(?creationDate)LIMIT 100 OFFSET 0
939
+ ```
940
+ """
941
+ if not isinstance(projectShortName, Xsd_NCName):
942
+ graph = Xsd_NCName(projectShortName, validate=True)
943
+ else:
944
+ graph = projectShortName
945
+ if resClass and not isinstance(resClass, Xsd_QName):
946
+ resClass = Xsd_QName(resClass, validate=True)
947
+
948
+ blank = ''
949
+ context = Context(name=con.context_name)
950
+ sparql = context.sparql_context
951
+
952
+ if (count_only):
953
+ sparql += f'{blank:{indent * indent_inc}}SELECT (COUNT(DISTINCT ?s) as ?numResult)'
954
+ else:
955
+ sparql += f'{blank:{indent * indent_inc}}SELECT DISTINCT ?s ?t ?p ?o'
956
+ if sortBy:
957
+ if sortBy == SortBy.CREATED:
958
+ sparql += ' ?creationDate'
959
+ if sortBy == SortBy.LASTMOD:
960
+ sparql += '?lastModificationDate'
961
+ sparql += f'\n{blank:{indent * indent_inc}}WHERE {{'
962
+ sparql += f'\n{blank:{(indent + 1) * indent_inc}}GRAPH {graph}:data {{'
963
+ if sortBy:
964
+ if sortBy == SortBy.CREATED:
965
+ sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s oldap:creationDate ?creationDate .'
966
+ if sortBy == SortBy.LASTMOD:
967
+ sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s oldap:lastModificationDate ?lastModificationDate .'
968
+ sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s ?p ?o .'
969
+ sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s rdf:type ?t .'
970
+ if resClass:
971
+ sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s rdf:type {resClass} .'
972
+ sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s oldap:grantsPermission ?permset .'
973
+ sparql += f'\n{blank:{(indent + 1) * indent_inc}}}}'
974
+ sparql += f'\n{blank:{(indent + 1) * indent_inc}}FILTER(isLiteral(?o) && (datatype(?o) = xsd:string || datatype(?o) = rdf:langString || lang(?o) != ""))'
975
+ sparql += f'\n{blank:{(indent + 1) * indent_inc}}FILTER(CONTAINS(LCASE(STR(?o)), "{s}")) # case-insensitive substring match'
976
+ sparql += f'\n{blank:{(indent + 1) * indent_inc}}GRAPH oldap:admin {{'
977
+ sparql += f'\n{blank:{(indent + 2) * indent_inc}}{con.userIri.toRdf} oldap:hasPermissions ?permset .'
978
+ sparql += f'\n{blank:{(indent + 2) * indent_inc}}?permset oldap:givesPermission ?DataPermission .'
979
+ sparql += f'\n{blank:{(indent + 2) * indent_inc}}?DataPermission oldap:permissionValue ?permval .'
980
+ sparql += f'\n{blank:{(indent + 1) * indent_inc}}}}'
981
+ sparql += f'\n{blank:{(indent + 1) * indent_inc}}FILTER(?permval >= {DataPermission.DATA_VIEW.numeric.toRdf})'
982
+ sparql += f'\n{blank:{indent * indent_inc}}}}'
983
+
984
+ if sortBy:
985
+ if sortBy == SortBy.CREATED:
986
+ sparql += f'\n{blank:{indent * indent_inc}}ORDER BY ASC(?creationDate)'
987
+ if sortBy == SortBy.LASTMOD:
988
+ sparql += f'\n{blank:{indent * indent_inc}}ORDER BY ASC(?lastModificationDate)'
989
+ if sortBy == SortBy.PROPVAL:
990
+ sparql += f'\n{blank:{indent * indent_inc}}ORDER BY ASC(LCASE(STR(?o)))'
991
+
992
+ if not count_only:
993
+ sparql += f'\n{blank:{indent * indent_inc}}LIMIT {limit} OFFSET {offset}'
994
+ sparql += '\n'
995
+
996
+
997
+ try:
998
+ jsonres = con.query(sparql)
999
+ except OldapError:
1000
+ print(sparql)
1001
+ raise
1002
+ res = QueryProcessor(context, jsonres)
1003
+ if count_only:
1004
+ return res[0]['numResult']
1005
+ else:
1006
+ result = {}
1007
+ for r in res:
1008
+ tmp = {
1009
+ r['p']: r['o'],
1010
+ Xsd_QName('owl:Class'): r['t']
1011
+ }
1012
+ if sortBy:
1013
+ if sortBy == SortBy.CREATED:
1014
+ tmp['oldap:creationDate'] = r['creationDate'],
1015
+ if sortBy == SortBy.LASTMOD:
1016
+ tmp['oldap:lastModificationDate'] = r['lastModificationDate']
1017
+ result[r['s']] = tmp
1018
+ return result
1019
+
1020
+ @staticmethod
1021
+ def all_resources(con: IConnection,
1022
+ projectShortName: Xsd_NCName | str,
1023
+ resClass: Xsd_QName | str,
1024
+ includeProperties: list[Xsd_QName] | None = None,
1025
+ count_only: bool = False,
1026
+ sortBy: SortBy | None = None,
1027
+ limit: int = 100,
1028
+ offset: int = 0,
1029
+ indent: int = 0, indent_inc: int = 4) -> dict[Iri, dict[str, Xsd]]:
1030
+ """
1031
+ Retrieves all resources matching the specified parameters from a data store using a SPARQL query.
1032
+ Depending on the `count_only` flag, it can return either a count of matching resources or detailed
1033
+ information about each resource.
1034
+
1035
+ :param con: The connection object used to execute the SPARQL query.
1036
+ :type con: IConnection
1037
+ :param projectShortName: The short name of the project being queried.
1038
+ :type projectShortName: Xsd_NCName | str
1039
+ :param resClass: The resource class to filter the results by.
1040
+ :type resClass: Xsd_QName | str
1041
+ :param includeProperties: A list of resource properties to include in the query and results.
1042
+ :type includeProperties: list[Xsd_QName] | None
1043
+ :param count_only: If True, returns only the count of matching resources. Defaults to False.
1044
+ :type count_only: bool
1045
+ :param sortBy: The sorting criterion for the results. Defaults to None.
1046
+ :type sortBy: SortBy | None
1047
+ :param limit: The maximum number of results to retrieve. Defaults to 100.
1048
+ :type limit: int
1049
+ :param offset: The starting point for result retrieval in pagination. Defaults to 0.
1050
+ :type offset: int
1051
+ :param indent: The initial level of indentation for the SPARQL query strings. Defaults to 0.
1052
+ :type indent: int
1053
+ :param indent_inc: The incremental level of indentation for the SPARQL query strings. Defaults to 4.
1054
+ :type indent_inc: int
1055
+ :return: A dictionary where keys are resource IRIs and values are dictionaries containing resource
1056
+ properties and their corresponding values. If `count_only` is True, returns the total count of
1057
+ matching resources as an integer.
1058
+ :rtype: dict[Iri, dict[str, Xsd]]
1059
+ :raises OldapError: If there is an error during query execution in the connection object.
1060
+ """
1061
+ if not isinstance(projectShortName, Xsd_NCName):
1062
+ graph = Xsd_NCName(projectShortName, validate=True)
1063
+ else:
1064
+ graph = projectShortName
1065
+ if not isinstance(resClass, Xsd_QName):
1066
+ resClass = Xsd_QName(resClass, validate=True)
1067
+
1068
+ blank = ''
1069
+ context = Context(name=con.context_name)
1070
+ sparql = context.sparql_context
1071
+
1072
+ if (count_only):
1073
+ sparql += f'{blank:{indent * indent_inc}}SELECT (COUNT(DISTINCT ?s) as ?numResult)'
1074
+ else:
1075
+ sparql += f'{blank:{indent * indent_inc}}SELECT DISTINCT ?s'
1076
+ for index, item in enumerate(includeProperties):
1077
+ sparql += f' ?o{index}'
1078
+ if sortBy:
1079
+ if sortBy == SortBy.CREATED:
1080
+ sparql += ' ?creationDate'
1081
+ if sortBy == SortBy.LASTMOD:
1082
+ sparql += '?lastModificationDate'
1083
+ sparql += f'\n{blank:{indent * indent_inc}}WHERE {{'
1084
+ sparql += f'\n{blank:{(indent + 1) * indent_inc}}GRAPH {graph}:data {{'
1085
+ if sortBy:
1086
+ if sortBy == SortBy.CREATED:
1087
+ sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s oldap:creationDate ?creationDate .'
1088
+ if sortBy == SortBy.LASTMOD:
1089
+ sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s oldap:lastModificationDate ?lastModificationDate .'
1090
+ for index, prop in enumerate(includeProperties):
1091
+ sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s {prop} ?o{index} .'
1092
+ sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s rdf:type {resClass} .'
1093
+ sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s oldap:grantsPermission ?permset .'
1094
+ sparql += f'\n{blank:{(indent + 1) * indent_inc}}}}'
1095
+ sparql += f'\n{blank:{(indent + 1) * indent_inc}}GRAPH oldap:admin {{'
1096
+ sparql += f'\n{blank:{(indent + 2) * indent_inc}}{con.userIri.toRdf} oldap:hasPermissions ?permset .'
1097
+ sparql += f'\n{blank:{(indent + 2) * indent_inc}}?permset oldap:givesPermission ?DataPermission .'
1098
+ sparql += f'\n{blank:{(indent + 2) * indent_inc}}?DataPermission oldap:permissionValue ?permval .'
1099
+ sparql += f'\n{blank:{(indent + 1) * indent_inc}}}}'
1100
+ sparql += f'\n{blank:{(indent + 1) * indent_inc}}FILTER(?permval >= {DataPermission.DATA_VIEW.numeric.toRdf})'
1101
+ sparql += f'\n{blank:{indent * indent_inc}}}}'
1102
+
1103
+ if sortBy:
1104
+ if sortBy == SortBy.CREATED:
1105
+ sparql += f'\n{blank:{indent * indent_inc}}ORDER BY ASC(?creationDate)'
1106
+ if sortBy == SortBy.LASTMOD:
1107
+ sparql += f'\n{blank:{indent * indent_inc}}ORDER BY ASC(?lastModificationDate)'
1108
+ if sortBy == SortBy.PROPVAL:
1109
+ sparql += f'\n{blank:{indent * indent_inc}}ORDER BY'
1110
+ for index, item in enumerate(includeProperties):
1111
+ sparql += f'\n{blank:{indent * indent_inc}} ?o{index}'
1112
+
1113
+ if not count_only:
1114
+ sparql += f'\n{blank:{indent * indent_inc}}LIMIT {limit} OFFSET {offset}'
1115
+ sparql += '\n'
1116
+
1117
+ try:
1118
+ jsonres = con.query(sparql)
1119
+ except OldapError:
1120
+ print(sparql)
1121
+ raise
1122
+ res = QueryProcessor(context, jsonres)
1123
+ if count_only:
1124
+ return res[0]['numResult']
1125
+ else:
1126
+ result = {}
1127
+ for r in res:
1128
+ tmp = {}
1129
+ for index, item in enumerate(includeProperties):
1130
+ tmp[item] = r[f'o{index}']
1131
+
1132
+ if sortBy:
1133
+ if sortBy == SortBy.CREATED:
1134
+ tmp[Xsd_QName('oldap:creationDate')] = r['creationDate']
1135
+ if sortBy == SortBy.LASTMOD:
1136
+ tmp[Xsd_QName('oldap:lastModificationDate')] = r['lastModificationDate']
1137
+ result[r['s']] = tmp
1138
+ return result
1139
+
1140
+
751
1141
  def toJsonObject(self) -> dict[str, list[str] | str]:
752
1142
  result = {'iri': str(self._iri)}
753
1143
  for propiri, values in self._values.items():
@@ -791,9 +1181,6 @@ class ResourceInstanceFactory:
791
1181
 
792
1182
  self._datamodel = DataModel.read(con=self._con, project=self._project, ignore_cache=True)
793
1183
 
794
- #self._oldap_project = Project.read(self._con, "oldap")
795
- #self._oldap_datamodel = DataModel.read(con=self._con, project=self._oldap_project)
796
-
797
1184
  def createObjectInstance(self, name: Xsd_NCName | str) -> Type: ## ToDo: Get name automatically from IRI
798
1185
  classiri = Xsd_QName(self._project.projectShortName, name)
799
1186
  resclass = self._datamodel.get(classiri)
@@ -809,46 +1196,6 @@ class ResourceInstanceFactory:
809
1196
  'properties': resclass.properties,
810
1197
  'superclass': resclass.superclass})
811
1198
 
812
- @staticmethod
813
- def read_data(con: IConnection, projectShortName: Xsd_NCName | str, iri: Iri | str) -> dict[Xsd_QName, Any]:
814
- if not isinstance(iri, Iri):
815
- iri = Iri(iri, validate=True)
816
- if not isinstance(projectShortName, Xsd_NCName):
817
- graph = Xsd_NCName(projectShortName)
818
- else:
819
- graph = projectShortName
820
-
821
- context = Context(name=con.context_name)
822
- sparql = context.sparql_context
823
- sparql += f'''
824
- SELECT ?predicate ?value
825
- WHERE {{
826
- GRAPH {graph}:data {{
827
- {iri.toRdf} ?predicate ?value .
828
- {iri.toRdf} oldap:grantsPermission ?permset .
829
- }}
830
- GRAPH oldap:admin {{
831
- {con.userIri.toRdf} oldap:hasPermissions ?permset .
832
- ?permset oldap:givesPermission ?DataPermission .
833
- ?DataPermission oldap:permissionValue ?permval .
834
- }}
835
- FILTER(?permval >= {DataPermission.DATA_VIEW.numeric.toRdf})
836
- }}
837
- '''
838
- jsonres = con.query(sparql)
839
- res = QueryProcessor(context, jsonres)
840
- data = {}
841
- for r in res:
842
- if r['predicate'].is_qname:
843
- if not data.get(r['predicate'].as_qname):
844
- data[r['predicate'].as_qname] = []
845
- data[str(r['predicate'].as_qname)].append(str(r['value']))
846
- else:
847
- raise OldapErrorInconsistency(f"Expected QName as predicate, got {r['predicate']}")
848
- if not data.get('rdf:type'):
849
- raise OldapErrorNotFound(f'Resource with iri <{iri}> not found.')
850
- return data
851
-
852
1199
 
853
1200
  def read(self, iri: Iri | str) -> ResourceInstance:
854
1201
  if not isinstance(iri, Iri):
@@ -901,50 +1248,6 @@ class ResourceInstanceFactory:
901
1248
  Instance = self.createObjectInstance(objtype)
902
1249
  return Instance(iri=iri, **kwargs)
903
1250
 
904
- def search_fulltext(self, s: str, count_only: bool = False, limit: int = 100, offset: int = 0) -> int | dict[Iri, dict[str, Xsd]]:
905
- graph = self._project.projectShortName
906
- context = Context(name=self._con.context_name)
907
- sparql = context.sparql_context
908
- if (count_only):
909
- sparql += "SELECT (COUNT(DISTINCT ?s) as ?numResult)"
910
- else:
911
- sparql += "SELECT DISTINCT ?s ?t ?p ?o"
912
- sparql += f'''
913
- WHERE {{
914
- GRAPH {graph}:data {{
915
- ?s ?p ?o .
916
- ?s rdf:type ?t .
917
- ?s oldap:grantsPermission ?permset .
918
- }}
919
- FILTER(isLiteral(?o) &&
920
- (datatype(?o) = xsd:string || datatype(?o) = rdf:langString || lang(?o) != ""))
921
- FILTER(CONTAINS(LCASE(STR(?o)), "{s}")) # case-insensitive substring match
922
- GRAPH oldap:admin {{
923
- {self._con.userIri.toRdf} oldap:hasPermissions ?permset .
924
- ?permset oldap:givesPermission ?DataPermission .
925
- ?DataPermission oldap:permissionValue ?permval .
926
- }}
927
- FILTER(?permval >= {DataPermission.DATA_VIEW.numeric.toRdf})
928
- }}
929
- '''
930
- if not count_only:
931
- sparql += f'LIMIT {limit} OFFSET {offset}'
932
- jsonres = self._con.query(sparql)
933
- res = QueryProcessor(context, jsonres)
934
- if count_only:
935
- if isinstance(res[0]['numResult'], Xsd_integer):
936
- tmp = cast(Xsd_integer, res[0]['numResult'])
937
- return int(tmp)
938
- else:
939
- raise OldapErrorInconsistency(f'Expected integer as value, got "{res[0]["numResult"]}"')
940
- else:
941
- result: dict[Iri, dict[str, Xsd]] = {}
942
- for r in res:
943
- iri = cast(Iri, r['s'])
944
- resclass = cast(Iri, r['t'])
945
- result[iri] = {'resclass': resclass, 'property': r['p'], 'value': r['o']}
946
- return result
947
-
948
1251
 
949
1252
 
950
1253
 
oldaplib/src/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.3.9"
1
+ __version__ = "0.3.11"
@@ -8,7 +8,7 @@ from time import sleep
8
8
 
9
9
  from oldaplib.src.cachesingleton import CacheSingletonRedis
10
10
  from oldaplib.src.datamodel import DataModel
11
- from oldaplib.src.objectfactory import ResourceInstanceFactory
11
+ from oldaplib.src.objectfactory import ResourceInstanceFactory, SortBy, ResourceInstance
12
12
  from oldaplib.src.connection import Connection
13
13
  from oldaplib.src.enums.action import Action
14
14
  from oldaplib.src.enums.datapermissions import DataPermission
@@ -357,7 +357,7 @@ class TestObjectFactory(unittest.TestCase):
357
357
  pubDate="2001-01-01",
358
358
  grantsPermission=Iri('oldap:GenericView'))
359
359
  b.create()
360
- data = ResourceInstanceFactory.read_data(con=self._connection, iri=b.iri, projectShortName='test')
360
+ data = ResourceInstance.read_data(con=self._connection, iri=b.iri, projectShortName='test')
361
361
  self.assertEqual(data['rdf:type'], ['test:Book'])
362
362
  self.assertEqual(data['test:title'], ['The Life and Times of Scrooge'])
363
363
  self.assertEqual(data['test:author'], ['test:TuomasHolopainen'])
@@ -638,17 +638,84 @@ class TestObjectFactory(unittest.TestCase):
638
638
 
639
639
  project = Project.read(con=self._connection, projectIri_SName='test')
640
640
  factory = ResourceInstanceFactory(con=self._connection, project=project)
641
+
642
+ Person = factory.createObjectInstance('Person')
643
+ persons = []
644
+ for i in range(4):
645
+ if i % 2 == 0:
646
+ familyName = 'Gaga' + random_string()
647
+ else:
648
+ familyName = random_string()
649
+ p = Person(familyName=familyName,
650
+ givenName=random_string(),
651
+ grantsPermission=Iri('oldap:GenericView'))
652
+ p.create()
653
+ persons.append(p.iri)
654
+
641
655
  Book = factory.createObjectInstance('Book')
642
656
  for i in range(10):
643
- b = Book(title=f'These are {random_string()} Tales from the Wood',
644
- author=Iri(f'test:Gaga', validate=False),
657
+ title = f'These are {random_string()} Tales from the Wood'
658
+ if i % 2 == 0:
659
+ title = 'GAGA' + title
660
+ b = Book(title=title,
661
+ author=persons[i % 4],
645
662
  pubDate="1995-09-27",
646
663
  grantsPermission=Iri('oldap:GenericView'))
647
664
  b.create()
648
- res = factory.search_fulltext('tales')
649
665
 
666
+
667
+ res = ResourceInstance.search_fulltext(con=self._connection,
668
+ projectShortName='test',
669
+ resClass='test:Book',
670
+ s='gaga',
671
+ sortBy=SortBy.CREATED)
672
+
673
+ self.assertEqual(len(res), 5)
650
674
  for x, y in res.items():
651
- print(x, y)
675
+ self.assertEqual(y[Xsd_QName("owl:Class")], Xsd_QName('test:Book'))
676
+
677
+ res = ResourceInstance.search_fulltext(con=self._connection,
678
+ projectShortName='test',
679
+ s='gaga',
680
+ sortBy=SortBy.CREATED)
681
+
682
+ self.assertEqual(len(res), 7)
683
+ for x, y in res.items():
684
+ self.assertTrue(y[Xsd_QName("owl:Class")] in {Xsd_QName('test:Book'), Xsd_QName('test:Person')})
685
+
686
+ def test_search_resource_B(self):
687
+
688
+ def random_string(length=12):
689
+ chars = string.ascii_letters + string.digits
690
+ return ''.join(random.choices(chars, k=length))
691
+
692
+ project = Project.read(con=self._connection, projectIri_SName='test')
693
+ factory = ResourceInstanceFactory(con=self._connection, project=project)
694
+ Page = factory.createObjectInstance('Page')
695
+ for i in range(1, 11):
696
+ b = Page(pageNum=Xsd_positiveInteger(i),
697
+ pageDesignation=f'Seite {i}',
698
+ pageContent=random_string(16),
699
+ pageInBook=Xsd_QName('test', 'gaga', validate=False),
700
+ grantsPermission=Iri('oldap:GenericView'))
701
+ b.create()
702
+
703
+ Person = factory.createObjectInstance('Person')
704
+ for i in range(4):
705
+ p = Person(familyName=random_string(),
706
+ givenName=random_string(),
707
+ grantsPermission=Iri('oldap:GenericView'))
708
+ p.create()
709
+
710
+ res = ResourceInstance.all_resources(con=self._connection,
711
+ projectShortName='test',
712
+ resClass='test:Page',
713
+ includeProperties=[Xsd_QName('test:pageNum'), Xsd_QName('test:pageContent')],
714
+ sortBy = SortBy.CREATED)
715
+ self.assertEqual(len(res), 10)
716
+ for r in res:
717
+ self.assertEqual(len(res[r]), 3)
718
+
652
719
 
653
720
 
654
721
  if __name__ == '__main__':
@@ -0,0 +1,119 @@
1
+ @prefix : <http://oldap.org/base#> .
2
+ @prefix test: <http://oldap.org/test#> .
3
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
4
+
5
+ test:data {
6
+ <urn:uuid:7a1de6d7-de75-4875-ab24-74819057703f> a test:Book;
7
+ :createdBy <https://orcid.org/0000-0003-1681-4036>;
8
+ :creationDate "2025-11-13T16:43:21.284536+01:00"^^xsd:dateTimeStamp;
9
+ :lastModifiedBy <https://orcid.org/0000-0003-1681-4036>;
10
+ :lastModificationDate "2025-11-13T16:43:21.284536+01:00"^^xsd:dateTimeStamp;
11
+ :grantsPermission :GenericView;
12
+ test:title "Die Geschichte der tQh5OAgXOaK5"@de;
13
+ test:pubDate "2026-01-01"^^xsd:date .
14
+
15
+ <urn:uuid:57141a6b-46b5-4c82-a74c-d48a15437c4f> a test:Page;
16
+ :createdBy <https://orcid.org/0000-0003-1681-4036>;
17
+ :creationDate "2025-11-13T16:43:22.598149+01:00"^^xsd:dateTimeStamp;
18
+ :lastModifiedBy <https://orcid.org/0000-0003-1681-4036>;
19
+ :lastModificationDate "2025-11-13T16:43:22.598149+01:00"^^xsd:dateTimeStamp;
20
+ :grantsPermission :GenericView;
21
+ test:pageDesignation "Page 1";
22
+ test:pageNum "1"^^xsd:positiveInteger;
23
+ test:pageDescription "Description for page 1"@en;
24
+ test:pageContent "Content for page 1\\nXpVzpnoxhxZEhp0hRWWcBmOLA3h62KT4f8FLxwL3kpGUdhLWBveN9KiML34YXk86SW6PDnZgz4GELOiZOqMvo9chdXhR1e0W3FIn";
25
+ test:pageInBook <urn:uuid:7a1de6d7-de75-4875-ab24-74819057703f> .
26
+
27
+ <urn:uuid:b382c2bc-6a61-4f60-a963-ec1eb5bc7428> a test:Page;
28
+ :createdBy <https://orcid.org/0000-0003-1681-4036>;
29
+ :creationDate "2025-11-13T16:43:23.323339+01:00"^^xsd:dateTimeStamp;
30
+ :lastModifiedBy <https://orcid.org/0000-0003-1681-4036>;
31
+ :lastModificationDate "2025-11-13T16:43:23.323339+01:00"^^xsd:dateTimeStamp;
32
+ :grantsPermission :GenericView;
33
+ test:pageDesignation "Page 2";
34
+ test:pageNum "2"^^xsd:positiveInteger;
35
+ test:pageDescription "Description for page 2"@en;
36
+ test:pageContent "Waseliwas for page 2\\nP7OGEXPNRcM62O2gVVmTzp8xSjnMM0jNTdyFpDI3Cf1VTH1AcvrFt3AYSWCLEQIBttAs23DHkAXzaehFbA81TwkIKLKUSz9v1qAV";
37
+ test:pageInBook <urn:uuid:7a1de6d7-de75-4875-ab24-74819057703f> .
38
+
39
+ <urn:uuid:a8f0ec0c-28ed-449c-8f22-81ee20bfb0a3> a test:Page;
40
+ :createdBy <https://orcid.org/0000-0003-1681-4036>;
41
+ :creationDate "2025-11-13T16:43:24.013627+01:00"^^xsd:dateTimeStamp;
42
+ :lastModifiedBy <https://orcid.org/0000-0003-1681-4036>;
43
+ :lastModificationDate "2025-11-13T16:43:24.013627+01:00"^^xsd:dateTimeStamp;
44
+ :grantsPermission :GenericView;
45
+ test:pageDesignation "Page 3";
46
+ test:pageNum "3"^^xsd:positiveInteger;
47
+ test:pageDescription "Description for page 3"@en;
48
+ test:pageContent "Content for page 3\\nAdjA5kTzS7lT6W7F2bgLYtcXBkDxOAelvXThXNt5uranbB2WgsSsPu5uklCy8IVdRhqod6iWhMVWdqMhZWnv1NkgJQ2vjhHB57bh";
49
+ test:pageInBook <urn:uuid:7a1de6d7-de75-4875-ab24-74819057703f> .
50
+
51
+ <urn:uuid:098df661-de13-4fa7-b3aa-2ed5aa1180a8> a test:Page;
52
+ :createdBy <https://orcid.org/0000-0003-1681-4036>;
53
+ :creationDate "2025-11-13T16:43:24.742317+01:00"^^xsd:dateTimeStamp;
54
+ :lastModifiedBy <https://orcid.org/0000-0003-1681-4036>;
55
+ :lastModificationDate "2025-11-13T16:43:24.742317+01:00"^^xsd:dateTimeStamp;
56
+ :grantsPermission :GenericView;
57
+ test:pageDesignation "Page 4";
58
+ test:pageNum "4"^^xsd:positiveInteger;
59
+ test:pageDescription "Description for page 4"@en;
60
+ test:pageContent "Waseliwas for page 4\\nMc6l85dn7CMgYyL5qmQVRUpoICNxJ7f3GpydUY67gfXssGOokV3CPoSmre5MHWpcFaKHlHxWDSrL0qNEcECe28AS438654klipu4";
61
+ test:pageInBook <urn:uuid:7a1de6d7-de75-4875-ab24-74819057703f> .
62
+
63
+ <urn:uuid:9bf6ae23-bf2f-4466-abe3-65efe6afe589> a test:Book;
64
+ :createdBy <https://orcid.org/0000-0003-1681-4036>;
65
+ :creationDate "2025-11-13T16:43:25.444141+01:00"^^xsd:dateTimeStamp;
66
+ :lastModifiedBy <https://orcid.org/0000-0003-1681-4036>;
67
+ :lastModificationDate "2025-11-13T16:43:25.444141+01:00"^^xsd:dateTimeStamp;
68
+ :grantsPermission :GenericView;
69
+ test:title "Die Geschichte der fGqkycKqu4Fg"@de;
70
+ test:pubDate "2026-01-01"^^xsd:date .
71
+
72
+ <urn:uuid:cda5bacb-4082-4fef-9a17-990cf16e2f56> a test:Page;
73
+ :createdBy <https://orcid.org/0000-0003-1681-4036>;
74
+ :creationDate "2025-11-13T16:43:26.755559+01:00"^^xsd:dateTimeStamp;
75
+ :lastModifiedBy <https://orcid.org/0000-0003-1681-4036>;
76
+ :lastModificationDate "2025-11-13T16:43:26.755559+01:00"^^xsd:dateTimeStamp;
77
+ :grantsPermission :GenericView;
78
+ test:pageDesignation "Page 1";
79
+ test:pageNum "1"^^xsd:positiveInteger;
80
+ test:pageDescription "Description for page 1"@en;
81
+ test:pageContent "Content for page 1\\nTnfJDOE1D0hFuY9B2zKJW7g5oW48XTqKSd9nNYL0QrjxAk38Aka6g9zEr6q8OdAoxWePellSt4Ixq3jfaF1YlkOYBLyWft0LpzjS";
82
+ test:pageInBook <urn:uuid:9bf6ae23-bf2f-4466-abe3-65efe6afe589> .
83
+
84
+ <urn:uuid:674467a8-8fbe-425c-a2f6-06d2e52adc99> a test:Page;
85
+ :createdBy <https://orcid.org/0000-0003-1681-4036>;
86
+ :creationDate "2025-11-13T16:43:27.463742+01:00"^^xsd:dateTimeStamp;
87
+ :lastModifiedBy <https://orcid.org/0000-0003-1681-4036>;
88
+ :lastModificationDate "2025-11-13T16:43:27.463742+01:00"^^xsd:dateTimeStamp;
89
+ :grantsPermission :GenericView;
90
+ test:pageDesignation "Page 2";
91
+ test:pageNum "2"^^xsd:positiveInteger;
92
+ test:pageDescription "Description for page 2"@en;
93
+ test:pageContent "Waseliwas for page 2\\npwZym6JetP02VeGCX5cVddgaBGWwy2AStfs6W3elfpweFYdS5Z81dvPEPYAo1xDgBSQcAwqnP1pfVEj1YBkz2X7aNCob22SKCztw";
94
+ test:pageInBook <urn:uuid:9bf6ae23-bf2f-4466-abe3-65efe6afe589> .
95
+
96
+ <urn:uuid:dc2704cf-8352-43c1-94ef-a7a81e838532> a test:Page;
97
+ :createdBy <https://orcid.org/0000-0003-1681-4036>;
98
+ :creationDate "2025-11-13T16:43:28.161174+01:00"^^xsd:dateTimeStamp;
99
+ :lastModifiedBy <https://orcid.org/0000-0003-1681-4036>;
100
+ :lastModificationDate "2025-11-13T16:43:28.161174+01:00"^^xsd:dateTimeStamp;
101
+ :grantsPermission :GenericView;
102
+ test:pageDesignation "Page 3";
103
+ test:pageNum "3"^^xsd:positiveInteger;
104
+ test:pageDescription "Description for page 3"@en;
105
+ test:pageContent "Content for page 3\\nmEbj4wfY55KWkSqIlMkOK6LpHlHdlCa3vq3GtTkvvHhzieT0FIax7U489xSGJNOxPEdeNk8Ywhtk1ETo0AIBoNNywvyFV6jLxe5H";
106
+ test:pageInBook <urn:uuid:9bf6ae23-bf2f-4466-abe3-65efe6afe589> .
107
+
108
+ <urn:uuid:f46ea23a-65ab-47ce-908d-586d6c8091a6> a test:Page;
109
+ :createdBy <https://orcid.org/0000-0003-1681-4036>;
110
+ :creationDate "2025-11-13T16:43:28.861171+01:00"^^xsd:dateTimeStamp;
111
+ :lastModifiedBy <https://orcid.org/0000-0003-1681-4036>;
112
+ :lastModificationDate "2025-11-13T16:43:28.861171+01:00"^^xsd:dateTimeStamp;
113
+ :grantsPermission :GenericView;
114
+ test:pageDesignation "Page 4";
115
+ test:pageNum "4"^^xsd:positiveInteger;
116
+ test:pageDescription "Description for page 4"@en;
117
+ test:pageContent "Waseliwas for page 4\\n9pB6yFsJs7zcCkyF9j9flbGUcNczytEsw1nSUYCBLIN3P63wePvVQnWDX5dgUDXyeEwUwoBycRPcrp6kG2wsknVjfajQI30lZ73E";
118
+ test:pageInBook <urn:uuid:9bf6ae23-bf2f-4466-abe3-65efe6afe589> .
119
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: oldaplib
3
- Version: 0.3.9
3
+ Version: 0.3.11
4
4
  Summary: Open Media Access Server Library (Linked Open Data middleware/RESTApi)
5
5
  License: GNU Affero General Public License version 3
6
6
  Author: Lukas Rosenthaler
@@ -59,7 +59,7 @@ oldaplib/src/helpers/tools.py,sha256=sNbiOLucTGNFzZmiWwPLFOb80VTXQH0Zd9uCGubhzAk
59
59
  oldaplib/src/iconnection.py,sha256=XlOc2Kh4tK_UOHydLQwlWjUFLUze-Aq_vEZpf9KS1-s,3677
60
60
  oldaplib/src/in_project.py,sha256=2KuhHPj8DNveFRBeImrRfxlCOYhBK-mcxXYUp6s--j8,10672
61
61
  oldaplib/src/model.py,sha256=VACR3T6zJYFaE5J1PFFdP0OSwhbu4sahoLMWg6_L_rE,19267
62
- oldaplib/src/objectfactory.py,sha256=JaIDrdOiprLxhJkgCnrUtcp9UdKcHrHPQBG8cBWqvrg,47027
62
+ oldaplib/src/objectfactory.py,sha256=lUKwJWFWdOmUrrP17AB06U-AUeRHjbovIlgq915iYko,63554
63
63
  oldaplib/src/oldaplist.py,sha256=sGAvEEJukRCjM70G0NFaR-L9YPleQTOtdWGExj3oYL8,42933
64
64
  oldaplib/src/oldaplist_helpers.py,sha256=1Gur0nS1PCKb9iUtCKPUFDOYjw6vvAwYpe-G3DdxlEc,14213
65
65
  oldaplib/src/oldaplistnode.py,sha256=NnC2juEGTtEkDO6OlB9PjSw_zTF-wSsRUgEk-6VV9DA,87344
@@ -70,7 +70,7 @@ oldaplib/src/propertyclass.py,sha256=pnaDsmyGKQnJaaOHXA0XyLcp4zn1b1vC9sLbjXls4lM
70
70
  oldaplib/src/resourceclass.py,sha256=EIxyd7Z_w59wDxWLXCaLvhhvh5SjLEUWb8gqmZz8LLM,102046
71
71
  oldaplib/src/user.py,sha256=Z4GXPRkaHXx3glUpPXQdFqYMxQPOuqayDwkTAE5RGjU,48820
72
72
  oldaplib/src/userdataclass.py,sha256=FbZkcRt0pKbOeqsZ7HbpwoKE-XPWH2AqpHG1GcsrBPo,12364
73
- oldaplib/src/version.py,sha256=7YeBgSVj8ydF7tymPSFdq22NONiQoBjKL1iwcxp4TJo,21
73
+ oldaplib/src/version.py,sha256=T2nK8OAwAkUKZ_FINBrFk5NtAsVGU9e9ygu4affw1zw,22
74
74
  oldaplib/src/xsd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
75
75
  oldaplib/src/xsd/floatingpoint.py,sha256=rDReKqh0mXyc4F5wslgTUxbeGf3-PGERyughj5_62YI,8852
76
76
  oldaplib/src/xsd/iri.py,sha256=w1Dr0z-REi7yPe3GPGnyzGrLVMvLY03kEeK-AmZ9sxw,8383
@@ -126,7 +126,7 @@ oldaplib/test/test_hasproperty.py,sha256=r991g8kBTfv1CGs9Hf0fli-AUp7Ob7rOHWYD74h
126
126
  oldaplib/test/test_in_project.py,sha256=DYT-guwRQ9crnfEt7cQZxoEMxThin7QeymNce3jaZx4,7779
127
127
  oldaplib/test/test_langstring.py,sha256=37BeKiQzj63G-SyS_paK_SEG7ulRbGrE89Mz40UB_bE,15146
128
128
  oldaplib/test/test_language_in.py,sha256=ELqHO-YIsZSCPF3E3rWde4J7rERL7En7sV_pzQ00zgs,8826
129
- oldaplib/test/test_objectfactory.py,sha256=IrU714mcpI2rterqauYA0XC_wKZdQSNrLAosCvrYo7M,34440
129
+ oldaplib/test/test_objectfactory.py,sha256=nak1-QFlaKg0b5vHvOXcLXEPhi318XHMJFwIWLicqy0,37372
130
130
  oldaplib/test/test_observable_dict.py,sha256=GxD0sM0nsVfVRBu92SFGkJ6--YXq4ibBWI4IpjZZzDU,1396
131
131
  oldaplib/test/test_observable_set.py,sha256=JWZSoAsr8XIEBXPVgSVJjQQEEc8uSAme5IrFYLYVVXw,6313
132
132
  oldaplib/test/test_oldaplist.py,sha256=9wo3tEOHt5bIuXyvSSyTzjhtdKrQHiiAA6EfVBuq4wI,20114
@@ -145,6 +145,7 @@ oldaplib/testdata/connection_test.trig,sha256=LFTGLEae7SaTU67rwvgvg_epi09O7oPZwf
145
145
  oldaplib/testdata/datamodel_test.trig,sha256=0n02awPthzi-Lx-_ABlrD9yZ3I1sWxp7eIbFwSxwKNA,802
146
146
  oldaplib/testdata/event_type.yaml,sha256=wpXiheSEKh4xOoUZvAxWytJQ-sNK6oUYdVpOmyW9wPc,3083
147
147
  oldaplib/testdata/hlist_schema.yaml,sha256=fgHiB-ZxOkE6OvkZKk9SL2kNn8Akj6dS6ySDFSpknTA,186
148
+ oldaplib/testdata/instances_test.trig,sha256=4PQT2eQ8jhOTuUsSdo2kM3-Lo9zVOtpeF2X579vG4Tw,6853
148
149
  oldaplib/testdata/institution_or_building_type.yaml,sha256=SA2rsQwoAdyn6eSIJU1ilmdIQf-f1XNApwBow-JlJTo,2439
149
150
  oldaplib/testdata/language.yaml,sha256=YaQA77d7QyOydqNylR5RSb-0A6h9pLM4mgadJSrYC3A,451
150
151
  oldaplib/testdata/location_type.yaml,sha256=amlhYNDc9qLv_if6urtAtBTnEXrVrb6_aulE180GYkc,1323
@@ -157,6 +158,6 @@ oldaplib/testdata/source_type.yaml,sha256=dSihKikw3O-IlGf6anj5KWMoBYLaweLVF1Zojm
157
158
  oldaplib/testdata/test_move_left_of_toL.yaml,sha256=2m1OSQrQFlsCQxeJrjzBAO74LMprNDo_HuyrYGsOeXI,787
158
159
  oldaplib/testdata/testlist.yaml,sha256=AT11nXEG81Sfyb-tr1gQV0H_dZBrOCcFuHf7YtL8P2g,1994
159
160
  oldaplib/testit.http,sha256=qW7mnr6aNLXFG6lQdLgyhXILOPN6qc5iFVZclLyVvkY,303
160
- oldaplib-0.3.9.dist-info/METADATA,sha256=ncha961sACYOwWBsWQKJAqOQBNl06LMs-FwdLm7neA8,2854
161
- oldaplib-0.3.9.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
162
- oldaplib-0.3.9.dist-info/RECORD,,
161
+ oldaplib-0.3.11.dist-info/METADATA,sha256=U_IWnhNS_6UtMWr1peta6uFVbQrD8dWv_0yFGRq8V-Q,2855
162
+ oldaplib-0.3.11.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
163
+ oldaplib-0.3.11.dist-info/RECORD,,