labtasker-client 2.0.0__tar.gz → 2.0.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 (25) hide show
  1. {labtasker_client-2.0.0 → labtasker_client-2.0.1}/PKG-INFO +1 -1
  2. {labtasker_client-2.0.0 → labtasker_client-2.0.1}/pyproject.toml +1 -1
  3. {labtasker_client-2.0.0 → labtasker_client-2.0.1}/src/labtasker/__init__.py +1 -1
  4. {labtasker_client-2.0.0 → labtasker_client-2.0.1}/src/labtasker/binding.py +6 -2
  5. {labtasker_client-2.0.0 → labtasker_client-2.0.1}/src/labtasker/cli.py +5 -5
  6. {labtasker_client-2.0.0 → labtasker_client-2.0.1}/src/labtasker/command_worker.py +10 -2
  7. {labtasker_client-2.0.0 → labtasker_client-2.0.1}/src/labtasker/config.py +6 -0
  8. labtasker_client-2.0.1/src/labtasker/py.typed +0 -0
  9. labtasker_client-2.0.0/src/labtasker/py.typed +0 -1
  10. {labtasker_client-2.0.0 → labtasker_client-2.0.1}/.gitignore +0 -0
  11. {labtasker_client-2.0.0 → labtasker_client-2.0.1}/LICENSE +0 -0
  12. {labtasker_client-2.0.0 → labtasker_client-2.0.1}/src/labtasker/__main__.py +0 -0
  13. {labtasker_client-2.0.0 → labtasker_client-2.0.1}/src/labtasker/api.py +0 -0
  14. {labtasker_client-2.0.0 → labtasker_client-2.0.1}/src/labtasker/client.py +0 -0
  15. {labtasker_client-2.0.0 → labtasker_client-2.0.1}/src/labtasker/command_template.py +0 -0
  16. {labtasker_client-2.0.0 → labtasker_client-2.0.1}/src/labtasker/errors.py +0 -0
  17. {labtasker_client-2.0.0 → labtasker_client-2.0.1}/src/labtasker/execution.py +0 -0
  18. {labtasker_client-2.0.0 → labtasker_client-2.0.1}/src/labtasker/journal.py +0 -0
  19. {labtasker_client-2.0.0 → labtasker_client-2.0.1}/src/labtasker/local.py +0 -0
  20. {labtasker_client-2.0.0 → labtasker_client-2.0.1}/src/labtasker/models.py +0 -0
  21. {labtasker_client-2.0.0 → labtasker_client-2.0.1}/src/labtasker/paths.py +0 -0
  22. {labtasker_client-2.0.0 → labtasker_client-2.0.1}/src/labtasker/tee.py +0 -0
  23. {labtasker_client-2.0.0 → labtasker_client-2.0.1}/src/labtasker/types.py +0 -0
  24. {labtasker_client-2.0.0 → labtasker_client-2.0.1}/src/labtasker/validation.py +0 -0
  25. {labtasker_client-2.0.0 → labtasker_client-2.0.1}/src/labtasker/worker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: labtasker-client
3
- Version: 2.0.0
3
+ Version: 2.0.1
4
4
  Summary: A small task queue for parallel model inference and evaluation
5
5
  Project-URL: Homepage, https://github.com/luocfprime/labtasker
6
6
  Project-URL: Repository, https://github.com/luocfprime/labtasker.git
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "labtasker-client"
7
- version = "2.0.0"
7
+ version = "2.0.1"
8
8
  description = "A small task queue for parallel model inference and evaluation"
9
9
  requires-python = ">=3.11"
10
10
  license = "Apache-2.0"
@@ -35,7 +35,7 @@ from labtasker.models import BulkUpdateResult, LastError, Queue, Task, TaskInfo,
35
35
  from labtasker.types import JSONValue, TaskOrderField, TaskStatus, TaskUpdate
36
36
  from labtasker.worker import loop
37
37
 
38
- __version__ = "2.0.0"
38
+ __version__ = "2.0.1"
39
39
 
