Skip to content

Commit

Permalink
Added support for documentation of Exportable
Browse files Browse the repository at this point in the history
  • Loading branch information
PonteIneptique committed Dec 16, 2016
1 parent d400f2b commit 8e6a8c6
Show file tree
Hide file tree
Showing 10 changed files with 150 additions and 41 deletions.
2 changes: 0 additions & 2 deletions MyCapytain/common/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,6 @@ def export_capacities(self):
def __export__(self, output=None, **kwargs):
""" Export the collection item in the Mimetype required.
..note:: If current implementation does not have special mimetypes, reuses default_export method
:param output: Mimetype to export to (Uses MyCapytain.common.utils.Mimetypes)
:type output: str
:return: Object using a different representation
Expand Down
40 changes: 22 additions & 18 deletions MyCapytain/retrievers/cts5.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,49 +178,53 @@ def getMetadata(self, objectId=None, **filters):
filters.update({"urn": objectId})
return self.getCapabilities(**filters)

def getText(self, textId, reference=None, prevnext=False, metadata=False):
def getTextualNode(self, textId, subreference=None, prevnext=False, metadata=False):
""" Retrieve a text node from the API
:param textId: Text Identifier
:param reference: Passage Reference
:param subreference: Passage Reference
:param prevnext: Retrieve graph representing previous and next passage
:param metadata: Retrieve metadata about the passage and the text
:return: GetPassage or GetPassagePlus CTS API request response
"""
if reference:
textId = "{}:{}".format(textId, reference)
if subreference:
textId = "{}:{}".format(textId, subreference)

if prevnext or metadata:
return self.getPassagePlus(urn=textId)
else:
return self.getPassage(urn=textId)

def getSiblings(self, textId, reference):
def getSiblings(self, textId, subreference):
""" Retrieve the siblings of a textual node
:param textId: Text Identifier
:param reference: Passage Reference
:return: GetPrevNextUrn request response from the endpoint
"""
textId = "{}:{}".format(textId, reference)
textId = "{}:{}".format(textId, subreference)
return self.getPrevNextUrn(urn=textId)

def getChildren(self, textId, reference=None, depth=1):
def getReffs(self, textId, level=1, subreference=None):
""" Retrieve the siblings of a textual node
:param textId: Text Identifier
:param reference: Passage Reference
:param depth: Depth of the children reference to retrieve
:return: GetValidReff request response from the endpoint
:type textId: str
:param level: Depth for retrieval
:type level: int
:param subreference: Passage Reference
:type subreference: str
:return: List of references
:rtype: [str]
"""
if reference:
textId = "{}:{}".format(textId, reference)
level = depth
if reference:
if isinstance(reference, Reference):
level += len(reference)
depth = level
if subreference:
textId = "{}:{}".format(textId, subreference)
if subreference:
if isinstance(subreference, Reference):
depth += len(subreference)
else:
level += len(Reference(reference))
if depth:
depth += len(Reference(subreference))
if level:
level = max(depth, level)
return self.getValidReff(urn=textId, level=level)
19 changes: 12 additions & 7 deletions MyCapytain/retrievers/prototypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,32 +41,37 @@ def getMetadata(self, objectId=None, **filters):
"""
raise NotImplementedError

def getText(self, textId, reference=None, prevnext=False, metadata=False):
def getTextualNode(self, textId, subreference=None, prevnext=False, metadata=False):
""" Retrieve a text node from the API
:param textId: Text Identifier
:param reference: Passage Reference
:param subreference: Passage Reference
:param prevnext: Retrieve graph representing previous and next passage
:param metadata: Retrieve metadata about the passage and the text
:return: Text of a Passage from an API or the likes as bytes
"""
raise NotImplementedError

def getSiblings(self, textId, reference):
def getSiblings(self, textId, subreference):
""" Retrieve the siblings of a textual node
:param textId: Text Identifier
:param reference: Passage Reference
:param subreference: Passage Reference
:return: Siblings references from an API or the likes as bytes
"""
raise NotImplementedError

def getChildren(self, textId, reference=None, depth=None):
def getReffs(self, textId, level=1, subreference=None):
""" Retrieve the siblings of a textual node
:param textId: Text Identifier
:param reference: Passage Reference
:return: Children references from an API or the likes as bytes
:type textId: str
:param level: Depth for retrieval
:type level: int
:param subreference: Passage Reference
:type subreference: str
:return: List of references
:rtype: [str]
"""
raise NotImplementedError

