enthought / apptools Goto Github PK
View Code? Open in Web Editor NEWLicense: Other
License: Other
There are several (random, of course) test failures when running the test suite with PYTHONHASHSEED=random, indicating that we've got dictionary-order dependencies either in the core code (bad), or the test-suite (not so bad, but should still be fixed). An example test run is below.
(Canopy 64bit) taniyama:apptools mdickinson$ PYTHONHASHSEED=random nosetests .
............................................................................................................F.............F..............F..............F.............F................F...EF.F....................F........................................................................................................................................................................
======================================================================
ERROR: Test if classic classes can be pickled.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/mdickinson/Enthought/ETS/apptools/apptools/persistence/tests/test_state_pickler.py", line 245, in test_pickle_classic
self.verify(t, state)
File "/Users/mdickinson/Enthought/ETS/apptools/apptools/persistence/tests/test_state_pickler.py", line 112, in verify
self.assertEqual(lst[-1]['data']['data']['a'], 'b')
TypeError: 'NoneType' object has no attribute '__getitem__'
======================================================================
FAIL: test retrieving the names of bound objects
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/mdickinson/Enthought/ETS/apptools/apptools/naming/tests/context_test_case.py", line 514, in test_search
self.assertEqual( names, ['one', 'sub/sub sub/one'] )
AssertionError: Lists differ: ['sub/sub sub/one', 'one'] != ['one', 'sub/sub sub/one']
First differing element 0:
sub/sub sub/one
one
- ['sub/sub sub/one', 'one']
+ ['one', 'sub/sub sub/one']
======================================================================
FAIL: test retrieving the names of bound objects
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/mdickinson/Enthought/ETS/apptools/apptools/naming/tests/context_test_case.py", line 514, in test_search
self.assertEqual( names, ['one', 'sub/sub sub/one'] )
AssertionError: Lists differ: ['sub/sub sub/one', 'one'] != ['one', 'sub/sub sub/one']
First differing element 0:
sub/sub sub/one
one
- ['sub/sub sub/one', 'one']
+ ['one', 'sub/sub sub/one']
======================================================================
FAIL: test retrieving the names of bound objects
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/mdickinson/Enthought/ETS/apptools/apptools/naming/tests/context_test_case.py", line 514, in test_search
self.assertEqual( names, ['one', 'sub/sub sub/one'] )
AssertionError: Lists differ: ['sub/sub sub/one', 'one'] != ['one', 'sub/sub sub/one']
First differing element 0:
sub/sub sub/one
one
- ['sub/sub sub/one', 'one']
+ ['one', 'sub/sub sub/one']
======================================================================
FAIL: test retrieving the names of bound objects
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/mdickinson/Enthought/ETS/apptools/apptools/naming/tests/context_test_case.py", line 514, in test_search
self.assertEqual( names, ['one', 'sub/sub sub/one'] )
AssertionError: Lists differ: ['sub/sub sub/one', 'one'] != ['one', 'sub/sub sub/one']
First differing element 0:
sub/sub sub/one
one
- ['sub/sub sub/one', 'one']
+ ['one', 'sub/sub sub/one']
======================================================================
FAIL: test retrieving the names of bound objects
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/mdickinson/Enthought/ETS/apptools/apptools/naming/tests/context_test_case.py", line 514, in test_search
self.assertEqual( names, ['one', 'sub/sub sub/one'] )
AssertionError: Lists differ: ['sub/sub sub/one', 'one'] != ['one', 'sub/sub sub/one']
First differing element 0:
sub/sub sub/one
one
- ['sub/sub sub/one', 'one']
+ ['one', 'sub/sub sub/one']
======================================================================
FAIL: Test if we are able to dump the state to a string.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/mdickinson/Enthought/ETS/apptools/apptools/persistence/tests/test_spickle.py", line 48, in test_dump_state
self.assertEqual(str, str1)
AssertionError: "ccopy_reg\n_reconstructor\np0\n(ctest_spickle\nFoo\np1\nc__builtin__\nobject\np2\nNtp3\nRp4\n(dp5\nS'a'\np6\n(itest_spickle\nA\np7\n(dp8\nS'array'\np9\ncnumpy.core.multiarray\n_reconstruct\np10\n(cnumpy\nndarray\np11\n(I0\ntp12\nS'b'\np13\ntp14\nRp15\n(I1\n(I5\ntp16\ncnumpy\ndtype\np17\n(S'f8'\np18\nI0\nI1\ntp19\nRp20\n(I3\nS'<'\np21\nNNNI-1\nI-1\nI0\ntp22\nbI00\nS'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xd0?\\x00\\x00\\x00\\x00\\x00\\x00\\xe0?\\x00\\x00\\x00\\x00\\x00\\x00\\xe8?\\x00\\x00\\x00\\x00\\x00\\x00\\xf0?'\np23\ntp24\nbsg6\nI100\nsg13\nI200\nsbsg13\nctraits.traits\n__newobj__\np25\n(ctest_spickle\nB\np26\ntp27\nRp28\n(dp29\nS'f'\np30\nF2.0\nsS'i'\np31\nI20\nsS'__traits_version__'\np32\nS'4.5.0'\np33\nsbsS'ref'\np34\ng7\nsb." != "ccopy_reg\n_reconstructor\np0\n(ctest_spickle\nFoo\np1\nc__builtin__\nobject\np2\nNtp3\nRp4\n(dp5\nS'a'\np6\n(itest_spickle\nA\np7\n(dp8\nS'array'\np9\ncnumpy.core.multiarray\n_reconstruct\np10\n(cnumpy\nndarray\np11\n(I0\ntp12\nS'b'\np13\ntp14\nRp15\n(I1\n(I5\ntp16\ncnumpy\ndtype\np17\n(S'f8'\np18\nI0\nI1\ntp19\nRp20\n(I3\nS'<'\np21\nNNNI-1\nI-1\nI0\ntp22\nbI00\nS'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xd0?\\x00\\x00\\x00\\x00\\x00\\x00\\xe0?\\x00\\x00\\x00\\x00\\x00\\x00\\xe8?\\x00\\x00\\x00\\x00\\x00\\x00\\xf0?'\np23\ntp24\nbsg6\nI100\nsg13\nI200\nsbsg13\nctraits.traits\n__newobj__\np25\n(ctest_spickle\nB\np26\ntp27\nRp28\n(dp29\nS'i'\np30\nI20\nsS'f'\np31\nF2.0\nsS'__traits_version__'\np32\nS'4.5.0'\np33\nsbsS'ref'\np34\ng7\nsb."
======================================================================
FAIL: Test if traited classes can be pickled.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/mdickinson/Enthought/ETS/apptools/apptools/persistence/tests/test_state_pickler.py", line 320, in test_pickle_traits
self.verify(t, state)
File "/Users/mdickinson/Enthought/ETS/apptools/apptools/persistence/tests/test_state_pickler.py", line 110, in verify
self.assertEqual(lst[-1]['type'], 'instance')
AssertionError: 'reference' != 'instance'
======================================================================
FAIL: Test if the state can be saved like the object itself.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/mdickinson/Enthought/ETS/apptools/apptools/persistence/tests/test_state_pickler.py", line 367, in test_state_is_saveable
self.verify_state(state1, state)
File "/Users/mdickinson/Enthought/ETS/apptools/apptools/persistence/tests/test_state_pickler.py", line 183, in verify_state
self.assertEqual(state.inst.__metadata__, state1.inst.__metadata__)
AssertionError: {'initargs': (), 'version': [(('A', 'test_state_pickler'), -1)], 'module': 'test [truncated]... != {'initargs': (), 'version': [(('A', 'test_state_pickler'), -1)], 'module': 'test [truncated]...
{'class_name': 'A',
'has_instance': True,
- 'id': 5,
? ^
+ 'id': 4,
? ^
'initargs': (),
'module': 'test_state_pickler',
'type': 'instance',
'version': [(('A', 'test_state_pickler'), -1)]}
======================================================================
FAIL: preferences node changed
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/mdickinson/Enthought/ETS/apptools/apptools/preferences/tests/preferences_helper_test_case.py", line 438, in test_preferences_node_changed
self.assertEqual('width', listener.trait_name)
AssertionError: 'width' != 'bgcolor'
-------------------- >> begin captured logging << --------------------
apptools.preferences.preferences: DEBUG: loading preferences from </Users/mdickinson/Enthought/ETS/apptools/apptools/preferences/tests/example.ini>
apptools.preferences.preferences: DEBUG: loading preferences from </Users/mdickinson/Enthought/ETS/apptools/apptools/preferences/tests/example.ini>
--------------------- >> end captured logging << ---------------------
----------------------------------------------------------------------
Ran 380 tests in 1.234s
FAILED (errors=1, failures=9)
Exception occurred in traits notification handler for object: <Preferences object at 0x40c19b0>, trait: last_name, old value: value, new value: TestUÜöser
Traceback (most recent call last):
File "lib/python2.7/site-packages/traits/trait_notifiers.py", line 340, in __call__
self.handler( *args )
File "lib/python2.7/site-packages/apptools/preferences/preferences_helper.py", line 71, in _anytrait_changed
self.preferences.set('%s.%s' % (self._get_path(), trait_name), new)
File "lib/python2.7/site-packages/apptools/preferences/scoped_preferences.py", line 166, in set
node.set(path, value)
File "lib/python2.7/site-packages/apptools/preferences/preferences.py", line 191, in set
node.set('.'.join(components[1:]), value)
File "lib/python2.7/site-packages/apptools/preferences/preferences.py", line 185, in set
self._set(path, value)
File "lib/python2.7/site-packages/apptools/preferences/preferences.py", line 546, in _set
value = str(value)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 5-6: ordinal not in range(128)
Apptools provides the sweet_pickle
subpackage to handle versioning of pickled objects to allow unpickling of objects after changes to the class structure.
The persistence
subpackage has a slightly different focus: it is more about extracting state as a dictionary, but it has similar themes.
Mayavi uses persistence
, but it also uses apptools.naming
which internally uses sweet_pickle
, so we cannot simply deprecate sweet_pickle
.
The test suite is currently based on nose. nose is no longer maintained. There's a successor, nose2
, but that doesn't pick up all the apptools tests right now. (Out of the box, nose finds 401 tests, while nose2 finds 174. That may be tweakable.)
We should consider converting all the tests to regular unittest testcases (and then users can still choose to use whichever test runner they prefer).
The apptools.logger.agent
code is currently Wx-specific. We should either make the dialog use TraitsUI or write a Qt equivalent.
This has been superseded by Enable's component editor.
Projects that don't use the GUI parts of apptools are still required to install traitsui if they want to have an environment where all the dependencies are met:
09:56 $ edm install apptools
Fetching indices for package repositories.... done
The following packages will be installed:
apptools 4.4.0-4 787 KiB
configobj 5.0.6-2 70 KiB
pyface 5.1.0-5 1.5 MiB
pygments 2.1.3-1 1.73 MiB
six 1.10.0-1 19 KiB
traits 4.6.0-1 636 KiB
traitsui 5.1.0-2 1.5 MiB
Do you want to continue ? [Y/n]:
Version info (although the same problem essentially exists with traits v6.0.0):
$ edm list | grep -P "apptools|traits "
apptools 4.5.0-5 enthought/free
traits 6.1.1-1 enthought/free
Here's a small example:
Initially, the preferences file contains:
# File: myprefs.ini
[my_section]
things = "['one', 'two']"
Then, we run a script that updates the things
preference list:
from apptools.preferences.api import Preferences, PreferencesHelper
from traits.api import Int, List, Str
class MyHelper(PreferencesHelper):
preferences_path = 'my_section'
things = List(Str)
prefs = Preferences(filename='myprefs.ini')
helper = MyHelper(preferences=prefs)
helper.things.append('another thing!')
prefs.save()
After the script is run, the preferences file looks like:
# File: myprefs.ini
[my_section]
things = "['one', 'two']"
things_items = "TraitListEvent(index=2, removed=[], added=['another thing!'])"
As far as I can tell, the culprit is this block in the PreferencesHelper class:
apptools/apptools/preferences/preferences_helper.py
Lines 65 to 73 in 5a136f6
This is a comparatively recent addition to apptools. It should be documented with examples of the problems it is idesigned to solve.
Pyface and TraitsUI accept "qt" for a toolkit name, Apptools should as well
Same problem as #79: state-pickler.py is getting a blank line added after ever line when doing a pip install. Other files don't seem to have this problem, and doing a manual .zip folder download doesn't seem to have this problem either. This is causing multiple syntax errors and preventing use of mayavi without manually adjusting the state-pickler.py file.
When I run the test suite under Python 3.8.1 (on macOS, in a venv), it modifies the file apptools/preferences/tests/example.ini
:
(apptools-3.8) mirzakhani:apptools mdickinson$ git diff
diff --git a/apptools/preferences/tests/example.ini b/apptools/preferences/tests/example.ini
index 100dc6e1..c535635c 100644
--- a/apptools/preferences/tests/example.ini
+++ b/apptools/preferences/tests/example.ini
@@ -3,7 +3,7 @@ bgcolor = blue
width = 50
ratio = 1.0
visible = True
-description = 'acme ui'
+description = acme ui
offsets = "[1, 2, 3, 4]"
names = "['joe', 'fred', 'jane']"
Steps to reproduce, from a clean clone:
python3.8 -m venv ~/.venvs/apptools-3.8
, source ~/.venvs/apptools-3.8/bin/activate
pip install nose numpy tables pandas
pip install -e .
git status
at this point shows that the working tree is cleannosetests .
git status
now shows modifications to examples.ini
.We no longer need to support Python 2; related code can be dropped.
[From discussion in enthought/envisage#188]
There are a number of testing utilities that are being replicated from repository to repository (usually with minor API changes each time). It would be good to standardise these and put them in a common place.
The two things that sparked this discussion were (a) utilities for catching and testing logs (though with Python 3, the standard library unittest
has this capabiilty), and (b) utilities for capturing output streams.
Here's the relevant code. For context, see: https://github.com/enthought/envisage/blob/54bda86ca195b5b6d59b72a037d58c4bc01f3ff9/envisage/plugins/ipython_kernel/tests/test_internal_ipkernel.py#L33-L108
# Machinery for catching logged messages in tests (both for testing
# the existence and content of those messages, and for hiding the
# logger output during the test run).
class ListHandler(logging.Handler):
"""
Simple logging handler that stores all records in a list.
Used by catch_logs below.
"""
def __init__(self):
logging.Handler.__init__(self)
self.records = []
def emit(self, record):
self.records.append(record)
@contextlib.contextmanager
def catch_logs(logger_name, level=logging.WARNING):
"""
Temporarily redirect logs for the given logger to a list.
Also allows temporarily changing the level of that logger.
"""
logger = logging.getLogger(logger_name)
handler = ListHandler()
old_propagate = logger.propagate
old_level = logger.level
logger.addHandler(handler)
logger.propagate = False
logger.setLevel(level)
try:
yield handler.records
finally:
logger.setLevel(old_level)
logger.propagate = old_propagate
logger.removeHandler(handler)
@contextlib.contextmanager
def capture_stream(stream, callback=None):
"""
Context manager to capture output to a particular stream.
Capture all output written to the given stream. If the optional
callback is provided, call it with the captured output (which
will be a bytestring) when exiting the with block.
Parameters
----------
stream : Python stream
For example, sys.__stdout__.
callback : callable
Callable of a single argument.
"""
stream_fd = stream.fileno()
with tempfile.TemporaryFile() as new_stream:
old_stream_fd = os.dup(stream_fd)
stream.flush()
os.dup2(new_stream.fileno(), stream_fd)
try:
yield
finally:
stream.flush()
os.dup2(old_stream_fd, stream_fd)
os.close(old_stream_fd)
new_stream.flush()
new_stream.seek(0)
captured = new_stream.read()
if callback is not None:
callback(captured)
I'm not sure if this was intentional or not. image_LICENSE_Nuvola.txt is not included in the source archive.
See the deprecation in enthought/traits#190 and see similar PR enthought/envisage#118
After eggs are built for EDM:
I suggest deprecating use of the global preferences (via the get_default_preferences
and set_default_preferences
functions, and implicitly via the three-argument form of bind_preference
). This mutable global default complicates testing, and leads to code with spooky action-at-a-distance.
It would be nice to populate the CHANGES.TXT file with all the changes that have happend between version 4.2.1 and version 4.4.0
Documentation about the io.h5 is apparently missing (at least, I could not find it on the online docs)
Using object equality in from_available_items
will fail if the selected object is not comparable (e.g. numpy.arrays).
Travis (and possibly appveyor too) allow the creation of cron jobs. Some of the ETS packages now have cron jobs setup to test against dependencies which are installed from source - instead of testing against the released versions.
See examples :
The apptools.persistence.spickle
module does not work on Python 3.4. We either should port it so it does or remove it entirely if no one is using it.
At the moment, set_selection
accepts multiple items to be selected, but some selection provider might have only one item selected at any time. We need to specify a behavior for this case. (In practice, it matter little if the provider is properly documented.)
My proposal is to select the last available item form the selection list.
See enthought/pyface#249 This would impact Mayavi and Envisage, but only as far as changing import locations.
@rkern is this something we should be considering?
After I upgrade to Python 3.7.1, when "from mayavi import mlab", it throws out "Invalid syntax" error from \apptools\persistence\state_pickler.py
line 1210, 1456, 2001
I think it is caused by when you wrap the line with "", the following line is blank, and that throws out an error with the latest Python 3.7.
Some of the parts of Apptools provide fundamental application services for any type of application (eg. preferences, persistence, naming, logging), but others are tightly tied to GUI features (preference UI, logging UI, undo/redo, scripting).
There may be a point to providing two packages: a low-level set of tools which depends only on Traits (and maybe, optionally, Envisage), and a high-level set of tools and interfaces to the low-level tools for use in GUI applications.
For backwards compatibility, the high-level toolkit should retain the Apptools name and at least for a while should import the low-level tools into the namespace.
If we were to add a __fspath__
method and register the class with os.PathLike
(where available) it would mean that File
objects could be used in a similar way to pathlib.Path
objects throughout Python.
As a secondary consideration, using a pathlib
path object instead of a string as the source of truth for the File
class would simplify a lot of the logic; it would probably make sense to also duplicate the pathlib.Path
API (alongside the current API).
This is an implementation of the Java Naming and Directory Interface - or at least the naming part of that - with specific implementations for a hierarchy of Python objects and for file system stores. It is used by Mayavi, but possibly only as part of the Wx backend.
It is intended to provide a standard API for hierarchical namespaces that standard interfaces can then build on top of, but I have a suspicion that at least some of the code that duplicates the Java APIs is over-engineered for Python (eg. the InitialContextFactory
object feels very much like it could just be a callable).
If it is to be kept, then there are some improvements that should be made:
The apptools.lru_cache is a comparatively recent addition to the apptools suite. It provides a traitified version of an LRU cache. While this is a fairly well-understood concept, it should have at least minimal documentation and examples of use.
The apptools.type_manager
module has a lot of overlap with the Traits adaptation system since the latter gained the ability to have multiple adapter registries.
It is, however, used by apptools.naming
which is in turn used by Mayavi, so we can't simply remove.
The correct way forward is probably to investigate whether apptools.naming
can use Traits adaptation, and whether Mayavi uses the type manager's objects directly via the naming module
The current implementation will call _initialize
during the HasTraits contructor and at the same time the static change handler on the preferences
trait would have already triggered the same call when the parent constructor is called.
While this behavior is normally harmless it is problematic and unnecessary.
[Update] A decision has been made to remove LRUCache
from apptools
. See comment further down the thread - #91 (comment)
Python 3.x provides lru cache via the functools stdlib package, which is available on Python 2.x as the backported functools32
package.
I don't know what the differences between the LRUCache
that apptools
provides and how it is different from the one from functools
. I am also not sure who is using LRUCache
from apptools
.
Note that if we do choose to remove the module/class, the next release will have to be a major release.
See https://github.com/enthought/apptools/blob/master/apptools/lru_cache/lru_cache.py
#41 has changed the way the Preferences are managed internally. They are no more only str. Documentation must be updated.
It should grow a Qt backend as well, or be converted to use TraitsUI.
This is a workbench/envisage plugin for contributing links to external documentation and demos. It uses preferences for pointing to directories which contain documentation and demo code.
It may make sense to keep for applications still using workbench; it may also make sense to create a Tasks version as well.
It may be used by Mayavi, but that is not clear.
I'm seeing the following with Python 3.8 (it probably occurs under Python 3.7 too):
======================================================================
ERROR: apptools.io.h5.tests.test_file.test_iter_groups
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/tables/misc/proxydict.py", line 62, in itervalues
raise StopIteration
StopIteration
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/nose/case.py", line 197, in runTest
self.test(*self.arg)
File "/<<PKGBUILDDIR>>/.pybuild/cpython3_3.8_apptools/build/apptools/io/h5/tests/test_file.py", line 429, in test_iter_groups
assert set(n.name for n in group.iter_groups()) == set(['subgroup'])
File "/<<PKGBUILDDIR>>/.pybuild/cpython3_3.8_apptools/build/apptools/io/h5/tests/test_file.py", line 429, in <genexpr>
assert set(n.name for n in group.iter_groups()) == set(['subgroup'])
File "/<<PKGBUILDDIR>>/.pybuild/cpython3_3.8_apptools/build/apptools/io/h5/file.py", line 434, in <genexpr>
return (_wrap_node(g) for g in self._h5_group._v_groups.itervalues())
RuntimeError: generator raised StopIteration
----------------------------------------------------------------------
Ran 401 tests in 1.491s
FAILED (SKIP=1, errors=1)
There's currently no easy way to unbind preferences that were bound with bind_preference
. There are some situations where it would be useful to be able to do so. One example is during testing, where one sometimes wants to swap out the current file-backed preferences for a simpler preferences object in order to avoid the test writing to the preferences file unnecessarily.
apptools.permissions
in several _*_default()
methods tries to import a class from an apptools.permissions.external
package and then defaults to loading the default class from apptools.permissions
itself. The documentation recommends that you make an apptools.permissions.external
namespace package with your custom implementations if you want to use them. We haven't supported namespace packages since it was enthought.permissions
.
We could fix up the _*_default()
methods and the documentation to recommend the right way to do things. I'm not really sure why such an inflexible-yet-convoluted scheme was put in place at all, but obviously, we aren't using this code. Should we just deprecate it?
PR #41 seems to have broken about 20 tests. Either the tests need to be fixed, or the code.
Currently the tests fail unless a number of 3rd party packages are installed, including NumPy, Pandas and PyTables. Those tests should be skipped instead if the corresponding packages aren't installed.
1 2 3 ...
1 2 3 ...
11 ...
The StatePickler
uses the hash function hash
to generate a key for its object cache, at least for hashable objects. Without an extra equality check, this is broken, and leads to different objects with the same hash being treated as the same object.
Example failure resulting from this:
>>> from apptools.persistence.state_pickler import *
>>> loads_state(dumps([(-1, -1), (-2, -2), (-3, -3)]))
[(-1, -1), (-1, -1), (-3, -3)]
Here the error occurs because the tuples (-1, -1)
and (-2, -2)
have the same hash.
There are two application scripting systems in AppTools. Mayavi uses the apptools.scripting
package. No Enthought application has used apptools.appscripting
in the last 10 years or so. Therefore apptools.scripting
should be removed.
This removal should probably occur in the next major release, with any third party users encouraged to use apptools.scripting
.
Apptools naming is complex and almost completely undocumented. It is used by Mayavi, it cannot be ignored as not to be used, but without documentation it is not clear what the module is intended to be used for.
It looks like this may be a Python implementation of the Java Naming and Directory Interface.
This submodule provides a traited File
object that provides properties and methods for common file path manipulation operations. Much of this functionality is provided in Python 3 by the pathlib
module, and it is not clear what precise benefits this provides, other than notifications of state change. It may be that this is not needed any more. Or it may be that there is some extra functionality which is part of the class, but which could be better handled by using pathlib
objects for the duplicated functionality and the File
class for everything novel.
There is also apptools.io.h5
which wraps h5py
with a dictionary-style mapping. This may end up being superseded by Zarr and similar libraries; but it is likely this code is used by various Enthought applications.
apptools for Python 3 may not have module named 'cStringIO', please have a look at: https://stackoverflow.com/q/28200366
Related issue: enthought/mayavi/issues/797
The apptools.template
package is designed to provide a system for configuring traits classes and instantiating them according to the template. This is motivated by, for example, allowing a user to create templates to style Chaco plots and then use those style choices when creating the actual plot instances.
The template objects are also designed to help with serialization and deserialization, allowing the configuration of application state to be separated from the data sources when serializaing.
This is potentially a very useful set of functionality, but it may not be worth preserving.
Or, alternatively, apptools is not the place for it, and it really needs to live in Chaco until a wider use for it is found.
Probably OK to simply run Black over it.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.