[pyepr] 01/03: Imported Upstream version 0.8.2

Antonio Valentino a_valentino-guest at moszumanska.debian.org
Fri Aug 15 09:00:05 UTC 2014


This is an automated email from the git hooks/post-receive script.

a_valentino-guest pushed a commit to branch master
in repository pyepr.

commit c9890c5992afb029ccc5fb769d589f921b165f69
Author: Antonio Valentino <antonio.valentino at tiscali.it>
Date:   Fri Aug 15 08:52:50 2014 +0000

    Imported Upstream version 0.8.2
---
 .travis.yml                          |  17 +-
 Makefile                             |   6 +-
 README.txt                           |  20 +-
 doc/Makefile                         |  26 ++-
 doc/NEWS.txt                         |  30 ++-
 doc/conf.py                          |  79 ++++++--
 doc/examples/write_ndvi.py           |  97 +++++----
 doc/index.txt                        |   9 +-
 doc/interactive_use.txt              |   8 +-
 doc/make.bat                         |  52 +++++
 doc/ndvi_example.txt                 |  15 +-
 doc/pydoctheme/LICENSE               |  42 +---
 doc/pydoctheme/static/pydoctheme.css |   2 +-
 doc/pydoctheme/static/sidebar.js     |  50 ++++-
 doc/reference.txt                    |  16 +-
 doc/usermanual.txt                   |  20 +-
 requirements.txt                     |   2 +-
 setup.py                             |   8 +-
 src/epr.pyx                          |  87 +++++---
 test/test_all.py                     | 378 +++++++++++++++++++++++++++++------
 20 files changed, 715 insertions(+), 249 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 555b791..49e342b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,19 +1,20 @@
 language: python
 
-virtualenv:
-  system_site_packages: true
-
 python:
-  - "2.6"
-  - "2.7"
-  - "3.2"
-  - "3.3"
+  - 2.6
+  - 2.7
+  - "2.7_with_system_site_packages"
+  - 3.2
+  - "3.2_with_system_site_packages"
+  - 3.3
+  - 3.4
 
 before_install:
   - sudo apt-get update -qq
   - sudo apt-get install -qq libepr-api2-dev
   - pip install -r requirements.txt --use-mirrors
+  - if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install -U unittest2 --use-mirrors; fi
 
 install: python setup.py build_ext --inplace
 
-script: make check
+script: make PYTHON=python check
diff --git a/Makefile b/Makefile
index a898edf..dd773fc 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 #!/usr/bin/make -f
 # -*- coding: utf-8 -*-
 
-# Copyright (C) 2011-2013, Antonio Valentino <antonio.valentino at tiscali.it>
+# Copyright (C) 2011-2014, Antonio Valentino <antonio.valentino at tiscali.it>
 #
 # This file is part of PyEPR.
 #
@@ -18,7 +18,7 @@
 # You should have received a copy of the GNU General Public License
 # along with PyEPR.  If not, see <http://www.gnu.org/licenses/>.
 
-PYTHON = python
+PYTHON = python3
 CYTHON = cython
 TEST_DATSET_URL = "http://earth.esa.int/services/sample_products/meris/LRC/L2/MER_LRC_2PTGMV20000620_104318_00000104X000_00000_00000_0001.N1.gz"
 TEST_DATSET = test/MER_LRC_2PTGMV20000620_104318_00000104X000_00000_00000_0001.N1
@@ -74,7 +74,7 @@ distclean: clean
 	$(RM) -r LICENSES epr-api-src
 
 check: ext $(TEST_DATSET)
-	$(PYTHON) test/test_all.py --verbose
+	env PYTHONPATH=. $(PYTHON) test/test_all.py --verbose
 
 debug:
 	$(PYTHON) setup.py build_ext --inplace --debug
diff --git a/README.txt b/README.txt
index b09c17c..c017621 100644
--- a/README.txt
+++ b/README.txt
@@ -2,11 +2,11 @@
 ENVISAT Product Reader Python API
 =================================
 
-:HomePage:  http://avalentino.github.com/pyepr
+:HomePage:  http://avalentino.github.io/pyepr
 :Author:    Antonio Valentino
 :Contact:   antonio.valentino at tiscali.it
-:Copyright: 2011-2013, Antonio Valentino <antonio.valentino at tiscali.it>
-:Version:   0.8.1
+:Copyright: 2011-2014, Antonio Valentino <antonio.valentino at tiscali.it>
+:Version:   0.8.2
 
 
 Introduction
@@ -36,17 +36,19 @@ In order to use PyEPR it is needed that the following software are
 correctly installed and configured:
 
 * Python2_ >= 2.6 or Python3_ >= 3.1
-* numpy_ >= 1.3.0
+* numpy_ >= 1.5.0
 * `EPR API`_ >= 2.2 (optional, since PyEPR 0.7 the source tar-ball comes
   with a copy of the PER C API sources)
 * a reasonably updated C compiler (build only)
 * Cython_ >= 0.13 (build only)
+* unittest2_ (only required for Python < 2.7)
 
 .. _Python2: Python_
 .. _Python3: Python_
 .. _numpy: http://www.numpy.org
 .. _gcc: http://gcc.gnu.org
 .. _Cython: http://cython.org
+.. _unittest2: https://pypi.python.org/pypi/unittest2
 
 
 Download
@@ -54,7 +56,7 @@ Download
 
 Official source tarballs can be downloaded form PyPi_:
 
-    http://pypi.python.org/pypi/pyepr
+    https://pypi.python.org/pypi/pyepr
 
 The source code of the development versions is available on the GitHub_
 project page
@@ -65,7 +67,7 @@ To clone the git_ repository the following command can be used::
 
     $ git clone https://github.com/avalentino/pyepr.git
 
-.. _PyPi: http://pypi.python.org
+.. _PyPi: https://pypi.python.org/pypi
 .. _GitHub: https://github.com
 .. _git: http://git-scm.com
 
@@ -90,14 +92,14 @@ To install PyEPR_ in a non-standard path::
 
     $ python setup.py install --prefix=<TARGET_PATH>
 
-.. _pip: http://pypi.python.org/pypi/pip
-.. _easy_install: http://pypi.python.org/pypi/setuptools#using-setuptools-and-easyinstall
+.. _pip: https://pypi.python.org/pypi/pip
+.. _easy_install: https://pypi.python.org/pypi/setuptools#using-setuptools-and-easyinstall
 
 
 License
 =======
 
-Copyright (C) 2011-2013 Antonio Valentino <antonio.valentino at tiscali.it>
+Copyright (C) 2011-2014 Antonio Valentino <antonio.valentino at tiscali.it>
 
 PyEPR is free software: you can redistribute it and/or modify
 it under the terms of the `GNU General Public License`_ as published by
diff --git a/doc/Makefile b/doc/Makefile
index 478ae40..78b1daf 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -7,6 +7,11 @@ SPHINXBUILD   = sphinx-build
 PAPER         =
 BUILDDIR      = _build
 
+# User-friendly check for sphinx-build
+ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
+$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
+endif
+
 # Internal variables.
 PAPEROPT_a4     = -D latex_paper_size=a4
 PAPEROPT_letter = -D latex_paper_size=letter
@@ -29,17 +34,20 @@ help:
 	@echo "  epub       to make an epub"
 	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
 	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+	@echo "  latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
 	@echo "  text       to make text files"
 	@echo "  man        to make manual pages"
 	@echo "  texinfo    to make Texinfo files"
 	@echo "  info       to make Texinfo files and run them through makeinfo"
 	@echo "  gettext    to make PO message catalogs"
 	@echo "  changes    to make an overview of all changed/added/deprecated items"
+	@echo "  xml        to make Docutils-native XML files"
+	@echo "  pseudoxml  to make pseudoxml-XML files for display purposes"
 	@echo "  linkcheck  to check all external links for integrity"
 	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
 
 clean:
-	-rm -rf $(BUILDDIR)/*
+	rm -rf $(BUILDDIR)/*
 
 html:
 	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) html
@@ -108,6 +116,12 @@ latexpdf:
 	$(MAKE) -C $(BUILDDIR)/latex all-pdf
 	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
 
+latexpdfja:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo "Running LaTeX files through platex and dvipdfmx..."
+	$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
 text:
 	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
 	@echo
@@ -151,3 +165,13 @@ doctest:
 	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
 	@echo "Testing of doctests in the sources finished, look at the " \
 	      "results in $(BUILDDIR)/doctest/output.txt."
+
+xml:
+	$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
+	@echo
+	@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
+
+pseudoxml:
+	$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
+	@echo
+	@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
diff --git a/doc/NEWS.txt b/doc/NEWS.txt
index e022224..44d61fe 100644
--- a/doc/NEWS.txt
+++ b/doc/NEWS.txt
@@ -2,6 +2,30 @@ Change history
 ==============
 
 
+PyEPR 0.8.2 (03/08/2014)
+------------------------
+
+* fixed segfault caused by incorrect access to :attr:`epr.Dataset.description`
+  string in case of closed products
+* fixed a memory leak in :class:`epr.Raster` (closes :issue:`10`)
+* the size parameters (*src_width* and *src_height*) in
+  :meth:`epr.Band.create_compatible_raster` are now optional. By default a
+  :class:`epr.Raster` with the same size of the scene is created
+* the test suite have been improved
+* improved the :doc:`NDVI computation example <ndvi_example>`
+* updates sphinx config
+* small clarification in the :ref:`installation` section of the
+  :doc:`usermanual`.
+* EPR C API (version bundled with the official source tar-ball)
+
+  - in case of error always free resources before setting the error code.
+    This avoids error shadowing in some cases.
+  - fixed a bug that caused reading of the incorrect portion of data in case
+    of mirrored annotation datasets (closes :issue:`9`)
+  - fixed a bug that caused incorrect data sub-sampling in case of mirrored
+    datasets
+
+
 PyEPR 0.8.1 (07/09/2013)
 ------------------------
 
@@ -125,8 +149,8 @@ PyEPR 0.5 (25/04/2011)
 * dropped old versions of cython_; now cython_ 0.14.1 or newer is required
 * suppressed several constness related warnings
 
-.. _`Python 3`: http://docs.python.org/py3k
-.. _intersphinx: http://sphinx.pocoo.org/latest/ext/intersphinx.html
+.. _`Python 3`: http://docs.python.org/3
+.. _intersphinx: http://sphinx-doc.org/latest/ext/intersphinx.html
 .. _cython: http://www.cython.org
 
 
@@ -177,7 +201,7 @@ PyEPR 0.2 (20/03/2011)
 * introduced some utility methods to :class:`epr.Product` and
   :class:`epr.Record` classes
 
-.. _sphinx: http://sphinx.pocoo.org
+.. _sphinx: http://sphinx-doc.org
 
 
 PyEPR 0.1 (09/03/2011)
diff --git a/doc/conf.py b/doc/conf.py
index 39584de..51beae7 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -1,9 +1,10 @@
 # -*- coding: utf-8 -*-
 #
 # PyEPR documentation build configuration file, created by
-# sphinx-quickstart on Thu Apr 26 19:30:10 2012.
+# sphinx-quickstart on Sat Jul 26 10:12:56 2014.
 #
-# This file is execfile()d with the current directory set to its containing dir.
+# This file is execfile()d with the current directory set to its
+# containing dir.
 #
 # Note that not all possible configuration values are present in this
 # autogenerated file.
@@ -11,20 +12,22 @@
 # All configuration values have a default; values that are commented out
 # serve to show the default.
 
-import sys, os
+import sys
+import os
 
 # If extensions (or modules to document with autodoc) are in another directory,
 # add these directories to sys.path here. If the directory is relative to the
 # documentation root, use os.path.abspath to make it absolute, like shown here.
 sys.path.insert(0, os.path.abspath('sphinxext'))
 
-# -- General configuration -----------------------------------------------------
+# -- General configuration ------------------------------------------------
 
 # If your documentation needs a minimal Sphinx version, state it here.
 needs_sphinx = '1.0'
 
-# Add any Sphinx extension module names here, as strings. They can be extensions
-# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
 extensions = [
     #'sphinx.ext.autodoc',
     #'sphinx.ext.autosummary',
@@ -34,6 +37,7 @@ extensions = [
     #'sphinx.ext.coverage',
     'sphinx.ext.pngmath',
     #'sphinx.ext.jsmath',
+    #'sphinx.ext.mathjax',
     #'sphinx.ext.graphviz',
     #'sphinx.ext.inheritance_diagram',
     #'sphinx.ext.refcounting',
@@ -57,14 +61,14 @@ master_doc = 'index'
 
 # General information about the project.
 project = u'PyEPR'
-copyright = u'2011-2013, Antonio Valentino'
+copyright = u'2011-2014, Antonio Valentino'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
 # built documents.
 #
 # The short X.Y version.
-version = '0.8.1'
+version = '0.8.2'
 # The full version, including alpha/beta/rc tags.
 release = version  # + 'dev'
 
@@ -82,7 +86,8 @@ release = version  # + 'dev'
 # directories to ignore when looking for source files.
 exclude_patterns = ['_build', 'sphinxext', '**/empty.txt']
 
-# The reST default role (used for this markup: `text`) to use for all documents.
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
 #default_role = None
 
 # If true, '()' will be appended to :func: etc. cross-reference text.
@@ -97,11 +102,13 @@ exclude_patterns = ['_build', 'sphinxext', '**/empty.txt']
 #show_authors = False
 
 # The name of the Pygments (syntax highlighting) style to use.
-#pygments_style = 'sphinx'
+pygments_style = 'sphinx'
 
 # A list of ignored prefixes for module index sorting.
 #modindex_common_prefix = []
 
+# If true, keep warnings as "system message" paragraphs in the built documents.
+#keep_warnings = False
 
 # -- Extensions configuration --------------------------------------------------
 
@@ -128,7 +135,7 @@ intersphinx_mapping = {
 }
 
 
-# -- Options for HTML output ---------------------------------------------------
+# -- Options for HTML output ----------------------------------------------
 
 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
@@ -165,6 +172,11 @@ html_theme_path = ['.']
 # so a file named "default.css" will overwrite the builtin "default.css".
 html_static_path = ['_static']
 
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+#html_extra_path = []
+
 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
 # using the given strftime format.
 html_last_updated_fmt = '%b %d, %Y'
@@ -213,7 +225,7 @@ html_domain_indices = False
 htmlhelp_basename = 'PyEPRdoc'
 
 