Expand Down
4 changes: 4 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@
.. image:: https://api.codacy.com/project/badge/grade/8e63e69a94274422865e4f275dbf08ea
:target: https://www.codacy.com/app/leponteineptique/MyCapytain


MyCapytain is a python library which provides a large set of methods to interact with Text Services API such as the \
Canonical Text Services, the Distributed Text Services. It also provides a programming interface to exploit local \
textual resources developed according to the Capitains Guidelines.

Simple Example of what it does
##############################

The following code and example is badly displayed at the moment on Github. We recommend you to go to \
http://mycapytain.readthedocs.org

On Leipzig DH Chair's Canonical Text Services API, we can find the Epigrammata of Martial. This texts are identified \
by the identifier "urn:cts:latinLit:phi1294.phi002.perseus-lat2". We want to have some information about this text \
so we are gonna ask the API to give its metadata to us :
Expand Down
74 changes: 74 additions & 0 deletions doc/Exportable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
from MyCapytain.common.constants import Exportable, Mimetypes


class Sentence(Exportable):
""" This class represent a Sentence
:param content: Content of the sentence
"""
# EXPORT_TO is a list of Mimetype the object is capable to export to
EXPORT_TO = [
Mimetypes.PLAINTEXT, Mimetypes.XML.Std
]
DEFAULT_EXPORT = Mimetypes.PLAINTEXT

def __init__(self, content):
self.content = content

def __export__(self, output=None, **kwargs):
""" Export the collection item in the Mimetype required.
:param output: Mimetype to export to (Uses MyCapytain.common.utils.Mimetypes)
:type output: str
:return: Object using a different representation
"""
if output == Mimetypes.PLAINTEXT:
return self.content
elif output == Mimetypes.XML.Std:
return "<sentence>{}</sentence>".format(self.content)


class TEISentence(Sentence):
""" This class represent a Sentence but adds some exportable accepted output
:param content: Content of the sentence
"""
EXPORT_TO = [
Mimetypes.JSON.Std
]

def __export__(self, output=None, **kwargs):
""" Export the collection item in the Mimetype required.
:param output: Mimetype to export to (Uses MyCapytain.common.utils.Mimetypes)
:type output: str
:return: Object using a different representation
"""
if output == Mimetypes.JSON.Std:
return {"http://www.tei-c.org/ns/1.0/sentence": self.content}
elif output == Mimetypes.XML.Std:
return "<sentence xmlns=\"http://www.tei-c.org/ns/1.0\">{}</sentence>".format(self.content)


s = Sentence("I love Martial's Epigrammatas")
print(s.export(Mimetypes.PLAINTEXT))
# I love Martial's Epigrammatas
print(s.export()) # Defaults to PLAINTEXT
# I love Martial's Epigrammatas
print(s.export(Mimetypes.XML.Std))
# <sentence>I love Martial's Epigrammatas</sentence>

tei = TEISentence("I love Martial's Epigrammatas")
print(tei.export(Mimetypes.PLAINTEXT))
# I love Martial's Epigrammatas
print(tei.export()) # Defaults to PLAINTEXT
# I love Martial's Epigrammatas
print(tei.export(Mimetypes.JSON.Std))
# {"http://www.tei-c.org/ns/1.0/sentence": I love Martial's Epigrammatas}
print(tei.export(Mimetypes.XML.Std)) # Has been rewritten by TEISentence
# <sentence xmlns="http://www.tei-c.org/ns/1.0">I love Martial's Epigrammatas</sentence>
try:
print(tei.export(Mimetypes.XML.RDF))
except NotImplementedError as error:
print(error)
# Raise the error and prints "Mimetype application/rdf+xml has not been implemented for this resource"
27 changes: 25 additions & 2 deletions doc/MyCapytain.classes.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,30 @@
MyCapytain's Main Objects Explained
===================================

Important "Abstract" Parent Classes
###################################

Exportable
**********

:class:`MyCapytain.common.constants.Exportable`

The Exportable class is visible all across the library. It provides a common, standardized way to retrieve in an API \
fashion to what can an object be exported and to exports it. Any exportable object should have an EXPORT_TO constant \
variable and include a __export__(output, **kwargs) methods if it provides an export type.
Example
-------

The following code block is a mere example of how to implement Exportable and what are its responsibilities. Exportable\
typically loops over all the parents class of the current class until it find one exportable system matching the \
required one.

.. literalinclude:: Exportabke.py
:language: python
:linenos:


Retrievers
##########

Expand Down Expand Up @@ -43,8 +67,7 @@ Example of implementation : CTS 5
Text and Passages
#################

Needs to be written

Text and Passages have been divided into a lot of different object

