Skip to content

Commit

Permalink
Local resolver + SubReference return only on ID operation on URN nodes
Browse files Browse the repository at this point in the history
- Added same test than for remote resolver to local cts resolver
- GetReffs and affiliated now returns only the subreference
  • Loading branch information
PonteIneptique committed Dec 13, 2016
1 parent a0773c7 commit 8418e53
Show file tree
Hide file tree
Showing 55 changed files with 412,180 additions and 116 deletions.
7 changes: 6 additions & 1 deletion MyCapytain/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,9 @@ class InvalidURN(Exception):

class MissingAttribute(Exception):
""" This error is thrown when an attribute is not present in the Object (missing at startup)
"""
"""


class UnknownObjectError(ValueError):
""" This error is thrown when an object does not exist in an inventory or in an API
"""
10 changes: 4 additions & 6 deletions MyCapytain/resolvers/cts/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,10 @@ def getSiblings(self, textId, subreference):
:param textId: Text Identifier
:type textId: str
:param level: Depth for retrieval
:type level: int
:param subreference: Passage Reference
:type subreference: str
:return: List of references
:rtype: [str]
:return: Tuple of references
:rtype: (str, str)
"""
text = Text(
urn=textId,
Expand Down Expand Up @@ -99,8 +97,8 @@ def getReffs(self, textId, level=1, subreference=None):
def getMetadata(self, objectId=None, **filters):
""" Request metadata about a text or a collection
:param textId: Object Identifier to filter on
:type textId: str
:param objectId: Object Identifier to filter on
:type objectId: str
:param filters: Kwargs parameters.
:type filters: dict
:return: Collection
Expand Down
117 changes: 106 additions & 11 deletions MyCapytain/resolvers/cts/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@
import io

from MyCapytain.common.utils import xmlparser
from MyCapytain.resources.collections.cts import TextInventory, TextGroup, Work, Citation
from MyCapytain.resources.collections.cts import TextInventory, TextGroup, Work, Citation, Text as InventoryText
from MyCapytain.resources.texts.locals.tei import Text
from MyCapytain.resolvers.prototypes import Resolver
from MyCapytain.errors import InvalidURN
from MyCapytain.common.reference import URN
from MyCapytain.common.reference import URN, Reference
from glob import glob
import os.path
from math import ceil
import logging
from copy import copy
from collections import OrderedDict


class CTSCapitainsLocalResolver(Resolver):
Expand All @@ -34,7 +36,7 @@ class CTSCapitainsLocalResolver(Resolver):
"""
TEXT_CLASS = Text
DEFAULT_PAGE = 1
PER_PAGE = (1, 10, 100) # Min, Default, Mainvex,
PER_PAGE = (1, 10, 100) # Min, Default, Mainvex,

@property
def inventory(self):
Expand Down Expand Up @@ -152,20 +154,21 @@ def __getText__(self, urn):
:param urn: URN of a text to retrieve
:type urn: str, URN
:return: Textual resource and metadata
:rtype: (text.Text, inventory.Text)
:rtype: (Text, InventoryText)
"""
if not isinstance(urn, URN):
urn = URN(urn)
if len(urn) != 5:
raise InvalidURN

text = self.inventory[str(urn)]

with io.open(text.path) as __xml__:
resource = self.TEXT_CLASS(urn=urn, resource=self.xmlparse(__xml__))

return resource, text

def __getCapabilities__(self,
def __getTextMetadata__(self,
urn=None, page=None, limit=None,
lang=None, category=None, pagination=False
):
Expand All @@ -189,16 +192,23 @@ def __getCapabilities__(self,
"""
__PART = None
if urn is not None:
_urn = URN(urn)
if isinstance(urn, URN):
_urn = urn
else:
_urn = URN(urn)
__PART = [None, None, URN.NAMESPACE, URN.TEXTGROUP, URN.WORK, URN.VERSION, URN.COMPLETE][len(_urn)]

matches = [
text
for text in self.__texts__
if (lang is None or (lang is not None and lang == text.lang)) and
if
(lang is None or (lang is not None and lang == text.lang)) and
(urn is None or (urn is not None and text.urn.upTo(__PART) == urn)) and
(text.citation is not None) and
(category not in ["edition", "translation"] or (category in ["edition", "translation"] and category.lower() == text.subtype.lower()))
(
category not in ["edition", "translation"] or
(category in ["edition", "translation"] and category.lower() == text.subtype.lower())
)
]
if pagination:
start_index, end_index, page, count = type(self).pagination(page, limit, len(matches))
Expand Down Expand Up @@ -236,8 +246,93 @@ def pagination(page, limit, length):
return page, count + 1, realpage, count - page + 1

def getMetadata(self, objectId=None, **filters):
return self.__getCapabilities__(urn=objectId)[0]
""" Request metadata about a text or a collection
def getPassage(self, textId, subreference=None, prevnext=False, metadata=False):
return self.__getText__(textId).getPassage(Reference(subreference))
:param objectId: Object Identifier to filter on
:type objectId: str
:param filters: Kwargs parameters.
:type filters: dict
:return: Collection
"""
if objectId is None:
return self.inventory
texts, _, _ = self.__getTextMetadata__(urn=objectId)
inventory = TextInventory()
# For each text we found using the filter
for text in texts:
tg_urn = str(text.parents[1].urn)
wk_urn = str(text.parents[0].urn)
txt_urn = str(text.urn)
# If we need to generate a textgroup object
if tg_urn not in inventory.textgroups:
inventory.textgroups[tg_urn] = copy(text.parents[1])
inventory.textgroups[tg_urn].works = OrderedDict()
# If we need to generate a work object
if wk_urn not in inventory.textgroups[tg_urn].works:
inventory.textgroups[tg_urn].works[wk_urn] = copy(text.parents[0])
inventory.textgroups[tg_urn].works[wk_urn].parents = tuple(
[inventory, inventory.textgroups[tg_urn]]
)
inventory.textgroups[tg_urn].works[wk_urn].texts = OrderedDict()
__text = copy(text)
inventory.textgroups[tg_urn].works[wk_urn].texts[txt_urn] = __text
__text.parents = tuple([
inventory,
inventory.textgroups[tg_urn],
inventory.textgroups[tg_urn].works[wk_urn]
])
return inventory[objectId]

def getPassage(self, textId, subreference=None, prevnext=False, metadata=False):
""" Retrieve a text node from the API
:param textId: Text Identifier
:type textId: str
:param subreference: Passage Reference
:type subreference: str
:param prevnext: Retrieve graph representing previous and next passage
:type prevnext: boolean
:param metadata: Retrieve metadata about the passage and the text
:type metadata: boolean
:return: Passage
:rtype: Passage
"""
text, inventory = self.__getText__(textId)
if subreference is not None:
subreference = Reference(subreference)
passage = text.getPassage(subreference)
if metadata:
for descendant in [inventory] + inventory.parents:
passage.about.metadata += descendant.metadata
return passage

def getSiblings(self, textId, subreference):
""" Retrieve the siblings of a textual node
:param textId: Text Identifier
:type textId: str
:param subreference: Passage Reference
:type subreference: str
:return: Tuple of references
:rtype: (str, str)
"""
text, inventory = self.__getText__(textId)
passage = text.getPassage(Reference(subreference))
return passage.siblingsId

def getReffs(self, textId, level=1, subreference=None):
""" Retrieve the siblings of a textual node
:param textId: Text Identifier
:type textId: str
:param level: Depth for retrieval
:type level: int
:param subreference: Passage Reference
:type subreference: str
:return: List of references
:rtype: [str]
"""
passage, inventory = self.__getText__(textId)
if subreference:
passage = passage.getPassage(subreference)
return passage.getReffs(level=level, subreference=subreference)
4 changes: 2 additions & 2 deletions MyCapytain/resolvers/prototypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ class Resolver(object):
def getMetadata(self, objectId=None, **filters):
""" Request metadata about a text or a collection
:param textId: Object Identifier to filter on
:type textId: str
:param objectId: Object Identifier to filter on
:type objectId: str
:param filters: Kwargs parameters.
:type filters: dict
:return: Collection
Expand Down
12 changes: 6 additions & 6 deletions MyCapytain/resources/texts/api/cts.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def getValidReff(self, level=1, reference=None):
xml = xmlparser(xml)
self.__parse_request__(xml.xpath("//ti:request", namespaces=NS)[0])

return [ref for ref in xml.xpath("//ti:reply//ti:urn/text()", namespaces=NS)]
return [ref.split(":")[-1] for ref in xml.xpath("//ti:reply//ti:urn/text()", namespaces=NS)]

def getPassage(self, reference=None):
""" Retrieve a passage and store it in the object
Expand All @@ -104,7 +104,7 @@ def getPassage(self, reference=None):
if ":" in reference:
urn = reference
else:
urn = "{0}:{1}".format(self.urn, reference)
urn = "{0}:{1}".format(self.urn.upTo(URN.NO_PASSAGE), reference)
elif isinstance(reference, list):
urn = "{0}:{1}".format(self.urn, ".".join(reference))
else:
Expand All @@ -126,7 +126,7 @@ def getReffs(self, level=1, subreference=None):
:returns: List of levels
"""
if self.depth is not None:
level = level + self.depth
level += self.depth

return self.getValidReff(level, subreference)

Expand Down Expand Up @@ -275,7 +275,7 @@ def firstUrn(resource):

if len(urn) > 0:
urn = str(urn[0])
return urn
return urn.split(":")[-1]

@staticmethod
def prevnext(resource):
Expand All @@ -297,10 +297,10 @@ def prevnext(resource):
_prev_xpath = prevnext.xpath("ti:prev/ti:urn/text()", namespaces=NS, smart_strings=False)

if len(_next_xpath):
_next = _next_xpath[0]
_next = _next_xpath[0].split(":")[-1]

if len(_prev_xpath):
_prev = _prev_xpath[0]
_prev = _prev_xpath[0].split(":")[-1]

return _prev, _next

Expand Down
49 changes: 23 additions & 26 deletions MyCapytain/resources/texts/locals/tei.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ def getPassage(self, reference=None, simple=False):
if reference is None:
return self._getSimplePassage()

if isinstance(reference, str):
reference = Reference(reference)
if isinstance(reference, list):
start, end = reference, reference
reference = Reference(".".join(reference))
Expand Down Expand Up @@ -105,7 +107,10 @@ def _getSimplePassage(self, reference=None):
:rtype: Passage
"""
if reference is None:
return __SimplePassage__(self.resource, reference=None, urn=self.urn, citation=self.citation)
return __SimplePassage__(
self.resource, reference=None, urn=self.urn, citation=self.citation,
text=self
)

resource = self.resource.xpath(
self.citation[len(reference)-1].fill(reference),
Expand Down Expand Up @@ -137,23 +142,24 @@ def textObject(self):
text = self.__text__
return text

def getReffs(self, level=1, reference=None):
def getReffs(self, level=1, subreference=None):
""" Reference available at a given level
:param level: Depth required. If not set, should retrieve first encountered level (1 based)
:type level: Int
:param passage: Subreference (optional)
:type passage: Reference
:param subreference: Subreference (optional)
:type subreference: str
:rtype: List.basestring
:returns: List of levels
"""
if hasattr(self, "__depth__"):
level = level + self.depth
if not reference:
if not subreference:
if hasattr(self, "reference"):
reference = self.reference

return self.getValidReff(level, reference)
subreference = self.reference
else:
subreference = Reference(subreference)
return self.getValidReff(level, subreference)

def getValidReff(self, level=None, reference=None, _debug=False):
""" Retrieve valid passages directly
Expand Down Expand Up @@ -285,7 +291,7 @@ def __init__(self, resource, reference, citation, urn=None, text=None):
self.__text__ = text
self.__reference__ = reference
self.__children__ = None
self.__depth__ = None
self.__depth__ = 0
if reference is not None:
self.__depth__ = len(reference)
self.__prevnext__ = None
Expand Down Expand Up @@ -589,36 +595,28 @@ def siblingsId(self):
_prev = None
elif start - range_length < 0:
if start == end:
_prev = Reference(document_references[0])
_prev = document_references[0]
else:
_prev = Reference(
"{}-{}".format(document_references[0], document_references[start-1])
)
_prev = "{}-{}".format(document_references[0], document_references[start-1])
else:
if start == end:
_prev = Reference(document_references[start-1])
_prev = document_references[start-1]
else:
_prev = Reference(
"{}-{}".format(document_references[start-range_length], document_references[start-1])
)
_prev = "{}-{}".format(document_references[start-range_length], document_references[start-1])

if start + 1 == len(document_references) or end + 1 == len(document_references):
# If the passage is already at the end
_next = None
elif end + range_length > len(document_references):
if start == end:
_next = Reference(document_references[-1])
_next = document_references[-1]
else:
_next = Reference(
"{}-{}".format(document_references[end+1], document_references[-1])
)
_next = "{}-{}".format(document_references[end+1], document_references[-1])
else:
if start == end:
_next = Reference(document_references[end+1])
_next = document_references[end+1]
else:
_next = Reference(
"{}-{}".format(document_references[end+1], document_references[end + range_length])
)
_next = "{}-{}".format(document_references[end+1], document_references[end + range_length])

self.__prevnext__ = (_prev, _next)
return self.__prevnext__
Expand All @@ -634,7 +632,6 @@ def prev(self):
return __SharedMethods__.getPassage(self.__text__, self.prevId)

def getPassage(self, reference, simple=False):
__doc__ = __SharedMethods__.__doc__
if not isinstance(reference, Reference):
reference = Reference(reference)
X = __SharedMethods__.getPassage(self, reference, simple)
Expand Down

0 comments on commit 8418e53

Please sign in to comment.