Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ Documentation changes
Test suite
----------
* Fix AttributeError on Python 3.9 due to usage of ``base64.decodestring`` in tests (#210)
* Make optional dependencies optional for tests (#260)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing I noticed in this PR (it very well may have already been pointed out, I can't remember), is that with the new news fragment system PRs are added to the changelog in order of lowest to highest PR number, which may differ from other ets changelogs.
Not saying anything needs to change, just an observation

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh. Good point. Not anything we need to change though.


Build System
------------
* Add extras_require to setup.py for optional dependencies (#257)

Version 4.5.0
~~~~~~~~~~~~~
Expand Down
3 changes: 1 addition & 2 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ include CHANGES.txt
include LICENSE.txt
include MANIFEST.in
include image_LICENSE.txt
include image_LICENSE_Nuvola.txt
include image_LICENSE_OOo.txt
include image_LICENSE_CP.txt
graft docs
prune docs/build
recursive-exclude docs *.pyc
Expand Down
32 changes: 32 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,46 @@ All packages in apptools require:

* `traits <https://github.com/enthought/traits>`_

Certain sub-packages within apptools have their own specific dependencies,
which are optional for apptools overall.

The `apptools.preferences` package requires:

* `configobj <http://pypi.python.org/pypi/configobj>`_

The `apptools.io.h5` package requires:

* `numpy <https://pypi.org/project/numpy/>`_
* `pandas <https://pypi.org/project/pandas/>`_
* `tables <https://pypi.org/project/tables/>`_

The `apptools.persistence` package requires:

* `numpy <https://pypi.org/project/numpy/>`_

Many of the packages provide optional user interfaces using Pyface and
Traitsui. In additon, many of the packages are designed to work with the
Envisage plug-in system, althought most can be used independently:

* `envisage <https://github.com/enthought/envisage>`_
* `pyface <https://github.com/enthought/pyface>`_
* `traitsui <https://github.com/enthought/traitsui>`_

Installation
------------

To install with `apptools.preferences` dependencies::

$ pip install apptools[preferences]

To install with `apptools.io.h5` dependencies::

$ pip install apptools[h5]

To install with `apptools.persistence` dependencies::

$ pip install apptools[persistence]

To install with additional test dependencies::

$ pip install apptools[test]
25 changes: 16 additions & 9 deletions apptools/io/h5/tests/test_dict_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,23 @@
# Thanks for using Enthought open source!
import unittest

import numpy as np
from numpy.testing import assert_allclose
from apptools._testing.optional_dependencies import (
numpy as np,
tables,
requires_numpy,
requires_tables,
)

from ..dict_node import H5DictNode
from .utils import open_h5file, temp_h5_file, temp_file
if np is not None and tables is not None:
from ..dict_node import H5DictNode
from .utils import open_h5file, temp_h5_file, temp_file


NODE = "/dict_node"


@requires_tables
@requires_numpy
class DictNodeTestCase(unittest.TestCase):
def test_create(self):
with temp_h5_file() as h5:
Expand Down Expand Up @@ -56,8 +63,8 @@ def test_create_with_array_data(self):

h5dict = H5DictNode.add_to_h5file(h5, NODE, data)
assert h5dict["a"] == 10
assert_allclose(h5dict["foo"], foo)
assert_allclose(h5dict["bar"], bar)
np.testing.assert_allclose(h5dict["foo"], foo)
np.testing.assert_allclose(h5dict["bar"], bar)

def test_load_saved_dict_node(self):
with temp_file() as filename:
Expand Down Expand Up @@ -91,16 +98,16 @@ def test_load_saved_dict_node_with_array(self):
# Read dict node and make sure the data was saved.
with open_h5file(filename, mode="r+") as h5:
h5dict = h5[NODE]
assert_allclose(h5dict["arr"], arr)
np.testing.assert_allclose(h5dict["arr"], arr)
# Change data for next test
h5dict["arr"] = arr1
h5dict["arr_old"] = arr

# Check that data is modified by the previous write.
with open_h5file(filename) as h5:
h5dict = h5[NODE]
assert_allclose(h5dict["arr"], arr1)
assert_allclose(h5dict["arr_old"], arr)
np.testing.assert_allclose(h5dict["arr"], arr1)
np.testing.assert_allclose(h5dict["arr_old"], arr)
# Make sure that arrays come back as arrays
assert isinstance(h5dict["arr"], np.ndarray)
assert isinstance(h5dict["arr_old"], np.ndarray)
Expand Down
50 changes: 28 additions & 22 deletions apptools/io/h5/tests/test_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,25 @@
from contextlib import closing
import unittest

import numpy as np
from numpy import testing
import tables
from apptools._testing.optional_dependencies import (
numpy as np,
tables,
requires_numpy,
requires_tables,
)

from ..file import H5File
from ..dict_node import H5DictNode
from ..table_node import H5TableNode
from .utils import open_h5file, temp_h5_file
if np is not None and tables is not None:
from ..file import H5File
from ..dict_node import H5DictNode
from ..table_node import H5TableNode
from .utils import open_h5file, temp_h5_file


H5_TEST_FILE = "_temp_test_filt.h5"


@requires_numpy
@requires_tables
class FileTestCase(unittest.TestCase):
def tearDown(self):
try:
Expand Down Expand Up @@ -58,9 +64,9 @@ def test_create_array_with_H5File(self):
with open_h5file(H5_TEST_FILE, mode="w") as h5:
h5array = h5.create_array("/array", array)
# Test returned array
testing.assert_allclose(h5array, array)
np.testing.assert_allclose(h5array, array)
# Test stored array
testing.assert_allclose(h5["/array"], array)
np.testing.assert_allclose(h5["/array"], array)

def test_create_array_with_H5Group(self):
array = np.arange(3)
Expand All @@ -69,9 +75,9 @@ def test_create_array_with_H5Group(self):
group = h5.create_group("/tardigrade")
h5array = group.create_array("array", array)
# Test returned array
testing.assert_allclose(h5array, array)
np.testing.assert_allclose(h5array, array)
# Test stored array
testing.assert_allclose(h5[node_path], array)
np.testing.assert_allclose(h5[node_path], array)

def test_getitem_failure(self):
array = np.arange(3)
Expand Down Expand Up @@ -117,28 +123,28 @@ def test_create_chunked_array_with_H5File(self):
array = np.arange(3, dtype=np.uint8)
with open_h5file(H5_TEST_FILE, mode="w") as h5:
h5array = h5.create_array("/array", array, chunked=True)
testing.assert_allclose(h5array, array)
np.testing.assert_allclose(h5array, array)
assert isinstance(h5array, tables.CArray)

def test_create_chunked_array_with_H5Group(self):
array = np.arange(3, dtype=np.uint8)
with open_h5file(H5_TEST_FILE, mode="w") as h5:
h5array = h5.root.create_array("/array", array, chunked=True)
testing.assert_allclose(h5array, array)
np.testing.assert_allclose(h5array, array)
assert isinstance(h5array, tables.CArray)

def test_create_extendable_array_with_H5File(self):
array = np.arange(3, dtype=np.uint8)
with open_h5file(H5_TEST_FILE, mode="w") as h5:
h5array = h5.create_array("/array", array, extendable=True)
testing.assert_allclose(h5array, array)
np.testing.assert_allclose(h5array, array)
assert isinstance(h5array, tables.EArray)

def test_create_extendable_array_with_H5Group(self):
array = np.arange(3, dtype=np.uint8)
with open_h5file(H5_TEST_FILE, mode="w") as h5:
h5array = h5.root.create_array("/array", array, extendable=True)
testing.assert_allclose(h5array, array)
np.testing.assert_allclose(h5array, array)
assert isinstance(h5array, tables.EArray)

def test_str_and_repr(self):
Expand Down Expand Up @@ -179,7 +185,7 @@ def test_delete_existing_array_with_H5File(self):
h5.create_array("/array", old_array)
# New array with the same node name should delete old array
h5.create_array("/array", new_array)
testing.assert_allclose(h5["/array"], new_array)
np.testing.assert_allclose(h5["/array"], new_array)

def test_delete_existing_array_with_H5Group(self):
old_array = np.arange(3)
Expand All @@ -188,7 +194,7 @@ def test_delete_existing_array_with_H5Group(self):
h5.create_array("/array", old_array)
# New array with the same node name should delete old array
h5.root.create_array("/array", new_array, delete_existing=True)
testing.assert_allclose(h5["/array"], new_array)
np.testing.assert_allclose(h5["/array"], new_array)

def test_delete_existing_dict_with_H5File(self):
old_dict = {"a": "Goose"}
Expand Down Expand Up @@ -371,8 +377,8 @@ def test_groups(self):
group_b = group_a["b"]
# Check that __contains__ works for arrays
assert "array" in group_b
testing.assert_allclose(group_b["array"], array)
testing.assert_allclose(group_a["b/array"], array)
np.testing.assert_allclose(group_b["array"], array)
np.testing.assert_allclose(group_a["b/array"], array)

def test_group_attributes(self):
value_1 = "foo"
Expand Down Expand Up @@ -419,7 +425,7 @@ def test_mapping_interface_for_file(self):
assert len(h5) == 2
assert "/group" in h5
assert "/array" in h5
testing.assert_allclose(h5["/array"], array)
np.testing.assert_allclose(h5["/array"], array)
assert set(n.name for n in h5) == set(["array", "group"])

def test_mapping_interface_for_group(self):
Expand All @@ -431,7 +437,7 @@ def test_mapping_interface_for_group(self):
assert len(group) == 2
assert "subgroup" in group
assert "array" in group
testing.assert_allclose(group["array"], array)
np.testing.assert_allclose(group["array"], array)
assert set(n.name for n in group) == set(["array", "subgroup"])

def test_group_str_and_repr(self):
Expand All @@ -447,7 +453,7 @@ def test_attribute_translation(self):
with open_h5file(H5_TEST_FILE, mode="w") as h5:
h5["/"].attrs["name"] = value_1
assert isinstance(h5["/"].attrs["name"], np.ndarray)
testing.assert_allclose(h5["/"].attrs["name"], value_1_array)
np.testing.assert_allclose(h5["/"].attrs["name"], value_1_array)

def test_get_attribute(self):
with open_h5file(H5_TEST_FILE, mode="w") as h5:
Expand Down
2 changes: 0 additions & 2 deletions apptools/logger/log_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@

# Standard library imports.
import inspect

# Third-party library imports.
from io import StringIO


Expand Down
4 changes: 1 addition & 3 deletions apptools/logger/plugin/logger_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,11 @@
#
# Thanks for using Enthought open source!
# Standard library imports
from io import BytesIO
import logging
import os
import zipfile

# Third-party library imports
from io import BytesIO

# Enthought library imports
from pyface.workbench.api import View as WorkbenchView
from traits.api import (
Expand Down
15 changes: 0 additions & 15 deletions apptools/logger/plugin/view/images/image_LICENSE.txt

This file was deleted.

12 changes: 10 additions & 2 deletions apptools/persistence/tests/test_file_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,24 @@
# 3rd party imports.
from importlib_resources import files

from apptools._testing.optional_dependencies import (
numpy as np,
requires_numpy,
)

# Enthought library imports.
from apptools.persistence import state_pickler
from apptools.persistence import file_path
if np is not None:
from apptools.persistence import state_pickler
from apptools.persistence import file_path


@requires_numpy
class Test:
def __init__(self):
self.f = file_path.FilePath()


@requires_numpy
class TestFilePath(unittest.TestCase):
def setUp(self):
# If the cwd is somewhere under /tmp, that confuses the tests below.
Expand Down
6 changes: 5 additions & 1 deletion apptools/persistence/tests/test_state_pickler.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
import os
import tempfile

import numpy
try:
import numpy
except ImportError:
raise unittest.SkipTest("Can't import NumPy: skipping")

from traits.api import (
Bool,
Expand Down Expand Up @@ -48,6 +51,7 @@

# A simple class to test instances.
class A(object):

def __init__(self):
self.a = "a"

Expand Down
8 changes: 7 additions & 1 deletion apptools/persistence/tests/test_version_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@
# Enthought library imports.
from traits.api import HasTraits

from apptools.persistence import version_registry, state_pickler
from apptools._testing.optional_dependencies import (
numpy as np,
requires_numpy,
)
if np is not None:
from apptools.persistence import version_registry, state_pickler


class Classic:
Expand Down Expand Up @@ -52,6 +57,7 @@ def upgrade1(self, state, version):
self.calls.append(("upgrade1", state, version))


@requires_numpy
class TestVersionRegistry(unittest.TestCase):
def test_get_version(self):
"""Test the get_version function."""
Expand Down
Loading