python 3.13 removed some modules such as cgi which is required by python3-requests-ftp:

    https://docs.python.org/3/whatsnew/3.13.html

    Important removals:

    PEP 594: The remaining 19 “dead batteries” (legacy stdlib modules) have
    been removed from the standard library: aifc, audioop, cgi, cgitb,
    chunk, crypt, imghdr, mailcap, msilib, nis, nntplib, ossaudiodev, pipes,
    sndhdr, spwd, sunau, telnetlib, uu and xdrlib.

Backport and rebase a patch from Fedora to remove use of module cgi.

Upstream-Status: Backport [https://dl.fedoraproject.org/pub/fedora/linux/development/rawhide/Server/source/tree/Packages/p/python-requests-ftp-0.3.1-36.fc42.src.rpm]

Signed-off-by: Kai Kang <kai.kang@windriver.com>
---
 requests_ftp/ftp.py | 56 ---------------------------------------------
 1 file changed, 56 deletions(-)

diff --git a/requests_ftp/ftp.py b/requests_ftp/ftp.py
index 9711905..85dac47 100644
--- a/requests_ftp/ftp.py
+++ b/requests_ftp/ftp.py
@@ -6,7 +6,6 @@ from requests.compat import urlparse
 from requests.hooks import dispatch_hook
 from requests import Response, codes
 from io import BytesIO
-import cgi
 import os
 import socket
 
@@ -29,12 +28,6 @@ class FTPSession(requests.Session):
         content field contains the binary data.'''
         return self.request('RETR', url, **kwargs)
 
-    def stor(self, url, files=None, **kwargs):
-        '''Sends an FTP STOR to a given URL. Returns a Response object. Expects
-        to be given one file by the standard Requests method. The remote
-        filename will be given by the URL provided.'''
-        return self.request('STOR', url, files=files, **kwargs)
-
     def nlst(self, url, **kwargs):
         '''Sends an FTP NLST. Returns a Response object.'''
         return self.request('NLST', url, **kwargs)
@@ -52,30 +45,6 @@ def monkeypatch_session():
     return
 
 
-def parse_multipart_files(request):
-    '''Given a prepared reqest, return a file-like object containing the
-    original data. This is pretty hacky.'''
-    # Start by grabbing the pdict.
-    _, pdict = cgi.parse_header(request.headers['Content-Type'])
-
-    # Now, wrap the multipart data in a BytesIO buffer. This is annoying.
-    buf = BytesIO()
-    buf.write(request.body)
-    buf.seek(0)
-
-    # Parse the data. Simply take the first file.
-    data = cgi.parse_multipart(buf, pdict)
-    _, filedata = data.popitem()
-    buf.close()
-
-    # Get a BytesIO now, and write the file into it.
-    buf = BytesIO()
-    buf.write(''.join(filedata))
-    buf.seek(0)
-
-    return buf
-
-
 def data_callback_factory(variable):
     '''Returns a callback suitable for use by the FTP library. This callback
     will repeatedly save data into the variable provided to this function. This
@@ -135,7 +104,6 @@ class FTPAdapter(requests.adapters.BaseAdapter):
         # send the specific queries.
         self.func_table = {'LIST': self.list,
                            'RETR': self.retr,
-                           'STOR': self.stor,
                            'NLST': self.nlst,
                            'SIZE': self.size,
                            'HEAD': self.head,
@@ -314,30 +282,6 @@ class FTPAdapter(requests.adapters.BaseAdapter):
         response.status_code = codes.ok
         return response
 
-    def stor(self, path, request):
-        '''Executes the FTP STOR command on the given path.'''
-
-        # First, get the file handle. We assume (bravely)
-        # that there is only one file to be sent to a given URL. We also
-        # assume that the filename is sent as part of the URL, not as part of
-        # the files argument. Both of these assumptions are rarely correct,
-        # but they are easy.
-        data = parse_multipart_files(request)
-
-        # Split into the path and the filename.
-        path, filename = os.path.split(path)
-
-        # Switch directories and upload the data.
-        self.conn.cwd(path)
-        code = self.conn.storbinary('STOR ' + filename, data)
-
-        # Close the connection and build the response.
-        self.conn.close()
-
-        response = build_binary_response(request, BytesIO(), code)
-
-        return response
-
     def nlst(self, path, request):
         '''Executes the FTP NLST command on the given path.'''
         data = BytesIO()
