doc.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. # -*- coding: utf-8
  2. """
  3. This module provides the Base Document class.
  4. """
  5. import uuid
  6. from . import base
  7. from . import dtypes
  8. from . import format as fmt
  9. from . import terminology
  10. from . import validation
  11. from .tools.doc_inherit import inherit_docstring, allow_inherit_docstring
  12. @allow_inherit_docstring
  13. class BaseDocument(base.Sectionable):
  14. """
  15. A representation of an odML document in memory.
  16. Its odml attributes are: *author*, *date*, *version* and *repository*.
  17. A Document behaves very much like a section, except that it cannot hold
  18. properties.
  19. """
  20. _format = fmt.Document
  21. def __init__(self, author=None, date=None, version=None, repository=None, oid=None):
  22. super(BaseDocument, self).__init__()
  23. try:
  24. if oid is not None:
  25. self._id = str(uuid.UUID(oid))
  26. else:
  27. self._id = str(uuid.uuid4())
  28. except ValueError as exc:
  29. print(exc)
  30. self._id = str(uuid.uuid4())
  31. self._author = author
  32. self._version = version
  33. self._repository = repository
  34. # Make sure date is properly parsed into a datetime object
  35. self._date = None
  36. self.date = date
  37. # Enable setting of the file name from whence this document came.
  38. # It is for knowing while processing and will not be serialized to a file.
  39. self._origin_file_name = None
  40. def __repr__(self):
  41. return "Document %s {author = %s, %d sections}" % \
  42. (self._version, self._author, len(self._sections))
  43. @property
  44. def oid(self):
  45. """
  46. The uuid for the document. Required for entity creation and comparison,
  47. saving and loading.
  48. """
  49. return self.id
  50. @property
  51. def id(self):
  52. """
  53. The uuid for the document.
  54. """
  55. return self._id
  56. def new_id(self, oid=None):
  57. """
  58. new_id sets the id of the current object to a RFC 4122 compliant UUID.
  59. If an id was provided, it is assigned if it is RFC 4122 UUID format compliant.
  60. If no id was provided, a new UUID is generated and assigned.
  61. :param oid: UUID string as specified in RFC 4122.
  62. """
  63. if oid is not None:
  64. self._id = str(uuid.UUID(oid))
  65. else:
  66. self._id = str(uuid.uuid4())
  67. @property
  68. def author(self):
  69. """
  70. The author of the document.
  71. """
  72. return self._author
  73. @author.setter
  74. def author(self, new_value):
  75. if new_value == "":
  76. new_value = None
  77. self._author = new_value
  78. @property
  79. def version(self):
  80. """
  81. A personal version-specifier that can be used to track different
  82. versions of the same document.
  83. """
  84. return self._version
  85. @version.setter
  86. def version(self, new_value):
  87. if new_value == "":
  88. new_value = None
  89. self._version = new_value
  90. @property
  91. def date(self):
  92. """
  93. The date the document was created.
  94. """
  95. return self._date
  96. @date.setter
  97. def date(self, new_value):
  98. if not new_value:
  99. new_value = None
  100. else:
  101. new_value = dtypes.date_set(new_value)
  102. self._date = new_value
  103. @property
  104. def parent(self):
  105. """ The parent of a document is always None. """
  106. return None
  107. @property
  108. def origin_file_name(self):
  109. """
  110. If available, the file name from where the document has been loaded.
  111. Will not be serialized to file when saving the document.
  112. """
  113. return self._origin_file_name
  114. @origin_file_name.setter
  115. def origin_file_name(self, new_value):
  116. if not new_value:
  117. new_value = None
  118. self._origin_file_name = new_value
  119. def finalize(self):
  120. """
  121. This needs to be called after the document is set up from parsing
  122. it will perform additional operations, that need the complete document.
  123. In particular, this method will resolve all *link* and *include*
  124. attributes accordingly.
  125. """
  126. # We could not fill out links while parsing (referenced sections where
  127. # not known), so try to set them now, where the document is complete
  128. for sec in self.itersections(recursive=True):
  129. if sec._link is not None:
  130. sec.link = sec._link
  131. if sec._include is not None:
  132. sec.include = sec._include
  133. def validate(self):
  134. """
  135. Runs a validation on itself and returns the Validation object.
  136. :return: odml.Validation
  137. """
  138. return validation.Validation(self)
  139. @inherit_docstring
  140. def get_terminology_equivalent(self):
  141. if self.repository is None:
  142. return None
  143. term = terminology.load(self.repository)
  144. return term
  145. def pprint(self, indent=2, max_depth=1, max_length=80, current_depth=0):
  146. """
  147. Pretty print method to visualize Document-Section trees.
  148. :param indent: number of leading spaces for every child Section or Property.
  149. :param max_depth: maximum number of hierarchical levels printed from the
  150. starting Section.
  151. :param max_length: maximum number of characters printed in one line.
  152. :param current_depth: number of hierarchical levels printed from the
  153. starting Section.
  154. """
  155. annotation = "{} [{}] {}".format(self.author, self.version, self.date)
  156. sec_num = "sections: {}".format(len(self._sections))
  157. repo = "repository: {}".format(self.repository)
  158. doc_str = "[{}, {}, {}]".format(annotation, sec_num, repo)
  159. print(doc_str)
  160. for sec in self._sections:
  161. sec.pprint(current_depth=current_depth+1, max_depth=max_depth,
  162. indent=indent, max_length=max_length)