libtorrent icon indicating copy to clipboard operation
libtorrent copied to clipboard

Pypi builds are missing type stubs

Open baseplate-admin opened this issue 5 months ago • 7 comments

Hi,

It seems that RC branch does not include the type hints, is it possible to include those in pypi?

I see that there were discussions on this before https://github.com/arvidn/libtorrent/issues/6730

cc: @AllSeeingEyeTolledEweSew

baseplate-admin avatar Jul 23 '25 06:07 baseplate-admin

@qstokkink You interested in submitting a PR? (Since you have experience with "type stubs" -> #7691)

https://github.com/AllSeeingEyeTolledEweSew/libtorrent/pulls/AllSeeingEyeTolledEweSew might provide some inspiration.

xavier2k6 avatar Jul 23 '25 11:07 xavier2k6

cc: @AllSeeingEyeTolledEweSew

Hasn't appeared to be active for a long time.

xavier2k6 avatar Jul 23 '25 11:07 xavier2k6

This is just a matter of hanging the master typing-related commits into the RC branch: relatively easy[^1]. However, I assume the types were parked on master because Arvid didn't want them in an RC yet, for some reason. Of course, he may have also forgotten the types exist, I have no way of knowing. Probably best to ask him instead of me.

[^1]: The typing is a bit out of date. A little bit of love is needed to get it up to date.

qstokkink avatar Jul 23 '25 13:07 qstokkink

one challenge with type stubs is to make sure they remain correct and aligned with the actual bindings. having a CI check for that (something like stubtest) would be important. If there's a CI test for that, I don't have any opinion about including it in RC_2_0 or not.

arvidn avatar Jul 26 '25 03:07 arvidn

If that's the case, I can have a look. I don't mind scouting out some options.

If successful, I can create a PR. If not, I'll report back with how/why I failed.

EDIT: Options so far:

  • stubtest ► ✅ passed, detected missing stubs and inconsistencies.

  • pyright, --verifytypes

    Failed to detect that libtorrent.load_torrent_* bindings are not present in __init__.pyi.
       libtorrent
    
    Symbols used in public interface:
    libtorrent.add_magnet_uri
      /home/quinten/Documents/lttypechecker/venv/lib/python3.12/site-packages/libtorrent/__init__.pyi:66:5 - error: Type of parameter "_session" is partially unknown
        Parameter type is "session"
    libtorrent.session.add_torrent
      /home/quinten/Documents/lttypechecker/venv/lib/python3.12/site-packages/libtorrent/__init__.pyi:1337:9 - error: Type of parameter "resume_data" is partially unknown
        Parameter type is "bytes | int | List[Unknown] | Dict[bytes, Any] | Tuple[int, ...] | None"
          Type argument 1 for class "list" has unknown type
    libtorrent.session.dht_put_immutable_item
      /home/quinten/Documents/lttypechecker/venv/lib/python3.12/site-packages/libtorrent/__init__.pyi:1356:9 - error: Type of parameter "_entry" is partially unknown
        Parameter type is "bytes | int | List[Unknown] | Dict[bytes, Any] | Tuple[int, ...]"
          Type argument 1 for class "list" has unknown type
    libtorrent.session.load_state
      /home/quinten/Documents/lttypechecker/venv/lib/python3.12/site-packages/libtorrent/__init__.pyi:1384:9 - error: Type of parameter "entry" is partially unknown
        Parameter type is "bytes | int | List[Unknown] | Dict[bytes, Any] | Tuple[int, ...]"
          Type argument 1 for class "list" has unknown type
    libtorrent.bdecode
      /home/quinten/Documents/lttypechecker/venv/lib/python3.12/site-packages/libtorrent/__init__.pyi:69:5 - error: Return type is partially unknown
        Return type is "bytes | int | List[Unknown] | Dict[bytes, Any] | Tuple[int, ...]"
          Type argument 1 for class "list" has unknown type
    libtorrent.bencode
      /home/quinten/Documents/lttypechecker/venv/lib/python3.12/site-packages/libtorrent/__init__.pyi:71:5 - error: Type of parameter "_bdecoded" is partially unknown
        Parameter type is "bytes | int | List[Unknown] | Dict[bytes, Any] | Tuple[int, ...]"
          Type argument 1 for class "list" has unknown type
    libtorrent.dht_immutable_item_alert.item
      /home/quinten/Documents/lttypechecker/venv/lib/python3.12/site-packages/libtorrent/__init__.pyi:508:5 - error: Type argument 1 for class "list" has unknown type
    libtorrent.dht_mutable_item_alert.item
      /home/quinten/Documents/lttypechecker/venv/lib/python3.12/site-packages/libtorrent/__init__.pyi:542:5 - error: Type argument 1 for class "list" has unknown type
    
    Symbols exported by "libtorrent": 1556
      With known type: 1545
      With ambiguous type: 0
      With unknown type: 11
    
    Other symbols referenced but not exported by "libtorrent": 195
      With known type: 195
      With ambiguous type: 0
      With unknown type: 0
    
    Symbols without documentation:
      Functions without docstring: 385
      Functions without default param: 38
      Classes without docstring: 179
    
    Type completeness score: 99.3%
    
    Completed in 0.641sec
    
  • flake8-pyi, https://github.com/PyCQA/flake8-pyi ► ✅ℹ️ failed the assignment. However, detected use of deprecated typing constructions.

Current best approach: combine python -m mypy.stubtest libtorrent with flake8 __init__.pyi

qstokkink avatar Jul 28 '25 08:07 qstokkink

@arvidn What's your policy on picking commits from master into an RC_* branch? cherry-pick/rebase/other?


For reference, I think these are all the necessary commits, starting from commit aaa5691 as the first commit:

pick c6b03bac9 Add type stubs and tests for sha256_hash
pick 6247153cd Add binding for announce_flags_t
pick 421a00af4 Add binding to fix session.add_port_mapping
pick 17259c7db Remove binding for session_params.ext_state
pick 8b386b678 Fix bindings for members of picker_log_alert
pick 0ec312e34 Fix deprecated session.add_torrent form to prevent crash
pick 3a35e1583 Fix dht_[im]mutable_item_alert.item to just be the item
pick 9ad9d82fe Add session.session_state()
pick 4812bfbe3 update python type stubs
pick 258fd0f87 fix python tests when disabling deprecated functions
pick 7c698d826 fix wheel types not being found
pick 618992875 Moved type stubs into libtorrent directory
pick 1d644d19c update name, listen_succeeded_alert_socket_type_t

Given that these commits build on the test.py -> tests/ directory split. I think it would be best to rewrite these commits using cherry-pick, to avoid pulling in the plethora of related files.

For now, I'm proceeding with cherry-pick. The type-fixing + CI commit I build on top of that should be applicable either way.

If anyone is looking for an update before the weekend: when I said "relatively easy" before, what I should've said is "Repetitive Strain Injury ". Current status: commits cherry-picked, types modernized, types fixed, now double-checking work.

qstokkink avatar Jul 29 '25 07:07 qstokkink

Alright guys, I finished: https://github.com/qstokkink/libtorrent/actions/runs/16753752474

At this point:

  • All types are consistent, enforced with CI.
  • All types are modernized, enforced with CI.
  • There are no missing types, enforced with CI.

That said, there is one thing that the CI does not do and even cannot do:

  • Actually call the code with the given function signatures.

So, practically, this means that if the libtorrent wheel exposes a function f(a: some_type), a function f() has to exist in the type stubs. However, the arguments to f() in the type stubs can be complete nonsense. The "only" way[^1] to catch this is by calling the method (for example, in the unit tests) and checking if the types match up at runtime.

If anyone has some spare time, it would nice if you could install one of the built wheels (that I linked to in the GH Actions run above) and let me know if you spot any function signature mismatches. I opened up a PR for reviews, if you do spot any inconsistencies.

[^1]: Boost.Python also generates __doc__ strings for functions at runtime. So, I guess technically you can read that without necessarily calling anything.

qstokkink avatar Aug 05 '25 16:08 qstokkink