Repository navigation
Bluetooth socket additions in Python 3.14 #15213
Copy link
Copy link
Open
Labels
stubs: incompleteAnnotations or sub-modules missing from an existing package or moduleAnnotations or sub-modules missing from an existing package or module
Description
Python 3.14 added some additional constants to the socket module for Bluetooth-related sockets.
Related documentation sections:
- https://docs.python.org/3/library/socket.html#socket-families (have to scroll a bit to get to the
AF_BLUETOOTHbullet point) - https://docs.python.org/3/library/socket.html#socket.AF_BLUETOOTH
Changes needed:
_socket._Addressneeds to addintto the union because of "device_idnot packed in a tuple is now accepted." forBTPROTO_HCIwheredevice_idis an integer.- Windows gets new constants
SOL_RFCOMM,SO_BTH_ENCRYPT,SO_BTH_MTU,SO_BTH_MTU_MAX,SO_BTH_MTU_MIN. - Linux gets new constants
BDADDR_BREDR,BDADDR_LE_PUBLIC,BDADDR_LE_RANDOM,SOL_BLUETOOTH,SOL_L2CAP,SOL_RFCOMM,SOL_SCO,L2CAP_LM,L2CAP_LM_AUTH,L2CAP_LM_ENCRYPT,L2CAP_LM_MASTER,L2CAP_LM_RELIABLE,L2CAP_LM_SECURE,L2CAP_LM_TRUSTED,BT_CHANNEL_POLICY,BT_CHANNEL_POLICY_BREDR_ONLY,BT_CHANNEL_POLICY_BREDR_PREFERRED,BT_CODEC,BT_DEFER_SETUP,BT_FLUSHABLE,BT_FLUSHABLE_OFF,BT_FLUSHABLE_ON,BT_ISO_QOS,BT_MODE,BT_MODE_BASIC,BT_MODE_ERTM,BT_MODE_EXT_FLOWCTL,BT_MODE_LE_FLOWCTL,BT_MODE_STREAMING,BT_PHY,BT_PHY_BR_1M_1SLOT,BT_PHY_BR_1M_3SLOT,BT_PHY_BR_1M_5SLOT,BT_PHY_EDR_2M_1SLOT,BT_PHY_EDR_2M_3SLOT,BT_PHY_EDR_2M_5SLOT,BT_PHY_EDR_3M_1SLOT,BT_PHY_EDR_3M_3SLOT,BT_PHY_EDR_3M_5SLOT,BT_PHY_LE_1M_RX,BT_PHY_LE_1M_TX,BT_PHY_LE_2M_RX,BT_PHY_LE_2M_TX,BT_PHY_LE_CODED_RX,BT_PHY_LE_CODED_TX,BT_PKT_STATUS,BT_POWER,BT_POWER_FORCE_ACTIVE_OFF,BT_POWER_FORCE_ACTIVE_ON,BT_RCVMTU,BT_SECURITY,BT_SECURITY_FIPS,BT_SECURITY_HIGH,BT_SECURITY_LOW,BT_SECURITY_MEDIUM,BT_SECURITY_SDP,BT_SNDMTU,BT_VOICE,BT_VOICE_CVSD_16BIT,BT_VOICE_TRANSPARENT,BT_VOICE_TRANSPARENT_16BIT,HCI_CHANNEL_CONTROL,HCI_CHANNEL_LOGGING,HCI_CHANNEL_MONITOR,HCI_CHANNEL_RAW,HCI_CHANNEL_USER,HCI_DEV_NONE - TODO: need someone with BSD to do a runtime check there
Runtime tests where info above comes from:
Windows 11
Python 3.14.2 (tags/v3.14.2:df79316, Dec 5 2025, 17:18:21) [MSC v.1944 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> [x for x in socket.__all__ if x.startswith("SOL_")]
['SOL_IP', 'SOL_RFCOMM', 'SOL_SOCKET', 'SOL_TCP', 'SOL_UDP']
>>> socket.SOL_RFCOMM
3
>>> [x for x in socket.__all__ if x.startswith("SO_")]
['SO_ACCEPTCONN', 'SO_BROADCAST', 'SO_BTH_ENCRYPT', 'SO_BTH_MTU', 'SO_BTH_MTU_MAX', 'SO_BTH_MTU_MIN', 'SO_DEBUG', 'SO_DONTROUTE', 'SO_ERROR', 'SO_EXCLUSIVEADDRUSE', 'SO_KEEPALIVE', 'SO_LINGER', 'SO_OOBINLINE', 'SO_ORIGINAL_DST', 'SO_RCVBUF', 'SO_RCVLOWAT', 'SO_RCVTIMEO', 'SO_REUSEADDR', 'SO_SNDBUF', 'SO_SNDLOWAT', 'SO_SNDTIMEO', 'SO_TYPE', 'SO_USELOOPBACK']
>>> socket.SO_BTH_ENCRYPT, socket.SO_BTH_MTU, socket.SO_BTH_MTU_MAX, socket.SO_BTH_MTU_MIN
(2, -2147483641, -2147483640, -2147483638)
Debian Testing
Python 3.14.2 (main, Dec 8 2025, 11:53:33) [GCC 15.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> [x for x in socket.__all__ if x.startswith("BDADDR_")]
['BDADDR_ANY', 'BDADDR_BREDR', 'BDADDR_LE_PUBLIC', 'BDADDR_LE_RANDOM', 'BDADDR_LOCAL']
>>> socket.BDADDR_BREDR, socket.BDADDR_LE_PUBLIC, socket.BDADDR_LE_RANDOM
(0, 1, 2)
>>> [x for x in socket.__all__ if x.startswith("SO_")]
['SO_ACCEPTCONN', 'SO_BINDTODEVICE', 'SO_BINDTOIFINDEX', 'SO_BROADCAST', 'SO_DEBUG', 'SO_DOMAIN', 'SO_DONTROUTE', 'SO_ERROR', 'SO_INCOMING_CPU', 'SO_J1939_ERRQUEUE', 'SO_J1939_FILTER', 'SO_J1939_PROMISC', 'SO_J1939_SEND_PRIO', 'SO_KEEPALIVE', 'SO_LINGER', 'SO_MARK', 'SO_OOBINLINE', 'SO_ORIGINAL_DST', 'SO_PASSCRED', 'SO_PASSSEC', 'SO_PEERCRED', 'SO_PEERSEC', 'SO_PRIORITY', 'SO_PROTOCOL', 'SO_RCVBUF', 'SO_RCVLOWAT', 'SO_RCVTIMEO', 'SO_REUSEADDR', 'SO_REUSEPORT', 'SO_SNDBUF', 'SO_SNDLOWAT', 'SO_SNDTIMEO', 'SO_TYPE', 'SO_VM_SOCKETS_BUFFER_MAX_SIZE', 'SO_VM_SOCKETS_BUFFER_MIN_SIZE', 'SO_VM_SOCKETS_BUFFER_SIZE']
>>> {x: eval(f"socket.{x}") for x in socket.__all__ if x.startswith("SOL_")}
{'SOL_ALG': 279, 'SOL_BLUETOOTH': 274, 'SOL_CAN_BASE': 100, 'SOL_CAN_RAW': 101, 'SOL_HCI': 0, 'SOL_IP': 0, 'SOL_L2CAP': 6, 'SOL_RDS': 276, 'SOL_RFCOMM': 18, 'SOL_SCO': 17, 'SOL_SOCKET': 1, 'SOL_TCP': 6, 'SOL_TIPC': 271, 'SOL_UDP': 17}
>>> {x: eval(f"socket.{x}") for x in socket.__all__ if x.startswith("L2CAP_")}
{'L2CAP_LM': 3, 'L2CAP_LM_AUTH': 2, 'L2CAP_LM_ENCRYPT': 4, 'L2CAP_LM_MASTER': 1, 'L2CAP_LM_RELIABLE': 16, 'L2CAP_LM_SECURE': 32, 'L2CAP_LM_TRUSTED': 8}
>>> {x: eval(f"socket.{x}") for x in socket.__all__ if x.startswith("BT_")}
{'BT_CHANNEL_POLICY': 10, 'BT_CHANNEL_POLICY_BREDR_ONLY': 0, 'BT_CHANNEL_POLICY_BREDR_PREFERRED': 1, 'BT_CODEC': 19, 'BT_DEFER_SETUP': 7, 'BT_FLUSHABLE': 8, 'BT_FLUSHABLE_OFF': 0, 'BT_FLUSHABLE_ON': 1, 'BT_ISO_QOS': 17, 'BT_MODE': 15, 'BT_MODE_BASIC': 0, 'BT_MODE_ERTM': 1, 'BT_MODE_EXT_FLOWCTL': 4, 'BT_MODE_LE_FLOWCTL': 3, 'BT_MODE_STREAMING': 2, 'BT_PHY': 14, 'BT_PHY_BR_1M_1SLOT': 1, 'BT_PHY_BR_1M_3SLOT': 2, 'BT_PHY_BR_1M_5SLOT': 4, 'BT_PHY_EDR_2M_1SLOT': 8, 'BT_PHY_EDR_2M_3SLOT': 16, 'BT_PHY_EDR_2M_5SLOT': 32, 'BT_PHY_EDR_3M_1SLOT': 64, 'BT_PHY_EDR_3M_3SLOT': 128, 'BT_PHY_EDR_3M_5SLOT': 256, 'BT_PHY_LE_1M_RX': 1024, 'BT_PHY_LE_1M_TX': 512, 'BT_PHY_LE_2M_RX': 4096, 'BT_PHY_LE_2M_TX': 2048, 'BT_PHY_LE_CODED_RX': 16384, 'BT_PHY_LE_CODED_TX': 8192, 'BT_PKT_STATUS': 16, 'BT_POWER': 9, 'BT_POWER_FORCE_ACTIVE_OFF': 0, 'BT_POWER_FORCE_ACTIVE_ON': 1, 'BT_RCVMTU': 13, 'BT_SECURITY': 4, 'BT_SECURITY_FIPS': 4, 'BT_SECURITY_HIGH': 3, 'BT_SECURITY_LOW': 1, 'BT_SECURITY_MEDIUM': 2, 'BT_SECURITY_SDP': 0, 'BT_SNDMTU': 12, 'BT_VOICE': 11, 'BT_VOICE_CVSD_16BIT': 96, 'BT_VOICE_TRANSPARENT': 3, 'BT_VOICE_TRANSPARENT_16BIT': 99}
>>> {x: eval(f"socket.{x}") for x in socket.__all__ if x.startswith("HCI_")}
{'HCI_CHANNEL_CONTROL': 3, 'HCI_CHANNEL_LOGGING': 4, 'HCI_CHANNEL_MONITOR': 2, 'HCI_CHANNEL_RAW': 0, 'HCI_CHANNEL_USER': 1, 'HCI_DATA_DIR': 1, 'HCI_DEV_NONE': 65535, 'HCI_FILTER': 2, 'HCI_TIME_STAMP': 3}
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
stubs: incompleteAnnotations or sub-modules missing from an existing package or moduleAnnotations or sub-modules missing from an existing package or module
Activity
srittau commentedon Jan 15, 2026
Any PRs to add missing items are welcome!
Divyanshudevtalla commentedon Jan 27, 2026
Hi! I’m new to typeshed and would like to work on this issue if it`s still available.
srittau commentedon Jan 27, 2026
All typeshed issues are free-for-all, unless they are specifically assigned to some one.
dlech commentedon Jan 27, 2026
@Divyanshudevtalla, if you are going to work on this, I suggest to read the discussion in #15209. It will help to understand some of the thinking behind why some of the Bluetooth stuff is the way it is in the code. It is a bit unusual because some builds of Python don't include these Bluetooth constants (like the ones on GitHub CI and the ones installed by
uv) in addition to the cross-platform and Python version considerations.Divyanshudevtalla commentedon Jan 27, 2026
Hi @dlech, thank you for the guidance! I've read through the discussion in #15209 and have followed the suggested approach for organizing these constants. I have now raised a Pull Request here: #15330 (comment) l. Could you please take a look when you have a moment? Thanks!
Divyanshudevtalla commentedon Jan 28, 2026
Hi @dlech, I have been working on resolving the CI failures and have managed to clear about 44 of them. I've added the Bluetooth constants to socket.pyi and _socket.pyi under the (3, 14) guard and updated the stubtest allowlist.
However, I'm currently stuck with 19 remaining failures related to redefinition errors. Even though I've removed the duplicate blocks I found, the logs still show conflicts between the new definitions (Line 586) and existing ones (Line 677).
Since I'm a student contributor, could you please guide me on whether I should be moving the existing constants into the new version-guarded block, or if there's a specific organization for these Bluetooth stubs that I'm missing? Thank you for your patience!
Divyanshudevtalla commentedon Jan 28, 2026
Hi @dlech, I've realized that my current branch has become quite cluttered with merge conflicts and duplicate constants, which is causing many of the current CI failures.
I've learned a lot about the typeshed workflow and Git commands like commit --amend and push --force during this process. To ensure the final contribution is clean and professional, I would like to restart this repository from a fresh branch. I'm confident I can apply what I've learned to work more effectively this time. Thank you for your patience
dlech commentedon Jun 11, 2026
I suggest to re-open this since only Linux was addressed in the commit that automatically closed the issue.