prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Add a `description` parameter to the work decorator, to use in place of the auto-generated description.
  
  
  </issue>
  <code>
  [start of src/textual/_work_decorator.py]
  1 """
  2 
  3 A decorator used to create [workers](/guide/workers).
  4 """
  5 
  6 
  7 from __future__ import annotations
  8 
  9 from functools import partial, wraps
  10 from typing import TYPE_CHECKING, Callable, Coroutine, TypeVar, Union, cast, overload
  11 
  12 from typing_extensions import ParamSpec, TypeAlias
  13 
  14 if TYPE_CHECKING:
  15     from .worker import Worker
  16 
  17 
  18 FactoryParamSpec = ParamSpec("FactoryParamSpec")
  19 DecoratorParamSpec = ParamSpec("DecoratorParamSpec")
  20 ReturnType = TypeVar("ReturnType")
  21 
  22 Decorator: TypeAlias = Callable[
  23     [
  24         Union[
  25             Callable[DecoratorParamSpec, ReturnType],
  26             Callable[DecoratorParamSpec, Coroutine[None, None, ReturnType]],
  27         ]
  28     ],
  29     Callable[DecoratorParamSpec, "Worker[ReturnType]"],
  30 ]
  31 
  32 
  33 @overload
  34 def work(
  35     method: Callable[FactoryParamSpec, Coroutine[None, None, ReturnType]]
  36 ) -> Callable[FactoryParamSpec, "Worker[ReturnType]"]:
  37     ...
  38 
  39 
  40 @overload
  41 def work(
  42     method: Callable[FactoryParamSpec, ReturnType]
  43 ) -> Callable[FactoryParamSpec, "Worker[ReturnType]"]:
  44     ...
  45 
  46 
  47 @overload
  48 def work(*, exclusive: bool = False) -> Decorator[..., ReturnType]:
  49     ...
  50 
  51 
  52 def work(
  53     method: Callable[FactoryParamSpec, ReturnType]
  54     | Callable[FactoryParamSpec, Coroutine[None, None, ReturnType]]
  55     | None = None,
  56     *,
  57     name: str = "",
  58     group: str = "default",
  59     exit_on_error: bool = True,
  60     exclusive: bool = False,
  61 ) -> Callable[FactoryParamSpec, Worker[ReturnType]] | Decorator:
  62     """A decorator used to create [workers](/guide/workers).
  63 
  64     Args:
  65         method: A function or coroutine.
  66         name: A short string to identify the worker (in logs and debugging).
  67         group: A short string to identify a group of workers.
  68         exit_on_error: Exit the app if the worker raises an error. Set to `False` to suppress exceptions.
  69         exclusive: Cancel all workers in the same group.
  70     """
  71 
  72     def decorator(
  73         method: (
  74             Callable[DecoratorParamSpec, ReturnType]
  75             | Callable[DecoratorParamSpec, Coroutine[None, None, ReturnType]]
  76         )
  77     ) -> Callable[DecoratorParamSpec, Worker[ReturnType]]:
  78         """The decorator."""
  79 
  80         @wraps(method)
  81         def decorated(
  82             *args: DecoratorParamSpec.args, **kwargs: DecoratorParamSpec.kwargs
  83         ) -> Worker[ReturnType]:
  84             """The replaced callable."""
  85             from .dom import DOMNode
  86 
  87             self = args[0]
  88             assert isinstance(self, DOMNode)
  89 
  90             try:
  91                 positional_arguments = ", ".join(repr(arg) for arg in args[1:])
  92                 keyword_arguments = ", ".join(
  93                     f"{name}={value!r}" for name, value in kwargs.items()
  94                 )
  95                 tokens = [positional_arguments, keyword_arguments]
  96                 worker_description = f"{method.__name__}({', '.join(token for token in tokens if token)})"
  97             except Exception:
  98                 worker_description = "<worker>"
  99             worker = cast(
  100                 "Worker[ReturnType]",
  101                 self.run_worker(
  102                     partial(method, *args, **kwargs),
  103                     name=name or method.__name__,
  104                     group=group,
  105                     description=worker_description,
  106                     exclusive=exclusive,
  107                     exit_on_error=exit_on_error,
  108                 ),
  109             )
  110             return worker
  111 
  112         return decorated
  113 
  114     if method is None:
  115         return decorator
  116     else:
  117         return decorator(method)
  118
  [end of src/textual/_work_decorator.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/src/textual/_work_decorator.py b/src/textual/_work_decorator.py
  --- a/src/textual/_work_decorator.py
  +++ b/src/textual/_work_decorator.py
  @@ -58,6 +58,7 @@
       group: str = "default",
       exit_on_error: bool = True,
       exclusive: bool = False,
  +    description: str | None = None,
   ) -> Callable[FactoryParamSpec, Worker[ReturnType]] | Decorator:
       """A decorator used to create [workers](/guide/workers).
   
  @@ -67,6 +68,9 @@
           group: A short string to identify a group of workers.
           exit_on_error: Exit the app if the worker raises an error. Set to `False` to suppress exceptions.
           exclusive: Cancel all workers in the same group.
  +        description: Readable description of the worker for debugging purposes.
  +            By default, it uses a string representation of the decorated method
  +            and its arguments.
       """
   
       def decorator(
  @@ -87,22 +91,25 @@
               self = args[0]
               assert isinstance(self, DOMNode)
   
  -            try:
  -                positional_arguments = ", ".join(repr(arg) for arg in args[1:])
  -                keyword_arguments = ", ".join(
  -                    f"{name}={value!r}" for name, value in kwargs.items()
  -                )
  -                tokens = [positional_arguments, keyword_arguments]
  -                worker_description = f"{method.__name__}({', '.join(token for token in tokens if token)})"
  -            except Exception:
  -                worker_description = "<worker>"
  +            if description is not None:
  +                debug_description = description
  +            else:
  +                try:
  +                    positional_arguments = ", ".join(repr(arg) for arg in args[1:])
  +                    keyword_arguments = ", ".join(
  +                        f"{name}={value!r}" for name, value in kwargs.items()
  +                    )
  +                    tokens = [positional_arguments, keyword_arguments]
  +                    debug_description = f"{method.__name__}({', '.join(token for token in tokens if token)})"
  +                except Exception:
  +                    debug_description = "<worker>"
               worker = cast(
                   "Worker[ReturnType]",
                   self.run_worker(
                       partial(method, *args, **kwargs),
                       name=name or method.__name__,
                       group=group,
  -                    description=worker_description,
  +                    description=debug_description,
                       exclusive=exclusive,
                       exit_on_error=exit_on_error,
                   ),
  
verification_info: {"golden_diff": "diff --git a/src/textual/_work_decorator.py b/src/textual/_work_decorator.py\n--- a/src/textual/_work_decorator.py\n+++ b/src/textual/_work_decorator.py\n@@ -58,6 +58,7 @@\n     group: str = \"default\",\n     exit_on_error: bool = True,\n     exclusive: bool = False,\n+    description: str | None = None,\n ) -> Callable[FactoryParamSpec, Worker[ReturnType]] | Decorator:\n     \"\"\"A decorator used to create [workers](/guide/workers).\n \n@@ -67,6 +68,9 @@\n         group: A short string to identify a group of workers.\n         exit_on_error: Exit the app if the worker raises an error. Set to `False` to suppress exceptions.\n         exclusive: Cancel all workers in the same group.\n+        description: Readable description of the worker for debugging purposes.\n+            By default, it uses a string representation of the decorated method\n+            and its arguments.\n     \"\"\"\n \n     def decorator(\n@@ -87,22 +91,25 @@\n             self = args[0]\n             assert isinstance(self, DOMNode)\n \n-            try:\n-                positional_arguments = \", \".join(repr(arg) for arg in args[1:])\n-                keyword_arguments = \", \".join(\n-                    f\"{name}={value!r}\" for name, value in kwargs.items()\n-                )\n-                tokens = [positional_arguments, keyword_arguments]\n-                worker_description = f\"{method.__name__}({', '.join(token for token in tokens if token)})\"\n-            except Exception:\n-                worker_description = \"<worker>\"\n+            if description is not None:\n+                debug_description = description\n+            else:\n+                try:\n+                    positional_arguments = \", \".join(repr(arg) for arg in args[1:])\n+                    keyword_arguments = \", \".join(\n+                        f\"{name}={value!r}\" for name, value in kwargs.items()\n+                    )\n+                    tokens = [positional_arguments, keyword_arguments]\n+                    debug_description = f\"{method.__name__}({', '.join(token for token in tokens if token)})\"\n+                except Exception:\n+                    debug_description = \"<worker>\"\n             worker = cast(\n                 \"Worker[ReturnType]\",\n                 self.run_worker(\n                     partial(method, *args, **kwargs),\n                     name=name or method.__name__,\n                     group=group,\n-                    description=worker_description,\n+                    description=debug_description,\n                     exclusive=exclusive,\n                     exit_on_error=exit_on_error,\n                 ),\n", "issue": "Add a `description` parameter to the work decorator, to use in place of the auto-generated description.\n\n", "before_files": [{"content": "\"\"\"\n\nA decorator used to create [workers](/guide/workers).\n\"\"\"\n\n\nfrom __future__ import annotations\n\nfrom functools import partial, wraps\nfrom typing import TYPE_CHECKING, Callable, Coroutine, TypeVar, Union, cast, overload\n\nfrom typing_extensions import ParamSpec, TypeAlias\n\nif TYPE_CHECKING:\n    from .worker import Worker\n\n\nFactoryParamSpec = ParamSpec(\"FactoryParamSpec\")\nDecoratorParamSpec = ParamSpec(\"DecoratorParamSpec\")\nReturnType = TypeVar(\"ReturnType\")\n\nDecorator: TypeAlias = Callable[\n    [\n        Union[\n            Callable[DecoratorParamSpec, ReturnType],\n            Callable[DecoratorParamSpec, Coroutine[None, None, ReturnType]],\n        ]\n    ],\n    Callable[DecoratorParamSpec, \"Worker[ReturnType]\"],\n]\n\n\n@overload\ndef work(\n    method: Callable[FactoryParamSpec, Coroutine[None, None, ReturnType]]\n) -> Callable[FactoryParamSpec, \"Worker[ReturnType]\"]:\n    ...\n\n\n@overload\ndef work(\n    method: Callable[FactoryParamSpec, ReturnType]\n) -> Callable[FactoryParamSpec, \"Worker[ReturnType]\"]:\n    ...\n\n\n@overload\ndef work(*, exclusive: bool = False) -> Decorator[..., ReturnType]:\n    ...\n\n\ndef work(\n    method: Callable[FactoryParamSpec, ReturnType]\n    | Callable[FactoryParamSpec, Coroutine[None, None, ReturnType]]\n    | None = None,\n    *,\n    name: str = \"\",\n    group: str = \"default\",\n    exit_on_error: bool = True,\n    exclusive: bool = False,\n) -> Callable[FactoryParamSpec, Worker[ReturnType]] | Decorator:\n    \"\"\"A decorator used to create [workers](/guide/workers).\n\n    Args:\n        method: A function or coroutine.\n        name: A short string to identify the worker (in logs and debugging).\n        group: A short string to identify a group of workers.\n        exit_on_error: Exit the app if the worker raises an error. Set to `False` to suppress exceptions.\n        exclusive: Cancel all workers in the same group.\n    \"\"\"\n\n    def decorator(\n        method: (\n            Callable[DecoratorParamSpec, ReturnType]\n            | Callable[DecoratorParamSpec, Coroutine[None, None, ReturnType]]\n        )\n    ) -> Callable[DecoratorParamSpec, Worker[ReturnType]]:\n        \"\"\"The decorator.\"\"\"\n\n        @wraps(method)\n        def decorated(\n            *args: DecoratorParamSpec.args, **kwargs: DecoratorParamSpec.kwargs\n        ) -> Worker[ReturnType]:\n            \"\"\"The replaced callable.\"\"\"\n            from .dom import DOMNode\n\n            self = args[0]\n            assert isinstance(self, DOMNode)\n\n            try:\n                positional_arguments = \", \".join(repr(arg) for arg in args[1:])\n                keyword_arguments = \", \".join(\n                    f\"{name}={value!r}\" for name, value in kwargs.items()\n                )\n                tokens = [positional_arguments, keyword_arguments]\n                worker_description = f\"{method.__name__}({', '.join(token for token in tokens if token)})\"\n            except Exception:\n                worker_description = \"<worker>\"\n            worker = cast(\n                \"Worker[ReturnType]\",\n                self.run_worker(\n                    partial(method, *args, **kwargs),\n                    name=name or method.__name__,\n                    group=group,\n                    description=worker_description,\n                    exclusive=exclusive,\n                    exit_on_error=exit_on_error,\n                ),\n            )\n            return worker\n\n        return decorated\n\n    if method is None:\n        return decorator\n    else:\n        return decorator(method)\n", "path": "src/textual/_work_decorator.py"}]}