40
40
  __all__ = [
41
41
  "APIError",
@@ -119,7 +119,7 @@ class CompiledBinding:
119
119
 
120
120
 
121
121
  def compile_binding(function: Callable[..., Any]) -> CompiledBinding:
122
- if inspect.iscoroutinefunction(function):
122
+ if _is_async_callable(function):
123
123
  raise TypeError("Labtasker v2 Worker handlers must be synchronous functions.")
124
124
  signature = inspect.signature(function)
125
125
  try:
@@ -170,7 +170,7 @@ def compile_binding(function: Callable[..., Any]) -> CompiledBinding:
170
170
  def _validate_resolver(resolver: object, name: str) -> None:
171
171
  if not callable(resolver):
172
172
  raise TypeError(f"TaskArg resolver for {name!r} must be callable.")
173
- if inspect.iscoroutinefunction(resolver):
173
+ if _is_async_callable(resolver):
174
174
  raise TypeError(f"TaskArg resolver for {name!r} must be synchronous.")
175
175
  try:
176
176
  signature = inspect.signature(resolver)
@@ -182,3 +182,7 @@ def _validate_resolver(resolver: object, name: str) -> None:
182
182
  inspect.Parameter.POSITIONAL_OR_KEYWORD,
183
183
  }:
184
184
  raise TypeError(f"TaskArg resolver for {name!r} must accept exactly one value.")
185
+
186
+
187
+ def _is_async_callable(value: object) -> bool:
188
+ return inspect.iscoroutinefunction(value) or inspect.iscoroutinefunction(type(value).__call__)
@@ -98,7 +98,7 @@ def worker_loop(
98
98
 
99
99
  Example:
100
100
 
101
- 
101
+ \b
102
102
  labtasker loop --route train -- \\
103
103
  python train.py --seed '%{seed}' --lr '%{optimizer.lr}'
104
104
  """
@@ -174,7 +174,7 @@ def task_submit(
174
174
 
175
175
  Example:
176
176
 
177
- 
177
+ \b
178
178
  labtasker task submit --name baseline \\
179
179
  --args '{"seed":1,"enabled":true}' \\
180
180
  --metadata '{"group":"paper"}' --route train
@@ -250,7 +250,7 @@ def task_list(
250
250
 
251
251
  Example:
252
252
 
253
- 
253
+ \b
254
254
  labtasker task list --status pending \\
255
255
  --filter 'priority >= 10 and metadata.group == "paper"' \\
256
256
  --order-by priority --descending --limit 100
@@ -295,7 +295,7 @@ def task_count(
295
295
 
296
296
  Example:
297
297
 
298
- 
298
+ \b
299
299
  labtasker task count --status failed \\
300
300
  --filter 'last_error.type == "ValueError"'
301
301
  """
@@ -339,7 +339,7 @@ def task_update(
339
339
 
340
340
  Examples:
341
341
 
342
- 
342
+ \b
343
343
  labtasker task update t_ABCDEFGHIJKL \\
344
344
  --changes '{"priority":20}'
345
345
  labtasker task update --filter 'status == "pending"' \\
@@ -244,13 +244,21 @@ def _start_drain(
244
244
  name: str,
245
245
  ) -> threading.Thread:
246
246
  def drain() -> None:
247
+ relay = True
247
248
  while True:
248
- chunk = source.read(65536)
249
+ chunk = os.read(source.fileno(), 65536)
249
250
  if not chunk:
250
251
  return
251
252
  with lock:
252
253
  log.write(chunk)
253
- _write_bytes(destination, chunk)
254
+ if relay:
255
+ try:
256
+ _write_bytes(destination, chunk)
257
+ except Exception:
258
+ # The child must never block on a full pipe merely because the
259
+ # caller closed or replaced its output stream. Keep draining and
260
+ # journaling after live relay becomes unavailable.
261
+ relay = False
254
262
 
255
263
  thread = threading.Thread(target=drain, name=f"labtasker-command-{name}", daemon=True)
256
264
  thread.start()
@@ -190,4 +190,10 @@ def _validate_token(value: str | None, *, source: str) -> str | None:
190
190
  return None
191
191
  if not isinstance(value, str) or not value:
192
192
  raise invalid_config("Token must be a non-empty string.", source=source, field="token")
193
+ if any(not 0x21 <= ord(character) <= 0x7E for character in value):
194
+ raise invalid_config(
195
+ "Token must contain only visible ASCII characters.",
196
+ source=source,
197
+ field="token",
198
+ )
193
199
  return value
File without changes
@@ -1 +0,0 @@
1
-