diff options
author | Oleg Pudeyev <code@olegp.name> | 2021-07-17 16:14:49 -0400 |
---|---|---|
committer | Oleg Pudeyev <code@olegp.name> | 2021-07-17 16:14:49 -0400 |
commit | 9d20c737e150a3b9110d0b88f7218a590bb30121 (patch) | |
tree | fd1b9eff9c0a805c28b799d609b6d77183ba0c86 | |
parent | 3a97433c3920b01303de0b8ba918ec03120fd167 (diff) | |
parent | 6b637a03ff8c6b640ca7a0f7e354351b2385109b (diff) | |
download | pycurl-9d20c737e150a3b9110d0b88f7218a590bb30121.tar.gz |
Merge branch 'master' into pr-655
* master:
Depend on o-nose-show-skipped to get unreleased fixes i nose-show-skipped
Best effort python 2 support. See #652
failonerror_test: skip the test with curl-7.75.0+
option_constants_test: skip check of SSLVERSION_SSLv*
curl_version_info_struct lags behind curl #662
Allow to get CURLINFO_CONDITION_UNMET
Remove bintray from docs
docs: fix typos
docs(quickstart): only show Python 3 code
Expose MAX_CONCURRENT_STREAMS in CurlMulti
src/module.c: make the code compile against python-3.10.0a1
Build documentation using specified Python version
Use make -C for building fake-curl
-rw-r--r-- | INSTALL.rst | 5 | ||||
-rw-r--r-- | Makefile | 10 | ||||
-rw-r--r-- | README.kr.rst | 3 | ||||
-rw-r--r-- | README.rst | 3 | ||||
-rw-r--r-- | doc/index.rst | 5 | ||||
-rw-r--r-- | doc/quickstart.rst | 62 | ||||
-rw-r--r-- | setup.py | 14 | ||||
-rw-r--r-- | src/easy.c | 2 | ||||
-rw-r--r-- | src/easyinfo.c | 4 | ||||
-rw-r--r-- | src/module.c | 40 | ||||
-rw-r--r-- | src/multi.c | 13 | ||||
-rw-r--r-- | src/pycurl.h | 4 | ||||
-rw-r--r-- | tests/failonerror_test.py | 6 | ||||
-rw-r--r-- | tests/option_constants_test.py | 9 | ||||
-rwxr-xr-x | tests/travis/run.sh | 2 | ||||
-rw-r--r-- | tests/util.py | 15 |
16 files changed, 125 insertions, 72 deletions
diff --git a/INSTALL.rst b/INSTALL.rst index f1d0acd..8f085c9 100644 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -128,9 +128,6 @@ install PycURL by running: pip install pycurl -If you are not using pip, EXE and MSI installers are available in the -`download area`_. - Both 32-bit and 64-bit builds of PycURL are available for Windows. @@ -265,8 +262,6 @@ Prerequisites: if this is not the case edit it as needed. ``winbuild.py`` itself can be run with any Python it supports. -.. _`download area`: https://dl.bintray.com/pycurl/pycurl/ - Git Checkout ------------ @@ -100,7 +100,7 @@ build-release: $(RELEASE_SOURCES) PYCURL_RELEASE=1 $(PYTHON) setup.py build do-test: - cd tests/fake-curl/libcurl && make + make -C tests/fake-curl/libcurl ./tests/run.sh ./tests/ext/test-suite.sh $(PYFLAKES) python examples tests setup.py @@ -145,9 +145,9 @@ run-quickstart: docs: build mkdir -p build/docstrings for file in doc/docstrings/*.rst; do tail -n +3 $$file >build/docstrings/`basename $$file`; done - PYTHONSUFFIX=$$(python -V 2>&1 |awk '{print $$2}' |awk -F. '{print $$1 "." $$2}') && \ + PYTHONSUFFIX=$$($(PYTHON) -V 2>&1 |awk '{print $$2}' |awk -F. '{print $$1 "." $$2}') && \ PYTHONPATH=$$(ls -d build/lib.*$$PYTHONSUFFIX):$$PYTHONPATH \ - sphinx-build doc build/doc + $(PYTHON) -m sphinx doc build/doc cp ChangeLog build/doc # Rebuild all documentation. @@ -157,9 +157,9 @@ docs-force: build # sphinx-docs has an -a option but it does not seem to always # rebuild everything rm -rf build/doc - PYTHONSUFFIX=$$(python -V 2>&1 |awk '{print $$2}' |awk -F. '{print $$1 "." $$2}') && \ + PYTHONSUFFIX=$$($(PYTHON) -V 2>&1 |awk '{print $$2}' |awk -F. '{print $$1 "." $$2}') && \ PYTHONPATH=$$(ls -d build/lib.*$$PYTHONSUFFIX):$$PYTHONPATH \ - sphinx-build doc build/doc + $(PYTHON) -m sphinx doc build/doc cp ChangeLog build/doc www: docs diff --git a/README.kr.rst b/README.kr.rst index 0684e66..536fe0a 100644 --- a/README.kr.rst +++ b/README.kr.rst @@ -34,13 +34,12 @@ urllib_ Python 모듈과 마찬가지로, PycURL 을 사용하여 Python프로 설치 ---- -`PyPI`_ 또는 `Bintray`_ 에서 소스 및 바이너리 배포판을 다운로드 하십시오. +`PyPI`_ 에서 소스 및 바이너리 배포판을 다운로드 하십시오. 이제 바이너리 휘을 32 비트 및 64 비트 Windows 버전에서 사용할 수 있습니다. 설치 지침은 `INSTALL.rst`_ 를 참조하십시오. Git checkout에서 설치하는 경우, INSTALL.rst 의 `Git Checkout`_ 섹션의 지침을 따르십시오. .. _PyPI: https://pypi.python.org/pypi/pycurl -.. _Bintray: https://dl.bintray.com/pycurl/pycurl/ .. _INSTALL.rst: http://pycurl.io/docs/latest/install.html .. _Git Checkout: http://pycurl.io/docs/latest/install.html#git-checkout @@ -39,7 +39,7 @@ Requirements Installation ------------ -Download source and binary distributions from `PyPI`_ or `Bintray`_. +Download source and binary distributions from `PyPI`_. Binary wheels are now available for 32 and 64 bit Windows versions. Please see `INSTALL.rst`_ for installation instructions. If installing from @@ -47,7 +47,6 @@ a Git checkout, please follow instruction in the `Git Checkout`_ section of INSTALL.rst. .. _PyPI: https://pypi.python.org/pypi/pycurl -.. _Bintray: https://dl.bintray.com/pycurl/pycurl/ .. _INSTALL.rst: http://pycurl.io/docs/latest/install.html .. _Git Checkout: http://pycurl.io/docs/latest/install.html#git-checkout diff --git a/doc/index.rst b/doc/index.rst index 7dc1d73..1d26d74 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -78,11 +78,6 @@ On Windows, use pip to install a binary wheel for Python 2.7, 3.5 or 3.6:: pip install pycurl -If not using pip, binary distributions in other formats are available -`on Bintray`_. - -.. _on Bintray: https://dl.bintray.com/pycurl/pycurl/ - Support ------- diff --git a/doc/quickstart.rst b/doc/quickstart.rst index 7170e36..22607f9 100644 --- a/doc/quickstart.rst +++ b/doc/quickstart.rst @@ -12,24 +12,29 @@ PycURL, the following steps are required: 2. Use ``setopt`` to set options. 3. Call ``perform`` to perform the operation. -Here is how we can retrieve a network resource in Python 2:: +Here is how we can retrieve a network resource in Python 3:: import pycurl - from StringIO import StringIO + import certifi + from io import BytesIO - buffer = StringIO() + buffer = BytesIO() c = pycurl.Curl() c.setopt(c.URL, 'http://pycurl.io/') c.setopt(c.WRITEDATA, buffer) + c.setopt(c.CAINFO, certifi.where()) c.perform() c.close() body = buffer.getvalue() - # Body is a string in some encoding. - # In Python 2, we can print it without knowing what the encoding is. - print(body) + # Body is a byte string. + # We have to know the encoding in order to print it to a text file + # such as standard output. + print(body.decode('iso-8859-1')) -This code is available as ``examples/quickstart/get_python2.py``. +This code is available as ``examples/quickstart/get_python3.py``. +For a Python 2 only example, see ``examples/quickstart/get_python2.py``. +For an example targeting Python 2 and 3, see ``examples/quickstart/get.py``. PycURL does not provide storage for the network response - that is the application's job. Therefore we must setup a buffer (in the form of a @@ -44,36 +49,6 @@ While the WRITEFUNCTION idiom continues to work, it is now unnecessary. As of PycURL 7.19.3 WRITEDATA accepts any Python object with a ``write`` method. -Python 3 version is slightly more complicated:: - - import pycurl - from io import BytesIO - - buffer = BytesIO() - c = pycurl.Curl() - c.setopt(c.URL, 'http://pycurl.io/') - c.setopt(c.WRITEDATA, buffer) - c.perform() - c.close() - - body = buffer.getvalue() - # Body is a byte string. - # We have to know the encoding in order to print it to a text file - # such as standard output. - print(body.decode('iso-8859-1')) - -This code is available as ``examples/quickstart/get_python3.py``. - -In Python 3, PycURL returns the response body as a byte string. -This is handy if we are downloading a binary file, but for text documents -we must decode the byte string. In the above example, we assume that the -body is encoded in iso-8859-1. - -Python 2 and Python 3 versions can be combined. Doing so requires decoding -the response body as in Python 3 version. The code for the combined -example can be found in ``examples/quickstart/get.py``. - - Working With HTTPS ------------------ @@ -85,9 +60,9 @@ if not, consider using the `certifi`_ Python package:: import pycurl import certifi - from StringIO import StringIO + from io import BytesIO - buffer = StringIO() + buffer = BytesIO() c = pycurl.Curl() c.setopt(c.URL, 'https://python.org/') c.setopt(c.WRITEDATA, buffer) @@ -96,10 +71,13 @@ if not, consider using the `certifi`_ Python package:: c.close() body = buffer.getvalue() - print(body) + # Body is a byte string. + # We have to know the encoding in order to print it to a text file + # such as standard output. + print(body.decode('iso-8859-1')) -This code is available as ``examples/quickstart/get_python2_https.py`` and -``examples/quickstart/get_python3_https.py``. +This code is available as ``examples/quickstart/get_python3_https.py``. +For a Python 2 example, see ``examples/quickstart/get_python2_https.py``. Troubleshooting @@ -511,6 +511,17 @@ manually. For other SSL backends please ignore this message.''') ('libidn', ctypes.c_char_p), ('iconv_ver_num', ctypes.c_int), ('libssh_version', ctypes.c_char_p), + ('brotli_ver_num', ctypes.c_uint), + ('brotli_version', ctypes.c_char_p), + ('nghttp2_ver_num', ctypes.c_uint), + ('nghttp2_version', ctypes.c_char_p), + ('quic_version', ctypes.c_char_p), + ('cainfo', ctypes.c_char_p), + ('capath', ctypes.c_char_p), + ('zstd_ver_num', ctypes.c_uint), + ('zstd_version', ctypes.c_char_p), + ('hyper_version', ctypes.c_char_p), + ('gsasl_version', ctypes.c_char_p), ] dll = ctypes.CDLL(dll_path) @@ -850,13 +861,12 @@ Requirements Installation ------------ -Download source and binary distributions from `PyPI`_ or `Bintray`_. +Download source and binary distributions from `PyPI`_. Binary wheels are now available for 32 and 64 bit Windows versions. Please see `the installation documentation`_ for installation instructions. .. _PyPI: https://pypi.python.org/pypi/pycurl -.. _Bintray: https://dl.bintray.com/pycurl/pycurl/ .. _the installation documentation: http://pycurl.io/docs/latest/install.html @@ -43,7 +43,7 @@ check_curl_state(const CurlObject *self, int flags, const char *name) /* --------------- construct/destruct (i.e. open/close) --------------- */ -/* initializer - used to intialize curl easy handles for use with pycurl */ +/* initializer - used to initialize curl easy handles for use with pycurl */ static int util_curl_init(CurlObject *self) { diff --git a/src/easyinfo.c b/src/easyinfo.c index 3712646..5412a5a 100644 --- a/src/easyinfo.c +++ b/src/easyinfo.c @@ -157,7 +157,9 @@ do_curl_getinfo_raw(CurlObject *self, PyObject *args) #ifdef HAVE_CURLINFO_HTTP_VERSION case CURLINFO_HTTP_VERSION: #endif - +#ifdef HAVE_CURL_7_19_4_OPTS + case CURLINFO_CONDITION_UNMET: +#endif { /* Return PyInt as result */ long l_res = -1; diff --git a/src/module.c b/src/module.c index 65e8c3a..8bb0fd3 100644 --- a/src/module.c +++ b/src/module.c @@ -11,6 +11,12 @@ #define PYCURL_VERSION_PREFIX "PycURL/" PYCURL_VERSION_STRING +/* needed for compatibility with python < 3.10, as suggested at: + * https://docs.python.org/3.10/whatsnew/3.10.html#id2 */ +#if PY_VERSION_HEX < 0x030900A4 +# define Py_SET_TYPE(obj, type) ((Py_TYPE(obj) = (type)), (void)0) +#endif + PYCURL_INTERNAL char *empty_keywords[] = { NULL }; PYCURL_INTERNAL PyObject *bytesio = NULL; @@ -412,9 +418,9 @@ initpycurl(void) p_Curl_Type = &Curl_Type; p_CurlMulti_Type = &CurlMulti_Type; p_CurlShare_Type = &CurlShare_Type; - Py_TYPE(&Curl_Type) = &PyType_Type; - Py_TYPE(&CurlMulti_Type) = &PyType_Type; - Py_TYPE(&CurlShare_Type) = &PyType_Type; + Py_SET_TYPE(&Curl_Type, &PyType_Type); + Py_SET_TYPE(&CurlMulti_Type, &PyType_Type); + Py_SET_TYPE(&CurlShare_Type, &PyType_Type); /* Create the module and add the functions */ if (PyType_Ready(&Curl_Type) < 0) @@ -1065,6 +1071,9 @@ initpycurl(void) insint_m(d, "M_PIPELINING_SITE_BL", CURLMOPT_PIPELINING_SITE_BL); insint_m(d, "M_PIPELINING_SERVER_BL", CURLMOPT_PIPELINING_SERVER_BL); #endif +#ifdef HAVE_CURL_7_67_0_MULTI_STREAMS + insint_m(d, "M_MAX_CONCURRENT_STREAMS", CURLMOPT_MAX_CONCURRENT_STREAMS); +#endif #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 43, 0) insint_m(d, "PIPE_NOTHING", CURLPIPE_NOTHING); @@ -1362,6 +1371,31 @@ initpycurl(void) #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 47, 0) insint(d, "VERSION_PSL", CURL_VERSION_PSL); #endif +#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) + insint(d, "CURL_VERSION_HTTPS_PROXY", CURL_VERSION_HTTPS_PROXY); +#endif +#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 56, 0) + insint(d, "CURL_VERSION_MULTI_SSL", CURL_VERSION_MULTI_SSL); +#endif +#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 57, 0) + insint(d, "CURL_VERSION_BROTLI", CURL_VERSION_BROTLI); +#endif +#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 64, 1) + insint(d, "CURL_VERSION_ALTSVC", CURL_VERSION_ALTSVC); +#endif +#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 66, 0) + insint(d, "CURL_VERSION_HTTP3", CURL_VERSION_HTTP3); +#endif +#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 72, 0) + insint(d, "CURL_VERSION_UNICODE", CURL_VERSION_UNICODE); + insint(d, "CURL_VERSION_ZSTD", CURL_VERSION_ZSTD); +#endif +#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 74, 0) + insint(d, "CURL_VERSION_HSTS", CURL_VERSION_HSTS); +#endif +#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 76, 0) + insint(d, "CURL_VERSION_GSASL", CURL_VERSION_GSASL); +#endif /** ** the order of these constants mostly follows <curl/multi.h> diff --git a/src/multi.c b/src/multi.c index 5181119..4bade73 100644 --- a/src/multi.c +++ b/src/multi.c @@ -276,6 +276,9 @@ do_multi_setopt_int(CurlMultiObject *self, int option, PyObject *obj) case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE: case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE: #endif +#ifdef HAVE_CURL_7_67_0_MULTI_STREAMS + case CURLMOPT_MAX_CONCURRENT_STREAMS: +#endif curl_multi_setopt(self->multi_handle, option, d); break; default: @@ -806,11 +809,17 @@ do_multi_info_read(CurlMultiObject *self, PyObject *args) } else { /* Create a result tuple that will get added to err_list. */ - PyObject *error_str = PyUnicode_DecodeLocale(co->error, "surrogateescape"); + PyObject *error_str = NULL; + PyObject *v; +#if PY_MAJOR_VERSION >= 3 + error_str = PyUnicode_DecodeLocale(co->error, "surrogateescape"); if (error_str == NULL) { goto error; } - PyObject *v = Py_BuildValue("(OiO)", (PyObject *)co, (int)msg->data.result, error_str); + v = Py_BuildValue("(OiO)", (PyObject *)co, (int)msg->data.result, error_str); +#else + v = Py_BuildValue("(Ois)", (PyObject *)co, (int)msg->data.result, co->error); +#endif /* Append curl object to list of objects which failed */ if (v == NULL || PyList_Append(err_list, v) != 0) { Py_XDECREF(error_str); diff --git a/src/pycurl.h b/src/pycurl.h index 95e08b3..31d1eac 100644 --- a/src/pycurl.h +++ b/src/pycurl.h @@ -163,6 +163,10 @@ pycurl_inet_ntop (int family, void *addr, char *string, size_t string_size); #define HAVE_CURL_GLOBAL_SSLSET #endif +#if LIBCURL_VERSION_NUM >= 0x074300 /* check for 7.67.0 or greater */ +#define HAVE_CURL_7_67_0_MULTI_STREAMS +#endif + #undef UNUSED #define UNUSED(var) ((void)&var) diff --git a/tests/failonerror_test.py b/tests/failonerror_test.py index dc4d8cd..519aed8 100644 --- a/tests/failonerror_test.py +++ b/tests/failonerror_test.py @@ -21,6 +21,8 @@ class FailonerrorTest(unittest.TestCase): # not sure what the actual min is but 7.26 is too old # and does not include status text, only the status code @util.min_libcurl(7, 38, 0) + # no longer supported by libcurl: https://github.com/curl/curl/issues/6615 + @util.removed_in_libcurl(7, 75, 0) def test_failonerror(self): self.curl.setopt(pycurl.URL, 'http://%s:8380/status/403' % localhost) sio = util.BytesIO() @@ -41,6 +43,8 @@ class FailonerrorTest(unittest.TestCase): # not sure what the actual min is but 7.26 is too old # and does not include status text, only the status code @util.min_libcurl(7, 38, 0) + # no longer supported by libcurl: https://github.com/curl/curl/issues/6615 + @util.removed_in_libcurl(7, 75, 0) def test_failonerror_status_line_invalid_utf8_python2(self): self.curl.setopt(pycurl.URL, 'http://%s:8380/status_invalid_utf8' % localhost) sio = util.BytesIO() @@ -61,6 +65,8 @@ class FailonerrorTest(unittest.TestCase): # not sure what the actual min is but 7.26 is too old # and does not include status text, only the status code @util.min_libcurl(7, 38, 0) + # no longer supported by libcurl: https://github.com/curl/curl/issues/6615 + @util.removed_in_libcurl(7, 75, 0) def test_failonerror_status_line_invalid_utf8_python3(self): self.curl.setopt(pycurl.URL, 'http://%s:8380/status_invalid_utf8' % localhost) sio = util.BytesIO() diff --git a/tests/option_constants_test.py b/tests/option_constants_test.py index 6791c31..b8aab1e 100644 --- a/tests/option_constants_test.py +++ b/tests/option_constants_test.py @@ -163,9 +163,16 @@ class OptionConstantsTest(unittest.TestCase): def test_sslversion_options(self): curl = pycurl.Curl() curl.setopt(curl.SSLVERSION, curl.SSLVERSION_DEFAULT) + curl.setopt(curl.SSLVERSION, curl.SSLVERSION_TLSv1) + curl.close() + + # SSLVERSION_SSLv* return CURLE_BAD_FUNCTION_ARGUMENT with curl-7.77.0 + @util.removed_in_libcurl(7, 77, 0) + @util.only_ssl + def test_legacy_sslversion_options(self): + curl = pycurl.Curl() curl.setopt(curl.SSLVERSION, curl.SSLVERSION_SSLv2) curl.setopt(curl.SSLVERSION, curl.SSLVERSION_SSLv3) - curl.setopt(curl.SSLVERSION, curl.SSLVERSION_TLSv1) curl.close() @util.min_libcurl(7, 34, 0) diff --git a/tests/travis/run.sh b/tests/travis/run.sh index 7eaf7ad..c71630f 100755 --- a/tests/travis/run.sh +++ b/tests/travis/run.sh @@ -45,7 +45,7 @@ fi make gen python setup.py build $setup_args -(cd tests/fake-curl/libcurl && make) +make -C tests/fake-curl/libcurl ldd build/lib*/pycurl*.so diff --git a/tests/util.py b/tests/util.py index c53b96a..542175f 100644 --- a/tests/util.py +++ b/tests/util.py @@ -115,6 +115,21 @@ def min_libcurl(major, minor, patch): return decorator +def removed_in_libcurl(major, minor, patch): + import nose.plugins.skip + + def decorator(fn): + @functools.wraps(fn) + def decorated(*args, **kwargs): + if not pycurl_version_less_than(major, minor, patch): + raise nose.plugins.skip.SkipTest('libcurl >= %d.%d.%d' % (major, minor, patch)) + + return fn(*args, **kwargs) + + return decorated + + return decorator + def only_ssl(fn): import pycurl |