--- /dev/null
+From df7d20459901d7e9167fa2a69168da6b0267487e Mon Sep 17 00:00:00 2001
+From: JinWang An <jinwang.an@samsung.com>
+Date: Fri, 12 Apr 2024 07:19:39 +0900
+Subject: [PATCH] Fix build error for python 3.12
+
+Signed-off-by: JinWang An <jinwang.an@samsung.com>
+---
+ src/easy.c | 17 +++++++++++++++++
+ src/easyopt.c | 1 -
+ src/multi.c | 15 +++++++++++++++
+ src/pythoncompat.c | 6 +++---
+ src/share.c | 15 +++++++++++++++
+ 5 files changed, 50 insertions(+), 4 deletions(-)
+
+diff --git a/src/easy.c b/src/easy.c
+index a5f7849..e0d9e36 100644
+--- a/src/easy.c
++++ b/src/easy.c
+@@ -85,6 +85,7 @@ PYCURL_INTERNAL PyTypeObject CurlSlist_Type = {
+ #if PY_VERSION_HEX >= 0x03080000
+ 0, /* tp_vectorcall */
+ #endif
++ 0, /* tp_watched*/
+ #endif
+ };
+
+@@ -174,6 +175,7 @@ PYCURL_INTERNAL PyTypeObject CurlHttppost_Type = {
+ #if PY_VERSION_HEX >= 0x03080000
+ 0, /* tp_vectorcall */
+ #endif
++ 0, /* tp_watched*/
+ #endif
+ };
+
+@@ -869,6 +871,21 @@ PYCURL_INTERNAL PyTypeObject Curl_Type = {
+ PyType_GenericAlloc, /* tp_alloc */
+ (newfunc)do_curl_new, /* tp_new */
+ PyObject_GC_Del, /* tp_free */
++ 0, /* tp_is_gc */
++ 0, /* tp_bases */
++ 0, /* tp_mro */
++ 0, /* tp_cache */
++ 0, /* tp_subclasses */
++ 0, /* tp_weaklist */
++#if PY_MAJOR_VERSION >= 3
++ 0, /* tp_del */
++ 0, /* tp_version_tag */
++ 0, /* tp_finalize */
++#if PY_VERSION_HEX >= 0x03080000
++ 0, /* tp_vectorcall */
++#endif
++ 0, /* tp_watched*/
++#endif
+ };
+
+ /* vi:ts=4:et:nowrap
+diff --git a/src/easyopt.c b/src/easyopt.c
+index d209aaa..dab8756 100644
+--- a/src/easyopt.c
++++ b/src/easyopt.c
+@@ -717,7 +717,6 @@ do_curl_setopt_httppost(CurlObject *self, int option, int which, PyObject *obj)
+ forms[k].value = (const char *)olen;
+ ++k;
+ } else if (val == CURLFORM_BUFFERPTR) {
+- PyObject *obj = NULL;
+
+ if (ref_params == NULL) {
+ ref_params = PyList_New((Py_ssize_t)0);
+diff --git a/src/multi.c b/src/multi.c
+index 12c1125..d8f5854 100644
+--- a/src/multi.c
++++ b/src/multi.c
+@@ -1074,6 +1074,21 @@ PYCURL_INTERNAL PyTypeObject CurlMulti_Type = {
+ PyType_GenericAlloc, /* tp_alloc */
+ (newfunc)do_multi_new, /* tp_new */
+ PyObject_GC_Del, /* tp_free */
++ 0, /* tp_is_gc */
++ 0, /* tp_bases */
++ 0, /* tp_mro */
++ 0, /* tp_cache */
++ 0, /* tp_subclasses */
++ 0, /* tp_weaklist */
++#if PY_MAJOR_VERSION >= 3
++ 0, /* tp_del */
++ 0, /* tp_version_tag */
++ 0, /* tp_finalize */
++#if PY_VERSION_HEX >= 0x03080000
++ 0, /* tp_vectorcall */
++#endif
++ 0, /* tp_watched*/
++#endif
+ };
+
+ /* vi:ts=4:et:nowrap
+diff --git a/src/pythoncompat.c b/src/pythoncompat.c
+index 4ef586b..ed38231 100644
+--- a/src/pythoncompat.c
++++ b/src/pythoncompat.c
+@@ -31,14 +31,14 @@ my_setattro(PyObject **dict, PyObject *name, PyObject *v)
+ if (v != NULL)
+ return PyDict_SetItem(*dict, name, v);
+ else {
+- int v = PyDict_DelItem(*dict, name);
+- if (v != 0) {
++ int r = PyDict_DelItem(*dict, name);
++ if (r != 0) {
+ /* need to convert KeyError to AttributeError */
+ if (PyErr_ExceptionMatches(PyExc_KeyError)) {
+ PyErr_Format(PyExc_AttributeError, "trying to delete a non-existing attribute: %U", name);
+ }
+ }
+- return v;
++ return r;
+ }
+ }
+
+diff --git a/src/share.c b/src/share.c
+index bc16ebc..7305bfe 100644
+--- a/src/share.c
++++ b/src/share.c
+@@ -342,6 +342,21 @@ PYCURL_INTERNAL PyTypeObject CurlShare_Type = {
+ PyType_GenericAlloc, /* tp_alloc */
+ (newfunc)do_share_new, /* tp_new */
+ PyObject_GC_Del, /* tp_free */
++ 0, /* tp_is_gc */
++ 0, /* tp_bases */
++ 0, /* tp_mro */
++ 0, /* tp_cache */
++ 0, /* tp_subclasses */
++ 0, /* tp_weaklist */
++#if PY_MAJOR_VERSION >= 3
++ 0, /* tp_del */
++ 0, /* tp_version_tag */
++ 0, /* tp_finalize */
++#if PY_VERSION_HEX >= 0x03080000
++ 0, /* tp_vectorcall */
++#endif
++ 0, /* tp_watched*/
++#endif
+ };
+
+ /* vi:ts=4:et:nowrap
+--
+2.25.1
+
--- /dev/null
+Index: pycurl-7.45.1/tests/memory_mgmt_test.py
+===================================================================
+--- pycurl-7.45.1.orig/tests/memory_mgmt_test.py
++++ pycurl-7.45.1/tests/memory_mgmt_test.py
+@@ -9,6 +9,7 @@ import unittest
+ import gc
+ import flaky
+ from . import util
++import pytest
+
+ debug = False
+
+@@ -17,6 +18,7 @@ if sys.platform == 'win32':
+ else:
+ devnull = '/dev/null'
+
++@pytest.mark.occasionally_failing
+ @flaky.flaky(max_runs=3)
+ class MemoryMgmtTest(unittest.TestCase):
+ def maybe_enable_debug(self):
+Index: pycurl-7.45.1/tests/multi_memory_mgmt_test.py
+===================================================================
+--- pycurl-7.45.1.orig/tests/multi_memory_mgmt_test.py
++++ pycurl-7.45.1/tests/multi_memory_mgmt_test.py
+@@ -7,11 +7,13 @@ import unittest
+ import gc
+ import flaky
+ import weakref
++import pytest
+
+ from . import util
+
+ debug = False
+
++@pytest.mark.occasionally_failing
+ @flaky.flaky(max_runs=3)
+ class MultiMemoryMgmtTest(unittest.TestCase):
+ def test_opensocketfunction_collection(self):
+Index: pycurl-7.45.1/tests/multi_timer_test.py
+===================================================================
+--- pycurl-7.45.1.orig/tests/multi_timer_test.py
++++ pycurl-7.45.1/tests/multi_timer_test.py
+@@ -5,6 +5,7 @@
+ from . import localhost
+ import pycurl
+ import unittest
++import pytest
+
+ from . import appmanager
+ from . import util
+@@ -23,6 +24,7 @@ def teardown_module(mod):
+ teardown_module_2(mod)
+ teardown_module_1(mod)
+
++@pytest.mark.occasionally_failing
+ class MultiSocketTest(unittest.TestCase):
+ def test_multi_timer(self):
+ urls = [
+Index: pycurl-7.45.1/pytest.ini
+===================================================================
+--- pycurl-7.45.1.orig/pytest.ini
++++ pycurl-7.45.1/pytest.ini
+@@ -7,3 +7,4 @@ markers =
+ gssapi: mark a test as requiring GSSAPI
+ http2: mark a test as requiring HTTP/2
+ standalone: mark a test as being standalone
++ occasionally_failing: mark a test as occasionally failing
--- /dev/null
+Index: pycurl-7.43.0/tests/runwsgi.py
+===================================================================
+--- pycurl-7.43.0.orig/tests/runwsgi.py
++++ pycurl-7.43.0/tests/runwsgi.py
+@@ -48,10 +48,10 @@ def start_bottle_server(app, port, serve
+ server_thread.daemon = True
+ server_thread.start()
+
+- ok = util.wait_for_network_service(('127.0.0.1', port), 0.1, 10)
++ ok = util.wait_for_network_service(('127.0.0.1', port), 0.1, 30)
+ if not ok:
+ import warnings
+- warnings.warn('Server did not start after 1 second')
++ warnings.warn('Server did not start after 3 seconds')
+
+ return server_thread.server
+
--- /dev/null
+---
+ tests/curl_object_test.py | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/tests/curl_object_test.py
++++ b/tests/curl_object_test.py
+@@ -143,11 +143,11 @@ class CurlObjectTest(unittest.TestCase):
+ # change does not affect objects created later
+ obj3 = cls()
+ self.assertEqual(old_value, getattr(obj3, name))
+-
++
+ def test_bogus_attribute_access(self):
+- with pytest.raises(AttributeError, match='trying to obtain.*'):
+- self.curl.foo
+-
++ with pytest.raises(AttributeError):
++ self.curl.foo
++
+ def test_bogus_attribute_delete(self):
+ with pytest.raises(AttributeError, match='trying to delete.*'):
+ del self.curl.foo
--- /dev/null
+--- a/tests/ssh_key_cb_test.py
++++ b/tests/ssh_key_cb_test.py
+@@ -33,8 +33,11 @@ class SshKeyCbTest(unittest.TestCase):
+ def keyfunction(known_key, found_key, match):
+ return pycurl.KHSTAT_FINE
+
+- self.curl.setopt(pycurl.SSH_KNOWNHOSTS, '.known_hosts')
+- self.curl.setopt(pycurl.SSH_KEYFUNCTION, keyfunction)
++ try:
++ self.curl.setopt(pycurl.SSH_KNOWNHOSTS, '.known_hosts')
++ self.curl.setopt(pycurl.SSH_KEYFUNCTION, keyfunction)
++ except pycurl.error as e:
++ self.assertEqual(pycurl.E_UNKNOWN_OPTION, e.args[0])
+
+ try:
+ self.curl.perform()
+@@ -47,8 +50,11 @@ class SshKeyCbTest(unittest.TestCase):
+ def keyfunction(known_key, found_key, match):
+ return pycurl.KHSTAT_REJECT
+
+- self.curl.setopt(pycurl.SSH_KNOWNHOSTS, '.known_hosts')
+- self.curl.setopt(pycurl.SSH_KEYFUNCTION, keyfunction)
++ try:
++ self.curl.setopt(pycurl.SSH_KNOWNHOSTS, '.known_hosts')
++ self.curl.setopt(pycurl.SSH_KEYFUNCTION, keyfunction)
++ except pycurl.error as e:
++ self.assertEqual(pycurl.E_UNKNOWN_OPTION, e.args[0])
+
+ try:
+ self.curl.perform()
+@@ -62,8 +68,11 @@ class SshKeyCbTest(unittest.TestCase):
+ def keyfunction(known_key, found_key, match):
+ return 'bogus'
+
+- self.curl.setopt(pycurl.SSH_KNOWNHOSTS, '.known_hosts')
+- self.curl.setopt(pycurl.SSH_KEYFUNCTION, keyfunction)
++ try:
++ self.curl.setopt(pycurl.SSH_KNOWNHOSTS, '.known_hosts')
++ self.curl.setopt(pycurl.SSH_KEYFUNCTION, keyfunction)
++ except pycurl.error as e:
++ self.assertEqual(pycurl.E_UNKNOWN_OPTION, e.args[0])
+
+ try:
+ self.curl.perform()
+@@ -82,9 +91,15 @@ class SshKeyCbUnsetTest(unittest.TestCas
+ @util.min_libcurl(7, 19, 6)
+ @util.guard_unknown_libcurl_option
+ def test_keyfunction_none(self):
+- self.curl.setopt(pycurl.SSH_KEYFUNCTION, None)
++ try:
++ self.curl.setopt(pycurl.SSH_KEYFUNCTION, None)
++ except pycurl.error as e:
++ self.assertEqual(pycurl.E_UNKNOWN_OPTION, e.args[0])
+
+ @util.min_libcurl(7, 19, 6)
+ @util.guard_unknown_libcurl_option
+ def test_keyfunction_unset(self):
+- self.curl.unsetopt(pycurl.SSH_KEYFUNCTION)
++ try:
++ self.curl.unsetopt(pycurl.SSH_KEYFUNCTION)
++ except pycurl.error as e:
++ self.assertEqual(pycurl.E_UNKNOWN_OPTION, e.args[0])
--- /dev/null
+#
+# spec file
+#
+# Copyright (c) 2023 SUSE LLC
+#
+# All modifications and additions to the file contributed by third parties
+# remain the property of their copyright owners, unless otherwise agreed
+# upon. The license for this file, and modifications and additions to the
+# file, is the same license as for the pristine package itself (unless the
+# license for the pristine package is not an Open Source License, in which
+# case the license is the MIT License). An "Open Source License" is a
+# license that conforms to the Open Source Definition (Version 1.9)
+# published by the Open Source Initiative.
+
+# Please submit bugfixes or comments via https://bugs.opensuse.org/
+#
+
+
+
+Name: python3-pycurl
+Version: 7.45.3
+Release: 0
+Summary: PycURL -- cURL library module
+License: LGPL-2.1-or-later AND MIT
+URL: http://pycurl.io/
+Source: https://files.pythonhosted.org/packages/source/p/pycurl/pycurl-%{version}.tar.gz
+Source1000: Fix-build-error-for-python-3.12.patch
+Source1001: disable_randomly_failing_tests.patch
+# PATCH-FIX-UPSTREAM handle difference between libssh and libssh2
+Source1002: pycurl-libssh.patch
+# PATCH-FIX-OPENSUSE increase_test_timeout.diff -- Increase the timeout in a test so it doesn't fail when obs is overloaded
+Source1003: increase_test_timeout.diff
+# PATCH-FIX-OPENSUSE make-leap15-compat.patch mcepl@suse.com
+# Make tests passing with Leap 15.2
+Source1004: make-leap15-compat.patch
+BuildRequires: python3
+BuildRequires: python3-devel
+BuildRequires: python3-setuptools
+BuildRequires: pkgconfig
+BuildRequires: pkgconfig(libcurl) >= 7.19.0
+BuildRequires: pkgconfig(openssl1.1)
+
+
+%description
+This module provides bindings for the cURL library.
+
+
+%prep
+%setup -q -n %{name}-%{version}
+%{__patch} -p1 < %{SOURCE1000}
+%{__patch} -p1 < %{SOURCE1001}
+%{__patch} -p1 < %{SOURCE1002}
+%{__patch} -p1 < %{SOURCE1003}
+%{__patch} -p1 < %{SOURCE1004}
+
+# temporarily remove a failing test-case until the issue is
+# fixed in curl: https://github.com/curl/curl/issues/6615
+rm -f tests/failonerror_test.py
+
+%build
+export CFLAGS="%{optflags} -fno-strict-aliasing"
+export PYCURL_SSL_LIBRARY=openssl
+python3 setup.py build --with-openssl
+
+%install
+export PYCURL_SSL_LIBRARY=openssl
+python3 setup.py install -O1 --skip-build --root=%{buildroot} --prefix=%{_prefix} --with-openssl
+
+rm -rf %{buildroot}%{_datadir}/doc # Remove wrongly installed junk
+
+
+
+%files
+%license COPYING-LGPL COPYING-MIT
+%doc AUTHORS ChangeLog README.rst
+%{python3_sitearch}/*