6
0

File.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. from __future__ import annotations
  2. import typing as T
  3. from datetime import datetime
  4. from pathlib import Path
  5. from pycs import db
  6. from pycs.database.Collection import Collection
  7. from pycs.database.Result import Result
  8. from pycs.database.base import NamedBaseModel
  9. from pycs.database.util import commit_on_return
  10. class File(NamedBaseModel):
  11. """
  12. database class for files
  13. """
  14. # table columns
  15. uuid = db.Column(db.String, nullable=False)
  16. extension = db.Column(db.String, nullable=False)
  17. type = db.Column(db.String, nullable=False)
  18. size = db.Column(db.String, nullable=False)
  19. created = db.Column(db.DateTime, default=datetime.utcnow,
  20. index=True, nullable=False)
  21. path = db.Column(db.String, nullable=False)
  22. frames = db.Column(db.Integer)
  23. fps = db.Column(db.Float)
  24. project_id = db.Column(
  25. db.Integer,
  26. db.ForeignKey("project.id", ondelete="CASCADE"),
  27. nullable=False)
  28. collection_id = db.Column(
  29. db.Integer,
  30. db.ForeignKey("collection.id", ondelete="SET NULL"))
  31. # contraints
  32. __table_args__ = (
  33. db.UniqueConstraint('project_id', 'path'),
  34. )
  35. results = db.relationship("Result", backref="file",
  36. lazy="dynamic", passive_deletes=True)
  37. serialize_only = NamedBaseModel.serialize_only + (
  38. "uuid",
  39. "extension",
  40. "type",
  41. "size",
  42. "created",
  43. "path",
  44. "frames",
  45. "fps",
  46. "project_id",
  47. "collection_id",
  48. )
  49. @property
  50. def filename(self):
  51. return f"{self.name}{self.extension}"
  52. @property
  53. def absolute_path(self) -> str:
  54. path = Path(self.path)
  55. if path.is_absolute():
  56. return str(path)
  57. return str(Path.cwd() / path)
  58. @commit_on_return
  59. def set_collection(self, collection_id: T.Optional[int]):
  60. """
  61. set this file's collection
  62. :param collection_id: new collection id
  63. :return:
  64. """
  65. self.collection_id = collection_id
  66. @commit_on_return
  67. def set_collection_by_reference(self, collection_reference: T.Optional[str]):
  68. """
  69. set this file's collection
  70. :param collection_reference: collection reference
  71. :return:
  72. """
  73. if self.collection_reference is None:
  74. self.set_collection(None)
  75. collection = Collection.query.filter_by(reference=collection_reference).one()
  76. self.collection_id = collection.id
  77. def _get_another_file(self, *query) -> T.Optional[File]:
  78. """
  79. get the first file matching the query ordered by descending id
  80. :return: another file or None
  81. """
  82. return File.query.filter(File.project_id == self.project_id, *query)
  83. def next(self) -> T.Optional[File]:
  84. """
  85. get the successor of this file
  86. :return: another file or None
  87. """
  88. return self._get_another_file(File.id > self.id)\
  89. .order_by(File.id).first()
  90. def previous(self) -> T.Optional[File]:
  91. """
  92. get the predecessor of this file
  93. :return: another file or None
  94. """
  95. return self._get_another_file(File.id < self.id)\
  96. .order_by(File.id.desc()).first()
  97. def next_in_collection(self) -> T.Optional[File]:
  98. """
  99. get the predecessor of this file
  100. :return: another file or None
  101. """
  102. return self._get_another_file(
  103. File.id > self.id, File.collection_id == self.collection_id)\
  104. .order_by(File.id).first()
  105. def previous_in_collection(self) -> T.Optional[File]:
  106. """
  107. get the predecessor of this file
  108. :return: another file or None
  109. """
  110. return self._get_another_file(
  111. File.id < self.id, File.collection_id == self.collection_id)\
  112. .order_by(File.id.desc()).first()
  113. def result(self, id: int) -> T.Optional[Result]:
  114. return self.results.get(id)
  115. @commit_on_return
  116. def create_result(self,
  117. origin: str,
  118. result_type: str,
  119. label: T.Optional[T.Union[Label, int]] = None,
  120. data: T.Optional[dict] = None) -> Result:
  121. result = Result.new(commit=False,
  122. file_id=self.id,
  123. origin=origin,
  124. type=result_type)
  125. result.data = data
  126. if label is not None:
  127. assert isinstance(label, (int, Label)), f"Wrong label type: {type(label)}"
  128. if isinstance(label, Label):
  129. label = label.id
  130. result.label_id = label
  131. return result
  132. def remove_results(self, origin='pipeline') -> T.List[Result]:
  133. results = Result.query.filter(
  134. Result.file_id == self.id,
  135. Result.origin == origin)
  136. _results = results.all()
  137. results.delete()
  138. return _results