[tryton-debian-vcs] relatorio branch py3-WIP updated. debian/0.6.0-3-7-g0d813af
Mathias Behrle
tryton-debian-vcs at alioth.debian.org
Fri Apr 10 18:48:12 UTC 2015
The following commit has been merged in the py3-WIP branch:
https://alioth.debian.org/plugins/scmgit/cgi-bin/gitweb.cgi/?p=tryton/relatorio.git;a=commitdiff;h=debian/0.6.0-3-7-g0d813af
commit 0d813af9969a0f009e03be841d670b7e8625d669
Author: Mathias Behrle <mathiasb at m9s.biz>
Date: Fri Apr 10 20:47:53 2015 +0200
Updating for current unreleased version 0.6.2.
diff --git a/debian/changelog b/debian/changelog
index 2d3178c..36dba63 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,30 @@
+relatorio (0.6.2-1) unstable; urgency=medium
+
+ * Test release
+
+ -- Mathias Behrle <mathiasb at m9s.biz> Wed, 08 Oct 2014 19:21:25 +0200
+
+relatorio (0.6.1-2) unstable; urgency=medium
+
+ * Adding actual upstream signing key.
+ * Updating to Standards-Version: 3.9.6, no changes needed.
+
+ -- Mathias Behrle <mathiasb at m9s.biz> Wed, 08 Oct 2014 19:21:24 +0200
+
+relatorio (0.6.1-1) unstable; urgency=medium
+
+ * Removing LC_ALL=C.UTF-8 as build environment.
+ * Removing accidently doubled option pgpsigurlmangle from watch file.
+ * Updating signing key while using now plain .asc files instead of .pgp
+ binaries.
+ * Removing examples file, there are none.
+ * Updating gbp.conf for the usage of the tarball compression.
+ * Merging upstream version 0.6.1.
+ * Updating copyright.
+ * Enabling tests for Python2.
+
+ -- Mathias Behrle <mathiasb at m9s.biz> Fri, 12 Sep 2014 14:20:50 +0200
+
relatorio (0.6.0-3) unstable; urgency=medium
* Updating year in debian copyright.
diff --git a/debian/control b/debian/control
index 2b259f0..1e35002 100644
--- a/debian/control
+++ b/debian/control
@@ -4,10 +4,17 @@ Priority: optional
Maintainer: Debian Tryton Maintainers <maintainers at debian.tryton.org>
Uploaders: Mathias Behrle <mathiasb at m9s.biz>
Build-Depends:
- debhelper (>= 9), python (>= 2.6.6-3~), python3 (>= 3.3.0-2~), dh-python,
- python-setuptools, python3-setuptools, python-genshi, python3-genshi,
- python-lxml, python3-lxml, python-nose, python3-nose
-Standards-Version: 3.9.5
+ debhelper (>= 9),
+ dh-python,
+ python (>= 2.6.6-3~),
+ python-genshi,
+ python-lxml,
+ python-setuptools,
+ python3 (>= 3.3.0-2~),
+ python3-genshi,
+ python3-lxml,
+ python3-setuptools,
+Standards-Version: 3.9.6
Homepage: http://code.google.com/p/python-relatorio/
Vcs-Browser: http://anonscm.debian.org/gitweb/?p=tryton/relatorio.git
Vcs-Git: git://anonscm.debian.org/tryton/relatorio.git
@@ -17,8 +24,11 @@ X-Python3-Version: >= 3.2
Package: python-relatorio
Architecture: all
Depends:
- ${misc:Depends}, ${python:Depends}, python-genshi, python-lxml,
- python-pkg-resources
+ python-genshi,
+ python-lxml,
+ python-pkg-resources,
+ ${misc:Depends},
+ ${python:Depends},
Suggests: python-pycha, python-yaml
Description: Python module to create reports from Python objects (Python2)
This is a Python module to create reports from Python objects. Output plugins
@@ -30,8 +40,11 @@ Description: Python module to create reports from Python objects (Python2)
Package: python3-relatorio
Architecture: all
Depends:
- ${misc:Depends}, ${python3:Depends}, python3-genshi, python3-lxml,
- python3-pkg-resources
+ python3-genshi,
+ python3-lxml,
+ python3-pkg-resources,
+ ${misc:Depends},
+ ${python3:Depends},
Suggests: python3-yaml
Description: Python module to create reports from Python objects (Python3)
This is a Python module to create reports from Python objects. Output plugins
diff --git a/debian/copyright b/debian/copyright
index 01533cd..b3775c9 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -4,9 +4,29 @@ Files: *
Copyright: 2007-2008 OpenHex SPRL <http://www.openhex.com/>
License: GPL-3+
+Files: relatorio/templates/chart.py
+Copyright: 2007-2008 OpenHex SPRL <http://www.openhex.com/>
+ 2014 Cedric Krier
+License: GPL-3+
+
Files: relatorio/templates/opendocument.py
Copyright: 2007-2008 OpenHex SPRL <http://www.openhex.com/>
- 2009-2013 Cedric Krier
+ 2009-2014 Cedric Krier
+License: GPL-3+
+
+Files: relatorio/templates/pdf.py
+Copyright: 2007-2008 OpenHex SPRL <http://www.openhex.com/>
+ 2014 Cedric Krier
+License: GPL-3+
+
+Files: relatorio/tests/test_api.py
+Copyright: 2007-2008 OpenHex SPRL <http://www.openhex.com/>
+ 2014 Cedric Krier
+License: GPL-3+
+
+Files: relatorio/tests/test_odt.py
+Copyright: 2007-2008 OpenHex SPRL <http://www.openhex.com/>
+ 2014 Cedric Krier
License: GPL-3+
Files: debian/*
diff --git a/debian/gbp.conf b/debian/gbp.conf
index f1cc3fc..6ec8758 100644
--- a/debian/gbp.conf
+++ b/debian/gbp.conf
@@ -7,8 +7,9 @@ pristine-tar = True
[git-buildpackage]
ignore-new = True
-# Use with orig.tar.xz tarballs, subject to change in the future
-compression = xz
+# Use with orig.tar.xz tarballs, used for releases 0.5.7 to 0.6.0
+# Currently we are using upstream compression, which is gz
+#compression = xz
# Use export-dir at your discretion to avoid git-buildpackage messing
# your git repeository
#export-dir = ../build-area/
diff --git a/debian/patches/python3.patch b/debian/patches/python3.patch
deleted file mode 100644
index f4b83f2..0000000
--- a/debian/patches/python3.patch
+++ /dev/null
@@ -1,271 +0,0 @@
-Description: <short summary of the patch>
- TODO: Put a short summary on the line above and replace this paragraph
- with a longer explanation of this change. Complete the meta-information
- with other relevant fields (see below for details). To make it easier, the
- information below has been extracted from the changelog. Adjust it or drop
- it.
- .
- relatorio (0.6.0-3) unstable; urgency=medium
- .
- * Updating year in debian copyright.
- * Removing debian/source/options, we are building with dpkg defaults.
- * Removing PYBUILD_NAME from rules, it is no more needed.
- * Adding pgp verification for uscan.
- * Adding gbp.conf for usage with git-buildpackage.
- * Updating Hompage url of the upstream project in control.
-Author: Mathias Behrle <mathiasb at m9s.biz>
-
----
-The information above should follow the Patch Tagging Guidelines, please
-checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here
-are templates for supplementary fields that you might want to add:
-
-Origin: <vendor|upstream|other>, <url of original patch>
-Bug: <url in upstream bugtracker>
-Bug-Debian: http://bugs.debian.org/<bugnumber>
-Bug-Ubuntu: https://launchpad.net/bugs/<bugnumber>
-Forwarded: <no|not-needed|url proving that it has been forwarded>
-Reviewed-By: <name and email of someone who approved the patch>
-Last-Update: <YYYY-MM-DD>
-
---- relatorio.orig/relatorio/__init__.py 2014-07-08 20:13:57.306941929 +0200
-+++ relatorio/relatorio/__init__.py 2014-07-08 20:13:57.302942064 +0200
-@@ -9,7 +9,7 @@
- relatorio also provides a report repository allowing you to link python objects
- and report together, find reports by mimetypes/name/python objects.
- """
--from relatorio.reporting import MIMETemplateLoader, ReportRepository, Report
--import templates
-+from .reporting import MIMETemplateLoader, ReportRepository, Report
-+from . import templates
-
- __version__ = '0.6.0'
---- relatorio.orig/relatorio/templates/__init__.py 2014-07-08 20:13:57.306941929 +0200
-+++ relatorio/relatorio/templates/__init__.py 2014-07-08 20:17:01.104716091 +0200
-@@ -18,26 +18,17 @@
- #
- ###############################################################################
-
--import traceback
- import warnings
--try:
-- from cStringIO import StringIO
--except ImportError:
-- from StringIO import StringIO
-
- plugins = ['base', 'opendocument', 'pdf', 'chart']
-
- for name in plugins:
- try:
- __import__('relatorio.templates.%s' % name)
-- except Exception, e:
-- tb_file = StringIO()
--
-- print >> tb_file, ("Unable to load plugin '%s', you will not be able "
-- "to use it" % name)
-- print >> tb_file
-- print >> tb_file, 'Original traceback:'
-- print >> tb_file, '-------------------'
-- traceback.print_exc(file=tb_file)
-- print >> tb_file
-- warnings.warn(tb_file.getvalue())
-+ except Exception as e:
-+ msg = "Unable to load plugin '%s', you will not be able to use it" \
-+ % name
-+ msg += '\nOriginal traceback:\n'
-+ msg += '-------------------\n'
-+ msg += str(e)
-+ warnings.warn(msg)
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ relatorio/relatorio/templates/_compat.py 2014-07-08 20:13:57.302942064 +0200
-@@ -0,0 +1,7 @@
-+try:
-+ from io import BytesIO
-+except ImportError:
-+ try:
-+ from cStringIO import StringIO as BytesIO
-+ except ImportError:
-+ from StringIO import StringIO as BytesIO
---- relatorio.orig/relatorio/templates/chart.py 2014-07-08 20:13:57.306941929 +0200
-+++ relatorio/relatorio/templates/chart.py 2014-07-08 20:13:57.302942064 +0200
-@@ -20,10 +20,7 @@
-
- __metaclass__ = type
-
--try:
-- from cStringIO import StringIO
--except ImportError:
-- from StringIO import StringIO
-+from ._compat import BytesIO
-
- import yaml
- import genshi
-@@ -67,8 +64,8 @@
- self.text_serializer = genshi.output.TextSerializer()
-
- def __call__(self, stream):
-- result = StringIO()
-- yml = StringIO(_encode(self.text_serializer(stream)))
-+ result = BytesIO()
-+ yml = BytesIO(_encode(self.text_serializer(stream)))
- chart_yaml = yaml.load(yml.read())
- chart_info = chart_yaml['chart']
- chart_type = chart_info['output_type']
---- relatorio.orig/relatorio/templates/opendocument.py 2014-07-08 20:13:57.306941929 +0200
-+++ relatorio/relatorio/templates/opendocument.py 2014-07-08 20:13:57.302942064 +0200
-@@ -22,6 +22,7 @@
- __metaclass__ = type
-
- import re
-+import sys
- try:
- # requires python 2.5+
- from hashlib import md5
-@@ -31,13 +32,7 @@
- import time
- import urllib
- import zipfile
--try:
-- from io import BytesIO
--except ImportError:
-- try:
-- from cStringIO import StringIO as BytesIO
-- except ImportError:
-- from StringIO import StringIO as BytesIO
-+from ._compat import BytesIO
- from copy import deepcopy
- import datetime
- from decimal import Decimal
-@@ -108,9 +103,13 @@
- # the nsmap attribute of Element objects is (currently) readonly.
-
- def guess_type(val):
-- if isinstance(val, (str, unicode)):
-- return 'string'
-- elif isinstance(val, (int, float, long, Decimal)):
-+ if sys.version_info < (3,):
-+ if isinstance(val, (str, unicode)):
-+ return 'string'
-+ else:
-+ if isinstance(val, str):
-+ return 'string'
-+ if isinstance(val, (int, float, long, Decimal)):
- return 'float'
-
-
-@@ -355,7 +354,12 @@
- if statement.tag == placeholder:
- expr = statement.text[1:-1]
- elif statement.tag == text_a:
-- expr = urllib.unquote(statement.attrib[xlink_href_attrib][12:])
-+ if sys.version_info < (3,):
-+ expr = urllib.unquote(
-+ statement.attrib[xlink_href_attrib][12:])
-+ else:
-+ expr = urllib.parse.unquote(
-+ statement.attrib[xlink_href_attrib][12:])
-
- if not expr:
- raise OOTemplateError("No expression in the tag",
-@@ -499,8 +503,10 @@
- repeat_tag = '{%s}repeat' % RELATORIO_URI
-
- # table node (it is not necessarily the direct parent of ancestor)
-- table_node = ancestor.iterancestors('{%s}table' % table_namespace) \
-- .next()
-+ #table_node = ancestor.iterancestors('{%s}table' % table_namespace) \
-+ # .next()
-+ table_node = next(ancestor.iterancestors('{%s}table' %
-+ table_namespace))
- table_name = table_node.attrib['{%s}name' % table_namespace]
-
- # add counting instructions
---- relatorio.orig/relatorio/templates/pdf.py 2014-07-08 20:13:57.306941929 +0200
-+++ relatorio/relatorio/templates/pdf.py 2014-07-08 20:13:57.302942064 +0200
-@@ -24,10 +24,7 @@
- import shutil
- import tempfile
- import subprocess
--try:
-- from cStringIO import StringIO
--except ImportError:
-- from StringIO import StringIO
-+from ._compat import BytesIO
-
- import genshi
- import genshi.output
-@@ -63,7 +60,7 @@
- subprocess.check_call([TEXEXEC, '--purge', 'report.tex'],
- cwd=self.working_dir)
-
-- pdf = StringIO()
-+ pdf = BytesIO()
- pdf.write(open(self.pdf_file, 'r').read())
-
- shutil.rmtree(self.working_dir, ignore_errors=True)
---- relatorio.orig/relatorio/tests/test_odt.py 2014-07-08 20:13:57.306941929 +0200
-+++ relatorio/relatorio/tests/test_odt.py 2014-07-08 20:13:57.302942064 +0200
-@@ -21,11 +21,8 @@
-
-
- import os
--try:
-- from cStringIO import StringIO
--except ImportError:
-- from StringIO import StringIO
--
-+import sys
-+from ..templates._compat import BytesIO
- import lxml.etree
- from nose.tools import *
- from genshi.filters import Translator
-@@ -49,10 +46,12 @@
- return catalog.get(string, string)
-
- def stream_to_string(stream):
-- # In Python 3, stream will be bytes
-- if not isinstance(stream, str):
-- return str(stream, 'utf-8')
-- return stream
-+ if sys.version_info < (3,):
-+ if not isinstance(stream, str):
-+ return buffer(str(stream, 'utf-8'))
-+ return stream
-+ else:
-+ return stream.decode('utf-8')
-
-
- class TestOOTemplating(object):
-@@ -60,7 +59,8 @@
- def setup(self):
- thisdir = os.path.dirname(__file__)
- filepath = os.path.join(thisdir, 'test.odt')
-- self.oot = Template(open(filepath, mode='rb'))
-+ with open(filepath, mode='rb') as fp:
-+ self.oot = Template(fp)
- self.data = {'first_name': u'Trente',
- 'last_name': u'Møller',
- 'ville': u'Liège',
-@@ -276,7 +276,10 @@
- stream = self.oot.generate(**self.data)
- rendered = stream_to_string(stream.events.render(encoding='utf-8'))
- styles_idx = rendered.find('<?relatorio styles.xml?>')
-- tree = lxml.etree.parse(StringIO(rendered[25:styles_idx]))
-+ r = rendered[25:styles_idx]
-+ if sys.version_info >= (3,):
-+ r = r.encode('utf-8')
-+ tree = lxml.etree.parse(BytesIO(r))
- root = tree.getroot()
- images = root.xpath('//draw:frame', namespaces=self.oot.namespaces)
- eq_(len(images), 3)
---- relatorio.orig/relatorio/tests/test_api.py 2014-07-08 20:13:57.306941929 +0200
-+++ relatorio/relatorio/tests/test_api.py 2014-07-08 20:13:57.302942064 +0200
-@@ -29,7 +29,7 @@
- class StubObject(object):
-
- def __init__(self, **kwargs):
-- for key, val in kwargs.iteritems():
-+ for key, val in kwargs.items():
- setattr(self, key, val)
-
-
diff --git a/debian/patches/series b/debian/patches/series
deleted file mode 100644
index a2fba86..0000000
--- a/debian/patches/series
+++ /dev/null
@@ -1 +0,0 @@
-python3.patch
diff --git a/debian/upstream/signing-key.asc b/debian/upstream/signing-key.asc
index 6fa6f15..3eabfa3 100644
--- a/debian/upstream/signing-key.asc
+++ b/debian/upstream/signing-key.asc
@@ -248,3 +248,475 @@ lrSuu4/ARphsFC1gfb0rcjdgmriTRVhL3tZO4i6kfd7qzAQr85qShIYY7RZp0WDe
dFPotSaWozR/BjY=
=ch1l
-----END PGP PUBLIC KEY BLOCK-----
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1
+
+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
+pvm+lnoNgb6Jq88/p0GZrfi3Jjlm+MN1+oIeLNrJ6So7QZKphSXhdJYpk3EUhPGT
+pyzIZemNODPRKameaSxmcvEWJpVPs0G0pC0Z2yqTnYQzUXVLSfYrRrFYEmvuNrQl
+Q8OpZHJpYyBLcmllciA8Y2VkcmljLmtyaWVyQGIyY2suY29tPokCNwQTAQgAIQUC
+SgVk3wIbAwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRA8rT/USZVWA014D/4w
+lB4weKktE18HrNgcqKPOx0vDSnFSftY05H1vePAnw9TbCi6KoQepjcod8Bt0WbTs
+p6L4m4eAywNNXnkcmAQ40Tc2ZckIrL8oYstbHaK/klAVib0Q+6ffg9reYYGtbikl
+r04RtY4LyqiiGgCACvvfjxKRtjrpsx6DPcb1MqQwoT6PLd/fu4+UQOXJOmcYpMah
+qZMMS0zyN9balAs5M/WOGDMD998WmGxs+kZ7SUuSTkeW95WrwgFpBgrSbyITc8NP
+qmsoZcZgcogPYrEw6bgq2bZ/DpmCW/M5nDb4n7oMQZ5NwF+BeIp6Uuh+asWFe/PW
+TGoJ7f4l3T4po2iJPszK5hvU9/r7WjddlCCWi8zpzspsSzOqF0y8Ne7Mp2sHpWEH
+x739VFvxySwtkv08YWjF1buiMo4Tswu2WbbCX4vt2LH1RXp/oleRlWlgMkpQSq+/
+AL7HFzWWurY6hf4WJQ3XKRYtaZIuqD6VcfdK167tZq6nDRnXAcZsDITeK8/yuOXo
+VkV3OHXU5M7wadySJLhfunZN3/K4pgEmv/mEJA+O1xuoiFI4qENaYBWuDTs2y5UD
+rxs3UX6Vz4Rqt2VkyqHdv9hDaVP+IErGUPqNmHUFuV1liTXIgFIE1Z7MQH67umRy
+pgK61jkzdgj7BrdrdxmhiE20SBX5xfm1lIBeoAsMsohGBBARCAAGBQJKBWauAAoJ
+EF1CVh5OpP8xoicAniJt+u9nZiJKK1SGrTPzqodGMhEVAKCbT5aPwgYB0rKxlENb
+k7gjPeHWs4hGBBARAgAGBQJOXMwnAAoJENXyeXM9f/tlE1IAoJaSz/2d81JSr78R
+AkzP8UNS+X4xAJ9xWTZkEV1ba9xqBeuOTXl3dvCxbYkCNwQTAQgAIQIbAwULCQgH
+AwUVCgkICwUWAgMBAAIeAQIXgAUCUnUdiAAKCRA8rT/USZVWA+H/D/9y74s8iyxZ
+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
+=vhyP
+-----END PGP PUBLIC KEY BLOCK-----
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1
+
+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
+BQJU4IgRAhsCBQkB4TOAAMoJEG/1Cv4DSJEwvyAEGREIAGYFAlTgiBFfFIAAAAAA
+LgAoaXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5l
+dDY2OTBGMzM2QUY4RUIxQ0EwRThGNDkzMkRBNjJDMUZCNEM1QTI4NTUACgkQ2mLB
++0xaKFXKkAEA+py4X5bgP6Qm72F/DSJIR7+Yo8Fv6myK7qxz4NQ7Wl0A/2gggIWK
+E52WiXcMm10ttc/4KkQXsvGRKOcpRjKgzyHItLUP/R6UIkg4PslTmTeYNAgfsfKE
+9gA0L0wbhjh9sHz8/4sKyFs9WGaTngVIsO7KxJ3Ak9Aqzrbe4xxma4tLqBBQsVWe
+1XjgZ38DDIV54gXLKVQcMAPnazlkYbuBBWnr2NhY5fy5coJ550nPT4NRqvDDs5fj
+ZBhn4E9jeUB+rGN4SxNQwzgqMdc86lXKCkrMK4TSBsFWWktLSRNw8tsdbVZCnro4
+C8zHegRi9iZQ08WQjW+GaYWGmDu7FJPHp0zbkfUoeaAoIlPHugfBTEK9ipUMi1Bp
+pPa4JZqw/Hw4HuPkXEgbz36GhUo+jeBJatfftyos4cOh3Z71czpw2tLI6T86JOFv
+aBJzwDh/QnF2VbVVdulmPp4F0Di14tKo9bNsk/LTRERuHZY6oypGCYw+V72uFsMA
+9854snXKTS9LnuesJb2jLvcW2umuZ3p4Qkpf9Q+3WHAl2pYhJKizImsJH24Kepdy
+tmROrRxJ8BjDM/8oscdvBQb45nlWsHyvJ8j9JdO994XlkbJd+TOJJ0vuly/6Tsrr
+aGuiT4XsCzPhsw7d0Ca4Axf5Eka97sktEBZij9wMd95atuYT9pqYEAav6EdXsehK
+XOJYg+1aKGo1I0E6uVVAYW8uni1od+BgI7wQgF9Y3oOItIrcETLH6Ty3+EUxkbzE
+Mr6rPW2WRhqTQgTMeD7j
+=77CA
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/debian/watch b/debian/watch
index f1103ae..4e7e41f 100644
--- a/debian/watch
+++ b/debian/watch
@@ -1,2 +1,3 @@
version=3
-opts=pgpsigurlmangle=s/$/.asc/ http://pypi.python.org/packages/source/r/relatorio/relatorio-(\d+.*)\.(?:tgz|tbz2|txz|tar\.(?:gz|bz2|xz))
+opts=uversionmangle=s/(rc|a|b|c)/~$1/,pgpsigurlmangle=s/$/.asc/ \
+http://pypi.debian.net/relatorio/relatorio-(.+)\.(?:zip|tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz)))
\ No newline at end of file
commit ad18dff09ed97146cc40f12291a98feae5b4c884
Author: Mathias Behrle <mathiasb at m9s.biz>
Date: Fri Apr 10 20:23:46 2015 +0200
Merging upstream version 0.6.2-211:42a05363db0d.
diff --git a/CHANGES b/CHANGES
index 15bec1b..b6cc3a1 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,11 @@
+* Remove table:end-cell-address from draw:frame as the address could be wrong
+* Remove nose
+* Add directives: attrs, content, replace and strip
+
+0.6.1 - 20140909
+* Use io module instead of StringIO
+* Explicitly close ZipFile
+
0.6.0 - 20130810
* Add support for Python 3
* Allow to pass only source to Template
diff --git a/PKG-INFO b/PKG-INFO
index e112e9f..500960e 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,8 +1,8 @@
Metadata-Version: 1.1
Name: relatorio
-Version: 0.6.0
+Version: 0.6.2
Summary: A templating library able to output odt and pdf files
-Home-page: http://relatorio.openhex.org/
+Home-page: http://code.google.com/p/python-relatorio/
Author: Cedric Krier
Author-email: cedric.krier at b2ck.com
License: GPL License
diff --git a/relatorio.egg-info/PKG-INFO b/relatorio.egg-info/PKG-INFO
index e112e9f..500960e 100644
--- a/relatorio.egg-info/PKG-INFO
+++ b/relatorio.egg-info/PKG-INFO
@@ -1,8 +1,8 @@
Metadata-Version: 1.1
Name: relatorio
-Version: 0.6.0
+Version: 0.6.2
Summary: A templating library able to output odt and pdf files
-Home-page: http://relatorio.openhex.org/
+Home-page: http://code.google.com/p/python-relatorio/
Author: Cedric Krier
Author-email: cedric.krier at b2ck.com
License: GPL License
diff --git a/relatorio.egg-info/requires.txt b/relatorio.egg-info/requires.txt
index a315bff..1929729 100644
--- a/relatorio.egg-info/requires.txt
+++ b/relatorio.egg-info/requires.txt
@@ -1,2 +1,2 @@
Genshi >= 0.5
-lxml >= 2.0
\ No newline at end of file
+lxml >= 2.0
diff --git a/relatorio/__init__.py b/relatorio/__init__.py
index 09888e1..91f89f1 100644
--- a/relatorio/__init__.py
+++ b/relatorio/__init__.py
@@ -9,7 +9,8 @@ easy: you just have to create a plugin for this.
relatorio also provides a report repository allowing you to link python objects
and report together, find reports by mimetypes/name/python objects.
"""
-from relatorio.reporting import MIMETemplateLoader, ReportRepository, Report
-import templates
+from .reporting import MIMETemplateLoader, ReportRepository, Report
+from . import templates
-__version__ = '0.6.0'
+__version__ = '0.6.2'
+__all__ = ['MIMETemplateLoader', 'ReportRepository', 'Report', 'templates']
diff --git a/relatorio/templates/__init__.py b/relatorio/templates/__init__.py
index a4bbb60..c514f00 100644
--- a/relatorio/templates/__init__.py
+++ b/relatorio/templates/__init__.py
@@ -18,26 +18,12 @@
#
###############################################################################
-import traceback
import warnings
-try:
- from cStringIO import StringIO
-except ImportError:
- from StringIO import StringIO
plugins = ['base', 'opendocument', 'pdf', 'chart']
for name in plugins:
try:
__import__('relatorio.templates.%s' % name)
- except Exception, e:
- tb_file = StringIO()
-
- print >> tb_file, ("Unable to load plugin '%s', you will not be able "
- "to use it" % name)
- print >> tb_file
- print >> tb_file, 'Original traceback:'
- print >> tb_file, '-------------------'
- traceback.print_exc(file=tb_file)
- print >> tb_file
- warnings.warn(tb_file.getvalue())
+ except ImportError:
+ warnings.warn("Unable to load plugin '%s'" % name)
diff --git a/relatorio/templates/chart.py b/relatorio/templates/chart.py
index 34d0770..b937fd9 100644
--- a/relatorio/templates/chart.py
+++ b/relatorio/templates/chart.py
@@ -1,5 +1,6 @@
###############################################################################
#
+# Copyright (c) 2014 Cedric Krier.
# Copyright (c) 2007, 2008 OpenHex SPRL. (http://openhex.com) All Rights
# Reserved.
#
@@ -20,10 +21,7 @@
__metaclass__ = type
-try:
- from cStringIO import StringIO
-except ImportError:
- from StringIO import StringIO
+from io import BytesIO
import yaml
import genshi
@@ -67,8 +65,8 @@ class CairoSerializer:
self.text_serializer = genshi.output.TextSerializer()
def __call__(self, stream):
- result = StringIO()
- yml = StringIO(_encode(self.text_serializer(stream)))
+ result = BytesIO()
+ yml = BytesIO(_encode(self.text_serializer(stream)))
chart_yaml = yaml.load(yml.read())
chart_info = chart_yaml['chart']
chart_type = chart_info['output_type']
diff --git a/relatorio/templates/opendocument.py b/relatorio/templates/opendocument.py
index 159eff0..f59143e 100644
--- a/relatorio/templates/opendocument.py
+++ b/relatorio/templates/opendocument.py
@@ -1,6 +1,6 @@
###############################################################################
#
-# Copyright (c) 2009-2013 Cedric Krier.
+# Copyright (c) 2009-2014 Cedric Krier.
# Copyright (c) 2007, 2008 OpenHex SPRL. (http://openhex.com) All Rights
# Reserved.
#
@@ -31,13 +31,7 @@ except ImportError:
import time
import urllib
import zipfile
-try:
- from io import BytesIO
-except ImportError:
- try:
- from cStringIO import StringIO as BytesIO
- except ImportError:
- from StringIO import StringIO as BytesIO
+from io import BytesIO
from copy import deepcopy
import datetime
from decimal import Decimal
@@ -65,12 +59,20 @@ except ImportError:
GENSHI_EXPR = re.compile(r'''
(/)? # is this a closing tag?
- (for|if|choose|when|otherwise|with) # tag directive
+ (for|if|choose|when|otherwise|with|
+ attrs|content|replace|strip) # tag directive
\s*
- (?:\s(\w+)=["'](.*)["']|$) # match a single attr & its value
+ (?:\s([\w:-]+)=["'](.*)["']|$) # match a single attr & its value
|
.* # or anything else
''', re.VERBOSE)
+GENSHI_CLOSING_DIRECTIVE = ['for',
+ 'if',
+ 'choose',
+ 'when',
+ 'otherwise',
+ 'with',
+ ]
EXTENSIONS = {'image/png': 'png',
'image/jpeg': 'jpg',
@@ -225,7 +227,7 @@ def update_py_attrs(node, value):
if not value:
return
py_attrs_attr = '{%s}attrs' % GENSHI_URI
- if not py_attrs_attr in node.attrib:
+ if py_attrs_attr not in node.attrib:
node.attrib[py_attrs_attr] = value
else:
node.attrib[py_attrs_attr] = \
@@ -240,7 +242,7 @@ class Template(MarkupTemplate):
self.namespaces = {}
self.inner_docs = []
self.has_col_loop = False
- self._zip_source = None
+ self._source = None
super(Template, self).__init__(source, filepath, filename, loader,
encoding, lookup, allow_exec)
@@ -261,7 +263,9 @@ class Template(MarkupTemplate):
source = BytesIO(source.read())
else:
source = self.filepath
- self._zip_source = zf = zipfile.ZipFile(source)
+ self._source = source
+ self.filepath = None # Prevent zip content in traceback
+ zf = zipfile.ZipFile(source)
content = zf.read('content.xml')
styles = zf.read('styles.xml')
@@ -283,6 +287,7 @@ class Template(MarkupTemplate):
encoding)
content_files.append((c_path, c_parsed))
styles_files.append((s_path, s_parsed))
+ zf.close()
parsed = []
for fpath, fparsed in content_files + styles_files:
@@ -361,7 +366,7 @@ class Template(MarkupTemplate):
raise OOTemplateError("No expression in the tag",
self.filepath)
closing, directive, attr, attr_val = \
- GENSHI_EXPR.match(expr).groups()
+ GENSHI_EXPR.match(expr).groups()
is_opening = closing != '/'
warn_msg = None
@@ -378,7 +383,7 @@ class Template(MarkupTemplate):
% opened_tags[-1].text
warnings.warn(warn_msg)
- if directive is not None:
+ if directive in GENSHI_CLOSING_DIRECTIVE:
# map closing tags with their opening tag
if is_opening:
opened_tags.append(statement)
@@ -413,7 +418,7 @@ class Template(MarkupTemplate):
expr, directive, attr, a_val = parsed
# If the node is a genshi directive statement:
- if directive is not None:
+ if directive in GENSHI_CLOSING_DIRECTIVE:
opening = r_node
closing = closing_tags[id(r_node)]
@@ -436,7 +441,7 @@ class Template(MarkupTemplate):
pass
o_ancestors.append(node)
assert ancestor is not None, \
- "No common ancestor found for opening and closing tag"
+ "No common ancestor found for opening and closing tag"
outermost_o_ancestor = o_ancestors[-1]
outermost_c_ancestor = c_ancestors[-1]
@@ -465,6 +470,21 @@ class Template(MarkupTemplate):
# - we delete the closing statement (and its ancestors)
wrap_nodes_between(outermost_o_ancestor, outermost_c_ancestor,
genshi_node)
+ elif directive:
+ # find the first parent with the same tag name as the attribute
+ parent = r_node
+ namespace, name = attr.split(':')
+ attr = '{%s}%s' % (self.namespaces[namespace], name)
+ while parent is not None and parent.tag != attr:
+ parent = parent.getparent()
+ assert parent is not None, "Parent not found"
+
+ # add the py:attribute to the parent
+ py_attr = '{%s}%s' % (GENSHI_URI, directive)
+ parent.attrib[py_attr] = a_val
+
+ # remove the directive node
+ r_node.getparent().remove(r_node)
else:
# It's not a genshi statement it's a python expression
parent = r_node.getparent().getparent()
@@ -577,7 +597,7 @@ class Template(MarkupTemplate):
for tag in to_split:
tag_pos = table_node.index(tag)
num = int(tag.attrib.pop(table_num_col_attr))
- new_tags = [deepcopy(tag) for _ in range(num)]
+ new_tags = [deepcopy(tag) for i in range(num)]
table_node[tag_pos:tag_pos + 1] = new_tags
# compute the column header nodes corresponding to
@@ -588,10 +608,10 @@ class Template(MarkupTemplate):
# add a <relatorio:repeat> node around the column
# definitions nodes
attribs = {
- "opening": str(opening_pos),
- "closing": str(closing_pos),
- "table": table_name
- }
+ "opening": str(opening_pos),
+ "closing": str(closing_pos),
+ "table": table_name,
+ }
repeat_node = EtreeElement(repeat_tag, attrib=attribs,
nsmap={'relatorio': RELATORIO_URI})
wrap_nodes_between(first, last, repeat_node)
@@ -665,6 +685,7 @@ class Template(MarkupTemplate):
draw_name = '{%s}name' % draw_namespace
draw_image = '{%s}image' % draw_namespace
py_attrs = '{%s}attrs' % self.namespaces['py']
+ end_cell_address = '{%s}end-cell-address' % self.namespaces['table']
svg_namespace = self.namespaces['svg']
svg_width = '{%s}width' % svg_namespace
svg_height = '{%s}height' % svg_namespace
@@ -686,6 +707,8 @@ class Template(MarkupTemplate):
"__relatorio_store_cache(%s, %s), '%s', '%s')" %
(cache_id, d_name, width, height))
draw.attrib[py_attrs] = attr_expr
+ # remove end-cell-address as the address specified could be wrong
+ draw.attrib.pop(end_cell_address, '')
def _handle_innerdocs(self, tree):
"finds inner_docs and adds them to the processing stack."
@@ -707,7 +730,7 @@ class Template(MarkupTemplate):
def generate(self, *args, **kwargs):
"creates the RelatorioStream."
- serializer = OOSerializer(self._zip_source)
+ serializer = OOSerializer(self._source)
kwargs['__relatorio_make_href'] = ImageHref(serializer.outzip,
serializer.manifest,
kwargs)
@@ -812,7 +835,7 @@ class Meta(object):
meta = self.office_meta.find('{%s}%s' % (namespace, name))
if meta is None:
meta = EtreeElement('{%s}%s' % (namespace, name),
- nsmap={'meta': namespace})
+ nsmap={'meta': namespace})
self.office_meta.append(meta)
meta.text = value
@@ -845,8 +868,8 @@ class Meta(object):
class OOSerializer:
- def __init__(self, inzip):
- self.inzip = inzip
+ def __init__(self, source):
+ self.inzip = zipfile.ZipFile(source)
self.manifest = Manifest(self.inzip.read(MANIFEST))
self.meta = Meta(self.inzip.read(META))
self.new_oo = BytesIO()
@@ -887,6 +910,7 @@ class OOSerializer:
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
diff --git a/relatorio/templates/pdf.py b/relatorio/templates/pdf.py
index c99024c..f21945b 100644
--- a/relatorio/templates/pdf.py
+++ b/relatorio/templates/pdf.py
@@ -1,5 +1,6 @@
###############################################################################
#
+# Copyright (c) 2014 Cedric Krier.
# Copyright (c) 2007, 2008 OpenHex SPRL. (http://openhex.com) All Rights
# Reserved.
#
@@ -24,10 +25,7 @@ import os
import shutil
import tempfile
import subprocess
-try:
- from cStringIO import StringIO
-except ImportError:
- from StringIO import StringIO
+from io import BytesIO
import genshi
import genshi.output
@@ -63,7 +61,7 @@ class PDFSerializer:
subprocess.check_call([TEXEXEC, '--purge', 'report.tex'],
cwd=self.working_dir)
- pdf = StringIO()
+ pdf = BytesIO()
pdf.write(open(self.pdf_file, 'r').read())
shutil.rmtree(self.working_dir, ignore_errors=True)
diff --git a/relatorio/tests/__init__.py b/relatorio/tests/__init__.py
index e69de29..72d44a5 100644
--- a/relatorio/tests/__init__.py
+++ b/relatorio/tests/__init__.py
@@ -0,0 +1,48 @@
+###############################################################################
+#
+# Copyright (c) 2015 Cedric Krier.
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 3 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program. If not, see <http://www.gnu.org/licenses/>.
+#
+###############################################################################
+
+import sys
+import os
+import unittest
+
+here = os.path.dirname(__file__)
+
+
+def test_suite():
+ suite = unittest.TestSuite()
+ loader = unittest.TestLoader()
+ for fn in os.listdir(here):
+ if fn.startswith('test') and fn.endswith('.py'):
+ modname = 'relatorio.tests.' + fn[:-3]
+ __import__(modname)
+ module = sys.modules[modname]
+ suite.addTests(loader.loadTestsFromModule(module))
+ return suite
+
+
+def main():
+ suite = test_suite()
+ runner = unittest.TextTestRunner()
+ runner.run(suite)
+
+if __name__ == '__main__':
+ sys.path.insert(0, os.path.dirname(os.path.dirname(
+ os.path.dirname(os.path.abspath(__file__)))))
+ main()
diff --git a/relatorio/tests/test_api.py b/relatorio/tests/test_api.py
index 11e8993..5a78d16 100644
--- a/relatorio/tests/test_api.py
+++ b/relatorio/tests/test_api.py
@@ -1,5 +1,6 @@
###############################################################################
#
+# Copyright (c) 2014 Cedric Krier.
# Copyright (c) 2007, 2008 OpenHex SPRL. (http://openhex.com) All Rights
# Reserved.
#
@@ -20,7 +21,7 @@
import os
-from nose.tools import *
+import unittest
from relatorio.reporting import (ReportRepository, Report, MIMETemplateLoader,
DefaultFactory, _absolute, _guess_type)
@@ -33,7 +34,7 @@ class StubObject(object):
setattr(self, key, val)
-class TestRepository(object):
+class TestRepository(unittest.TestCase):
def test_register(self):
"Testing the registration"
@@ -42,45 +43,47 @@ class TestRepository(object):
os.path.join('templates', 'test.tmpl'),
description='Test report')
- assert_true(StubObject in reporting.classes)
- assert_true('default' in reporting.classes[StubObject].ids)
- assert_true('text/plain' in reporting.classes[StubObject].mimetypes)
+ self.assertTrue(StubObject in reporting.classes)
+ self.assertTrue('default' in reporting.classes[StubObject].ids)
+ self.assertTrue(
+ 'text/plain' in reporting.classes[StubObject].mimetypes)
report, mime, desc = reporting.classes[StubObject].ids['default']
- eq_(mime, 'text/plain')
- eq_(desc, 'Test report')
- eq_(report.mimetype, 'text/plain')
- assert_true(report.fpath.endswith(os.path.join('templates',
+ self.assertEqual(mime, 'text/plain')
+ self.assertEqual(desc, 'Test report')
+ self.assertEqual(report.mimetype, 'text/plain')
+ self.assertTrue(report.fpath.endswith(os.path.join('templates',
'test.tmpl')))
report2, name = (reporting.classes[StubObject]
.mimetypes['text/plain'][0])
- eq_(name, 'default')
- eq_(report, report2)
+ self.assertEqual(name, 'default')
+ self.assertEqual(report, report2)
def test_mimeguesser(self):
- eq_(_guess_type('application/pdf'), 'pdf')
- eq_(_guess_type('text/plain'), 'text')
- eq_(_guess_type('text/xhtml'), 'markup')
- eq_(_guess_type('application/vnd.oasis.opendocument.text'), 'oo.org')
+ self.assertEqual(_guess_type('application/pdf'), 'pdf')
+ self.assertEqual(_guess_type('text/plain'), 'text')
+ self.assertEqual(_guess_type('text/xhtml'), 'markup')
+ self.assertEqual(
+ _guess_type('application/vnd.oasis.opendocument.text'), 'oo.org')
def abspath_helper(self, path):
return _absolute(path)
def test_absolute(self):
"Test the absolute path calculation"
- eq_("/home/nicoe/python/mock.py",
+ self.assertEqual("/home/nicoe/python/mock.py",
_absolute("/home/nicoe/python/mock.py"))
our_dir, _ = os.path.split(__file__)
# We use this because me go up by two frames
new_path = self.abspath_helper(os.path.join('brol', 'toto'))
- eq_(os.path.join(our_dir, 'brol', 'toto'), new_path)
+ self.assertEqual(os.path.join(our_dir, 'brol', 'toto'), new_path)
-class TestReport(object):
+class TestReport(unittest.TestCase):
- def setup(self):
+ def setUp(self):
self.loader = MIMETemplateLoader()
our_dir, _ = os.path.split(__file__)
self.report = Report(os.path.join(our_dir, 'templates', 'test.tmpl'),
@@ -89,7 +92,7 @@ class TestReport(object):
def test_report(self):
"Testing the report generation"
a = StubObject(name='OpenHex')
- eq_(self.report(o=a).render(), 'Hello OpenHex.\n')
+ self.assertEqual(self.report(o=a).render(), 'Hello OpenHex.\n')
def test_factory(self):
"Testing the data factory"
@@ -107,18 +110,18 @@ class TestReport(object):
'text/plain', MyFactory(), self.loader)
a = StubObject(name='Foo')
- eq_(report(o=a, time="One o'clock").render(),
+ self.assertEqual(report(o=a, time="One o'clock").render(),
"Hi Foo,\nIt's One o'clock to 2 !\n")
- eq_(report(o=a, time="One o'clock", y=4).render(),
+ self.assertEqual(report(o=a, time="One o'clock", y=4).render(),
"Hi Foo,\nIt's One o'clock to 5 !\n")
- assert_raises(TypeError, report, a)
+ self.assertRaises(TypeError, report, a)
-class TestReportInclude(object):
+class TestReportInclude(unittest.TestCase):
def test_include(self):
our_dir = os.path.dirname(__file__)
template_path = os.path.join(our_dir, 'templates')
relative_report = Report(os.path.join(template_path, 'include.tmpl'),
'text/plain')
- eq_(relative_report().render(), 'Another Hello.\n\n')
+ self.assertEqual(relative_report().render(), 'Another Hello.\n\n')
diff --git a/relatorio/tests/test_odt.py b/relatorio/tests/test_odt.py
index 2d982ff..d7e8bcf 100644
--- a/relatorio/tests/test_odt.py
+++ b/relatorio/tests/test_odt.py
@@ -1,6 +1,7 @@
# -*- encoding: utf-8 -*-
###############################################################################
#
+# Copyright (c) 2014 Cedric Krier.
# Copyright (c) 2007, 2008 OpenHex SPRL. (http://openhex.com) All Rights
# Reserved.
#
@@ -21,13 +22,10 @@
import os
-try:
- from cStringIO import StringIO
-except ImportError:
- from StringIO import StringIO
+import unittest
+from io import StringIO
import lxml.etree
-from nose.tools import *
from genshi.filters import Translator
from genshi.core import PI
from genshi.template.eval import UndefinedError
@@ -42,22 +40,23 @@ def pseudo_gettext(string):
catalog = {'Mes collègues sont:': 'My colleagues are:',
'Bonjour,': 'Hello,',
'Je suis un test de templating en odt.':
- 'I am an odt templating test',
+ 'I am an odt templating test',
'Felix da housecat': u'Félix le chat de la maison',
'We sell stuff': u'On vend des choses',
}
return catalog.get(string, string)
+
def stream_to_string(stream):
# In Python 3, stream will be bytes
- if not isinstance(stream, str):
- return str(stream, 'utf-8')
+ if not isinstance(stream, unicode):
+ return unicode(stream, 'utf-8')
return stream
-class TestOOTemplating(object):
+class TestOOTemplating(unittest.TestCase):
- def setup(self):
+ def setUp(self):
thisdir = os.path.dirname(__file__)
filepath = os.path.join(thisdir, 'test.odt')
self.oot = Template(open(filepath, mode='rb'))
@@ -79,9 +78,11 @@ class TestOOTemplating(object):
def test_init(self):
"Testing the correct handling of the styles.xml and content.xml files"
- ok_(isinstance(self.oot.stream, list))
- eq_(self.oot.stream[0], (PI, ('relatorio', 'content.xml'), None))
- ok_((PI, ('relatorio', 'content.xml'), None) in self.oot.stream)
+ self.assertTrue(isinstance(self.oot.stream, list))
+ self.assertEqual(
+ self.oot.stream[0], (PI, ('relatorio', 'content.xml'), None))
+ self.assertTrue(
+ (PI, ('relatorio', 'content.xml'), None) in self.oot.stream)
def test_directives(self):
"Testing the directives interpolation"
@@ -91,7 +92,8 @@ class TestOOTemplating(object):
interpolated = self.oot.insert_directives(xml)
root_interpolated = lxml.etree.parse(interpolated).getroot()
child = root_interpolated[0]
- eq_(child.get('{http://genshi.edgewall.org/}replace'), 'foo')
+ self.assertEqual(
+ child.get('{http://genshi.edgewall.org/}replace'), 'foo')
def test_column_looping(self):
xml = b'''
@@ -199,25 +201,25 @@ class TestOOTemplating(object):
interpolated = self.oot.insert_directives(xml)
root = lxml.etree.parse(interpolated).getroot()
child2 = root[1]
- eq_(child2.tag, "{%s}repeat" % RELATORIO_URI)
- eq_(child2.get("closing"), "3")
- eq_(child2.get("opening"), "1")
- eq_(len(child2), 1)
+ self.assertEqual(child2.tag, "{%s}repeat" % RELATORIO_URI)
+ self.assertEqual(child2.get("closing"), "3")
+ self.assertEqual(child2.get("opening"), "1")
+ self.assertEqual(len(child2), 1)
child4 = root[3]
- eq_(child4.tag, "{%s}table-header-rows" % OO_TABLE_NS)
+ self.assertEqual(child4.tag, "{%s}table-header-rows" % OO_TABLE_NS)
row1 = child4[0]
- ok_(row1.get("{%s}attrs" % GENSHI_URI)
+ self.assertTrue(row1.get("{%s}attrs" % GENSHI_URI)
.startswith('__relatorio_reset_col_count'))
- eq_(len(row1), 4)
+ self.assertEqual(len(row1), 4)
loop = row1[1]
- eq_(loop.tag, "{%s}for" % GENSHI_URI)
+ self.assertEqual(loop.tag, "{%s}for" % GENSHI_URI)
cell = loop[0]
- ok_(cell.get("{%s}attrs" % GENSHI_URI)
+ self.assertTrue(cell.get("{%s}attrs" % GENSHI_URI)
.startswith('__relatorio_inc_col_count'))
last_row_node = row1[3]
- eq_(last_row_node.tag, "{%s}replace" % GENSHI_URI)
- ok_(last_row_node.get("value")
- .startswith('__relatorio_store_col_count'))
+ self.assertEqual(last_row_node.tag, "{%s}replace" % GENSHI_URI)
+ self.assertTrue(last_row_node.get("value")
+ .startswith('__relatorio_store_col_count'))
def test_text_outside_p(self):
"Testing that the tail text of a directive node is handled properly"
@@ -232,31 +234,31 @@ class TestOOTemplating(object):
interpolated = self.oot.insert_directives(xml)
root_interpolated = lxml.etree.parse(interpolated).getroot()
child = root_interpolated[0]
- eq_(child.tag, '{http://genshi.edgewall.org/}if')
- eq_(child.text.strip(), 'xxx')
- eq_(child.tail.strip(), 'aaa')
+ self.assertEqual(child.tag, '{http://genshi.edgewall.org/}if')
+ self.assertEqual(child.text.strip(), 'xxx')
+ self.assertEqual(child.tail.strip(), 'aaa')
def test_styles(self):
"Testing that styles get rendered"
stream = self.oot.generate(**self.data)
rendered = stream_to_string(stream.events.render(encoding='utf-8'))
- ok_('We sell stuff' in rendered)
+ self.assertTrue('We sell stuff' in rendered)
dico = self.data.copy()
del dico['footer']
stream = self.oot.generate(**dico)
- assert_raises(UndefinedError,
+ self.assertRaises(UndefinedError,
lambda: stream.events.render(encoding='utf-8'))
def test_generate(self):
"Testing that content get rendered"
stream = self.oot.generate(**self.data)
rendered = stream_to_string(stream.events.render(encoding='utf-8'))
- ok_('Bonjour,' in rendered)
- ok_('Trente' in rendered)
- ok_('Møller' in rendered)
- ok_('Dog eat Dog' in rendered)
- ok_('Felix da housecat' in rendered)
+ self.assertTrue('Bonjour,' in rendered)
+ self.assertTrue('Trente' in rendered)
+ self.assertTrue(u'Møller' in rendered)
+ self.assertTrue('Dog eat Dog' in rendered)
+ self.assertTrue('Felix da housecat' in rendered)
def test_filters(self):
"Testing the filters with the Translator filter"
@@ -264,12 +266,12 @@ class TestOOTemplating(object):
translated = stream.filter(Translator(pseudo_gettext))
translated_xml = stream_to_string(
translated.events.render(encoding='utf-8'))
- ok_("Hello," in translated_xml)
- ok_("I am an odt templating test" in translated_xml)
- ok_('Felix da housecat' not in translated_xml)
- ok_('Félix le chat de la maison' in translated_xml)
- ok_('We sell stuff' not in translated_xml)
- ok_('On vend des choses' in translated_xml)
+ self.assertTrue("Hello," in translated_xml)
+ self.assertTrue("I am an odt templating test" in translated_xml)
+ self.assertTrue('Felix da housecat' not in translated_xml)
+ self.assertTrue(u'Félix le chat de la maison' in translated_xml)
+ self.assertTrue('We sell stuff' not in translated_xml)
+ self.assertTrue('On vend des choses' in translated_xml)
def test_images(self):
"Testing the image replacement directive"
@@ -279,34 +281,38 @@ class TestOOTemplating(object):
tree = lxml.etree.parse(StringIO(rendered[25:styles_idx]))
root = tree.getroot()
images = root.xpath('//draw:frame', namespaces=self.oot.namespaces)
- eq_(len(images), 3)
- eq_(images[0].get('{%s}name' % self.oot.namespaces['draw']), "")
- eq_(images[1].get('{%s}name' % self.oot.namespaces['draw']), '')
- eq_(images[1].get('{%s}width' % self.oot.namespaces['svg']),
- '1.732cm')
- eq_(images[1].get('{%s}height' % self.oot.namespaces['svg']),
+ self.assertEqual(len(images), 3)
+ self.assertEqual(
+ images[0].get('{%s}name' % self.oot.namespaces['draw']), "")
+ self.assertEqual(
+ images[1].get('{%s}name' % self.oot.namespaces['draw']), '')
+ self.assertEqual(
+ images[1].get('{%s}width' % self.oot.namespaces['svg']), '1.732cm')
+ self.assertEqual(
+ images[1].get('{%s}height' % self.oot.namespaces['svg']),
'1.513cm')
- eq_(images[2].get('{%s}width' % self.oot.namespaces['svg']),
- '1.732cm')
- eq_(images[2].get('{%s}height' % self.oot.namespaces['svg']),
+ self.assertEqual(
+ images[2].get('{%s}width' % self.oot.namespaces['svg']), '1.732cm')
+ self.assertEqual(
+ images[2].get('{%s}height' % self.oot.namespaces['svg']),
'1.513cm')
def test_regexp(self):
"Testing the regexp used to find relatorio tags"
# a valid expression
group = GENSHI_EXPR.match('for each="foo in bar"').groups()
- eq_(group, (None, 'for', 'each', 'foo in bar'))
+ self.assertEqual(group, (None, 'for', 'each', 'foo in bar'))
# invalid expr
group = GENSHI_EXPR.match('foreach="foo in bar"').groups()
- eq_(group, (None, None, None, None))
+ self.assertEqual(group, (None, None, None, None))
# valid closing tags
group = GENSHI_EXPR.match('/for').groups()
- eq_(group, ('/', 'for', None, None))
+ self.assertEqual(group, ('/', 'for', None, None))
group = GENSHI_EXPR.match('/for ').groups()
- eq_(group, ('/', 'for', None, None))
+ self.assertEqual(group, ('/', 'for', None, None))
# another non matching expr
group = GENSHI_EXPR.match('formatLang("en")').groups()
- eq_(group, (None, None, None, None))
+ self.assertEqual(group, (None, None, None, None))
diff --git a/setup.py b/setup.py
index f342bf6..70028ec 100644
--- a/setup.py
+++ b/setup.py
@@ -2,6 +2,7 @@ import os
import re
from setuptools import setup, find_packages
+
def get_version():
init = open(os.path.join(os.path.dirname(__file__), 'relatorio',
'__init__.py')).read()
@@ -9,9 +10,9 @@ def get_version():
setup(
name="relatorio",
- url="http://relatorio.openhex.org/",
+ url="http://code.google.com/p/python-relatorio/",
author="Nicolas Evrard",
- author_email="nicoe at openhex.org",
+ author_email="nicolas.evrard at b2ck.com",
maintainer="Cedric Krier",
maintainer_email="cedric.krier at b2ck.com",
description="A templating library able to output odt and pdf files",
@@ -46,8 +47,5 @@ and report together, find reports by mimetypes/name/python objects.
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Text Processing",
],
- test_suite="nose.collector",
- tests_require=[
- "nose",
- ],
+ test_suite="relatorio.tests",
use_2to3=True)
--
relatorio
More information about the tryton-debian-vcs
mailing list