Collection
##########
Expand Down
1 change: 1 addition & 0 deletions doc/MyCapytain.local.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ Getting all passages from a text
# We print the passage from which we retrieve <note> nodes
print("\t".join([ref, psg.text(exclude=["note"])]))
8 changes: 4 additions & 4 deletions tests/resources/texts/api/test_cts.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,15 +401,15 @@ def test_get_siblings(self):
retriever=self.endpoint
)
passage = text.getTextualNode("1.1")
self.assertEqual(
passage.siblingsId, ("1.pr", "1.2"),
"SiblingsId should resolve"
)

# When next does not exist from the original resource
self.endpoint.getPrevNextUrn.assert_called_with(
urn="urn:cts:latinLit:phi1294.phi002.perseus-lat2:1.1"
)
self.assertEqual(
passage.siblingsId, ("1.pr", "1.2"),
"SiblingsId should resolve"
)

def test_get_last_id(self):
self.endpoint.getPassage = mock.MagicMock(return_value=GET_PASSAGE)
Expand Down
10 changes: 5 additions & 5 deletions tests/retrievers/test_cts5.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ def test_get_siblings(self):
def test_get_children(self):
""" Ensure Citable Text Service getMetadata is correctly routed """
with patch('requests.get') as patched_get:
self.cts.getChildren("urn:cts:latinLit:phi1294.phi002.perseus-lat2")
self.cts.getReffs("urn:cts:latinLit:phi1294.phi002.perseus-lat2")
patched_get.assert_called_once_with(
"http://domainname.com/rest/cts", params={
"request": "GetValidReff",
Expand All @@ -159,7 +159,7 @@ def test_get_children(self):
}
)
with patch('requests.get') as patched_get:
self.cts.getChildren("urn:cts:latinLit:phi1294.phi002.perseus-lat2", reference="1.1")
self.cts.getReffs("urn:cts:latinLit:phi1294.phi002.perseus-lat2", subreference="1.1")
patched_get.assert_called_once_with(
"http://domainname.com/rest/cts", params={
"request": "GetValidReff",
Expand All @@ -169,7 +169,7 @@ def test_get_children(self):
)

with patch('requests.get') as patched_get:
self.cts.getChildren("urn:cts:latinLit:phi1294.phi002.perseus-lat2", reference="1", depth=2)
self.cts.getReffs("urn:cts:latinLit:phi1294.phi002.perseus-lat2", subreference="1", level=2)
patched_get.assert_called_once_with(
"http://domainname.com/rest/cts", params={
"request": "GetValidReff",
Expand Down Expand Up @@ -199,15 +199,15 @@ def test_get_metadata(self):
def test_get_text(self):
""" Ensure Citable Text Service getText is correctly routed """
with patch('requests.get') as patched_get:
self.cts.getText(textId="urn", metadata=True)
self.cts.getTextualNode(textId="urn", metadata=True)
patched_get.assert_called_once_with(
"http://domainname.com/rest/cts", params={
"request": "GetPassagePlus",
"urn": "urn"
}
)
with patch('requests.get') as patched_get:
self.cts.getText(textId="urn", reference="1.1")
self.cts.getTextualNode(textId="urn", subreference="1.1")
patched_get.assert_called_once_with(
"http://domainname.com/rest/cts", params={
"request": "GetPassage",
Expand Down
6 changes: 3 additions & 3 deletions tests/retrievers/test_proto.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ def test_raise_CitableTextServicesProto(self):
with self.assertRaises(NotImplementedError):
Proto.getMetadata(textId="urn:cts:latinLit:phi1294.phi002.perseus-lat2")
with self.assertRaises(NotImplementedError):
Proto.getText(textId="urn:cts:latinLit:phi1294.phi002.perseus-lat2")
Proto.getTextualNode(textId="urn:cts:latinLit:phi1294.phi002.perseus-lat2")
with self.assertRaises(NotImplementedError):
Proto.getChildren(textId="urn:cts:latinLit:phi1294.phi002.perseus-lat2")
Proto.getReffs(textId="urn:cts:latinLit:phi1294.phi002.perseus-lat2")
with self.assertRaises(NotImplementedError):
Proto.getSiblings(textId="urn:cts:latinLit:phi1294.phi002.perseus-lat2", reference="1.1")
Proto.getSiblings(textId="urn:cts:latinLit:phi1294.phi002.perseus-lat2", subreference="1.1")

def test_raise_CTS_getCapabilities_arguments(self):
""" Tests that methods getCapabilities have consistent arguments"""
Expand Down

0 comments on commit 8e6a8c6

Please sign in to comment.