openSUSE Commits
Threads by month
- ----- 2024 -----
- September
- August
- 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
October 2017
- 1 participants
- 1963 discussions
Hello community,
here is the log from the commit of package lua-luadbi for openSUSE:Factory checked in at 2017-10-31 15:44:05
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/lua-luadbi (Old)
and /work/SRC/openSUSE:Factory/.lua-luadbi.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "lua-luadbi"
Tue Oct 31 15:44:05 2017 rev:2 rq:537623 version:0.5
Changes:
--------
--- /work/SRC/openSUSE:Factory/lua-luadbi/lua-luadbi.changes 2017-08-24 18:38:54.395430349 +0200
+++ /work/SRC/openSUSE:Factory/.lua-luadbi.new/lua-luadbi.changes 2017-10-31 15:44:05.849562056 +0100
@@ -1,0 +2,5 @@
+Mon Oct 30 14:45:32 UTC 2017 - jmatejek(a)suse.com
+
+- do not build for Lua 5.2
+
+-------------------------------------------------------------------
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ _multibuild ++++++
--- /var/tmp/diff_new_pack.MKynO7/_old 2017-10-31 15:44:06.429541032 +0100
+++ /var/tmp/diff_new_pack.MKynO7/_new 2017-10-31 15:44:06.433540887 +0100
@@ -1,5 +1,4 @@
<multibuild>
<package>lua51</package>
-<package>lua52</package>
<package>lua53</package>
</multibuild>
1
0
Hello community,
here is the log from the commit of package lua-lpeg for openSUSE:Factory checked in at 2017-10-31 15:44:04
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/lua-lpeg (Old)
and /work/SRC/openSUSE:Factory/.lua-lpeg.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "lua-lpeg"
Tue Oct 31 15:44:04 2017 rev:2 rq:537622 version:1.0.1
Changes:
--------
--- /work/SRC/openSUSE:Factory/lua-lpeg/lua-lpeg.changes 2017-08-24 18:39:32.542056265 +0200
+++ /work/SRC/openSUSE:Factory/.lua-lpeg.new/lua-lpeg.changes 2017-10-31 15:44:04.025628175 +0100
@@ -1,0 +2,5 @@
+Mon Oct 30 14:45:32 UTC 2017 - jmatejek(a)suse.com
+
+- do not build for Lua 5.2
+
+-------------------------------------------------------------------
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ _multibuild ++++++
--- /var/tmp/diff_new_pack.jBGLOQ/_old 2017-10-31 15:44:04.489611356 +0100
+++ /var/tmp/diff_new_pack.jBGLOQ/_new 2017-10-31 15:44:04.489611356 +0100
@@ -1,5 +1,4 @@
<multibuild>
<package>lua51</package>
-<package>lua52</package>
<package>lua53</package>
</multibuild>
1
0
Hello community,
here is the log from the commit of package lua-lgi for openSUSE:Factory checked in at 2017-10-31 15:44:02
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/lua-lgi (Old)
and /work/SRC/openSUSE:Factory/.lua-lgi.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "lua-lgi"
Tue Oct 31 15:44:02 2017 rev:6 rq:537621 version:0.9.1
Changes:
--------
--- /work/SRC/openSUSE:Factory/lua-lgi/lua-lgi.changes 2017-08-24 18:47:35.698005482 +0200
+++ /work/SRC/openSUSE:Factory/.lua-lgi.new/lua-lgi.changes 2017-10-31 15:44:02.493683709 +0100
@@ -1,0 +2,5 @@
+Mon Oct 30 14:45:32 UTC 2017 - jmatejek(a)suse.com
+
+- do not build for Lua 5.2
+
+-------------------------------------------------------------------
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ _multibuild ++++++
--- /var/tmp/diff_new_pack.CaAyGI/_old 2017-10-31 15:44:03.049663554 +0100
+++ /var/tmp/diff_new_pack.CaAyGI/_new 2017-10-31 15:44:03.053663410 +0100
@@ -1,5 +1,4 @@
<multibuild>
<package>lua51</package>
-<package>lua52</package>
<package>lua53</package>
</multibuild>
1
0
Hello community,
here is the log from the commit of package lua-ldbus for openSUSE:Factory checked in at 2017-10-31 15:44:00
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/lua-ldbus (Old)
and /work/SRC/openSUSE:Factory/.lua-ldbus.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "lua-ldbus"
Tue Oct 31 15:44:00 2017 rev:2 rq:537620 version:0.0+git20161023.e277e22
Changes:
--------
--- /work/SRC/openSUSE:Factory/lua-ldbus/lua-ldbus.changes 2017-08-24 18:54:38.846424161 +0200
+++ /work/SRC/openSUSE:Factory/.lua-ldbus.new/lua-ldbus.changes 2017-10-31 15:44:01.633714884 +0100
@@ -1,0 +2,5 @@
+Mon Oct 30 14:45:32 UTC 2017 - jmatejek(a)suse.com
+
+- do not build for Lua 5.2
+
+-------------------------------------------------------------------
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ lua-ldbus.spec ++++++
--- /var/tmp/diff_new_pack.c3Yjnh/_old 2017-10-31 15:44:02.325689799 +0100
+++ /var/tmp/diff_new_pack.c3Yjnh/_new 2017-10-31 15:44:02.333689509 +0100
@@ -25,8 +25,8 @@
Group: Development/Libraries/Other
Url: https://github.com/daurnimator/ldbus/
Source: lua-ldbus-%{version}.tar.xz
-BuildRequires: pkgconfig(dbus-1)
BuildRequires: %{flavor}-devel
+BuildRequires: pkgconfig(dbus-1)
Requires: %{flavor}
%if "%{flavor}" == "lua53"
Provides: lua-%{mod_name} = %{version}
++++++ _multibuild ++++++
--- /var/tmp/diff_new_pack.c3Yjnh/_old 2017-10-31 15:44:02.365688349 +0100
+++ /var/tmp/diff_new_pack.c3Yjnh/_new 2017-10-31 15:44:02.365688349 +0100
@@ -1,5 +1,4 @@
<multibuild>
<package>lua51</package>
-<package>lua52</package>
<package>lua53</package>
</multibuild>
1
0
Hello community,
here is the log from the commit of package lua-BitOp for openSUSE:Factory checked in at 2017-10-31 15:43:57
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/lua-BitOp (Old)
and /work/SRC/openSUSE:Factory/.lua-BitOp.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "lua-BitOp"
Tue Oct 31 15:43:57 2017 rev:3 rq:537619 version:1.0.2
Changes:
--------
--- /work/SRC/openSUSE:Factory/lua-BitOp/lua-BitOp.changes 2017-10-11 23:02:44.765241201 +0200
+++ /work/SRC/openSUSE:Factory/.lua-BitOp.new/lua-BitOp.changes 2017-10-31 15:43:59.029809277 +0100
@@ -1,0 +2,5 @@
+Mon Oct 30 14:45:32 UTC 2017 - jmatejek(a)suse.com
+
+- do not build for Lua 5.2
+
+-------------------------------------------------------------------
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ _multibuild ++++++
--- /var/tmp/diff_new_pack.y060eb/_old 2017-10-31 15:43:59.497792312 +0100
+++ /var/tmp/diff_new_pack.y060eb/_new 2017-10-31 15:43:59.497792312 +0100
@@ -1,4 +1,3 @@
<multibuild>
<package>lua51</package>
-<package>lua52</package>
</multibuild>
1
0
Hello community,
here is the log from the commit of package buzztrax for openSUSE:Factory checked in at 2017-10-31 15:43:56
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/buzztrax (Old)
and /work/SRC/openSUSE:Factory/.buzztrax.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "buzztrax"
Tue Oct 31 15:43:56 2017 rev:7 rq:537612 version:0.10.2
Changes:
--------
--- /work/SRC/openSUSE:Factory/buzztrax/buzztrax.changes 2017-04-06 11:02:37.815512721 +0200
+++ /work/SRC/openSUSE:Factory/.buzztrax.new/buzztrax.changes 2017-10-31 15:43:57.225874671 +0100
@@ -1,0 +2,5 @@
+Mon Oct 30 15:58:00 UTC 2017 - davejplater(a)gmail.com
+
+- Fixed spec generated baselibs.conf by adding libbuzztrax-gst.
+
+-------------------------------------------------------------------
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ buzztrax.spec ++++++
--- /var/tmp/diff_new_pack.LlYa1N/_old 2017-10-31 15:43:57.889850602 +0100
+++ /var/tmp/diff_new_pack.LlYa1N/_new 2017-10-31 15:43:57.897850312 +0100
@@ -245,8 +245,10 @@
ln -sf %{_datadir}/icons/hicolor/${icon} %{buildroot}%{_datadir}/icons/gnome/${icon}
done
%fdupes -s %{buildroot}
+# WARNING: this creates baselibs.conf
printf 'libbuzztrax-ic%{ic_soname}\n
libbuzztrax-core%{core_soname}\n
+libbuzztrax-gst%{gst_soname}\n
typelib-1_0-BuzztraxIc-1_1\n
\t+^%{typelibdir}/BuzztraxIc-%{girsoname}.typelib$\n
typelib-1_0-BuzztraxCore-1_1\n
1
0
Hello community,
here is the log from the commit of package obs-service-set_version for openSUSE:Factory checked in at 2017-10-31 15:43:53
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/obs-service-set_version (Old)
and /work/SRC/openSUSE:Factory/.obs-service-set_version.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "obs-service-set_version"
Tue Oct 31 15:43:53 2017 rev:30 rq:537602 version:0.5.7
Changes:
--------
--- /work/SRC/openSUSE:Factory/obs-service-set_version/obs-service-set_version.changes 2017-10-18 10:53:49.719452972 +0200
+++ /work/SRC/openSUSE:Factory/.obs-service-set_version.new/obs-service-set_version.changes 2017-10-31 15:43:55.821925566 +0100
@@ -1,0 +2,9 @@
+Mon Oct 30 15:59:17 UTC 2017 - adrian(a)suse.de
+
+- Update to version 0.5.7:
+ * workaround for python3 locale problems in factory
+ * add a hint to flake8
+ * satisfy flake8
+ * skip also sha256sums check for Arch
+
+-------------------------------------------------------------------
Old:
----
obs-service-set_version-0.5.6.tar.gz
New:
----
obs-service-set_version-0.5.7.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ obs-service-set_version.spec ++++++
--- /var/tmp/diff_new_pack.EB3wyf/_old 2017-10-31 15:43:56.433903381 +0100
+++ /var/tmp/diff_new_pack.EB3wyf/_new 2017-10-31 15:43:56.437903236 +0100
@@ -19,7 +19,7 @@
%define service set_version
Name: obs-service-%{service}
-Version: 0.5.6
+Version: 0.5.7
Release: 0
Summary: An OBS source service: Update spec file version
License: GPL-2.0+
++++++ PKGBUILD ++++++
--- /var/tmp/diff_new_pack.EB3wyf/_old 2017-10-31 15:43:56.473901931 +0100
+++ /var/tmp/diff_new_pack.EB3wyf/_new 2017-10-31 15:43:56.473901931 +0100
@@ -1,5 +1,5 @@
pkgname=obs-service-set_version
-pkgver=0.5.6
+pkgver=0.5.7
pkgrel=0
pkgdesc="An OBS source service: Update spec file version"
arch=('i686' 'x86_64')
++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.EB3wyf/_old 2017-10-31 15:43:56.509900626 +0100
+++ /var/tmp/diff_new_pack.EB3wyf/_new 2017-10-31 15:43:56.509900626 +0100
@@ -1,5 +1,5 @@
<servicedata>
<service name="tar_scm">
<param name="url">git@github.com:openSUSE/obs-service-set_version.git</param>
- <param name="changesrevision">586b879838fd9f362372736d2878862bced025e6</param></service>
+ <param name="changesrevision">b2bbe4efb4b4db45e21200eaa76b1c528fd62979</param></service>
</servicedata>
\ No newline at end of file
++++++ debian.dsc ++++++
--- /var/tmp/diff_new_pack.EB3wyf/_old 2017-10-31 15:43:56.529899901 +0100
+++ /var/tmp/diff_new_pack.EB3wyf/_new 2017-10-31 15:43:56.529899901 +0100
@@ -1,6 +1,6 @@
Format: 1.0
Source: obs-service-set_version
-Version: 0.5.6-0
+Version: 0.5.7-0
Binary: obs-service-set_version
Provides: obs-service-set_version
Maintainer: Adrian Schroeter <adrian(a)suse.de>
++++++ obs-service-set_version-0.5.6.tar.gz -> obs-service-set_version-0.5.7.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/obs-service-set_version-0.5.6/README.md new/obs-service-set_version-0.5.7/README.md
--- old/obs-service-set_version-0.5.6/README.md 2017-09-19 14:25:06.000000000 +0200
+++ new/obs-service-set_version-0.5.7/README.md 2017-10-30 16:57:46.000000000 +0100
@@ -24,4 +24,9 @@
python -m unittest discover tests/
-The testrun may take some time.
+The testrun may take some time. Don't forget to run also
+
+ flake8 set_version tests/
+
+
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/obs-service-set_version-0.5.6/set_version new/obs-service-set_version-0.5.7/set_version
--- old/obs-service-set_version-0.5.6/set_version 2017-09-19 14:25:06.000000000 +0200
+++ new/obs-service-set_version-0.5.7/set_version 2017-10-30 16:57:46.000000000 +0100
@@ -283,6 +283,12 @@
if __name__ == '__main__':
+
+ # may be a real fix or just a temporary workaround that python3 fails otherwise
+ # on non utf-8 chars in build env where "C" is default atm
+ import locale
+ locale.setlocale(locale.LC_CTYPE, 'C.UTF-8')
+
parser = argparse.ArgumentParser(
description='Open Build Service source service "set_version".'
'Used to update build description files with a '
@@ -372,5 +378,6 @@
filename = outdir + "/" + f
shutil.copyfile(f, filename)
_replace_tag(filename, "md5sums", "('SKIP')")
+ _replace_tag(filename, "sha256sums", "('SKIP')")
_replace_tag(filename, "pkgver", version)
_replace_tag(filename, "pkgrel", "0")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/obs-service-set_version-0.5.6/tests/test_pkgbuild.py new/obs-service-set_version-0.5.7/tests/test_pkgbuild.py
--- old/obs-service-set_version-0.5.6/tests/test_pkgbuild.py 2017-09-19 14:25:06.000000000 +0200
+++ new/obs-service-set_version-0.5.7/tests/test_pkgbuild.py 2017-10-30 16:57:46.000000000 +0100
@@ -42,8 +42,14 @@
def test_from_commandline(self, data):
old_version, new_version = data
pkgbuild_path = self._write_pkgbuild_file(
- "PKGBUILD", {"pkgver": old_version})
+ "PKGBUILD", {"pkgver": old_version,
+ "md5sums": "fail",
+ "sha256sums": "fail"})
self._run_set_version(params=['--version', new_version])
expected_str = "pkgver=%s" % (new_version)
self._check_file_assert_contains(pkgbuild_path, expected_str)
self._check_file_assert_not_contains(pkgbuild_path, old_version)
+ expected_str = "md5sums=('SKIP')"
+ self._check_file_assert_contains(pkgbuild_path, expected_str)
+ expected_str = "sha256sums=('SKIP')"
+ self._check_file_assert_contains(pkgbuild_path, expected_str)
1
0
Hello community,
here is the log from the commit of package iio-sensor-proxy for openSUSE:Factory checked in at 2017-10-31 15:43:50
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/iio-sensor-proxy (Old)
and /work/SRC/openSUSE:Factory/.iio-sensor-proxy.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "iio-sensor-proxy"
Tue Oct 31 15:43:50 2017 rev:10 rq:537538 version:2.3
Changes:
--------
--- /work/SRC/openSUSE:Factory/iio-sensor-proxy/iio-sensor-proxy.changes 2017-09-28 12:34:14.537198306 +0200
+++ /work/SRC/openSUSE:Factory/.iio-sensor-proxy.new/iio-sensor-proxy.changes 2017-10-31 15:43:51.766072593 +0100
@@ -1,0 +2,11 @@
+Sat Oct 28 16:26:56 UTC 2017 - badshah400(a)gmail.com
+
+- Add iio-sensor-proxy-revert-cast-align-warnings-arm-fix.patch
+ Revert "iio-buffer-utils: Fix cast-align warnings on ARM"
+ because it caused rotations on all devices to have undefined
+ values; patch taken from upstream (boo#1061190,
+ gh#hadess/iio-sensor-proxy#191).
+- Add relevant package Group for both iio-sensor-proxy
+ (System/Monitor) and iio-sensor-proxy-doc (Documentation/HTML).
+
+-------------------------------------------------------------------
New:
----
iio-sensor-proxy-revert-cast-align-warnings-arm-fix.patch
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ iio-sensor-proxy.spec ++++++
--- /var/tmp/diff_new_pack.1C1H5X/_old 2017-10-31 15:43:52.198056933 +0100
+++ /var/tmp/diff_new_pack.1C1H5X/_new 2017-10-31 15:43:52.202056788 +0100
@@ -21,12 +21,15 @@
Release: 0
Summary: Proxy for IIO and input subsystems
License: GPL-3.0
+Group: System/Monitoring
Url: https://github.com/hadess/iio-sensor-proxy
Source0: https://github.com/hadess/iio-sensor-proxy/releases/download/%{version}/%{n…
Source99: iio-sensor-proxy-rpmlintrc
# PATCH-FIX-UPSTREAM 0001-data-fix-permissions-when-geoclue-runs-with-a-differ.patch fcrozat(a)suse.com -- Ensure we handle geoclue not running as geoclue user
Patch0: 0001-data-fix-permissions-when-geoclue-runs-with-a-differ.patch
+# PATCH-FIX-UPSTREAM iio-sensor-proxy-revert-cast-align-warnings-arm-fix.patch boo#1061190 gh#hadess/iio-sensor-proxy#191 badshah400(a)opensuse.org -- Revert "iio-buffer-utils: Fix cast-align warnings on ARM" because it caused rotations on all devices to have undefined values.
# needed by patch0
+Patch1: iio-sensor-proxy-revert-cast-align-warnings-arm-fix.patch
BuildRequires: autoconf
BuildRequires: automake
BuildRequires: pkgconfig
@@ -44,6 +47,7 @@
%package doc
Summary: Documentation for %{name}
+Group: Documentation/HTML
BuildArch: noarch
%description doc
@@ -52,6 +56,7 @@
%prep
%setup -q
%patch0 -p1
+%patch1 -p1
%build
# needed by patch0
++++++ iio-sensor-proxy-revert-cast-align-warnings-arm-fix.patch ++++++
>From 70da85b8c31aa2db1e2471f5a0d62eb7589e454a Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess(a)hadess.net>
Date: Wed, 11 Oct 2017 18:22:31 +0200
Subject: [PATCH] Revert "iio-buffer-utils: Fix cast-align warnings on ARM"
This was causing unsigned buffer values to be read as signed.
This reverts commit ebc348abfea241d02861c09ce05ff759d65b77a0.
---
src/iio-buffer-utils.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/iio-buffer-utils.c b/src/iio-buffer-utils.c
index 9df8137..6482a25 100644
--- a/src/iio-buffer-utils.c
+++ b/src/iio-buffer-utils.c
@@ -493,14 +493,14 @@ process_scan_1 (char *data,
/* only a few cases implemented so far */
case 4:
if (!buffer_data->channels[k]->is_signed) {
- guint32 val = *(data + buffer_data->channels[k]->location);
+ guint32 val = *(guint32 *) (data + buffer_data->channels[k]->location);
val = val >> buffer_data->channels[k]->shift;
if (buffer_data->channels[k]->bits_used < 32)
val &= ((guint32) 1 << buffer_data->channels[k]->bits_used) - 1;
*ch_val = (int) val;
*ch_present = TRUE;
} else {
- gint32 val = *(data + buffer_data->channels[k]->location);
+ gint32 val = *(gint32 *) (data + buffer_data->channels[k]->location);
val = val >> buffer_data->channels[k]->shift;
if (buffer_data->channels[k]->bits_used < 32)
val &= ((guint32) 1 << buffer_data->channels[k]->bits_used) - 1;
1
0
Hello community,
here is the log from the commit of package python-plotly for openSUSE:Factory checked in at 2017-10-31 15:43:48
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-plotly (Old)
and /work/SRC/openSUSE:Factory/.python-plotly.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-plotly"
Tue Oct 31 15:43:48 2017 rev:4 rq:537520 version:2.2.1
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-plotly/python-plotly.changes 2017-10-17 01:53:15.952332750 +0200
+++ /work/SRC/openSUSE:Factory/.python-plotly.new/python-plotly.changes 2017-10-31 15:43:50.290126098 +0100
@@ -1,0 +2,12 @@
+Fri Oct 27 15:47:20 UTC 2017 - arun(a)gmx.de
+
+- update to version 2.2.1:
+ * presentation objects now added to setup.py
+
+- changes from version 2.2.0:
+ * Added
+ + NEW Presentations API for Python! Run
+ help(plotly.presentation_objs.Presentations) for help or check
+ out the new documentation
+
+-------------------------------------------------------------------
Old:
----
plotly-2.1.0.tar.gz
New:
----
plotly-2.2.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-plotly.spec ++++++
--- /var/tmp/diff_new_pack.2aaqlM/_old 2017-10-31 15:43:50.850105798 +0100
+++ /var/tmp/diff_new_pack.2aaqlM/_new 2017-10-31 15:43:50.850105798 +0100
@@ -18,7 +18,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-plotly
-Version: 2.1.0
+Version: 2.2.1
Release: 0
Summary: Library for collaborative, interactive, publication-quality graphs
License: MIT
++++++ plotly-2.1.0.tar.gz -> plotly-2.2.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/plotly-2.1.0/PKG-INFO new/plotly-2.2.1/PKG-INFO
--- old/plotly-2.1.0/PKG-INFO 2017-10-11 19:09:16.000000000 +0200
+++ new/plotly-2.2.1/PKG-INFO 2017-10-27 01:55:26.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: plotly
-Version: 2.1.0
+Version: 2.2.1
Summary: Python plotting library for collaborative, interactive, publication-quality graphs.
Home-page: https://plot.ly/python/
Author: Chris P
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/plotly-2.1.0/plotly/api/v2/__init__.py new/plotly-2.2.1/plotly/api/v2/__init__.py
--- old/plotly-2.1.0/plotly/api/v2/__init__.py 2017-05-09 20:13:16.000000000 +0200
+++ new/plotly-2.2.1/plotly/api/v2/__init__.py 2017-10-26 21:48:29.000000000 +0200
@@ -1,4 +1,5 @@
from __future__ import absolute_import
from plotly.api.v2 import (dash_apps, dashboards, files, folders, grids,
- images, plot_schema, plots, users)
+ images, plot_schema, plots, spectacle_presentations,
+ users)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/plotly-2.1.0/plotly/api/v2/spectacle_presentations.py new/plotly-2.2.1/plotly/api/v2/spectacle_presentations.py
--- old/plotly-2.1.0/plotly/api/v2/spectacle_presentations.py 1970-01-01 01:00:00.000000000 +0100
+++ new/plotly-2.2.1/plotly/api/v2/spectacle_presentations.py 2017-10-26 21:48:29.000000000 +0200
@@ -0,0 +1,32 @@
+"""
+Interface to Plotly's /v2/spectacle-presentations endpoint.
+"""
+from __future__ import absolute_import
+
+from plotly.api.v2.utils import build_url, request
+
+RESOURCE = 'spectacle-presentations'
+
+
+def create(body):
+ """Create a presentation."""
+ url = build_url(RESOURCE)
+ return request('post', url, json=body)
+
+
+def list():
+ """Returns the list of all users' presentations."""
+ url = build_url(RESOURCE)
+ return request('get', url)
+
+
+def retrieve(fid):
+ """Retrieve a presentation from Plotly."""
+ url = build_url(RESOURCE, id=fid)
+ return request('get', url)
+
+
+def update(fid, content):
+ """Completely update the writable."""
+ url = build_url(RESOURCE, id=fid)
+ return request('put', url, json=content)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/plotly-2.1.0/plotly/figure_factory/_scatterplot.py new/plotly-2.2.1/plotly/figure_factory/_scatterplot.py
--- old/plotly-2.1.0/plotly/figure_factory/_scatterplot.py 2017-07-26 14:04:02.000000000 +0200
+++ new/plotly-2.2.1/plotly/figure_factory/_scatterplot.py 2017-10-26 21:48:29.000000000 +0200
@@ -1,6 +1,6 @@
from __future__ import absolute_import
-from plotly import exceptions, optional_imports
+from plotly import colors, exceptions, optional_imports
from plotly.figure_factory import utils
from plotly.graph_objs import graph_objs
from plotly.tools import make_subplots
@@ -386,9 +386,9 @@
# Convert colormap to list of n RGB tuples
if colormap_type == 'seq':
- foo = utils.color_parser(colormap, utils.unlabel_rgb)
+ foo = colors.color_parser(colormap, colors.unlabel_rgb)
foo = utils.n_colors(foo[0], foo[1], n_colors_len)
- theme = utils.color_parser(foo, utils.label_rgb)
+ theme = colors.color_parser(foo, colors.label_rgb)
if colormap_type == 'cat':
# leave list of colors the same way
@@ -556,9 +556,9 @@
# Convert colormap to list of n RGB tuples
if colormap_type == 'seq':
- foo = utils.color_parser(colormap, utils.unlabel_rgb)
+ foo = colors.color_parser(colormap, colors.unlabel_rgb)
foo = utils.n_colors(foo[0], foo[1], len(intervals))
- theme = utils.color_parser(foo, utils.label_rgb)
+ theme = colors.color_parser(foo, colors.label_rgb)
if colormap_type == 'cat':
# leave list of colors the same way
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/plotly-2.1.0/plotly/graph_objs/graph_objs.py new/plotly-2.2.1/plotly/graph_objs/graph_objs.py
--- old/plotly-2.1.0/plotly/graph_objs/graph_objs.py 2017-10-11 19:07:35.000000000 +0200
+++ new/plotly-2.2.1/plotly/graph_objs/graph_objs.py 2017-10-25 00:03:32.000000000 +0200
@@ -113,7 +113,7 @@
pass
def validate(self):
- """Everything is *always* validated now. keep for backwards compat."""
+ """Everything is *always* validated now. Keep for backwards compat."""
pass
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/plotly-2.1.0/plotly/package_data/default-schema.json new/plotly-2.2.1/plotly/package_data/default-schema.json
--- old/plotly-2.1.0/plotly/package_data/default-schema.json 2017-10-11 19:07:35.000000000 +0200
+++ new/plotly-2.2.1/plotly/package_data/default-schema.json 2017-10-26 21:48:29.000000000 +0200
@@ -35081,6 +35081,7 @@
"role": "info",
"valType": "string"
},
+ "description": "",
"editType": "calc",
"family": {
"arrayOk": true,
@@ -35101,6 +35102,7 @@
"size": {
"arrayOk": true,
"editType": "calc",
+ "min": 1,
"role": "style",
"valType": "number"
},
@@ -35134,6 +35136,7 @@
"line": {
"color": {
"arrayOk": true,
+ "dflt": "grey",
"editType": "calc",
"role": "style",
"valType": "color"
@@ -35148,6 +35151,7 @@
"role": "object",
"width": {
"arrayOk": true,
+ "dflt": 1,
"editType": "calc",
"role": "style",
"valType": "number"
@@ -35216,7 +35220,7 @@
},
"columnwidth": {
"arrayOk": true,
- "description": "The width of cells.",
+ "description": "The width of columns expressed as a ratio. Columns fill the available width in proportion of their specified column widths.",
"dflt": null,
"editType": "calc",
"role": "style",
@@ -35345,6 +35349,7 @@
"role": "info",
"valType": "string"
},
+ "description": "",
"editType": "calc",
"family": {
"arrayOk": true,
@@ -35365,6 +35370,7 @@
"size": {
"arrayOk": true,
"editType": "calc",
+ "min": 1,
"role": "style",
"valType": "number"
},
@@ -35398,6 +35404,7 @@
"line": {
"color": {
"arrayOk": true,
+ "dflt": "grey",
"editType": "calc",
"role": "style",
"valType": "color"
@@ -35412,6 +35419,7 @@
"role": "object",
"width": {
"arrayOk": true,
+ "dflt": 1,
"editType": "calc",
"role": "style",
"valType": "number"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/plotly-2.1.0/plotly/plotly/__init__.py new/plotly-2.2.1/plotly/plotly/__init__.py
--- old/plotly-2.1.0/plotly/plotly/__init__.py 2017-05-09 20:13:16.000000000 +0200
+++ new/plotly-2.2.1/plotly/plotly/__init__.py 2017-10-26 21:48:29.000000000 +0200
@@ -24,6 +24,7 @@
get_config,
get_grid,
dashboard_ops,
+ presentation_ops,
create_animations,
icreate_animations
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/plotly-2.1.0/plotly/plotly/plotly.py new/plotly-2.2.1/plotly/plotly/plotly.py
--- old/plotly-2.1.0/plotly/plotly/plotly.py 2017-08-09 20:10:48.000000000 +0200
+++ new/plotly-2.2.1/plotly/plotly/plotly.py 2017-10-26 21:48:29.000000000 +0200
@@ -47,6 +47,11 @@
'sharing': files.FILE_CONTENT[files.CONFIG_FILE]['sharing']
}
+SHARING_ERROR_MSG = (
+ "Whoops, sharing can only be set to either 'public', 'private', or "
+ "'secret'."
+)
+
# test file permissions and make sure nothing is corrupted
tools.ensure_local_plotly_files()
@@ -1520,6 +1525,81 @@
return [str(dboard['filename']) for dboard in dashboards]
+class presentation_ops:
+ """
+ Interface to Plotly's Spectacle-Presentations API.
+ """
+ @classmethod
+ def upload(cls, presentation, filename, sharing='public', auto_open=True):
+ """
+ Function for uploading presentations to Plotly.
+
+ :param (dict) presentation: the JSON presentation to be uploaded. Use
+ plotly.presentation_objs.Presentation to create presentations
+ from a Markdown-like string.
+ :param (str) filename: the name of the presentation to be saved in
+ your Plotly account. Will overwrite a presentation of the same
+ name if it already exists in your files.
+ :param (str) sharing: can be set to either 'public', 'private'
+ or 'secret'. If 'public', your presentation will be viewable by
+ all other users. If 'private' only you can see your presentation.
+ If it is set to 'secret', the url will be returned with a string
+ of random characters appended to the url which is called a
+ sharekey. The point of a sharekey is that it makes the url very
+ hard to guess, but anyone with the url can view the presentation.
+ :param (bool) auto_open: automatically opens the presentation in the
+ browser.
+
+ See the documentation online for examples.
+ """
+ if sharing == 'public':
+ world_readable = True
+ elif sharing in ['private', 'secret']:
+ world_readable = False
+ else:
+ raise exceptions.PlotlyError(
+ SHARING_ERROR_MSG
+ )
+ data = {
+ 'content': json.dumps(presentation),
+ 'filename': filename,
+ 'world_readable': world_readable
+ }
+
+ # lookup if pre-existing filename already exists
+ try:
+ lookup_res = v2.files.lookup(filename)
+ lookup_res.raise_for_status()
+ matching_file = json.loads(lookup_res.content)
+
+ if matching_file['filetype'] != 'spectacle_presentation':
+ raise exceptions.PlotlyError(
+ "'{filename}' is already a {filetype} in your account. "
+ "You can't overwrite a file that is not a spectacle_"
+ "presentation. Please pick another filename.".format(
+ filename=filename,
+ filetype=matching_file['filetype']
+ )
+ )
+ else:
+ old_fid = matching_file['fid']
+ res = v2.spectacle_presentations.update(old_fid, data)
+
+ except exceptions.PlotlyRequestError:
+ res = v2.spectacle_presentations.create(data)
+ res.raise_for_status()
+
+ url = res.json()['web_url']
+
+ if sharing == 'secret':
+ url = add_share_key_to_url(url)
+
+ if auto_open:
+ webbrowser.open_new(res.json()['web_url'])
+
+ return url
+
+
def create_animations(figure, filename=None, sharing='public', auto_open=True):
"""
BETA function that creates plots with animations via `frames`.
@@ -1712,8 +1792,7 @@
body['share_key_enabled'] = True
else:
raise exceptions.PlotlyError(
- "Whoops, sharing can only be set to either 'public', 'private', "
- "or 'secret'."
+ SHARING_ERROR_MSG
)
response = v2.plots.create(body)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/plotly-2.1.0/plotly/presentation_objs/__init__.py new/plotly-2.2.1/plotly/presentation_objs/__init__.py
--- old/plotly-2.1.0/plotly/presentation_objs/__init__.py 1970-01-01 01:00:00.000000000 +0100
+++ new/plotly-2.2.1/plotly/presentation_objs/__init__.py 2017-10-26 21:48:29.000000000 +0200
@@ -0,0 +1,8 @@
+"""
+presentation_objs
+
+A wrapper for the spectacle-presentations endpoint.
+===========
+
+"""
+from . presentation_objs import Presentation
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/plotly-2.1.0/plotly/presentation_objs/presentation_objs.py new/plotly-2.2.1/plotly/presentation_objs/presentation_objs.py
--- old/plotly-2.1.0/plotly/presentation_objs/presentation_objs.py 1970-01-01 01:00:00.000000000 +0100
+++ new/plotly-2.2.1/plotly/presentation_objs/presentation_objs.py 2017-10-27 01:54:28.000000000 +0200
@@ -0,0 +1,1176 @@
+"""
+dashboard_objs
+==========
+
+A module for creating and manipulating spectacle-presentation dashboards.
+"""
+
+import copy
+import random
+import re
+import string
+import warnings
+
+from plotly import exceptions
+from plotly.config import get_config
+
+HEIGHT = 700.0
+WIDTH = 1000.0
+
+CODEPANE_THEMES = ['tomorrow', 'tomorrowNight']
+
+VALID_LANGUAGES = ['cpp', 'cs', 'css', 'fsharp', 'go', 'haskell', 'java',
+ 'javascript', 'jsx', 'julia', 'xml', 'matlab', 'php',
+ 'python', 'r', 'ruby', 'scala', 'sql', 'yaml']
+
+VALID_TRANSITIONS = ['slide', 'zoom', 'fade', 'spin']
+
+PRES_THEMES = ['moods', 'martik']
+
+VALID_GROUPTYPES = [
+ 'leftgroup_v', 'rightgroup_v', 'middle', 'checkerboard_topleft',
+ 'checkerboard_topright'
+]
+
+fontWeight_dict = {
+ 'Thin': {'fontWeight': 100},
+ 'Thin Italic': {'fontWeight': 100, 'fontStyle': 'italic'},
+ 'Light': {'fontWeight': 300},
+ 'Light Italic': {'fontWeight': 300, 'fontStyle': 'italic'},
+ 'Regular': {'fontWeight': 400},
+ 'Regular Italic': {'fontWeight': 400, 'fontStyle': 'italic'},
+ 'Medium': {'fontWeight': 500},
+ 'Medium Italic': {'fontWeight': 500, 'fontStyle': 'italic'},
+ 'Bold': {'fontWeight': 700},
+ 'Bold Italic': {'fontWeight': 700, 'fontStyle': 'italic'},
+ 'Black': {'fontWeight': 900},
+ 'Black Italic': {'fontWeight': 900, 'fontStyle': 'italic'},
+}
+
+
+def list_of_options(iterable, conj='and', period=True):
+ """
+ Returns an English listing of objects seperated by commas ','
+
+ For example, ['foo', 'bar', 'baz'] becomes 'foo, bar and baz'
+ if the conjunction 'and' is selected.
+ """
+ if len(iterable) < 2:
+ raise exceptions.PlotlyError(
+ 'Your list or tuple must contain at least 2 items.'
+ )
+ template = (len(iterable) - 2)*'{}, ' + '{} ' + conj + ' {}' + period*'.'
+ return template.format(*iterable)
+
+
+# Error Messages
+STYLE_ERROR = "Your presentation style must be {}".format(
+ list_of_options(PRES_THEMES, conj='or', period=True)
+)
+
+CODE_ENV_ERROR = (
+ "If you are putting a block of code into your markdown "
+ "presentation, make sure your denote the start and end "
+ "of the code environment with the '```' characters. For "
+ "example, your markdown string would include something "
+ "like:\n\n```python\nx = 2\ny = 1\nprint x\n```\n\n"
+ "Notice how the language that you want the code to be "
+ "displayed in is immediately to the right of first "
+ "entering '```', i.e. '```python'."
+)
+
+LANG_ERROR = (
+ "The language of your code block should be "
+ "clearly indicated after the first ``` that "
+ "begins the code block. The valid languages to "
+ "choose from are" + list_of_options(
+ VALID_LANGUAGES
+ )
+)
+
+
+def _generate_id(size):
+ letters_and_numbers = string.ascii_letters
+ for num in range(10):
+ letters_and_numbers += str(num)
+ letters_and_numbers += str(num)
+ id_str = ''
+ for _ in range(size):
+ id_str += random.choice(list(letters_and_numbers))
+
+ return id_str
+
+
+paragraph_styles = {
+ 'Body': {
+ 'color': '#3d3d3d',
+ 'fontFamily': 'Open Sans',
+ 'fontSize': 11,
+ 'fontStyle': 'normal',
+ 'fontWeight': 400,
+ 'lineHeight': 'normal',
+ 'minWidth': 20,
+ 'opacity': 1,
+ 'textAlign': 'center',
+ 'textDecoration': 'none',
+ 'wordBreak': 'break-word'
+ },
+ 'Body Small': {
+ 'color': '#3d3d3d',
+ 'fontFamily': 'Open Sans',
+ 'fontSize': 10,
+ 'fontStyle': 'normal',
+ 'fontWeight': 400,
+ 'lineHeight': 'normal',
+ 'minWidth': 20,
+ 'opacity': 1,
+ 'textAlign': 'center',
+ 'textDecoration': 'none'
+ },
+ 'Caption': {
+ 'color': '#3d3d3d',
+ 'fontFamily': 'Open Sans',
+ 'fontSize': 11,
+ 'fontStyle': 'italic',
+ 'fontWeight': 400,
+ 'lineHeight': 'normal',
+ 'minWidth': 20,
+ 'opacity': 1,
+ 'textAlign': 'center',
+ 'textDecoration': 'none'
+ },
+ 'Heading 1': {
+ 'color': '#3d3d3d',
+ 'fontFamily': 'Open Sans',
+ 'fontSize': 26,
+ 'fontStyle': 'normal',
+ 'fontWeight': 400,
+ 'lineHeight': 'normal',
+ 'minWidth': 20,
+ 'opacity': 1,
+ 'textAlign': 'center',
+ 'textDecoration': 'none',
+ },
+ 'Heading 2': {
+ 'color': '#3d3d3d',
+ 'fontFamily': 'Open Sans',
+ 'fontSize': 20,
+ 'fontStyle': 'normal',
+ 'fontWeight': 400,
+ 'lineHeight': 'normal',
+ 'minWidth': 20,
+ 'opacity': 1,
+ 'textAlign': 'center',
+ 'textDecoration': 'none'
+ },
+ 'Heading 3': {
+ 'color': '#3d3d3d',
+ 'fontFamily': 'Open Sans',
+ 'fontSize': 11,
+ 'fontStyle': 'normal',
+ 'fontWeight': 700,
+ 'lineHeight': 'normal',
+ 'minWidth': 20,
+ 'opacity': 1,
+ 'textAlign': 'center',
+ 'textDecoration': 'none'
+ }
+}
+
+
+def _empty_slide(transition, id):
+ empty_slide = {'children': [],
+ 'id': id,
+ 'props': {'style': {}, 'transition': transition}}
+ return empty_slide
+
+
+def _box(boxtype, text_or_url, left, top, height, width, id, props_attr,
+ style_attr, paragraphStyle):
+ children_list = []
+ fontFamily = "Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace"
+ if boxtype == 'Text':
+ children_list = text_or_url.split('\n')
+
+ props = {
+ 'isQuote': False,
+ 'listType': None,
+ 'paragraphStyle': paragraphStyle,
+ 'size': 4,
+ 'style': copy.deepcopy(paragraph_styles[paragraphStyle])
+ }
+
+ props['style'].update(
+ {'height': height,
+ 'left': left,
+ 'top': top,
+ 'width': width,
+ 'position': 'absolute'}
+ )
+
+ elif boxtype == 'Image':
+ # height, width are set to default 512
+ # as set by the Presentation Editor
+ props = {
+ 'height': 512,
+ 'imageName': None,
+ 'src': text_or_url,
+ 'style': {'height': height,
+ 'left': left,
+ 'opacity': 1,
+ 'position': 'absolute',
+ 'top': top,
+ 'width': width},
+ 'width': 512
+ }
+ elif boxtype == 'Plotly':
+ if '?share_key' in text_or_url:
+ src = text_or_url
+ else:
+ src = text_or_url + '.embed?link=false'
+ props = {
+ 'frameBorder': 0,
+ 'scrolling': 'no',
+ 'src': src,
+ 'style': {'height': height,
+ 'left': left,
+ 'position': 'absolute',
+ 'top': top,
+ 'width': width}
+ }
+ elif boxtype == 'CodePane':
+ props = {
+ 'language': 'python',
+ 'source': text_or_url,
+ 'style': {'fontFamily': fontFamily,
+ 'fontSize': 13,
+ 'height': height,
+ 'left': left,
+ 'margin': 0,
+ 'position': 'absolute',
+ 'textAlign': 'left',
+ 'top': top,
+ 'width': width},
+ 'theme': 'tomorrowNight'
+ }
+
+ # update props and style attributes
+ for item in props_attr.items():
+ props[item[0]] = item[1]
+ for item in style_attr.items():
+ props['style'][item[0]] = item[1]
+
+ child = {
+ 'children': children_list,
+ 'id': id,
+ 'props': props,
+ 'type': boxtype
+ }
+
+ if boxtype == 'Text':
+ child['defaultHeight'] = 36
+ child['defaultWidth'] = 52
+ child['resizeVertical'] = False
+ if boxtype == 'CodePane':
+ child['defaultText'] = 'Code'
+
+ return child
+
+
+def _percentage_to_pixel(value, side):
+ if side == 'left':
+ return WIDTH * (0.01 * value)
+ elif side == 'top':
+ return HEIGHT * (0.01 * value)
+ elif side == 'height':
+ return HEIGHT * (0.01 * value)
+ elif side == 'width':
+ return WIDTH * (0.01 * value)
+
+
+def _return_box_position(left, top, height, width):
+ values_dict = {
+ 'left': left,
+ 'top': top,
+ 'height': height,
+ 'width': width,
+ }
+ for key in iter(values_dict):
+ if isinstance(values_dict[key], str):
+ var = float(values_dict[key][: -2])
+ else:
+ var = _percentage_to_pixel(values_dict[key], key)
+ values_dict[key] = var
+
+ return (values_dict['left'], values_dict['top'],
+ values_dict['height'], values_dict['width'])
+
+
+def _remove_extra_whitespace_from_line(line):
+ line = line.lstrip()
+ line = line.rstrip()
+ return line
+
+
+def _list_of_slides(markdown_string):
+ if not markdown_string.endswith('\n---\n'):
+ markdown_string += '\n---\n'
+
+ text_blocks = re.split('\n-{2,}\n', markdown_string)
+
+ list_of_slides = []
+ for text in text_blocks:
+ if not all(char in ['\n', '-', ' '] for char in text):
+ list_of_slides.append(text)
+
+ if '\n-\n' in markdown_string:
+ msg = ("You have at least one '-' by itself on its own line in your "
+ "markdown string. If you are trying to denote a new slide, "
+ "make sure that the line has 3 '-'s like this: \n\n---\n\n"
+ "A new slide will NOT be created here.")
+ warnings.warn(msg)
+
+ return list_of_slides
+
+
+def _top_spec_for_text_at_bottom(text_block, width_per, per_from_bottom=0,
+ min_top=30):
+ # This function ensures that if there is a large block of
+ # text in your slide it will not overflow off the bottom
+ # of the slide.
+ # The input for this function are a block of text and the
+ # params that define where it will be placed in the slide.
+ # The function makes some calculations and will output a
+ # 'top' value (i.e. the left, top, height, width css params)
+ # so that the text block will come down to some specified
+ # distance from the bottom of the page.
+
+ # TODO: customize this function for different fonts/sizes
+ max_lines = 37
+ one_char_percent_width = 0.764
+ chars_in_full_line = width_per / one_char_percent_width
+
+ num_of_lines = 0
+ char_group = 0
+ for char in text_block:
+ if char == '\n':
+ num_of_lines += 1
+ char_group = 0
+ else:
+ if char_group >= chars_in_full_line:
+ char_group = 0
+ num_of_lines += 1
+ else:
+ char_group += 1
+
+ num_of_lines += 1
+ top_frac = (max_lines - num_of_lines) / float(max_lines)
+ top = top_frac * 100 - per_from_bottom
+
+ # to be safe
+ return max(top, min_top)
+
+
+def _box_specs_gen(num_of_boxes, grouptype='leftgroup_v', width_range=50,
+ height_range=50, margin=2, betw_boxes=4, middle_center=50):
+ # the (left, top, width, height) specs
+ # are added to specs_for_boxes
+ specs_for_boxes = []
+ if num_of_boxes == 1 and grouptype in ['leftgroup_v', 'rightgroup_v']:
+ if grouptype == 'rightgroup_v':
+ left_shift = (100 - width_range)
+ else:
+ left_shift = 0
+
+ box_spec = (
+ left_shift + (margin / WIDTH) * 100,
+ (margin / HEIGHT) * 100,
+ 100 - (2 * margin / HEIGHT * 100),
+ width_range - (2 * margin / WIDTH) * 100
+ )
+ specs_for_boxes.append(box_spec)
+
+ elif num_of_boxes > 1 and grouptype in ['leftgroup_v', 'rightgroup_v']:
+ if grouptype == 'rightgroup_v':
+ left_shift = (100 - width_range)
+ else:
+ left_shift = 0
+
+ if num_of_boxes % 2 == 0:
+ box_width_px = 0.5 * (
+ (float(width_range)/100) * WIDTH - 2 * margin - betw_boxes
+ )
+ box_width = (box_width_px / WIDTH) * 100
+
+ height = (200.0 / (num_of_boxes * HEIGHT)) * (
+ HEIGHT - (num_of_boxes / 2 - 1) * betw_boxes - 2 * margin
+ )
+
+ left1 = left_shift + (margin / WIDTH) * 100
+ left2 = left_shift + (
+ ((margin + betw_boxes) / WIDTH) * 100 + box_width
+ )
+ for left in [left1, left2]:
+ for j in range(int(num_of_boxes / 2)):
+ top = (margin * 100 / HEIGHT) + j * (
+ height + (betw_boxes * 100 / HEIGHT)
+ )
+ specs = (
+ left,
+ top,
+ height,
+ box_width
+ )
+ specs_for_boxes.append(specs)
+
+ if num_of_boxes % 2 == 1:
+ width = width_range - (200 * margin) / WIDTH
+ height = (100.0 / (num_of_boxes * HEIGHT)) * (
+ HEIGHT - (num_of_boxes - 1) * betw_boxes - 2 * margin
+ )
+ left = left_shift + (margin / WIDTH) * 100
+ for j in range(num_of_boxes):
+ top = (margin / HEIGHT) * 100 + j * (
+ height + (betw_boxes / HEIGHT) * 100
+ )
+ specs = (
+ left,
+ top,
+ height,
+ width
+ )
+ specs_for_boxes.append(specs)
+
+ elif grouptype == 'middle':
+ top = float(middle_center - (height_range / 2))
+ height = height_range
+ width = (1 / float(num_of_boxes)) * (
+ width_range - (num_of_boxes - 1) * (100*betw_boxes/WIDTH)
+ )
+ for j in range(num_of_boxes):
+ left = ((100 - float(width_range)) / 2) + j * (
+ width + (betw_boxes / WIDTH) * 100
+ )
+ specs = (left, top, height, width)
+ specs_for_boxes.append(specs)
+
+ elif 'checkerboard' in grouptype and num_of_boxes == 2:
+ if grouptype == 'checkerboard_topleft':
+ for j in range(2):
+ left = j * 50
+ top = j * 50
+ height = 50
+ width = 50
+ specs = (
+ left,
+ top,
+ height,
+ width
+ )
+ specs_for_boxes.append(specs)
+ else:
+ for j in range(2):
+ left = 50 * (1 - j)
+ top = j * 50
+ height = 50
+ width = 50
+ specs = (
+ left,
+ top,
+ height,
+ width
+ )
+ specs_for_boxes.append(specs)
+ return specs_for_boxes
+
+
+def _return_layout_specs(num_of_boxes, url_lines, title_lines, text_block,
+ code_blocks, slide_num, style):
+ # returns specs of the form (left, top, height, width)
+ code_theme = 'tomorrowNight'
+ if style == 'martik':
+ specs_for_boxes = []
+ margin = 18 # in pxs
+
+ # set Headings styles
+ paragraph_styles['Heading 1'].update(
+ {'color': '#0D0A1E',
+ 'fontFamily': 'Raleway',
+ 'fontSize': 55,
+ 'fontWeight': fontWeight_dict['Bold']['fontWeight']}
+ )
+
+ paragraph_styles['Heading 2'] = copy.deepcopy(
+ paragraph_styles['Heading 1']
+ )
+ paragraph_styles['Heading 2'].update({'fontSize': 36})
+ paragraph_styles['Heading 3'] = copy.deepcopy(
+ paragraph_styles['Heading 1']
+ )
+ paragraph_styles['Heading 3'].update({'fontSize': 30})
+
+ # set Body style
+ paragraph_styles['Body'].update(
+ {'color': '#96969C',
+ 'fontFamily': 'Roboto',
+ 'fontSize': 16,
+ 'fontWeight': fontWeight_dict['Regular']['fontWeight']}
+ )
+
+ bkgd_color = '#F4FAFB'
+ title_font_color = '#0D0A1E'
+ text_font_color = '#96969C'
+ if num_of_boxes == 0 and slide_num == 0:
+ text_textAlign = 'center'
+ else:
+ text_textAlign = 'left'
+ if num_of_boxes == 0:
+ specs_for_title = (0, 50, 20, 100)
+ specs_for_text = (15, 60, 50, 70)
+
+ bkgd_color = '#0D0A1E'
+ title_font_color = '#F4FAFB'
+ text_font_color = '#F4FAFB'
+ elif num_of_boxes == 1:
+ if code_blocks != [] or (url_lines != [] and
+ get_config()['plotly_domain'] in
+ url_lines[0]):
+ if code_blocks != []:
+ w_range = 40
+ else:
+ w_range = 60
+ text_top = _top_spec_for_text_at_bottom(
+ text_block, 80,
+ per_from_bottom=(margin / HEIGHT) * 100
+ )
+ specs_for_title = (0, 3, 20, 100)
+ specs_for_text = (10, text_top, 30, 80)
+ specs_for_boxes = _box_specs_gen(
+ num_of_boxes, grouptype='middle', width_range=w_range,
+ height_range=60, margin=margin, betw_boxes=4
+ )
+ bkgd_color = '#0D0A1E'
+ title_font_color = '#F4FAFB'
+ text_font_color = '#F4FAFB'
+ code_theme = 'tomorrow'
+ elif title_lines == [] and text_block == '':
+ specs_for_title = (0, 50, 20, 100)
+ specs_for_text = (15, 60, 50, 70)
+ specs_for_boxes = _box_specs_gen(
+ num_of_boxes, grouptype='middle', width_range=50,
+ height_range=80, margin=0, betw_boxes=0
+ )
+ else:
+ title_text_width = 40 - (margin / WIDTH) * 100
+
+ text_top = _top_spec_for_text_at_bottom(
+ text_block, title_text_width,
+ per_from_bottom=(margin / HEIGHT) * 100
+ )
+ specs_for_title = (60, 3, 20, 40)
+ specs_for_text = (60, text_top, 1, title_text_width)
+ specs_for_boxes = _box_specs_gen(
+ num_of_boxes, grouptype='leftgroup_v', width_range=60,
+ margin=margin, betw_boxes=4
+ )
+ bkgd_color = '#0D0A1E'
+ title_font_color = '#F4FAFB'
+ text_font_color = '#F4FAFB'
+ elif num_of_boxes == 2 and url_lines != []:
+ text_top = _top_spec_for_text_at_bottom(
+ text_block, 46, per_from_bottom=(margin / HEIGHT) * 100,
+ min_top=50
+ )
+ specs_for_title = (0, 3, 20, 50)
+ specs_for_text = (52, text_top, 40, 46)
+ specs_for_boxes = _box_specs_gen(
+ num_of_boxes, grouptype='checkerboard_topright'
+ )
+ elif num_of_boxes >= 2 and url_lines == []:
+ text_top = _top_spec_for_text_at_bottom(
+ text_block, 92, per_from_bottom=(margin / HEIGHT) * 100,
+ min_top=15
+ )
+ if num_of_boxes == 2:
+ betw_boxes = 90
+ else:
+ betw_boxes = 10
+ specs_for_title = (0, 3, 20, 100)
+ specs_for_text = (4, text_top, 1, 92)
+ specs_for_boxes = _box_specs_gen(
+ num_of_boxes, grouptype='middle', width_range=92,
+ height_range=60, margin=margin, betw_boxes=betw_boxes
+ )
+ code_theme = 'tomorrow'
+ else:
+ text_top = _top_spec_for_text_at_bottom(
+ text_block, 40 - (margin / WIDTH) * 100,
+ per_from_bottom=(margin / HEIGHT) * 100
+ )
+ specs_for_title = (0, 3, 20, 40 - (margin / WIDTH) * 100)
+ specs_for_text = (
+ (margin / WIDTH) * 100, text_top, 50,
+ 40 - (margin / WIDTH) * 100
+ )
+ specs_for_boxes = _box_specs_gen(
+ num_of_boxes, grouptype='rightgroup_v', width_range=60,
+ margin=margin, betw_boxes=4
+ )
+
+ elif style == 'moods':
+ specs_for_boxes = []
+ margin = 18
+ code_theme = 'tomorrowNight'
+
+ # set Headings styles
+ paragraph_styles['Heading 1'].update(
+ {'color': '#000016',
+ 'fontFamily': 'Roboto',
+ 'fontSize': 55,
+ 'fontWeight': fontWeight_dict['Black']['fontWeight']}
+ )
+
+ paragraph_styles['Heading 2'] = copy.deepcopy(
+ paragraph_styles['Heading 1']
+ )
+ paragraph_styles['Heading 2'].update({'fontSize': 36})
+ paragraph_styles['Heading 3'] = copy.deepcopy(
+ paragraph_styles['Heading 1']
+ )
+ paragraph_styles['Heading 3'].update({'fontSize': 30})
+
+ # set Body style
+ paragraph_styles['Body'].update(
+ {'color': '#000016',
+ 'fontFamily': 'Roboto',
+ 'fontSize': 16,
+ 'fontWeight': fontWeight_dict['Thin']['fontWeight']}
+ )
+
+ bkgd_color = '#FFFFFF'
+ title_font_color = None
+ text_font_color = None
+ if num_of_boxes == 0 and slide_num == 0:
+ text_textAlign = 'center'
+ else:
+ text_textAlign = 'left'
+ if num_of_boxes == 0:
+ if slide_num == 0 or text_block == '':
+ bkgd_color = '#F7F7F7'
+ specs_for_title = (0, 50, 20, 100)
+ specs_for_text = (15, 60, 50, 70)
+ else:
+ bkgd_color = '#F7F7F7'
+ text_top = _top_spec_for_text_at_bottom(
+ text_block, width_per=90,
+ per_from_bottom=(margin / HEIGHT) * 100,
+ min_top=20
+ )
+ specs_for_title = (0, 2, 20, 100)
+ specs_for_text = (5, text_top, 50, 90)
+
+ elif num_of_boxes == 1:
+ if code_blocks != []:
+ # code
+ if text_block == '':
+ margin = 5
+ specs_for_title = (0, 3, 20, 100)
+ specs_for_text = (0, 0, 0, 0)
+ top = 12
+ specs_for_boxes = [
+ (margin, top, 100 - top - margin, 100 - 2 * margin)
+ ]
+
+ elif slide_num % 2 == 0:
+ # middle center
+ width_per = 90
+ height_range = 60
+ text_top = _top_spec_for_text_at_bottom(
+ text_block, width_per=width_per,
+ per_from_bottom=(margin / HEIGHT) * 100,
+ min_top=100 - height_range / 2.
+ )
+ specs_for_boxes = _box_specs_gen(
+ num_of_boxes, grouptype='middle',
+ width_range=50, height_range=60, margin=margin,
+ )
+ specs_for_title = (0, 3, 20, 100)
+ specs_for_text = (
+ 5, text_top, 2, width_per
+ )
+ else:
+ # right
+ width_per = 50
+ text_top = _top_spec_for_text_at_bottom(
+ text_block, width_per=width_per,
+ per_from_bottom=(margin / HEIGHT) * 100,
+ min_top=30
+ )
+ specs_for_boxes = _box_specs_gen(
+ num_of_boxes, grouptype='rightgroup_v',
+ width_range=50, margin=40,
+ )
+ specs_for_title = (0, 3, 20, 50)
+ specs_for_text = (
+ 2, text_top, 2, width_per - 2
+ )
+ elif (url_lines != [] and
+ get_config()['plotly_domain'] in url_lines[0]):
+ # url
+ if slide_num % 2 == 0:
+ # top half
+ width_per = 95
+ text_top = _top_spec_for_text_at_bottom(
+ text_block, width_per=width_per,
+ per_from_bottom=(margin / HEIGHT) * 100,
+ min_top=60
+ )
+ specs_for_boxes = _box_specs_gen(
+ num_of_boxes, grouptype='middle',
+ width_range=100, height_range=60,
+ middle_center=30
+ )
+ specs_for_title = (0, 60, 20, 100)
+ specs_for_text = (
+ 2.5, text_top, 2, width_per
+ )
+ else:
+ # middle across
+ width_per = 95
+ text_top = _top_spec_for_text_at_bottom(
+ text_block, width_per=width_per,
+ per_from_bottom=(margin / HEIGHT) * 100,
+ min_top=60
+ )
+ specs_for_boxes = _box_specs_gen(
+ num_of_boxes, grouptype='middle',
+ width_range=100, height_range=60
+ )
+ specs_for_title = (0, 3, 20, 100)
+ specs_for_text = (
+ 2.5, text_top, 2, width_per
+ )
+ else:
+ # image
+ if slide_num % 2 == 0:
+ # right
+ width_per = 50
+ text_top = _top_spec_for_text_at_bottom(
+ text_block, width_per=width_per,
+ per_from_bottom=(margin / HEIGHT) * 100,
+ min_top=30
+ )
+ specs_for_boxes = _box_specs_gen(
+ num_of_boxes, grouptype='rightgroup_v',
+ width_range=50, margin=0,
+ )
+ specs_for_title = (0, 3, 20, 50)
+ specs_for_text = (
+ 2, text_top, 2, width_per - 2
+ )
+ else:
+ # left
+ width_per = 50
+ text_top = _top_spec_for_text_at_bottom(
+ text_block, width_per=width_per,
+ per_from_bottom=(margin / HEIGHT) * 100,
+ min_top=30
+ )
+ specs_for_boxes = _box_specs_gen(
+ num_of_boxes, grouptype='leftgroup_v',
+ width_range=50, margin=0,
+ )
+ specs_for_title = (50, 3, 20, 50)
+ specs_for_text = (
+ 52, text_top, 2, width_per - 2
+ )
+ elif num_of_boxes == 2:
+ # right stack
+ width_per = 50
+ text_top = _top_spec_for_text_at_bottom(
+ text_block, width_per=width_per,
+ per_from_bottom=(margin / HEIGHT) * 100,
+ min_top=30
+ )
+ specs_for_boxes = [(50, 0, 50, 50), (50, 50, 50, 50)]
+ specs_for_title = (0, 3, 20, 50)
+ specs_for_text = (
+ 2, text_top, 2, width_per - 2
+ )
+ elif num_of_boxes == 3:
+ # middle top
+ width_per = 95
+ text_top = _top_spec_for_text_at_bottom(
+ text_block, width_per=width_per,
+ per_from_bottom=(margin / HEIGHT) * 100,
+ min_top=40
+ )
+ specs_for_boxes = _box_specs_gen(
+ num_of_boxes, grouptype='middle',
+ width_range=100, height_range=40, middle_center=30
+ )
+ specs_for_title = (0, 0, 20, 100)
+ specs_for_text = (
+ 2.5, text_top, 2, width_per
+ )
+ else:
+ # right stack
+ width_per = 40
+ text_top = _top_spec_for_text_at_bottom(
+ text_block, width_per=width_per,
+ per_from_bottom=(margin / HEIGHT) * 100,
+ min_top=30
+ )
+ specs_for_boxes = _box_specs_gen(
+ num_of_boxes, grouptype='rightgroup_v',
+ width_range=60, margin=0,
+ )
+ specs_for_title = (0, 3, 20, 40)
+ specs_for_text = (
+ 2, text_top, 2, width_per - 2
+ )
+
+ # set text style attributes
+ title_style_attr = {}
+ text_style_attr = {'textAlign': text_textAlign}
+
+ if text_font_color:
+ text_style_attr['color'] = text_font_color
+ if title_font_color:
+ title_style_attr['color'] = title_font_color
+
+ return (specs_for_boxes, specs_for_title, specs_for_text, bkgd_color,
+ title_style_attr, text_style_attr, code_theme)
+
+
+def _url_parens_contained(url_name, line):
+ return line.startswith(url_name + '(') and line.endswith(')')
+
+
+class Presentation(dict):
+ """
+ The Presentation class for creating spectacle-presentations.
+
+ The Presentations API is a means for creating JSON blobs which are then
+ converted Spectacle Presentations. To use the API you only need to define
+ a block string and define your slides using markdown. Then you can upload
+ your presentation to the Plotly Server.
+
+ Rules for your presentation string:
+ - use '---' to denote a slide break.
+ - headers work as per usual, where if '#' is used before a line of text
+ then it is interpretted as a header. Only the first header in a slide is
+ displayed on the slide. There are only 3 heading sizes: #, ## and ###.
+ 4 or more hashes will be interpretted as ###.
+ - you can set the type of slide transition you want by writing a line that
+ starts with 'transition: ' before your first header line in the slide,
+ and write the types of transition you want after. Your transition to
+ choose from are 'slide', 'zoom', 'fade' and 'spin'.
+ - to insert a Plotly chart into your slide, write a line that has the form
+ Plotly(url) with your url pointing to your chart. Note that it is
+ STRONGLY advised that your chart has fig['layout']['autosize'] = True.
+ - to insert an image from the web, write a line with the form Image(url)
+ - to insert a block of text, begin with a line that denotes the code
+ envoronment '```lang' where lang is a valid programming language. To find
+ the valid languages run:\n
+ 'plotly.presentation_objs.presentation_objs.VALID_LANGUAGES'\n
+ To end the code block environment,
+ write a single '```' line. All Plotly(url) and Image(url) lines will NOT
+ be interpretted as a Plotly or Image url if they are in the code block.
+
+ :param (str) markdown_string: the block string that denotes the slides,
+ slide properties, and images to be placed in the presentation. If
+ 'markdown_string' is set to 'None', the JSON for a presentation with
+ one empty slide will be created.
+ :param (str) style: the theme that the presentation will take on. The
+ themes that are available now are 'martik' and 'moods'.
+ Default = 'moods'.
+ :param (bool) imgStretch: if set to False, all images in the presentation
+ will not have heights and widths that will not exceed the parent
+ container they belong to. In other words, images will keep their
+ original aspect ratios.
+ Default = True.
+
+ For examples see the documentation:\n
+ https://plot.ly/python/presentations-api/
+ """
+ def __init__(self, markdown_string=None, style='moods', imgStretch=True):
+ self['presentation'] = {
+ 'slides': [],
+ 'slidePreviews': [None for _ in range(496)],
+ 'version': '0.1.3',
+ 'paragraphStyles': paragraph_styles
+ }
+
+ if markdown_string:
+ if style not in PRES_THEMES:
+ raise exceptions.PlotlyError(
+ "Your presentation style must be {}".format(
+ list_of_options(PRES_THEMES, conj='or', period=True)
+ )
+ )
+ self._markdown_to_presentation(markdown_string, style, imgStretch)
+ else:
+ self._add_empty_slide()
+
+ def _markdown_to_presentation(self, markdown_string, style, imgStretch):
+ list_of_slides = _list_of_slides(markdown_string)
+
+ for slide_num, slide in enumerate(list_of_slides):
+ lines_in_slide = slide.split('\n')
+ title_lines = []
+
+ # validate blocks of code
+ if slide.count('```') % 2 != 0:
+ raise exceptions.PlotlyError(CODE_ENV_ERROR)
+
+ # find code blocks
+ code_indices = []
+ code_blocks = []
+ wdw_size = len('```')
+ for j in range(len(slide)):
+ if slide[j:j+wdw_size] == '```':
+ code_indices.append(j)
+
+ for k in range(int(len(code_indices) / 2)):
+ code_blocks.append(
+ slide[code_indices[2 * k]:code_indices[(2 * k) + 1]]
+ )
+
+ lang_and_code_tuples = []
+ for code_block in code_blocks:
+ # validate code blocks
+ code_by_lines = code_block.split('\n')
+ language = _remove_extra_whitespace_from_line(
+ code_by_lines[0][3:]
+ ).lower()
+ if language == '' or language not in VALID_LANGUAGES:
+ raise exceptions.PlotlyError(
+ "The language of your code block should be "
+ "clearly indicated after the first ``` that "
+ "begins the code block. The valid languages to "
+ "choose from are" + list_of_options(
+ VALID_LANGUAGES
+ )
+ )
+ lang_and_code_tuples.append(
+ (language, '\n'.join(code_by_lines[1:]))
+ )
+
+ # collect text, code and urls
+ title_lines = []
+ url_lines = []
+ text_lines = []
+ inCode = False
+
+ for line in lines_in_slide:
+ # inCode handling
+ if line[:3] == '```' and len(line) > 3:
+ inCode = True
+ if line == '```':
+ inCode = False
+
+ if not inCode and line != '```':
+ if len(line) > 0 and line[0] == '#':
+ title_lines.append(line)
+ elif (_url_parens_contained('Plotly', line) or
+ _url_parens_contained('Image', line)):
+ if (line.startswith('Plotly(') and
+ get_config()['plotly_domain'] not in line):
+ raise exceptions.PlotlyError(
+ "You are attempting to insert a Plotly Chart "
+ "in your slide but your url does not have "
+ "your plotly domain '{}' in it.".format(
+ get_config()['plotly_domain']
+ )
+ )
+ url_lines.append(line)
+ else:
+ # find and set transition properties
+ trans = 'transition:'
+ if line.startswith(trans) and title_lines == []:
+ slide_trans = line[len(trans):]
+ slide_trans = _remove_extra_whitespace_from_line(
+ slide_trans
+ )
+ slide_transition_list = []
+ for key in VALID_TRANSITIONS:
+ if key in slide_trans:
+ slide_transition_list.append(key)
+
+ if slide_transition_list == []:
+ slide_transition_list.append('slide')
+ self._set_transition(
+ slide_transition_list, slide_num
+ )
+
+ else:
+ text_lines.append(line)
+
+ # make text block
+ for i in range(2):
+ try:
+ while text_lines[-i] == '':
+ text_lines.pop(-i)
+ except IndexError:
+ pass
+
+ text_block = '\n'.join(text_lines)
+ num_of_boxes = len(url_lines) + len(lang_and_code_tuples)
+
+ (specs_for_boxes, specs_for_title, specs_for_text, bkgd_color,
+ title_style_attr, text_style_attr,
+ code_theme) = _return_layout_specs(
+ num_of_boxes, url_lines, title_lines, text_block, code_blocks,
+ slide_num, style
+ )
+
+ # background color
+ self._color_background(bkgd_color, slide_num)
+
+ # insert title, text, code, and images
+ if len(title_lines) > 0:
+ # clean titles
+ title = title_lines[0]
+ num_hashes = 0
+ while title[0] == '#':
+ title = title[1:]
+ num_hashes += 1
+ title = _remove_extra_whitespace_from_line(title)
+
+ self._insert(
+ box='Text', text_or_url=title,
+ left=specs_for_title[0], top=specs_for_title[1],
+ height=specs_for_title[2], width=specs_for_title[3],
+ slide=slide_num, style_attr=title_style_attr,
+ paragraphStyle='Heading 1'.format(
+ min(num_hashes, 3)
+ )
+ )
+
+ # text
+ if len(text_lines) > 0:
+ self._insert(
+ box='Text', text_or_url=text_block,
+ left=specs_for_text[0], top=specs_for_text[1],
+ height=specs_for_text[2], width=specs_for_text[3],
+ slide=slide_num, style_attr=text_style_attr,
+ paragraphStyle='Body'
+ )
+
+ url_and_code_blocks = list(url_lines + lang_and_code_tuples)
+ for k, specs in enumerate(specs_for_boxes):
+ url_or_code = url_and_code_blocks[k]
+ if isinstance(url_or_code, tuple):
+ # code
+ language = url_or_code[0]
+ code = url_or_code[1]
+ box_name = 'CodePane'
+
+ # code style
+ props_attr = {}
+ props_attr['language'] = language
+ props_attr['theme'] = code_theme
+
+ self._insert(box=box_name, text_or_url=code,
+ left=specs[0], top=specs[1],
+ height=specs[2], width=specs[3],
+ slide=slide_num, props_attr=props_attr)
+ else:
+ # url
+ if get_config()['plotly_domain'] in url_or_code:
+ box_name = 'Plotly'
+ else:
+ box_name = 'Image'
+ url = url_or_code[len(box_name) + 1: -1]
+
+ self._insert(box=box_name, text_or_url=url,
+ left=specs[0], top=specs[1],
+ height=specs[2], width=specs[3],
+ slide=slide_num)
+
+ if not imgStretch:
+ for s, slide in enumerate(self['presentation']['slides']):
+ for c, child in enumerate(slide['children']):
+ if child['type'] in ['Image', 'Plotly']:
+ deep_child = child['props']['style']
+ width = deep_child['width']
+ height = deep_child['height']
+
+ if width >= height:
+ deep_child['max-width'] = deep_child.pop('width')
+ else:
+ deep_child['max-height'] = deep_child.pop('height')
+
+ def _add_empty_slide(self):
+ self['presentation']['slides'].append(
+ _empty_slide(['slide'], _generate_id(9))
+ )
+
+ def _add_missing_slides(self, slide):
+ # add slides if desired slide number isn't in the presentation
+ try:
+ self['presentation']['slides'][slide]['children']
+ except IndexError:
+ num_of_slides = len(self['presentation']['slides'])
+ for _ in range(slide - num_of_slides + 1):
+ self._add_empty_slide()
+
+ def _insert(self, box, text_or_url, left, top, height, width, slide=0,
+ props_attr={}, style_attr={}, paragraphStyle=None):
+ self._add_missing_slides(slide)
+
+ left, top, height, width = _return_box_position(left, top, height,
+ width)
+ new_id = _generate_id(9)
+ child = _box(box, text_or_url, left, top, height, width, new_id,
+ props_attr, style_attr, paragraphStyle)
+
+ self['presentation']['slides'][slide]['children'].append(child)
+
+ def _color_background(self, color, slide):
+ self._add_missing_slides(slide)
+
+ loc = self['presentation']['slides'][slide]
+ loc['props']['style']['backgroundColor'] = color
+
+ def _background_image(self, url, slide, bkrd_image_dict):
+ self._add_missing_slides(slide)
+
+ loc = self['presentation']['slides'][slide]['props']
+
+ # default settings
+ size = 'stretch'
+ repeat = 'no-repeat'
+
+ if 'background-size:' in bkrd_image_dict:
+ size = bkrd_image_dict['background-size:']
+ if 'background-repeat:' in bkrd_image_dict:
+ repeat = bkrd_image_dict['background-repeat:']
+
+ if size == 'stretch':
+ backgroundSize = '100% 100%'
+ elif size == 'original':
+ backgroundSize = 'auto'
+ elif size == 'contain':
+ backgroundSize = 'contain'
+ elif size == 'cover':
+ backgroundSize = 'cover'
+
+ style = {
+ 'backgroundImage': 'url({})'.format(url),
+ 'backgroundPosition': 'center center',
+ 'backgroundRepeat': repeat,
+ 'backgroundSize': backgroundSize
+ }
+
+ for item in style.items():
+ loc['style'].setdefault(item[0], item[1])
+
+ loc['backgroundImageSrc'] = url
+ loc['backgroundImageName'] = None
+
+ def _set_transition(self, transition, slide):
+ self._add_missing_slides(slide)
+ loc = self['presentation']['slides'][slide]['props']
+ loc['transition'] = transition
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/plotly-2.1.0/plotly/version.py new/plotly-2.2.1/plotly/version.py
--- old/plotly-2.1.0/plotly/version.py 2017-10-11 19:07:35.000000000 +0200
+++ new/plotly-2.2.1/plotly/version.py 2017-10-27 01:54:28.000000000 +0200
@@ -1 +1 @@
-__version__ = '2.1.0'
+__version__ = '2.2.1'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/plotly-2.1.0/plotly.egg-info/PKG-INFO new/plotly-2.2.1/plotly.egg-info/PKG-INFO
--- old/plotly-2.1.0/plotly.egg-info/PKG-INFO 2017-10-11 19:09:16.000000000 +0200
+++ new/plotly-2.2.1/plotly.egg-info/PKG-INFO 2017-10-27 01:55:26.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: plotly
-Version: 2.1.0
+Version: 2.2.1
Summary: Python plotting library for collaborative, interactive, publication-quality graphs.
Home-page: https://plot.ly/python/
Author: Chris P
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/plotly-2.1.0/plotly.egg-info/SOURCES.txt new/plotly-2.2.1/plotly.egg-info/SOURCES.txt
--- old/plotly-2.1.0/plotly.egg-info/SOURCES.txt 2017-10-11 19:09:16.000000000 +0200
+++ new/plotly-2.2.1/plotly.egg-info/SOURCES.txt 2017-10-27 01:55:26.000000000 +0200
@@ -32,6 +32,7 @@
plotly/api/v2/images.py
plotly/api/v2/plot_schema.py
plotly/api/v2/plots.py
+plotly/api/v2/spectacle_presentations.py
plotly/api/v2/users.py
plotly/api/v2/utils.py
plotly/dashboard_objs/__init__.py
@@ -79,5 +80,7 @@
plotly/plotly/plotly.py
plotly/plotly/chunked_requests/__init__.py
plotly/plotly/chunked_requests/chunked_request.py
+plotly/presentation_objs/__init__.py
+plotly/presentation_objs/presentation_objs.py
plotly/widgets/__init__.py
plotly/widgets/graph_widget.py
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/plotly-2.1.0/plotly.egg-info/top_level.txt new/plotly-2.2.1/plotly.egg-info/top_level.txt
--- old/plotly-2.1.0/plotly.egg-info/top_level.txt 2017-10-11 19:09:16.000000000 +0200
+++ new/plotly-2.2.1/plotly.egg-info/top_level.txt 2017-10-27 01:55:26.000000000 +0200
@@ -12,4 +12,5 @@
plotly/offline
plotly/plotly
plotly/plotly/chunked_requests
+plotly/presentation_objs
plotly/widgets
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/plotly-2.1.0/setup.py new/plotly-2.2.1/setup.py
--- old/plotly-2.1.0/setup.py 2017-07-26 14:04:02.000000000 +0200
+++ new/plotly-2.2.1/setup.py 2017-10-27 01:54:28.000000000 +0200
@@ -35,6 +35,7 @@
'plotly/api/v1',
'plotly/api/v2',
'plotly/dashboard_objs',
+ 'plotly/presentation_objs',
'plotly/plotly',
'plotly/plotly/chunked_requests',
'plotly/figure_factory',
1
0
Hello community,
here is the log from the commit of package python-CommonMark for openSUSE:Factory checked in at 2017-10-31 15:43:45
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-CommonMark (Old)
and /work/SRC/openSUSE:Factory/.python-CommonMark.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-CommonMark"
Tue Oct 31 15:43:45 2017 rev:4 rq:537519 version:0.7.4
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-CommonMark/python-CommonMark.changes 2017-06-24 08:35:02.267438470 +0200
+++ /work/SRC/openSUSE:Factory/.python-CommonMark.new/python-CommonMark.changes 2017-10-31 15:43:46.122277185 +0100
@@ -1,0 +2,6 @@
+Mon Oct 30 01:51:43 UTC 2017 - arun(a)gmx.de
+
+- update to version 0.7.4:
+ * The CommonMark spec has been updated to 0.28.
+
+-------------------------------------------------------------------
Old:
----
CommonMark-0.7.3.tar.gz
New:
----
CommonMark-0.7.4.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-CommonMark.spec ++++++
--- /var/tmp/diff_new_pack.PVmQys/_old 2017-10-31 15:43:46.654257901 +0100
+++ /var/tmp/diff_new_pack.PVmQys/_new 2017-10-31 15:43:46.654257901 +0100
@@ -19,7 +19,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
%define oldpython python
Name: python-CommonMark
-Version: 0.7.3
+Version: 0.7.4
Release: 0
Summary: Python parser for the CommonMark Markdown spec
License: BSD-3-Clause
++++++ CommonMark-0.7.3.tar.gz -> CommonMark-0.7.4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/CommonMark-0.7.3/.gitignore new/CommonMark-0.7.4/.gitignore
--- old/CommonMark-0.7.3/.gitignore 2016-04-29 20:33:44.000000000 +0200
+++ new/CommonMark-0.7.4/.gitignore 2017-08-05 19:28:59.000000000 +0200
@@ -78,6 +78,7 @@
.env
# virtualenv
+ve/
venv/
ENV/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/CommonMark-0.7.3/CommonMark/__init__.py new/CommonMark-0.7.4/CommonMark/__init__.py
--- old/CommonMark-0.7.3/CommonMark/__init__.py 2016-08-04 15:18:10.000000000 +0200
+++ new/CommonMark-0.7.4/CommonMark/__init__.py 2017-08-05 18:33:33.000000000 +0200
@@ -5,3 +5,4 @@
from CommonMark.dump import dumpAST, dumpJSON
from CommonMark.blocks import Parser
from CommonMark.render.html import HtmlRenderer
+from CommonMark.render.rst import ReStructuredTextRenderer
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/CommonMark-0.7.3/CommonMark/blocks.py new/CommonMark-0.7.4/CommonMark/blocks.py
--- old/CommonMark-0.7.3/CommonMark/blocks.py 2017-01-05 19:42:33.000000000 +0100
+++ new/CommonMark-0.7.4/CommonMark/blocks.py 2017-08-05 19:23:13.000000000 +0200
@@ -94,8 +94,8 @@
'padding': None,
'marker_offset': parser.indent,
}
- m = re.match(reBulletListMarker, rest)
- m2 = re.match(reOrderedListMarker, rest)
+ m = re.search(reBulletListMarker, rest)
+ m2 = re.search(reOrderedListMarker, rest)
if m:
data['type'] = 'bullet'
data['bullet_char'] = m.group()[0]
@@ -320,7 +320,7 @@
match = indent <= 3 and \
len(ln) >= parser.next_nonspace + 1 and \
ln[parser.next_nonspace] == container.fence_char and \
- re.match(reClosingCodeFence, ln[parser.next_nonspace:])
+ re.search(reClosingCodeFence, ln[parser.next_nonspace:])
if match and len(match.group()) >= container.fence_length:
# closing fence - we're at end of line, so we can return
parser.finalize(container, parser.line_number)
@@ -448,8 +448,8 @@
@staticmethod
def atx_heading(parser, container=None):
if not parser.indented:
- m = re.match(reATXHeadingMarker,
- parser.current_line[parser.next_nonspace:])
+ m = re.search(reATXHeadingMarker,
+ parser.current_line[parser.next_nonspace:])
if m:
parser.advance_next_nonspace()
parser.advance_offset(len(m.group()), False)
@@ -459,8 +459,10 @@
container.level = len(m.group().strip())
# remove trailing ###s:
container.string_content = re.sub(
- r' +#+ *$', '', re.sub(
- r'^ *#+ *$', '', parser.current_line[parser.offset:]))
+ r'[ \t]+#+[ \t]*$', '', re.sub(
+ r'^[ \t]*#+[ \t]*$',
+ '',
+ parser.current_line[parser.offset:]))
parser.advance_offset(
len(parser.current_line) - parser.offset, False)
return 2
@@ -470,7 +472,7 @@
@staticmethod
def fenced_code_block(parser, container=None):
if not parser.indented:
- m = re.match(
+ m = re.search(
reCodeFence,
parser.current_line[parser.next_nonspace:])
if m:
@@ -508,7 +510,7 @@
@staticmethod
def setext_heading(parser, container=None):
if not parser.indented and container.t == 'paragraph':
- m = re.match(
+ m = re.search(
reSetextHeadingLine,
parser.current_line[parser.next_nonspace:])
if m:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/CommonMark-0.7.3/CommonMark/inlines.py new/CommonMark-0.7.4/CommonMark/inlines.py
--- old/CommonMark-0.7.3/CommonMark/inlines.py 2017-01-05 19:42:33.000000000 +0100
+++ new/CommonMark-0.7.4/CommonMark/inlines.py 2017-08-05 19:23:13.000000000 +0200
@@ -22,8 +22,32 @@
ESCAPED_CHAR = '\\\\' + common.ESCAPABLE
rePunctuation = re.compile(
- r'^[\u2000-\u206F\u2E00-\u2E7F\\' + "'" + '!"#\$%&\(\)'
- r'\*\+,\-\.\/:;<=>\?@\[\]\^_`\{\|\}~]')
+ r'[!"#$%&\'()*+,\-./:;<=>?@\[\]^_`{|}~\xA1\xA7\xAB\xB6\xB7\xBB'
+ r'\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3'
+ r'\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F'
+ r'\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E'
+ r'\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12'
+ r'\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB'
+ r'\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736'
+ r'\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-'
+ r'\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F'
+ r'\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E'
+ r'\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5'
+ r'\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC'
+ r'\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E42\u3001-\u3003\u3008-\u3011'
+ r'\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673'
+ r'\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E'
+ r'\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0'
+ r'\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63'
+ r'\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B'
+ r'\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-'
+ r'\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58'
+ r'\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD804[\uDC47-\uDC4D'
+ r'\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC9\uDDCD'
+ r'\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDCC6\uDDC1-\uDDD7'
+ r'\uDE41-\uDE43\uDF3C-\uDF3E]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F'
+ r'\uDEF5\uDF37-\uDF3B\uDF44]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]'
+)
reLinkTitle = re.compile(
'^(?:"(' + ESCAPED_CHAR + '|[^"\\x00])*"' +
@@ -184,7 +208,7 @@
self.pos += 1
node = Node('linebreak', None)
block.append_child(node)
- elif subjchar and re.match(reEscapable, subjchar):
+ elif subjchar and re.search(reEscapable, subjchar):
block.append_child(text(subjchar))
self.pos += 1
else:
@@ -258,21 +282,22 @@
c_after = '\n'
# Python 2 doesn't recognize '\xa0' as whitespace
- after_is_whitespace = re.match(reUnicodeWhitespaceChar, c_after) or \
+ after_is_whitespace = re.search(reUnicodeWhitespaceChar, c_after) or \
c_after == '\xa0'
- after_is_punctuation = re.match(rePunctuation, c_after)
- before_is_whitespace = re.match(reUnicodeWhitespaceChar, c_before) or \
+ after_is_punctuation = re.search(rePunctuation, c_after)
+ before_is_whitespace = re.search(
+ reUnicodeWhitespaceChar, c_before) or \
c_before == '\xa0'
- before_is_punctuation = re.match(rePunctuation, c_before)
+ before_is_punctuation = re.search(rePunctuation, c_before)
left_flanking = not after_is_whitespace and \
- not (after_is_punctuation and
- not before_is_whitespace and
- not before_is_punctuation)
+ (not after_is_punctuation or
+ before_is_whitespace or
+ before_is_punctuation)
right_flanking = not before_is_whitespace and \
- not (before_is_punctuation and
- not after_is_whitespace and
- not after_is_punctuation)
+ (not before_is_punctuation or
+ after_is_whitespace or
+ after_is_punctuation)
if c == '_':
can_open = left_flanking and \
(not right_flanking or before_is_punctuation)
@@ -385,16 +410,9 @@
else:
# Calculate actual number of delimiters used from
# closer
- if closer['numdelims'] < 3 or opener['numdelims'] < 3:
- if closer['numdelims'] <= opener['numdelims']:
- use_delims = closer['numdelims']
- else:
- use_delims = opener['numdelims']
- else:
- if closer['numdelims'] % 2 == 0:
- use_delims = 2
- else:
- use_delims = 1
+ use_delims = 2 if (
+ closer['numdelims'] >= 2 and
+ opener['numdelims'] >= 2) else 1
opener_inl = opener.get('node')
closer_inl = closer.get('node')
@@ -502,7 +520,7 @@
else:
self.pos += 1
openparens -= 1
- elif re.match(reWhitespaceChar, c):
+ elif re.search(reWhitespaceChar, c):
break
else:
self.pos += 1
@@ -518,8 +536,10 @@
Attempt to parse a link label, returning number of
characters parsed.
"""
+ # Note: our regex will allow something of form [..\];
+ # we disallow it here rather than using lookahead in the regex:
m = self.match(reLinkLabel)
- if m is None or len(m) > 1001 or re.match(r'\[\s+\]', m):
+ if m is None or len(m) > 1001 or re.search(r'([^\\]\\\]$|\[\n\]$)', m):
return 0
else:
return len(m)
@@ -601,7 +621,7 @@
dest = self.parseLinkDestination()
if dest is not None and self.spnl():
# make sure there's a space before the title
- if re.match(reWhitespaceChar, self.subject[self.pos-1]):
+ if re.search(reWhitespaceChar, self.subject[self.pos-1]):
title = self.parseLinkTitle()
if self.spnl() and self.peek() == ')':
self.pos += 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/CommonMark-0.7.3/CommonMark/main.py new/CommonMark-0.7.4/CommonMark/main.py
--- old/CommonMark-0.7.3/CommonMark/main.py 2016-08-04 15:18:10.000000000 +0200
+++ new/CommonMark-0.7.4/CommonMark/main.py 2017-08-05 18:33:33.000000000 +0200
@@ -14,6 +14,7 @@
from CommonMark.blocks import Parser
from CommonMark.dump import dumpAST, dumpJSON
from CommonMark.render.html import HtmlRenderer
+from CommonMark.render.rst import ReStructuredTextRenderer
def commonmark(text, format="html"):
@@ -26,7 +27,7 @@
"""
parser = Parser()
ast = parser.parse(text)
- if format not in ["html", "json", "ast"]:
+ if format not in ["html", "json", "ast", "rst"]:
raise ValueError("format must be 'html', 'json' or 'ast'")
if format == "html":
renderer = HtmlRenderer()
@@ -35,3 +36,6 @@
return dumpJSON(ast)
if format == "ast":
return dumpAST(ast)
+ if format == "rst":
+ renderer = ReStructuredTextRenderer()
+ return renderer.render(ast)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/CommonMark-0.7.3/CommonMark/node.py new/CommonMark-0.7.4/CommonMark/node.py
--- old/CommonMark-0.7.3/CommonMark/node.py 2016-08-04 15:18:10.000000000 +0200
+++ new/CommonMark-0.7.4/CommonMark/node.py 2017-08-05 19:23:13.000000000 +0200
@@ -10,7 +10,7 @@
def is_container(node):
- return (re.match(reContainer, node.t) is not None)
+ return (re.search(reContainer, node.t) is not None)
class NodeWalker(object):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/CommonMark-0.7.3/CommonMark/render/html.py new/CommonMark-0.7.4/CommonMark/render/html.py
--- old/CommonMark-0.7.3/CommonMark/render/html.py 2016-08-04 15:18:10.000000000 +0200
+++ new/CommonMark-0.7.4/CommonMark/render/html.py 2017-08-05 19:23:13.000000000 +0200
@@ -14,8 +14,8 @@
def potentially_unsafe(url):
- return re.match(reUnsafeProtocol, url) and \
- (not re.match(reSafeDataProtocol, url))
+ return re.search(reUnsafeProtocol, url) and \
+ (not re.search(reSafeDataProtocol, url))
class HtmlRenderer(Renderer):
@@ -29,6 +29,9 @@
self.last_out = '\n'
self.options = options
+ def escape(self, text, preserve_entities):
+ return escape_xml(text, preserve_entities)
+
def tag(self, name, attrs=None, selfclosing=None):
"""Helper function to produce an HTML tag."""
if self.disable_tags > 0:
@@ -62,10 +65,10 @@
if entering:
if not (self.options.get('safe') and
potentially_unsafe(node.destination)):
- attrs.append(['href', escape_xml(node.destination, True)])
+ attrs.append(['href', self.escape(node.destination, True)])
if node.title:
- attrs.append(['title', escape_xml(node.title, True)])
+ attrs.append(['title', self.escape(node.title, True)])
self.tag('a', attrs)
else:
@@ -79,14 +82,14 @@
self.lit('<img src="" alt="')
else:
self.lit('<img src="' +
- escape_xml(node.destination, True) +
+ self.escape(node.destination, True) +
'" alt="')
self.disable_tags += 1
else:
self.disable_tags -= 1
if self.disable_tags == 0:
if node.title:
- self.lit('" title="' + escape_xml(node.title, True))
+ self.lit('" title="' + self.escape(node.title, True))
self.lit('" />')
def emph(self, node, entering):
@@ -129,7 +132,7 @@
attrs = self.attrs(node)
if len(info_words) > 0 and len(info_words[0]) > 0:
attrs.append(['class', 'language-' +
- escape_xml(info_words[0], True)])
+ self.escape(info_words[0], True)])
self.cr()
self.tag('pre')
@@ -211,7 +214,7 @@
# Helper methods #
def out(self, s):
- self.lit(escape_xml(s, False))
+ self.lit(self.escape(s, False))
def attrs(self, node):
att = []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/CommonMark-0.7.3/CommonMark/render/rst.py new/CommonMark-0.7.4/CommonMark/render/rst.py
--- old/CommonMark-0.7.3/CommonMark/render/rst.py 1970-01-01 01:00:00.000000000 +0100
+++ new/CommonMark-0.7.4/CommonMark/render/rst.py 2017-08-05 18:33:33.000000000 +0200
@@ -0,0 +1,159 @@
+from __future__ import unicode_literals
+
+
+from CommonMark.render.renderer import Renderer
+
+
+class ReStructuredTextRenderer(Renderer):
+ """
+ Render reStructuredText from Markdown
+
+ Example:
+
+ .. code:: python
+
+ import CommonMark
+
+ parser = CommonMark.Parser()
+ ast = parser.parse('Hello `inline code` example')
+
+ renderer = CommonMark.ReStructuredTextRenderer()
+ rst = renderer.render(ast)
+ print(rst) # Hello ``inline code`` example
+ """
+ def __init__(self, indent_char=' '):
+ self.indent_char = indent_char
+ self.indent_length = 0
+
+ def lit(self, s):
+ if s == '\n':
+ indent = '' # Avoid whitespace if we're just adding a newline
+ elif self.last_out != '\n':
+ indent = '' # Don't indent if we're in the middle of a line
+ else:
+ indent = self.indent_char * self.indent_length
+
+ return super(ReStructuredTextRenderer, self).lit(indent + s)
+
+ def cr(self):
+ self.lit('\n')
+
+ def indent_lines(self, literal, indent_length=4):
+ indent = self.indent_char * indent_length
+ new_lines = []
+
+ for line in literal.splitlines():
+ new_lines.append(indent + line)
+
+ return '\n'.join(new_lines)
+
+ # Nodes
+
+ def document(self, node, entering):
+ pass
+
+ def softbreak(self, node, entering):
+ self.cr()
+
+ def linebreak(self, node, entering):
+ self.cr()
+ self.cr()
+
+ def text(self, node, entering):
+ self.out(node.literal)
+
+ def emph(self, node, entering):
+ self.out('*')
+
+ def strong(self, node, entering):
+ self.out('**')
+
+ def paragraph(self, node, entering):
+ if node.parent.t == 'item':
+ pass
+ else:
+ self.cr()
+
+ def link(self, node, entering):
+ if entering:
+ self.out('`')
+ else:
+ self.out(' <%s>`_' % node.destination)
+
+ def image(self, node, entering):
+ directive = '.. image:: ' + node.destination
+
+ if entering:
+ self.out(directive)
+ self.cr()
+ self.indent_length += 4
+ self.out(':alt: ')
+ else:
+ self.indent_length -= 4
+
+ def code(self, node, entering):
+ self.out('``')
+ self.out(node.literal)
+ self.out('``')
+
+ def code_block(self, node, entering):
+ directive = '.. code::'
+ language_name = None
+
+ info_words = node.info.split() if node.info else []
+ if len(info_words) > 0 and len(info_words[0]) > 0:
+ language_name = info_words[0]
+
+ if language_name:
+ directive += ' ' + language_name
+
+ self.cr()
+ self.out(directive)
+ self.cr()
+ self.cr()
+ self.out(self.indent_lines(node.literal))
+ self.cr()
+
+ def list(self, node, entering):
+ if entering:
+ self.cr()
+
+ def item(self, node, entering):
+ tagname = '*' if node.list_data['type'] == 'bullet' else '#.'
+
+ if entering:
+ self.out(tagname + ' ')
+ else:
+ self.cr()
+
+ def block_quote(self, node, entering):
+ if entering:
+ self.indent_length += 4
+ else:
+ self.indent_length -= 4
+
+ def heading(self, node, entering):
+ heading_chars = [
+ '#',
+ '*',
+ '=',
+ '-',
+ '^',
+ '"'
+ ]
+
+ try:
+ heading_char = heading_chars[node.level-1]
+ except IndexError:
+ # Default to the last level if we're in too deep
+ heading_char = heading_chars[-1]
+
+ heading_length = len(node.first_child.literal)
+ banner = heading_char * heading_length
+
+ if entering:
+ self.cr()
+ else:
+ self.cr()
+ self.out(banner)
+ self.cr()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/CommonMark-0.7.3/CommonMark/tests/rst_tests.py new/CommonMark-0.7.4/CommonMark/tests/rst_tests.py
--- old/CommonMark-0.7.3/CommonMark/tests/rst_tests.py 1970-01-01 01:00:00.000000000 +0100
+++ new/CommonMark-0.7.4/CommonMark/tests/rst_tests.py 2017-08-05 18:33:33.000000000 +0200
@@ -0,0 +1,172 @@
+import unittest
+
+import CommonMark
+
+
+class TestCommonmark(unittest.TestCase):
+ def setUp(self):
+ self.parser = CommonMark.Parser()
+ self.renderer = CommonMark.ReStructuredTextRenderer()
+
+ def render_rst(self, test_str):
+ ast = self.parser.parse(test_str)
+ rst = self.renderer.render(ast)
+
+ return rst
+
+ def assertEqualRender(self, src_markdown, expected_rst):
+ rendered_rst = self.render_rst(src_markdown)
+ self.assertEqual(rendered_rst, expected_rst)
+
+ def test_strong(self):
+ src_markdown = 'Hello **Strong**'
+ expected_rst = '\nHello **Strong**\n'
+ self.assertEqualRender(src_markdown, expected_rst)
+
+ def test_emphasis(self):
+ src_markdown = 'Hello *Emphasis*'
+ expected_rst = '\nHello *Emphasis*\n'
+ self.assertEqualRender(src_markdown, expected_rst)
+
+ def test_paragraph(self):
+ src_markdown = 'Hello paragraph'
+ expected_rst = '\nHello paragraph\n'
+ self.assertEqualRender(src_markdown, expected_rst)
+
+ def test_link(self):
+ src_markdown = '[Link](http://example.com)'
+ expected_rst = '\n`Link <http://example.com>`_\n'
+ self.assertEqualRender(src_markdown, expected_rst)
+
+ def test_image(self):
+ src_markdown = '![Image](http://placekitten.com/100/100)'
+ expected_rst = """
+.. image:: http://placekitten.com/100/100
+ :alt: Image
+"""
+ self.assertEqualRender(src_markdown, expected_rst)
+
+ def test_code(self):
+ src_markdown = 'Test `inline code` with backticks'
+ expected_rst = '\nTest ``inline code`` with backticks\n'
+ self.assertEqualRender(src_markdown, expected_rst)
+
+ def test_code_block(self):
+ src_markdown = """
+```python
+# code block
+print '3 backticks or'
+print 'indent 4 spaces'
+```
+"""
+ expected_rst = """
+.. code:: python
+
+ # code block
+ print '3 backticks or'
+ print 'indent 4 spaces'
+"""
+ self.assertEqualRender(src_markdown, expected_rst)
+
+ def test_unordered_list(self):
+ src_markdown = """
+This is a list:
+* List item
+* List item
+* List item
+"""
+ expected_rst = """
+This is a list:
+
+* List item
+* List item
+* List item
+"""
+ self.assertEqualRender(src_markdown, expected_rst)
+
+ def test_ordered_list(self):
+ src_markdown = """
+This is a ordered list:
+1. One
+2. Two
+3. Three
+"""
+ expected_rst = """
+This is a ordered list:
+
+#. One
+#. Two
+#. Three
+"""
+ self.assertEqualRender(src_markdown, expected_rst)
+
+ def test_block_quote(self):
+ src_markdown = """
+Before the blockquote:
+
+> The blockquote
+
+After the blockquote
+"""
+ expected_rst = """
+Before the blockquote:
+
+ The blockquote
+
+After the blockquote
+"""
+ self.assertEqualRender(src_markdown, expected_rst)
+
+ def test_heading(self):
+ src_markdown = '''
+# Heading 1
+
+## Heading 2
+
+### Heading 3
+
+#### Heading 4
+
+##### Heading 5
+
+###### Heading 6
+'''
+ expected_rst = '''
+Heading 1
+#########
+
+Heading 2
+*********
+
+Heading 3
+=========
+
+Heading 4
+---------
+
+Heading 5
+^^^^^^^^^
+
+Heading 6
+"""""""""
+'''
+ self.assertEqualRender(src_markdown, expected_rst)
+
+ def test_multiple_paragraphs(self):
+ src_markdown = '''
+Start of first paragraph that
+continues on a new line
+
+This is the second paragraph
+'''
+ expected_rst = '''
+Start of first paragraph that
+continues on a new line
+
+This is the second paragraph
+'''
+ self.assertEqualRender(src_markdown, expected_rst)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/CommonMark-0.7.3/CommonMark.egg-info/PKG-INFO new/CommonMark-0.7.4/CommonMark.egg-info/PKG-INFO
--- old/CommonMark-0.7.3/CommonMark.egg-info/PKG-INFO 2017-01-05 19:49:57.000000000 +0100
+++ new/CommonMark-0.7.4/CommonMark.egg-info/PKG-INFO 2017-08-05 19:34:09.000000000 +0200
@@ -1,11 +1,11 @@
Metadata-Version: 1.1
Name: CommonMark
-Version: 0.7.3
+Version: 0.7.4
Summary: Python parser for the CommonMark Markdown spec
Home-page: https://github.com/rtfd/CommonMark-py
Author: Nik Nyby
Author-email: nikolas(a)gnu.org
-License: BSD License
+License: BSD-3-Clause
Description: UNKNOWN
Keywords: markup,markdown,commonmark
Platform: UNKNOWN
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/CommonMark-0.7.3/CommonMark.egg-info/SOURCES.txt new/CommonMark-0.7.4/CommonMark.egg-info/SOURCES.txt
--- old/CommonMark-0.7.3/CommonMark.egg-info/SOURCES.txt 2017-01-05 19:49:57.000000000 +0100
+++ new/CommonMark-0.7.4/CommonMark.egg-info/SOURCES.txt 2017-08-05 19:34:09.000000000 +0200
@@ -24,6 +24,8 @@
CommonMark/render/__init__.py
CommonMark/render/html.py
CommonMark/render/renderer.py
+CommonMark/render/rst.py
CommonMark/tests/__init__.py
+CommonMark/tests/rst_tests.py
CommonMark/tests/run_spec_tests.py
CommonMark/tests/unit_tests.py
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/CommonMark-0.7.3/PKG-INFO new/CommonMark-0.7.4/PKG-INFO
--- old/CommonMark-0.7.3/PKG-INFO 2017-01-05 19:49:57.000000000 +0100
+++ new/CommonMark-0.7.4/PKG-INFO 2017-08-05 19:34:09.000000000 +0200
@@ -1,11 +1,11 @@
Metadata-Version: 1.1
Name: CommonMark
-Version: 0.7.3
+Version: 0.7.4
Summary: Python parser for the CommonMark Markdown spec
Home-page: https://github.com/rtfd/CommonMark-py
Author: Nik Nyby
Author-email: nikolas(a)gnu.org
-License: BSD License
+License: BSD-3-Clause
Description: UNKNOWN
Keywords: markup,markdown,commonmark
Platform: UNKNOWN
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/CommonMark-0.7.3/README.rst new/CommonMark-0.7.4/README.rst
--- old/CommonMark-0.7.3/README.rst 2017-01-05 19:48:02.000000000 +0100
+++ new/CommonMark-0.7.4/README.rst 2017-08-05 19:28:59.000000000 +0200
@@ -1,7 +1,7 @@
CommonMark-py
=============
-Pure Python port of `jgm <https://github.com/jgm>`__'s
+CommonMark-py is a pure Python port of `jgm <https://github.com/jgm>`__'s
`commonmark.js <https://github.com/jgm/commonmark.js>`__, a
Markdown parser and renderer for the
`CommonMark <http://commonmark.org>`__ specification, using only native
@@ -9,14 +9,10 @@
stable we will release the first ``1.0`` version and attempt to keep up
to date with changes in ``commonmark.js``.
-We are currently at the same development stage (actually a bit ahead
-because we have implemented HTML entity conversion and href URL
-escaping) as ``commonmark.js``. Since Python versions pre-3.4 use outdated
-(i.e. not HTML5 spec) entity conversion, I've converted the 3.4
-implementation into a single file, ``entitytrans.py`` which so far seems
-to work (all tests pass on 2.6, 2.7, 3.3, 3.4, and 3.5).
+CommonMark-py is tested against the CommonMark spec with Python versions
+2.6, 2.7, 3.3, 3.4, 3.5, and 3.6.
-**Current version:** 0.7.3
+**Current version:** 0.7.4
|Build Status| |Doc Link|
@@ -107,7 +103,7 @@
::
- $ python run_spec_tests.py -h
+ $ ./venv/bin/python CommonMark/tests/run_spec_tests.py -h
usage: run_spec_tests.py [-h] [-t T] [-p] [-f] [-i] [-d] [-np] [-s]
script to run the CommonMark specification tests against the CommonMark.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/CommonMark-0.7.3/setup.cfg new/CommonMark-0.7.4/setup.cfg
--- old/CommonMark-0.7.3/setup.cfg 2017-01-05 19:49:57.000000000 +0100
+++ new/CommonMark-0.7.4/setup.cfg 2017-08-05 19:34:09.000000000 +0200
@@ -5,7 +5,7 @@
universal = 1
[egg_info]
-tag_svn_revision = 0
tag_build =
tag_date = 0
+tag_svn_revision = 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/CommonMark-0.7.3/setup.py new/CommonMark-0.7.4/setup.py
--- old/CommonMark-0.7.3/setup.py 2017-01-05 19:48:02.000000000 +0100
+++ new/CommonMark-0.7.4/setup.py 2017-08-05 19:28:59.000000000 +0200
@@ -21,8 +21,8 @@
setup(
name="CommonMark",
packages=find_packages(exclude=['tests']),
- version="0.7.3",
- license="BSD License",
+ version="0.7.4",
+ license="BSD-3-Clause",
description="Python parser for the CommonMark Markdown spec",
author="Bibek Kafle <bkafle662(a)gmail.com>, " +
"Roland Shoemaker <rolandshoemaker(a)gmail.com>",
@@ -41,8 +41,8 @@
'future',
],
tests_require=[
- 'flake8==2.6.2',
- 'hypothesis',
+ 'flake8==3.4.0',
+ 'hypothesis==3.7.1',
# For python 2.6
'hypothesislegacysupport',
],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/CommonMark-0.7.3/spec.txt new/CommonMark-0.7.4/spec.txt
--- old/CommonMark-0.7.3/spec.txt 2017-01-05 19:42:33.000000000 +0100
+++ new/CommonMark-0.7.4/spec.txt 2017-08-05 19:23:13.000000000 +0200
@@ -1,8 +1,8 @@
---
title: CommonMark Spec
author: John MacFarlane
-version: 0.27
-date: '2016-11-18'
+version: 0.28
+date: '2017-08-01'
license: '[CC-BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)'
...
@@ -11,10 +11,12 @@
## What is Markdown?
Markdown is a plain text format for writing structured documents,
-based on conventions used for indicating formatting in email and
-usenet posts. It was developed in 2004 by John Gruber, who wrote
-the first Markdown-to-HTML converter in Perl, and it soon became
-ubiquitous. In the next decade, dozens of implementations were
+based on conventions for indicating formatting in email
+and usenet posts. It was developed by John Gruber (with
+help from Aaron Swartz) and released in 2004 in the form of a
+[syntax description](http://daringfireball.net/projects/markdown/syntax)
+and a Perl script (`Markdown.pl`) for converting Markdown to
+HTML. In the next decade, dozens of implementations were
developed in many languages. Some extended the original
Markdown syntax with conventions for footnotes, tables, and
other document elements. Some allowed Markdown documents to be
@@ -312,7 +314,7 @@
characters].
A [Unicode whitespace character](@) is
-any code point in the Unicode `Zs` class, or a tab (`U+0009`),
+any code point in the Unicode `Zs` general category, or a tab (`U+0009`),
carriage return (`U+000D`), newline (`U+000A`), or form feed
(`U+000C`).
@@ -331,7 +333,7 @@
A [punctuation character](@) is an [ASCII
punctuation character] or anything in
-the Unicode classes `Pc`, `Pd`, `Pe`, `Pf`, `Pi`, `Po`, or `Ps`.
+the general Unicode categories `Pc`, `Pd`, `Pe`, `Pf`, `Pi`, `Po`, or `Ps`.
## Tabs
@@ -402,8 +404,8 @@
Normally the `>` that begins a block quote may be followed
optionally by a space, which is not considered part of the
content. In the following case `>` is followed by a tab,
-which is treated as if it were expanded into spaces.
-Since one of theses spaces is considered part of the
+which is treated as if it were expanded into three spaces.
+Since one of these spaces is considered part of the
delimiter, `foo` is considered to be indented six spaces
inside the block quote context, so we get an indented
code block starting with two spaces.
@@ -481,7 +483,7 @@
quotations, lists, headings, rules, and code blocks. Some blocks (like
block quotes and list items) contain other blocks; others (like
headings and paragraphs) contain [inline](@) content---text,
-links, emphasized text, images, code, and so on.
+links, emphasized text, images, code spans, and so on.
## Precedence
@@ -1643,6 +1645,15 @@
</code></pre>
````````````````````````````````
+Fewer than three backticks is not enough:
+
+```````````````````````````````` example
+``
+foo
+``
+.
+<p><code>foo</code></p>
+````````````````````````````````
The closing code fence must use the same character as the opening
fence:
@@ -2031,6 +2042,37 @@
or the end of the line.\
**End condition:** line is followed by a [blank line].
+HTML blocks continue until they are closed by their appropriate
+[end condition], or the last line of the document or other [container block].
+This means any HTML **within an HTML block** that might otherwise be recognised
+as a start condition will be ignored by the parser and passed through as-is,
+without changing the parser's state.
+
+For instance, `<pre>` within a HTML block started by `<table>` will not affect
+the parser state; as the HTML block was started in by start condition 6, it
+will end at any blank line. This can be surprising:
+
+```````````````````````````````` example
+<table><tr><td>
+<pre>
+**Hello**,
+
+_world_.
+</pre>
+</td></tr></table>
+.
+<table><tr><td>
+<pre>
+**Hello**,
+<p><em>world</em>.
+</pre></p>
+</td></tr></table>
+````````````````````````````````
+
+In this case, the HTML block is terminated by the newline — the `**hello**`
+text remains verbatim — and regular parsing resumes, with a paragraph,
+emphasised `world` and inline and block HTML following.
+
All types of [HTML blocks] except type 7 may interrupt
a paragraph. Blocks of type 7 may not interrupt a paragraph.
(This restriction is intended to prevent unwanted interpretation
@@ -3637,11 +3679,15 @@
If the list item is ordered, then it is also assigned a start
number, based on the ordered list marker.
- Exceptions: When the first list item in a [list] interrupts
- a paragraph---that is, when it starts on a line that would
- otherwise count as [paragraph continuation text]---then (a)
- the lines *Ls* must not begin with a blank line, and (b) if
- the list item is ordered, the start number must be 1.
+ Exceptions:
+
+ 1. When the first list item in a [list] interrupts
+ a paragraph---that is, when it starts on a line that would
+ otherwise count as [paragraph continuation text]---then (a)
+ the lines *Ls* must not begin with a blank line, and (b) if
+ the list item is ordered, the start number must be 1.
+ 2. If any line is a [thematic break][thematic breaks] then
+ that line is not a list item.
For example, let *Ls* be the lines
@@ -5796,6 +5842,15 @@
<p>`foo</p>
````````````````````````````````
+The following case also illustrates the need for opening and
+closing backtick strings to be equal in length:
+
+```````````````````````````````` example
+`foo``bar``
+.
+<p>`foo<code>bar</code></p>
+````````````````````````````````
+
## Emphasis and strong emphasis
@@ -5845,19 +5900,20 @@
First, some definitions. A [delimiter run](@) is either
a sequence of one or more `*` characters that is not preceded or
-followed by a `*` character, or a sequence of one or more `_`
-characters that is not preceded or followed by a `_` character.
+followed by a non-backslash-escaped `*` character, or a sequence
+of one or more `_` characters that is not preceded or followed by
+a non-backslash-escaped `_` character.
A [left-flanking delimiter run](@) is
a [delimiter run] that is (a) not followed by [Unicode whitespace],
-and (b) either not followed by a [punctuation character], or
+and (b) not followed by a [punctuation character], or
preceded by [Unicode whitespace] or a [punctuation character].
For purposes of this definition, the beginning and the end of
the line count as Unicode whitespace.
A [right-flanking delimiter run](@) is
a [delimiter run] that is (a) not preceded by [Unicode whitespace],
-and (b) either not preceded by a [punctuation character], or
+and (b) not preceded by a [punctuation character], or
followed by [Unicode whitespace] or a [punctuation character].
For purposes of this definition, the beginning and the end of
the line count as Unicode whitespace.
@@ -5936,7 +5992,7 @@
7. A double `**` [can close strong emphasis](@)
iff it is part of a [right-flanking delimiter run].
-8. A double `__` [can close strong emphasis]
+8. A double `__` [can close strong emphasis] iff
it is part of a [right-flanking delimiter run]
and either (a) not part of a [left-flanking delimiter run]
or (b) part of a [left-flanking delimiter run]
@@ -5976,8 +6032,8 @@
an interpretation `<strong>...</strong>` is always preferred to
`<em><em>...</em></em>`.
-14. An interpretation `<strong><em>...</em></strong>` is always
- preferred to `<em><strong>..</strong></em>`.
+14. An interpretation `<em><strong>...</strong></em>` is always
+ preferred to `<strong><em>...</em></strong>`.
15. When two potential emphasis or strong emphasis spans overlap,
so that the second begins before the first ends and ends after
@@ -7000,14 +7056,14 @@
```````````````````````````````` example
***foo***
.
-<p><strong><em>foo</em></strong></p>
+<p><em><strong>foo</strong></em></p>
````````````````````````````````
```````````````````````````````` example
_____foo_____
.
-<p><strong><strong><em>foo</em></strong></strong></p>
+<p><em><strong><strong>foo</strong></strong></em></p>
````````````````````````````````
@@ -7148,7 +7204,9 @@
- a nonempty sequence of characters that does not include
ASCII space or control characters, and includes parentheses
only if (a) they are backslash-escaped or (b) they are part of
- a balanced pair of unescaped parentheses.
+ a balanced pair of unescaped parentheses. (Implementations
+ may impose limits on parentheses nesting to avoid performance
+ issues, but at least three levels of nesting should be supported.)
A [link title](@) consists of either
@@ -7254,7 +7312,7 @@
<p><a href="(foo)">link</a></p>
````````````````````````````````
-Any number parentheses are allowed without escaping, as long as they are
+Any number of parentheses are allowed without escaping, as long as they are
balanced:
```````````````````````````````` example
@@ -7560,13 +7618,16 @@
A [link label](@) begins with a left bracket (`[`) and ends
with the first right bracket (`]`) that is not backslash-escaped.
Between these brackets there must be at least one [non-whitespace character].
-Unescaped square bracket characters are not allowed in
-[link labels]. A link label can have at most 999
-characters inside the square brackets.
+Unescaped square bracket characters are not allowed inside the
+opening and closing square brackets of [link labels]. A link
+label can have at most 999 characters inside the square
+brackets.
One label [matches](@)
another just in case their normalized forms are equal. To normalize a
-label, perform the *Unicode case fold* and collapse consecutive internal
+label, strip off the opening and closing brackets,
+perform the *Unicode case fold*, strip leading and trailing
+[whitespace] and collapse consecutive internal
[whitespace] to a single space. If there are multiple
matching reference link definitions, the one that comes first in the
document is used. (It is desirable in such cases to emit a warning.)
@@ -8319,11 +8380,11 @@
````````````````````````````````
-If you just want bracketed text, you can backslash-escape the
-opening `!` and `[`:
+If you just want a literal `!` followed by bracketed text, you can
+backslash-escape the opening `[`:
```````````````````````````````` example
-\!\[foo]
+!\[foo]
[foo]: /url "title"
.
1
0