-# -- Options for LaTeX output --------------------------------------------------
+# -- Options for LaTeX output ---------------------------------------------
 
 latex_elements = {
 # The paper size ('letterpaper' or 'a4paper').
@@ -227,7 +239,8 @@ latex_elements = {
 }
 
 # Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, documentclass [howto/manual]).
+# (source start file, target name, title,
+#  author, documentclass [howto, manual, or own class]).
 latex_documents = [
   ('index', 'pyepr.tex', u'PyEPR Documentation',
    u'Antonio Valentino', 'manual'),
@@ -254,7 +267,7 @@ latex_documents = [
 latex_domain_indices = False
 
 
-# -- Options for manual page output --------------------------------------------
+# -- Options for manual page output ---------------------------------------
 
 # One entry per manual page. List of tuples
 # (source start file, name, description, authors, manual section).
@@ -267,7 +280,7 @@ man_pages = [
 #man_show_urls = False
 
 
-# -- Options for Texinfo output ------------------------------------------------
+# -- Options for Texinfo output -------------------------------------------
 
 # Grouping the document tree into Texinfo files. List of tuples
 # (source start file, target name, title, author,
@@ -287,14 +300,26 @@ texinfo_documents = [
 # How to display URL addresses: 'footnote', 'no', or 'inline'.
 #texinfo_show_urls = 'footnote'
 
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+#texinfo_no_detailmenu = False
+
 
-# -- Options for Epub output ---------------------------------------------------
+# -- Options for Epub output ----------------------------------------------
 
 # Bibliographic Dublin Core info.
 epub_title = u'PyEPR'
 epub_author = u'Antonio Valentino'
 epub_publisher = u'Antonio Valentino'
-epub_copyright = u'2011-2013, Antonio Valentino'
+epub_copyright = u'2011-2014, Antonio Valentino'
+
+# The basename for the epub file. It defaults to the project name.
+#epub_basename = u'PyEPR'
+
+# The HTML theme for the epub output. Since the default themes are not optimized
+# for small screen space, using the same theme for HTML and epub output is
+# usually not wise. This defaults to 'epub', a theme designed to save visual
+# space.
+#epub_theme = 'epub'
 
 # The language of the text. It defaults to the language option
 # or en if the language is not set.
@@ -313,6 +338,9 @@ epub_copyright = u'2011-2013, Antonio Valentino'
 # A tuple containing the cover image and cover page html template filenames.
 #epub_cover = ()
 
+# A sequence of (type, uri, title) tuples for the guide element of content.opf.
+#epub_guide = ()
+
 # HTML files that should be inserted before the pages created by sphinx.
 # The format is a list of tuples containing the path and title.
 #epub_pre_files = []
@@ -322,7 +350,7 @@ epub_copyright = u'2011-2013, Antonio Valentino'
 #epub_post_files = []
 
 # A list of files that should not be packed into the epub file.
-#epub_exclude_files = []
+epub_exclude_files = ['search.html']
 
 # The depth of the table of contents in toc.ncx.
 #epub_tocdepth = 3
@@ -330,6 +358,21 @@ epub_copyright = u'2011-2013, Antonio Valentino'
 # Allow duplicate toc entries.
 #epub_tocdup = True
 
+# Choose between 'default' and 'includehidden'.
+#epub_tocscope = 'default'
+
+# Fix unsupported image types using the PIL.
+#epub_fix_images = False
+
+# Scale large images.
+#epub_max_image_width = 0
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#epub_show_urls = 'inline'
+
+# If false, no index is generated.
+#epub_use_index = True
+
 
 # Example configuration for intersphinx: refer to the Python standard library.
 #intersphinx_mapping = {'http://docs.python.org/': None}
diff --git a/doc/examples/write_ndvi.py b/doc/examples/write_ndvi.py
index 167297e..3c2a27a 100755
--- a/doc/examples/write_ndvi.py
+++ b/doc/examples/write_ndvi.py
@@ -46,56 +46,53 @@ def main(*argv):
         sys.exit(1)
 
     # Open the product
-    product = epr.open(argv[1])
-
-    # The NDVI shall be calculated using bands 6 and 8.
-    band1_name = 'radiance_6'
-    band2_name = 'radiance_10'
-
-    band1 = product.get_band(band1_name)
-    band2 = product.get_band(band2_name)
-
-    # Allocate memory for the rasters
-    width = product.get_scene_width()
-    height = product.get_scene_height()
-    subsampling_x = 1
-    subsampling_y = 1
-    raster1 = band1.create_compatible_raster(width, height,
-                                             subsampling_x, subsampling_y)
-    raster2 = band2.create_compatible_raster(width, height,
-                                             subsampling_x, subsampling_y)
-
-    # Read the radiance into the raster.
-    offset_x = 0
-    offset_y = 0
-
-    logging.info('read "%s" data' % band1_name)
-    band1.read_raster(offset_x, offset_y, raster1)
-
-    logging.info('read "%s" data' % band2_name)
-    band2.read_raster(offset_x, offset_y, raster2)
-
-    # Open the output file
-    logging.info('write ndvi to "%s"' % argv[2])
-    out_stream = open(argv[2], 'wb')
-
-    # Loop over all pixel and calculate the NDVI.
-    #
-    # @NOTE: looping over data matrices is not the best soluton.
-    #        It is done here just for demostrative purposes
-    for j in range(height):
-        for i in range(width):
-            rad1 = raster1.get_pixel(i, j)
-            rad2 = raster2.get_pixel(i, j)
-            if (rad1 + rad2) != 0.0:
-                ndvi = (rad2 - rad1) / (rad2 + rad1)
-            else:
-                ndvi = -1.0
-            out_stream.write(struct.pack('f', ndvi))
-    logging.info('ndvi was written success')
-
-    out_stream.close()
-    product.close()
+    with epr.open(argv[1]) as product:
+
+        # The NDVI shall be calculated using bands 6 and 8.
+        band1_name = 'radiance_6'
+        band2_name = 'radiance_10'
+
+        band1 = product.get_band(band1_name)
+        band2 = product.get_band(band2_name)
+
+        # Allocate memory for the rasters
+        width = product.get_scene_width()
+        height = product.get_scene_height()
+        subsampling_x = 1
+        subsampling_y = 1
+        raster1 = band1.create_compatible_raster(width, height,
+                                                 subsampling_x, subsampling_y)
+        raster2 = band2.create_compatible_raster(width, height,
+                                                 subsampling_x, subsampling_y)
+
+        # Read the radiance into the raster.
+        offset_x = 0
+        offset_y = 0
+
+        logging.info('read "%s" data' % band1_name)
+        band1.read_raster(offset_x, offset_y, raster1)
+
+        logging.info('read "%s" data' % band2_name)
+        band2.read_raster(offset_x, offset_y, raster2)
+
+        # Open the output file
+        logging.info('write ndvi to "%s"' % argv[2])
+        with open(argv[2], 'wb') as out_stream:
+
+            # Loop over all pixel and calculate the NDVI.
+            #
+            # @NOTE: looping over data matrices is not the best soluton.
+            #        It is done here just for demostrative purposes
+            for j in range(height):
+                for i in range(width):
+                    rad1 = raster1.get_pixel(i, j)
+                    rad2 = raster2.get_pixel(i, j)
+                    if (rad1 + rad2) != 0.0:
+                        ndvi = (rad2 - rad1) / (rad2 + rad1)
+                    else:
+                        ndvi = -1.0
+                    out_stream.write(struct.pack('f', ndvi))
+            logging.info('ndvi was written success')
 
 
 if __name__ == '__main__':
diff --git a/doc/index.txt b/doc/index.txt
index 9b855a0..0c27a95 100644
--- a/doc/index.txt
+++ b/doc/index.txt
@@ -9,10 +9,10 @@ ENVISAT Product Reader Python API
     \clearpage
 
 
-:HomePage:  http://avalentino.github.com/pyepr
+:HomePage:  http://avalentino.github.io/pyepr
 :Author:    Antonio Valentino
 :Contact:   antonio.valentino at tiscali.it
-:Copyright: 2011-2013, Antonio Valentino
+:Copyright: 2011-2014, Antonio Valentino
 :Version:   |release|
 
 
@@ -58,7 +58,8 @@ ENVISAT Product Reader Python API
     Online documentation for other PyEpr_ versions:
 
     * `latest <https://pyepr.readthedocs.org/en/latest/>`_ development
-    * `0.8.1 <https://pyepr.readthedocs.org/en/v0.8.1/>`_ (latest stable)
+    * `0.8.2 <https://pyepr.readthedocs.org/en/v0.8.2/>`_ (latest stable)
+    * `0.8.1 <https://pyepr.readthedocs.org/en/v0.8.1/>`_
     * `0.8 <https://pyepr.readthedocs.org/en/v0.8/>`_
     * `0.7.1 <https://pyepr.readthedocs.org/en/v0.7.1/>`_
     * `0.7 <https://pyepr.readthedocs.org/en/v0.7/>`_
@@ -69,7 +70,7 @@ ENVISAT Product Reader Python API
 License
 =======
 
-Copyright (C) 2011-2013 Antonio Valentino <antonio.valentino at tiscali.it>
+Copyright (C) 2011-2014 Antonio Valentino <antonio.valentino at tiscali.it>
 
 PyEPR is free software: you can redistribute it and/or modify
 it under the terms of the `GNU General Public License`_ as published by
diff --git a/doc/interactive_use.txt b/doc/interactive_use.txt
index 3307216..5d2da36 100644
--- a/doc/interactive_use.txt
+++ b/doc/interactive_use.txt
@@ -16,8 +16,8 @@ ESA_ web site.
 .. _PyEPR: https://github.com/avalentino/pyepr
 .. _ENVISAT: http://envisat.esa.int
 .. _ASAR: http://envisat.esa.int/handbooks/asar
-.. _IPython: http://ipython.scipy.org/moin
-.. _matplotlib: http://matplotlib.sourceforge.net
+.. _IPython: http://ipython.org
+.. _matplotlib: http://matplotlib.org
 .. _`free sample`: http://earth.esa.int/services/sample_products/asar/IMP/ASA_IMP_1PNUPA20060202_062233_000000152044_00435_20529_3110.N1.gz
 .. _ESA: http://earth.esa.int
 
@@ -68,14 +68,14 @@ available classes and functions::
         The raw data access makes it possible to read any data field contained
         in a product file.
 
-        .. _PyEPR: http://avalentino.github.com/pyepr
+        .. _PyEPR: http://avalentino.github.io/pyepr
         .. _Python: http://www.python.org
         .. _`EPR API`: https://github.com/bcdev/epr-api
         .. _ENVISAT: http://envisat.esa.int
         .. _ESA: http://earth.esa.int
 
     In [3]: epr.__version__, epr.EPR_C_API_VERSION
-    Out[3]: ('0.8.1', '2.3dev')
+    Out[3]: ('0.8.2', '2.3dev')
 
 Docstrings are available for almost all classes, methods and functions in
 the :mod:`epr` and they can be displayed using the :func:`help` python_
diff --git a/doc/make.bat b/doc/make.bat
index 2faa749..0983803 100644
--- a/doc/make.bat
+++ b/doc/make.bat
@@ -33,6 +33,8 @@ if "%1" == "help" (
 	echo.  texinfo    to make Texinfo files
 	echo.  gettext    to make PO message catalogs
 	echo.  changes    to make an overview over all changed/added/deprecated items
+	echo.  xml        to make Docutils-native XML files
+	echo.  pseudoxml  to make pseudoxml-XML files for display purposes
 	echo.  linkcheck  to check all external links for integrity
 	echo.  doctest    to run all doctests embedded in the documentation if enabled
 	goto end
@@ -44,6 +46,20 @@ if "%1" == "clean" (
 	goto end
 )
 
+
+%SPHINXBUILD% 2> nul
+if errorlevel 9009 (
+	echo.
+	echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+	echo.installed, then set the SPHINXBUILD environment variable to point
+	echo.to the full path of the 'sphinx-build' executable. Alternatively you
+	echo.may add the Sphinx directory to PATH.
+	echo.
+	echo.If you don't have Sphinx installed, grab it from
+	echo.http://sphinx-doc.org/
+	exit /b 1
+)
+
 if "%1" == "html" (
 	%SPHINXBUILD% -b html %ALLSPHINXOPTS% html
 	if errorlevel 1 exit /b 1
@@ -129,6 +145,26 @@ if "%1" == "latex" (
 	goto end
 )
 
+if "%1" == "latexpdf" (
+	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+	cd %BUILDDIR%/latex
+	make all-pdf
+	cd %BUILDDIR%/..
+	echo.
+	echo.Build finished; the PDF files are in %BUILDDIR%/latex.
+	goto end
+)
+
+if "%1" == "latexpdfja" (
+	%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+	cd %BUILDDIR%/latex
+	make all-pdf-ja
+	cd %BUILDDIR%/..
+	echo.
+	echo.Build finished; the PDF files are in %BUILDDIR%/latex.
+	goto end
+)
+
 if "%1" == "text" (
 	%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
 	if errorlevel 1 exit /b 1
@@ -187,4 +223,20 @@ results in %BUILDDIR%/doctest/output.txt.
 	goto end
 )
 
+if "%1" == "xml" (
+	%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The XML files are in %BUILDDIR%/xml.
+	goto end
+)
+
+if "%1" == "pseudoxml" (
+	%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
+	if errorlevel 1 exit /b 1
+	echo.
+	echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
+	goto end
+)
+
 :end
diff --git a/doc/ndvi_example.txt b/doc/ndvi_example.txt
index ae91077..5900b29 100644
--- a/doc/ndvi_example.txt
+++ b/doc/ndvi_example.txt
@@ -39,7 +39,20 @@ function.
 .. literalinclude:: examples/write_ndvi.py
    :lines: 49
 
-The name of the product is in the first argument of the program call.
+As usual in modern python programs the *with* statement has been used to
+ensure that the product is automatically closed as soon as the program exits
+the block.
+Of course it is possible to use a simple assignment form::
+
+    product = open(argv[1])
+    
+but in this case the user should take care of manually call::
+
+    product.close()
+
+when appropriate.
+
+The name of the product is in the first argument passed to the program.
 In order to keep the code simple no check is performed to ensure that the
 product is a valid L1B product.
 
diff --git a/doc/pydoctheme/LICENSE b/doc/pydoctheme/LICENSE
index 88eed1f..583f9f6 100644
--- a/doc/pydoctheme/LICENSE
+++ b/doc/pydoctheme/LICENSE
@@ -36,45 +36,9 @@ the various releases.
     2.1             2.0+1.6.1   2001        PSF         no
     2.0.1           2.0+1.6.1   2001        PSF         yes
     2.1.1           2.1+2.0.1   2001        PSF         yes
-    2.2             2.1.1       2001        PSF         yes
     2.1.2           2.1.1       2002        PSF         yes
     2.1.3           2.1.2       2002        PSF         yes
-    2.2.1           2.2         2002        PSF         yes
-    2.2.2           2.2.1       2002        PSF         yes
-    2.2.3           2.2.2       2003        PSF         yes
-    2.3             2.2.2       2002-2003   PSF         yes
-    2.3.1           2.3         2002-2003   PSF         yes
-    2.3.2           2.3.1       2002-2003   PSF         yes
-    2.3.3           2.3.2       2002-2003   PSF         yes
-    2.3.4           2.3.3       2004        PSF         yes
-    2.3.5           2.3.4       2005        PSF         yes
-    2.4             2.3         2004        PSF         yes
-    2.4.1           2.4         2005        PSF         yes
-    2.4.2           2.4.1       2005        PSF         yes
-    2.4.3           2.4.2       2006        PSF         yes
-    2.4.4           2.4.3       2006        PSF         yes
-    2.5             2.4         2006        PSF         yes
-    2.5.1           2.5         2007        PSF         yes
-    2.5.2           2.5.1       2008        PSF         yes
-    2.5.3           2.5.2       2008        PSF         yes
-    2.6             2.5         2008        PSF         yes
-    2.6.1           2.6         2008        PSF         yes
-    2.6.2           2.6.1       2009        PSF         yes
-    2.6.3           2.6.2       2009        PSF         yes
-    2.6.4           2.6.3       2009        PSF         yes
-    2.6.5           2.6.4       2010        PSF         yes
-    3.0             2.6         2008        PSF         yes
-    3.0.1           3.0         2009        PSF         yes
-    3.1             3.0.1       2009        PSF         yes
-    3.1.1           3.1         2009        PSF         yes
-    3.1.2           3.1.1       2010        PSF         yes
-    3.1.3           3.1.2       2010        PSF         yes
-    3.1.4           3.1.3       2011        PSF         yes
-    3.2             3.1         2011        PSF         yes
-    3.2.1           3.2         2011        PSF         yes
-    3.2.2           3.2.1       2011        PSF         yes
-    3.2.3           3.2.2       2012        PSF         yes
-    3.3.0           3.2         2012        PSF         yes
+    2.2 and above   2.1.1       2001-now    PSF         yes
 
 Footnotes:
 
@@ -110,8 +74,8 @@ analyze, test, perform and/or display publicly, prepare derivative works,
 distribute, and otherwise use Python alone or in any derivative version,
 provided, however, that PSF's License Agreement and PSF's notice of copyright,
 i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-2011, 2012 Python Software Foundation; All Rights Reserved" are retained in Python
-alone or in any derivative version prepared by Licensee.
+2011, 2012, 2013, 2014 Python Software Foundation; All Rights Reserved" are
+retained in Python alone or in any derivative version prepared by Licensee.
 
 3. In the event Licensee prepares a derivative work that is based on
 or incorporates Python or any part thereof, and wants to make
diff --git a/doc/pydoctheme/static/pydoctheme.css b/doc/pydoctheme/static/pydoctheme.css
index 9942ca6..5e1bd14 100644
--- a/doc/pydoctheme/static/pydoctheme.css
+++ b/doc/pydoctheme/static/pydoctheme.css
@@ -122,7 +122,7 @@ div.body tt.xref, div.body a tt {
     font-weight: normal;
 }
 
-p.deprecated {
+.deprecated {
     border-radius: 3px;
 }
 
diff --git a/doc/pydoctheme/static/sidebar.js b/doc/pydoctheme/static/sidebar.js
index 0c410e6..e8d58f4 100644
--- a/doc/pydoctheme/static/sidebar.js
+++ b/doc/pydoctheme/static/sidebar.js
@@ -2,7 +2,8 @@
  * sidebar.js
  * ~~~~~~~~~~
  *
- * This script makes the Sphinx sidebar collapsible.
+ * This script makes the Sphinx sidebar collapsible and implements intelligent
+ * scrolling.
  *
  * .sphinxsidebar contains .sphinxsidebarwrapper.  This script adds in
  * .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton used to
@@ -24,6 +25,8 @@ $(function() {
   // global elements used by the functions.
   // the 'sidebarbutton' element is defined as global after its
   // creation, in the add_sidebar_button function
+  var jwindow = $(window);
+  var jdocument = $(document);
   var bodywrapper = $('.bodywrapper');
   var sidebar = $('.sphinxsidebar');
   var sidebarwrapper = $('.sphinxsidebarwrapper');
@@ -42,6 +45,13 @@ $(function() {
   var dark_color = '#AAAAAA';
   var light_color = '#CCCCCC';
 
+  function get_viewport_height() {
+    if (window.innerHeight)
+      return window.innerHeight;
+    else
+      return jwindow.height();
+  }
+
   function sidebar_is_collapsed() {
     return sidebarwrapper.is(':not(:visible)');
   }
@@ -51,6 +61,8 @@ $(function() {
       expand_sidebar();
     else
       collapse_sidebar();
+    // adjust the scrolling of the sidebar
+    scroll_sidebar();
   }
 
   function collapse_sidebar() {
@@ -95,11 +107,7 @@ $(function() {
     );
     var sidebarbutton = $('#sidebarbutton');
     // find the height of the viewport to center the '<<' in the page
-    var viewport_height;
-    if (window.innerHeight)
- 	  viewport_height = window.innerHeight;
-    else
-	  viewport_height = $(window).height();
+    var viewport_height = get_viewport_height();
     var sidebar_offset = sidebar.offset().top;
     var sidebar_height = Math.max(bodywrapper.height(), sidebar.height());
     sidebarbutton.find('span').css({
@@ -152,4 +160,34 @@ $(function() {
   add_sidebar_button();
   var sidebarbutton = $('#sidebarbutton');
   set_position_from_cookie();
+
+
+  /* intelligent scrolling */
+  function scroll_sidebar() {
+    var sidebar_height = sidebarwrapper.height();
+    var viewport_height = get_viewport_height();
+    var offset = sidebar.position()['top'];
+    var wintop = jwindow.scrollTop();
+    var winbot = wintop + viewport_height;
+    var curtop = sidebarwrapper.position()['top'];
+    var curbot = curtop + sidebar_height;
+    // does sidebar fit in window?
+    if (sidebar_height < viewport_height) {
+      // yes: easy case -- always keep at the top
+      sidebarwrapper.css('top', $u.min([$u.max([0, wintop - offset - 10]),
+                            jdocument.height() - sidebar_height - 200]));
+    }
+    else {
+      // no: only scroll if top/bottom edge of sidebar is at
+      // top/bottom edge of window
+      if (curtop > wintop && curbot > winbot) {
+        sidebarwrapper.css('top', $u.max([wintop - offset - 10, 0]));
+      }
+      else if (curtop < wintop && curbot < winbot) {
+        sidebarwrapper.css('top', $u.min([winbot - sidebar_height - offset - 20,
+                              jdocument.height() - sidebar_height - 200]));
+      }
+    }
+  }
+  jwindow.scroll(scroll_sidebar);
 });
diff --git a/doc/reference.txt b/doc/reference.txt
index f034cbb..0f067c8 100644
--- a/doc/reference.txt
+++ b/doc/reference.txt
@@ -766,7 +766,7 @@ Band
       Gets the name of the band
 
 
-   .. method:: create_compatible_raster(src_width, src_height[, xstep, ystep])
+   .. method:: create_compatible_raster([src_width, src_height, xstep, ystep])
 
       Creates a raster which is compatible with the data type of the band
 
@@ -802,10 +802,12 @@ Band
 
       :param src_width:
             the width (across track dimension) of the source to be read
-            into the raster
+            into the raster. Default: scene width (see
+            :attr:`Product.get_scene_width`)
       :param src_height:
             the height (along track dimension) of the source to be read
-            into the raster
+            into the raster. Default: scene height (see
+            :attr:`Product.get_scene_height`)
       :param xstep:
             the sub-sampling step across track of the source when reading
             into the raster. Default: 1.
@@ -816,6 +818,14 @@ Band
             the new raster instance or raises an exception
             (:exc:`EPRValueError`) if an error occurred
 
+      .. note::
+
+         *src_width* and *src_height* are the dimantion of the of the source
+         area. If one specifies a *step* parameter the resulting raster
+         will have a size that is smaller that the specifies source size::
+
+             raster_size = src_size // step
+
 
    .. method:: read_raster([xoffset, yoffset, raster])
 
diff --git a/doc/usermanual.txt b/doc/usermanual.txt
index 51e0971..f7c3d97 100644
--- a/doc/usermanual.txt
+++ b/doc/usermanual.txt
@@ -46,11 +46,12 @@ In order to use PyEPR it is needed that the following software are
 correctly installed and configured:
 
 * Python2_ >= 2.6 or Python3_ >= 3.1
-* numpy_ >= 1.3.0
+* numpy_ >= 1.5.0
 * `EPR API`_ >= 2.2 (optional, since PyEPR 0.7 the source tar-ball comes
   with a copy of the PER C API sources)
 * a reasonably updated C compiler [#]_ (build only)
 * Cython_ >= 0.13 [#]_ (optional and build only)
+* unittest2_ (only required for Python < 2.7)
 
 .. note:: in order to build PyEPR_ for Python3_ it is required Cython_ >= 0.15
 
@@ -68,6 +69,7 @@ correctly installed and configured:
 .. _numpy: http://www.numpy.org
 .. _gcc: http://gcc.gnu.org
 .. _Cython: http://cython.org
+.. _unittest2: https://pypi.python.org/pypi/unittest2
 
 
 Download
@@ -77,7 +79,7 @@ Download
 
 Official source tar-balls can be downloaded form PyPi_:
 
-    http://pypi.python.org/pypi/pyepr
+    https://pypi.python.org/pypi/pyepr
 
 The source code of the development versions is available on the GitHub_
 project page
@@ -88,11 +90,13 @@ To clone the git_ repository the following command can be used::
 
     $ git clone https://github.com/avalentino/pyepr.git
 
-.. _PyPi: http://pypi.python.org
+.. _PyPi: https://pypi.python.org/pypi
 .. _GitHub: https://github.com
 .. _git: http://git-scm.com
 
 
+.. _installation:
+
 Installation
 ------------
 
@@ -104,6 +108,12 @@ The easier way to install PyEPR_ is using tools like pip_ or easy_install_::
 
     the :file:`setup.py` script does not use easy_install_ specific functions
     so it is unable to handle dependencies automatically.
+
+    Also the :file:`setup.py` script uses numpy_ to retrieve the path of
+    headers and libraries.
+    For this reaseon numpy_ must be already installed when :file:`setup.py`
+    is executed.
+
     In the above example the required numpy_ package is explicitly included in
     the list of packages to be installed.
 
@@ -147,8 +157,8 @@ with the system `EPR API`_ C library::
 
     $ python setup.py install --epr-api-src=None
 
-.. _pip: http://pypi.python.org/pypi/pip
-.. _easy_install: http://pypi.python.org/pypi/setuptools#using-setuptools-and-easyinstall
+.. _pip: https://pypi.python.org/pypi/pip
+.. _easy_install: https://pypi.python.org/pypi/setuptools#using-setuptools-and-easyinstall
 .. _distutils: http://docs.python.org/distutils
 
 
diff --git a/requirements.txt b/requirements.txt
index 1081285..6798762 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1,2 @@
-numpy>=1.3
+numpy>=1.5
 cython
diff --git a/setup.py b/setup.py
index 6c52080..41d4307 100644
--- a/setup.py
+++ b/setup.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 
-# Copyright (C) 2011-2013, Antonio Valentino <antonio.valentino at tiscali.it>
+# Copyright (C) 2011-2014, Antonio Valentino <antonio.valentino at tiscali.it>
 #
 # This file is part of PyEPR.
 #
@@ -68,12 +68,13 @@ if eprsrcdir:
     print('using EPR C API sources at "{}"'.format(eprsrcdir))
 else:
     libraries.append('epr_api')
-    print('using pre-built dynamic libraray for EPR C API')
+    print('using pre-built dynamic library for EPR C API')
 
 
 def get_version():
     filename = os.path.join('src', 'epr.pyx')
-    data = open(filename).read()
+    with open(filename) as fd:
+        data = fd.read()
 
     mobj = re.search(
         r"^__version__\s*=\s*\'(?P<version>\d+(\.\d+)*(\+|(\-)?dev)?)\'",
@@ -132,7 +133,6 @@ any data field contained in a product file.
             include_dirs=include_dirs,
             libraries=libraries,
             #define_macros=[('NPY_NO_DEPRECATED_API', 'NPY_1_7_API_VERSION'),],
-            #extra_compile_args=['-Wno-strict-prototypes', '-ansi'],
         ),
     ],
     requires=['numpy'],
diff --git a/src/epr.pyx b/src/epr.pyx
index fc8c7b9..8eef770 100644
--- a/src/epr.pyx
+++ b/src/epr.pyx
@@ -2,7 +2,7 @@
 
 # PyEPR - Python bindings for ENVISAT Product Reader API
 #
-# Copyright (C) 2011-2013, Antonio Valentino <antonio.valentino at tiscali.it>
+# Copyright (C) 2011-2014, Antonio Valentino <antonio.valentino at tiscali.it>
 #
 # This file is part of PyEPR.
 #
@@ -41,7 +41,7 @@ in a product file.
 
 '''
 
-__version__ = '0.8.1'
+__version__ = '0.8.2'
 __revision__ = __version__  # deprecated
 
 
@@ -368,6 +368,7 @@ cimport numpy as np
 np.import_array()
 
 import sys
+import weakref
 from collections import namedtuple
 
 import numpy as np
@@ -1387,7 +1388,7 @@ cdef class Raster(EprObject):
 
     cdef EPR_SRaster* _ptr
     cdef Band _parent
-    cdef np.ndarray _data
+    cdef object _data
 
     def __dealloc__(self):
         if self._ptr is not NULL:
@@ -1524,15 +1525,20 @@ cdef class Raster(EprObject):
         '''
 
         def __get__(self):
+            cdef object data
+
             if self._data is not None:
-                return self._data
+                data = self._data()
+                if data is not None:
+                    return data
 
             if self._ptr.buffer is NULL:
                 return np.ndarray(())
 
-            self._data = self.toarray()
+            data = self.toarray()
+            self._data = weakref.ref(data)
 
-            return self._data
+            return data
 
     def __repr__(self):
         return '%s %s (%dL x %dP)' % (super(Raster, self).__repr__(),
@@ -1820,8 +1826,7 @@ cdef class Band(EprObject):
 
         return _to_str(name, 'ascii')
 
-    # @TODO: default values for src_width and src_height
-    def create_compatible_raster(self, uint src_width, uint src_height,
+    def create_compatible_raster(self, uint src_width=0, uint src_height=0,
                                  uint xstep=1, uint ystep=1):
         '''create_compatible_raster(self, src_width, src_height, xstep=1, ystep=1)
 
@@ -1863,33 +1868,56 @@ cdef class Band(EprObject):
 
         :param src_width:
             the width (across track dimension) of the source to be read
-            into the raster
+            into the raster (default: scene_width)
         :param src_height:
             the height (along track dimension) of the source to be read
-            into the raster
+            into the raster (default: scene_height)
         :param xstep:
             the sub-sampling step across track of the source when
-            reading into the raster
+            reading into the raster (default=1)
         :param ystep:
             the sub-sampling step along track of the source when
-            reading into the raster
+            reading into the raster (default=1)
         :returns:
             the new raster instance or raises an exception
             (:exc:`EPRValueError`) if an error occurred
 
-        '''
+        .. note::
+
+            src_width and src_height are the dimantion of the of the source
+            area. If one specifies a *step* parameter the resulting raster
+            will have a size that is smaller that the specifies source size::
 
-        # @TODO: improve
-        #if width is None:
-        #    width = self._parent.get_scene_width()
-        #
-        #if height is None:
-        #    height = self._parent.get_scene_height()
+                raster_size = src_size // step
 
-        cdef EPR_SRaster* raster_ptr
+        '''
+
+        cdef EPR_SRaster* raster_ptr=NULL
 
         self.check_closed_product()
 
+        if src_width == 0:
+            src_width = self._parent.get_scene_width()
+        elif src_width > self._parent.get_scene_width():
+            raise ValueError('requeted raster width (%d) is too large for '
+                             'the Band (scene_width=%d)' % (
+                                src_width, self._parent.get_scene_width()))
+
+        if src_height == 0:
+            src_height = self._parent.get_scene_height()
+        elif src_height > self._parent.get_scene_height():
+            raise ValueError('requeted raster height (%d) is too large for '
+                             'the Band (scene_height=%d)' % (
+                                src_height, self._parent.get_scene_height()))
+
+        if xstep > src_width:
+            raise ValueError('xstep (%d) too large for the requested width '
+                             '(%d)' % (xstep, src_width))
+
+        if ystep > src_height:
+            raise ValueError('ystep (%d) too large for the requested height '
+                             '(%d)' % (ystep, src_height))
+
         raster_ptr = epr_create_compatible_raster(self._ptr,
                                                   src_width, src_height,
                                                   xstep, ystep)
@@ -1941,6 +1969,14 @@ cdef class Band(EprObject):
         if raster is None:
             raster = self.create_compatible_raster()
 
+        if (xoffset + raster.source_width > self.product.get_scene_width() or
+                yoffset + raster.source_height >
+                    self.product.get_scene_height()):
+            raise ValueError(
+                'at lease part of the requested area is outside the scene')
+
+        raster._data = None
+
         with nogil:
             ret = epr_read_band_raster(self._ptr, xoffset, yoffset,
                                        raster._ptr)
@@ -1948,8 +1984,6 @@ cdef class Band(EprObject):
         if ret != 0:
             pyepr_check_errors()
 
-        raster._data = None
-
         return raster
 
     # --- high level interface ------------------------------------------------
@@ -2061,10 +2095,11 @@ cdef class Dataset(EprObject):
         '''A short description of the band's contents'''
 
         def __get__(self):
-            if self._ptr.description is NULL:
-                return ''
-            else:
-                return _to_str(self._ptr.description, 'ascii')
+            if self._ptr is not NULL:
+                self.check_closed_product()
+                if self._ptr.description is not NULL:
+                    return _to_str(self._ptr.description, 'ascii')
+            return ''
 
     def get_name(self):
         '''get_name(self)
diff --git a/test/test_all.py b/test/test_all.py
old mode 100644
new mode 100755
index 740f0de..f06da17
--- a/test/test_all.py
+++ b/test/test_all.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 
-# Copyright (C) 2011-2013, Antonio Valentino <antonio.valentino at tiscali.it>
+# Copyright (C) 2011-2014, Antonio Valentino <antonio.valentino at tiscali.it>
 #
 # This file is part of PyEPR.
 #
@@ -24,14 +24,25 @@ import re
 import sys
 import numbers
 import operator
-import unittest
 import tempfile
 import functools
+from distutils.version import LooseVersion
 
-import numpy as np
+try:
+    import resource
+except ImportError:
+    resource = None
 
-TESTDIR = os.path.abspath(os.path.dirname(__file__))
-sys.path.insert(0, os.path.join(TESTDIR, os.pardir))
+try:
+    from unittest import skipIf
+except ImportError:
+    import unittest2 as unittest
+else:
+    del skipIf
+    import unittest
+
+import numpy as np
+import numpy.testing as npt
 
 import epr
 
@@ -52,6 +63,19 @@ EPR_TO_NUMPY_TYPE = {
 }
 
 
+def has_epr_c_bug_pyepr009():
+    v = LooseVersion(epr.EPR_C_API_VERSION)
+    if 'pyepr' in v.version:
+        return v < LooseVersion('2.3dev_pyepr082')
+    else:
+        return v <= LooseVersion('2.3')
+
+
+EPR_C_BUG_PYEPR009 = has_epr_c_bug_pyepr009()
+EPR_C_BUG_BCEPR002 = EPR_C_BUG_PYEPR009
+
+
+TESTDIR = os.path.abspath(os.path.dirname(__file__))
 TEST_PRODUCT = 'MER_LRC_2PTGMV20000620_104318_00000104X000_00000_00000_0001.N1'
 
 
@@ -573,7 +597,6 @@ class TestDataset(unittest.TestCase):
         created_record = self.dataset.create_record()
         read_record = self.dataset.read_record(0, created_record)
         self.assertTrue(created_record is read_record)
-        # @TODO: check contents
 
     def test_read_record_passed_invalid(self):
         self.assertRaises(TypeError, self.dataset.read_record, 0, 0)
@@ -640,8 +663,7 @@ class TestDatasetOnClosedProduct(unittest.TestCase):
         self.assertTrue(isinstance(self.dataset.product, epr.Product))
 
     def test_description_property(self):
-        # @TODO: check
-        self.assertEqual(self.dataset.description, '')
+        self.assertRaises(ValueError, getattr, self.dataset, 'description')
 
     def test_get_name(self):
         self.assertRaises(ValueError, self.dataset.get_name)
@@ -801,11 +823,11 @@ class TestBand(unittest.TestCase):
         self.assertRaises((ValueError, OverflowError),
                           self.band.create_compatible_raster,
                           width, -1)
-        # @TODO: check
-        #self.assertRaises(ValueError, self.band.create_compatible_raster,
-        #                  self.product.get_scene_width() + 10, height)
-        #self.assertRaises(ValueError, self.band.create_compatible_raster,
-        #                  width, self.product.get_scene_height() + 10)
+
+        self.assertRaises(ValueError, self.band.create_compatible_raster,
+                          self.product.get_scene_width() + 10, height)
+        self.assertRaises(ValueError, self.band.create_compatible_raster,
+                          width, self.product.get_scene_height() + 10)
 
     def test_create_compatible_raster_with_step(self):
         src_width = self.product.get_scene_width()
@@ -836,60 +858,103 @@ class TestBand(unittest.TestCase):
                           self.band.create_compatible_raster,
                           width, height, -2, -1)
 
-        # @TODO: check
-        #self.assertRaises((ValueError, OverflowError),
-        #                  self.band.create_compatible_raster,
-        #                  width, height, width + 10, 2)
-        #self.assertRaises((ValueError, OverflowError),
-        #                  self.band.create_compatible_raster,
-        #                  width, height, 2, height + 10)
-        #self.assertRaises((ValueError, OverflowError),
-        #                  self.band.create_compatible_raster,
-        #                  width, height, width + 10, height + 10)
+        self.assertRaises((ValueError, ValueError),
+                          self.band.create_compatible_raster,
+                          width, height, width + 10, 2)
+        self.assertRaises((ValueError, ValueError),
+                          self.band.create_compatible_raster,
+                          width, height, 2, height + 10)
+        self.assertRaises((ValueError, ValueError),
+                          self.band.create_compatible_raster,
+                          width, height, width + 10, height + 10)
+
+    def test_create_compatible_raster_with_default_size(self):
+        src_width = self.product.get_scene_width()
+        src_height = self.product.get_scene_height()
+        raster = self.band.create_compatible_raster()
+        self.assertTrue(isinstance(raster, epr.Raster))
+        self.assertEqual(raster.get_width(), src_width)
+        self.assertEqual(raster.get_height(), src_height)
+        # @NOTE: data type on disk is epr.E_TID_USHORT
+        self.assertEqual(raster.data_type, epr.E_TID_FLOAT)
 
     def test_read_raster(self):
-        raster = self.band.create_compatible_raster(self.WIDTH, self.HEIGHT)
+        rasterin = self.band.create_compatible_raster(self.WIDTH, self.HEIGHT)
 
-        self.band.read_raster(self.XOFFSET, self.YOFFSET, raster)
+        raster = self.band.read_raster(self.XOFFSET, self.YOFFSET, rasterin)
 
         self.assertTrue(isinstance(raster, epr.Raster))
+        self.assertTrue(raster is rasterin)
         self.assertEqual(raster.get_width(), self.WIDTH)
         self.assertEqual(raster.get_height(), self.HEIGHT)
         # @NOTE: data type on disk is epr.E_TID_USHORT
         self.assertEqual(raster.data_type, epr.E_TID_FLOAT)
 
+        h, w = self.TEST_DATA.shape
+        npt.assert_allclose(raster.get_pixel(0, 0), self.TEST_DATA[0, 0])
+        npt.assert_allclose(raster.get_pixel(w - 1, h - 1),
+                            self.TEST_DATA[h - 1, w - 1])
+
+    def test_read_raster_none(self):
+        raster = self.band.read_raster()
+
+        self.assertTrue(isinstance(raster, epr.Raster))
+        self.assertEqual(raster.get_width(), self.product.get_scene_width())
+        self.assertEqual(raster.get_height(), self.product.get_scene_height())
+        # @NOTE: data type on disk is epr.E_TID_USHORT
+        self.assertEqual(raster.data_type, epr.E_TID_FLOAT)
+
+        h, w = self.TEST_DATA.shape
+        npt.assert_allclose(
+            raster.get_pixel(self.XOFFSET, self.YOFFSET), self.TEST_DATA[0, 0])
+        npt.assert_allclose(
+            raster.get_pixel(self.XOFFSET + w - 1, self.YOFFSET + h - 1),
+            self.TEST_DATA[h - 1, w - 1])
+
     def test_read_raster_default_offset(self):
-        height, width = self.TEST_DATA.shape
+        height = self.HEIGHT
+        width = self.WIDTH
 
         raster1 = self.band.create_compatible_raster(width, height)
         raster2 = self.band.create_compatible_raster(width, height)
 
-        self.band.read_raster(0, 0, raster1)
-        self.band.read_raster(raster=raster2)
+        r1 = self.band.read_raster(0, 0, raster1)
+        r2 = self.band.read_raster(raster=raster2)
 
+        self.assertTrue(r1 is raster1)
+        self.assertTrue(r2 is raster2)
         self.assertEqual(raster1.get_pixel(0, 0), raster2.get_pixel(0, 0))
         self.assertEqual(raster1.get_pixel(width - 1, height - 1),
                          raster2.get_pixel(width - 1, height - 1))
 
+        h, w = self.TEST_DATA.shape
+        npt.assert_allclose(
+            raster1.get_pixel(self.XOFFSET, self.YOFFSET),
+            self.TEST_DATA[0, 0])
+        npt.assert_allclose(
+            raster1.get_pixel(self.XOFFSET + w - 1, self.YOFFSET + h - 1),
+            self.TEST_DATA[h - 1, w - 1])
+
     def test_read_raster_with_invalid_raster(self):
         self.assertRaises(TypeError, self.band.read_raster, 0, 0, 0)
 
     def test_read_raster_with_invalid_offset(self):
         raster = self.band.create_compatible_raster(self.WIDTH, self.HEIGHT)
 
-        # @TODO: check
         self.assertRaises(ValueError, self.band.read_raster, -1, 0, raster)
         self.assertRaises(ValueError, self.band.read_raster, 0, -1, raster)
         self.assertRaises(ValueError, self.band.read_raster, -1, -1, raster)
-        # @TODO: check
-        #self.assertRaises(ValueError, self.band.read_raster,
-        #                  width + 10, 0, raster)
-        #self.assertRaises(ValueError, self.band.read_raster,
-        #                  0, height + 10, raster)
-        #self.assertRaises(ValueError, self.band.read_raster,
-        #                  width + 10, height + 10, raster)
 
-    def test_read_as_array(self):
+        invalid_xoffset = self.WIDTH
+        invalid_yoffset = self.HEIGHT
+        self.assertRaises(ValueError, self.band.read_raster,
+                          invalid_xoffset, 0, raster)
+        self.assertRaises(ValueError, self.band.read_raster,
+                          0, invalid_yoffset, raster)
+        self.assertRaises(ValueError, self.band.read_raster,
+                          invalid_xoffset, invalid_yoffset, raster)
+
+    def test_read_as_array_ref(self):
         data = self.band.read_as_array(self.WIDTH, self.HEIGHT,
                                        self.XOFFSET, self.YOFFSET)
 
@@ -898,29 +963,178 @@ class TestBand(unittest.TestCase):
         self.assertEqual(data.dtype, self.DATA_TYPE)
 
         h, w = self.TEST_DATA.shape
-        self.assertTrue(np.allclose(data[:h, :w], self.TEST_DATA))
+        npt.assert_allclose(data[:h, :w], self.TEST_DATA)
+
+    def test_read_as_array_cross(self):
+        data = self.band.read_as_array()
+        box = self.band.read_as_array(self.WIDTH, self.HEIGHT,
+                                      self.XOFFSET, self.YOFFSET)
+
+        npt.assert_array_equal(
+            data[self.YOFFSET:self.YOFFSET + self.HEIGHT,
+                 self.XOFFSET:self.XOFFSET + self.WIDTH],
+            box)
+
+    def test_read_as_array_default(self):
+        data = self.band.read_as_array()
+
+        self.assertTrue(isinstance(data, np.ndarray))
+        self.assertEqual(
+            data.shape,
+            (self.product.get_scene_height(), self.product.get_scene_width()))
+        self.assertEqual(data.dtype, self.DATA_TYPE)
+
+        h, w = self.TEST_DATA.shape
+        npt.assert_allclose(
+            data[self.YOFFSET:self.YOFFSET + h, self.XOFFSET:self.XOFFSET + w],
+            self.TEST_DATA)
 
-    # @TODO: check, it seems to be an upstream bug or a metter of data
-    #        mirroring
     # @SEEALSO: https://www.brockmann-consult.de/beam-jira/browse/EPR-2
-    #def test_read_as_array_with_step(self):
-    #    width = 400
-    #    height = 300
-    #
-    #    data = self.band.read_as_array(width, height,
-    #                                   self.XOFFSET, self.YOFFSET, 2, 2)
-    #
-    #    self.assertTrue(isinstance(data, np.ndarray))
-    #    self.assertEqual(data.shape, (height/2, width/2))
-    #    self.assertEqual(data.dtype, self.DATA_TYPE)
-    #
-    #    h, w = self.TEST_DATA.shape
-    #    self.assertTrue(
-    #               np.all(data[:h / 2, :w / 2] == self.TEST_DATA[::2, ::2]))
-    #    #self.assertTrue(
-    #    #           np.all(data[:h / 2, :w / 2] == self.TEST_DATA[::2, 1::2]))
-
-    # @TODO: more read_as_array testing
+    @unittest.skipIf(EPR_C_BUG_BCEPR002, 'buggy EPR_C_API detected')
+    def test_read_as_array_with_step_2(self):
+        step = 2
+        band = self.band
+
+        data = band.read_as_array()
+        box = band.read_as_array(self.WIDTH, self.HEIGHT,
+                                 self.XOFFSET, self.YOFFSET, step, step)
+
+        self.assertTrue(isinstance(box, np.ndarray))
+        self.assertEqual(
+            box.shape,
+            ((self.HEIGHT - 1) // step + 1, (self.WIDTH - 1) // step + 1))
+        self.assertEqual(box.dtype, self.DATA_TYPE)
+
+        npt.assert_allclose(
+            data[self.YOFFSET:self.YOFFSET + self.HEIGHT:step,
+                 self.XOFFSET:self.XOFFSET + self.WIDTH:step],
+            box)
+
+        h, w = self.TEST_DATA.shape
+        npt.assert_allclose(
+            box[:(h-1)//step+1, :(w-1)//step+1],
+            self.TEST_DATA[::step, ::step])
+
+    @unittest.skipIf(EPR_C_BUG_BCEPR002, 'buggy EPR_C_API detected')
+    def test_read_as_array_with_step_3(self):
+        step = 3
+        band = self.band
+
+        data = band.read_as_array()
+        box = band.read_as_array(self.WIDTH, self.HEIGHT,
+                                 self.XOFFSET, self.YOFFSET, step, step)
+
+        self.assertTrue(isinstance(box, np.ndarray))
+        self.assertEqual(
+            box.shape,
+            ((self.HEIGHT - 1) // step + 1, (self.WIDTH - 1) // step + 1))
+        self.assertEqual(box.dtype, self.DATA_TYPE)
+
+        npt.assert_allclose(
+            data[self.YOFFSET:self.YOFFSET + self.HEIGHT:step,
+                 self.XOFFSET:self.XOFFSET + self.WIDTH:step],
+            box)
+
+        h, w = self.TEST_DATA.shape
+        npt.assert_allclose(
+            box[:(h-1)//step+1, :(w-1)//step+1],
+            self.TEST_DATA[::step, ::step])
+
+    @unittest.skipIf(EPR_C_BUG_BCEPR002, 'buggy EPR_C_API detected')
+    def test_read_as_array_with_step_4(self):
+        step = 4
+        band = self.band
+
+        data = band.read_as_array()
+        box = band.read_as_array(self.WIDTH, self.HEIGHT,
+                                 self.XOFFSET, self.YOFFSET, step, step)
+
+        self.assertTrue(isinstance(box, np.ndarray))
+        self.assertEqual(
+            box.shape,
+            ((self.HEIGHT - 1) // step + 1, (self.WIDTH - 1) // step + 1))
+        self.assertEqual(box.dtype, self.DATA_TYPE)
+
+        npt.assert_allclose(
+            data[self.YOFFSET:self.YOFFSET + self.HEIGHT:step,
+                 self.XOFFSET:self.XOFFSET + self.WIDTH:step],
+            box)
+
+        h, w = self.TEST_DATA.shape
+        npt.assert_allclose(
+            box[:(h-1)//step+1, :(w-1)//step+1],
+            self.TEST_DATA[::step, ::step])
+
+    @unittest.skipIf(EPR_C_BUG_BCEPR002, 'buggy EPR_C_API detected')
+    def test_read_as_array_with_step_5(self):
+        step = 5
+        band = self.band
+
+        data = band.read_as_array()
+        box = band.read_as_array(self.WIDTH, self.HEIGHT,
+                                 self.XOFFSET, self.YOFFSET, step, step)
+
+        self.assertTrue(isinstance(box, np.ndarray))
+        self.assertEqual(
+            box.shape,
+            ((self.HEIGHT - 1) // step + 1, (self.WIDTH - 1) // step + 1))
+        self.assertEqual(box.dtype, self.DATA_TYPE)
+
+        npt.assert_allclose(
+            data[self.YOFFSET:self.YOFFSET + self.HEIGHT:step,
+                 self.XOFFSET:self.XOFFSET + self.WIDTH:step],
+            box)
+
+        h, w = self.TEST_DATA.shape
+        npt.assert_allclose(
+            box[:(h-1)//step+1, :(w-1)//step+1],
+            self.TEST_DATA[::step, ::step])
+
+
+class TestAnnotationBand(TestBand):
+    BAND_NAME = 'sun_zenith'
+    BAND_DESCTIPTION = 'Sun zenith angle'
+    SCALING_FACTOR = 9.999999974752427e-07
+    SCALING_OFFSET = 0.0
+    UNIT = 'deg'
+    TEST_DATA = np.asarray([
+        [33.11141205, 33.07904434, 33.04668045, 33.01435089, 32.98202515,
+         32.94969559, 32.91736603, 32.88507462, 32.85278320, 32.82049179],
+        [33.08905792, 33.05667114, 33.02428818, 32.99193954, 32.95959473,
+         32.92724609, 32.89489746, 32.86258316, 32.83027649, 32.79796219],
+        [33.06670380, 33.03429794, 33.00189590, 32.96953201, 32.93716431,
+         32.90479279, 32.87242889, 32.84009933, 32.80776978, 32.77543640],
+        [33.04434967, 33.01192474, 32.97950363, 32.94711685, 32.91473389,
+         32.88234329, 32.84995651, 32.81761169, 32.78525925, 32.75291061],
+        [33.02199554, 32.98955536, 32.95711136, 32.92470551, 32.89229965,
+         32.85989380, 32.82748795, 32.79512024, 32.76274872, 32.73038101],
+        [32.99978256, 32.96732330, 32.93486023, 32.90243149, 32.87001038,
+         32.83758163, 32.80516052, 32.77277374, 32.74037933, 32.70799255],
+        [32.97756958, 32.94509125, 32.91260529, 32.88016129, 32.84771729,
+         32.81527328, 32.78282928, 32.75042343, 32.71801376, 32.68560410],
+        [32.95535278, 32.92285538, 32.89035416, 32.85789108, 32.82542419,
+         32.79296494, 32.76049805, 32.72807693, 32.69564438, 32.66321945],
+        [32.93313980, 32.90061951, 32.86810303, 32.83562088, 32.80313873,
+         32.77065277, 32.73817062, 32.70572281, 32.67327881, 32.64083099],
+        [32.91106796, 32.87852859, 32.84599304, 32.81349182, 32.78099060,
+         32.74848557, 32.71598434, 32.68351364, 32.65105438, 32.61858749],
+    ])
+
+    @unittest.skipIf(EPR_C_BUG_PYEPR009, 'buggy EPR_C_API detected')
+    def test_read_raster(self):
+        super(TestAnnotationBand, self).test_read_raster()
+
+    @unittest.skipIf(EPR_C_BUG_PYEPR009, 'buggy EPR_C_API detected')
+    def test_read_raster_default_offset(self):
+        super(TestAnnotationBand, self).test_read_raster_default_offset()
+
+    @unittest.skipIf(EPR_C_BUG_PYEPR009, 'buggy EPR_C_API detected')
+    def test_read_as_array_ref(self):
+        super(TestAnnotationBand, self).test_read_as_array_ref()
+
+    @unittest.skipIf(EPR_C_BUG_PYEPR009, 'buggy EPR_C_API detected')
+    def test_read_as_array_cross(self):
+        super(TestAnnotationBand, self).test_read_as_array_cross()
 
 
 class TestBandHighLevelAPI(unittest.TestCase):
@@ -996,7 +1210,8 @@ class TestBandOnClosedProduct(unittest.TestCase):
 
     def test_lines_mirrored_property(self):
         self.assertTrue(isinstance(self.band.lines_mirrored, bool))
-        self.assertEqual(self.band.lines_mirrored, False)
+        # @TODO: check
+        #self.assertEqual(self.band.lines_mirrored, False)
 
     # END: check
 
@@ -1158,7 +1373,7 @@ class TestRaster(unittest.TestCase):
         self.assertEqual(data.dtype, EPR_TO_NUMPY_TYPE[self.raster.data_type])
 
         ny, nx = self.TEST_DATA.shape
-        self.assertTrue(np.allclose(data[:ny, :nx], self.TEST_DATA))
+        npt.assert_allclose(data[:ny, :nx], self.TEST_DATA)
 
     def test_data_property_two_times(self):
         data1 = self.raster.data
@@ -1186,7 +1401,7 @@ class TestRaster(unittest.TestCase):
         self.assertTrue(isinstance(data, np.ndarray))
 
         ny, nx = self.TEST_DATA.shape
-        self.assertTrue(np.allclose(data[:ny, :nx], self.TEST_DATA))
+        npt.assert_allclose(data[:ny, :nx], self.TEST_DATA)
 
 
 class TestRasterRead(TestRaster):
@@ -1215,6 +1430,26 @@ class TestRasterRead(TestRaster):
         self.assertTrue(np.all(data1 == data2))
 
 
+class TestAnnotatedRasterRead(TestRasterRead):
+    PRODUCT_FILE = os.path.join(TESTDIR, TEST_PRODUCT)
+    BAND_NAME = TestAnnotationBand.BAND_NAME
+    RASTER_XOFFSET = TestAnnotationBand.XOFFSET
+    RASTER_YOFFSET = TestAnnotationBand.YOFFSET
+    TEST_DATA = TestAnnotationBand.TEST_DATA
+
+    @unittest.skipIf(EPR_C_BUG_PYEPR009, 'buggy EPR_C_API detected')
+    def test_get_pixel(self):
+        super(TestAnnotatedRasterRead, self).test_get_pixel()
+
+    @unittest.skipIf(EPR_C_BUG_PYEPR009, 'buggy EPR_C_API detected')
+    def test_data_property(self):
+        super(TestAnnotatedRasterRead, self).test_data_property()
+
+    @unittest.skipIf(EPR_C_BUG_PYEPR009, 'buggy EPR_C_API detected')
+    def test_data_property_raster_scope(self):
+        super(TestAnnotatedRasterRead, self).test_data_property_raster_scope()
+
+
 class TestRasterHighLevelAPI(unittest.TestCase):
     RASTER_WIDTH = 400
     RASTER_HEIGHT = 300
@@ -1530,8 +1765,7 @@ class TestField(unittest.TestCase):
         self.assertTrue(isinstance(vect, np.ndarray))
         self.assertEqual(vect.shape, (self.field.get_num_elems(),))
         self.assertEqual(vect.dtype, np.int8)
-        self.assertTrue(np.allclose(vect[:len(self.FIELD_VALUES)],
-                                    self.FIELD_VALUES))
+        npt.assert_allclose(vect[:len(self.FIELD_VALUES)], self.FIELD_VALUES)
 
 
 class TestFieldWithMiltipleElems(TestField):
@@ -1973,6 +2207,24 @@ class TestLibVersion(unittest.TestCase):
         self.assertTrue(isinstance(epr.EPR_C_API_VERSION, str))
 
 
+ at unittest.skipIf(resource is None, '"resource" module not available')
+class TestMemoryLeaks(unittest.TestCase):
+    # See gh-10 (https://github.com/avalentino/pyepr/issues/10)
+
+    PRODUCT_FILE = os.path.join(TESTDIR, TEST_PRODUCT)
+
+    def test_memory_leacks_on_read_as_array(self):
+        N = 10
+
+        for n in range(N):
+            with epr.open(self.PRODUCT_FILE) as p:
+                p.get_band('l2_flags').read_as_array()
+            if n <= 1:
+                m1 = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
+            m2 = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
+        self.assertLessEqual(m2 - m1, 8)
+
+
 if __name__ == '__main__':
     print('PyEPR: %s' % epr.__version__)
     print('EPR API: %s' % epr.EPR_C_API_VERSION)

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/pyepr.git



More information about the Pkg-grass-devel mailing list