Hello community,
here is the log from the commit of package python-relatorio for openSUSE:Factory checked in at 2019-07-31 14:36:54
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-relatorio (Old)
and /work/SRC/openSUSE:Factory/.python-relatorio.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-relatorio"
Wed Jul 31 14:36:54 2019 rev:8 rq:720017 version:0.9.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-relatorio/python-relatorio.changes 2019-07-08 15:11:04.543348006 +0200
+++ /work/SRC/openSUSE:Factory/.python-relatorio.new.4126/python-relatorio.changes 2019-07-31 14:36:57.817847138 +0200
@@ -1,0 +2,13 @@
+Wed Jul 31 09:24:57 UTC 2019 - Tomáš Chvátal
+
+- Run tests
+- Run fdupes
+
+-------------------------------------------------------------------
+Tue Jul 30 18:41:41 UTC 2019 - Axel Braun
+
+- version 0.9.0
+ * Support out parameter of render
+ * Write opendocument stream directly to the ZipFile
+
+-------------------------------------------------------------------
Old:
----
relatorio-0.8.1.tar.gz
New:
----
relatorio-0.9.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-relatorio.spec ++++++
--- /var/tmp/diff_new_pack.sP44MG/_old 2019-07-31 14:36:58.733846620 +0200
+++ /var/tmp/diff_new_pack.sP44MG/_new 2019-07-31 14:36:58.733846620 +0200
@@ -1,7 +1,7 @@
#
# spec file for package python-relatorio
#
-# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
# Copyright (c) 2016-2019 Dr. Axel Braun
#
# All modifications and additions to the file contributed by third parties
@@ -13,32 +13,31 @@
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
-# Please submit bugfixes or comments via http://bugs.opensuse.org/
+# Please submit bugfixes or comments via https://bugs.opensuse.org/
#
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
-%bcond_with tests
%define mod_name relatorio
Name: python-relatorio
-Version: 0.8.1
+Version: 0.9.0
Release: 0
Summary: Python module to create reports from Python objects
-License: GPL-3.0+
+License: GPL-3.0-or-later
Group: Productivity/Office/Management
-Url: https://pypi.python.org/pypi/relatorio
+URL: https://pypi.python.org/pypi/relatorio
Source: https://pypi.io/packages/source/r/%{mod_name}/%{mod_name}-%{version}.tar.gz
BuildRequires: %{python_module Genshi}
BuildRequires: %{python_module lxml}
-# It requires different magic for tests https://github.com/ahupp/python-magic
-#BuildRequires: %{python_module magic}
+BuildRequires: %{python_module python-magic}
BuildRequires: %{python_module setuptools}
+BuildRequires: fdupes
BuildRequires: python-rpm-macros
Requires: python-Genshi
Requires: python-PyYAML
Requires: python-lxml
-Requires: python-magic
Requires: python-pycha
+Requires: python-python-magic
BuildArch: noarch
%python_subpackages
@@ -55,11 +54,10 @@
%install
%python_install
+%python_expand %fdupes %{buildroot}%{$python_sitelib}
-%if %{with tests}
%check
%python_exec setup.py test
-%endif
%files %{python_files}
%license LICENSE
++++++ relatorio-0.8.1.tar.gz -> relatorio-0.9.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/relatorio-0.8.1/.drone.yml new/relatorio-0.9.0/.drone.yml
--- old/relatorio-0.8.1/.drone.yml 2018-08-18 13:27:26.000000000 +0200
+++ new/relatorio-0.9.0/.drone.yml 2019-07-29 15:52:57.000000000 +0200
@@ -17,8 +17,6 @@
include:
- IMAGE: python:2.7
TOXENV: py27
- - IMAGE: python:3.4
- TOXENV: py34
- IMAGE: python:3.5
TOXENV: py35
- IMAGE: python:3.6
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/relatorio-0.8.1/.hgtags new/relatorio-0.9.0/.hgtags
--- old/relatorio-0.8.1/.hgtags 2018-09-30 14:43:38.000000000 +0200
+++ new/relatorio-0.9.0/.hgtags 2019-07-29 16:01:09.000000000 +0200
@@ -25,3 +25,4 @@
8ee1d7515d35918944151d3a44003063e1ab6a18 0.7.1
0775b131b51d40c2147b1ae104f760698a8d9f9e 0.8.0
a9a586fec08da03f86ec781472a981949d4c455a 0.8.1
+a0cf6c5a86e3eaf125a96f942f64114b326dba3b 0.9.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/relatorio-0.8.1/CHANGES new/relatorio-0.9.0/CHANGES
--- old/relatorio-0.8.1/CHANGES 2018-09-30 14:42:26.000000000 +0200
+++ new/relatorio-0.9.0/CHANGES 2019-07-29 15:55:56.000000000 +0200
@@ -1,3 +1,7 @@
+0.9.0 - 20190729
+* Support out parameter of render
+* Write opendocument stream directly to the ZipFile
+
0.8.1 - 20180930
* Add support for Python 3.7
* Escape invalid XML characters
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/relatorio-0.8.1/PKG-INFO new/relatorio-0.9.0/PKG-INFO
--- old/relatorio-0.8.1/PKG-INFO 2018-09-30 14:44:06.000000000 +0200
+++ new/relatorio-0.9.0/PKG-INFO 2019-07-29 16:02:35.000000000 +0200
@@ -1,12 +1,13 @@
-Metadata-Version: 1.1
+Metadata-Version: 2.1
Name: relatorio
-Version: 0.8.1
+Version: 0.9.0
Summary: A templating library able to output odt and pdf files
Home-page: http://relatorio.tryton.org/
-Author: Cedric Krier
-Author-email: cedric.krier@b2ck.com
+Author: Nicolas Evrard
+Author-email: nicolas.evrard@b2ck.com
+Maintainer: Cedric Krier
+Maintainer-email: cedric.krier@b2ck.com
License: GPL License
-Description-Content-Type: UNKNOWN
Description: Relatorio
=========
@@ -31,3 +32,5 @@
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Text Processing
+Provides-Extra: fodt
+Provides-Extra: chart
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/relatorio-0.8.1/doc/conf.py new/relatorio-0.9.0/doc/conf.py
--- old/relatorio-0.8.1/doc/conf.py 2018-08-18 13:27:26.000000000 +0200
+++ new/relatorio-0.9.0/doc/conf.py 2019-07-29 15:57:29.000000000 +0200
@@ -48,9 +48,9 @@
# built documents.
#
# The short X.Y version.
-version = '0.8'
+version = '0.9'
# The full version, including alpha/beta/rc tags.
-release = '0.8.1'
+release = '0.9.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Binary files old/relatorio-0.8.1/examples/big.odt and new/relatorio-0.9.0/examples/big.odt differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/relatorio-0.8.1/examples/demo_context.py new/relatorio-0.9.0/examples/demo_context.py
--- old/relatorio-0.8.1/examples/demo_context.py 2018-08-18 13:27:26.000000000 +0200
+++ new/relatorio-0.9.0/examples/demo_context.py 2018-11-09 16:41:53.000000000 +0100
@@ -1,3 +1,4 @@
+from __future__ import print_function
from os.path import abspath, join, dirname
from relatorio import Report
@@ -6,9 +7,9 @@
# PDF
if __name__ == '__main__':
- print "generating output_basic.pdf... ",
+ print("generating output_basic.pdf... ", end='')
report = Report(abspath(join(dirname(__file__), 'basic.tex')),
'application/pdf')
content = report(o=inv).render().getvalue()
open(join(dirname(__file__), 'output_basic.pdf'), 'wb').write(content)
- print "done"
+ print("done")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/relatorio-0.8.1/examples/demo_odf.py new/relatorio-0.9.0/examples/demo_odf.py
--- old/relatorio-0.8.1/examples/demo_odf.py 2018-08-18 13:27:26.000000000 +0200
+++ new/relatorio-0.9.0/examples/demo_odf.py 2018-11-09 22:48:09.000000000 +0100
@@ -1,3 +1,4 @@
+from __future__ import print_function
from os.path import abspath, join, dirname
from relatorio import Report
from relatorio.templates import opendocument
@@ -12,21 +13,21 @@
if __name__ == '__main__':
pwd = dirname(__file__)
# ODT
- print "generating output_basic.odt... ",
+ print("generating output_basic.odt... ", end='')
report = Report(abspath(join(dirname(__file__), 'basic.odt')), ODT_MIME)
content = report(o=inv).render().getvalue()
open(join(pwd, 'output_basic.odt'), 'wb').write(content)
- print "done"
+ print("done")
# we could also use an opendocument template directly
- print "generating output_template_basic.odt... ",
+ print("generating output_template_basic.odt... ", end='')
template = opendocument.Template(source='',
filepath=abspath(join(pwd, 'basic.odt')))
content = template.generate(o=inv).render().getvalue()
open(join(pwd, 'output_template_basic.odt'), 'wb').write(content)
- print "done"
+ print("done")
- print "generating output_complicated.odt... ",
+ print("generating output_complicated.odt... ", end='')
# Add a chart to the invoice
inv['chart'] = (
Report(abspath(join(pwd, 'pie_chart')), 'image/png'), 'image/png')
@@ -34,35 +35,41 @@
try:
content = report(o=inv).render().getvalue()
except NotImplementedError:
- print "skipped"
+ print("skipped")
else:
open(join(pwd, 'output_complicated.odt'), 'wb').write(content)
- print "done"
+ print("done")
- print "generating output_columns.odt... ",
+ print("generating output_columns.odt... ", end='')
report = Report(abspath(join(pwd, 'columns.odt')), ODT_MIME)
lst = [[], ['i'], ['a', 'b'], [1, 2, 3], ['I', 'II', 'III', 'IV']]
titles = ['first', 'second', 'third', 'fourth']
content = report(titles=titles, lst=lst).render().getvalue()
open(join(pwd, 'output_columns.odt'), 'wb').write(content)
- print "done"
+ print("done")
# ODS
- print "generating output_pivot.ods... ",
+ print("generating output_pivot.ods... ", end='')
report = Report(abspath(join(pwd, 'pivot.ods')), ODS_MIME)
content = report(o=inv).render().getvalue()
open(join(pwd, 'output_pivot.ods'), 'wb').write(content)
- print "done"
+ print("done")
- print "generating output_sheets.ods... ",
+ print("generating output_sheets.ods... ", end='')
report = Report(abspath(join(pwd, 'demo_sheets.ods')), ODS_MIME)
content = report(lst=lst).render().getvalue()
open(join(pwd, 'output_sheets.ods'), 'wb').write(content)
- print "done"
+ print("done")
# ODP
- print "generating output_presentation.odp... ",
+ print("generating output_presentation.odp... ", end='')
report = Report(abspath(join(pwd, 'presentation.odp')), ODP_MIME)
content = report(o=inv).render().getvalue()
open(join(pwd, 'output_presentation.odp'), 'wb').write(content)
- print "done"
+ print("done")
+
+ # Big document
+ print("generating output_big.odt... ", end='')
+ report = Report(abspath(join(pwd, 'big.odt')), ODT_MIME)
+ content = report().render(out=open(join(pwd, 'output_big.odt'), 'wb'))
+ print("done")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/relatorio-0.8.1/examples/demo_repository.py new/relatorio-0.9.0/examples/demo_repository.py
--- old/relatorio-0.8.1/examples/demo_repository.py 2018-08-18 13:27:26.000000000 +0200
+++ new/relatorio-0.9.0/examples/demo_repository.py 2018-11-09 16:41:53.000000000 +0100
@@ -1,3 +1,4 @@
+from __future__ import print_function
import relatorio
from common import Invoice, inv
from os.path import join, dirname
@@ -25,8 +26,8 @@
('pivot', '.ods'),
('presentation', '.odp')):
filename = 'output_%s%s' % (report_name, ext)
- print "generating '%s'..." % filename,
+ print("generating '%s'..." % filename, end='')
report, mimetype, desc = repository.by_id(Invoice, report_name)
data = report(o=inv).render().getvalue()
open(join(dirname(__file__), filename), 'wb').write(data)
- print "done"
+ print("done")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/relatorio-0.8.1/relatorio/__init__.py new/relatorio-0.9.0/relatorio/__init__.py
--- old/relatorio-0.8.1/relatorio/__init__.py 2018-08-18 13:27:26.000000000 +0200
+++ new/relatorio-0.9.0/relatorio/__init__.py 2019-07-29 15:56:20.000000000 +0200
@@ -12,5 +12,5 @@
from .reporting import MIMETemplateLoader, ReportRepository, Report
from . import templates
-__version__ = '0.8.1'
+__version__ = '0.9.0'
__all__ = ['MIMETemplateLoader', 'ReportRepository', 'Report', 'templates']
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/relatorio-0.8.1/relatorio/templates/base.py new/relatorio-0.9.0/relatorio/templates/base.py
--- old/relatorio-0.8.1/relatorio/templates/base.py 2018-08-18 13:27:26.000000000 +0200
+++ new/relatorio-0.9.0/relatorio/templates/base.py 2018-11-09 22:48:09.000000000 +0100
@@ -31,7 +31,8 @@
def render(self, method=None, encoding='utf-8', out=None, **kwargs):
"calls the serializer to render the template"
- return self.serializer(self.events)
+ return self.serializer(
+ self.events, method=method, encoding=encoding, out=out)
def serialize(self, method='xml', **kwargs):
"generates the bitstream corresponding to the template"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/relatorio-0.8.1/relatorio/templates/chart.py new/relatorio-0.9.0/relatorio/templates/chart.py
--- old/relatorio-0.8.1/relatorio/templates/chart.py 2018-08-18 13:27:26.000000000 +0200
+++ new/relatorio-0.9.0/relatorio/templates/chart.py 2018-11-09 22:48:09.000000000 +0100
@@ -68,10 +68,13 @@
def __init__(self):
self.text_serializer = genshi.output.TextSerializer()
- def __call__(self, stream):
+ def __call__(self, stream, method=None, encoding='utf-8', out=None):
if not PYCHA_TYPE:
raise NotImplementedError
- result = BytesIO()
+ if out is None:
+ result = BytesIO()
+ else:
+ result = out
yml = StringIO(_encode(self.text_serializer(stream)))
chart_yaml = yaml.load(yml.read())
chart_info = chart_yaml['chart']
@@ -95,6 +98,8 @@
elif chart_type == 'svg':
surface.finish()
- return result
+ if out is None:
+ return result
+
MIMETemplateLoader.add_factory('chart', Template, Template.id_function)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/relatorio-0.8.1/relatorio/templates/opendocument.py new/relatorio-0.9.0/relatorio/templates/opendocument.py
--- old/relatorio-0.8.1/relatorio/templates/opendocument.py 2018-08-18 13:27:26.000000000 +0200
+++ new/relatorio-0.9.0/relatorio/templates/opendocument.py 2019-07-29 16:00:49.000000000 +0200
@@ -28,6 +28,7 @@
import base64
import mimetypes
+import sys
import time
import urllib
import zipfile
@@ -114,9 +115,8 @@
class ImageHref:
"A class used to add images in the odf zipfile"
- def __init__(self, zfile, manifest, context):
- self.zip = zfile
- self.manifest = manifest
+ def __init__(self, serializer, context):
+ self.serializer = serializer
self.context = context.copy()
def __call__(self, expr):
@@ -132,9 +132,7 @@
name = md5(file_content).hexdigest()
path = 'Pictures/%s%s' % (
name, mimetypes.guess_extension(mimetype))
- if path not in self.zip.namelist():
- self.zip.writestr(path, file_content)
- self.manifest.add_file_entry(path, mimetype)
+ self.serializer.add_file(path, file_content, mimetype)
return {'{http://www.w3.org/1999/xlink}href': path}
@@ -264,6 +262,7 @@
self.inner_docs = []
self.has_col_loop = False
self._source = None
+ self._files = set()
super(Template, self).__init__(source, filepath, filename, loader,
encoding, lookup, allow_exec)
@@ -312,6 +311,7 @@
parsed = []
for fpath, fparsed in content_files + styles_files:
+ self._files.add(fpath)
parsed.append((genshi.core.PI, ('relatorio', fpath), None))
parsed += fparsed
@@ -408,12 +408,11 @@
% (self.filepath, expr)
elif expr != statement.text and statement.tag == text_a:
warn_msg = "url and text do not match in %s: %s != %s" \
- % (self.filepath, expr,
- statement.text.encode('utf-8'))
+ % (self.filepath, expr, statement.text)
if warn_msg:
if directive is not None and not is_opening:
warn_msg += " corresponding to opening tag '%s'" \
- % opened_tags[-1].text
+ % opened_tags[-1][0].text
warnings.warn(warn_msg)
if directive in GENSHI_CLOSING_DIRECTIVE:
@@ -822,10 +821,8 @@
def generate(self, *args, **kwargs):
"creates the RelatorioStream."
- serializer = OOSerializer(self._source)
- kwargs['__relatorio_make_href'] = ImageHref(serializer.outzip,
- serializer.manifest,
- kwargs)
+ serializer = OOSerializer(self._source, self._files)
+ kwargs['__relatorio_make_href'] = ImageHref(serializer, kwargs)
kwargs['__relatorio_make_dimension'] = ImageDimension(self.namespaces)
kwargs['__relatorio_guess_type'] = self._guess_type
kwargs['__relatorio_escape_invalid_chars'] = escape_xml_invalid_chars
@@ -848,6 +845,7 @@
col_filter = Transformer('//repeat[namespace-uri()="%s"]'
% RELATORIO_URI)
col_filter = col_filter.apply(transformation)
+ # Must consume the stream to fill counter
stream = Stream(list(stream), self.serializer) | col_filter
return RelatorioStream(stream, serializer)
@@ -1041,40 +1039,115 @@
return val
-class OOSerializer:
+class _AbstractZipWriteSplitStream(object):
+ def __init__(self, zipfile, chunksize=64):
+ self.zipfile = zipfile
+ self.chunksize = chunksize
- def __init__(self, source):
- self.inzip = get_zip_file(source)
- self.manifest = Manifest(self.inzip.read(MANIFEST))
- self.meta = Meta(self.inzip.read(META))
- self.new_oo = BytesIO()
- self.outzip = zipfile.ZipFile(
- self.new_oo, mode='w', compression=zipfile.ZIP_DEFLATED)
- self.xml_serializer = genshi.output.XMLSerializer()
+ def open(self, zinfo):
+ raise NotImplementedError
+
+ def close(self):
+ raise NotImplementedError
def __call__(self, stream):
- files = {}
for kind, data, pos in stream:
if kind == genshi.core.PI and data[0] == 'relatorio':
- stream_for = data[1]
+ self.open(data[1])
continue
- files.setdefault(stream_for, []).append((kind, data, pos))
+ yield kind, data, pos
+ self.close()
+
+ def write(self, data):
+ raise NotImplementedError
+
+
+if sys.version_info >= (3, 6):
+ class _ZipWriteSplitStream(_AbstractZipWriteSplitStream):
+ def __init__(self, *args, **kwargs):
+ super(_ZipWriteSplitStream, self).__init__(*args, **kwargs)
+ self._fp = None
+ self._buffer = []
+ self._zinfo = None
+
+ def open(self, zinfo):
+ if self._fp:
+ self.close()
+ self._zinfo = zinfo
+ self._fp = None
+
+ def close(self):
+ self.flush()
+ self._fp.close()
+ self._zinfo = None
+ self._fp = None
+
+ def write(self, data):
+ self._buffer.append(data)
+ if len(self._buffer) > self.chunksize:
+ self.flush()
+
+ def flush(self):
+ if not self._fp:
+ self._fp = self.zipfile.open(self._zinfo, mode='w')
+ self._fp.write(b''.join(self._buffer))
+ self._buffer.clear()
+else:
+ class _ZipWriteSplitStream(_AbstractZipWriteSplitStream):
+ def __init__(self, *args, **kwargs):
+ super(_ZipWriteSplitStream, self).__init__(*args, **kwargs)
+ self._fp = None
+ self._zinfo = None
+
+ def open(self, zinfo):
+ if self._fp:
+ self.close()
+ self._zinfo = zinfo
+ self._fp = BytesIO()
+
+ def close(self):
+ self._fp.seek(0)
+ self.zipfile.writestr(self._zinfo, self._fp.read())
+ self._zinfo = None
+ self._fp = None
+
+ def write(self, data):
+ self._fp.write(data)
+
+class OOSerializer:
+
+ def __init__(self, source, files, chunksize=64):
+ self.inzip = get_zip_file(source)
+ self.manifest = Manifest(self.inzip.read(MANIFEST))
+ self.meta = Meta(self.inzip.read(META))
+ self.xml_serializer = genshi.output.XMLSerializer()
+ self._files = files
+ self.chunksize = chunksize
+ self.outzip = None
+ self._deferred = None
+
+ def __call__(self, stream, method=None, encoding='utf-8', out=None):
+ if out is None:
+ result = BytesIO()
+ else:
+ result = out
+ self.outzip = zipfile.ZipFile(
+ result, mode='w', compression=zipfile.ZIP_DEFLATED)
+ self._deferred = []
+ files = {}
now = time.localtime()[:6]
manifest_info = None
for f_info in self.inzip.infolist():
if f_info.filename.startswith('ObjectReplacements'):
continue
- elif f_info.filename in files:
- stream = files[f_info.filename]
+ elif f_info.filename in self._files:
# create a new file descriptor, copying some attributes from
# the original file
new_info = zipfile.ZipInfo(f_info.filename, now)
for attr in ('compress_type', 'flag_bits', 'create_system'):
setattr(new_info, attr, getattr(f_info, attr))
- serialized_stream = output_encode(self.xml_serializer(stream),
- encoding='utf-8')
- self.outzip.writestr(new_info, serialized_stream)
+ files[f_info.filename] = new_info
elif f_info.filename == MANIFEST:
manifest_info = f_info
elif f_info.filename == META:
@@ -1083,12 +1156,29 @@
self.manifest.remove_file_entry(f_info.filename)
else:
self.outzip.writestr(f_info, self.inzip.read(f_info.filename))
+
+ writer = _ZipWriteSplitStream(self.outzip, self.chunksize)
+ output_encode(
+ self.xml_serializer(writer(stream)), encoding=encoding, out=writer)
+
+ for args in self._deferred:
+ self.add_file(*args)
self.manifest.remove_file_entry(THUMBNAILS + '/')
if manifest_info:
self.outzip.writestr(manifest_info, str(self.manifest))
self.inzip.close()
self.outzip.close()
- return self.new_oo
+ if out is None:
+ return result
+
+ def add_file(self, path, content, mimetype):
+ if self.outzip and path not in self.outzip.namelist():
+ try:
+ self.outzip.writestr(path, content)
+ self.manifest.add_file_entry(path, mimetype)
+ except ValueError:
+ self._deferred.append((path, content, mimetype))
+
MIMETemplateLoader.add_factory('oo.org', Template)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/relatorio-0.8.1/relatorio/templates/pdf.py new/relatorio-0.9.0/relatorio/templates/pdf.py
--- old/relatorio-0.8.1/relatorio/templates/pdf.py 2018-08-18 13:27:26.000000000 +0200
+++ new/relatorio-0.9.0/relatorio/templates/pdf.py 2018-11-09 22:48:09.000000000 +0100
@@ -48,23 +48,30 @@
class PDFSerializer:
def __init__(self):
- self.working_dir = tempfile.mkdtemp(prefix='relatorio')
- self.tex_file = os.path.join(self.working_dir, 'report.tex')
- self.pdf_file = os.path.join(self.working_dir, 'report.pdf')
self.text_serializer = genshi.output.TextSerializer()
- def __call__(self, stream):
- tex_file = open(self.tex_file, 'w')
- tex_file.write(_encode(self.text_serializer(stream)))
- tex_file.close()
+ def __call__(self, stream, method=None, encoding='utf-8', out=None):
+ if out is None:
+ result = BytesIO()
+ else:
+ result = out
+ working_dir = tempfile.mkdtemp(prefix='relatorio')
+ tex_file = os.path.join(working_dir, 'report.tex')
+ pdf_file = os.path.join(working_dir, 'report.pdf')
+
+ with open(tex_file, 'w') as fp:
+ fp.write(_encode(self.text_serializer(stream)))
subprocess.check_call([TEXEXEC, '--purge', 'report.tex'],
- cwd=self.working_dir)
+ cwd=working_dir)
+
+ with open(pdf_file, 'r') as fp:
+ result.write(fp.read())
+
+ shutil.rmtree(working_dir, ignore_errors=True)
- pdf = BytesIO()
- pdf.write(open(self.pdf_file, 'r').read())
+ if out is None:
+ return result
- shutil.rmtree(self.working_dir, ignore_errors=True)
- return pdf
MIMETemplateLoader.add_factory('pdf', Template)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/relatorio-0.8.1/relatorio/tests/test_odt.py new/relatorio-0.9.0/relatorio/tests/test_odt.py
--- old/relatorio-0.8.1/relatorio/tests/test_odt.py 2018-08-18 13:27:26.000000000 +0200
+++ new/relatorio-0.9.0/relatorio/tests/test_odt.py 2019-07-29 16:00:49.000000000 +0200
@@ -230,6 +230,49 @@
self.assertTrue(last_row_node.get("value")
.startswith('__relatorio_store_col_count'))
+ @unittest.skipIf(
+ not getattr(unittest.TestCase, 'assertWarnsRegex', None),
+ "assertWarns not supported")
+ def test_statement_no_text_warning(self):
+ "Test warning for missing statement text"
+ xml = b'''<xml xmlns:text="urn:text" xmlns:xlink="urn:xlink">
+
+ </xml>'''
+
+ with self.assertWarnsRegex(
+ UserWarning, r"No statement text in '.*' for 'content:foo'"):
+ self.oot.insert_directives(xml)
+
+ @unittest.skipIf(
+ not getattr(unittest.TestCase, 'assertWarnsRegex', None),
+ "assertWarns not supported")
+ def test_statement_missmatch_text_warning(self):
+ "Test warning for missing statement text"
+ xml = b'''<xml xmlns:text="urn:text" xmlns:xlink="urn:xlink">
+ content:bar
+ </xml>'''
+
+ with self.assertWarnsRegex(
+ UserWarning,
+ r"url and text do not match in .*: "
+ "content:foo != content:bar"):
+ self.oot.insert_directives(xml)
+
+ @unittest.skipIf(
+ not getattr(unittest.TestCase, 'assertWarnsRegex', None),
+ "assertWarns not supported")
+ def test_statement_text_warning_closing(self):
+ "Test warning for statement text in closing"
+ xml = b'''<xml xmlns:text="urn:text" xmlns:xlink="urn:xlink">
+ with foo='test'
+
+ </xml>'''
+
+ with self.assertWarnsRegex(
+ UserWarning,
+ r".* corresponding to opening tag 'with foo='test'"):
+ self.oot.insert_directives(xml)
+
def test_text_outside_p(self):
"Testing that the tail text of a directive node is handled properly"
xml = b'''<xml xmlns:text="urn:text" xmlns:xlink="urn:xlink">
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/relatorio-0.8.1/relatorio.egg-info/PKG-INFO new/relatorio-0.9.0/relatorio.egg-info/PKG-INFO
--- old/relatorio-0.8.1/relatorio.egg-info/PKG-INFO 2018-09-30 14:44:06.000000000 +0200
+++ new/relatorio-0.9.0/relatorio.egg-info/PKG-INFO 2019-07-29 16:02:34.000000000 +0200
@@ -1,12 +1,13 @@
-Metadata-Version: 1.1
+Metadata-Version: 2.1
Name: relatorio
-Version: 0.8.1
+Version: 0.9.0
Summary: A templating library able to output odt and pdf files
Home-page: http://relatorio.tryton.org/
-Author: Cedric Krier
-Author-email: cedric.krier@b2ck.com
+Author: Nicolas Evrard
+Author-email: nicolas.evrard@b2ck.com
+Maintainer: Cedric Krier
+Maintainer-email: cedric.krier@b2ck.com
License: GPL License
-Description-Content-Type: UNKNOWN
Description: Relatorio
=========
@@ -31,3 +32,5 @@
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Text Processing
+Provides-Extra: fodt
+Provides-Extra: chart
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/relatorio-0.8.1/relatorio.egg-info/SOURCES.txt new/relatorio-0.9.0/relatorio.egg-info/SOURCES.txt
--- old/relatorio-0.8.1/relatorio.egg-info/SOURCES.txt 2018-09-30 14:44:06.000000000 +0200
+++ new/relatorio-0.9.0/relatorio.egg-info/SOURCES.txt 2019-07-29 16:02:35.000000000 +0200
@@ -28,6 +28,7 @@
doc/relatorio_basic.png
examples/basic.odt
examples/basic.tex
+examples/big.odt
examples/bouteille.png
examples/columns.odt
examples/common.py