virtool-workflow 7.0.0__tar.gz → 7.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/PKG-INFO +3 -5
  2. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/pyproject.toml +9 -3
  3. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/api/acquire.py +6 -2
  4. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/api/utils.py +8 -8
  5. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/data/indexes.py +12 -9
  6. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/data/samples.py +15 -7
  7. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/data/subtractions.py +13 -6
  8. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/decorators.py +7 -5
  9. virtool_workflow-7.1.1/virtool_workflow/errors.py +62 -0
  10. virtool_workflow-7.1.1/virtool_workflow/files.py +40 -0
  11. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/hooks.py +2 -3
  12. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/pytest_plugin/data.py +0 -1
  13. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/runtime/run_subprocess.py +3 -2
  14. virtool_workflow-7.0.0/virtool_workflow/errors.py +0 -61
  15. virtool_workflow-7.0.0/virtool_workflow/files.py +0 -24
  16. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/LICENSE +0 -0
  17. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/README.md +0 -0
  18. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/__init__.py +0 -0
  19. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/analysis/__init__.py +0 -0
  20. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/analysis/fastqc.py +0 -0
  21. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/analysis/skewer.py +0 -0
  22. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/analysis/trimming.py +0 -0
  23. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/analysis/utils.py +0 -0
  24. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/api/__init__.py +0 -0
  25. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/api/client.py +0 -0
  26. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/cli.py +0 -0
  27. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/data/__init__.py +0 -0
  28. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/data/analyses.py +0 -0
  29. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/data/hmms.py +0 -0
  30. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/data/jobs.py +0 -0
  31. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/data/ml.py +0 -0
  32. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/data/uploads.py +0 -0
  33. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/pytest_plugin/__init__.py +0 -0
  34. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/pytest_plugin/utils.py +0 -0
  35. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/runtime/__init__.py +0 -0
  36. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/runtime/config.py +0 -0
  37. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/runtime/discover.py +0 -0
  38. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/runtime/events.py +0 -0
  39. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/runtime/hook.py +0 -0
  40. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/runtime/path.py +0 -0
  41. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/runtime/ping.py +0 -0
  42. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/runtime/redis.py +0 -0
  43. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/runtime/run.py +0 -0
  44. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/runtime/sentry.py +0 -0
  45. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/utils.py +0 -0
  46. {virtool_workflow-7.0.0 → virtool_workflow-7.1.1}/virtool_workflow/workflow.py +0 -0
@@ -1,16 +1,14 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: virtool-workflow
3
- Version: 7.0.0
3
+ Version: 7.1.1
4
4
  Summary: A framework for developing bioinformatics workflows for Virtool.
5
5
  Home-page: https://github.com/virtool/virtool-workflow
6
6
  License: MIT
7
7
  Author: Ian Boyes
8
8
  Maintainer: Ian Boyes
9
- Requires-Python: >=3.10,<3.13
9
+ Requires-Python: >=3.12,<3.13
10
10
  Classifier: License :: OSI Approved :: MIT License
11
11
  Classifier: Programming Language :: Python :: 3
12
- Classifier: Programming Language :: Python :: 3.10
13
- Classifier: Programming Language :: Python :: 3.11
14
12
  Classifier: Programming Language :: Python :: 3.12
15
13
  Requires-Dist: aiofiles (>=0.7.0,<0.8.0)
16
14
  Requires-Dist: aiohttp (>=3.8.1,<4.0.0)
@@ -20,7 +18,7 @@ Requires-Dist: orjson (>=3.9.9,<4.0.0)
20
18
  Requires-Dist: pydantic-factories (>=1.17.3,<2.0.0)
21
19
  Requires-Dist: pyfixtures (>=1.0.0,<2.0.0)
22
20
  Requires-Dist: sentry-sdk (>=2.3.1,<3.0.0)
23
- Requires-Dist: virtool-core (>=12.0.0,<13.0.0)
21
+ Requires-Dist: virtool-core (>=14.0.0,<15.0.0)
24
22
  Project-URL: Repository, https://github.com/virtool/virtool-workflow
25
23
  Description-Content-Type: text/markdown
