openSUSE Commits
Threads by month
- ----- 2024 -----
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
July 2019
- 2 participants
- 2045 discussions
Hello community,
here is the log from the commit of package python-pytest-sugar for openSUSE:Factory checked in at 2019-07-30 13:06:11
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pytest-sugar (Old)
and /work/SRC/openSUSE:Factory/.python-pytest-sugar.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pytest-sugar"
Tue Jul 30 13:06:11 2019 rev:5 rq:718214 version:0.9.2
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pytest-sugar/python-pytest-sugar.changes 2019-02-24 17:04:38.552644872 +0100
+++ /work/SRC/openSUSE:Factory/.python-pytest-sugar.new.4126/python-pytest-sugar.changes 2019-07-30 13:06:12.570375040 +0200
@@ -1,0 +2,5 @@
+Wed Jul 24 07:09:44 UTC 2019 - Tomáš Chvátal <tchvatal(a)suse.com>
+
+- Skip failing pytest5 checks that need tweaking upstream
+
+-------------------------------------------------------------------
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-pytest-sugar.spec ++++++
--- /var/tmp/diff_new_pack.2LyyCu/_old 2019-07-30 13:06:13.198374878 +0200
+++ /var/tmp/diff_new_pack.2LyyCu/_new 2019-07-30 13:06:13.202374877 +0200
@@ -23,7 +23,7 @@
Summary: Pretty printer for pytest progress
License: BSD-3-Clause
Group: Development/Languages/Python
-URL: http://pivotfinland.com/pytest-sugar/
+URL: https://github.com/Frozenball/pytest-sugar
Source: https://files.pythonhosted.org/packages/source/p/pytest-sugar/pytest-sugar-…
Patch0: pytest4.patch
BuildRequires: %{python_module pytest}
@@ -31,7 +31,7 @@
BuildRequires: %{python_module termcolor}
BuildRequires: fdupes
BuildRequires: python-rpm-macros
-Requires: python-pytest
+Requires: python-pytest < 5.0
Requires: python-termcolor
BuildArch: noarch
%python_subpackages
@@ -51,7 +51,9 @@
%python_expand %fdupes %{buildroot}%{$python_sitelib}
%check
-%python_expand PYTHONPATH=%{buildroot}%{$python_sitelib} py.test-%{$python_bin_suffix}
+# test_item_count_after_pytest_collection_modifyitems - https://github.com/Frozenball/pytest-sugar/issues/180
+# test_doctest - same as above
+%pytest -k 'not test_item_count_after_pytest_collection_modifyitems and not test_doctest'
%files %{python_files}
%license LICENSE
1
0
Hello community,
here is the log from the commit of package python-celery for openSUSE:Factory checked in at 2019-07-30 13:06:04
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-celery (Old)
and /work/SRC/openSUSE:Factory/.python-celery.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-celery"
Tue Jul 30 13:06:04 2019 rev:27 rq:718188 version:4.3.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-celery/python-celery.changes 2019-04-28 19:58:26.514971549 +0200
+++ /work/SRC/openSUSE:Factory/.python-celery.new.4126/python-celery.changes 2019-07-30 13:06:05.658376827 +0200
@@ -1,0 +2,25 @@
+Wed Jul 24 11:12:29 UTC 2019 - Tomáš Chvátal <tchvatal(a)suse.com>
+
+- Add ringdisabled to avoid pulling the test deps in rings to
+ keep them from growing too much
+
+-------------------------------------------------------------------
+Wed Jul 24 10:50:33 UTC 2019 - Tomáš Chvátal <tchvatal(a)suse.com>
+
+- Switch to multibuild in order to not pull moto everywhere
+
+-------------------------------------------------------------------
+Fri Jul 19 12:48:17 UTC 2019 - Tomáš Chvátal <tchvatal(a)suse.com>
+
+- Update to 4.3.0:
+ * See the changelog for in-depth details
+- Remove merged patches:
+ * python37-1.patch
+ * python37-2.patch
+ * python37-3.patch
+ * disable-pytest-log-capturing.patch
+ * celery-no-redis.patch
+ * relax-billiard-pin.patch
+- Rebase patch unpin-pytest.patch
+
+-------------------------------------------------------------------
Old:
----
celery-4.2.1.tar.gz
celery-no-redis.patch
disable-pytest-log-capturing.patch
python37-1.patch
python37-2.patch
python37-3.patch
relax-billiard-pin.patch
New:
----
_multibuild
celery-4.3.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-celery.spec ++++++
--- /var/tmp/diff_new_pack.QiZIQh/_old 2019-07-30 13:06:06.494376611 +0200
+++ /var/tmp/diff_new_pack.QiZIQh/_new 2019-07-30 13:06:06.498376610 +0200
@@ -17,45 +17,33 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
-Name: python-celery
-Version: 4.2.1
+%global flavor @BUILD_FLAVOR@%{nil}
+%if "%{flavor}" == "test"
+%define psuffix -test
+%bcond_without test
+%else
+%define psuffix %{nil}
+%bcond_with test
+%endif
+%bcond_with ringdisabled
+Name: python-celery%{psuffix}
+Version: 4.3.0
Release: 0
Summary: Distributed Task Queue module for Python
License: BSD-3-Clause
Group: Development/Languages/Python
URL: http://celeryproject.org
Source: https://files.pythonhosted.org/packages/source/c/celery/celery-%{version}.t…
-Patch0: disable-pytest-log-capturing.patch
-Patch1: celery-no-redis.patch
Patch2: unpin-pytest.patch
-Patch3: relax-billiard-pin.patch
-# Upstream patches for Python 3.7 support
-Patch4: python37-1.patch
-Patch5: python37-2.patch
-Patch6: python37-3.patch
-BuildRequires: %{python_module SQLAlchemy}
-BuildRequires: %{python_module billiard >= 3.5.0.2}
-BuildRequires: %{python_module case >= 1.3.1}
-BuildRequires: %{python_module curses}
-BuildRequires: %{python_module eventlet}
-BuildRequires: %{python_module gevent}
-BuildRequires: %{python_module kombu >= 4.0.2}
-BuildRequires: %{python_module pyOpenSSL}
-BuildRequires: %{python_module pytest >= 3.0}
-BuildRequires: %{python_module python-dateutil}
-BuildRequires: %{python_module pytz >= 2016.7}
BuildRequires: %{python_module setuptools}
BuildRequires: fdupes
BuildRequires: netcfg
BuildRequires: python-rpm-macros
-Requires: python-billiard >= 3.5.0.2
-Requires: python-kombu >= 4.0.2
+Requires: python-billiard >= 3.6.0
+Requires: python-kombu >= 4.4.0
Requires: python-python-dateutil
Requires: python-pytz >= 2016.7
-Requires: python-vine
-%ifpython3
-Requires: python3-dbm
-%endif
+Requires: python-vine >= 1.3.0
Recommends: python-curses
Recommends: python-pyOpenSSL
Suggests: python-eventlet
@@ -64,6 +52,28 @@
Suggests: python-python-daemon
Suggests: python-pytyrant
BuildArch: noarch
+%if %{with test}
+BuildRequires: %{python_module SQLAlchemy}
+BuildRequires: %{python_module billiard >= 3.6.0}
+BuildRequires: %{python_module boto3 >= 1.9.125}
+BuildRequires: %{python_module case >= 1.3.1}
+BuildRequires: %{python_module curses}
+BuildRequires: %{python_module eventlet}
+BuildRequires: %{python_module gevent}
+BuildRequires: %{python_module kombu >= 4.4.0}
+BuildRequires: %{python_module moto >= 1.3.7}
+BuildRequires: %{python_module pyOpenSSL}
+BuildRequires: %{python_module pytest >= 4.3.1}
+BuildRequires: %{python_module python-dateutil}
+BuildRequires: %{python_module pytz >= 2016.7}
+BuildRequires: %{python_module vine >= 1.3.0}
+%if %{with ringdisabled}
+ExclusiveArch: do-not-build
+%endif
+%endif
+%ifpython3
+Requires: python3-dbm
+%endif
%python_subpackages
%description
@@ -74,21 +84,29 @@
%prep
%setup -q -n celery-%{version}
%autopatch -p1
+# do not hardcode versions
+sed -i -e 's:==:>=:g' requirements/*.txt
%build
%python_build
%install
+%if !%{with test}
%python_install
%python_expand %fdupes %{buildroot}%{$python_sitelib}
+%endif
%check
+%if %{with test}
%python_exec setup.py test
+%endif
+%if !%{with test}
%files %{python_files}
%{python_sitelib}/*
%license LICENSE
%doc Changelog README.rst TODO
%python3_only %{_bindir}/celery*
+%endif
%changelog
++++++ _multibuild ++++++
<multibuild>
<package>test</package>
</multibuild>
++++++ celery-4.2.1.tar.gz -> celery-4.3.0.tar.gz ++++++
++++ 14523 lines of diff (skipped)
++++++ unpin-pytest.patch ++++++
--- /var/tmp/diff_new_pack.QiZIQh/_old 2019-07-30 13:06:06.722376552 +0200
+++ /var/tmp/diff_new_pack.QiZIQh/_new 2019-07-30 13:06:06.726376551 +0200
@@ -1,6 +1,10 @@
---- celery-4.2.1/requirements/test.txt.orig 2019-02-21 17:43:53.252577134 +0700
-+++ celery-4.2.1/requirements/test.txt 2019-02-21 17:44:02.860644766 +0700
-@@ -1,2 +1,2 @@
+Index: celery-4.3.0/requirements/test.txt
+===================================================================
+--- celery-4.3.0.orig/requirements/test.txt
++++ celery-4.3.0/requirements/test.txt
+@@ -1,4 +1,4 @@
case>=1.3.1
--pytest>=3.0,<3.3
-+pytest>=3.0
+-pytest>=4.3.1,<4.4.0
++pytest>=4.3.1
+ boto3>=1.4.6
+ moto==1.3.7
1
0
Hello community,
here is the log from the commit of package python-execnet for openSUSE:Factory checked in at 2019-07-30 13:05:58
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-execnet (Old)
and /work/SRC/openSUSE:Factory/.python-execnet.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-execnet"
Tue Jul 30 13:05:58 2019 rev:9 rq:718149 version:1.6.1
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-execnet/python-execnet.changes 2019-04-04 12:00:22.401267225 +0200
+++ /work/SRC/openSUSE:Factory/.python-execnet.new.4126/python-execnet.changes 2019-07-30 13:06:00.850378075 +0200
@@ -1,0 +2,18 @@
+Wed Jul 24 08:57:00 UTC 2019 - Tomáš Chvátal <tchvatal(a)suse.com>
+
+- Update to 1.6.1:
+ * Internal change to avoid using deprecated funcargs name in pytest 5+.
+- Obsoletes pytest4.patch
+
+-------------------------------------------------------------------
+Fri Jul 19 09:14:51 UTC 2019 - Tomáš Chvátal <tchvatal(a)suse.com>
+
+- Add patch to play with new pytest rather than restricting:
+ * pytest4.patch
+
+-------------------------------------------------------------------
+Thu Jul 18 08:47:00 UTC 2019 - Ondřej Súkup <mimi.vx(a)gmail.com>
+
+- use pytest4 to run testsuite, pytest-5 for testsuite isn't supported
+
+-------------------------------------------------------------------
Old:
----
execnet-1.6.0.tar.gz
New:
----
execnet-1.6.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-execnet.spec ++++++
--- /var/tmp/diff_new_pack.mBgfOP/_old 2019-07-30 13:06:01.950377785 +0200
+++ /var/tmp/diff_new_pack.mBgfOP/_new 2019-07-30 13:06:01.950377785 +0200
@@ -18,7 +18,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-execnet
-Version: 1.6.0
+Version: 1.6.1
Release: 0
Summary: Rapid multi-Python deployment
License: MIT
@@ -26,11 +26,11 @@
URL: https://github.com/pytest-dev/execnet
Source0: https://files.pythonhosted.org/packages/source/e/execnet/execnet-%{version}…
BuildRequires: %{python_module apipkg}
-BuildRequires: %{python_module base}
BuildRequires: %{python_module pytest}
BuildRequires: %{python_module setuptools_scm}
BuildRequires: %{python_module setuptools}
BuildRequires: fdupes
+BuildRequires: procps
BuildRequires: python-rpm-macros
Requires: python-apipkg
BuildArch: noarch
@@ -58,10 +58,10 @@
%install
%python_install
-%python_expand %fdupes -s %{buildroot}%{$python_sitelib}
+%python_expand %fdupes %{buildroot}%{$python_sitelib}
%check
-%python_expand PYTHONPATH=build/lib py.test-%{$python_version} -r s -k"-test_gateway" testing
+%pytest -r s -k"not test_gateway" testing
%files %{python_files}
%license LICENSE
++++++ execnet-1.6.0.tar.gz -> execnet-1.6.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/execnet-1.6.0/.travis.yml new/execnet-1.6.1/.travis.yml
--- old/execnet-1.6.0/.travis.yml 2019-03-31 23:11:54.000000000 +0200
+++ new/execnet-1.6.1/.travis.yml 2019-07-22 23:16:42.000000000 +0200
@@ -43,7 +43,7 @@
distributions: sdist bdist_wheel
skip_upload_docs: true
password:
- secure: "gnnagE3aOIHwv+Wonhn4+Ge3biuC8pOCN+aKIOko4ZOWgZlTBZjNSP/PFdhOmQp1sYHsm98GLubF5D5aEmKYQQOkiUn5PLMjyBjijN5qF5wwKK22MR73MCw+zVXt/o5K0uFiXPFTXzRlT2VrD86tjjGIOUQqpXBvm9X+8wu1nL8OkzurWRDzeY8Sv1XopOh6v0PD85fxu6pkFv4iVvNTUytIqTLU4LJTNFdfuWMQvr1JMHgtQUsCdT4CvSPsvu4WGAsYMyNAQFtNJwxqukkPySgVv5vTIdHfnCMURm6vjv9oprO5t3O6fDJS3K/EWxmz5+3CfRBJ20OdDUM62DKsVbjg2rSjuwiafgFKcs+Ob20CalvF4ZOwddQGz3I8n0I0zJarGhEmr/c9XXY31LH/Y3FaghUUYOq4Hfh8+mEZgE7MGyvRjD8zA2Cq8cfOivqg9dM7HQniZSybSCkF47pF+qwRPzYkC9dm8IHi24v1/hA8d7uuXel44dauJiGJqvQ7qN0Bh4ZEuE1EVju+v8NwlTk6C93ShzIRhKUZVx1GgoI/KorRgIlRbd6I24xo2kKtXw2mb5+dnbsL2ip/ungw+saTZsXSWICY/L0Nv+WHWl7DskwSSdl/iKJaztv/7975wXSxLEG+K6xweufx5N6eTh9A1Sa7YLBDOEpTC4lkq0A="
+ secure: "l+Khw6WjS1tX+jQ2sGLneAXB7iRKctBx1SnU9jCnRHj1VEN3FhNSKkwaHOvUM56WaPS8Z6KZeDzd4qk0o8bSz+ee+ofpODX+ueherWh3I5pBXdgVC9mpFO5hznBxqSDE/9dvCfPnjed8FE3uMICLxB+0A45zZONaMp1SWSTorOJ7t6MJ9YJwefiCW2Jsw8qcNDJlF2jUzfpOOOMhN824v9R57/o8UnXle9RwqqClq/7OMNqDtFGdYbbLgxoS7RxiknyJ+kRG95bxF/lknPcRrOkpSL+xNcweiFA/cNlz/JQrh6j7HCvUfQYkHAT64CuderUcAHOLhwTDf56j6DSoArxrNKN8vg0wsMqw9wpHI/MmSrw0LMN8MpHXRF902K+DPgxn/yNyJTKR4E3ZZEpJDIYf3Z1K15I2Px/K11r42wP3ulo6yEX7PX6qgPgsRhQuiI8MLrdFnfAjSSWunUsIUGOzO5q/gzaFLT8XlIGI6exuUlyYJfu9Fhtd3PSuEUnxuvEbWLrhOTUfCtVdq9aNV0NiF1bVjPcA0UawD5XUzH7rfBXbkcSHK12C/HzOGUR5UlNeiHnOSVx7FBy7OqbS7/5aBYWtkrAB1cIuhNLJSjOCzGphKvjQtxBja1iJk0atSS4kEKra723rlOZZ6r75bdL9QhB/P5YEnWTIVMbkPZ0="
on:
tags: true
repo: pytest-dev/execnet
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/execnet-1.6.0/CHANGELOG.rst new/execnet-1.6.1/CHANGELOG.rst
--- old/execnet-1.6.0/CHANGELOG.rst 2019-03-31 23:11:54.000000000 +0200
+++ new/execnet-1.6.1/CHANGELOG.rst 2019-07-22 23:16:42.000000000 +0200
@@ -1,3 +1,9 @@
+1.6.1 (2019-07-22)
+------------------
+
+* `#98 <https://github.com/pytest-dev/execnet/pull/98>`__: Internal change to avoid
+ using deprecated ``funcargs`` name in pytest 5+.
+
1.6.0 (2019-03-31)
------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/execnet-1.6.0/PKG-INFO new/execnet-1.6.1/PKG-INFO
--- old/execnet-1.6.0/PKG-INFO 2019-03-31 23:12:14.000000000 +0200
+++ new/execnet-1.6.1/PKG-INFO 2019-07-22 23:19:03.000000000 +0200
@@ -1,11 +1,16 @@
Metadata-Version: 1.2
Name: execnet
-Version: 1.6.0
+Version: 1.6.1
Summary: execnet: rapid multi-Python deployment
Home-page: https://execnet.readthedocs.io/en/latest/
Author: holger krekel and others
License: MIT
-Description: execnet: distributed Python deployment and communication
+Description: .. warning::
+
+ execnet is currently not maintained
+
+
+ execnet: distributed Python deployment and communication
========================================================
.. image:: https://img.shields.io/pypi/v/execnet.svg
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/execnet-1.6.0/README.rst new/execnet-1.6.1/README.rst
--- old/execnet-1.6.0/README.rst 2019-03-31 23:11:54.000000000 +0200
+++ new/execnet-1.6.1/README.rst 2019-07-22 23:16:42.000000000 +0200
@@ -1,3 +1,8 @@
+.. warning::
+
+ execnet is currently not maintained
+
+
execnet: distributed Python deployment and communication
========================================================
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/execnet-1.6.0/execnet/_version.py new/execnet-1.6.1/execnet/_version.py
--- old/execnet-1.6.0/execnet/_version.py 2019-03-31 23:12:14.000000000 +0200
+++ new/execnet-1.6.1/execnet/_version.py 2019-07-22 23:19:02.000000000 +0200
@@ -1,4 +1,4 @@
# coding: utf-8
# file generated by setuptools_scm
# don't change, don't track in version control
-version = '1.6.0'
+version = '1.6.1'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/execnet-1.6.0/execnet.egg-info/PKG-INFO new/execnet-1.6.1/execnet.egg-info/PKG-INFO
--- old/execnet-1.6.0/execnet.egg-info/PKG-INFO 2019-03-31 23:12:14.000000000 +0200
+++ new/execnet-1.6.1/execnet.egg-info/PKG-INFO 2019-07-22 23:19:02.000000000 +0200
@@ -1,11 +1,16 @@
Metadata-Version: 1.2
Name: execnet
-Version: 1.6.0
+Version: 1.6.1
Summary: execnet: rapid multi-Python deployment
Home-page: https://execnet.readthedocs.io/en/latest/
Author: holger krekel and others
License: MIT
-Description: execnet: distributed Python deployment and communication
+Description: .. warning::
+
+ execnet is currently not maintained
+
+
+ execnet: distributed Python deployment and communication
========================================================
.. image:: https://img.shields.io/pypi/v/execnet.svg
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/execnet-1.6.0/testing/conftest.py new/execnet-1.6.1/testing/conftest.py
--- old/execnet-1.6.0/testing/conftest.py 2019-03-31 23:11:55.000000000 +0200
+++ new/execnet-1.6.1/testing/conftest.py 2019-07-22 23:16:42.000000000 +0200
@@ -83,8 +83,8 @@
def pytest_generate_tests(metafunc):
- if 'gw' in metafunc.funcargnames:
- assert 'anypython' not in metafunc.funcargnames, "need combine?"
+ if 'gw' in metafunc.fixturenames:
+ assert 'anypython' not in metafunc.fixturenames, "need combine?"
if hasattr(metafunc.function, 'gwtypes'):
gwtypes = metafunc.function.gwtypes
elif hasattr(metafunc.cls, 'gwtype'):
@@ -92,7 +92,7 @@
else:
gwtypes = ['popen', 'socket', 'ssh', 'proxy']
metafunc.parametrize("gw", gwtypes, indirect=True)
- elif 'anypython' in metafunc.funcargnames:
+ elif 'anypython' in metafunc.fixturenames:
metafunc.parametrize(
"anypython", indirect=True, argvalues=(
'sys.executable', 'python2.7', 'pypy', 'jython',
1
0
Hello community,
here is the log from the commit of package python-invoke for openSUSE:Factory checked in at 2019-07-30 13:05:52
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-invoke (Old)
and /work/SRC/openSUSE:Factory/.python-invoke.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-invoke"
Tue Jul 30 13:05:52 2019 rev:7 rq:718087 version:1.2.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-invoke/python-invoke.changes 2019-03-26 22:34:35.313674418 +0100
+++ /work/SRC/openSUSE:Factory/.python-invoke.new.4126/python-invoke.changes 2019-07-30 13:05:54.806379669 +0200
@@ -1,0 +2,13 @@
+Wed Jul 24 07:25:08 UTC 2019 - Tomáš Chvátal <tchvatal(a)suse.com>
+
+- Disable tests for now as they break with new pytest-relaxed
+- Add another patch fixing errors with new pytest:
+ * pytest4.patch
+
+-------------------------------------------------------------------
+Fri Jul 19 09:59:13 UTC 2019 - Tomáš Chvátal <tchvatal(a)suse.com>
+
+- Restrict pytest5 and pytest4 for now upstream tests only with
+ pytest3...
+
+-------------------------------------------------------------------
New:
----
pytest4.patch
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-invoke.spec ++++++
--- /var/tmp/diff_new_pack.8xXQ9M/_old 2019-07-30 13:05:55.498379486 +0200
+++ /var/tmp/diff_new_pack.8xXQ9M/_new 2019-07-30 13:05:55.498379486 +0200
@@ -26,6 +26,7 @@
URL: http://www.pyinvoke.org
Source: https://files.pythonhosted.org/packages/source/i/invoke/invoke-%{version}.t…
Patch0: 0001-Make-test-fallback-to-system-modules-when-vendorized.patch
+Patch1: pytest4.patch
BuildRequires: %{python_module PyYAML}
BuildRequires: %{python_module fluidity-sm}
BuildRequires: %{python_module lexicon}
@@ -59,6 +60,7 @@
rm -r invoke/completion/__pycache__/
%patch0 -p1
+%patch1 -p1
%build
%python_build
@@ -71,7 +73,9 @@
%python_clone -a %{buildroot}%{_bindir}/invoke
%check
-%python_expand PYTHONPATH=%{buildroot}%{$python_sitelib} py.test-%{$python_bin_suffix}
+# broken with new pytest-relaxed (same author), just disable until he
+# gets around to release new version
+#%%pytest
%post
%{python_install_alternative inv invoke}
++++++ pytest4.patch ++++++
>From 84f296062a48d30a6c1497e523c21ef3fd9ab534 Mon Sep 17 00:00:00 2001
From: Marcus Crane <marcus(a)utf9k.net>
Date: Fri, 26 Oct 2018 10:52:19 +1300
Subject: [PATCH 1/3] Updated inspect method
---
invoke/tasks.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/invoke/tasks.py b/invoke/tasks.py
index ed838c31..18cf0afd 100644
--- a/invoke/tasks.py
+++ b/invoke/tasks.py
@@ -151,7 +151,7 @@ def argspec(self, body):
# TODO: __call__ exhibits the 'self' arg; do we manually nix 1st result
# in argspec, or is there a way to get the "really callable" spec?
func = body if isinstance(body, types.FunctionType) else body.__call__
- spec = inspect.getargspec(func)
+ spec = inspect.getfullargspec(func)
arg_names = spec.args[:]
matched_args = [reversed(x) for x in [spec.args, spec.defaults or []]]
spec_dict = dict(zip_longest(*matched_args, fillvalue=NO_DEFAULT))
>From db6596d63c76239a91a898ee1557084456e480f7 Mon Sep 17 00:00:00 2001
From: Marcus Crane <marcus(a)utf9k.net>
Date: Fri, 26 Oct 2018 11:49:41 +1300
Subject: [PATCH 2/3] Update inspect import to be conditional based on 2.7 or 3
---
invoke/tasks.py | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/invoke/tasks.py b/invoke/tasks.py
index 18cf0afd..cbe106b9 100644
--- a/invoke/tasks.py
+++ b/invoke/tasks.py
@@ -4,7 +4,6 @@
"""
from copy import deepcopy
-import inspect
import types
from .util import six
@@ -14,6 +13,11 @@
else:
from itertools import izip_longest as zip_longest
+try:
+ from inspect import getfullargspec as getargspec
+except AttributeError:
+ from inspect import getargspec
+
from .context import Context
from .parser import Argument, translate_underscores
@@ -151,7 +155,7 @@ def argspec(self, body):
# TODO: __call__ exhibits the 'self' arg; do we manually nix 1st result
# in argspec, or is there a way to get the "really callable" spec?
func = body if isinstance(body, types.FunctionType) else body.__call__
- spec = inspect.getfullargspec(func)
+ spec = getargspec(func)
arg_names = spec.args[:]
matched_args = [reversed(x) for x in [spec.args, spec.defaults or []]]
spec_dict = dict(zip_longest(*matched_args, fillvalue=NO_DEFAULT))
>From de3f339f4d699c0a641074ad437802307d0050ba Mon Sep 17 00:00:00 2001
From: Marcus Crane <marcus(a)utf9k.net>
Date: Fri, 26 Oct 2018 12:10:43 +1300
Subject: [PATCH 3/3] Ooops, checked AttributeError instead of ImportError
---
invoke/tasks.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/invoke/tasks.py b/invoke/tasks.py
index cbe106b9..ad08c893 100644
--- a/invoke/tasks.py
+++ b/invoke/tasks.py
@@ -15,7 +15,7 @@
try:
from inspect import getfullargspec as getargspec
-except AttributeError:
+except ImportError:
from inspect import getargspec
from .context import Context
1
0
Hello community,
here is the log from the commit of package python-pip-shims for openSUSE:Factory checked in at 2019-07-30 13:05:46
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pip-shims (Old)
and /work/SRC/openSUSE:Factory/.python-pip-shims.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pip-shims"
Tue Jul 30 13:05:46 2019 rev:2 rq:717859 version:0.3.3
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pip-shims/python-pip-shims.changes 2019-03-22 15:01:57.485762547 +0100
+++ /work/SRC/openSUSE:Factory/.python-pip-shims.new.4126/python-pip-shims.changes 2019-07-30 13:05:47.926381483 +0200
@@ -1,0 +2,8 @@
+Tue Jul 23 11:25:17 UTC 2019 - Tomáš Chvátal <tchvatal(a)suse.com>
+
+- Update to 0.3.3:
+ * Added commands.freeze.DEV_PKGS and utils.compat.stdlib_pkgs shims. #25
+ * Updated PackageFinder test and added CandidateEvaluator import starting with pip>=19.1 for finding prerelease candidates. #27
+ * Fixed import paths for VcsSupport on pip>19.1.1. #28
+
+-------------------------------------------------------------------
Old:
----
pip-shims-0.3.2.tar.gz
New:
----
pip-shims-0.3.3.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-pip-shims.spec ++++++
--- /var/tmp/diff_new_pack.aaPD2p/_old 2019-07-30 13:05:48.386381362 +0200
+++ /var/tmp/diff_new_pack.aaPD2p/_new 2019-07-30 13:05:48.386381362 +0200
@@ -18,7 +18,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-pip-shims
-Version: 0.3.2
+Version: 0.3.3
Release: 0
Summary: Compatibility shims for pip versions 8 thru current
License: ISC
@@ -56,7 +56,7 @@
%check
# Skip two online tests
-%python_expand PYTHONPATH=%{buildroot}%{$python_sitelib} $python -m pytest -k 'not (test_resolution or test_wheelbuilder)'
+%pytest -k 'not (test_resolution or test_wheelbuilder)'
%files %{python_files}
%license LICENSE
++++++ pip-shims-0.3.2.tar.gz -> pip-shims-0.3.3.tar.gz ++++++
++++ 3167 lines of diff (skipped)
1
0
Hello community,
here is the log from the commit of package python-pycountry for openSUSE:Factory checked in at 2019-07-30 13:05:40
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pycountry (Old)
and /work/SRC/openSUSE:Factory/.python-pycountry.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pycountry"
Tue Jul 30 13:05:40 2019 rev:4 rq:717841 version:19.7.15
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pycountry/python-pycountry.changes 2019-05-22 10:49:24.323382630 +0200
+++ /work/SRC/openSUSE:Factory/.python-pycountry.new.4126/python-pycountry.changes 2019-07-30 13:05:41.810383096 +0200
@@ -1,0 +2,6 @@
+Tue Jul 23 10:31:50 UTC 2019 - Tomáš Chvátal <tchvatal(a)suse.com>
+
+- Update to 19.7.15:
+ * Updates for more countries and various fixes
+
+-------------------------------------------------------------------
Old:
----
pycountry-18.12.8.tar.gz
New:
----
pycountry-19.7.15.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-pycountry.spec ++++++
--- /var/tmp/diff_new_pack.FPWKYC/_old 2019-07-30 13:05:42.534382905 +0200
+++ /var/tmp/diff_new_pack.FPWKYC/_new 2019-07-30 13:05:42.538382904 +0200
@@ -17,24 +17,23 @@
%define real_name pycountry
-
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-pycountry
-Version: 18.12.8
+Version: 19.7.15
Release: 0
Summary: Databases for ISO standards 639 3166 3166-2 4217 15924
License: LGPL-2.1-only
Group: Development/Libraries/Python
-Url: https://pypi.python.org/pypi/pycountry/
+URL: https://pypi.python.org/pypi/pycountry/
Source: https://pypi.io/packages/source/p/%{real_name}/%{real_name}-%{version}.tar.…
BuildRequires: %{python_module setuptools}
+BuildRequires: fdupes
BuildRequires: python-rpm-macros
+Requires: python-lxml
+BuildArch: noarch
# SECTION test requirements
BuildRequires: %{python_module pytest}
# /SECTION
-Requires: python-lxml
-BuildRoot: %{_tmppath}/%{name}-%{version}-build
-BuildArch: noarch
%python_subpackages
%description
@@ -52,14 +51,14 @@
%install
%python_install
+%python_expand %fdupes %{buildroot}%{$python_sitelib}
%check
%pytest
%files %{python_files}
-%defattr(-,root,root,-)
%license LICENSE.txt
-%doc README
+%doc README.rst
%{python_sitelib}/*
%changelog
++++++ pycountry-18.12.8.tar.gz -> pycountry-19.7.15.tar.gz ++++++
/work/SRC/openSUSE:Factory/python-pycountry/pycountry-18.12.8.tar.gz /work/SRC/openSUSE:Factory/.python-pycountry.new.4126/pycountry-19.7.15.tar.gz differ: char 5, line 1
1
0
Hello community,
here is the log from the commit of package python-pycurl for openSUSE:Factory checked in at 2019-07-30 13:05:33
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pycurl (Old)
and /work/SRC/openSUSE:Factory/.python-pycurl.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pycurl"
Tue Jul 30 13:05:33 2019 rev:30 rq:717837 version:7.43.0.3
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pycurl/python-pycurl.changes 2019-04-10 23:10:59.771960287 +0200
+++ /work/SRC/openSUSE:Factory/.python-pycurl.new.4126/python-pycurl.changes 2019-07-30 13:05:37.918384122 +0200
@@ -1,0 +2,10 @@
+Tue Jul 23 10:20:14 UTC 2019 - Tomáš Chvátal <tchvatal(a)suse.com>
+
+- Update to 7.43.0.3:
+ * This release primarily fixes an OpenSSL-related installation issue, and
+ repairs the ability to use PycURL with newer libcurls compiled without
+ FTP support.
+- Rebase patch:
+ * python-pycurl-7.43.0-tls-backend.patch
+
+-------------------------------------------------------------------
Old:
----
pycurl-7.43.0.2.tar.gz
New:
----
pycurl-7.43.0.3.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-pycurl.spec ++++++
--- /var/tmp/diff_new_pack.6idyEJ/_old 2019-07-30 13:05:38.334384013 +0200
+++ /var/tmp/diff_new_pack.6idyEJ/_new 2019-07-30 13:05:38.338384011 +0200
@@ -18,7 +18,6 @@
%define oldpython python
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
-
%global flavor @BUILD_FLAVOR@%{nil}
%if "%{flavor}" == "test"
%define psuffix -test
@@ -28,7 +27,7 @@
%bcond_with test
%endif
Name: python-pycurl%{psuffix}
-Version: 7.43.0.2
+Version: 7.43.0.3
Release: 0
Summary: PycURL -- cURL library module
License: LGPL-2.1-or-later AND MIT
@@ -45,9 +44,10 @@
BuildRequires: %{python_module devel}
BuildRequires: %{python_module setuptools}
BuildRequires: fdupes
-BuildRequires: libcurl-devel >= 7.19.0
-BuildRequires: openssl-devel
+BuildRequires: pkgconfig
BuildRequires: python-rpm-macros
+BuildRequires: pkgconfig(libcurl) >= 7.19.0
+BuildRequires: pkgconfig(openssl)
%if %{with test}
BuildRequires: %{python_module bottle}
BuildRequires: %{python_module flaky}
@@ -81,7 +81,7 @@
%build
export CFLAGS="%{optflags} -fno-strict-aliasing"
export PYCURL_SSL_LIBRARY=openssl
-%python_build --with-ssl
+%python_build --with-openssl
%install
export PYCURL_SSL_LIBRARY=openssl
++++++ pycurl-7.43.0.2.tar.gz -> pycurl-7.43.0.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/AUTHORS new/pycurl-7.43.0.3/AUTHORS
--- old/pycurl-7.43.0.2/AUTHORS 2018-06-02 06:59:02.000000000 +0200
+++ new/pycurl-7.43.0.3/AUTHORS 2019-06-17 07:49:30.000000000 +0200
@@ -1,6 +1,6 @@
Copyright (C) 2001-2008 by Kjetil Jacobsen <kjetilja at gmail.com>
Copyright (C) 2001-2008 by Markus F.X.J. Oberhumer <markus at oberhumer.com>
-Copyright (C) 2013-2018 by Oleg Pudeyev <oleg at bsdpower.com>
+Copyright (C) 2013-2019 by Oleg Pudeyev <oleg at bsdpower.com>
Please see README, COPYING-LGPL and COPYING-MIT for license information.
@@ -22,6 +22,7 @@
Daniel Pena Arteaga <dpena at ph.tum.de>
Daniel Stenberg <daniel at haxx.se>
decitre <decitre at gmail.com>
+Dmitriy Taychenachev <dmitriy.taychenachev at skypicker.com>
Dmitry Ketov <dketov at gmail.com>
Domenico Andreoli <cavok at libero.it>
Dominique <curl-and-python at d242.net>
@@ -37,12 +38,14 @@
Jakub Wilk <jwilk at jwilk.net>
Jan Kryl <jan.kryl at nexenta.com>
Jayne <corvine at gmail.com>
+James Deucker <bitwisecook at users.noreply.github.com>
JiCiT <jason at infinitebubble.com>
Jim Patterson
Jozef Melicher <jozef.melicher at eset.sk>
K.S.Sreeram <sreeram at tachyontech.net>
Kamil Dudka <kdudka at redhat.com>
Kevin Ko <kevin.s.ko at gmail.com>
+Khavish Anshudass Bhundoo <khavishbhundoo at users.noreply.github.com>
kxrd <onyeabor at riseup.net>
Lipin Dmitriy <blackwithwhite666 at gmail.com>
Léo El Amri <leo at superlel.me>
@@ -53,6 +56,7 @@
Markus <nepenthesdev at gmail.com>
Martin Muenstermann <mamuema at sourceforge.net>
Matt King <matt at gnik.com>
+Nelson Chen <crazysim at gmail.com>
Nick Pilon <npilon at oreilly.com>
Oren <orenyomtov at users.noreply.github.com>
Orion Poplawski <orion at cora.nwra.com>
@@ -66,6 +70,7 @@
Tal Einat <tal.einat at socialcodeinc.com>
Thomas Hunger <teh at camvine.org>
Tino Lange <Tino.Lange at gmx.de>
+toddrme2178 <toddrme2178 at gmail.com>
Tom Pierce <tom.pierce0 at gmail.com>
Victor Lascurain <bittor at eleka.net>
Vitaly Murashev <vitaly.murashev at gmail.com>
@@ -78,3 +83,4 @@
Yuri Ushakov <yuri.ushakov at gmail.com>
Yves Bastide <yves at botify.com>
Zdenek Pavlas <zpavlas at redhat.com>
+ziggy <ziggy at elephant-bird.net>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/COPYING-MIT new/pycurl-7.43.0.3/COPYING-MIT
--- old/pycurl-7.43.0.2/COPYING-MIT 2018-06-02 06:59:02.000000000 +0200
+++ new/pycurl-7.43.0.3/COPYING-MIT 2019-06-17 07:49:37.000000000 +0200
@@ -2,7 +2,7 @@
Copyright (C) 2001-2008 by Kjetil Jacobsen <kjetilja at gmail.com>
Copyright (C) 2001-2008 by Markus F.X.J. Oberhumer <markus at oberhumer.com>
-Copyright (C) 2013-2018 by Oleg Pudeyev <oleg at bsdpower.com>
+Copyright (C) 2013-2019 by Oleg Pudeyev <oleg at bsdpower.com>
All rights reserved.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/ChangeLog new/pycurl-7.43.0.3/ChangeLog
--- old/pycurl-7.43.0.2/ChangeLog 2018-06-02 06:59:02.000000000 +0200
+++ new/pycurl-7.43.0.3/ChangeLog 2019-06-17 07:51:23.000000000 +0200
@@ -1,3 +1,23 @@
+Version 7.43.0.3 [requires libcurl-7.19.0 or better] - 2019-06-17
+-----------------------------------------------------------------
+
+ * Fixed use with libcurl 7.65+ when FTP support is disabled.
+
+ * Added support for mbedTLS (patch by Josef Schlehofer).
+
+ * Fixed string processing on Python 3 (patch by Dmitriy Taychenachev).
+
+ * Added CURLOPT_TCP_FASTOPEN and CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE
+ (patch by Khavish Anshudass Bhundoo).
+
+ * Repaired inability to install PycURL when libcurl is using an SSL
+ backend other than the ones PycURL explicitly recognizes and
+ handles (OpenSSL, LibreSSL, BoringSSL, GnuTLS, NSS).
+ The requirement for setup.py to detect an SSL backend if libcurl
+ is configured to use SSL, added in 7.43.0.2, has been changed
+ to a warning to allow this.
+
+
Version 7.43.0.2 [requires libcurl-7.19.0 or better] - 2018-06-02
-----------------------------------------------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/INSTALL.rst new/pycurl-7.43.0.3/INSTALL.rst
--- old/pycurl-7.43.0.2/INSTALL.rst 2018-05-18 21:53:25.000000000 +0200
+++ new/pycurl-7.43.0.3/INSTALL.rst 2019-06-17 07:14:58.000000000 +0200
@@ -53,7 +53,7 @@
To fix this, you need to tell ``setup.py`` what SSL backend is used::
- python setup.py --with-[openssl|gnutls|nss] install
+ python setup.py --with-[openssl|gnutls|nss|mbedtls] install
Note: as of PycURL 7.21.5, setup.py accepts ``--with-openssl`` option to
indicate that libcurl is built against OpenSSL. ``--with-ssl`` is an alias
@@ -85,7 +85,7 @@
The same applies to the SSL backend, if you need to specify it (see the SSL
note above)::
- export PYCURL_SSL_LIBRARY=[openssl|gnutls|nss]
+ export PYCURL_SSL_LIBRARY=[openssl|gnutls|nss|mbedtls]
easy_install pycurl
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/PKG-INFO new/pycurl-7.43.0.3/PKG-INFO
--- old/pycurl-7.43.0.2/PKG-INFO 2018-06-02 06:59:34.000000000 +0200
+++ new/pycurl-7.43.0.3/PKG-INFO 2019-06-17 07:56:09.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: pycurl
-Version: 7.43.0.2
+Version: 7.43.0.3
Summary: PycURL -- A Python Interface To The cURL library
Home-page: http://pycurl.io/
Author: Oleg Pudeyev
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/README.rst new/pycurl-7.43.0.3/README.rst
--- old/pycurl-7.43.0.2/README.rst 2018-06-02 06:59:02.000000000 +0200
+++ new/pycurl-7.43.0.3/README.rst 2019-06-17 07:49:52.000000000 +0200
@@ -174,7 +174,7 @@
Copyright (C) 2001-2008 by Kjetil Jacobsen <kjetilja at gmail.com>
Copyright (C) 2001-2008 by Markus F.X.J. Oberhumer <markus at oberhumer.com>
- Copyright (C) 2013-2018 by Oleg Pudeyev <oleg at bsdpower.com>
+ Copyright (C) 2013-2019 by Oleg Pudeyev <oleg at bsdpower.com>
All rights reserved.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/RELEASE-NOTES.rst new/pycurl-7.43.0.3/RELEASE-NOTES.rst
--- old/pycurl-7.43.0.2/RELEASE-NOTES.rst 2018-06-02 06:59:02.000000000 +0200
+++ new/pycurl-7.43.0.3/RELEASE-NOTES.rst 2019-06-17 07:51:27.000000000 +0200
@@ -1,6 +1,14 @@
Release Notes
=============
+PycURL 7.43.0.3 - 2019-06-17
+----------------------------
+
+This release primarily fixes an OpenSSL-related installation issue, and
+repairs the ability to use PycURL with newer libcurls compiled without FTP
+support. Also, mbedTLS support has been contributed by Josef Schlehofer.
+
+
PycURL 7.43.0.2 - 2018-06-02
----------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/doc/conf.py new/pycurl-7.43.0.3/doc/conf.py
--- old/pycurl-7.43.0.2/doc/conf.py 2018-06-02 06:59:02.000000000 +0200
+++ new/pycurl-7.43.0.3/doc/conf.py 2019-06-17 07:51:55.000000000 +0200
@@ -47,16 +47,16 @@
# General information about the project.
project = u'PycURL'
-copyright = u'2001-2018 Kjetil Jacobsen, Markus F.X.J. Oberhumer, Oleg Pudeyev'
+copyright = u'2001-2019 Kjetil Jacobsen, Markus F.X.J. Oberhumer, Oleg Pudeyev'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
-version = '7.43.0.2'
+version = '7.43.0.3'
# The full version, including alpha/beta/rc tags.
-release = '7.43.0.2'
+release = '7.43.0.3'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/doc/docstrings/multi_remove_handle.rst new/pycurl-7.43.0.3/doc/docstrings/multi_remove_handle.rst
--- old/pycurl-7.43.0.2/doc/docstrings/multi_remove_handle.rst 2017-12-03 20:03:17.000000000 +0100
+++ new/pycurl-7.43.0.3/doc/docstrings/multi_remove_handle.rst 2018-06-13 20:07:03.000000000 +0200
@@ -3,9 +3,5 @@
Corresponds to `curl_multi_remove_handle`_ in libcurl. This method
removes an existing and valid Curl object from the CurlMulti object.
-IMPORTANT NOTE: remove_handle does not implicitly remove a Python reference
-from the Curl object (and thus does not decrease the reference count on the
-Curl object).
-
.. _curl_multi_remove_handle:
https://curl.haxx.se/libcurl/c/curl_multi_remove_handle.html
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/doc/release-process.rst new/pycurl-7.43.0.3/doc/release-process.rst
--- old/pycurl-7.43.0.2/doc/release-process.rst 2018-06-02 06:59:02.000000000 +0200
+++ new/pycurl-7.43.0.3/doc/release-process.rst 2018-06-13 20:07:03.000000000 +0200
@@ -23,11 +23,11 @@
13. Build windows packages using winbuild.py.
14. Add sdist and windows packages to downloads repo on github.
15. Tag the new version.
-16. Register new version with pypi - ``python setup.py register``.
-17. Upload source distribution to pypi using twine.
-18. Upload windows wheels to pypi using twine.
-19. Upload windows exe installers to pypi using twine.
-20. Upload release files to bintray.
-21. Push tag to github pycurl repo.
-22. Announce release on mailing list.
-23. Link to announcement from website.
+16. Upload source distribution to pypi using twine.
+17. Upload windows wheels to pypi using twine.
+18. Upload windows exe installers to pypi using twine.
+19. Upload release files to bintray.
+20. Push tag to github pycurl repo.
+21. Generate and upload documentation to web site.
+22. Update web site home page.
+23. Announce release on mailing list.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/doc/thread-safety.rst new/pycurl-7.43.0.3/doc/thread-safety.rst
--- old/pycurl-7.43.0.2/doc/thread-safety.rst 2017-12-03 20:03:17.000000000 +0100
+++ new/pycurl-7.43.0.3/doc/thread-safety.rst 2019-06-17 07:14:58.000000000 +0200
@@ -21,7 +21,7 @@
Python code *outside of a libcurl callback for the PycURL object in question*
is unsafe.
-PycURL handles the necessary SSL locks for OpenSSL/LibreSSL, GnuTLS and NSS.
+PycURL handles the necessary SSL locks for OpenSSL/LibreSSL, GnuTLS, NSS and mbedTLS.
A special situation exists when libcurl uses the standard C library
name resolver (i.e., not threaded nor c-ares resolver). By default libcurl
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/pycurl.egg-info/PKG-INFO new/pycurl-7.43.0.3/pycurl.egg-info/PKG-INFO
--- old/pycurl-7.43.0.2/pycurl.egg-info/PKG-INFO 2018-06-02 06:59:34.000000000 +0200
+++ new/pycurl-7.43.0.3/pycurl.egg-info/PKG-INFO 2019-06-17 07:56:09.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: pycurl
-Version: 7.43.0.2
+Version: 7.43.0.3
Summary: PycURL -- A Python Interface To The cURL library
Home-page: http://pycurl.io/
Author: Oleg Pudeyev
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/python/curl/__init__.py new/pycurl-7.43.0.3/python/curl/__init__.py
--- old/pycurl-7.43.0.2/python/curl/__init__.py 2017-12-03 20:03:17.000000000 +0100
+++ new/pycurl-7.43.0.3/python/curl/__init__.py 2019-06-17 07:03:13.000000000 +0200
@@ -34,16 +34,16 @@
class Curl:
"High-level interface to pycurl functions."
- def __init__(self, base_url="", fakeheaders=[]):
+ def __init__(self, base_url="", fakeheaders=None):
self.handle = pycurl.Curl()
# These members might be set.
self.set_url(base_url)
self.verbosity = 0
- self.fakeheaders = fakeheaders
+ self.fakeheaders = fakeheaders or []
# Nothing past here should be modified by the caller.
self.payload = None
self.payload_io = BytesIO()
- self.hrd = ""
+ self.hdr = ""
# Verify that we've got the right site; harmless on a non-SSL connect.
self.set_option(pycurl.SSL_VERIFYHOST, 2)
# Follow redirects in case it wants to take us to a CGI...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/setup.py new/pycurl-7.43.0.3/setup.py
--- old/pycurl-7.43.0.2/setup.py 2018-06-02 06:59:02.000000000 +0200
+++ new/pycurl-7.43.0.3/setup.py 2019-06-17 07:52:05.000000000 +0200
@@ -6,7 +6,7 @@
PACKAGE = "pycurl"
PY_PACKAGE = "curl"
-VERSION = "7.43.0.2"
+VERSION = "7.43.0.3"
import glob, os, re, sys, subprocess
import distutils
@@ -42,38 +42,39 @@
i = 1
while i < len(argv):
arg = argv[i]
- if str.find(arg, s) == 0:
- if s.endswith('='):
+ if s.endswith('='):
+ if str.find(arg, s) == 0:
# --option=value
p = arg[len(s):]
if s != '--openssl-lib-name=':
assert p, arg
+ del argv[i]
else:
+ i += 1
+ else:
+ if s == arg:
# --option
# set value to True
p = True
- del argv[i]
- else:
- i = i + 1
+ del argv[i]
+ else:
+ i = i + 1
##print argv
return p
def scan_argvs(argv, s):
+ if not s.endswith('='):
+ raise Exception('specification must end with =')
p = []
i = 1
while i < len(argv):
arg = argv[i]
if str.find(arg, s) == 0:
- if s.endswith('='):
- # --option=value
- p.append(arg[len(s):])
- if s != '--openssl-lib-name=':
- assert p[-1], arg
- else:
- # --option
- # set value to True
- raise Exception('specification must end with =')
+ # --option=value
+ p.append(arg[len(s):])
+ if s != '--openssl-lib-name=':
+ assert p[-1], arg
del argv[i]
else:
i = i + 1
@@ -95,6 +96,7 @@
self.extra_objects = []
self.extra_compile_args = []
self.extra_link_args = []
+ self.ssl_lib_detected = None
self.configure()
@@ -143,6 +145,7 @@
'--with-ssl': self.using_openssl,
'--with-gnutls': self.using_gnutls,
'--with-nss': self.using_nss,
+ '--with-mbedtls': self.using_mbedtls,
}
def detect_ssl_option(self):
@@ -152,31 +155,30 @@
if option != other_option:
if scan_argv(self.argv, other_option) is not None:
raise ConfigurationError('Cannot give both %s and %s' % (option, other_option))
-
+
return option
def detect_ssl_backend(self):
- ssl_lib_detected = False
-
+ ssl_lib_detected = None
+
if 'PYCURL_SSL_LIBRARY' in os.environ:
ssl_lib = os.environ['PYCURL_SSL_LIBRARY']
- if ssl_lib in ['openssl', 'gnutls', 'nss']:
- ssl_lib_detected = True
+ if ssl_lib in ['openssl', 'gnutls', 'nss', 'mbedtls']:
+ ssl_lib_detected = ssl_lib
getattr(self, 'using_%s' % ssl_lib)()
else:
raise ConfigurationError('Invalid value "%s" for PYCURL_SSL_LIBRARY' % ssl_lib)
-
+
option = self.detect_ssl_option()
if option:
- ssl_lib_detected = True
+ ssl_lib_detected = option.replace('--with-', '')
self.ssl_options()[option]()
# ssl detection - ssl libraries are added
if not ssl_lib_detected:
libcurl_dll_path = scan_argv(self.argv, "--libcurl-dll=")
if libcurl_dll_path is not None:
- if self.detect_ssl_lib_from_libcurl_dll(libcurl_dll_path):
- ssl_lib_detected = True
+ ssl_lib_detected = self.detect_ssl_lib_from_libcurl_dll(libcurl_dll_path)
if not ssl_lib_detected:
# self.sslhintbuf is a hack
@@ -184,15 +186,19 @@
if arg[:2] == "-l":
if arg[2:] == 'ssl':
self.using_openssl()
- ssl_lib_detected = True
+ ssl_lib_detected = 'openssl'
break
if arg[2:] == 'gnutls':
self.using_gnutls()
- ssl_lib_detected = True
+ ssl_lib_detected = 'gnutls'
break
if arg[2:] == 'ssl3':
self.using_nss()
- ssl_lib_detected = True
+ ssl_lib_detected = 'nss'
+ break
+ if arg[2:] == 'mbedtls':
+ self.using_mbedtls()
+ ssl_lib_detected = 'mbedtls'
break
if not ssl_lib_detected and len(self.argv) == len(self.original_argv) \
@@ -201,7 +207,7 @@
# this path should only be taken when no options or
# configuration environment variables are given to setup.py
ssl_lib_detected = self.detect_ssl_lib_on_centos6()
-
+
self.ssl_lib_detected = ssl_lib_detected
def curl_config(self):
@@ -301,19 +307,21 @@
if errtext:
msg += ":\n" + errtext
raise ConfigurationError(msg)
-
+
# hack
self.sslhintbuf = sslhintbuf
self.detect_features()
+ self.ssl_lib_detected = None
if self.curl_has_ssl:
self.detect_ssl_backend()
if not self.ssl_lib_detected:
- raise ConfigurationError('''\
-Curl is configured to use SSL, but we have not been able to determine \
-which SSL backend it is using. Please see PycURL documentation for how to \
-specify the SSL backend manually.''')
+ sys.stderr.write('''\
+Warning: libcurl is configured to use SSL, but we have not been able to \
+determine which SSL backend it is using. If your Curl is built against \
+OpenSSL, LibreSSL, BoringSSL, GnuTLS, NSS or mbedTLS please specify the SSL backend \
+manually. For other SSL backends please ignore this message.''')
else:
if self.detect_ssl_option():
sys.stderr.write("Warning: SSL backend specified manually but libcurl does not use SSL\n")
@@ -327,7 +335,7 @@
self.library_dirs.append(arg[2:])
else:
self.extra_link_args.append(arg)
-
+
if not self.libraries:
self.libraries.append("curl")
@@ -339,7 +347,7 @@
self.check_avoid_stdio()
def detect_ssl_lib_from_libcurl_dll(self, libcurl_dll_path):
- ssl_lib_detected = False
+ ssl_lib_detected = None
curl_version_info = self.get_curl_version_info(libcurl_dll_path)
ssl_version = curl_version_info.ssl_version
if py3:
@@ -347,13 +355,16 @@
ssl_version = ssl_version.decode('ascii')
if ssl_version.startswith('OpenSSL/') or ssl_version.startswith('LibreSSL/'):
self.using_openssl()
- ssl_lib_detected = True
+ ssl_lib_detected = 'openssl'
elif ssl_version.startswith('GnuTLS/'):
self.using_gnutls()
- ssl_lib_detected = True
+ ssl_lib_detected = 'gnutls'
elif ssl_version.startswith('NSS/'):
self.using_nss()
- ssl_lib_detected = True
+ ssl_lib_detected = 'nss'
+ elif ssl_version.startswith('mbedTLS/'):
+ self.using_mbedtls()
+ ssl_lib_detected = 'mbedtls'
return ssl_lib_detected
def detect_ssl_lib_on_centos6(self):
@@ -505,6 +516,11 @@
self.libraries.append('ssl3')
self.define_macros.append(('HAVE_CURL_SSL', 1))
+ def using_mbedtls(self):
+ self.define_macros.append(('HAVE_CURL_MBEDTLS', 1))
+ self.libraries.append('mbedtls')
+ self.define_macros.append(('HAVE_CURL_SSL', 1))
+
def get_bdist_msi_version_hack():
# workaround for distutils/msi version requirement per
# epydoc.sourceforge.net/stdlib/distutils.version.StrictVersion-class.html -
@@ -553,6 +569,14 @@
###############################################################################
+PRETTY_SSL_LIBS = {
+ # setup.py may be detecting BoringSSL properly, need to test
+ 'openssl': 'OpenSSL/LibreSSL/BoringSSL',
+ 'gnutls': 'GnuTLS',
+ 'nss': 'NSS',
+ 'mbedtls': 'mbedTLS',
+}
+
def get_extension(argv, split_extension_source=False):
if split_extension_source:
sources = [
@@ -580,6 +604,12 @@
]
depends = []
ext_config = ExtensionConfiguration(argv)
+
+ if ext_config.ssl_lib_detected:
+ print('Using SSL library: %s' % PRETTY_SSL_LIBS[ext_config.ssl_lib_detected])
+ else:
+ print('Not using an SSL library')
+
ext = Extension(
name=PACKAGE,
sources=sources,
@@ -871,6 +901,7 @@
--with-ssl legacy alias for --with-openssl
--with-gnutls libcurl is linked against GnuTLS
--with-nss libcurl is linked against NSS
+ --with-mbedtls libcurl is linked against mbedTLS
'''
windows_help = '''\
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/src/docstrings.c new/pycurl-7.43.0.3/src/docstrings.c
--- old/pycurl-7.43.0.2/src/docstrings.c 2018-06-02 06:59:23.000000000 +0200
+++ new/pycurl-7.43.0.3/src/docstrings.c 2019-06-17 07:52:49.000000000 +0200
@@ -525,10 +525,6 @@
Corresponds to `curl_multi_remove_handle`_ in libcurl. This method\n\
removes an existing and valid Curl object from the CurlMulti object.\n\
\n\
-IMPORTANT NOTE: remove_handle does not implicitly remove a Python reference\n\
-from the Curl object (and thus does not decrease the reference count on the\n\
-Curl object).\n\
-\n\
.. _curl_multi_remove_handle:\n\
https://curl.haxx.se/libcurl/c/curl_multi_remove_handle.html";
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/src/easy.c new/pycurl-7.43.0.3/src/easy.c
--- old/pycurl-7.43.0.2/src/easy.c 2018-05-23 20:34:47.000000000 +0200
+++ new/pycurl-7.43.0.3/src/easy.c 2019-06-17 07:32:35.000000000 +0200
@@ -74,12 +74,6 @@
return (-1);
}
- /* Set FTP_ACCOUNT to NULL by default */
- res = curl_easy_setopt(self->handle, CURLOPT_FTP_ACCOUNT, NULL);
- if (res != CURLE_OK) {
- return (-1);
- }
-
/* Set default USERAGENT */
assert(g_pycurl_useragent);
res = curl_easy_setopt(self->handle, CURLOPT_USERAGENT, g_pycurl_useragent);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/src/easyinfo.c new/pycurl-7.43.0.3/src/easyinfo.c
--- old/pycurl-7.43.0.2/src/easyinfo.c 2018-05-23 07:08:32.000000000 +0200
+++ new/pycurl-7.43.0.3/src/easyinfo.c 2019-06-17 07:14:54.000000000 +0200
@@ -277,6 +277,7 @@
if (decoded_item == NULL) {
goto err;
}
+ PyList_SetItem(decoded_list, i, decoded_item);
}
return decoded_list;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/src/easyopt.c new/pycurl-7.43.0.3/src/easyopt.c
--- old/pycurl-7.43.0.2/src/easyopt.c 2018-05-23 20:34:47.000000000 +0200
+++ new/pycurl-7.43.0.3/src/easyopt.c 2019-06-17 07:14:54.000000000 +0200
@@ -521,7 +521,7 @@
if (PyText_AsStringAndSize(httppost_option, &cstr, &clen, &cencoded_obj)) {
PyText_EncodedDecref(nencoded_obj);
- CURLERROR_SET_RETVAL();
+ create_and_set_error_object(self, CURLE_BAD_FUNCTION_ARGUMENT);
goto error;
}
/* INFO: curl_formadd() internally does memdup() the data, so
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/src/module.c new/pycurl-7.43.0.3/src/module.c
--- old/pycurl-7.43.0.2/src/module.c 2018-05-23 20:34:47.000000000 +0200
+++ new/pycurl-7.43.0.3/src/module.c 2019-06-17 07:14:58.000000000 +0200
@@ -328,7 +328,7 @@
PyObject *collections_module = NULL;
PyObject *named_tuple = NULL;
PyObject *arglist = NULL;
-
+
assert(Curl_Type.tp_weaklistoffset > 0);
assert(CurlMulti_Type.tp_weaklistoffset > 0);
assert(CurlShare_Type.tp_weaklistoffset > 0);
@@ -355,6 +355,8 @@
runtime_ssl_lib = "gnutls";
} else if (!strncmp(vi->ssl_version, "NSS/", 4)) {
runtime_ssl_lib = "nss";
+ } else if (!strncmp(vi->ssl_version, "mbedTLS/", 8)) {
+ runtime_ssl_lib = "mbedtls";
} else {
runtime_ssl_lib = "none/other";
}
@@ -461,7 +463,7 @@
/* constants for ioctl callback argument values */
insint_c(d, "IOCMD_NOP", CURLIOCMD_NOP);
insint_c(d, "IOCMD_RESTARTREAD", CURLIOCMD_RESTARTREAD);
-
+
/* opensocketfunction return value */
insint_c(d, "SOCKET_BAD", CURL_SOCKET_BAD);
@@ -1039,6 +1041,10 @@
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 47, 0)
insint_c(d, "CURL_HTTP_VERSION_2TLS", CURL_HTTP_VERSION_2TLS);
#endif
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 49, 0)
+ insint_c(d, "CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE", CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE);
+ insint_c(d, "TCP_FASTOPEN", CURLOPT_TCP_FASTOPEN);
+#endif
insint_c(d, "CURL_HTTP_VERSION_LAST", CURL_HTTP_VERSION_LAST);
/* CURL_NETRC_OPTION: constants for setopt(NETRC, x) */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/src/multi.c new/pycurl-7.43.0.3/src/multi.c
--- old/pycurl-7.43.0.2/src/multi.c 2018-05-22 05:44:40.000000000 +0200
+++ new/pycurl-7.43.0.3/src/multi.c 2019-06-17 07:14:54.000000000 +0200
@@ -627,8 +627,8 @@
assert(obj->multi_stack == NULL);
res = curl_multi_add_handle(self->multi_handle, obj->handle);
if (res != CURLM_OK) {
- CURLERROR_MSG("curl_multi_add_handle() failed due to internal errors");
PyDict_DelItem(self->easy_object_dict, (PyObject *) obj);
+ CURLERROR_MSG("curl_multi_add_handle() failed due to internal errors");
}
obj->multi_stack = self;
Py_INCREF(self);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/src/pycurl.h new/pycurl-7.43.0.3/src/pycurl.h
--- old/pycurl-7.43.0.2/src/pycurl.h 2018-05-23 20:34:47.000000000 +0200
+++ new/pycurl-7.43.0.3/src/pycurl.h 2019-06-17 07:14:58.000000000 +0200
@@ -174,6 +174,11 @@
# define COMPILE_SSL_LIB "gnutls"
# elif defined(HAVE_CURL_NSS)
# define COMPILE_SSL_LIB "nss"
+# elif defined(HAVE_CURL_MBEDTLS)
+# include <mbedtls/ssl.h>
+# define PYCURL_NEED_SSL_TSL
+# define PYCURL_NEED_MBEDTLS_TSL
+# define COMPILE_SSL_LIB "mbedtls"
# else
# ifdef _MSC_VER
/* sigh */
@@ -190,7 +195,7 @@
/* since we have no crypto callbacks for other ssl backends,
* no reason to require users match those */
# define COMPILE_SSL_LIB "none/other"
-# endif /* HAVE_CURL_OPENSSL || HAVE_CURL_GNUTLS || HAVE_CURL_NSS */
+# endif /* HAVE_CURL_OPENSSL || HAVE_CURL_GNUTLS || HAVE_CURL_NSS || HAVE_CURL_MBEDTLS */
#else
# define COMPILE_SSL_LIB "none/other"
#endif /* HAVE_CURL_SSL */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/src/threadsupport.c new/pycurl-7.43.0.3/src/threadsupport.c
--- old/pycurl-7.43.0.2/src/threadsupport.c 2018-05-19 02:47:45.000000000 +0200
+++ new/pycurl-7.43.0.3/src/threadsupport.c 2019-06-17 07:14:58.000000000 +0200
@@ -232,6 +232,45 @@
}
#endif
+/* mbedTLS */
+
+#ifdef PYCURL_NEED_MBEDTLS_TSL
+static int
+pycurl_ssl_mutex_create(void **m)
+{
+ if ((*((PyThread_type_lock *) m) = PyThread_allocate_lock()) == NULL) {
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+static int
+pycurl_ssl_mutex_destroy(void **m)
+{
+ PyThread_free_lock(*((PyThread_type_lock *) m));
+ return 0;
+}
+
+static int
+pycurl_ssl_mutex_lock(void **m)
+{
+ return !PyThread_acquire_lock(*((PyThread_type_lock *) m), 1);
+}
+
+PYCURL_INTERNAL int
+pycurl_ssl_init(void)
+{
+ return 0;
+}
+
+PYCURL_INTERNAL void
+pycurl_ssl_cleanup(void)
+{
+ return;
+}
+#endif
+
/*************************************************************************
// CurlShareObject
**************************************************************************/
Binary files old/pycurl-7.43.0.2/tests/fake-curl/libcurl/with_gnutls.so and new/pycurl-7.43.0.3/tests/fake-curl/libcurl/with_gnutls.so differ
Binary files old/pycurl-7.43.0.2/tests/fake-curl/libcurl/with_nss.so and new/pycurl-7.43.0.3/tests/fake-curl/libcurl/with_nss.so differ
Binary files old/pycurl-7.43.0.2/tests/fake-curl/libcurl/with_openssl.so and new/pycurl-7.43.0.3/tests/fake-curl/libcurl/with_openssl.so differ
Binary files old/pycurl-7.43.0.2/tests/fake-curl/libcurl/with_unknown_ssl.so and new/pycurl-7.43.0.3/tests/fake-curl/libcurl/with_unknown_ssl.so differ
Binary files old/pycurl-7.43.0.2/tests/fake-curl/libcurl/without_ssl.so and new/pycurl-7.43.0.3/tests/fake-curl/libcurl/without_ssl.so differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/tests/option_constants_test.py new/pycurl-7.43.0.3/tests/option_constants_test.py
--- old/pycurl-7.43.0.2/tests/option_constants_test.py 2018-06-02 06:14:57.000000000 +0200
+++ new/pycurl-7.43.0.3/tests/option_constants_test.py 2019-06-17 07:03:13.000000000 +0200
@@ -455,6 +455,11 @@
def test_http_version_2tls(self):
self.curl.setopt(self.curl.HTTP_VERSION, self.curl.CURL_HTTP_VERSION_2TLS)
+ @nose.plugins.attrib.attr('http2')
+ @util.min_libcurl(7, 49, 0)
+ def test_http_version_2prior_knowledge(self):
+ self.curl.setopt(self.curl.HTTP_VERSION, self.curl.CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE)
+
@util.min_libcurl(7, 21, 5)
def test_sockopt_constants(self):
assert self.curl.SOCKOPT_OK is not None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/tests/setup_test.py new/pycurl-7.43.0.3/tests/setup_test.py
--- old/pycurl-7.43.0.2/tests/setup_test.py 2018-06-02 06:14:57.000000000 +0200
+++ new/pycurl-7.43.0.3/tests/setup_test.py 2018-06-13 20:07:03.000000000 +0200
@@ -69,6 +69,24 @@
assert 'curl' in config.libraries
@util.only_unix
+ def test_valid_option_consumes_argv(self):
+ argv = ['', '--with-nss']
+ pycurl_setup.ExtensionConfiguration(argv)
+ self.assertEqual([''], argv)
+
+ @util.only_unix
+ def test_invalid_option_not_consumed(self):
+ argv = ['', '--bogus']
+ pycurl_setup.ExtensionConfiguration(argv)
+ self.assertEqual(['', '--bogus'], argv)
+
+ @util.only_unix
+ def test_invalid_option_suffix_not_consumed(self):
+ argv = ['', '--with-nss-bogus']
+ pycurl_setup.ExtensionConfiguration(argv)
+ self.assertEqual(['', '--with-nss-bogus'], argv)
+
+ @util.only_unix
@using_curl_config('curl-config-empty')
def test_no_ssl(self):
config = pycurl_setup.ExtensionConfiguration()
@@ -129,15 +147,17 @@
@util.only_unix
@using_curl_config('curl-config-ssl-feature-only')
def test_ssl_feature_only(self):
+ saved_stderr = sys.stderr
+ sys.stderr = captured_stderr = StringIO()
try:
- pycurl_setup.ExtensionConfiguration()
- except pycurl_setup.ConfigurationError as e:
- self.assertEqual('''\
-Curl is configured to use SSL, but we have not been able to determine \
-which SSL backend it is using. Please see PycURL documentation for how to \
-specify the SSL backend manually.''', str(e))
- else:
- self.fail('Should have raised')
+ config = pycurl_setup.ExtensionConfiguration()
+ finally:
+ sys.stderr = saved_stderr
+ # ssl define should be on
+ assert 'HAVE_CURL_SSL' in config.define_symbols
+ # and a warning message
+ assert 'Warning: libcurl is configured to use SSL, but we have \
+not been able to determine which SSL backend it is using.' in captured_stderr.getvalue()
@util.only_unix
@using_curl_config('curl-config-ssl-feature-only')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pycurl-7.43.0.2/winbuild.py new/pycurl-7.43.0.3/winbuild.py
--- old/pycurl-7.43.0.2/winbuild.py 2018-06-02 06:59:02.000000000 +0200
+++ new/pycurl-7.43.0.3/winbuild.py 2019-06-17 07:52:10.000000000 +0200
@@ -91,7 +91,7 @@
# whether to build binary wheels
build_wheels = True
# pycurl version to build, we should know this ourselves
- pycurl_version = '7.43.0.2'
+ pycurl_version = '7.43.0.3'
# sometimes vc14 does not include windows sdk path in vcvars which breaks stuff.
# another application for this is to supply normaliz.lib for vc9
@@ -269,6 +269,7 @@
'3.4': 'vc10',
'3.5': 'vc14',
'3.6': 'vc14',
+ '3.7': 'vc14',
}
def mkdir_p(path):
++++++ python-pycurl-7.43.0-tls-backend.patch ++++++
--- /var/tmp/diff_new_pack.6idyEJ/_old 2019-07-30 13:05:38.462383979 +0200
+++ /var/tmp/diff_new_pack.6idyEJ/_new 2019-07-30 13:05:38.462383979 +0200
@@ -11,10 +11,10 @@
src/module.c | 20 +-------------------
1 file changed, 1 insertion(+), 19 deletions(-)
-diff --git a/src/module.c b/src/module.c
-index a7108a0..af79875 100644
---- a/src/module.c
-+++ b/src/module.c
+Index: pycurl-7.43.0.3/src/module.c
+===================================================================
+--- pycurl-7.43.0.3.orig/src/module.c
++++ pycurl-7.43.0.3/src/module.c
@@ -322,7 +322,7 @@ initpycurl(void)
{
PyObject *m, *d;
@@ -24,7 +24,7 @@
size_t libcurl_version_len, pycurl_version_len;
PyObject *xio_module = NULL;
PyObject *collections_module = NULL;
-@@ -345,24 +345,6 @@ initpycurl(void)
+@@ -345,26 +345,6 @@ initpycurl(void)
goto error;
}
@@ -38,6 +38,8 @@
- runtime_ssl_lib = "gnutls";
- } else if (!strncmp(vi->ssl_version, "NSS/", 4)) {
- runtime_ssl_lib = "nss";
+- } else if (!strncmp(vi->ssl_version, "mbedTLS/", 8)) {
+- runtime_ssl_lib = "mbedtls";
- } else {
- runtime_ssl_lib = "none/other";
- }
@@ -49,6 +51,3 @@
/* Initialize the type of the new type objects here; doing it here
* is required for portability to Windows without requiring C++. */
p_Curl_Type = &Curl_Type;
---
-2.10.2
-
1
0
Hello community,
here is the log from the commit of package python-lxml for openSUSE:Factory checked in at 2019-07-30 13:05:26
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-lxml (Old)
and /work/SRC/openSUSE:Factory/.python-lxml.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-lxml"
Tue Jul 30 13:05:26 2019 rev:73 rq:717675 version:4.3.4
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-lxml/python-lxml.changes 2019-07-08 15:00:02.490445336 +0200
+++ /work/SRC/openSUSE:Factory/.python-lxml.new.4126/python-lxml.changes 2019-07-30 13:05:36.374384530 +0200
@@ -1,0 +2,7 @@
+Mon Jul 22 16:49:22 UTC 2019 - Todd R <toddrme2178(a)gmail.com>
+
+- Update to 4.3.4
+ * Rebuilt with Cython 0.29.10 to support Python 3.8.
+ Note: documentation is not updated
+
+-------------------------------------------------------------------
Old:
----
lxml-4.3.3.tar.gz
New:
----
lxml-4.3.4.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-lxml.spec ++++++
--- /var/tmp/diff_new_pack.jafybT/_old 2019-07-30 13:05:36.826384411 +0200
+++ /var/tmp/diff_new_pack.jafybT/_new 2019-07-30 13:05:36.826384411 +0200
@@ -18,14 +18,15 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-lxml
-Version: 4.3.3
+Version: 4.3.4
+%define docver 4.3.3
Release: 0
Summary: Pythonic XML processing library
License: BSD-3-Clause AND GPL-2.0-or-later
Group: Development/Languages/Python
URL: http://lxml.de/
Source: https://files.pythonhosted.org/packages/source/l/lxml/lxml-%{version}.tar.gz
-Source1: https://lxml.de/lxmldoc-%{version}.pdf
+Source1: https://lxml.de/lxmldoc-%{docver}.pdf
BuildRequires: %{python_module Cython >= 0.26.1}
BuildRequires: %{python_module cssselect >= 0.9.1}
BuildRequires: %{python_module setuptools >= 18.0.1}
++++++ lxml-4.3.3.tar.gz -> lxml-4.3.4.tar.gz ++++++
++++ 284479 lines of diff (skipped)
1
0
Hello community,
here is the log from the commit of package python-XlsxWriter for openSUSE:Factory checked in at 2019-07-30 13:05:18
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-XlsxWriter (Old)
and /work/SRC/openSUSE:Factory/.python-XlsxWriter.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-XlsxWriter"
Tue Jul 30 13:05:18 2019 rev:8 rq:717651 version:1.1.8
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-XlsxWriter/python-XlsxWriter.changes 2019-02-25 17:57:42.422272264 +0100
+++ /work/SRC/openSUSE:Factory/.python-XlsxWriter.new.4126/python-XlsxWriter.changes 2019-07-30 13:05:35.078384871 +0200
@@ -1,0 +2,26 @@
+Mon Jul 22 16:16:15 UTC 2019 - Todd R <toddrme2178(a)gmail.com>
+
+- Update to Release 1.1.8
+ * Added ability to combine Doughnut and Pie charts.
+ * Added gauge chart example which is a combination of a Doughnut and a Pie
+ chart.
+- Update to Release 1.1.7
+ * Added docs on object_position.
+ * Added fix for sizing of cell comment boxes when they cross columns/rows that
+ have size changes that occur after the comment is written.
+ * Added fix for the sizing of worksheet objects (images, charts, textboxes)
+ when the underlying cell sizes have changed and the "object_position"
+ parameter has been set to 1 "Move and size with cells". An additional mode 4
+ has been added to simulate inserting the object in hidden rows.
+ * Added object positioning for charts and textboxes, it was already supported
+ for images. Note, the parameter is now called ``object_position``. The
+ previous parameter name ``positioning`` is deprecated but still supported
+ for images.
+- Update to Release 1.1.6
+ * Fixed issue where images that started in hidden rows/columns weren't placed
+ correctly in the worksheet.
+ * Fixed the mime-type reported by system ``file(1)``. The mime-type reported
+ by "file --mime-type"/magic was incorrect for XlsxWriter files since it
+ expected the ``[Content_types]`` to be the first file in the zip container.
+
+-------------------------------------------------------------------
Old:
----
XlsxWriter-1.1.5.tar.gz
New:
----
XlsxWriter-RELEASE_1.1.8.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-XlsxWriter.spec ++++++
--- /var/tmp/diff_new_pack.JEChzh/_old 2019-07-30 13:05:35.966384637 +0200
+++ /var/tmp/diff_new_pack.JEChzh/_new 2019-07-30 13:05:35.966384637 +0200
@@ -19,13 +19,13 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
%define oldpython python
Name: python-XlsxWriter
-Version: 1.1.5
+Version: 1.1.8
Release: 0
Summary: Python module for writing OOXML spreadsheet files
License: BSD-2-Clause
Group: Development/Languages/Python
Url: https://xlsxwriter.readthedocs.org/
-Source: https://github.com/jmcnamara/XlsxWriter/archive/RELEASE_%{version}.tar.gz#/…
+Source: https://github.com/jmcnamara/XlsxWriter/archive/RELEASE_%{version}.tar.gz#/…
BuildRequires: %{python_module setuptools}
BuildRequires: fdupes
BuildRequires: python-rpm-macros
1
0
Hello community,
here is the log from the commit of package python-beautifulsoup4 for openSUSE:Factory checked in at 2019-07-30 13:05:12
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-beautifulsoup4 (Old)
and /work/SRC/openSUSE:Factory/.python-beautifulsoup4.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-beautifulsoup4"
Tue Jul 30 13:05:12 2019 rev:29 rq:717648 version:4.8.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-beautifulsoup4/python-beautifulsoup4.changes 2019-03-04 09:11:05.132700786 +0100
+++ /work/SRC/openSUSE:Factory/.python-beautifulsoup4.new.4126/python-beautifulsoup4.changes 2019-07-30 13:05:15.146390127 +0200
@@ -1,0 +2,23 @@
+Mon Jul 22 16:18:23 UTC 2019 - Todd R <toddrme2178(a)gmail.com>
+
+- Update to 4.8.0
+ * It's now possible to customize the TreeBuilder object by passing
+ keyword arguments into the BeautifulSoup constructor. The main
+ reason to do this right now is to change how which attributes are
+ treated as multi-valued attributes (the way 'class' is treated by
+ default). You can do this with the `multi_valued_attributes` argument.
+ * The role of Formatter objects has been greatly expanded. The Formatter
+ class now controls the following:
+ > The function to call to perform entity substitution. (This was
+ previously Formatter's only job.)
+ > Which tags should be treated as containing CDATA and have their
+ contents exempt from entity substitution.
+ > The order in which a tag's attributes are output.
+ > Whether or not to put a '/' inside a void element, e.g. '<br/>' vs '<br>'
+ All preexisting code should work as before.
+ * Added a new method to the API, Tag.smooth(), which consolidates
+ multiple adjacent NavigableString elements.
+ * ' (which is valid in XML, XHTML, and HTML 5, but not HTML 4) is now
+ recognized as a named entity and converted to a single quote.
+
+-------------------------------------------------------------------
Old:
----
beautifulsoup4-4.7.1.tar.gz
New:
----
beautifulsoup4-4.8.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-beautifulsoup4.spec ++++++
--- /var/tmp/diff_new_pack.SDgoFB/_old 2019-07-30 13:05:15.818389950 +0200
+++ /var/tmp/diff_new_pack.SDgoFB/_new 2019-07-30 13:05:15.822389949 +0200
@@ -18,7 +18,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-beautifulsoup4
-Version: 4.7.1
+Version: 4.8.0
Release: 0
Summary: HTML/XML Parser for Quick-Turnaround Applications Like Screen-Scraping
License: MIT
++++++ beautifulsoup4-4.7.1.tar.gz -> beautifulsoup4-4.8.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/beautifulsoup4-4.7.1/NEWS.txt new/beautifulsoup4-4.8.0/NEWS.txt
--- old/beautifulsoup4-4.7.1/NEWS.txt 2019-01-07 01:36:52.000000000 +0100
+++ new/beautifulsoup4-4.8.0/NEWS.txt 2019-07-20 01:41:41.000000000 +0200
@@ -1,3 +1,30 @@
+= 4.8.0 (20190720, "One Small Soup")
+
+* It's now possible to customize the TreeBuilder object by passing
+ keyword arguments into the BeautifulSoup constructor. The main
+ reason to do this right now is to change how which attributes are
+ treated as multi-valued attributes (the way 'class' is treated by
+ default). You can do this with the `multi_valued_attributes` argument.
+ [bug=1832978]
+
+* The role of Formatter objects has been greatly expanded. The Formatter
+ class now controls the following:
+
+ - The function to call to perform entity substitution. (This was
+ previously Formatter's only job.)
+ - Which tags should be treated as containing CDATA and have their
+ contents exempt from entity substitution.
+ - The order in which a tag's attributes are output. [bug=1812422]
+ - Whether or not to put a '/' inside a void element, e.g. '<br/>' vs '<br>'
+
+ All preexisting code should work as before.
+
+* Added a new method to the API, Tag.smooth(), which consolidates
+ multiple adjacent NavigableString elements.
+
+* ' (which is valid in XML, XHTML, and HTML 5, but not HTML 4) is now
+ recognized as a named entity and converted to a single quote. [bug=1818721]
+
= 4.7.1 (20190106)
* Fixed a significant performance problem introduced in 4.7.0. [bug=1810617]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/beautifulsoup4-4.7.1/PKG-INFO new/beautifulsoup4-4.8.0/PKG-INFO
--- old/beautifulsoup4-4.7.1/PKG-INFO 2019-01-07 01:51:37.000000000 +0100
+++ new/beautifulsoup4-4.8.0/PKG-INFO 2019-07-20 13:29:22.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: beautifulsoup4
-Version: 4.7.1
+Version: 4.8.0
Summary: Screen-scraping library
Home-page: http://www.crummy.com/software/BeautifulSoup/bs4/
Author: Leonard Richardson
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/beautifulsoup4-4.7.1/beautifulsoup4.egg-info/PKG-INFO new/beautifulsoup4-4.8.0/beautifulsoup4.egg-info/PKG-INFO
--- old/beautifulsoup4-4.7.1/beautifulsoup4.egg-info/PKG-INFO 2019-01-07 01:51:37.000000000 +0100
+++ new/beautifulsoup4-4.8.0/beautifulsoup4.egg-info/PKG-INFO 2019-07-20 13:29:22.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: beautifulsoup4
-Version: 4.7.1
+Version: 4.8.0
Summary: Screen-scraping library
Home-page: http://www.crummy.com/software/BeautifulSoup/bs4/
Author: Leonard Richardson
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/beautifulsoup4-4.7.1/beautifulsoup4.egg-info/SOURCES.txt new/beautifulsoup4-4.8.0/beautifulsoup4.egg-info/SOURCES.txt
--- old/beautifulsoup4-4.7.1/beautifulsoup4.egg-info/SOURCES.txt 2019-01-07 01:51:37.000000000 +0100
+++ new/beautifulsoup4-4.8.0/beautifulsoup4.egg-info/SOURCES.txt 2019-07-20 13:29:22.000000000 +0200
@@ -17,6 +17,7 @@
bs4/dammit.py
bs4/diagnose.py
bs4/element.py
+bs4/formatter.py
bs4/testing.py
bs4/builder/__init__.py
bs4/builder/_html5lib.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/beautifulsoup4-4.7.1/bs4/__init__.py new/beautifulsoup4-4.8.0/bs4/__init__.py
--- old/beautifulsoup4-4.7.1/bs4/__init__.py 2019-01-07 01:50:44.000000000 +0100
+++ new/beautifulsoup4-4.8.0/bs4/__init__.py 2019-07-17 03:31:51.000000000 +0200
@@ -18,7 +18,7 @@
"""
__author__ = "Leonard Richardson (leonardr(a)segfault.org)"
-__version__ = "4.7.1"
+__version__ = "4.8.0"
__copyright__ = "Copyright (c) 2004-2019 Leonard Richardson"
# Use of this source code is governed by the MIT license.
__license__ = "MIT"
@@ -98,8 +98,10 @@
name a specific parser, so that Beautiful Soup gives you the
same results across platforms and virtual environments.
- :param builder: A specific TreeBuilder to use instead of looking one
- up based on `features`. You shouldn't need to use this.
+ :param builder: A TreeBuilder subclass to instantiate (or
+ instance to use) instead of looking one up based on
+ `features`. You only need to use this if you've implemented a
+ custom TreeBuilder.
:param parse_only: A SoupStrainer. Only parts of the document
matching the SoupStrainer will be considered. This is useful
@@ -118,11 +120,17 @@
:param kwargs: For backwards compatibility purposes, the
constructor accepts certain keyword arguments used in
Beautiful Soup 3. None of these arguments do anything in
- Beautiful Soup 4 and there's no need to actually pass keyword
- arguments into the constructor.
+ Beautiful Soup 4; they will result in a warning and then be ignored.
+
+ Apart from this, any keyword arguments passed into the BeautifulSoup
+ constructor are propagated to the TreeBuilder constructor. This
+ makes it possible to configure a TreeBuilder beyond saying
+ which one to use.
+
"""
if 'convertEntities' in kwargs:
+ del kwargs['convertEntities']
warnings.warn(
"BS4 does not respect the convertEntities argument to the "
"BeautifulSoup constructor. Entities are always converted "
@@ -177,13 +185,17 @@
warnings.warn("You provided Unicode markup but also provided a value for from_encoding. Your from_encoding will be ignored.")
from_encoding = None
- if len(kwargs) > 0:
- arg = kwargs.keys().pop()
- raise TypeError(
- "__init__() got an unexpected keyword argument '%s'" % arg)
-
- if builder is None:
- original_features = features
+ # We need this information to track whether or not the builder
+ # was specified well enough that we can omit the 'you need to
+ # specify a parser' warning.
+ original_builder = builder
+ original_features = features
+
+ if isinstance(builder, type):
+ # A builder class was passed in; it needs to be instantiated.
+ builder_class = builder
+ builder = None
+ elif builder is None:
if isinstance(features, basestring):
features = [features]
if features is None or len(features) == 0:
@@ -194,9 +206,16 @@
"Couldn't find a tree builder with the features you "
"requested: %s. Do you need to install a parser library?"
% ",".join(features))
- builder = builder_class()
- if not (original_features == builder.NAME or
- original_features in builder.ALTERNATE_NAMES):
+
+ # At this point either we have a TreeBuilder instance in
+ # builder, or we have a builder_class that we can instantiate
+ # with the remaining **kwargs.
+ if builder is None:
+ builder = builder_class(**kwargs)
+ if not original_builder and not (
+ original_features == builder.NAME or
+ original_features in builder.ALTERNATE_NAMES
+ ):
if builder.is_xml:
markup_type = "XML"
else:
@@ -231,7 +250,10 @@
markup_type=markup_type
)
warnings.warn(self.NO_PARSER_SPECIFIED_WARNING % values, stacklevel=2)
-
+ else:
+ if kwargs:
+ warnings.warn("Keyword arguments to the BeautifulSoup constructor will be ignored. These would normally be passed into the TreeBuilder constructor, but a TreeBuilder instance was passed in as `builder`.")
+
self.builder = builder
self.is_xml = builder.is_xml
self.known_xml = self.is_xml
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/beautifulsoup4-4.7.1/bs4/builder/__init__.py new/beautifulsoup4-4.8.0/bs4/builder/__init__.py
--- old/beautifulsoup4-4.7.1/bs4/builder/__init__.py 2018-12-31 02:49:46.000000000 +0100
+++ new/beautifulsoup4-4.8.0/bs4/builder/__init__.py 2019-07-14 22:16:04.000000000 +0200
@@ -7,7 +7,6 @@
from bs4.element import (
CharsetMetaAttributeValue,
ContentMetaAttributeValue,
- HTMLAwareEntitySubstitution,
nonwhitespace_re
)
@@ -90,18 +89,40 @@
is_xml = False
picklable = False
- preserve_whitespace_tags = set()
empty_element_tags = None # A tag will be considered an empty-element
# tag when and only when it has no contents.
# A value for these tag/attribute combinations is a space- or
# comma-separated list of CDATA, rather than a single CDATA.
- cdata_list_attributes = {}
+ DEFAULT_CDATA_LIST_ATTRIBUTES = {}
+ DEFAULT_PRESERVE_WHITESPACE_TAGS = set()
+
+ USE_DEFAULT = object()
+
+ def __init__(self, multi_valued_attributes=USE_DEFAULT, preserve_whitespace_tags=USE_DEFAULT):
+ """Constructor.
- def __init__(self):
- self.soup = None
+ :param multi_valued_attributes: If this is set to None, the
+ TreeBuilder will not turn any values for attributes like
+ 'class' into lists. Setting this do a dictionary will
+ customize this behavior; look at DEFAULT_CDATA_LIST_ATTRIBUTES
+ for an example.
+
+ Internally, these are called "CDATA list attributes", but that
+ probably doesn't make sense to an end-user, so the argument name
+ is `multi_valued_attributes`.
+ :param preserve_whitespace_tags:
+ """
+ self.soup = None
+ if multi_valued_attributes is self.USE_DEFAULT:
+ multi_valued_attributes = self.DEFAULT_CDATA_LIST_ATTRIBUTES
+ self.cdata_list_attributes = multi_valued_attributes
+ if preserve_whitespace_tags is self.USE_DEFAULT:
+ preserve_whitespace_tags = self.DEFAULT_PRESERVE_WHITESPACE_TAGS
+ self.preserve_whitespace_tags = preserve_whitespace_tags
+
def initialize_soup(self, soup):
"""The BeautifulSoup object has been initialized and is now
being associated with the TreeBuilder.
@@ -131,7 +152,7 @@
if self.empty_element_tags is None:
return True
return tag_name in self.empty_element_tags
-
+
def feed(self, markup):
raise NotImplementedError()
@@ -237,7 +258,6 @@
Such as which tags are empty-element tags.
"""
- preserve_whitespace_tags = HTMLAwareEntitySubstitution.preserve_whitespace_tags
empty_element_tags = set([
# These are from HTML5.
'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr',
@@ -259,7 +279,7 @@
# encounter one of these attributes, we will parse its value into
# a list of values if possible. Upon output, the list will be
# converted back into a string.
- cdata_list_attributes = {
+ DEFAULT_CDATA_LIST_ATTRIBUTES = {
"*" : ['class', 'accesskey', 'dropzone'],
"a" : ['rel', 'rev'],
"link" : ['rel', 'rev'],
@@ -276,6 +296,8 @@
"output" : ["for"],
}
+ DEFAULT_PRESERVE_WHITESPACE_TAGS = set(['pre', 'textarea'])
+
def set_up_substitutions(self, tag):
# We are only interested in <meta> tags
if tag.name != 'meta':
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/beautifulsoup4-4.7.1/bs4/builder/_html5lib.py new/beautifulsoup4-4.8.0/bs4/builder/_html5lib.py
--- old/beautifulsoup4-4.7.1/bs4/builder/_html5lib.py 2018-12-31 02:50:27.000000000 +0100
+++ new/beautifulsoup4-4.8.0/bs4/builder/_html5lib.py 2019-07-08 03:59:55.000000000 +0200
@@ -199,7 +199,7 @@
def __setitem__(self, name, value):
# If this attribute is a multi-valued attribute for this element,
# turn its value into a list.
- list_attr = HTML5TreeBuilder.cdata_list_attributes
+ list_attr = self.element.cdata_list_attributes
if (name in list_attr['*']
or (self.element.name in list_attr
and name in list_attr[self.element.name])):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/beautifulsoup4-4.7.1/bs4/builder/_htmlparser.py new/beautifulsoup4-4.8.0/bs4/builder/_htmlparser.py
--- old/beautifulsoup4-4.7.1/bs4/builder/_htmlparser.py 2018-12-24 16:32:39.000000000 +0100
+++ new/beautifulsoup4-4.8.0/bs4/builder/_htmlparser.py 2019-07-07 20:09:37.000000000 +0200
@@ -214,12 +214,15 @@
NAME = HTMLPARSER
features = [NAME, HTML, STRICT]
- def __init__(self, *args, **kwargs):
+ def __init__(self, parser_args=None, parser_kwargs=None, **kwargs):
+ super(HTMLParserTreeBuilder, self).__init__(**kwargs)
+ parser_args = parser_args or []
+ parser_kwargs = parser_kwargs or {}
if CONSTRUCTOR_TAKES_STRICT and not CONSTRUCTOR_STRICT_IS_DEPRECATED:
- kwargs['strict'] = False
+ parser_kwargs['strict'] = False
if CONSTRUCTOR_TAKES_CONVERT_CHARREFS:
- kwargs['convert_charrefs'] = False
- self.parser_args = (args, kwargs)
+ parser_kwargs['convert_charrefs'] = False
+ self.parser_args = (parser_args, parser_kwargs)
def prepare_markup(self, markup, user_specified_encoding=None,
document_declared_encoding=None, exclude_encodings=None):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/beautifulsoup4-4.7.1/bs4/builder/_lxml.py new/beautifulsoup4-4.8.0/bs4/builder/_lxml.py
--- old/beautifulsoup4-4.7.1/bs4/builder/_lxml.py 2019-01-07 00:41:32.000000000 +0100
+++ new/beautifulsoup4-4.8.0/bs4/builder/_lxml.py 2019-07-08 03:59:55.000000000 +0200
@@ -94,7 +94,7 @@
parser = parser(target=self, strip_cdata=False, encoding=encoding)
return parser
- def __init__(self, parser=None, empty_element_tags=None):
+ def __init__(self, parser=None, empty_element_tags=None, **kwargs):
# TODO: Issue a warning if parser is present but not a
# callable, since that means there's no way to create new
# parsers for different encodings.
@@ -103,6 +103,7 @@
self.empty_element_tags = set(empty_element_tags)
self.soup = None
self.nsmaps = [self.DEFAULT_NSMAPS_INVERTED]
+ super(LXMLTreeBuilderForXML, self).__init__(**kwargs)
def _getNsTag(self, tag):
# Split the namespace URL out of a fully-qualified lxml tag
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/beautifulsoup4-4.7.1/bs4/dammit.py new/beautifulsoup4-4.8.0/bs4/dammit.py
--- old/beautifulsoup4-4.7.1/bs4/dammit.py 2018-12-24 16:31:48.000000000 +0100
+++ new/beautifulsoup4-4.8.0/bs4/dammit.py 2019-07-08 03:45:20.000000000 +0200
@@ -57,15 +57,24 @@
lookup = {}
reverse_lookup = {}
characters_for_re = []
- for codepoint, name in list(codepoint2name.items()):
+
+ # &apos is an XHTML entity and an HTML 5, but not an HTML 4
+ # entity. We don't want to use it, but we want to recognize it on the way in.
+ #
+ # TODO: Ideally we would be able to recognize all HTML 5 named
+ # entities, but that's a little tricky.
+ extra = [(39, 'apos')]
+ for codepoint, name in list(codepoint2name.items()) + extra:
character = unichr(codepoint)
- if codepoint != 34:
+ if codepoint not in (34, 39):
# There's no point in turning the quotation mark into
- # ", unless it happens within an attribute value, which
- # is handled elsewhere.
+ # " or the single quote into ', unless it
+ # happens within an attribute value, which is handled
+ # elsewhere.
characters_for_re.append(character)
lookup[character] = name
- # But we do want to turn " into the quotation mark.
+ # But we do want to recognize those entities on the way in and
+ # convert them to Unicode characters.
reverse_lookup[name] = character
re_definition = "[%s]" % "".join(characters_for_re)
return lookup, reverse_lookup, re.compile(re_definition)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/beautifulsoup4-4.7.1/bs4/element.py new/beautifulsoup4-4.8.0/bs4/element.py
--- old/beautifulsoup4-4.7.1/bs4/element.py 2019-01-07 01:35:05.000000000 +0100
+++ new/beautifulsoup4-4.8.0/bs4/element.py 2019-07-16 22:46:05.000000000 +0200
@@ -16,7 +16,11 @@
'The soupsieve package is not installed. CSS selectors cannot be used.'
)
-from bs4.dammit import EntitySubstitution
+from bs4.formatter import (
+ Formatter,
+ HTMLFormatter,
+ XMLFormatter,
+)
DEFAULT_OUTPUT_ENCODING = "utf-8"
PY3K = (sys.version_info[0] > 2)
@@ -99,138 +103,71 @@
return match.group(1) + encoding
return self.CHARSET_RE.sub(rewrite, self.original_value)
-class HTMLAwareEntitySubstitution(EntitySubstitution):
-
- """Entity substitution rules that are aware of some HTML quirks.
-
- Specifically, the contents of <script> and <style> tags should not
- undergo entity substitution.
-
- Incoming NavigableString objects are checked to see if they're the
- direct children of a <script> or <style> tag.
- """
-
- cdata_containing_tags = set(["script", "style"])
-
- preformatted_tags = set(["pre"])
-
- preserve_whitespace_tags = set(['pre', 'textarea'])
-
- @classmethod
- def _substitute_if_appropriate(cls, ns, f):
- if (isinstance(ns, NavigableString)
- and ns.parent is not None
- and ns.parent.name in cls.cdata_containing_tags):
- # Do nothing.
- return ns
- # Substitute.
- return f(ns)
-
- @classmethod
- def substitute_html(cls, ns):
- return cls._substitute_if_appropriate(
- ns, EntitySubstitution.substitute_html)
-
- @classmethod
- def substitute_xml(cls, ns):
- return cls._substitute_if_appropriate(
- ns, EntitySubstitution.substitute_xml)
-
-class Formatter(object):
- """Contains information about how to format a parse tree."""
-
- # By default, represent void elements as <tag/> rather than <tag>
- void_element_close_prefix = '/'
-
- def substitute_entities(self, *args, **kwargs):
- """Transform certain characters into named entities."""
- raise NotImplementedError()
-
-class HTMLFormatter(Formatter):
- """The default HTML formatter."""
- def substitute(self, *args, **kwargs):
- return HTMLAwareEntitySubstitution.substitute_html(*args, **kwargs)
-
-class MinimalHTMLFormatter(Formatter):
- """A minimal HTML formatter."""
- def substitute(self, *args, **kwargs):
- return HTMLAwareEntitySubstitution.substitute_xml(*args, **kwargs)
-
-class HTML5Formatter(HTMLFormatter):
- """An HTML formatter that omits the slash in a void tag."""
- void_element_close_prefix = None
-
-class XMLFormatter(Formatter):
- """Substitute only the essential XML entities."""
- def substitute(self, *args, **kwargs):
- return EntitySubstitution.substitute_xml(*args, **kwargs)
-
-class HTMLXMLFormatter(Formatter):
- """Format XML using HTML rules."""
- def substitute(self, *args, **kwargs):
- return HTMLAwareEntitySubstitution.substitute_html(*args, **kwargs)
-
class PageElement(object):
"""Contains the navigational information for some part of the page
(either a tag or a piece of text)"""
+
+ def setup(self, parent=None, previous_element=None, next_element=None,
+ previous_sibling=None, next_sibling=None):
+ """Sets up the initial relations between this element and
+ other elements."""
+ self.parent = parent
+
+ self.previous_element = previous_element
+ if previous_element is not None:
+ self.previous_element.next_element = self
+
+ self.next_element = next_element
+ if self.next_element is not None:
+ self.next_element.previous_element = self
- # There are five possible values for the "formatter" argument passed in
- # to methods like encode() and prettify():
- #
- # "html" - All Unicode characters with corresponding HTML entities
- # are converted to those entities on output.
- # "html5" - The same as "html", but empty void tags are represented as
- # <tag> rather than <tag/>
- # "minimal" - Bare ampersands and angle brackets are converted to
- # XML entities: & < >
- # None - The null formatter. Unicode characters are never
- # converted to entities. This is not recommended, but it's
- # faster than "minimal".
- # A callable function - it will be called on every string that needs to undergo entity substitution.
- # A Formatter instance - Formatter.substitute(string) will be called on every string that
- # needs to undergo entity substitution.
- #
-
- # In an HTML document, the default "html", "html5", and "minimal"
- # functions will leave the contents of <script> and <style> tags
- # alone. For an XML document, all tags will be given the same
- # treatment.
-
- HTML_FORMATTERS = {
- "html" : HTMLFormatter(),
- "html5" : HTML5Formatter(),
- "minimal" : MinimalHTMLFormatter(),
- None : None
- }
-
- XML_FORMATTERS = {
- "html" : HTMLXMLFormatter(),
- "minimal" : XMLFormatter(),
- None : None
- }
+ self.next_sibling = next_sibling
+ if self.next_sibling is not None:
+ self.next_sibling.previous_sibling = self
- def format_string(self, s, formatter='minimal'):
+ if (previous_sibling is None
+ and self.parent is not None and self.parent.contents):
+ previous_sibling = self.parent.contents[-1]
+
+ self.previous_sibling = previous_sibling
+ if previous_sibling is not None:
+ self.previous_sibling.next_sibling = self
+
+ def format_string(self, s, formatter):
"""Format the given string using the given formatter."""
- if isinstance(formatter, basestring):
- formatter = self._formatter_for_name(formatter)
if formatter is None:
- output = s
- else:
- if isinstance(formatter, Callable):
- # Backwards compatibility -- you used to pass in a formatting method.
- output = formatter(s)
- else:
- output = formatter.substitute(s)
+ return s
+ if not isinstance(formatter, Formatter):
+ formatter = self.formatter_for_name(formatter)
+ output = formatter.substitute(s)
return output
+ def formatter_for_name(self, formatter):
+ """Look up or create a Formatter for the given identifier,
+ if necessary.
+
+ :param formatter: Can be a Formatter object (used as-is), a
+ function (used as the entity substitution hook for an
+ XMLFormatter or HTMLFormatter), or a string (used to look up
+ an XMLFormatter or HTMLFormatter in the appropriate registry.
+ """
+ if isinstance(formatter, Formatter):
+ return formatter
+ if self._is_xml:
+ c = XMLFormatter
+ else:
+ c = HTMLFormatter
+ if callable(formatter):
+ return c(entity_substitution=formatter)
+ return c.REGISTRY[formatter]
+
@property
def _is_xml(self):
"""Is this element part of an XML tree or an HTML tree?
- This is used when mapping a formatter name ("minimal") to an
- appropriate function (one that performs entity-substitution on
- the contents of <script> and <style> tags, or not). It can be
+ This is used in formatter_for_name, when deciding whether an
+ XMLFormatter or HTMLFormatter is more appropriate. It can be
inefficient, but it should be called very rarely.
"""
if self.known_xml is not None:
@@ -248,46 +185,13 @@
return getattr(self, 'is_xml', False)
return self.parent._is_xml
- def _formatter_for_name(self, name):
- "Look up a formatter function based on its name and the tree."
- if self._is_xml:
- return self.XML_FORMATTERS.get(name, XMLFormatter())
- else:
- return self.HTML_FORMATTERS.get(name, HTMLFormatter())
-
- def setup(self, parent=None, previous_element=None, next_element=None,
- previous_sibling=None, next_sibling=None):
- """Sets up the initial relations between this element and
- other elements."""
- self.parent = parent
-
- self.previous_element = previous_element
- if previous_element is not None:
- self.previous_element.next_element = self
-
- self.next_element = next_element
- if self.next_element is not None:
- self.next_element.previous_element = self
-
- self.next_sibling = next_sibling
- if self.next_sibling is not None:
- self.next_sibling.previous_sibling = self
-
- if (previous_sibling is None
- and self.parent is not None and self.parent.contents):
- previous_sibling = self.parent.contents[-1]
-
- self.previous_sibling = previous_sibling
- if previous_sibling is not None:
- self.previous_sibling.next_sibling = self
-
nextSibling = _alias("next_sibling") # BS3
previousSibling = _alias("previous_sibling") # BS3
def replace_with(self, replace_with):
if self.parent is None:
raise ValueError(
- "Cannot replace one element with another when the"
+ "Cannot replace one element with another when the "
"element to be replaced is not part of a tree.")
if replace_with is self:
return
@@ -742,6 +646,7 @@
self.__class__.__name__, attr))
def output_ready(self, formatter="minimal"):
+ """Run the string through the provided formatter."""
output = self.format_string(self, formatter)
return self.PREFIX + output + self.SUFFIX
@@ -760,10 +665,12 @@
but the return value will be ignored.
"""
- def output_ready(self, formatter="minimal"):
- """CData strings are passed into the formatter.
- But the return value is ignored."""
- self.format_string(self, formatter)
+ def output_ready(self, formatter=None):
+ """CData strings are passed into the formatter, purely
+ for any side effects. The return value is ignored.
+ """
+ if formatter is not None:
+ ignore = self.format_string(self, formatter)
return self.PREFIX + self + self.SUFFIX
class CData(PreformattedString):
@@ -831,14 +738,6 @@
self.name = name
self.namespace = namespace
self.prefix = prefix
- if builder is not None:
- preserve_whitespace_tags = builder.preserve_whitespace_tags
- else:
- if is_xml:
- preserve_whitespace_tags = []
- else:
- preserve_whitespace_tags = HTMLAwareEntitySubstitution.preserve_whitespace_tags
- self.preserve_whitespace_tags = preserve_whitespace_tags
if attrs is None:
attrs = {}
elif attrs:
@@ -861,12 +760,31 @@
self.setup(parent, previous)
self.hidden = False
- # Set up any substitutions, such as the charset in a META tag.
- if builder is not None:
+ if builder is None:
+ # In the absence of a TreeBuilder, assume this tag is nothing
+ # special.
+ self.can_be_empty_element = False
+ self.cdata_list_attributes = None
+ else:
+ # Set up any substitutions for this tag, such as the charset in a META tag.
builder.set_up_substitutions(self)
+
+ # Ask the TreeBuilder whether this tag might be an empty-element tag.
self.can_be_empty_element = builder.can_be_empty_element(name)
- else:
- self.can_be_empty_element = False
+
+ # Keep track of the list of attributes of this tag that
+ # might need to be treated as a list.
+ #
+ # For performance reasons, we store the whole data structure
+ # rather than asking the question of every tag. Asking would
+ # require building a new data structure every time, and
+ # (unlike can_be_empty_element), we almost never need
+ # to check this.
+ self.cdata_list_attributes = builder.cdata_list_attributes
+
+ # Keep track of the names that might cause this tag to be treated as a
+ # whitespace-preserved tag.
+ self.preserve_whitespace_tags = builder.preserve_whitespace_tags
parserClass = _alias("parser_class") # BS3
@@ -981,6 +899,43 @@
for element in self.contents[:]:
element.extract()
+ def smooth(self):
+ """Smooth out this element's children by consolidating consecutive strings.
+
+ This makes pretty-printed output look more natural following a
+ lot of operations that modified the tree.
+ """
+ # Mark the first position of every pair of children that need
+ # to be consolidated. Do this rather than making a copy of
+ # self.contents, since in most cases very few strings will be
+ # affected.
+ marked = []
+ for i, a in enumerate(self.contents):
+ if isinstance(a, Tag):
+ # Recursively smooth children.
+ a.smooth()
+ if i == len(self.contents)-1:
+ # This is the last item in .contents, and it's not a
+ # tag. There's no chance it needs any work.
+ continue
+ b = self.contents[i+1]
+ if (isinstance(a, NavigableString)
+ and isinstance(b, NavigableString)
+ and not isinstance(a, PreformattedString)
+ and not isinstance(b, PreformattedString)
+ ):
+ marked.append(i)
+
+ # Go over the marked positions in reverse order, so that
+ # removing items from .contents won't affect the remaining
+ # positions.
+ for i in reversed(marked):
+ a = self.contents[i]
+ b = self.contents[i+1]
+ b.extract()
+ n = NavigableString(a+b)
+ a.replace_with(n)
+
def index(self, element):
"""
Find the index of a child by identity, not value. Avoids issues with
@@ -1115,14 +1070,6 @@
u = self.decode(indent_level, encoding, formatter)
return u.encode(encoding, errors)
- def _should_pretty_print(self, indent_level):
- """Should this tag be pretty-printed?"""
-
- return (
- indent_level is not None
- and self.name not in self.preserve_whitespace_tags
- )
-
def decode(self, indent_level=None,
eventual_encoding=DEFAULT_OUTPUT_ENCODING,
formatter="minimal"):
@@ -1136,30 +1083,32 @@
encoding.
"""
- # First off, turn a string formatter into a Formatter object. This
- # will stop the lookup from happening over and over again.
- if not isinstance(formatter, Formatter) and not isinstance(formatter, Callable):
- formatter = self._formatter_for_name(formatter)
+ # First off, turn a non-Formatter `formatter` into a Formatter
+ # object. This will stop the lookup from happening over and
+ # over again.
+ if not isinstance(formatter, Formatter):
+ formatter = self.formatter_for_name(formatter)
+ attributes = formatter.attributes(self)
attrs = []
- if self.attrs:
- for key, val in sorted(self.attrs.items()):
- if val is None:
- decoded = key
- else:
- if isinstance(val, list) or isinstance(val, tuple):
- val = ' '.join(val)
- elif not isinstance(val, basestring):
- val = unicode(val)
- elif (
+ for key, val in attributes:
+ if val is None:
+ decoded = key
+ else:
+ if isinstance(val, list) or isinstance(val, tuple):
+ val = ' '.join(val)
+ elif not isinstance(val, basestring):
+ val = unicode(val)
+ elif (
isinstance(val, AttributeValueWithCharsetSubstitution)
- and eventual_encoding is not None):
- val = val.encode(eventual_encoding)
-
- text = self.format_string(val, formatter)
- decoded = (
- unicode(key) + '='
- + EntitySubstitution.quoted_attribute_value(text))
- attrs.append(decoded)
+ and eventual_encoding is not None
+ ):
+ val = val.encode(eventual_encoding)
+
+ text = formatter.attribute_value(val)
+ decoded = (
+ unicode(key) + '='
+ + formatter.quoted_attribute_value(text))
+ attrs.append(decoded)
close = ''
closeTag = ''
@@ -1168,9 +1117,7 @@
prefix = self.prefix + ":"
if self.is_empty_element:
- close = ''
- if isinstance(formatter, Formatter):
- close = formatter.void_element_close_prefix or close
+ close = formatter.void_element_close_prefix or ''
else:
closeTag = '</%s%s>' % (prefix, self.name)
@@ -1185,7 +1132,8 @@
else:
indent_contents = None
contents = self.decode_contents(
- indent_contents, eventual_encoding, formatter)
+ indent_contents, eventual_encoding, formatter
+ )
if self.hidden:
# This is the 'document root' object.
@@ -1217,6 +1165,13 @@
s = ''.join(s)
return s
+ def _should_pretty_print(self, indent_level):
+ """Should this tag be pretty-printed?"""
+ return (
+ indent_level is not None
+ and self.name not in self.preserve_whitespace_tags
+ )
+
def prettify(self, encoding=None, formatter="minimal"):
if encoding is None:
return self.decode(True, formatter=formatter)
@@ -1232,19 +1187,19 @@
indented this many spaces.
:param eventual_encoding: The tag is destined to be
- encoded into this encoding. This method is _not_
+ encoded into this encoding. decode_contents() is _not_
responsible for performing that encoding. This information
is passed in so that it can be substituted in if the
document contains a <META> tag that mentions the document's
encoding.
- :param formatter: The output formatter responsible for converting
- entities to Unicode characters.
+ :param formatter: A Formatter object, or a string naming one of
+ the standard Formatters.
"""
# First off, turn a string formatter into a Formatter object. This
# will stop the lookup from happening over and over again.
- if not isinstance(formatter, Formatter) and not isinstance(formatter, Callable):
- formatter = self._formatter_for_name(formatter)
+ if not isinstance(formatter, Formatter):
+ formatter = self.formatter_for_name(formatter)
pretty_print = (indent_level is not None)
s = []
@@ -1255,16 +1210,19 @@
elif isinstance(c, Tag):
s.append(c.decode(indent_level, eventual_encoding,
formatter))
- if text and indent_level and not self.name == 'pre':
+ preserve_whitespace = (
+ self.preserve_whitespace_tags and self.name in self.preserve_whitespace_tags
+ )
+ if text and indent_level and not preserve_whitespace:
text = text.strip()
if text:
- if pretty_print and not self.name == 'pre':
+ if pretty_print and not preserve_whitespace:
s.append(" " * (indent_level - 1))
s.append(text)
- if pretty_print and not self.name == 'pre':
+ if pretty_print and not preserve_whitespace:
s.append("\n")
return ''.join(s)
-
+
def encode_contents(
self, indent_level=None, encoding=DEFAULT_OUTPUT_ENCODING,
formatter="minimal"):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/beautifulsoup4-4.7.1/bs4/formatter.py new/beautifulsoup4-4.8.0/bs4/formatter.py
--- old/beautifulsoup4-4.7.1/bs4/formatter.py 1970-01-01 01:00:00.000000000 +0100
+++ new/beautifulsoup4-4.8.0/bs4/formatter.py 2019-07-16 22:46:05.000000000 +0200
@@ -0,0 +1,99 @@
+from bs4.dammit import EntitySubstitution
+
+class Formatter(EntitySubstitution):
+ """Describes a strategy to use when outputting a parse tree to a string.
+
+ Some parts of this strategy come from the distinction between
+ HTML4, HTML5, and XML. Others are configurable by the user.
+ """
+ # Registries of XML and HTML formatters.
+ XML_FORMATTERS = {}
+ HTML_FORMATTERS = {}
+
+ HTML = 'html'
+ XML = 'xml'
+
+ HTML_DEFAULTS = dict(
+ cdata_containing_tags=set(["script", "style"]),
+ )
+
+ def _default(self, language, value, kwarg):
+ if value is not None:
+ return value
+ if language == self.XML:
+ return set()
+ return self.HTML_DEFAULTS[kwarg]
+
+ def __init__(
+ self, language=None, entity_substitution=None,
+ void_element_close_prefix='/', cdata_containing_tags=None,
+ ):
+ """
+
+ :param void_element_close_prefix: By default, represent void
+ elements as <tag/> rather than <tag>
+ """
+ self.language = language
+ self.entity_substitution = entity_substitution
+ self.void_element_close_prefix = void_element_close_prefix
+ self.cdata_containing_tags = self._default(
+ language, cdata_containing_tags, 'cdata_containing_tags'
+ )
+
+ def substitute(self, ns):
+ """Process a string that needs to undergo entity substitution."""
+ if not self.entity_substitution:
+ return ns
+ from element import NavigableString
+ if (isinstance(ns, NavigableString)
+ and ns.parent is not None
+ and ns.parent.name in self.cdata_containing_tags):
+ # Do nothing.
+ return ns
+ # Substitute.
+ return self.entity_substitution(ns)
+
+ def attribute_value(self, value):
+ """Process the value of an attribute."""
+ return self.substitute(value)
+
+ def attributes(self, tag):
+ """Reorder a tag's attributes however you want."""
+ return sorted(tag.attrs.items())
+
+
+class HTMLFormatter(Formatter):
+ REGISTRY = {}
+ def __init__(self, *args, **kwargs):
+ return super(HTMLFormatter, self).__init__(self.HTML, *args, **kwargs)
+
+
+class XMLFormatter(Formatter):
+ REGISTRY = {}
+ def __init__(self, *args, **kwargs):
+ return super(XMLFormatter, self).__init__(self.XML, *args, **kwargs)
+
+
+# Set up aliases for the default formatters.
+HTMLFormatter.REGISTRY['html'] = HTMLFormatter(
+ entity_substitution=EntitySubstitution.substitute_html
+)
+HTMLFormatter.REGISTRY["html5"] = HTMLFormatter(
+ entity_substitution=EntitySubstitution.substitute_html,
+ void_element_close_prefix = None
+)
+HTMLFormatter.REGISTRY["minimal"] = HTMLFormatter(
+ entity_substitution=EntitySubstitution.substitute_xml
+)
+HTMLFormatter.REGISTRY[None] = HTMLFormatter(
+ entity_substitution=None
+)
+XMLFormatter.REGISTRY["html"] = XMLFormatter(
+ entity_substitution=EntitySubstitution.substitute_html
+)
+XMLFormatter.REGISTRY["minimal"] = XMLFormatter(
+ entity_substitution=EntitySubstitution.substitute_xml
+)
+XMLFormatter.REGISTRY[None] = Formatter(
+ Formatter(Formatter.XML, entity_substitution=None)
+)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/beautifulsoup4-4.7.1/bs4/testing.py new/beautifulsoup4-4.8.0/bs4/testing.py
--- old/beautifulsoup4-4.7.1/bs4/testing.py 2018-12-31 03:11:14.000000000 +0100
+++ new/beautifulsoup4-4.8.0/bs4/testing.py 2019-07-08 03:59:55.000000000 +0200
@@ -63,19 +63,19 @@
@property
def default_builder(self):
- return default_builder()
+ return default_builder
def soup(self, markup, **kwargs):
"""Build a Beautiful Soup object from markup."""
builder = kwargs.pop('builder', self.default_builder)
return BeautifulSoup(markup, builder=builder, **kwargs)
- def document_for(self, markup):
+ def document_for(self, markup, **kwargs):
"""Turn an HTML fragment into a document.
The details depend on the builder.
"""
- return self.default_builder.test_fragment_to_document(markup)
+ return self.default_builder(**kwargs).test_fragment_to_document(markup)
def assertSoupEquals(self, to_parse, compare_parsed_to=None):
builder = self.default_builder
@@ -232,7 +232,7 @@
soup = self.soup("")
new_tag = soup.new_tag(name)
self.assertEqual(True, new_tag.is_empty_element)
-
+
def test_pickle_and_unpickle_identity(self):
# Pickling a tree, then unpickling it, yields a tree identical
# to the original.
@@ -491,6 +491,12 @@
u"<p>\u2022 AT&T is in the s&p 500</p>"
)
+ def test_apos_entity(self):
+ self.assertSoupEquals(
+ u"<p>Bob's Bar</p>",
+ u"<p>Bob's Bar</p>",
+ )
+
def test_entities_in_foreign_document_encoding(self):
# “ and ” are invalid numeric entities referencing
# Windows-1252 characters. - references a character common
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/beautifulsoup4-4.7.1/bs4/tests/test_html5lib.py new/beautifulsoup4-4.8.0/bs4/tests/test_html5lib.py
--- old/beautifulsoup4-4.7.1/bs4/tests/test_html5lib.py 2018-12-23 23:16:18.000000000 +0100
+++ new/beautifulsoup4-4.8.0/bs4/tests/test_html5lib.py 2019-07-07 21:54:34.000000000 +0200
@@ -22,7 +22,7 @@
@property
def default_builder(self):
- return HTML5TreeBuilder()
+ return HTML5TreeBuilder
def test_soupstrainer(self):
# The html5lib tree builder does not support SoupStrainers.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/beautifulsoup4-4.7.1/bs4/tests/test_htmlparser.py new/beautifulsoup4-4.8.0/bs4/tests/test_htmlparser.py
--- old/beautifulsoup4-4.7.1/bs4/tests/test_htmlparser.py 2018-07-15 14:26:01.000000000 +0200
+++ new/beautifulsoup4-4.8.0/bs4/tests/test_htmlparser.py 2019-07-07 21:52:25.000000000 +0200
@@ -9,9 +9,7 @@
class HTMLParserTreeBuilderSmokeTest(SoupTest, HTMLTreeBuilderSmokeTest):
- @property
- def default_builder(self):
- return HTMLParserTreeBuilder()
+ default_builder = HTMLParserTreeBuilder
def test_namespaced_system_doctype(self):
# html.parser can't handle namespaced doctypes, so skip this one.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/beautifulsoup4-4.7.1/bs4/tests/test_lxml.py new/beautifulsoup4-4.8.0/bs4/tests/test_lxml.py
--- old/beautifulsoup4-4.7.1/bs4/tests/test_lxml.py 2019-01-07 00:41:32.000000000 +0100
+++ new/beautifulsoup4-4.8.0/bs4/tests/test_lxml.py 2019-07-07 21:54:54.000000000 +0200
@@ -36,7 +36,7 @@
@property
def default_builder(self):
- return LXMLTreeBuilder()
+ return LXMLTreeBuilder
def test_out_of_range_entity(self):
self.assertSoupEquals(
@@ -79,7 +79,7 @@
@property
def default_builder(self):
- return LXMLTreeBuilderForXML()
+ return LXMLTreeBuilderForXML
def test_namespace_indexing(self):
# We should not track un-prefixed namespaces as we can only hold one
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/beautifulsoup4-4.7.1/bs4/tests/test_soup.py new/beautifulsoup4-4.8.0/bs4/tests/test_soup.py
--- old/beautifulsoup4-4.7.1/bs4/tests/test_soup.py 2016-07-27 03:27:42.000000000 +0200
+++ new/beautifulsoup4-4.8.0/bs4/tests/test_soup.py 2019-07-16 22:46:05.000000000 +0200
@@ -24,6 +24,7 @@
EncodingDetector,
)
from bs4.testing import (
+ default_builder,
SoupTest,
skipIf,
)
@@ -54,7 +55,72 @@
soup = self.soup(utf8_data, exclude_encodings=["utf-8"])
self.assertEqual("windows-1252", soup.original_encoding)
+ def test_custom_builder_class(self):
+ # Verify that you can pass in a custom Builder class and
+ # it'll be instantiated with the appropriate keyword arguments.
+ class Mock(object):
+ def __init__(self, **kwargs):
+ self.called_with = kwargs
+ self.is_xml = True
+ def initialize_soup(self, soup):
+ pass
+ def prepare_markup(self, *args, **kwargs):
+ return ''
+
+ kwargs = dict(
+ var="value",
+ # This is a deprecated BS3-era keyword argument, which
+ # will be stripped out.
+ convertEntities=True,
+ )
+ with warnings.catch_warnings(record=True):
+ soup = BeautifulSoup('', builder=Mock, **kwargs)
+ assert isinstance(soup.builder, Mock)
+ self.assertEqual(dict(var="value"), soup.builder.called_with)
+
+ # You can also instantiate the TreeBuilder yourself. In this
+ # case, that specific object is used and any keyword arguments
+ # to the BeautifulSoup constructor are ignored.
+ builder = Mock(**kwargs)
+ with warnings.catch_warnings(record=True) as w:
+ soup = BeautifulSoup(
+ '', builder=builder, ignored_value=True,
+ )
+ msg = str(w[0].message)
+ assert msg.startswith("Keyword arguments to the BeautifulSoup constructor will be ignored.")
+ self.assertEqual(builder, soup.builder)
+ self.assertEqual(kwargs, builder.called_with)
+
+ def test_cdata_list_attributes(self):
+ # Most attribute values are represented as scalars, but the
+ # HTML standard says that some attributes, like 'class' have
+ # space-separated lists as values.
+ markup = '<a id=" an id " class=" a class "></a>'
+ soup = self.soup(markup)
+
+ # Note that the spaces are stripped for 'class' but not for 'id'.
+ a = soup.a
+ self.assertEqual(" an id ", a['id'])
+ self.assertEqual(["a", "class"], a['class'])
+
+ # TreeBuilder takes an argument called 'mutli_valued_attributes' which lets
+ # you customize or disable this. As always, you can customize the TreeBuilder
+ # by passing in a keyword argument to the BeautifulSoup constructor.
+ soup = self.soup(markup, builder=default_builder, multi_valued_attributes=None)
+ self.assertEqual(" a class ", soup.a['class'])
+
+ # Here are two ways of saying that `id` is a multi-valued
+ # attribute in this context, but 'class' is not.
+ for switcheroo in ({'*': 'id'}, {'a': 'id'}):
+ with warnings.catch_warnings(record=True) as w:
+ # This will create a warning about not explicitly
+ # specifying a parser, but we'll ignore it.
+ soup = self.soup(markup, builder=None, multi_valued_attributes=switcheroo)
+ a = soup.a
+ self.assertEqual(["an", "id"], a['id'])
+ self.assertEqual(" a class ", a['class'])
+
class TestWarnings(SoupTest):
def _no_parser_specified(self, s, is_there=True):
@@ -217,7 +283,7 @@
self.assertEqual(
self.sub.substitute_xml_containing_entities("ÁT&T"),
"ÁT&T")
-
+
def test_quotes_not_html_substituted(self):
"""There's no need to do this except inside attribute values."""
text = 'Bob\'s "bar"'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/beautifulsoup4-4.7.1/bs4/tests/test_tree.py new/beautifulsoup4-4.8.0/bs4/tests/test_tree.py
--- old/beautifulsoup4-4.7.1/bs4/tests/test_tree.py 2019-01-07 00:46:26.000000000 +0100
+++ new/beautifulsoup4-4.8.0/bs4/tests/test_tree.py 2019-07-16 22:46:05.000000000 +0200
@@ -25,6 +25,7 @@
Comment,
Declaration,
Doctype,
+ Formatter,
NavigableString,
SoupStrainer,
Tag,
@@ -416,6 +417,48 @@
self.assertEqual([], soup.find_all(id=1, text="bar"))
+class TestSmooth(TreeTest):
+ """Test Tag.smooth."""
+
+ def test_smooth(self):
+ soup = self.soup("<div>a</div>")
+ div = soup.div
+ div.append("b")
+ div.append("c")
+ div.append(Comment("Comment 1"))
+ div.append(Comment("Comment 2"))
+ div.append("d")
+ builder = self.default_builder()
+ span = Tag(soup, builder, 'span')
+ span.append('1')
+ span.append('2')
+ div.append(span)
+
+ # At this point the tree has a bunch of adjacent
+ # NavigableStrings. This is normal, but it has no meaning in
+ # terms of HTML, so we may want to smooth things out for
+ # output.
+
+ # Since the <span> tag has two children, its .string is None.
+ self.assertEquals(None, div.span.string)
+
+ self.assertEqual(7, len(div.contents))
+ div.smooth()
+ self.assertEqual(5, len(div.contents))
+
+ # The three strings at the beginning of div.contents have been
+ # merged into on string.
+ #
+ self.assertEqual('abc', div.contents[0])
+
+ # The call is recursive -- the <span> tag was also smoothed.
+ self.assertEqual('12', div.span.string)
+
+ # The two comments have _not_ been merged, even though
+ # comments are strings. Merging comments would change the
+ # meaning of the HTML.
+ self.assertEqual('Comment 1', div.contents[1])
+ self.assertEqual('Comment 2', div.contents[2])
class TestIndex(TreeTest):
@@ -896,7 +939,7 @@
self.assertEqual(soup.a.contents[0].next_element, "bar")
def test_insert_tag(self):
- builder = self.default_builder
+ builder = self.default_builder()
soup = self.soup(
"<a><b>Find</b><c>lady!</c><d></d></a>", builder=builder)
magic_tag = Tag(soup, builder, 'magictag')
@@ -1532,7 +1575,7 @@
# callable is called on every string.
self.assertEqual(
decoded,
- self.document_for(u"<b><FOO></b><b>BAR</b><br>"))
+ self.document_for(u"<b><FOO></b><b>BAR</b><br/>"))
def test_formatter_is_run_on_attribute_values(self):
markup = u'<a href="http://a.com?a=b&c=é">e</a>'
@@ -1570,11 +1613,11 @@
self.assertTrue(b"< < hey > >" in encoded)
def test_prettify_leaves_preformatted_text_alone(self):
- soup = self.soup("<div> foo <pre> \tbar\n \n </pre> baz ")
+ soup = self.soup("<div> foo <pre> \tbar\n \n </pre> baz <textarea> eee\nfff\t</textarea></div>")
# Everything outside the <pre> tag is reformatted, but everything
# inside is left alone.
self.assertEqual(
- u'<div>\n foo\n <pre> \tbar\n \n </pre>\n baz\n</div>',
+ u'<div>\n foo\n <pre> \tbar\n \n </pre>\n baz\n <textarea> eee\nfff\t</textarea>\n</div>',
soup.div.prettify())
def test_prettify_accepts_formatter_function(self):
@@ -1683,6 +1726,29 @@
else:
self.assertEqual(b'<b>\\u2603</b>', repr(soup))
+class TestFormatter(SoupTest):
+
+ def test_sort_attributes(self):
+ # Test the ability to override Formatter.attributes() to,
+ # e.g., disable the normal sorting of attributes.
+ class UnsortedFormatter(Formatter):
+ def attributes(self, tag):
+ self.called_with = tag
+ for k, v in sorted(tag.attrs.items()):
+ if k == 'ignore':
+ continue
+ yield k,v
+
+ soup = self.soup('<p cval="1" aval="2" ignore="ignored"></p>')
+ formatter = UnsortedFormatter()
+ decoded = soup.decode(formatter=formatter)
+
+ # attributes() was called on the <p> tag. It filtered out one
+ # attribute and sorted the other two.
+ self.assertEquals(formatter.called_with, soup.p)
+ self.assertEquals(u'<p aval="2" cval="1"></p>', decoded)
+
+
class TestNavigableStringSubclasses(SoupTest):
def test_cdata(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/beautifulsoup4-4.7.1/doc/source/index.rst new/beautifulsoup4-4.8.0/doc/source/index.rst
--- old/beautifulsoup4-4.7.1/doc/source/index.rst 2018-12-31 17:52:43.000000000 +0100
+++ new/beautifulsoup4-4.8.0/doc/source/index.rst 2019-07-17 03:31:27.000000000 +0200
@@ -31,7 +31,7 @@
* `这篇文档当然还有中文版. <http://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/>`_
* このページは日本語で利用できます(`外部リンク <http://kondou.com/BS4/>`_)
-* 이 문서는 한국어 번역도 가능합니다. (`외부 링크 <http://coreapython.hosting.paran.com/etc/beautifulsoup4.html>`_)
+* 이 문서는 한국어 번역도 가능합니다. (`외부 링크 <https://web.archive.org/web/20150319200824/http://coreapython.hosting.paran…>`_)
Getting help
------------
@@ -266,9 +266,9 @@
+----------------------+--------------------------------------------+--------------------------------+--------------------------+
| Parser | Typical usage | Advantages | Disadvantages |
+----------------------+--------------------------------------------+--------------------------------+--------------------------+
-| Python's html.parser | ``BeautifulSoup(markup, "html.parser")`` | * Batteries included | * Not very lenient |
-| | | * Decent speed | (before Python 2.7.3 |
-| | | * Lenient (as of Python 2.7.3 | or 3.2.2) |
+| Python's html.parser | ``BeautifulSoup(markup, "html.parser")`` | * Batteries included | * Not as fast as lxml, |
+| | | * Decent speed | less lenient than |
+| | | * Lenient (As of Python 2.7.3 | html5lib. |
| | | and 3.2.) | |
+----------------------+--------------------------------------------+--------------------------------+--------------------------+
| lxml's HTML parser | ``BeautifulSoup(markup, "lxml")`` | * Very fast | * External C dependency |
@@ -428,8 +428,15 @@
print(rel_soup.p)
# <p>Back to the <a rel="index contents">homepage</a></p>
-You can use ```get_attribute_list`` to get a value that's always a list,
-string, whether or not it's a multi-valued atribute
+ You can disable this by passing ``multi_valued_attributes=None`` as a
+keyword argument into the ``BeautifulSoup`` constructor::
+
+ no_list_soup = BeautifulSoup('<p class="body strikeout"></p>', 'html', multi_valued_attributes=None)
+ no_list_soup.p['class']
+ # u'body strikeout'
+
+You can use ```get_attribute_list`` to get a value that's always a
+list, whether or not it's a multi-valued atribute::
id_soup.p.get_attribute_list('id')
# ["my id"]
@@ -440,8 +447,20 @@
xml_soup.p['class']
# u'body strikeout'
+Again, you can configure this using the ``multi_valued_attributes`` argument::
+
+ class_is_multi= { '*' : 'class'}
+ xml_soup = BeautifulSoup('<p class="body strikeout"></p>', 'xml', multi_valued_attributes=class_is_multi)
+ xml_soup.p['class']
+ # [u'body', u'strikeout']
+You probably won't need to do this, but if you do, use the defaults as
+a guide. They implement the rules described in the HTML specification::
+ from bs4.builder import builder_registry
+ builder_registry.lookup('html').DEFAULT_CDATA_LIST_ATTRIBUTES
+
+
``NavigableString``
-------------------
@@ -2093,6 +2112,40 @@
Like ``replace_with()``, ``unwrap()`` returns the tag
that was replaced.
+``smooth()``
+---------------------------
+
+After calling a bunch of methods that modify the parse tree, you may end up with two or more ``NavigableString`` objects next to each other. Beautiful Soup doesn't have any problems with this, but since it can't happen in a freshly parsed document, you might not expect behavior like the following::
+
+ soup = BeautifulSoup("<p>A one</p>")
+ soup.p.append(", a two")
+
+ soup.p.contents
+ # [u'A one', u', a two']
+
+ print(soup.p.encode())
+ # <p>A one, a two</p>
+
+ print(soup.p.prettify())
+ # <p>
+ # A one
+ # , a two
+ # </p>
+
+You can call ``Tag.smooth()`` to clean up the parse tree by consolidating adjacent strings::
+
+ soup.smooth()
+
+ soup.p.contents
+ # [u'A one, a two']
+
+ print(soup.p.prettify())
+ # <p>
+ # A one, a two
+ # </p>
+
+The ``smooth()`` method is new in Beautiful Soup 4.8.0.
+
Output
======
@@ -2103,7 +2156,7 @@
The ``prettify()`` method will turn a Beautiful Soup parse tree into a
nicely formatted Unicode string, with a separate line for each
-tag and each string:
+tag and each string::
markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
soup = BeautifulSoup(markup)
@@ -2216,7 +2269,7 @@
# </body>
# </html>
- If you pass in ``formatter="html5"``, it's the same as
+If you pass in ``formatter="html5"``, it's the same as
``formatter="html5"``, but Beautiful Soup will
omit the closing slash in HTML void tags like "br"::
@@ -2245,16 +2298,17 @@
print(link_soup.a.encode(formatter=None))
# <a href="http://example.com/?foo=val1&bar=val2">A link</a>
-Finally, if you pass in a function for ``formatter``, Beautiful Soup
-will call that function once for every string and attribute value in
-the document. You can do whatever you want in this function. Here's a
-formatter that converts strings to uppercase and does absolutely
-nothing else::
+If you need more sophisticated control over your output, you can
+use Beautiful Soup's ``Formatter`` class. Here's a formatter that
+converts strings to uppercase, whether they occur in a text node or in an
+attribute value::
+ from bs4.formatter import HTMLFormatter
def uppercase(str):
return str.upper()
+ formatter = HTMLFormatter(uppercase)
- print(soup.prettify(formatter=uppercase))
+ print(soup.prettify(formatter=formatter))
# <html>
# <body>
# <p>
@@ -2263,34 +2317,31 @@
# </body>
# </html>
- print(link_soup.a.prettify(formatter=uppercase))
+ print(link_soup.a.prettify(formatter=formatter))
# <a href="HTTP://EXAMPLE.COM/?FOO=VAL1&BAR=VAL2">
# A LINK
# </a>
-If you're writing your own function, you should know about the
-``EntitySubstitution`` class in the ``bs4.dammit`` module. This class
-implements Beautiful Soup's standard formatters as class methods: the
-"html" formatter is ``EntitySubstitution.substitute_html``, and the
-"minimal" formatter is ``EntitySubstitution.substitute_xml``. You can
-use these functions to simulate ``formatter=html`` or
-``formatter==minimal``, but then do something extra.
-
-Here's an example that replaces Unicode characters with HTML entities
-whenever possible, but `also` converts all strings to uppercase::
-
- from bs4.dammit import EntitySubstitution
- def uppercase_and_substitute_html_entities(str):
- return EntitySubstitution.substitute_html(str.upper())
-
- print(soup.prettify(formatter=uppercase_and_substitute_html_entities))
- # <html>
- # <body>
- # <p>
- # IL A DIT <<SACRÉ BLEU!>>
- # </p>
- # </body>
- # </html>
+Subclassing ``HTMLFormatter`` or ``XMLFormatter`` will give you even
+more control over the output. For example, Beautiful Soup sorts the
+attributes in every tag by default::
+
+ attr_soup = BeautifulSoup(b'<p z="1" m="2" a="3"></p>')
+ print(attr_soup.p.encode())
+ # <p a="3" m="2" z="1"></p>
+
+To turn this off, you can subclass the ``Formatter.attributes()``
+method, which controls which attributes are output and in what
+order. This implementation also filters out out one of the attributes.
+
+ class UnsortedAttributes(HTMLFormatter):
+ def attributes(self, tag):
+ for k, v in tag.attrs.items():
+ if k == 'm':
+ continue
+ yield k, v
+ print(attr_soup.p.encode(formatter=UnsortedAttributes()))
+ # <p z="1" a="3"></p>
One last caveat: if you create a ``CData`` object, the text inside
that object is always presented `exactly as it appears, with no
@@ -3097,6 +3148,7 @@
* ``findPrevious`` -> ``find_previous``
* ``findPreviousSibling`` -> ``find_previous_sibling``
* ``findPreviousSiblings`` -> ``find_previous_siblings``
+* ``getText`` -> ``get_text``
* ``nextSibling`` -> ``next_sibling``
* ``previousSibling`` -> ``previous_sibling``
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/beautifulsoup4-4.7.1/setup.py new/beautifulsoup4-4.8.0/setup.py
--- old/beautifulsoup4-4.7.1/setup.py 2019-01-07 01:47:07.000000000 +0100
+++ new/beautifulsoup4-4.8.0/setup.py 2019-07-20 01:50:29.000000000 +0200
@@ -8,7 +8,7 @@
setup(
name="beautifulsoup4",
- version = "4.7.1",
+ version = "4.8.0",
author="Leonard Richardson",
author_email='leonardr(a)segfault.org',
url="http://www.crummy.com/software/BeautifulSoup/bs4/",
1
0