Repository: goodmami/wn

Issue:
Allow ILI objects as values of ili parameter on synsets() function
**Is your feature request related to a problem? Please describe.**

The `ili` parameter on the `Wordnet.synsets()` function currently accepts a string ID:

```pycon
>>> import wn
>>> ewn = wn.Wordnet("oewn")
>>> pencil = ewn.synsets(ili="i57109")[0]
>>> pencil.lemmas()
['pencil']
```

If we already have a synset and want to use its `ili` attribute to find other synsets, we can't just use `ss.ili` but have to use `ss.ili.id`:

```pycon
>>> jpn = wn.Wordnet("omw-ja")
>>> jpn.synsets(ili=pencil.ili)
Traceback (most recent call last):
  [...]
sqlite3.ProgrammingError: Error binding parameter 1: type 'ILI' is not supported
>>> jpn.synsets(ili=pencil.ili.id)[0].lemmas()
['ペンシル', '木筆', '鉛筆']
```

While this is conceptually simple (the argument type is always `str`), it would probably be more user-friendly to also allow the ILI object directly.

**Describe the solution you'd like**

I would like to query synsets using ILI objects as above without the somewhat cryptic SQLite error.

**Describe alternatives you've considered**

Keep it as-is. The straightforward typing of the `ili` parameter is appealing and requires less documentation. But I also find myself frequently making the above mistake.

Hints from issue comments:

Solution patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 864df3c..3a0ea2d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,11 @@
 
 * `wn.web` casts URL objects to strings for JSON serialization ([#238])
 
+## Changed
+
+* `Wordnet.synsets()` now accepts `wn.ILI` objects for the `ili`
+  parameter ([#235])
+
 ## Deprecated
 
 * `wn.word()` ([#236])
@@ -748,6 +753,7 @@ abandoned, but this is an entirely new codebase.
 [#216]: https://github.com/goodmami/wn/issues/216
 [#221]: https://github.com/goodmami/wn/issues/221
 [#228]: https://github.com/goodmami/wn/issues/228
+[#235]: https://github.com/goodmami/wn/issues/235
 [#236]: https://github.com/goodmami/wn/issues/236
 [#237]: https://github.com/goodmami/wn/issues/237
 [#238]: https://github.com/goodmami/wn/issues/238
diff --git a/wn/_core.py b/wn/_core.py
index 6687814..a3763e9 100644
--- a/wn/_core.py
+++ b/wn/_core.py
@@ -3,7 +3,7 @@ import enum
 import textwrap
 import warnings
 from collections.abc import Callable, Iterator, Sequence
-from typing import Optional, TypeVar
+from typing import Optional, TypeVar, Union
 
 from typing_extensions import deprecated  # until Python 3.13
 
@@ -1361,7 +1361,7 @@ class Wordnet:
         self,
         form: Optional[str] = None,
         pos: Optional[str] = None,
-        ili: Optional[str] = None
+        ili: Optional[Union[str, ILI]] = None
     ) -> list[Synset]:
         """Return the list of matching synsets in this wordnet.
 
@@ -1467,7 +1467,7 @@ def _find_helper(
     query_func: Callable,
     form: Optional[str],
     pos: Optional[str],
-    ili: Optional[str] = None
+    ili: Optional[Union[str, ILI]] = None
 ) -> list[C]:
     """Return the list of matching wordnet entities.
 
@@ -1483,8 +1483,15 @@ def _find_helper(
         'lexicon_rowids': w._lexicon_ids,
         'search_all_forms': w._search_all_forms,
     }
-    if ili is not None:
+    if isinstance(ili, str):
         kwargs['ili'] = ili
+    elif isinstance(ili, ILI):
+        kwargs['ili'] = ili.id
+    elif ili is not None:
+        raise TypeError(
+            "ili argument must be a string, an ILI, or None, "
+            f"not {type(ili).__name__!r}"
+        )
 
     # easy case is when there is no form
     if form is None:
@@ -1660,7 +1667,7 @@ def synset(
 def synsets(
     form: Optional[str] = None,
     pos: Optional[str] = None,
-    ili: Optional[str] = None,
+    ili: Optional[Union[str, ILI]] = None,
     *,
     lexicon: Optional[str] = None,
     lang: Optional[str] = None,


Test patch:
diff --git a/tests/primary_query_test.py b/tests/primary_query_test.py
index 15bdef0..1adcbf3 100644
--- a/tests/primary_query_test.py
+++ b/tests/primary_query_test.py
@@ -196,6 +196,7 @@ def test_synsets_mini():
 
     assert len(wn.synsets(ili='i67469')) == 2
     assert len(wn.synsets(ili='i67468')) == 0
+    assert len(wn.synsets(ili=wn.ili('i67469'))) == 2
 
     assert len(wn.synsets(lang='en')) == 8
     assert len(wn.synsets(lang='es')) == 4