anon-iclr-submission/benchname-bug-localization huggingface dataset:
Repository: juju/python-libjuju
Issue: [Bug]: model.destroy_units signature changed breaking compatability

### Description

in older versions of this library, the signature of `destroy_units` allows you to delete a list of units like this:

```await model.destroy_units(*list_of_units)```

because it's signature was this:

```python

    async def destroy_unit(self, *unit_names):
        ...

    destroy_units = destroy_unit
```

in newer versions of this library the signature is
```python
    async def destroy_unit(self, unit_id, destroy_storage=False, dry_run=False, force=False, max_wait=None):
        ...
    destroy_units = destroy_unit
```

This `destroy_units` simply no longer works:

a WORKAROUND for the callers is this:
```await asyncio.gather(*(model.destroy_unit(_) for _ in list_of_units))```

but restoring or removing `destroy_units` would be preferred

### Urgency

Annoying bug in our test suite

### Python-libjuju version

3.1.0.1

### Juju version

juju 3.1

### Reproduce / Test

```python
await model.destroy_units(*matched_units)
E       TypeError: Model.destroy_unit() missing 1 required positional argument: 'unit_id'
```


Changed files:
tests/integration/test_model.py, juju/model.py

diff --git a/juju/model.py b/juju/model.py
index d56233b..22a9ac8 100644
--- a/juju/model.py
+++ b/juju/model.py
@@ -2014,7 +2014,13 @@ class Model:
             'max-wait': max_wait,
             'dry-run': dry_run,
         }])
-    destroy_units = destroy_unit
+
+    async def destroy_units(self, *unit_names, destroy_storage=False, dry_run=False, force=False, max_wait=None):
+        """Destroy several units at once.
+
+        """
+        for u in unit_names:
+            await self.destroy_unit(u, destroy_storage, dry_run, force, max_wait)
 
     def download_backup(self, archive_id, target_filename=None):
         """Download a backup archive file.
diff --git a/tests/integration/test_model.py b/tests/integration/test_model.py
index 53e16f3..7658f86 100644
--- a/tests/integration/test_model.py
+++ b/tests/integration/test_model.py
@@ -882,6 +882,23 @@ async def test_wait_for_idle_with_exact_units_scale_down_zero(event_loop):
         assert (end_time - start_time) > 0.001
 
 
+@base.bootstrapped
+@pytest.mark.asyncio
+async def test_destroy_units(event_loop):
+    async with base.CleanModel() as model:
+        app = await model.deploy(
+            'ubuntu',
+            application_name='ubuntu',
+            series='jammy',
+            channel='stable',
+            num_units=3,
+        )
+        await model.wait_for_idle(status='active')
+        await model.destroy_units(*[u.name for u in app.units])
+        await model.wait_for_idle(timeout=5 * 60, wait_for_exact_units=0)
+        assert app.units == []
+
+
 @base.bootstrapped
 @pytest.mark.asyncio
 async def test_watcher_reconnect(event_loop):
Repository: juju/python-libjuju
Issue: Potential error in task handling code

If the `utils.run_with_interrupt` is ever called with `log=None`, 

https://github.com/juju/python-libjuju/blob/43becc4b9e05682522602bed2bf3575913e96573/juju/utils.py#L146-L161

then it'll cause the `jasyncio.create_task_with_handler`

https://github.com/juju/python-libjuju/blob/43becc4b9e05682522602bed2bf3575913e96573/juju/jasyncio.py#L49

to break at the following line if the wrapped task raises an exception:

https://github.com/juju/python-libjuju/blob/43becc4b9e05682522602bed2bf3575913e96573/juju/jasyncio.py#L75

--------------------

PR to follow with a small fix.

Changed files:
juju/jasyncio.py

diff --git a/juju/jasyncio.py b/juju/jasyncio.py
index 8208065..d5826fb 100644
--- a/juju/jasyncio.py
+++ b/juju/jasyncio.py
@@ -24,6 +24,9 @@ import asyncio
 import signal
 import functools
 import websockets
+import logging
+
+ROOT_LOGGER = logging.getLogger()
 
 from asyncio import Event, TimeoutError, Queue, ensure_future, \\
     gather, sleep, wait_for, create_subprocess_exec, subprocess, \\
@@ -46,7 +49,7 @@ except ImportError:
         return asyncio.ensure_future(coro)
 
 
-def create_task_with_handler(coro, task_name, logger):
+def create_task_with_handler(coro, task_name, logger=ROOT_LOGGER):
     """Wrapper around "asyncio.create_task" to make sure the task
     exceptions are handled properly.