6
0

File.py 4.7 KB

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