pycurl:用正确测试编码的filepath崩溃(错误26,'')发帖。

发布于 2025-02-08 19:28:29 字数 6310 浏览 0 评论 0原文

我的Pycurl版本7.45.1有问题,Windows 10上的Python 3.10.4。

我想从计算机上将文件发布到API上。当我运行代码时(可能),Filepath会出现问题,因为我以我的名义以及在完整的Filepath中有一个讨厌的“ Umlauts”。

我的上传文件的filepath可能看起来像:“ c:\\ users \\namewith_ö\\ folder \\ folder \\ enother_folder \\ more_folders \\ more_folders \\ file.pdf”

我已经找到了一些答案ASCII字符或字节词,因此我事先将FilePath字符串编码为UTF-8,这似乎也起作用,因为我在curl.setopt(curl.httpppost,files,files,files),的呼叫上获得了UnicodeencodeError。现在,使用编码的filepath,我收到错误消息“错误(26,'')”。

这是卷曲调用的代码:

def post(self, request_url, custom_headers : list = None, upload_fields : dict = None, upload_files : dict = None, further_directives : dict = None, proxy : dict = None):
        """
        Posts a HTTP POST request and returns a response object.

        :param request_url: The URL that request should point to.
        :type request_url: string
        :param custom_headers: An optional list of costum headers that should be sent with the request.
        :type custom_headers: list
        :param upload_fields: An optional dict of data that should be inputted into targeted upload fields {key = field name: value = input data}.
        :type upload_fields: dict
        :param upload_files: An optional dict of files that should be uploaded to the target site {key = field name: value = dict {key = 'filepath': value = path to file (required), key = 'new_filename': value = new name for uploaded file (optional), key = 'content_type': value = content type (optional, default is 'multipart/form-data')}}.
        :type upload_files: dict
        :param further_directives: An optional dict of further directives that should be included in the request (for list of all possible directives see PLACEHOLDER).
        :type further_directives: dict
        :param proxy: An optional dict of information used to route the request through a proxy {key = proxy port: value = int, key = proxy domain: value = string}
        :type proxy: dict

        :returns: Response object.
        :rtype: Curlified_Response
        """

        self.prepare_new_request()

        body_buffer = BytesIO()
        curl = pycurl.Curl()

        request_url, custom_headers, further_directives, proxy, upload_fields, upload_files = self.encode_strings(request_url, custom_headers, further_directives, proxy, upload_fields, upload_files)

        curl.setopt(curl.URL, request_url)
        if proxy:
            self.inject_kerberos_proxy(proxy['proxy port'], proxy['proxy domain'], curl)#
        if custom_headers:
            curl.setopt(curl.HTTPHEADER, custom_headers)#
        if further_directives:
            for item in further_directives.items():
                self.include_further_directive(item, curl)#
        if upload_fields:
            postfields = urlencode(upload_fields)#
            curl.setopt(curl.POSTFIELDS, postfields)
        if upload_files:
            files = []
            for item in upload_files.items():
                files.append(self.build_file_upload(item, curl))#
            curl.setopt(curl.HTTPPOST, files)
        curl.setopt(curl.HEADERFUNCTION, self.read_header_line)
        curl.setopt(curl.WRITEFUNCTION, body_buffer.write)
        curl.perform()
        self.read_body(body_buffer)
        curl.close()

这是用于参考的方法build> build_file_upload

def build_file_upload(self, item, curl):
        """
        Gets a tuple of information for a file upload, checks the correctnes of the content and returns the properly built input.
        """

        info_list = []
        for i in item[1].items():
            if i[0] == 'filepath':
                info_list.append(curl.FORM_FILE)
                info_list.append(i[1])
            elif i[0] == 'new filename':
                info_list.append(curl.FORM_FILENAME)
                info_list.append(i[1])
            elif i[0] == 'contenttype':
                info_list.append(curl.FORM_CONTENTTYPE)
                info_list.append(i[1])
            else:
                raise ArgumentsError("No known file upload key was provided! Please revise.")
        if not info_list:
            raise RequiredArgumentsMissing("One or more required parameters for the file to be uploaded are missing! Please revise.")
        if 'content_type' not in info_list:
            info_list.append(curl.FORM_CONTENTTYPE)
            info_list.append(b'multipart/form-data')
        return (item[0], tuple(info_list))