26
24
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "virtool-workflow"
3
- version = "7.0.0"
3
+ version = "7.1.1"
4
4
  description = "A framework for developing bioinformatics workflows for Virtool."
5
5
  authors = [
6
6
  "Ian Boyes",
@@ -29,7 +29,7 @@ packages = [
29
29
  ]
30
30
 
31
31
  [tool.poetry.dependencies]
32
- python = "^3.10,<3.13"
32
+ python = "~3.12"
33
33
  aiofiles = "^0.7.0"
34
34
  aiohttp = "^3.8.1"
35
35
  biopython = "^1.81"
@@ -38,7 +38,7 @@ orjson = "^3.9.9"
38
38
  pydantic-factories = "^1.17.3"
39
39
  pyfixtures = "^1.0.0"
40
40
  sentry-sdk = "^2.3.1"
41
- virtool-core = "^12.0.0"
41
+ virtool-core = "^14.0.0"
42
42
 
43
43
  [tool.poetry.scripts]
44
44
  run-workflow = "virtool_workflow.cli:cli_main"
@@ -71,8 +71,14 @@ exclude = [
71
71
  ".ruff_cache",
72
72
  "__pypackages__",
73
73
  ]
74
+ target-version = "py312"
74
75
 
75
76
  [tool.ruff.lint]
77
+ ignore = [
78
+ "ANN101",
79
+ "D203",
80
+ "D213"
81
+ ]
76
82
  select = ["ALL"]
77
83
 
78
84
  [build-system]
@@ -4,7 +4,11 @@ from aiohttp import ClientConnectionError, ClientSession, TCPConnector
4
4
  from structlog import get_logger
5
5
  from virtool_core.models.job import JobAcquired
6
6
 
7
- from virtool_workflow.errors import JobAlreadyAcquired, JobsAPIError, JobsAPIServerError
7
+ from virtool_workflow.errors import (
8
+ JobAlreadyAcquiredError,
9
+ JobsAPIError,
10
+ JobsAPIServerError,
11
+ )
8
12
 
9
13
  logger = get_logger("api")
10
14
 
@@ -39,7 +43,7 @@ async def acquire_job_by_id(
39
43
 
40
44
  if resp.status == 400:
41
45
  if "already acquired" in await resp.text():
42
- raise JobAlreadyAcquired(await resp.json())
46
+ raise JobAlreadyAcquiredError(await resp.json())
43
47
 
44
48
  logger.critical(
45
49
  "unexpected api error during job acquisition",
@@ -10,10 +10,10 @@ from aiohttp import (
10
10
  from structlog import get_logger
11
11
 
12
12
  from virtool_workflow.errors import (
13
- JobsAPIBadRequest,
14
- JobsAPIConflict,
15
- JobsAPIForbidden,
16
- JobsAPINotFound,
13
+ JobsAPIBadRequestError,
14
+ JobsAPIConflictError,
15
+ JobsAPIForbiddenError,
16
+ JobsAPINotFoundError,
17
17
  JobsAPIServerError,
18
18
  )
19
19
 
@@ -80,10 +80,10 @@ async def raise_exception_by_status_code(resp: ClientResponse):
80
80
  :raise JobsAPIServerError: the response status code is 500
81
81
  """
82
82
  status_exception_map = {
83
- 400: JobsAPIBadRequest,
84
- 403: JobsAPIForbidden,
85
- 404: JobsAPINotFound,
86
- 409: JobsAPIConflict,
83
+ 400: JobsAPIBadRequestError,
84
+ 403: JobsAPIForbiddenError,
85
+ 404: JobsAPINotFoundError,
86
+ 409: JobsAPIConflictError,
87
87
  500: JobsAPIServerError,
88
88
  }
89
89
 
@@ -13,7 +13,7 @@ from virtool_core.models.reference import ReferenceNested
13
13
  from virtool_core.utils import decompress_file
14
14
 
15
15
  from virtool_workflow.api.client import APIClient
16
- from virtool_workflow.errors import MissingJobArgument
16
+ from virtool_workflow.errors import MissingJobArgumentError
17
17
  from virtool_workflow.files import VirtoolFileFormat
18
18
 
19
19
  logger = get_logger("api")
@@ -43,9 +43,7 @@ class WFIndex:
43
43
 
44
44
  @property
45
45
  def bowtie_path(self) -> Path:
46
- """The path to the Bowtie2 index prefix for the Virtool index.
47
-
48
- """
46
+ """The path to the Bowtie2 index prefix for the Virtool index."""
49
47
  return self.path / "reference"
50
48
 
51
49
  @property
@@ -151,7 +149,10 @@ class WFNewIndex:
151
149
  await self._api.patch_json(f"/indexes/{self.id}", {})
152
150
 
153
151
  async def upload(
154
- self, path: Path, fmt: VirtoolFileFormat = "fasta", name: str | None = None,
152
+ self,
153
+ path: Path,
154
+ fmt: VirtoolFileFormat = "fasta",
155
+ name: str | None = None,
155
156
  ):
156
157
  """Upload a file to associate with the index being built.
157
158
 
@@ -272,14 +273,16 @@ async def index(
272
273
 
273
274
  @fixture
274
275
  async def new_index(
275
- _api: APIClient, job: Job, proc: int, work_path: Path,
276
+ _api: APIClient,
277
+ job: Job,
278
+ proc: int,
279
+ work_path: Path,
276
280
  ) -> WFNewIndex:
277
- """The :class:`.WFNewIndex` for an index being created by the current job.
278
- """
281
+ """The :class:`.WFNewIndex` for an index being created by the current job."""
279
282
  try:
280
283
  id_ = job.args["index_id"]
281
284
  except KeyError:
282
- raise MissingJobArgument("Missing jobs args key 'index_id'")
285
+ raise MissingJobArgumentError("Missing jobs args key 'index_id'")
283
286
 
284
287
  log = logger.bind(resource="new_index", id=id_, job_id=job.id)
285
288
  log.info("loading index")
@@ -12,7 +12,7 @@ from virtool_core.models.samples import Quality, Sample
12
12
  from virtool_workflow.analysis.utils import ReadPaths
13
13
  from virtool_workflow.api.client import APIClient
14
14
  from virtool_workflow.data.uploads import WFUploads
15
- from virtool_workflow.errors import JobsAPINotFound
15
+ from virtool_workflow.errors import JobsAPINotFoundError
16
16
  from virtool_workflow.files import VirtoolFileFormat
17
17
 
18
18
  logger = get_logger("api")
@@ -83,7 +83,10 @@ class WFNewSample:
83
83
 
84
84
  @fixture
85
85
  async def sample(
86
- _api: APIClient, job: Job, uploads: WFUploads, work_path: Path,
86
+ _api: APIClient,
87
+ job: Job,
88
+ uploads: WFUploads,
89
+ work_path: Path,
87
90
  ) -> WFSample:
88
91
  """The sample associated with the current job."""
89
92
  id_ = job.args["sample_id"]
@@ -92,8 +95,8 @@ async def sample(
92
95
 
93
96
  try:
94
97
  sample_json = await _api.get_json(base_url_path)
95
- except JobsAPINotFound:
96
- raise JobsAPINotFound("Sample not found")
98
+ except JobsAPINotFoundError:
99
+ raise JobsAPINotFoundError("Sample not found")
97
100
 
98
101
  sample = Sample(**sample_json)
99
102
 
@@ -101,7 +104,8 @@ async def sample(
101
104
  await asyncio.to_thread(reads_path.mkdir, exist_ok=True, parents=True)
102
105
 
103
106
  await _api.get_file(
104
- f"{base_url_path}/reads/reads_1.fq.gz", reads_path / "reads_1.fq.gz",
107
+ f"{base_url_path}/reads/reads_1.fq.gz",
108
+ reads_path / "reads_1.fq.gz",
105
109
  )
106
110
 
107
111
  if sample.paired:
@@ -110,7 +114,8 @@ async def sample(
110
114
  reads_path / "reads_2.fq.gz",
111
115
  )
112
116
  await _api.get_file(
113
- f"{base_url_path}/reads/reads_2.fq.gz", reads_path / "reads_2.fq.gz",
117
+ f"{base_url_path}/reads/reads_2.fq.gz",
118
+ reads_path / "reads_2.fq.gz",
114
119
  )
115
120
  else:
116
121
  read_paths = (reads_path / "reads_1.fq.gz",)
@@ -127,7 +132,10 @@ async def sample(
127
132
 
128
133
  @fixture
129
134
  async def new_sample(
130
- _api: APIClient, job: Job, uploads: WFUploads, work_path: Path,
135
+ _api: APIClient,
136
+ job: Job,
137
+ uploads: WFUploads,
138
+ work_path: Path,
131
139
  ) -> WFNewSample:
132
140
  """The sample associated with the current job."""
133
141
  id_ = job.args["sample_id"]
@@ -15,7 +15,7 @@ from virtool_core.models.subtraction import (
15
15
  from virtool_workflow.api.client import APIClient
16
16
  from virtool_workflow.data.analyses import WFAnalysis
17
17
  from virtool_workflow.data.uploads import WFUploads
18
- from virtool_workflow.errors import MissingJobArgument
18
+ from virtool_workflow.errors import MissingJobArgumentError
19
19
 
20
20
  logger = get_logger("api")
21
21
 
@@ -118,7 +118,9 @@ class WFNewSubtraction:
118
118
 
119
119
  @fixture
120
120
  async def subtractions(
121
- _api: APIClient, analysis: WFAnalysis, work_path: Path,
121
+ _api: APIClient,
122
+ analysis: WFAnalysis,
123
+ work_path: Path,
122
124
  ) -> list[WFSubtraction]:
123
125
  """The subtractions to be used for the current analysis job."""
124
126
  subtraction_work_path = work_path / "subtractions"
@@ -158,7 +160,10 @@ async def subtractions(
158
160
 
159
161
  @fixture
160
162
  async def new_subtraction(
161
- _api: APIClient, job: Job, uploads: WFUploads, work_path: Path,
163
+ _api: APIClient,
164
+ job: Job,
165
+ uploads: WFUploads,
166
+ work_path: Path,
162
167
  ) -> WFNewSubtraction:
163
168
  """A new subtraction that will be created during the current job.
164
169
 
@@ -167,12 +172,12 @@ async def new_subtraction(
167
172
  try:
168
173
  id_ = job.args["subtraction_id"]
169
174
  except KeyError:
170
- raise MissingJobArgument("subtraction_id")
175
+ raise MissingJobArgumentError("subtraction_id")
171
176
 
172
177
  try:
173
178
  upload_id = job.args["files"][0]["id"]
174
179
  except KeyError:
175
- raise MissingJobArgument("files")
180
+ raise MissingJobArgumentError("files")
176
181
 
177
182
  subtraction_json = await _api.get_json(f"/subtractions/{id_}")
178
183
  subtraction_ = Subtraction(**subtraction_json)
@@ -221,7 +226,9 @@ async def new_subtraction(
221
226
  log.info("Uploading subtraction file")
222
227
 
223
228
  await _api.put_file(
224
- f"/subtractions/{subtraction_.id}/files/{filename}", path, "unknown",
229
+ f"/subtractions/{subtraction_.id}/files/{filename}",
230
+ path,
231
+ "unknown",
225
232
  )
226
233
 
227
234
  log.info("Finished uploading subtraction file")
@@ -1,11 +1,13 @@
1
1
  """Create Workflows by decorating module scope functions."""
2
+
3
+ from collections.abc import Callable
2
4
  from types import ModuleType
3
- from typing import Callable
4
5
 
6
+ from virtool_workflow.errors import WorkflowStepsError
5
7
  from virtool_workflow.workflow import Workflow
6
8
 
7
9
 
8
- def step(func: Callable = None, *, name: str | None = None) -> Callable:
10
+ def step(func: Callable | None = None, *, name: str | None = None) -> Callable:
9
11
  """Mark a function as a workflow step function.
10
12
 
11
13
  :param func: the workflow step function
@@ -16,7 +18,7 @@ def step(func: Callable = None, *, name: str | None = None) -> Callable:
16
18
  return lambda _f: step(_f, name=name)
17
19
 
18
20
  func.__workflow_marker__ = "step"
19
- func.__workflow_step_props__ = dict(name=name)
21
+ func.__workflow_step_props__ = {"name": name}
20
22
 
21
23
  return func
22
24
 
@@ -39,7 +41,7 @@ def collect(module: ModuleType) -> Workflow:
39
41
  if marked.__workflow_marker__ == "step":
40
42
  workflow.step(marked, **marked.__workflow_step_props__)
41
43
 
42
- if len(workflow.steps) == 0:
43
- raise ValueError(f"No workflow steps could be found in {module}")
44
+ if not workflow.steps:
45
+ raise WorkflowStepsError(str(module))
44
46
 
45
47
  return workflow
@@ -0,0 +1,62 @@
1
+ """Custom exceptions for ``virtool_workflow``."""
2
+
3
+ from subprocess import SubprocessError
4
+
5
+
6
+ class JobAlreadyAcquiredError(Exception):
7
+ """Raised when an attempt is made to reacquire a job."""
8
+
9
+ def __init__(self, job_id: str) -> None:
10
+ """Initialize the exception with a message containing the job ID."""
11
+ super().__init__(
12
+ f"Job {job_id} is has already been acquired.",
13
+ )
14
+
15
+
16
+ class JobsAPIError(Exception):
17
+ """A base exception for errors due to HTTP errors from the jobs API."""
18
+
19
+
20
+ class JobsAPIBadRequestError(JobsAPIError):
21
+ """A ``400 Bad Request`` response was received from the jobs API."""
22
+
23
+ status = 400
24
+
25
+
26
+ class JobsAPIForbiddenError(JobsAPIError):
27
+ """A ``403 Forbidden`` response was received from the jobs API."""
28
+
29
+ status = 403
30
+
31
+
32
+ class JobsAPINotFoundError(JobsAPIError):
33
+ """A ``404 Not Found`` response was received from the jobs API."""
34
+
35
+ status = 404
36
+
37
+
38
+ class JobsAPIConflictError(JobsAPIError):
39
+ """A ``409 Conflict`` response was received from the jobs API."""
40
+
41
+ status = 409
42
+
43
+
44
+ class JobsAPIServerError(JobsAPIError):
45
+ """A ``500 Internal Server Error`` response was received from the jobs API."""
46
+
47
+ status = 500
48
+
49
+
50
+ class MissingJobArgumentError(ValueError):
51
+ """The `job.args` dict is missing a required key for some funcionality."""
52
+
53
+
54
+ class WorkflowStepsError(Exception):
55
+ """Raised when no workflow steps are found in a module."""
56
+
57
+ def __init__(self, module: str) -> None:
58
+ super().__init__(f"No workflow steps could be found in {module}")
59
+
60
+
61
+ class SubprocessFailedError(SubprocessError):
62
+ """Subprocess exited with non-zero status during a workflow."""
@@ -0,0 +1,40 @@
1
+ """Dataclasses for describing files uploaded to the Virtool server."""
2
+
3
+ import datetime
4
+ from dataclasses import dataclass
5
+ from typing import Literal
6
+
7
+ VirtoolFileFormat = Literal[
8
+ "sam",
9
+ "bam",
10
+ "fasta",
11
+ "fastq",
12
+ "csv",
13
+ "tsv",
14
+ "json",
15
+ "unknown",
16
+ ]
17
+ """A literal type hint for the format of a :class:`.VirtoolFile`."""
18
+
19
+
20
+ @dataclass
21
+ class VirtoolFile:
22
+ """A description of a file uploaded to the Virtool server."""
23
+
24
+ id: int
25
+ """The unique ID for the file."""
26
+
27
+ name: str
28
+ """The name of the file."""
29
+
30
+ size: int
31
+ """The size of the file in bytes."""
32
+
33
+ format: VirtoolFileFormat
34
+ """The format of the file."""
35
+
36
+ name_on_disk: str | None = None
37
+ """The actual name of the file on disk."""
38
+
39
+ uploaded_at: datetime.datetime | None = None
40
+ """When the file was uploaded."""
@@ -1,5 +1,4 @@
1
- """Hooks provide a way to do things when events happen during the workflow lifecycle.
2
- """
1
+ """Hooks do things when events happen during the workflow lifecycle."""
3
2
 
4
3
  from virtool_workflow.runtime.hook import Hook
5
4
 
@@ -124,7 +123,7 @@ __all__ = [
124
123
  ]
125
124
 
126
125
 
127
- def cleanup_builtin_status_hooks():
126
+ def cleanup_builtin_status_hooks() -> None:
128
127
  """Clear callbacks for built-in status hooks.
129
128
 
130
129
  This prevents carryover of hooks between tests. Carryover won't be encountered in
@@ -116,7 +116,6 @@ def data(
116
116
  "test": True,
117
117
  }
118
118
  job.ping = JobPing(pinged_at=static_datetime)
119
- job.rights = {}
120
119
 
121
120
  """A finalized sample to be used for testing analyses."""
122
121
  sample = SampleFactory.build()
@@ -1,4 +1,5 @@
1
1
  """Code for running and managing subprocesses."""
2
+
2
3
  import asyncio
3
4
  from asyncio.subprocess import Process
4
5
  from pathlib import Path
@@ -8,7 +9,7 @@ from pyfixtures import fixture
8
9
  from structlog import get_logger
9
10
  from virtool_core.utils import timestamp
10
11
 
11
- from virtool_workflow.errors import SubprocessFailed
12
+ from virtool_workflow.errors import SubprocessFailedError
12
13
 
13
14
  logger = get_logger("subprocess")
14
15
 
@@ -146,7 +147,7 @@ async def _run_subprocess(
146
147
  # Exit code 15 indicates that the process was terminated. This is expected
147
148
  # when the workflow fails for some other reason, hence not an exception
148
149
  if process.returncode not in [0, 15, -15]:
149
- raise SubprocessFailed(
150
+ raise SubprocessFailedError(
150
151
  f"{command[0]} failed with exit code {process.returncode}\n"
151
152
  f"arguments: {command}\n",
152
153
  )
@@ -1,61 +0,0 @@
1
- from subprocess import SubprocessError
2
-
3
-
4
- class IllegalJobArguments(ValueError):
5
- """The `job.args` dict is in an illegal state."""
6
-
7
-
8
-
9
- class InsufficientJobRights(Exception):
10
- ...
11
-
12
-
13
- class JobAlreadyAcquired(Exception):
14
- def __init__(self, job_id: str):
15
- super(JobAlreadyAcquired, self).__init__(
16
- f"Job {job_id} is has already been acquired.",
17
- )
18
-
19
-
20
- class JobAlreadyFinalized(Exception):
21
- ...
22
-
23
-
24
- class JobsAPIError(Exception):
25
- """A base exception for errors due to HTTP errors from the jobs API."""
26
-
27
-
28
-
29
- class JobsAPIBadRequest(JobsAPIError):
30
- """A ``400 Bad Request`` response from the jobs API."""
31
-
32
- status = 400
33
-
34
-
35
- class JobsAPIForbidden(JobsAPIError):
36
- status = 403
37
-
38
-
39
- class JobsAPINotFound(JobsAPIError):
40
- status = 404
41
-
42
-
43
- class JobsAPIConflict(JobsAPIError):
44
- status = 409
45
-
46
-
47
- class JobsAPIServerError(JobsAPIError):
48
- status = 500
49
-
50
-
51
- class MissingJobArgument(ValueError):
52
- """The `job.args` dict is missing a required key for some funcionality."""
53
-
54
-
55
-
56
- class NotFound(KeyError):
57
- ...
58
-
59
-
60
- class SubprocessFailed(SubprocessError):
61
- """Subprocess exited with non-zero status during a workflow."""
@@ -1,24 +0,0 @@
1
- from dataclasses import dataclass
2
- from datetime import datetime
3
- from typing import Literal
4
-
5
- VirtoolFileFormat = Literal[
6
- "sam",
7
- "bam",
8
- "fasta",
9
- "fastq",
10
- "csv",
11
- "tsv",
12
- "json",
13
- "unknown",
14
- ]
15
-
16
-
17
- @dataclass
18
- class VirtoolFile:
19
- id: int
20
- name: str
21
- size: int
22
- format: VirtoolFileFormat
23
- name_on_disk: str = None
24
- uploaded_at: datetime = None