From ab4f8a37076e47c9e92ff1491dba8cc4b4ee4717 Mon Sep 17 00:00:00 2001 From: Priyanshu Nayan Date: Wed, 8 Jul 2020 17:19:03 +0530 Subject: [PATCH 1/8] add collections array to the entrypoint --- hydra_python_core/doc_writer.py | 44 ++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/hydra_python_core/doc_writer.py b/hydra_python_core/doc_writer.py index b72f33d..c5c6285 100644 --- a/hydra_python_core/doc_writer.py +++ b/hydra_python_core/doc_writer.py @@ -21,9 +21,9 @@ def __init__(self, API: str, title: str, desc: str, self.desc = desc def add_supported_class( - self, class_: 'HydraClass', collection: Union[bool, 'HydraCollection']=False, - collection_path: str=None, collectionGet: bool=True, collectionPost: bool=True, - collection_manages: Union[Dict[str, Any], List]=None) -> None: + self, class_: 'HydraClass', collection: Union[bool, 'HydraCollection'] = False, + collection_path: str = None, collectionGet: bool = True, collectionPost: bool = True, + collection_manages: Union[Dict[str, Any], List] = None) -> None: """Add a new supportedClass. Raises: @@ -110,8 +110,8 @@ class HydraClass(): """Template for a new class.""" def __init__( - self, id_: str, title: str, desc: str, path: str=None, - endpoint: bool=False, sub_classof: None=None) -> None: + self, id_: str, title: str, desc: str, path: str = None, + endpoint: bool = False, sub_classof: None = None) -> None: """Initialize the Hydra_Class.""" self.id_ = id_ if "http" in id_ else "vocab:{}".format(id_) self.title = title @@ -212,7 +212,7 @@ def __init__(self, returns: Optional[str], expects_header: List[str] = [], returns_header: List[str] = [], - possible_status: List[Union['HydraStatus', 'HydraError']]=[], + possible_status: List[Union['HydraStatus', 'HydraError']] = [], ) -> None: """Initialize the Hydra_Prop.""" self.title = title @@ -254,8 +254,8 @@ class HydraCollection(): def __init__( self, class_: HydraClass, - collection_path: str=None, manages: Union[Dict[str, Any], List]=None, - get: bool=True, post: bool=True) -> None: + collection_path: str = None, manages: Union[Dict[str, Any], List] = None, + get: bool = True, post: bool = True) -> None: """Generate Collection for a given class.""" self.class_ = class_ self.name = "{}Collection".format(class_.title) @@ -314,7 +314,7 @@ def __init__(self, returns: Optional[str], expects_header: List[str] = [], returns_header: List[str] = [], - possible_status: List[Union['HydraStatus', 'HydraError']]=[], + possible_status: List[Union['HydraStatus', 'HydraError']] = [], ) -> None: """Create method.""" self.id_ = id_ @@ -361,6 +361,8 @@ def __init__(self, base_url: str, entrypoint: str) -> None: entrypoint), entrypoint=self) + self.collections: List[EntryPointCollection] = [] + def add_Class(self, class_: HydraClass) -> None: """Add supportedProperty to the EntryPoint. @@ -385,6 +387,7 @@ def add_Collection(self, collection: HydraCollection) -> None: if not isinstance(collection, HydraCollection): raise TypeError("Type is not ") entrypoint_collection = EntryPointCollection(collection) + self.collections.append(entrypoint_collection.generate()) self.entrypoint.add_supported_prop(entrypoint_collection) self.context.add(entrypoint_collection.name, { "@id": entrypoint_collection.id_, "@type": "@id"}) @@ -402,9 +405,23 @@ def get(self) -> Dict[str, str]: } for item in self.entrypoint.supportedProperty: uri = item.id_ - object_[item.name] = uri.replace( - "vocab:EntryPoint", "/{}".format(self.api)) - + if item.generate() in self.collections: + object_['collections'] = [] + collection_returned = item.generate() + collection_id = uri.replace( + "vocab:EntryPoint", "/{}".format(self.api)) + # TODO Add manages block too. + collection_to_append = { + "@id": collection_id, + 'title': collection_returned['hydra:title'], + '@type': "Collection", + "supportedOperation": collection_returned['property']['supportedOperation'], + } + object_['collections'].append(collection_to_append) + else: + object_[item.name] = uri.replace( + "vocab:EntryPoint", "/{}".format(self.api)) + return object_ @@ -501,7 +518,7 @@ def __init__(self, returns: Optional[str], expects_header: List[str] = [], returns_header: List[str] = [], - possible_status: List[Union['HydraStatus', 'HydraError']]=[], + possible_status: List[Union['HydraStatus', 'HydraError']] = [], type_: Optional[str] = None, label: str = "", ) -> None: @@ -724,7 +741,6 @@ def __init__(self, "label": "rdfs:label", "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", "vocab": "{}/vocab#".format(address), - # "vocab": "localhost/api/vocab#", "domain": { "@type": "@id", "@id": "rdfs:domain" From 3b91709ad53198330395ee6f5c48525cea1fc173 Mon Sep 17 00:00:00 2001 From: Priyanshu Nayan Date: Wed, 8 Jul 2020 23:51:22 +0530 Subject: [PATCH 2/8] add default manages block --- hydra_python_core/doc_writer.py | 21 +++++++++++++++------ samples/doc_writer_sample_output.py | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/hydra_python_core/doc_writer.py b/hydra_python_core/doc_writer.py index c5c6285..37e39fd 100644 --- a/hydra_python_core/doc_writer.py +++ b/hydra_python_core/doc_writer.py @@ -260,13 +260,20 @@ def __init__( self.class_ = class_ self.name = "{}Collection".format(class_.title) self.path = collection_path if collection_path else self.name - self.manages = manages + self.supportedOperation = list() # type: List self.supportedProperty = [HydraClassProp("http://www.w3.org/ns/hydra/core#member", "members", False, False, False, "The {}".format(self.class_.title.lower()))] + if manages is None: + # provide default manages block + self.manages = { + "property": "rdf:type", + "object": class_.id_, + } + if get: get_op = HydraCollectionOp("_:{}_collection_retrieve".format(self.class_.title.lower()), "http://schema.org/FindAction", @@ -295,10 +302,9 @@ def generate(self) -> Dict[str, Any]: "title": "{}".format(self.name), "description": "A collection of {}".format(self.class_.title.lower()), "supportedOperation": [x.generate() for x in self.supportedOperation], - "supportedProperty": [x.generate() for x in self.supportedProperty] + "supportedProperty": [x.generate() for x in self.supportedProperty], + "manages": self.manages } - if self.manages is not None: - collection["manages"] = self.manages return collection @@ -416,12 +422,13 @@ def get(self) -> Dict[str, str]: 'title': collection_returned['hydra:title'], '@type': "Collection", "supportedOperation": collection_returned['property']['supportedOperation'], + "manages": collection_returned['property']['manages'] } object_['collections'].append(collection_to_append) else: object_[item.name] = uri.replace( "vocab:EntryPoint", "/{}".format(self.api)) - + return object_ @@ -432,6 +439,7 @@ def __init__(self, collection: HydraCollection) -> None: """Create method.""" self.name = collection.name self.supportedOperation = collection.supportedOperation + self.manages = collection.manages if collection.path: self.id_ = "vocab:EntryPoint/{}".format(collection.path) else: @@ -447,7 +455,8 @@ def generate(self) -> Dict[str, Any]: "description": "The {} collection".format(self.name,), "domain": "vocab:EntryPoint", "range": "vocab:{}".format(self.name,), - "supportedOperation": [] + "supportedOperation": [], + "manages": self.manages }, "hydra:title": self.name.lower(), "hydra:description": "The {} collection".format(self.name,), diff --git a/samples/doc_writer_sample_output.py b/samples/doc_writer_sample_output.py index 67a8191..35cf62f 100644 --- a/samples/doc_writer_sample_output.py +++ b/samples/doc_writer_sample_output.py @@ -349,6 +349,10 @@ "@id": "vocab:dummyClassCollection", "@type": "hydra:Class", "description": "A collection of dummyclass", + "manages": { + "object": "vocab:dummyClass", + "property": "rdf:type" + }, "subClassOf": "http://www.w3.org/ns/hydra/core#Collection", "supportedOperation": [ { @@ -399,6 +403,10 @@ "@id": "vocab:extraClassCollection", "@type": "hydra:Class", "description": "A collection of extraclass", + "manages": { + "object": "vocab:extraClass", + "property": "rdf:type" + }, "subClassOf": "http://www.w3.org/ns/hydra/core#Collection", "supportedOperation": [ { @@ -606,6 +614,10 @@ "description": "The dummyClassCollection collection", "domain": "vocab:EntryPoint", "label": "dummyClassCollection", + "manages": { + "object": "vocab:dummyClass", + "property": "rdf:type" + }, "range": "vocab:dummyClassCollection", "supportedOperation": [ { @@ -653,6 +665,10 @@ "description": "The extraClassCollection collection", "domain": "vocab:EntryPoint", "label": "extraClassCollection", + "manages": { + "object": "vocab:extraClass", + "property": "rdf:type" + }, "range": "vocab:extraClassCollection", "supportedOperation": [ { From eef10439c1e81a5d0a477962aaa531535abd3c80 Mon Sep 17 00:00:00 2001 From: Priyanshu Nayan Date: Thu, 9 Jul 2020 22:25:05 +0530 Subject: [PATCH 3/8] allow configurable collection names --- hydra_python_core/doc_writer.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/hydra_python_core/doc_writer.py b/hydra_python_core/doc_writer.py index 37e39fd..e4b972a 100644 --- a/hydra_python_core/doc_writer.py +++ b/hydra_python_core/doc_writer.py @@ -1,5 +1,6 @@ """API Doc templates generator.""" from typing import Any, Dict, List, Optional, Union +from urllib.parse import quote class HydraDoc(): @@ -22,6 +23,7 @@ def __init__(self, API: str, title: str, desc: str, def add_supported_class( self, class_: 'HydraClass', collection: Union[bool, 'HydraCollection'] = False, + collection_name: str = None, collection_path: str = None, collectionGet: bool = True, collectionPost: bool = True, collection_manages: Union[Dict[str, Any], List] = None) -> None: """Add a new supportedClass. @@ -40,7 +42,7 @@ def add_supported_class( } if collection: collection = HydraCollection( - class_, collection_path, collection_manages, collectionGet, collectionPost) + class_, collection_name, collection_path, collection_manages, collectionGet, collectionPost) self.collections[collection.path] = { "context": Context(address="{}{}".format(self.base_url, self.API), collection=collection), "collection": collection} @@ -254,19 +256,20 @@ class HydraCollection(): def __init__( self, class_: HydraClass, - collection_path: str = None, manages: Union[Dict[str, Any], List] = None, + collection_name: str = None, + collection_path: str = None, + manages: Union[Dict[str, Any], List] = None, get: bool = True, post: bool = True) -> None: """Generate Collection for a given class.""" self.class_ = class_ - self.name = "{}Collection".format(class_.title) + self.name = "{}Collection".format(class_.title) \ + if (collection_name is None) else collection_name self.path = collection_path if collection_path else self.name - self.supportedOperation = list() # type: List self.supportedProperty = [HydraClassProp("http://www.w3.org/ns/hydra/core#member", "members", False, False, False, "The {}".format(self.class_.title.lower()))] - if manages is None: # provide default manages block self.manages = { @@ -295,9 +298,12 @@ def __init__( def generate(self) -> Dict[str, Any]: """Get as a python dict.""" + + # encode name because name might contain spaces or special Characters. + name = quote(self.name, safe='') collection = { - "@id": "vocab:{}".format(self.name,), - "@type": "hydra:Class", + "@id": "vocab:{}".format(name), + "@type": "Collection", "subClassOf": "http://www.w3.org/ns/hydra/core#Collection", "title": "{}".format(self.name), "description": "A collection of {}".format(self.class_.title.lower()), @@ -416,7 +422,6 @@ def get(self) -> Dict[str, str]: collection_returned = item.generate() collection_id = uri.replace( "vocab:EntryPoint", "/{}".format(self.api)) - # TODO Add manages block too. collection_to_append = { "@id": collection_id, 'title': collection_returned['hydra:title'], @@ -441,9 +446,10 @@ def __init__(self, collection: HydraCollection) -> None: self.supportedOperation = collection.supportedOperation self.manages = collection.manages if collection.path: - self.id_ = "vocab:EntryPoint/{}".format(collection.path) + self.id_ = "vocab:EntryPoint/{}".format( + quote(collection.path, safe='')) else: - self.id_ = "vocab:EntryPoint/{}".format(self.name) + self.id_ = "vocab:EntryPoint/{}".format(quote(self.name, safe='')) def generate(self) -> Dict[str, Any]: """Get as a python dict.""" From df657e802e9dc479926dbe7b7ef729162bafcb4f Mon Sep 17 00:00:00 2001 From: Priyanshu Nayan Date: Thu, 9 Jul 2020 23:33:24 +0530 Subject: [PATCH 4/8] fix tests and pep8 format --- hydra_python_core/doc_writer.py | 83 +++++++++++++++++---------------- tests/test_doc_writer.py | 4 +- 2 files changed, 44 insertions(+), 43 deletions(-) diff --git a/hydra_python_core/doc_writer.py b/hydra_python_core/doc_writer.py index e4b972a..10768fe 100644 --- a/hydra_python_core/doc_writer.py +++ b/hydra_python_core/doc_writer.py @@ -22,10 +22,10 @@ def __init__(self, API: str, title: str, desc: str, self.desc = desc def add_supported_class( - self, class_: 'HydraClass', collection: Union[bool, 'HydraCollection'] = False, - collection_name: str = None, - collection_path: str = None, collectionGet: bool = True, collectionPost: bool = True, - collection_manages: Union[Dict[str, Any], List] = None) -> None: + self, class_: 'HydraClass', collection: Union[bool, 'HydraCollection']=False, + collection_name: str=None, + collection_path: str=None, collectionGet: bool=True, collectionPost: bool=True, + collection_manages: Union[Dict[str, Any], List]=None) -> None: """Add a new supportedClass. Raises: @@ -42,7 +42,8 @@ def add_supported_class( } if collection: collection = HydraCollection( - class_, collection_name, collection_path, collection_manages, collectionGet, collectionPost) + class_, collection_name, collection_path, collection_manages, collectionGet, + collectionPost) self.collections[collection.path] = { "context": Context(address="{}{}".format(self.base_url, self.API), collection=collection), "collection": collection} @@ -112,8 +113,8 @@ class HydraClass(): """Template for a new class.""" def __init__( - self, id_: str, title: str, desc: str, path: str = None, - endpoint: bool = False, sub_classof: None = None) -> None: + self, id_: str, title: str, desc: str, path: str=None, + endpoint: bool=False, sub_classof: None=None) -> None: """Initialize the Hydra_Class.""" self.id_ = id_ if "http" in id_ else "vocab:{}".format(id_) self.title = title @@ -176,7 +177,7 @@ def __init__(self, read: bool, write: bool, required: bool, - desc: str = "", + desc: str="", ) -> None: """Initialize the Hydra_Prop.""" self.prop = prop @@ -212,9 +213,9 @@ def __init__(self, method: str, expects: Optional[str], returns: Optional[str], - expects_header: List[str] = [], - returns_header: List[str] = [], - possible_status: List[Union['HydraStatus', 'HydraError']] = [], + expects_header: List[str]=[], + returns_header: List[str]=[], + possible_status: List[Union['HydraStatus', 'HydraError']]=[], ) -> None: """Initialize the Hydra_Prop.""" self.title = title @@ -256,10 +257,10 @@ class HydraCollection(): def __init__( self, class_: HydraClass, - collection_name: str = None, - collection_path: str = None, - manages: Union[Dict[str, Any], List] = None, - get: bool = True, post: bool = True) -> None: + collection_name: str=None, + collection_path: str=None, + manages: Union[Dict[str, Any], List]=None, + get: bool=True, post: bool=True) -> None: """Generate Collection for a given class.""" self.class_ = class_ self.name = "{}Collection".format(class_.title) \ @@ -281,19 +282,19 @@ def __init__( get_op = HydraCollectionOp("_:{}_collection_retrieve".format(self.class_.title.lower()), "http://schema.org/FindAction", "GET", "Retrieves all {} entities".format( - self.class_.title), - None, "vocab:{}".format(self.name), [], [], []) + self.class_.title), + None, "vocab:{}".format(self.name), [], [], []) self.supportedOperation.append(get_op) if post: post_op = HydraCollectionOp("_:{}_create".format(self.class_.title.lower()), "http://schema.org/AddAction", "PUT", "Create new {} entity".format( - self.class_.title), - self.class_.id_, self.class_.id_, [], [], - [HydraStatus(code=201, desc="If the {} entity was created" - "successfully.".format(self.class_.title))] - ) + self.class_.title), + self.class_.id_, self.class_.id_, [], [], + [HydraStatus(code=201, desc="If the {} entity was created" + "successfully.".format(self.class_.title))] + ) self.supportedOperation.append(post_op) def generate(self) -> Dict[str, Any]: @@ -324,9 +325,9 @@ def __init__(self, desc: str, expects: Optional[str], returns: Optional[str], - expects_header: List[str] = [], - returns_header: List[str] = [], - possible_status: List[Union['HydraStatus', 'HydraError']] = [], + expects_header: List[str]=[], + returns_header: List[str]=[], + possible_status: List[Union['HydraStatus', 'HydraError']]=[], ) -> None: """Create method.""" self.id_ = id_ @@ -531,11 +532,11 @@ def __init__(self, desc: str, expects: Optional[str], returns: Optional[str], - expects_header: List[str] = [], - returns_header: List[str] = [], - possible_status: List[Union['HydraStatus', 'HydraError']] = [], - type_: Optional[str] = None, - label: str = "", + expects_header: List[str]=[], + returns_header: List[str]=[], + possible_status: List[Union['HydraStatus', 'HydraError']]=[], + type_: Optional[str]=None, + label: str="", ) -> None: """Create method.""" self.id_ = id_ @@ -586,7 +587,7 @@ class IriTemplateMapping(): def __init__(self, variable: str, prop: str, - required: bool = False): + required: bool=False): self.variable = variable self.prop = prop self.required = required @@ -608,7 +609,7 @@ class HydraIriTemplate(): def __init__(self, template: str, iri_mapping: List[IriTemplateMapping] = [], - basic_representation: bool = True): + basic_representation: bool=True): self.template = template if basic_representation: self.variable_rep = "hydra:BasicRepresentation" @@ -630,14 +631,14 @@ def generate(self) -> Dict[str, Any]: class HydraStatus(): """Class for possibleStatus in Hydra Doc.""" - def __init__(self, code: int, id_: str = None, title: str = "", desc: str = "") -> None: + def __init__(self, code: int, id_: str=None, title: str="", desc: str="") -> None: """Create method.""" self.code = code self.id_ = id_ self.title = title self.desc = desc - def generate(self, status_type: str = "Status") -> Dict[str, Any]: + def generate(self, status_type: str="Status") -> Dict[str, Any]: """Get as Python dict.""" status = { "@context": "http://www.w3.org/ns/hydra/context.jsonld", @@ -654,7 +655,7 @@ def generate(self, status_type: str = "Status") -> Dict[str, Any]: class HydraError(HydraStatus): """Class for Hydra Error to represent error details.""" - def __init__(self, code: int, id_: str = None, title: str = "", desc: str = "") -> None: + def __init__(self, code: int, id_: str=None, title: str="", desc: str="") -> None: """Create method""" super().__init__(code, id_, title, desc) @@ -668,8 +669,8 @@ class HydraLink(): """Template for a link property.""" def __init__( - self, id_: str, title: str = "", - desc: str = "", domain: str = "", range_: str = "") -> None: + self, id_: str, title: str="", + desc: str = "", domain: str="", range_: str="") -> None: """Initialize the Hydra_Link.""" self.id_ = id_ if "http" in id_ else "vocab:{}".format(id_) self.range = range_ @@ -709,10 +710,10 @@ class Context(): def __init__(self, address: str, - adders: Dict = {}, - class_: Optional[HydraClass] = None, - collection: Optional[HydraCollection] = None, - entrypoint: Optional[HydraEntryPoint] = None, + adders: Dict={}, + class_: Optional[HydraClass]=None, + collection: Optional[HydraCollection]=None, + entrypoint: Optional[HydraEntryPoint]=None, ) -> None: """Initialize context.""" # NOTE: adders is a dictionary containing additional diff --git a/tests/test_doc_writer.py b/tests/test_doc_writer.py index d373dd9..9975439 100644 --- a/tests/test_doc_writer.py +++ b/tests/test_doc_writer.py @@ -24,7 +24,6 @@ def test_context_with_nothing(self): "label": "rdfs:label", "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", "vocab": "https://hydrus.com/api/vocab#", - # "vocab": "localhost/api/vocab#", "domain": { "@type": "@id", "@id": "rdfs:domain" @@ -57,7 +56,8 @@ def test_context_with_nothing(self): "subClassOf": { "@id": "rdfs:subClassOf", "@type": "@id" - } + }, + "search": "hydra:search" } self.assertEqual(expected_context, context.generate()) From 76cebd2e0b9734d72809c7b06c13ff9a4548dd12 Mon Sep 17 00:00:00 2001 From: Priyanshu Nayan Date: Thu, 16 Jul 2020 22:39:51 +0530 Subject: [PATCH 5/8] add entrypoint property to the apidoc --- samples/doc_writer_sample.py | 2 +- samples/doc_writer_sample_output.py | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/samples/doc_writer_sample.py b/samples/doc_writer_sample.py index 1bcf7b4..a9d6cbb 100644 --- a/samples/doc_writer_sample.py +++ b/samples/doc_writer_sample.py @@ -6,7 +6,7 @@ # Creating the HydraDoc object, this is the primary class for the Doc API_NAME = "api" # Name of the API, will serve as EntryPoint -BASE_URL = "https://hydrus.com/" # The base url at which the API is hosted +BASE_URL = "https://hydrus.com" # The base url at which the API is hosted # NOTE: The API will be accessible at BASE_URL + ENTRY_POINT # (http://hydrus.com/api/) diff --git a/samples/doc_writer_sample_output.py b/samples/doc_writer_sample_output.py index 35cf62f..ab7a2c4 100644 --- a/samples/doc_writer_sample_output.py +++ b/samples/doc_writer_sample_output.py @@ -1,5 +1,5 @@ """Generated API Documentation sample using doc_writer_sample.py.""" - + doc = { "@context": { "ApiDocumentation": "hydra:ApiDocumentation", @@ -48,9 +48,10 @@ "vocab": "https://hydrus.com/api/vocab#", "writeable": "hydra:writeable" }, - "@id": "https://hydrus.com/api/vocab", + "@id": "https://hydrus.comapi/vocab", "@type": "ApiDocumentation", "description": "Description for the API Documentation", + "entrypoint": "https://hydrus.com/api", "possibleStatus": [], "supportedClass": [ { @@ -347,7 +348,7 @@ }, { "@id": "vocab:dummyClassCollection", - "@type": "hydra:Class", + "@type": "Collection", "description": "A collection of dummyclass", "manages": { "object": "vocab:dummyClass", @@ -401,7 +402,7 @@ }, { "@id": "vocab:extraClassCollection", - "@type": "hydra:Class", + "@type": "Collection", "description": "A collection of extraclass", "manages": { "object": "vocab:extraClass", From f88be99adee31cc074f5052f92ef66566fe279e4 Mon Sep 17 00:00:00 2001 From: Priyanshu Nayan Date: Thu, 16 Jul 2020 23:25:52 +0530 Subject: [PATCH 6/8] add example of manages block in sample --- hydra_python_core/doc_writer.py | 32 ++++++++++++----------------- samples/doc_writer_sample.py | 20 +++++++++++++++--- samples/doc_writer_sample_output.py | 10 +-------- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/hydra_python_core/doc_writer.py b/hydra_python_core/doc_writer.py index 10768fe..da04138 100644 --- a/hydra_python_core/doc_writer.py +++ b/hydra_python_core/doc_writer.py @@ -1,6 +1,6 @@ """API Doc templates generator.""" from typing import Any, Dict, List, Optional, Union -from urllib.parse import quote +from urllib.parse import quote, urljoin class HydraDoc(): @@ -10,9 +10,10 @@ def __init__(self, API: str, title: str, desc: str, entrypoint: str, base_url: str) -> None: """Initialize the APIDoc.""" self.API = API + self.entrypoint_endpoint = entrypoint self.title = title self.base_url = base_url - self.context = Context("{}{}".format(base_url, API)) + self.context = Context("{}".format(urljoin(base_url, API))) self.parsed_classes = dict() # type: Dict[str, Any] self.other_classes = list() # type: List[HydraClass] self.collections = dict() # type: Dict[str, Any] @@ -101,6 +102,7 @@ def generate(self) -> Dict[str, Any]: "@type": "ApiDocumentation", "title": self.title, "description": self.desc, + "entrypoint": urljoin(self.base_url, self.entrypoint_endpoint), "supportedClass": [ x.generate() for x in parsed_classes + self.other_classes + collections + [self.entrypoint]], @@ -277,6 +279,8 @@ def __init__( "property": "rdf:type", "object": class_.id_, } + else: + self.manages = manages if get: get_op = HydraCollectionOp("_:{}_collection_retrieve".format(self.class_.title.lower()), @@ -445,7 +449,6 @@ def __init__(self, collection: HydraCollection) -> None: """Create method.""" self.name = collection.name self.supportedOperation = collection.supportedOperation - self.manages = collection.manages if collection.path: self.id_ = "vocab:EntryPoint/{}".format( quote(collection.path, safe='')) @@ -463,7 +466,6 @@ def generate(self) -> Dict[str, Any]: "domain": "vocab:EntryPoint", "range": "vocab:{}".format(self.name,), "supportedOperation": [], - "manages": self.manages }, "hydra:title": self.name.lower(), "hydra:description": "The {} collection".format(self.name,), @@ -710,7 +712,6 @@ class Context(): def __init__(self, address: str, - adders: Dict={}, class_: Optional[HydraClass]=None, collection: Optional[HydraCollection]=None, entrypoint: Optional[HydraEntryPoint]=None, @@ -719,24 +720,17 @@ def __init__(self, # NOTE: adders is a dictionary containing additional # context elements to the base Hydra context if class_ is not None: - self.context = { - "vocab": "{}/vocab#".format(address), - "hydra": "http://www.w3.org/ns/hydra/core#", - "members": "http://www.w3.org/ns/hydra/core#member", - "object": "http://schema.org/object", - } # type: Dict[str, Any] - self.context[class_.title] = class_.id_ + self.context = {"vocab": "{}/vocab#".format(address), "hydra": "http://www.w3.org/ns/hydra/core#", + "members": "http://www.w3.org/ns/hydra/core#member", "object": "http://schema.org/object", + class_.title: class_.id_} # type: Dict[str, Any] for prop in class_.supportedProperty: self.context[prop.title] = prop.prop elif collection is not None: - self.context = { - "vocab": "{}/vocab#".format(address), - "hydra": "http://www.w3.org/ns/hydra/core#", - "members": "http://www.w3.org/ns/hydra/core#member", - } - self.context[collection.name] = "vocab:{}".format(collection.name) - self.context[collection.class_.title] = collection.class_.id_ + self.context = {"vocab": "{}/vocab#".format(address), "hydra": "http://www.w3.org/ns/hydra/core#", + "members": "http://www.w3.org/ns/hydra/core#member", + collection.name: "vocab:{}".format(collection.name), + collection.class_.title: collection.class_.id_} elif entrypoint is not None: self.context = { diff --git a/samples/doc_writer_sample.py b/samples/doc_writer_sample.py index a9d6cbb..d903152 100644 --- a/samples/doc_writer_sample.py +++ b/samples/doc_writer_sample.py @@ -138,9 +138,23 @@ class_2.add_supported_op(class_2_op4) class_1.add_supported_op(class_1_op1) +# add explicit statements about members of the collection +# Following manages block means every member of this collection is of type class_ +collection_1_managed_by = { + "property": "rdf:type", + "object": 'vocab:' + class_uri, +} +# Following manages block means every member of this collection is of type class_3 +collection_3_managed_by = { + "property": "rdf:type", + "object": 'vocab:' + class_3_uri, +} # Add the classes to the HydraDoc -api_doc.add_supported_class(class_, collection=True, collection_path="DcTest") -api_doc.add_supported_class(class_3, collection=True, collection_path="EcTest") + +api_doc.add_supported_class(class_, collection=True, collection_path="DcTest", + collection_manages=collection_1_managed_by) +api_doc.add_supported_class(class_3, collection=True, collection_path="EcTest", + collection_manages=collection_3_managed_by) api_doc.add_supported_class(class_2, collection=False) api_doc.add_supported_class(class_1, collection=False) # NOTE: Using collection=True creates a HydraCollection for the class. @@ -172,5 +186,5 @@ doc = doc.replace('true', '"true"') doc = doc.replace('false', '"false"') doc = doc.replace('null', '"null"') - with open("doc_writer_sample_output.py", "w") as f: + with open("samples/doc_writer_sample_output.py", "w") as f: f.write(doc) diff --git a/samples/doc_writer_sample_output.py b/samples/doc_writer_sample_output.py index ab7a2c4..07cc99a 100644 --- a/samples/doc_writer_sample_output.py +++ b/samples/doc_writer_sample_output.py @@ -1,5 +1,5 @@ """Generated API Documentation sample using doc_writer_sample.py.""" - + doc = { "@context": { "ApiDocumentation": "hydra:ApiDocumentation", @@ -615,10 +615,6 @@ "description": "The dummyClassCollection collection", "domain": "vocab:EntryPoint", "label": "dummyClassCollection", - "manages": { - "object": "vocab:dummyClass", - "property": "rdf:type" - }, "range": "vocab:dummyClassCollection", "supportedOperation": [ { @@ -666,10 +662,6 @@ "description": "The extraClassCollection collection", "domain": "vocab:EntryPoint", "label": "extraClassCollection", - "manages": { - "object": "vocab:extraClass", - "property": "rdf:type" - }, "range": "vocab:extraClassCollection", "supportedOperation": [ { From 3c9193bdb19aa142a4c14f41d3b0c61a37920dcf Mon Sep 17 00:00:00 2001 From: Priyanshu Nayan Date: Thu, 16 Jul 2020 23:35:01 +0530 Subject: [PATCH 7/8] fix id literal --- hydra_python_core/doc_writer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hydra_python_core/doc_writer.py b/hydra_python_core/doc_writer.py index da04138..81f7074 100644 --- a/hydra_python_core/doc_writer.py +++ b/hydra_python_core/doc_writer.py @@ -98,7 +98,7 @@ def generate(self) -> Dict[str, Any]: for key in self.collections] doc = { "@context": self.context.generate(), - "@id": "{}{}/vocab".format(self.base_url, self.API), + "@id": "{}/vocab".format(urljoin(self.base_url, self.API)), "@type": "ApiDocumentation", "title": self.title, "description": self.desc, From dd6b739eb930debfe32294aaeaf04177b589a6dc Mon Sep 17 00:00:00 2001 From: Priyanshu Nayan Date: Thu, 16 Jul 2020 23:35:01 +0530 Subject: [PATCH 8/8] fix id literal and generate sample doc --- samples/doc_writer_sample_output.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/doc_writer_sample_output.py b/samples/doc_writer_sample_output.py index 07cc99a..429b3bc 100644 --- a/samples/doc_writer_sample_output.py +++ b/samples/doc_writer_sample_output.py @@ -48,7 +48,7 @@ "vocab": "https://hydrus.com/api/vocab#", "writeable": "hydra:writeable" }, - "@id": "https://hydrus.comapi/vocab", + "@id": "https://hydrus.com/api/vocab", "@type": "ApiDocumentation", "description": "Description for the API Documentation", "entrypoint": "https://hydrus.com/api",