6
0

File.py 4.8 KB

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