diff -Naur PyBluez-0.23/bluez/btmodule.c PyBluez-0.23.new/bluez/btmodule.c
--- PyBluez-0.23/bluez/btmodule.c	2019-12-28 01:54:22.000000000 +0100
+++ PyBluez-0.23.new/bluez/btmodule.c	2022-12-11 16:47:52.974915482 +0100
@@ -16,10 +16,13 @@
 - names starting with bt_ are module-level functions
 
 */
-
+#define PY_SSIZE_T_CLEAN 1
+#include "Python.h"
 #include "btmodule.h"
 #include "structmember.h"
 
+#include "pythoncapi_compat.h"
+
 #include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
@@ -41,7 +44,6 @@
 #include <bluetooth/l2cap.h>
 #include <bluetooth/sco.h>
 
-#include <port3.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 #include "btsdp.h"
@@ -212,7 +214,7 @@
         switch(s->sock_proto) {
             case BTPROTO_HCI:
                 {
-                    return Py_BuildValue("H", 
+                    return Py_BuildValue("H",
                             ((struct sockaddr_hci*)(addr))->hci_dev );
                 }
             case BTPROTO_L2CAP:
@@ -234,7 +236,7 @@
                     return Py_BuildValue("s", ba_name);
                 }
             default:
-                PyErr_SetString(bluetooth_error, 
+                PyErr_SetString(bluetooth_error,
                         "getsockaddrarg: unknown Bluetooth protocol");
                 return 0;
         }
@@ -329,7 +331,7 @@
             }
         default:
             {
-                PyErr_SetString(bluetooth_error, 
+                PyErr_SetString(bluetooth_error,
                         "getsockaddrarg: unknown Bluetooth protocol");
                 return 0;
             }
@@ -418,7 +420,6 @@
     /* get ba */
     if(getsockname(socko->sock_fd, &addr, &alen) < 0)
         return -1;
-        
     switch(socko->sock_proto)
     {
     case BTPROTO_L2CAP:
@@ -480,7 +481,7 @@
             *len_ret = sizeof (struct sockaddr_hci);
             return 1;
         default:
-            PyErr_SetString(bluetooth_error, 
+            PyErr_SetString(bluetooth_error,
                     "getsockaddrlen: unknown bluetooth protocol");
             return 0;
     }
@@ -544,18 +545,14 @@
 int
 pyunicode2uuid( PyObject *item, uuid_t *uuid )
 {
-#if PY_MAJOR_VERSION >= 3
     PyObject* ascii = PyUnicode_AsASCIIString( item );
     int ret =  str2uuid( PyBytes_AsString( ascii ), uuid );
     Py_XDECREF( ascii );
     return ret;
-#else
-    return str2uuid( PyString_AsString( item ), NULL );
-#endif
 }
 
 void
-uuid2str( const uuid_t *uuid, char *dest ) 
+uuid2str( const uuid_t *uuid, char *dest )
 {
     if( uuid->type == SDP_UUID16 ) {
         sprintf(dest, "%04X", uuid->value.uuid16 );
@@ -564,11 +561,11 @@
     } else if( uuid->type == SDP_UUID128 ) {
         uint32_t *data = (uint32_t*)(&uuid->value.uuid128);
         sprintf(dest, "%08X-%04X-%04X-%04X-%04X%08X",
-                ntohl(data[0]), 
-                ntohl(data[1])>>16, 
+                ntohl(data[0]),
+                ntohl(data[1])>>16,
                 (ntohl(data[1])<<16)>>16,
-                ntohl(data[2])>>16, 
-                (ntohl(data[2])<<16)>>16, 
+                ntohl(data[2])>>16,
+                (ntohl(data[2])<<16)>>16,
                 ntohl(data[3]));
     }
 }
@@ -649,7 +646,7 @@
 {
 	int block;
 
-	block = PyInt_AsLong(arg);
+	block = PyLong_AsLong(arg);
 	if (block == -1 && PyErr_Occurred())
 		return NULL;
 
@@ -677,7 +674,7 @@
 {
 	double timeout;
 
-	if (arg == Py_None)
+	if (Py_IsNone(arg))
 		timeout = -1.0;
 	else {
 		timeout = PyFloat_AsDouble(arg);
@@ -732,7 +729,7 @@
     int optname;
     int res;
     void *buf;
-    int buflen;
+    Py_ssize_t buflen;
     int flag;
 
     if (PyArg_ParseTuple(args, "iii:setsockopt", &level, &optname, &flag)) {
@@ -779,21 +776,21 @@
 		res = getsockopt(s->sock_fd, level, optname, (void *)&flag, &flagsize);
 		if (res < 0)
 			return s->errorhandler();
-		return PyInt_FromLong(flag);
+		return PyLong_FromLong(flag);
     } else if (buflen <= 0 || buflen > 1024) {
         PyErr_SetString(bluetooth_error, "getsockopt buflen out of range");
         return NULL;
     } else {
-        PyObject *buf = PyString_FromStringAndSize((char *)NULL, buflen);
+        PyObject *buf = PyBytes_FromStringAndSize((char *)NULL, buflen);
         if (buf == NULL)
             return NULL;
         res = getsockopt(s->sock_fd, level, optname,
-                 (void *)PyString_AS_STRING(buf), &buflen);
+                 (void *)PyBytes_AS_STRING(buf), &buflen);
         if (res < 0) {
             Py_DECREF(buf);
             return s->errorhandler();
         }
-        _PyString_Resize(&buf, buflen);
+        _PyBytes_Resize(&buf, buflen);
         return buf;
 	}
     return NULL;
@@ -982,7 +979,7 @@
 	res = internal_connect(s, &addr, addrlen, &timeout);
 	Py_END_ALLOW_THREADS
 
-	return PyInt_FromLong((long) res);
+	return PyLong_FromLong((long) res);
 }
 
 PyDoc_STRVAR(connect_ex_doc,
@@ -997,7 +994,7 @@
 static PyObject *
 sock_fileno(PySocketSockObject *s)
 {
-	return PyInt_FromLong((long) s->sock_fd);
+	return PyLong_FromLong((long) s->sock_fd);
 }
 
 PyDoc_STRVAR(fileno_doc,
@@ -1098,7 +1095,7 @@
 	int backlog;
 	int res;
 
-	backlog = PyInt_AsLong(arg);
+	backlog = PyLong_AsLong(arg);
 	if (backlog == -1 && PyErr_Occurred())
 		return NULL;
 	Py_BEGIN_ALLOW_THREADS
@@ -1147,13 +1144,7 @@
 			close(fd);
 		return s->errorhandler();
 	}
-#if PY_MAJOR_VERSION >= 3
 	f = PyFile_FromFd(fd, "<socket>", mode, bufsize, NULL, NULL, NULL, 1);
-#else
-	f = PyFile_FromFile(fp, "<socket>", mode, fclose);
-	if (f != NULL)
-		PyFile_SetBufSize(f, bufsize);
-#endif
 	return f;
 }
 
@@ -1182,14 +1173,14 @@
 		return NULL;
 	}
 
-	buf = PyString_FromStringAndSize((char *) 0, len);
+	buf = PyBytes_FromStringAndSize((char *) 0, len);
 	if (buf == NULL)
 		return NULL;
 
 	Py_BEGIN_ALLOW_THREADS
 	timeout = internal_select(s, 0);
 	if (!timeout)
-		n = recv(s->sock_fd, PyString_AS_STRING(buf), len, flags);
+		n = recv(s->sock_fd, PyBytes_AS_STRING(buf), len, flags);
 	Py_END_ALLOW_THREADS
 
 	if (timeout) {
@@ -1202,7 +1193,7 @@
 		return s->errorhandler();
 	}
 	if (n != len)
-		_PyString_Resize(&buf, n);
+		_PyBytes_Resize(&buf, n);
 	return buf;
 }
 
@@ -1232,7 +1223,7 @@
 
 	if (!getsockaddrlen(s, &addrlen))
 		return NULL;
-	buf = PyString_FromStringAndSize((char *) 0, len);
+	buf = PyUnicode_FromStringAndSize((char *) 0, len);
 	if (buf == NULL)
 		return NULL;
 
@@ -1240,7 +1231,7 @@
 	memset(addrbuf, 0, addrlen);
 	timeout = internal_select(s, 0);
 	if (!timeout)
-		n = recvfrom(s->sock_fd, PyString_AS_STRING(buf), len, flags,
+		n = recvfrom(s->sock_fd, PyBytes_AS_STRING(buf), len, flags,
 			     (void *)addrbuf, &addrlen
 			);
 	Py_END_ALLOW_THREADS
@@ -1255,7 +1246,7 @@
 		return s->errorhandler();
 	}
 
-	if (n != len && _PyString_Resize(&buf, n) < 0)
+	if (n != len && _PyBytes_Resize(&buf, n) < 0)
 		return NULL;
 
 	if (!(addr = makesockaddr(s, (struct sockaddr *)addrbuf, addrlen)))
@@ -1279,17 +1270,18 @@
 static PyObject *
 sock_send(PySocketSockObject *s, PyObject *args)
 {
-	char *buf;
-	int len, n = 0, flags = 0, timeout;
+	Py_buffer buf;
+	int n = 0, flags = 0, timeout;
 
-	if (!PyArg_ParseTuple(args, "s#|i:send", &buf, &len, &flags))
+	if (!PyArg_ParseTuple(args, "s*|i:send", &buf, &flags))
 		return NULL;
 
 	Py_BEGIN_ALLOW_THREADS
 	timeout = internal_select(s, 1);
 	if (!timeout)
-		n = send(s->sock_fd, buf, len, flags);
+		n = send(s->sock_fd, buf.buf, buf.len, flags);
 	Py_END_ALLOW_THREADS
+	PyBuffer_Release(&buf);
 
 	if (timeout) {
 		PyErr_SetString(socket_timeout, "timed out");
@@ -1297,7 +1289,7 @@
 	}
 	if (n < 0)
 		return s->errorhandler();
-	return PyInt_FromLong((long)n);
+	return PyLong_FromLong((long)n);
 }
 
 PyDoc_STRVAR(send_doc,
@@ -1313,24 +1305,29 @@
 static PyObject *
 sock_sendall(PySocketSockObject *s, PyObject *args)
 {
-	char *buf;
+	Py_buffer buf;
+	char *raw_buf;
 	int len, n = 0, flags = 0, timeout;
 
-	if (!PyArg_ParseTuple(args, "s#|i:sendall", &buf, &len, &flags))
+	if (!PyArg_ParseTuple(args, "s*|i:sendall", &buf, &flags))
 		return NULL;
 
 	Py_BEGIN_ALLOW_THREADS
+	raw_buf = buf.buf;
+	len = buf.len;
 	do {
 		timeout = internal_select(s, 1);
 		if (timeout)
 			break;
-		n = send(s->sock_fd, buf, len, flags);
+		n = send(s->sock_fd, raw_buf, len, flags);
 		if (n < 0)
 			break;
-		buf += n;
+		raw_buf += n;
 		len -= n;
 	} while (len > 0);
+	raw_buf = NULL;
 	Py_END_ALLOW_THREADS
+	PyBuffer_Release(&buf);
 
 	if (timeout) {
 		PyErr_SetString(socket_timeout, "timed out");
@@ -1357,14 +1354,14 @@
 sock_sendto(PySocketSockObject *s, PyObject *args)
 {
 	PyObject *addro;
-	char *buf;
+	Py_buffer buf;
 	struct sockaddr addr = { 0 };
-	int addrlen, len, n = 0, flags, timeout;
+	int addrlen, n = 0, flags, timeout;
 
 	flags = 0;
-	if (!PyArg_ParseTuple(args, "s#O:sendto", &buf, &len, &addro)) {
+	if (!PyArg_ParseTuple(args, "s*O:sendto", &buf, &addro)) {
 		PyErr_Clear();
-		if (!PyArg_ParseTuple(args, "s#iO:sendto", &buf, &len, &flags, &addro))
+		if (!PyArg_ParseTuple(args, "s*iO:sendto", &buf, &flags, &addro))
 			return NULL;
 	}
 
@@ -1374,8 +1371,9 @@
 	Py_BEGIN_ALLOW_THREADS
 	timeout = internal_select(s, 1);
 	if (!timeout)
-		n = sendto(s->sock_fd, buf, len, flags, &addr, addrlen);
+		n = sendto(s->sock_fd, buf.buf, buf.len, flags, &addr, addrlen);
 	Py_END_ALLOW_THREADS
+	PyBuffer_Release(&buf);
 
 	if (timeout) {
 		PyErr_SetString(socket_timeout, "timed out");
@@ -1383,7 +1381,7 @@
 	}
 	if (n < 0)
 		return s->errorhandler();
-	return PyInt_FromLong((long)n);
+	return PyLong_FromLong((long)n);
 }
 
 PyDoc_STRVAR(sendto_doc,
@@ -1401,7 +1399,7 @@
 	int how;
 	int res;
 
-	how = PyInt_AsLong(arg);
+	how = PyLong_AsLong(arg);
 	if (how == -1 && PyErr_Occurred())
 		return NULL;
 	Py_BEGIN_ALLOW_THREADS
@@ -1512,7 +1510,7 @@
 		close(s->sock_fd);
         Py_END_ALLOW_THREADS
     }
-    
+
     if( s->sdp_session ) {
         sdp_close( s->sdp_session );
         s->sdp_record_handle = 0;
@@ -1544,7 +1542,7 @@
 		(long)s->sock_fd, s->sock_family,
 		s->sock_type,
 		s->sock_proto);
-	return PyString_FromString(buf);
+	return PyUnicode_FromString(buf);
 }
 
 
@@ -1617,12 +1615,7 @@
 /* Type object for socket objects. */
 
 PyTypeObject sock_type = {
-#if PY_MAJOR_VERSION < 3
-	PyObject_HEAD_INIT(0)	/* Must fill in type value later */
-	0,					/* ob_size */
-#else
     PyVarObject_HEAD_INIT(NULL, 0)   /* Must fill in type value later */
-#endif
 	"_bluetooth.btsocket",			/* tp_name */
 	sizeof(PySocketSockObject),		/* tp_basicsize */
 	0,					/* tp_itemsize */
@@ -1708,7 +1701,7 @@
 		return NULL;
 	}
 	x2 = (int)btohs((short)x1);
-	return PyInt_FromLong(x2);
+	return PyLong_FromLong(x2);
 }
 
 PyDoc_STRVAR(bt_btohs_doc,
@@ -1722,13 +1715,13 @@
 {
 	unsigned long x;
 	PyObject *arg;
-	
+
 	if (!PyArg_ParseTuple(args, "O:btohl", &arg)) {
 		return NULL;
 	}
 
-	if (PyInt_Check(arg)) {
-		x = PyInt_AS_LONG(arg);
+	if (PyLong_Check(arg)) {
+		x = PyLong_AS_LONG(arg);
 		if (x == (unsigned long) -1 && PyErr_Occurred())
 			return NULL;
 	}
@@ -1751,10 +1744,10 @@
 	else
 		return PyErr_Format(PyExc_TypeError,
 				    "expected int/long, %s found",
-				    arg->ob_type->tp_name);
+				    Py_TYPE(arg)->tp_name);
 	if (x == (unsigned long) -1 && PyErr_Occurred())
 		return NULL;
-	return PyInt_FromLong(btohl(x));
+	return PyLong_FromLong(btohl(x));
 }
 
 PyDoc_STRVAR(bt_btohl_doc,
@@ -1772,7 +1765,7 @@
 		return NULL;
 	}
 	x2 = (int)htobs((short)x1);
-	return PyInt_FromLong(x2);
+	return PyLong_FromLong(x2);
 }
 
 PyDoc_STRVAR(bt_htobs_doc,
@@ -1791,8 +1784,8 @@
 		return NULL;
 	}
 
-	if (PyInt_Check(arg)) {
-		x = PyInt_AS_LONG(arg);
+	if (PyLong_Check(arg)) {
+		x = PyLong_AS_LONG(arg);
 		if (x == (unsigned long) -1 && PyErr_Occurred())
 			return NULL;
 	}
@@ -1815,8 +1808,8 @@
 	else
 		return PyErr_Format(PyExc_TypeError,
 				    "expected int/long, %s found",
-				    arg->ob_type->tp_name);
-	return PyInt_FromLong(htobl(x));
+				    Py_TYPE(arg)->tp_name);
+	return PyLong_FromLong(htobl(x));
 }
 
 //static PyObject *
@@ -1825,7 +1818,7 @@
 //	int protocol = -1;
 //    int s;
 //
-//	protocol = PyInt_AsLong(arg);
+//	protocol = PyLong_AsLong(arg);
 //
 //	if (protocol == -1 && PyErr_Occurred())
 //		return NULL;
@@ -1838,7 +1831,7 @@
 //                s = socket( AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM );
 //
 //                sockaddr.rc_family = AF_BLUETOOTH;
-//                bacppy( &sockaddr.rc_bdaddr, BDADDR_ANY 
+//                bacppy( &sockaddr.rc_bdaddr, BDADDR_ANY
 //            }
 //            break;
 //        case BTPROTO_L2CAP:
@@ -1851,7 +1844,7 @@
 //            break;
 //        default:
 //            {
-//                PyErr_SetString( PyExc_ValueError, 
+//                PyErr_SetString( PyExc_ValueError,
 //                        "protocol must be either RFCOMM or L2CAP" );
 //                return 0;
 //            }
@@ -1888,7 +1881,7 @@
 {
 	double timeout;
 
-	if (arg == Py_None)
+	if (Py_IsNone(arg))
 		timeout = -1.0;
 	else {
 		timeout = PyFloat_AsDouble(arg);
@@ -1914,13 +1907,13 @@
 /*
  * ----------------------------------------------------------------------
  *  HCI Section   (Calvin)
- *  
+ *
  *  This section provides the socket methods for calling HCI commands.
  *  These commands may be called statically, and implementation is
  *  independent from the rest of the module (except for bt_methods[]).
  *
  * ----------------------------------------------------------------------
- *  
+ *
  */
 
 /*
@@ -1933,7 +1926,7 @@
 {
     int dev = -1, fd;
 	PySocketSockObject *s = NULL;
-    
+
     if ( !PyArg_ParseTuple(args, "|i", &dev) )
     {
         return NULL;
@@ -1948,7 +1941,7 @@
         PyErr_SetString(bluetooth_error, "no available bluetoot devices");
         return 0;
     }
-    
+
     Py_BEGIN_ALLOW_THREADS
     fd = hci_open_dev(dev);
     Py_END_ALLOW_THREADS
@@ -1969,7 +1962,7 @@
 bt_hci_close_dev(PyObject *self, PyObject *args)
 {
     int dev, err;
-    
+
     if ( !PyArg_ParseTuple(args, "i", &dev) )
     {
         return NULL;
@@ -1980,11 +1973,11 @@
     Py_END_ALLOW_THREADS
 
     if( err < 0 ) return set_error();
-    
+
     Py_RETURN_NONE;
 }
 
-PyDoc_STRVAR(bt_hci_close_dev_doc, 
+PyDoc_STRVAR(bt_hci_close_dev_doc,
 "hci_close_dev(dev_id)\n\
 \n\
 Closes the specified device id.  Note:  device id is NOT a btoscket.\n\
@@ -2001,11 +1994,12 @@
 bt_hci_send_cmd(PyObject *self, PyObject *args)
 {
     PySocketSockObject *socko = NULL;
-    int err, plen = 0;
+    int err;
+    Py_ssize_t plen = 0;
     uint16_t ogf, ocf;
     char *param = NULL;
     int dd = 0;
-    
+
     if ( !PyArg_ParseTuple(args, "OHH|s#", &socko, &ogf, &ocf, &param, &plen)) {
         return NULL;
     }
@@ -2021,7 +2015,7 @@
     return Py_BuildValue("i", err);
 }
 
-PyDoc_STRVAR(bt_hci_send_cmd_doc, 
+PyDoc_STRVAR(bt_hci_send_cmd_doc,
 "hci_send_cmd(sock, ogf, ocf, params)\n\
 \n\
 Transmits the specified HCI command to the socket.\n\
@@ -2036,6 +2030,7 @@
     int err;
     int to=0;
     char rparam[256];
+    Py_ssize_t req_clen;
     struct hci_request req = { 0 };
     int dd = 0;
 
@@ -2043,9 +2038,10 @@
                                 "timeout", 0 };
 
     if( !PyArg_ParseTupleAndKeywords(args, kwds, "OHHii|s#i", keywords,
-                &socko, &req.ogf, &req.ocf, &req.event, &req.rlen, 
-                &req.cparam, &req.clen, &to) )
+                &socko, &req.ogf, &req.ocf, &req.event, &req.rlen,
+                &req.cparam, &req_clen, &to) )
         return 0;
+    req.clen = req_clen;
 
     req.rparam = rparam;
     dd = socko->sock_fd;
@@ -2056,7 +2052,7 @@
 
     if( err< 0 ) return socko->errorhandler();
 
-    return PyString_FromStringAndSize(rparam, req.rlen);
+    return PyUnicode_FromStringAndSize(rparam, req.rlen);
 }
 PyDoc_STRVAR(bt_hci_send_req_doc,
 "hci_send_req(sock, ogf, ocf, event, rlen, params=None, timeout=0)\n\
@@ -2128,8 +2124,8 @@
         int err;
 
         ba2str( &(info+i)->bdaddr, ba_name );
-        
-        addr_entry = PyString_FromString( ba_name );
+
+        addr_entry = PyUnicode_FromString( ba_name );
 
         if (lookup_class) {
             PyObject *item_tuple = PyTuple_New(2);
@@ -2137,7 +2133,7 @@
             int dev_class = (info+i)->dev_class[2] << 16 |
                             (info+i)->dev_class[1] << 8 |
                             (info+i)->dev_class[0];
-            PyObject *class_entry = PyInt_FromLong( dev_class );
+            PyObject *class_entry = PyLong_FromLong( dev_class );
 
             err = PyTuple_SetItem( item_tuple, 0, addr_entry );
             if (err) {
@@ -2173,7 +2169,7 @@
     return rtn_list;
 }
 
-PyDoc_STRVAR(bt_hci_inquiry_doc, 
+PyDoc_STRVAR(bt_hci_inquiry_doc,
 "hci_inquiry(dev_id=0, duration=8, flush_cache=True\n\
 \n\
 Performs a device inquiry using the specified device (usually 0 or 1).\n\
@@ -2203,14 +2199,14 @@
     memset( name, 0, sizeof(name) );
 
     Py_BEGIN_ALLOW_THREADS
-    err = hci_read_remote_name( socko->sock_fd, &ba, sizeof(name)-1, 
+    err = hci_read_remote_name( socko->sock_fd, &ba, sizeof(name)-1,
                 name, timeout );
     Py_END_ALLOW_THREADS
 
-    if( err < 0) 
+    if( err < 0)
         return PyErr_SetFromErrno(bluetooth_error);
 
-    return PyString_FromString( name );
+    return PyUnicode_FromString( name );
 }
 PyDoc_STRVAR(bt_hci_read_remote_name_doc,
 "hci_read_remote_name(sock, bdaddr, timeout=5192)\n\
@@ -2232,7 +2228,7 @@
         // DPRINTF("opcode = %x\n", opcode);
         const char* cmd_name = opcode2str (opcode);
 
-    return PyString_FromString( cmd_name );
+    return PyUnicode_FromString( cmd_name );
 }
 PyDoc_STRVAR(bt_hci_opcode_name_doc,
 "hci_opcode_name(opcode)\n\
@@ -2258,7 +2254,7 @@
            return 0;
    }
    const char* event_name = event_str[eventNum];
-   return PyString_FromString( event_name );
+   return PyUnicode_FromString( event_name );
 }
 PyDoc_STRVAR(bt_hci_event_name_doc,
 "hci_event_name(eventNum)\n\
@@ -2274,7 +2270,8 @@
 static PyObject * bt_hci_filter_ ## name (PyObject *self, PyObject *args )\
 { \
     char *param; \
-    int len, arg; \
+    Py_ssize_t len; \
+    int arg; \
     if( !PyArg_ParseTuple(args,"s#i", &param, &len, &arg) ) \
         return 0; \
     if( len != sizeof(struct hci_filter) ) { \
@@ -2282,7 +2279,7 @@
         return 0; \
     } \
     hci_filter_ ## name ( arg, (struct hci_filter*)param ); \
-    return PyString_FromStringAndSize(param, len); \
+    return PyUnicode_FromStringAndSize(param, len); \
 } \
 PyDoc_STRVAR(bt_hci_filter_ ## name ## _doc, docstring);
 
@@ -2303,7 +2300,7 @@
 static PyObject * bt_hci_filter_ ## name (PyObject *self, PyObject *args )\
 { \
     char *param; \
-    int len; \
+    Py_ssize_t len; \
     if( !PyArg_ParseTuple(args,"s#", &param, &len) ) \
         return 0; \
     if( len != sizeof(struct hci_filter) ) { \
@@ -2311,7 +2308,7 @@
         return 0; \
     } \
     hci_filter_ ## name ( (struct hci_filter*)param ); \
-    return PyString_FromStringAndSize(param, len); \
+    return PyUnicode_FromStringAndSize(param, len); \
 } \
 PyDoc_STRVAR(bt_hci_filter_ ## name ## _doc, docstring);
 
@@ -2323,7 +2320,7 @@
 #undef DECL_HCI_FILTER_OP_2
 
 static PyObject *
-bt_cmd_opcode_pack(PyObject *self, PyObject *args ) 
+bt_cmd_opcode_pack(PyObject *self, PyObject *args )
 {
     uint16_t opcode, ogf, ocf;
     if (!PyArg_ParseTuple(args, "HH", &ogf, &ocf )) return 0;
@@ -2364,18 +2361,18 @@
 bt_ba2str(PyObject *self, PyObject *args)
 {
     char *data=NULL;
-    int len=0;
+    Py_ssize_t len=0;
     char ba_str[19] = {0};
     if (!PyArg_ParseTuple(args, "s#", &data, &len)) return 0;
     ba2str((bdaddr_t*)data, ba_str);
-    return PyString_FromString( ba_str );
+    return PyUnicode_FromString( ba_str );
 //    return Py_BuildValue("s#", ba_str, 18);
 }
 PyDoc_STRVAR(bt_ba2str_doc,
 "ba2str(data)\n\
 \n\
 Converts a packed bluetooth address to a human readable string");
-    
+
 static PyObject *
 bt_str2ba(PyObject *self, PyObject *args)
 {
@@ -2383,14 +2380,14 @@
     bdaddr_t ba;
     if (!PyArg_ParseTuple(args, "s", &ba_str)) return 0;
     str2ba( ba_str, &ba );
-    return Py_BuildValue(BYTES_FORMAT_CHR, (char*)(&ba), sizeof(ba));
+    return Py_BuildValue("y#", (char*)(&ba), sizeof(ba));
 }
 PyDoc_STRVAR(bt_str2ba_doc,
 "str2ba(string)\n\
 \n\
 Converts a bluetooth address string into a packed bluetooth address.\n\
 The string should be of the form \"XX:XX:XX:XX:XX:XX\"");
-    
+
 /*
  * params:  (string) device address
  * effect: -
@@ -2462,7 +2459,7 @@
     int which;
     int timeout;
     uint32_t btclock;
-    uint16_t accuracy; 
+    uint16_t accuracy;
     int res;
 
     if ( !PyArg_ParseTuple(args, "iiii", &fd, &handle, &which, &timeout) )
@@ -2502,7 +2499,7 @@
     if (dev_id < 0) {
         return PyErr_SetFromErrno(PyExc_OSError);
     }
-    return PyInt_FromLong(dev_id);
+    return PyLong_FromLong(dev_id);
 }
 PyDoc_STRVAR( bt_hci_get_route_doc,
 "hci_get_route(address)\n\
@@ -2561,6 +2558,85 @@
 methods, and for passing to getsockopt and setsockopt.  The filter is\n\
 initially cleared");
 
+
+static PyObject *
+bt_hci_le_add_white_list(PyObject *self, PyObject *args)
+{
+    PySocketSockObject *socko = NULL;
+    int err = 0;
+    int to = 0;
+    char *addr = NULL;
+    bdaddr_t ba;
+    int dd = 0;
+    uint8_t type;
+
+    if ( !PyArg_ParseTuple(args, "OsHi", &socko, &addr, &type, &to) ) {
+        return NULL;
+    }
+    if ( addr && strlen(addr) ){
+        str2ba( addr, &ba );
+    }
+    else {
+        return NULL;
+    }
+
+    dd = socko->sock_fd;
+    err = hci_le_add_white_list(dd, &ba, type, to);
+    if ( err < 0 ) {
+        return NULL;
+    }
+
+    return Py_BuildValue("i", err);
+}
+
+PyDoc_STRVAR(bt_hci_le_add_white_list_doc,
+"hci_le_add_white_list( dd, btaddr, type, to )\n\
+\n\
+Add the given MAC to the LE scan white list");
+
+static PyObject *
+bt_hci_le_read_white_list_size(PyObject *self, PyObject *args)
+{
+    PySocketSockObject *socko = NULL;
+    int err = 0;
+    int to = 0;
+    uint8_t ret;
+    int  dd;
+    if ( !PyArg_ParseTuple(args, "Oi", &socko, &to) ) {
+        return NULL;
+    }
+    dd = socko->sock_fd;
+    err = hci_le_read_white_list_size(dd, &ret, to);
+    if ( err < 0 ) {
+        return NULL;
+    }
+    return Py_BuildValue("i", ret);
+}
+PyDoc_STRVAR(bt_hci_le_read_white_list_size_doc,
+"hci_le_read_white_list_size( dd, size, to )\n\
+\n\
+Read the total length of the LE scan white list. This is the length of the\n\
+empty list, not the total entries in the list");
+
+static PyObject *
+bt_hci_le_clear_white_list(PyObject *self, PyObject *args)
+{
+    PySocketSockObject *socko = NULL;
+    int err = 0;
+    int to = 0;
+    int dd;
+    if ( !PyArg_ParseTuple(args, "Oi", &socko, &to) ) {
+        return NULL;
+    }
+    dd = socko->sock_fd;
+    err = hci_le_clear_white_list(dd, to);
+    return Py_BuildValue("i", err);
+}
+PyDoc_STRVAR(bt_hci_le_clear_white_list_doc,
+"hci_le_clear_white_list( dd, to )\n\
+\n\
+Clears the LE scan white list");
+
 /*
  * -------------------
  *  End of HCI section
@@ -2574,12 +2650,12 @@
 bt_sdp_advertise_service( PyObject *self, PyObject *args )
 {
     PySocketSockObject *socko = NULL;
-    char *name = NULL, 
-         *service_id_str = NULL, 
-         *provider = NULL, 
+    char *name = NULL,
+         *service_id_str = NULL,
+         *provider = NULL,
          *description = NULL;
     PyObject *service_classes, *profiles, *protocols;
-    int namelen = 0, provlen = 0, desclen = 0;
+    Py_ssize_t namelen = 0, provlen = 0, desclen = 0;
     uuid_t svc_uuid = { 0 };
     int i;
     char addrbuf[256] = { 0 };
@@ -2587,10 +2663,10 @@
     socklen_t addrlen;
     struct sockaddr *sockaddr;
     uuid_t root_uuid, l2cap_uuid, rfcomm_uuid;
-    sdp_list_t *l2cap_list = 0, 
+    sdp_list_t *l2cap_list = 0,
                *rfcomm_list = 0,
                *root_list = 0,
-               *proto_list = 0, 
+               *proto_list = 0,
                *profile_list = 0,
                *svc_class_list = 0,
                *access_proto_list = 0;
@@ -2601,7 +2677,7 @@
     int err = 0;
 
     if (!PyArg_ParseTuple(args, "O!s#sOOs#s#O", &sock_type, &socko, &name,
-                &namelen, &service_id_str, &service_classes, 
+                &namelen, &service_id_str, &service_classes,
                 &profiles, &provider, &provlen, &description, &desclen,
                 &protocols)) {
         return 0;
@@ -2635,7 +2711,7 @@
     for(i = 0; i < PySequence_Length(service_classes); ++i) {
         PyObject *item = PySequence_GetItem(service_classes, i);
         if( ! pyunicode2uuid( item, NULL ) ) {
-            PyErr_SetString(PyExc_ValueError, 
+            PyErr_SetString(PyExc_ValueError,
                     "service_classes must be a list of "
                     "strings, each either of the form XXXX or "
                     "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
@@ -2653,17 +2729,17 @@
         char *profile_uuid_str = NULL;
         uint16_t version;
         PyObject *tuple = PySequence_GetItem(profiles, i);
-        if ( ( ! PySequence_Check(tuple) ) || 
-             ( ! PyArg_ParseTuple(tuple, "sH", 
-                 &profile_uuid_str, &version)) || 
-             ( ! str2uuid( profile_uuid_str, NULL ) ) 
+        if ( ( ! PySequence_Check(tuple) ) ||
+             ( ! PyArg_ParseTuple(tuple, "sH",
+                 &profile_uuid_str, &version)) ||
+             ( ! str2uuid( profile_uuid_str, NULL ) )
            ) {
-            PyErr_SetString(PyExc_ValueError, 
+            PyErr_SetString(PyExc_ValueError,
                     "Each profile must be a ('uuid', version) tuple");
             return 0;
         }
     }
-    
+
     // protocols must be a list / sequence
     if (! PySequence_Check(protocols)) {
         PyErr_SetString(PyExc_ValueError, "protocols must be a sequence");
@@ -2673,7 +2749,7 @@
     for(i = 0; i < PySequence_Length(protocols); ++i) {
         PyObject *item = PySequence_GetItem(protocols, i);
         if( ! pyunicode2uuid( item, NULL ) ) {
-            PyErr_SetString(PyExc_ValueError, 
+            PyErr_SetString(PyExc_ValueError,
                     "protocols must be a list of "
                     "strings, each either of the form XXXX or "
                     "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
@@ -2683,7 +2759,7 @@
 
     // verify that the socket is bound and listening
     if( ! socko->is_listening_socket ) {
-        PyErr_SetString(bluetooth_error, 
+        PyErr_SetString(bluetooth_error,
                 "must have already called socket.listen()");
         return 0;
     }
@@ -2709,9 +2785,9 @@
     sockaddr = (struct sockaddr *)addrbuf;
 
     // can only deal with L2CAP and RFCOMM sockets
-    if( socko->sock_proto != BTPROTO_L2CAP && 
+    if( socko->sock_proto != BTPROTO_L2CAP &&
             socko->sock_proto != BTPROTO_RFCOMM ) {
-        PyErr_SetString(bluetooth_error, 
+        PyErr_SetString(bluetooth_error,
                 "Sorry, can only advertise L2CAP and RFCOMM sockets for now");
         return 0;
     }
@@ -2726,7 +2802,7 @@
 
     // okay, now construct the SDP service record.
     memset( &record, 0, sizeof(sdp_record_t) );
-    
+
     record.handle = 0xffffffff;
 
     // make the service record publicly browsable
@@ -2756,7 +2832,7 @@
         psm = sdp_data_alloc(SDP_UINT16, &l2cap_psm);
         sdp_list_append(l2cap_list, psm);
     }
-    
+
     // add additional protocols, if any
     sdp_list_t *extra_protos_array[PySequence_Length(protocols)];
     if (PySequence_Length(protocols) > 0) {
@@ -2764,16 +2840,16 @@
             uuid_t *proto_uuid = (uuid_t*) malloc( sizeof( uuid_t ) );
             PyObject *item = PySequence_GetItem(protocols, i);
             pyunicode2uuid( item, proto_uuid );
-            
+
             sdp_list_t *new_list;
             new_list = sdp_list_append( 0, proto_uuid );
             proto_list = sdp_list_append( proto_list, new_list );
-            
+
             // keep track, to free the list later
             extra_protos_array[i] = new_list;
         }
     }
-    
+
     access_proto_list = sdp_list_append( 0, proto_list );
     sdp_set_access_protos( &record, access_proto_list );
 
@@ -2789,10 +2865,10 @@
     // add profiles, if any
     for(i = 0; i < PySequence_Length(profiles); i++) {
         char *profile_uuid_str;
-        sdp_profile_desc_t *profile_desc = 
+        sdp_profile_desc_t *profile_desc =
             (sdp_profile_desc_t*)malloc(sizeof(sdp_profile_desc_t));
         PyObject *tuple = PySequence_GetItem(profiles, i);
-        PyArg_ParseTuple(tuple, "sH", &profile_uuid_str, 
+        PyArg_ParseTuple(tuple, "sH", &profile_uuid_str,
                 &profile_desc->version);
         str2uuid( profile_uuid_str, &profile_desc->uuid );
         profile_list = sdp_list_append( profile_list, profile_desc );
@@ -2805,7 +2881,7 @@
     // set the general service ID, if needed
     if( strlen(service_id_str) ) sdp_set_service_id( &record, svc_uuid );
 
-    // connect to the local SDP server, register the service record, and 
+    // connect to the local SDP server, register the service record, and
     // disconnect
     Py_BEGIN_ALLOW_THREADS
     session = sdp_connect( BDADDR_ANY, BDADDR_LOCAL, 0 );
@@ -2840,7 +2916,7 @@
 
     Py_RETURN_NONE;
 }
-PyDoc_STRVAR( bt_sdp_advertise_service_doc, 
+PyDoc_STRVAR( bt_sdp_advertise_service_doc,
 "sdp_advertise_service( socket, name )\n\
 \n\
 Registers a service with the local SDP server.\n\
@@ -2866,7 +2942,7 @@
     // verify that we got a real socket object
     if( ! socko || (Py_TYPE(socko) != &sock_type) ) {
         // TODO change this to a more accurate exception type
-        PyErr_SetString(bluetooth_error, 
+        PyErr_SetString(bluetooth_error,
                 "must pass in _bluetooth.socket object");
         return 0;
     }
@@ -2888,11 +2964,9 @@
 \n\
 Stop advertising services associated with this socket");
 
-
 /* List of functions exported by this module. */
 
-#define DECL_BT_METHOD(name, argtype) \
-{ #name, (PyCFunction)bt_ ##name, argtype, bt_ ## name ## _doc }
+#define DECL_BT_METHOD(name, argtype){ #name, (PyCFunction)bt_ ##name, argtype, bt_ ## name ## _doc }
 
 static PyMethodDef bt_methods[] = {
     DECL_BT_METHOD( hci_devid, METH_VARARGS ),
@@ -2937,6 +3011,9 @@
     DECL_BT_METHOD( setdefaulttimeout, METH_O ),
     DECL_BT_METHOD( sdp_advertise_service, METH_VARARGS ),
     DECL_BT_METHOD( sdp_stop_advertising, METH_VARARGS ),
+    DECL_BT_METHOD( hci_le_add_white_list, METH_VARARGS ),
+    DECL_BT_METHOD( hci_le_read_white_list_size, METH_VARARGS ),
+    DECL_BT_METHOD( hci_le_clear_white_list, METH_VARARGS ),
 //    DECL_BT_METHOD( advertise_service, METH_VARARGS | METH_KEYWORDS ),
 	{NULL,			NULL}		 /* Sentinel */
 };
@@ -2951,7 +3028,6 @@
 \n\
 See the bluetooth module for documentation.");
 
-#if PY_MAJOR_VERSION >= 3
 #define INITERROR return NULL
 
 static struct PyModuleDef moduledef = {
@@ -2968,20 +3044,10 @@
 
 PyMODINIT_FUNC
 PyInit__bluetooth(void)
-#else
-#define INITERROR return
-
-PyMODINIT_FUNC
-init_bluetooth(void)
-#endif
 {
-    Py_TYPE(&sock_type) = &PyType_Type;
-    Py_TYPE(&sdp_session_type) = &PyType_Type;
-#if PY_MAJOR_VERSION >= 3
+    Py_SET_TYPE(&sock_type, &PyType_Type);
+    Py_SET_TYPE(&sdp_session_type, &PyType_Type);
     PyObject *m = PyModule_Create(&moduledef);
-#else
-    PyObject *m = Py_InitModule3("_bluetooth", bt_methods, socket_doc);
-#endif
     if (m == NULL)
         INITERROR;
 
@@ -3026,7 +3092,7 @@
 //    PyModule_AddIntMacro(m, SOCK_DGRAM);
 //    PyModule_AddIntMacro(m, SOCK_RAW);
 //    PyModule_AddIntMacro(m, SOCK_SEQPACKET);
-    
+
 /* HCI Constants */
 
     /* HCI OGF values */
@@ -3695,23 +3761,21 @@
 #endif
     PyModule_AddIntMacro(m, SOL_BLUETOOTH);
 
-#if PY_MAJOR_VERSION >= 3
     return m;
-#endif
 }
 
 /*
- * Affix socket module 
+ * Affix socket module
  * Socket module for python based in the original socket module for python
  * This code is a copy from socket.c source code from python2.2 with
- * updates/modifications to support affix socket interface * 
- *   AAA     FFFFFFF FFFFFFF IIIIIII X     X    
+ * updates/modifications to support affix socket interface *
+ *   AAA     FFFFFFF FFFFFFF IIIIIII X     X
  * A     A   F       F          I     X   X
  * A     A   F       F      I      X X
  * AAAAAAA   FFFF    FFFF       I      X X
  * A     A   F       F      I     X   X
  * A     A   F       F       IIIIIII X     X
- * 
+ *
  * Any modifications of this sourcecode must keep this information !!!!!
  *
  * by Carlos Chinea
diff -Naur PyBluez-0.23/bluez/pythoncapi_compat.h PyBluez-0.23.new/bluez/pythoncapi_compat.h
--- PyBluez-0.23/bluez/pythoncapi_compat.h	1970-01-01 01:00:00.000000000 +0100
+++ PyBluez-0.23.new/bluez/pythoncapi_compat.h	2022-12-11 16:31:25.093057950 +0100
@@ -0,0 +1,364 @@
+// Header file providing new functions of the Python C API to old Python
+// versions.
+//
+// File distributed under the MIT license.
+// Copyright Contributors to the pythoncapi_compat project.
+//
+// Homepage:
+// https://github.com/pythoncapi/pythoncapi_compat
+//
+// Latest version:
+// https://raw.githubusercontent.com/pythoncapi/pythoncapi_compat/master/pythoncapi_compat.h
+//
+// SPDX-License-Identifier: MIT
+
+#ifndef PYTHONCAPI_COMPAT
+#define PYTHONCAPI_COMPAT
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <Python.h>
+#include "frameobject.h"          // PyFrameObject, PyFrame_GetBack()
+
+
+// Compatibility with Visual Studio 2013 and older which don't support
+// the inline keyword in C (only in C++): use __inline instead.
+#if (defined(_MSC_VER) && _MSC_VER < 1900 \
+     && !defined(__cplusplus) && !defined(inline))
+#  define inline __inline
+#  define PYTHONCAPI_COMPAT_MSC_INLINE
+   // These two macros are undefined at the end of this file
+#endif
+
+
+// Cast argument to PyObject* type.
+#ifndef _PyObject_CAST
+#  define _PyObject_CAST(op) ((PyObject*)(op))
+#endif
+#ifndef _PyObject_CAST_CONST
+#  define _PyObject_CAST_CONST(op) ((const PyObject*)(op))
+#endif
+
+
+// bpo-42262 added Py_NewRef() to Python 3.10.0a3
+#if PY_VERSION_HEX < 0x030A00A3 && !defined(Py_NewRef)
+static inline PyObject* _Py_NewRef(PyObject *obj)
+{
+    Py_INCREF(obj);
+    return obj;
+}
+#define Py_NewRef(obj) _Py_NewRef(_PyObject_CAST(obj))
+#endif
+
+
+// bpo-42262 added Py_XNewRef() to Python 3.10.0a3
+#if PY_VERSION_HEX < 0x030A00A3 && !defined(Py_XNewRef)
+static inline PyObject* _Py_XNewRef(PyObject *obj)
+{
+    Py_XINCREF(obj);
+    return obj;
+}
+#define Py_XNewRef(obj) _Py_XNewRef(_PyObject_CAST(obj))
+#endif
+
+
+// See https://bugs.python.org/issue42522
+#if !defined(_Py_StealRef)
+static inline PyObject* __Py_StealRef(PyObject *obj)
+{
+    Py_DECREF(obj);
+    return obj;
+}
+#define _Py_StealRef(obj) __Py_StealRef(_PyObject_CAST(obj))
+#endif
+
+
+// See https://bugs.python.org/issue42522
+#if !defined(_Py_XStealRef)
+static inline PyObject* __Py_XStealRef(PyObject *obj)
+{
+    Py_XDECREF(obj);
+    return obj;
+}
+#define _Py_XStealRef(obj) __Py_XStealRef(_PyObject_CAST(obj))
+#endif
+
+
+// bpo-39573 added Py_SET_REFCNT() to Python 3.9.0a4
+#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_REFCNT)
+static inline void _Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt)
+{
+    ob->ob_refcnt = refcnt;
+}
+#define Py_SET_REFCNT(ob, refcnt) _Py_SET_REFCNT(_PyObject_CAST(ob), refcnt)
+#endif
+
+
+// Py_SETREF() and Py_XSETREF() were added to Python 3.5.2.
+// It is excluded from the limited C API.
+#if (PY_VERSION_HEX < 0x03050200 && !defined(Py_SETREF)) && !defined(Py_LIMITED_API)
+#define Py_SETREF(op, op2)                      \
+    do {                                        \
+        PyObject *_py_tmp = _PyObject_CAST(op); \
+        (op) = (op2);                           \
+        Py_DECREF(_py_tmp);                     \
+    } while (0)
+
+#define Py_XSETREF(op, op2)                     \
+    do {                                        \
+        PyObject *_py_tmp = _PyObject_CAST(op); \
+        (op) = (op2);                           \
+        Py_XDECREF(_py_tmp);                    \
+    } while (0)
+#endif
+
+
+// bpo-43753 added Py_Is(), Py_IsNone(), Py_IsTrue() and Py_IsFalse()
+// to Python 3.10.0b1.
+#if PY_VERSION_HEX < 0x030A00B1 && !defined(Py_Is)
+#  define Py_Is(x, y) ((x) == (y))
+#endif
+#if PY_VERSION_HEX < 0x030A00B1 && !defined(Py_IsNone)
+#  define Py_IsNone(x) Py_Is(x, Py_None)
+#endif
+#if PY_VERSION_HEX < 0x030A00B1 && !defined(Py_IsTrue)
+#  define Py_IsTrue(x) Py_Is(x, Py_True)
+#endif
+#if PY_VERSION_HEX < 0x030A00B1 && !defined(Py_IsFalse)
+#  define Py_IsFalse(x) Py_Is(x, Py_False)
+#endif
+
+
+// bpo-39573 added Py_SET_TYPE() to Python 3.9.0a4
+#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_TYPE)
+static inline void
+_Py_SET_TYPE(PyObject *ob, PyTypeObject *type)
+{
+    ob->ob_type = type;
+}
+#define Py_SET_TYPE(ob, type) _Py_SET_TYPE(_PyObject_CAST(ob), type)
+#endif
+
+
+// bpo-39573 added Py_SET_SIZE() to Python 3.9.0a4
+#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_SIZE)
+static inline void
+_Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size)
+{
+    ob->ob_size = size;
+}
+#define Py_SET_SIZE(ob, size) _Py_SET_SIZE((PyVarObject*)(ob), size)
+#endif
+
+
+// bpo-40421 added PyFrame_GetCode() to Python 3.9.0b1
+#if PY_VERSION_HEX < 0x030900B1
+static inline PyCodeObject*
+PyFrame_GetCode(PyFrameObject *frame)
+{
+    assert(frame != NULL);
+    assert(frame->f_code != NULL);
+    return (PyCodeObject*)Py_NewRef(frame->f_code);
+}
+#endif
+
+static inline PyCodeObject*
+_PyFrame_GetCodeBorrow(PyFrameObject *frame)
+{
+    return (PyCodeObject *)_Py_StealRef(PyFrame_GetCode(frame));
+}
+
+
+// bpo-40421 added PyFrame_GetCode() to Python 3.9.0b1
+#if PY_VERSION_HEX < 0x030900B1 && !defined(PYPY_VERSION)
+static inline PyFrameObject*
+PyFrame_GetBack(PyFrameObject *frame)
+{
+    assert(frame != NULL);
+    return (PyFrameObject*)Py_XNewRef(frame->f_back);
+}
+#endif
+
+#if !defined(PYPY_VERSION)
+static inline PyFrameObject*
+_PyFrame_GetBackBorrow(PyFrameObject *frame)
+{
+    return (PyFrameObject *)_Py_XStealRef(PyFrame_GetBack(frame));
+}
+#endif
+
+
+// bpo-39947 added PyThreadState_GetInterpreter() to Python 3.9.0a5
+#if PY_VERSION_HEX < 0x030900A5
+static inline PyInterpreterState *
+PyThreadState_GetInterpreter(PyThreadState *tstate)
+{
+    assert(tstate != NULL);
+    return tstate->interp;
+}
+#endif
+
+
+// bpo-40429 added PyThreadState_GetFrame() to Python 3.9.0b1
+#if PY_VERSION_HEX < 0x030900B1 && !defined(PYPY_VERSION)
+static inline PyFrameObject*
+PyThreadState_GetFrame(PyThreadState *tstate)
+{
+    assert(tstate != NULL);
+    return (PyFrameObject *)Py_XNewRef(tstate->frame);
+}
+#endif
+
+#if !defined(PYPY_VERSION)
+static inline PyFrameObject*
+_PyThreadState_GetFrameBorrow(PyThreadState *tstate)
+{
+    return (PyFrameObject *)_Py_XStealRef(PyThreadState_GetFrame(tstate));
+}
+#endif
+
+
+// bpo-39947 added PyInterpreterState_Get() to Python 3.9.0a5
+#if PY_VERSION_HEX < 0x030900A5
+static inline PyInterpreterState *
+PyInterpreterState_Get(void)
+{
+    PyThreadState *tstate;
+    PyInterpreterState *interp;
+
+    tstate = PyThreadState_GET();
+    if (tstate == NULL) {
+        Py_FatalError("GIL released (tstate is NULL)");
+    }
+    interp = tstate->interp;
+    if (interp == NULL) {
+        Py_FatalError("no current interpreter");
+    }
+    return interp;
+}
+#endif
+
+
+// bpo-39947 added PyInterpreterState_Get() to Python 3.9.0a6
+#if 0x030700A1 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030900A6 && !defined(PYPY_VERSION)
+static inline uint64_t
+PyThreadState_GetID(PyThreadState *tstate)
+{
+    assert(tstate != NULL);
+    return tstate->id;
+}
+#endif
+
+
+// bpo-37194 added PyObject_CallNoArgs() to Python 3.9.0a1
+#if PY_VERSION_HEX < 0x030900A1
+static inline PyObject*
+PyObject_CallNoArgs(PyObject *func)
+{
+    return PyObject_CallFunctionObjArgs(func, NULL);
+}
+#endif
+
+
+// bpo-39245 made PyObject_CallOneArg() public (previously called
+// _PyObject_CallOneArg) in Python 3.9.0a4
+#if PY_VERSION_HEX < 0x030900A4
+static inline PyObject*
+PyObject_CallOneArg(PyObject *func, PyObject *arg)
+{
+    return PyObject_CallFunctionObjArgs(func, arg, NULL);
+}
+#endif
+
+
+// bpo-1635741 added PyModule_AddObjectRef() to Python 3.10.0a3
+#if PY_VERSION_HEX < 0x030A00A3
+static inline int
+PyModule_AddObjectRef(PyObject *module, const char *name, PyObject *value)
+{
+    Py_XINCREF(value);
+    int res = PyModule_AddObject(module, name, value);
+    if (res < 0) {
+        Py_XDECREF(value);
+    }
+    return res;
+}
+#endif
+
+
+// bpo-40024 added PyModule_AddType() to Python 3.9.0a5
+#if PY_VERSION_HEX < 0x030900A5
+static inline int
+PyModule_AddType(PyObject *module, PyTypeObject *type)
+{
+    const char *name, *dot;
+
+    if (PyType_Ready(type) < 0) {
+        return -1;
+    }
+
+    // inline _PyType_Name()
+    name = type->tp_name;
+    assert(name != NULL);
+    dot = strrchr(name, '.');
+    if (dot != NULL) {
+        name = dot + 1;
+    }
+
+    return PyModule_AddObjectRef(module, name, (PyObject *)type);
+}
+#endif
+
+
+// bpo-40241 added PyObject_GC_IsTracked() to Python 3.9.0a6.
+// bpo-4688 added _PyObject_GC_IS_TRACKED() to Python 2.7.0a2.
+#if PY_VERSION_HEX < 0x030900A6 && !defined(PYPY_VERSION)
+static inline int
+PyObject_GC_IsTracked(PyObject* obj)
+{
+    return (PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj));
+}
+#endif
+
+// bpo-40241 added PyObject_GC_IsFinalized() to Python 3.9.0a6.
+// bpo-18112 added _PyGCHead_FINALIZED() to Python 3.4.0 final.
+#if PY_VERSION_HEX < 0x030900A6 && PY_VERSION_HEX >= 0x030400F0 && !defined(PYPY_VERSION)
+static inline int
+PyObject_GC_IsFinalized(PyObject *obj)
+{
+    return (PyObject_IS_GC(obj) && _PyGCHead_FINALIZED((PyGC_Head *)(obj)-1));
+}
+#endif
+
+
+// bpo-39573 added Py_IS_TYPE() to Python 3.9.0a4
+#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_IS_TYPE)
+static inline int
+_Py_IS_TYPE(const PyObject *ob, const PyTypeObject *type) {
+    return ob->ob_type == type;
+}
+#define Py_IS_TYPE(ob, type) _Py_IS_TYPE(_PyObject_CAST_CONST(ob), type)
+#endif
+
+
+// Py_UNUSED() was added to Python 3.4.0b2.
+#if PY_VERSION_HEX < 0x030400B2 && !defined(Py_UNUSED)
+#  if defined(__GNUC__) || defined(__clang__)
+#    define Py_UNUSED(name) _unused_ ## name __attribute__((unused))
+#  else
+#    define Py_UNUSED(name) _unused_ ## name
+#  endif
+#endif
+
+
+#ifdef PYTHONCAPI_COMPAT_MSC_INLINE
+#  undef inline
+#  undef PYTHONCAPI_COMPAT_MSC_INLINE
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif  // PYTHONCAPI_COMPAT