最后,这是将给定字符串编码为字节的方法encode_strings

def encode_strings(self, request_url, custom_headers, further_directives, proxy, upload_fields = None, upload_files = None):
        """
        Turns all given strings into bytes to be processable by PycURL.
        """

        custom_headers = [] if custom_headers is None else custom_headers
        upload_fields = {} if upload_fields is None else upload_fields
        upload_files = {} if upload_files is None else upload_files
        further_directives = {} if further_directives is None else further_directives
        proxy = {} if proxy is None else proxy

        request_url = bytes(request_url, 'UTF-8')
        for i in range(len(custom_headers)):
            if isinstance(custom_headers[i], str):
                custom_headers[i] = bytes(custom_headers[i], 'UTF-8')
        for k, v in further_directives.items():
            if isinstance(v, str):
                further_directives[k] = bytes(further_directives[k], 'UTF-8')
        for k, v in proxy.items():
            if isinstance(v, str):
                proxy[k] = bytes(proxy[k], 'UTF-8')
        for k, v in upload_fields.items():
            if isinstance(v, str):
                upload_fields[k] = bytes(upload_fields[k], 'UTF-8')
        for k, v in upload_files.items():
            if isinstance(v, dict):
                for key, value in v.items():
                    if isinstance(value, str):
                        upload_files[k][key] = bytes(upload_files[k][key], 'UTF-8')
        
        if len(upload_fields) == 0 and len(upload_files) == 0:
            return request_url, custom_headers, further_directives, proxy
        else:
            return request_url, custom_headers, further_directives, proxy, upload_fields, upload_files

i希望任何人都知道问题可能是什么,甚至可以解决这个问题,真的失去了我的大理石。

I have a problem with PycURL Version 7.45.1 with python 3.10.4 on Windows 10.

I want to post a file from my computer onto an API. When I run my code (probably) the filepath makes problems because I have one of those pesky "Umlauts" in my name and thus also in my full filepath.

My filepath for an upload file could look like this: "C:\\Users\\NameWith_ö\\folder\\another_folder\\more_folders\\file.pdf"

I already found some answers that PycURL can only work with strings that include only ascii characters or bytestrings so I encode my filepath string to UTF-8 beforehand, which also seems to work because where I prior got the UnicodeEncodeError on the call of curl.setopt(curl.HTTPPOST, files), now with the encoded filepath I get the error message "error (26, ' ')".

Here is the code of the curl call:

def post(self, request_url, custom_headers : list = None, upload_fields : dict = None, upload_files : dict = None, further_directives : dict = None, proxy : dict = None):
        """
        Posts a HTTP POST request and returns a response object.

        :param request_url: The URL that request should point to.
        :type request_url: string
        :param custom_headers: An optional list of costum headers that should be sent with the request.
        :type custom_headers: list
        :param upload_fields: An optional dict of data that should be inputted into targeted upload fields {key = field name: value = input data}.
        :type upload_fields: dict
        :param upload_files: An optional dict of files that should be uploaded to the target site {key = field name: value = dict {key = 'filepath': value = path to file (required), key = 'new_filename': value = new name for uploaded file (optional), key = 'content_type': value = content type (optional, default is 'multipart/form-data')}}.
        :type upload_files: dict
        :param further_directives: An optional dict of further directives that should be included in the request (for list of all possible directives see PLACEHOLDER).
        :type further_directives: dict
        :param proxy: An optional dict of information used to route the request through a proxy {key = proxy port: value = int, key = proxy domain: value = string}
        :type proxy: dict

        :returns: Response object.
        :rtype: Curlified_Response
        """

        self.prepare_new_request()

        body_buffer = BytesIO()
        curl = pycurl.Curl()

        request_url, custom_headers, further_directives, proxy, upload_fields, upload_files = self.encode_strings(request_url, custom_headers, further_directives, proxy, upload_fields, upload_files)

        curl.setopt(curl.URL, request_url)
        if proxy:
            self.inject_kerberos_proxy(proxy['proxy port'], proxy['proxy domain'], curl)#
        if custom_headers:
            curl.setopt(curl.HTTPHEADER, custom_headers)#
        if further_directives:
            for item in further_directives.items():
                self.include_further_directive(item, curl)#
        if upload_fields:
            postfields = urlencode(upload_fields)#
            curl.setopt(curl.POSTFIELDS, postfields)
        if upload_files:
            files = []
            for item in upload_files.items():
                files.append(self.build_file_upload(item, curl))#
            curl.setopt(curl.HTTPPOST, files)
        curl.setopt(curl.HEADERFUNCTION, self.read_header_line)
        curl.setopt(curl.WRITEFUNCTION, body_buffer.write)
        curl.perform()
        self.read_body(body_buffer)
        curl.close()

And here is the method build_file_upload for reference:

def build_file_upload(self, item, curl):
        """
        Gets a tuple of information for a file upload, checks the correctnes of the content and returns the properly built input.
        """

        info_list = []
        for i in item[1].items():
            if i[0] == 'filepath':
                info_list.append(curl.FORM_FILE)
                info_list.append(i[1])
            elif i[0] == 'new filename':
                info_list.append(curl.FORM_FILENAME)
                info_list.append(i[1])
            elif i[0] == 'contenttype':
                info_list.append(curl.FORM_CONTENTTYPE)
                info_list.append(i[1])
            else:
                raise ArgumentsError("No known file upload key was provided! Please revise.")
        if not info_list:
            raise RequiredArgumentsMissing("One or more required parameters for the file to be uploaded are missing! Please revise.")
        if 'content_type' not in info_list:
            info_list.append(curl.FORM_CONTENTTYPE)
            info_list.append(b'multipart/form-data')
        return (item[0], tuple(info_list))

Lastly, here is the method encode_strings in which the given strings are encoded to bytestrings:

def encode_strings(self, request_url, custom_headers, further_directives, proxy, upload_fields = None, upload_files = None):
        """
        Turns all given strings into bytes to be processable by PycURL.
        """

        custom_headers = [] if custom_headers is None else custom_headers
        upload_fields = {} if upload_fields is None else upload_fields
        upload_files = {} if upload_files is None else upload_files
        further_directives = {} if further_directives is None else further_directives
        proxy = {} if proxy is None else proxy

        request_url = bytes(request_url, 'UTF-8')
        for i in range(len(custom_headers)):
            if isinstance(custom_headers[i], str):
                custom_headers[i] = bytes(custom_headers[i], 'UTF-8')
        for k, v in further_directives.items():
            if isinstance(v, str):
                further_directives[k] = bytes(further_directives[k], 'UTF-8')
        for k, v in proxy.items():
            if isinstance(v, str):
                proxy[k] = bytes(proxy[k], 'UTF-8')
        for k, v in upload_fields.items():
            if isinstance(v, str):
                upload_fields[k] = bytes(upload_fields[k], 'UTF-8')
        for k, v in upload_files.items():
            if isinstance(v, dict):
                for key, value in v.items():
                    if isinstance(value, str):
                        upload_files[k][key] = bytes(upload_files[k][key], 'UTF-8')
        
        if len(upload_fields) == 0 and len(upload_files) == 0:
            return request_url, custom_headers, further_directives, proxy
        else:
            return request_url, custom_headers, further_directives, proxy, upload_fields, upload_files

I hope anybody has an idea what the problem could be or even could resolve this issue, really loosing my marbles over this...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文