summaryrefslogtreecommitdiffstats
path: root/contrib/python/traitlets/py2
diff options
context:
space:
mode:
authormonster <[email protected]>2022-07-07 14:41:37 +0300
committermonster <[email protected]>2022-07-07 14:41:37 +0300
commit06e5c21a835c0e923506c4ff27929f34e00761c2 (patch)
tree75efcbc6854ef9bd476eb8bf00cc5c900da436a2 /contrib/python/traitlets/py2
parent03f024c4412e3aa613bb543cf1660176320ba8f4 (diff)
fix ya.make
Diffstat (limited to 'contrib/python/traitlets/py2')
-rw-r--r--contrib/python/traitlets/py2/.dist-info/METADATA34
-rw-r--r--contrib/python/traitlets/py2/.dist-info/top_level.txt1
-rw-r--r--contrib/python/traitlets/py2/COPYING.md62
-rw-r--r--contrib/python/traitlets/py2/README.md143
-rw-r--r--contrib/python/traitlets/py2/traitlets/__init__.py3
-rw-r--r--contrib/python/traitlets/py2/traitlets/_version.py2
-rw-r--r--contrib/python/traitlets/py2/traitlets/config/__init__.py8
-rw-r--r--contrib/python/traitlets/py2/traitlets/config/application.py711
-rw-r--r--contrib/python/traitlets/py2/traitlets/config/configurable.py432
-rw-r--r--contrib/python/traitlets/py2/traitlets/config/loader.py857
-rw-r--r--contrib/python/traitlets/py2/traitlets/config/manager.py88
-rw-r--r--contrib/python/traitlets/py2/traitlets/config/tests/__init__.py0
-rw-r--r--contrib/python/traitlets/py2/traitlets/config/tests/test_application.py421
-rw-r--r--contrib/python/traitlets/py2/traitlets/config/tests/test_configurable.py459
-rw-r--r--contrib/python/traitlets/py2/traitlets/config/tests/test_loader.py453
-rw-r--r--contrib/python/traitlets/py2/traitlets/log.py27
-rw-r--r--contrib/python/traitlets/py2/traitlets/tests/__init__.py0
-rw-r--r--contrib/python/traitlets/py2/traitlets/tests/_warnings.py107
-rw-r--r--contrib/python/traitlets/py2/traitlets/tests/test_traitlets.py2419
-rw-r--r--contrib/python/traitlets/py2/traitlets/tests/test_traitlets_enum.py181
-rw-r--r--contrib/python/traitlets/py2/traitlets/tests/utils.py39
-rw-r--r--contrib/python/traitlets/py2/traitlets/traitlets.py2690
-rw-r--r--contrib/python/traitlets/py2/traitlets/utils/__init__.py0
-rw-r--r--contrib/python/traitlets/py2/traitlets/utils/bunch.py25
-rw-r--r--contrib/python/traitlets/py2/traitlets/utils/getargspec.py86
-rw-r--r--contrib/python/traitlets/py2/traitlets/utils/importstring.py42
-rw-r--r--contrib/python/traitlets/py2/traitlets/utils/sentinel.py17
-rw-r--r--contrib/python/traitlets/py2/traitlets/utils/tests/__init__.py0
-rw-r--r--contrib/python/traitlets/py2/traitlets/utils/tests/test_bunch.py14
-rw-r--r--contrib/python/traitlets/py2/traitlets/utils/tests/test_importstring.py30
30 files changed, 0 insertions, 9351 deletions
diff --git a/contrib/python/traitlets/py2/.dist-info/METADATA b/contrib/python/traitlets/py2/.dist-info/METADATA
deleted file mode 100644
index bd031a5c309..00000000000
--- a/contrib/python/traitlets/py2/.dist-info/METADATA
+++ /dev/null
@@ -1,34 +0,0 @@
-Metadata-Version: 2.1
-Name: traitlets
-Version: 4.3.3
-Summary: Traitlets Python config system
-Home-page: http://ipython.org
-Author: IPython Development Team
-Author-email: [email protected]
-License: BSD
-Keywords: Interactive,Interpreter,Shell,Web
-Platform: Linux
-Platform: Mac OS X
-Platform: Windows
-Classifier: Intended Audience :: Developers
-Classifier: Intended Audience :: System Administrators
-Classifier: Intended Audience :: Science/Research
-Classifier: License :: OSI Approved :: BSD License
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2.7
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.3
-Classifier: Programming Language :: Python :: 3.4
-Classifier: Programming Language :: Python :: 3.5
-Requires-Dist: ipython-genutils
-Requires-Dist: six
-Requires-Dist: decorator
-Requires-Dist: enum34 ; python_version=="2.7"
-Requires-Dist: enum34 ; python_version=="3.3"
-Provides-Extra: test
-Requires-Dist: pytest ; extra == 'test'
-Requires-Dist: mock ; (python_version=="2.7") and extra == 'test'
-
-A configuration system for Python applications.
-
-
diff --git a/contrib/python/traitlets/py2/.dist-info/top_level.txt b/contrib/python/traitlets/py2/.dist-info/top_level.txt
deleted file mode 100644
index adfea9c6eb5..00000000000
--- a/contrib/python/traitlets/py2/.dist-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-traitlets
diff --git a/contrib/python/traitlets/py2/COPYING.md b/contrib/python/traitlets/py2/COPYING.md
deleted file mode 100644
index 39ca730a630..00000000000
--- a/contrib/python/traitlets/py2/COPYING.md
+++ /dev/null
@@ -1,62 +0,0 @@
-# Licensing terms
-
-Traitlets is adapted from enthought.traits, Copyright (c) Enthought, Inc.,
-under the terms of the Modified BSD License.
-
-This project is licensed under the terms of the Modified BSD License
-(also known as New or Revised or 3-Clause BSD), as follows:
-
-- Copyright (c) 2001-, IPython Development Team
-
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this
-list of conditions and the following disclaimer.
-
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-Neither the name of the IPython Development Team nor the names of its
-contributors may be used to endorse or promote products derived from this
-software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-## About the IPython Development Team
-
-The IPython Development Team is the set of all contributors to the IPython project.
-This includes all of the IPython subprojects.
-
-The core team that coordinates development on GitHub can be found here:
-https://github.com/jupyter/.
-
-## Our Copyright Policy
-
-IPython uses a shared copyright model. Each contributor maintains copyright
-over their contributions to IPython. But, it is important to note that these
-contributions are typically only changes to the repositories. Thus, the IPython
-source code, in its entirety is not the copyright of any single person or
-institution. Instead, it is the collective copyright of the entire IPython
-Development Team. If individual contributors want to maintain a record of what
-changes/contributions they have specific copyright on, they should indicate
-their copyright in the commit message of the change, when they commit the
-change to one of the IPython repositories.
-
-With this in mind, the following banner should be used in any source code file
-to indicate the copyright and license terms:
-
- # Copyright (c) IPython Development Team.
- # Distributed under the terms of the Modified BSD License.
diff --git a/contrib/python/traitlets/py2/README.md b/contrib/python/traitlets/py2/README.md
deleted file mode 100644
index aa288947efb..00000000000
--- a/contrib/python/traitlets/py2/README.md
+++ /dev/null
@@ -1,143 +0,0 @@
-# Traitlets
-
-[![Build Status](https://travis-ci.org/ipython/traitlets.svg?branch=master)](https://travis-ci.org/ipython/traitlets)
-[![Documentation Status](https://readthedocs.org/projects/traitlets/badge/?version=latest)](http://traitlets.readthedocs.org/en/latest/?badge=latest)
-
-Traitlets is a pure Python library enabling:
-
- - the enforcement of strong typing for attributes of Python objects
- (typed attributes are called "traits"),
- - notifications on changes of trait attributes,
- - automatic validation and coercion of trait attributes when attempting a
- change.
-
-Its implementation relies on the [descriptor](https://docs.python.org/howto/descriptor.html)
-pattern.
-
-Traitlets powers the configuration system of IPython and Jupyter
-and the declarative API of IPython interactive widgets.
-
-## Installation
-
-For a local installation, make sure you have
-[pip installed](https://pip.pypa.io/en/stable/installing/) and run:
-
-```bash
-pip install traitlets
-```
-
-For a **development installation**, clone this repository, change into the
-`traitlets` root directory, and run pip:
-
-```bash
-git clone https://github.com/ipython/traitlets.git
-cd traitlets
-pip install -e .
-```
-
-## Running the tests
-
-```bash
-pip install "traitlets[test]"
-py.test traitlets
-```
-
-## Usage
-
-Any class with trait attributes must inherit from `HasTraits`.
-For the list of available trait types and their properties, see the
-[Trait Types](https://traitlets.readthedocs.io/en/latest/trait_types.html)
-section of the documentation.
-
-### Dynamic default values
-
-To calculate a default value dynamically, decorate a method of your class with
-`@default({traitname})`. This method will be called on the instance, and
-should return the default value. In this example, the `_username_default`
-method is decorated with `@default('username')`:
-
-```Python
-import getpass
-from traitlets import HasTraits, Unicode, default
-
-class Identity(HasTraits):
- username = Unicode()
-
- @default('username')
- def _username_default(self):
- return getpass.getuser()
-```
-
-### Callbacks when a trait attribute changes
-
-When a trait changes, an application can follow this trait change with
-additional actions.
-
-To do something when a trait attribute is changed, decorate a method with
-[`traitlets.observe()`](https://traitlets.readthedocs.io/en/latest/api.html?highlight=observe#traitlets.observe).
-The method will be called with a single argument, a dictionary which contains
-an owner, new value, old value, name of the changed trait, and the event type.
-
-In this example, the `_num_changed` method is decorated with ``@observe(`num`)``:
-
-```Python
-from traitlets import HasTraits, Integer, observe
-
-class TraitletsExample(HasTraits):
- num = Integer(5, help="a number").tag(config=True)
-
- @observe('num')
- def _num_changed(self, change):
- print("{name} changed from {old} to {new}".format(**change))
-```
-
-and is passed the following dictionary when called:
-
-```Python
-{
- 'owner': object, # The HasTraits instance
- 'new': 6, # The new value
- 'old': 5, # The old value
- 'name': "foo", # The name of the changed trait
- 'type': 'change', # The event type of the notification, usually 'change'
-}
-```
-
-### Validation and coercion
-
-Each trait type (`Int`, `Unicode`, `Dict` etc.) may have its own validation or
-coercion logic. In addition, we can register custom cross-validators
-that may depend on the state of other attributes. For example:
-
-```Python
-from traitlets import HasTraits, TraitError, Int, Bool, validate
-
-class Parity(HasTraits):
- value = Int()
- parity = Int()
-
- @validate('value')
- def _valid_value(self, proposal):
- if proposal['value'] % 2 != self.parity:
- raise TraitError('value and parity should be consistent')
- return proposal['value']
-
- @validate('parity')
- def _valid_parity(self, proposal):
- parity = proposal['value']
- if parity not in [0, 1]:
- raise TraitError('parity should be 0 or 1')
- if self.value % 2 != parity:
- raise TraitError('value and parity should be consistent')
- return proposal['value']
-
-parity_check = Parity(value=2)
-
-# Changing required parity and value together while holding cross validation
-with parity_check.hold_trait_notifications():
- parity_check.value = 1
- parity_check.parity = 1
-```
-
-However, we **recommend** that custom cross-validators don't modify the state
-of the HasTraits instance.
diff --git a/contrib/python/traitlets/py2/traitlets/__init__.py b/contrib/python/traitlets/py2/traitlets/__init__.py
deleted file mode 100644
index b609adb565d..00000000000
--- a/contrib/python/traitlets/py2/traitlets/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from .traitlets import *
-from .utils.importstring import import_item
-from ._version import version_info, __version__
diff --git a/contrib/python/traitlets/py2/traitlets/_version.py b/contrib/python/traitlets/py2/traitlets/_version.py
deleted file mode 100644
index ed16b3c1e12..00000000000
--- a/contrib/python/traitlets/py2/traitlets/_version.py
+++ /dev/null
@@ -1,2 +0,0 @@
-version_info = (4, 3, 3)
-__version__ = '.'.join(map(str, version_info))
diff --git a/contrib/python/traitlets/py2/traitlets/config/__init__.py b/contrib/python/traitlets/py2/traitlets/config/__init__.py
deleted file mode 100644
index 0ae7d63171d..00000000000
--- a/contrib/python/traitlets/py2/traitlets/config/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# encoding: utf-8
-
-# Copyright (c) IPython Development Team.
-# Distributed under the terms of the Modified BSD License.
-
-from .application import *
-from .configurable import *
-from .loader import Config
diff --git a/contrib/python/traitlets/py2/traitlets/config/application.py b/contrib/python/traitlets/py2/traitlets/config/application.py
deleted file mode 100644
index d3a4c45e774..00000000000
--- a/contrib/python/traitlets/py2/traitlets/config/application.py
+++ /dev/null
@@ -1,711 +0,0 @@
-# encoding: utf-8
-"""A base class for a configurable application."""
-
-# Copyright (c) IPython Development Team.
-# Distributed under the terms of the Modified BSD License.
-
-from __future__ import print_function
-
-from copy import deepcopy
-import json
-import logging
-import os
-import re
-import sys
-from collections import defaultdict, OrderedDict
-
-from decorator import decorator
-
-from traitlets.config.configurable import Configurable, SingletonConfigurable
-from traitlets.config.loader import (
- KVArgParseConfigLoader, PyFileConfigLoader, Config, ArgumentError, ConfigFileNotFound, JSONFileConfigLoader
-)
-
-from traitlets.traitlets import (
- Bool, Unicode, List, Enum, Dict, Instance, TraitError, observe, observe_compat, default,
-)
-from ipython_genutils.importstring import import_item
-from ipython_genutils.text import indent, wrap_paragraphs, dedent
-from ipython_genutils import py3compat
-
-import six
-
-#-----------------------------------------------------------------------------
-# Descriptions for the various sections
-#-----------------------------------------------------------------------------
-
-# merge flags&aliases into options
-option_description = """
-Arguments that take values are actually convenience aliases to full
-Configurables, whose aliases are listed on the help line. For more information
-on full configurables, see '--help-all'.
-""".strip() # trim newlines of front and back
-
-keyvalue_description = """
-Parameters are set from command-line arguments of the form:
-`--Class.trait=value`.
-This line is evaluated in Python, so simple expressions are allowed, e.g.::
-`--C.a='range(3)'` For setting C.a=[0,1,2].
-""".strip() # trim newlines of front and back
-
-# sys.argv can be missing, for example when python is embedded. See the docs
-# for details: http://docs.python.org/2/c-api/intro.html#embedding-python
-if not hasattr(sys, "argv"):
- sys.argv = [""]
-
-subcommand_description = """
-Subcommands are launched as `{app} cmd [args]`. For information on using
-subcommand 'cmd', do: `{app} cmd -h`.
-"""
-# get running program name
-
-#-----------------------------------------------------------------------------
-# Application class
-#-----------------------------------------------------------------------------
-
-
-
-_envvar = os.environ.get('TRAITLETS_APPLICATION_RAISE_CONFIG_FILE_ERROR','')
-if _envvar.lower() in {'1','true'}:
- TRAITLETS_APPLICATION_RAISE_CONFIG_FILE_ERROR = True
-elif _envvar.lower() in {'0','false',''} :
- TRAITLETS_APPLICATION_RAISE_CONFIG_FILE_ERROR = False
-else:
- raise ValueError("Unsupported value for environment variable: 'TRAITLETS_APPLICATION_RAISE_CONFIG_FILE_ERROR' is set to '%s' which is none of {'0', '1', 'false', 'true', ''}."% _envvar )
-
-
-@decorator
-def catch_config_error(method, app, *args, **kwargs):
- """Method decorator for catching invalid config (Trait/ArgumentErrors) during init.
-
- On a TraitError (generally caused by bad config), this will print the trait's
- message, and exit the app.
-
- For use on init methods, to prevent invoking excepthook on invalid input.
- """
- try:
- return method(app, *args, **kwargs)
- except (TraitError, ArgumentError) as e:
- app.print_help()
- app.log.fatal("Bad config encountered during initialization:")
- app.log.fatal(str(e))
- app.log.debug("Config at the time: %s", app.config)
- app.exit(1)
-
-
-class ApplicationError(Exception):
- pass
-
-
-class LevelFormatter(logging.Formatter):
- """Formatter with additional `highlevel` record
-
- This field is empty if log level is less than highlevel_limit,
- otherwise it is formatted with self.highlevel_format.
-
- Useful for adding 'WARNING' to warning messages,
- without adding 'INFO' to info, etc.
- """
- highlevel_limit = logging.WARN
- highlevel_format = " %(levelname)s |"
-
- def format(self, record):
- if record.levelno >= self.highlevel_limit:
- record.highlevel = self.highlevel_format % record.__dict__
- else:
- record.highlevel = ""
- return super(LevelFormatter, self).format(record)
-
-
-class Application(SingletonConfigurable):
- """A singleton application with full configuration support."""
-
- # The name of the application, will usually match the name of the command
- # line application
- name = Unicode(u'application')
-
- # The description of the application that is printed at the beginning
- # of the help.
- description = Unicode(u'This is an application.')
- # default section descriptions
- option_description = Unicode(option_description)
- keyvalue_description = Unicode(keyvalue_description)
- subcommand_description = Unicode(subcommand_description)
-
- python_config_loader_class = PyFileConfigLoader
- json_config_loader_class = JSONFileConfigLoader
-
- # The usage and example string that goes at the end of the help string.
- examples = Unicode()
-
- # A sequence of Configurable subclasses whose config=True attributes will
- # be exposed at the command line.
- classes = []
-
- def _classes_inc_parents(self):
- """Iterate through configurable classes, including configurable parents
-
- Children should always be after parents, and each class should only be
- yielded once.
- """
- seen = set()
- for c in self.classes:
- # We want to sort parents before children, so we reverse the MRO
- for parent in reversed(c.mro()):
- if issubclass(parent, Configurable) and (parent not in seen):
- seen.add(parent)
- yield parent
-
- # The version string of this application.
- version = Unicode(u'0.0')
-
- # the argv used to initialize the application
- argv = List()
-
- # Whether failing to load config files should prevent startup
- raise_config_file_errors = Bool(TRAITLETS_APPLICATION_RAISE_CONFIG_FILE_ERROR)
-
- # The log level for the application
- log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
- default_value=logging.WARN,
- help="Set the log level by value or name.").tag(config=True)
-
- @observe('log_level')
- @observe_compat
- def _log_level_changed(self, change):
- """Adjust the log level when log_level is set."""
- new = change.new
- if isinstance(new, six.string_types):
- new = getattr(logging, new)
- self.log_level = new
- self.log.setLevel(new)
-
- _log_formatter_cls = LevelFormatter
-
- log_datefmt = Unicode("%Y-%m-%d %H:%M:%S",
- help="The date format used by logging formatters for %(asctime)s"
- ).tag(config=True)
-
- log_format = Unicode("[%(name)s]%(highlevel)s %(message)s",
- help="The Logging format template",
- ).tag(config=True)
-
- @observe('log_datefmt', 'log_format')
- @observe_compat
- def _log_format_changed(self, change):
- """Change the log formatter when log_format is set."""
- _log_handler = self.log.handlers[0]
- _log_formatter = self._log_formatter_cls(fmt=self.log_format, datefmt=self.log_datefmt)
- _log_handler.setFormatter(_log_formatter)
-
- @default('log')
- def _log_default(self):
- """Start logging for this application.
-
- The default is to log to stderr using a StreamHandler, if no default
- handler already exists. The log level starts at logging.WARN, but this
- can be adjusted by setting the ``log_level`` attribute.
- """
- log = logging.getLogger(self.__class__.__name__)
- log.setLevel(self.log_level)
- log.propagate = False
- _log = log # copied from Logger.hasHandlers() (new in Python 3.2)
- while _log:
- if _log.handlers:
- return log
- if not _log.propagate:
- break
- else:
- _log = _log.parent
- if sys.executable and sys.executable.endswith('pythonw.exe'):
- # this should really go to a file, but file-logging is only
- # hooked up in parallel applications
- _log_handler = logging.StreamHandler(open(os.devnull, 'w'))
- else:
- _log_handler = logging.StreamHandler()
- _log_formatter = self._log_formatter_cls(fmt=self.log_format, datefmt=self.log_datefmt)
- _log_handler.setFormatter(_log_formatter)
- log.addHandler(_log_handler)
- return log
-
- # the alias map for configurables
- aliases = Dict({'log-level' : 'Application.log_level'})
-
- # flags for loading Configurables or store_const style flags
- # flags are loaded from this dict by '--key' flags
- # this must be a dict of two-tuples, the first element being the Config/dict
- # and the second being the help string for the flag
- flags = Dict()
- @observe('flags')
- @observe_compat
- def _flags_changed(self, change):
- """ensure flags dict is valid"""
- new = change.new
- for key, value in new.items():
- assert len(value) == 2, "Bad flag: %r:%s" % (key, value)
- assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s" % (key, value)
- assert isinstance(value[1], six.string_types), "Bad flag: %r:%s" % (key, value)
-
-
- # subcommands for launching other applications
- # if this is not empty, this will be a parent Application
- # this must be a dict of two-tuples,
- # the first element being the application class/import string
- # and the second being the help string for the subcommand
- subcommands = Dict()
- # parse_command_line will initialize a subapp, if requested
- subapp = Instance('traitlets.config.application.Application', allow_none=True)
-
- # extra command-line arguments that don't set config values
- extra_args = List(Unicode())
-
- cli_config = Instance(Config, (), {},
- help="""The subset of our configuration that came from the command-line
-
- We re-load this configuration after loading config files,
- to ensure that it maintains highest priority.
- """
- )
-
- _loaded_config_files = List()
-
- def __init__(self, **kwargs):
- SingletonConfigurable.__init__(self, **kwargs)
- # Ensure my class is in self.classes, so my attributes appear in command line
- # options and config files.
- cls = self.__class__
- if cls not in self.classes:
- if self.classes is cls.classes:
- # class attr, assign instead of insert
- cls.classes = [cls] + self.classes
- else:
- self.classes.insert(0, self.__class__)
-
- @observe('config')
- @observe_compat
- def _config_changed(self, change):
- super(Application, self)._config_changed(change)
- self.log.debug('Config changed:')
- self.log.debug(repr(change.new))
-
- @catch_config_error
- def initialize(self, argv=None):
- """Do the basic steps to configure me.
-
- Override in subclasses.
- """
- self.parse_command_line(argv)
-
-
- def start(self):
- """Start the app mainloop.
-
- Override in subclasses.
- """
- if self.subapp is not None:
- return self.subapp.start()
-
- def print_alias_help(self):
- """Print the alias part of the help."""
- if not self.aliases:
- return
-
- lines = []
- classdict = {}
- for cls in self.classes:
- # include all parents (up to, but excluding Configurable) in available names
- for c in cls.mro()[:-3]:
- classdict[c.__name__] = c
-
- for alias, longname in self.aliases.items():
- classname, traitname = longname.split('.',1)
- cls = classdict[classname]
-
- trait = cls.class_traits(config=True)[traitname]
- help = cls.class_get_trait_help(trait).splitlines()
- # reformat first line
- help[0] = help[0].replace(longname, alias) + ' (%s)'%longname
- if len(alias) == 1:
- help[0] = help[0].replace('--%s='%alias, '-%s '%alias)
- lines.extend(help)
- # lines.append('')
- print(os.linesep.join(lines))
-
- def print_flag_help(self):
- """Print the flag part of the help."""
- if not self.flags:
- return
-
- lines = []
- for m, (cfg,help) in self.flags.items():
- prefix = '--' if len(m) > 1 else '-'
- lines.append(prefix+m)
- lines.append(indent(dedent(help.strip())))
- # lines.append('')
- print(os.linesep.join(lines))
-
- def print_options(self):
- if not self.flags and not self.aliases:
- return
- lines = ['Options']
- lines.append('-'*len(lines[0]))
- lines.append('')
- for p in wrap_paragraphs(self.option_description):
- lines.append(p)
- lines.append('')
- print(os.linesep.join(lines))
- self.print_flag_help()
- self.print_alias_help()
- print()
-
- def print_subcommands(self):
- """Print the subcommand part of the help."""
- if not self.subcommands:
- return
-
- lines = ["Subcommands"]
- lines.append('-'*len(lines[0]))
- lines.append('')
- for p in wrap_paragraphs(self.subcommand_description.format(
- app=self.name)):
- lines.append(p)
- lines.append('')
- for subc, (cls, help) in self.subcommands.items():
- lines.append(subc)
- if help:
- lines.append(indent(dedent(help.strip())))
- lines.append('')
- print(os.linesep.join(lines))
-
- def print_help(self, classes=False):
- """Print the help for each Configurable class in self.classes.
-
- If classes=False (the default), only flags and aliases are printed.
- """
- self.print_description()
- self.print_subcommands()
- self.print_options()
-
- if classes:
- help_classes = self.classes
- if help_classes:
- print("Class parameters")
- print("----------------")
- print()
- for p in wrap_paragraphs(self.keyvalue_description):
- print(p)
- print()
-
- for cls in help_classes:
- cls.class_print_help()
- print()
- else:
- print("To see all available configurables, use `--help-all`")
- print()
-
- self.print_examples()
-
- def document_config_options(self):
- """Generate rST format documentation for the config options this application
-
- Returns a multiline string.
- """
- return '\n'.join(c.class_config_rst_doc()
- for c in self._classes_inc_parents())
-
-
- def print_description(self):
- """Print the application description."""
- for p in wrap_paragraphs(self.description):
- print(p)
- print()
-
- def print_examples(self):
- """Print usage and examples.
-
- This usage string goes at the end of the command line help string
- and should contain examples of the application's usage.
- """
- if self.examples:
- print("Examples")
- print("--------")
- print()
- print(indent(dedent(self.examples.strip())))
- print()
-
- def print_version(self):
- """Print the version string."""
- print(self.version)
-
- @catch_config_error
- def initialize_subcommand(self, subc, argv=None):
- """Initialize a subcommand with argv."""
- subapp,help = self.subcommands.get(subc)
-
- if isinstance(subapp, six.string_types):
- subapp = import_item(subapp)
-
- # clear existing instances
- self.__class__.clear_instance()
- # instantiate
- self.subapp = subapp.instance(parent=self)
- # and initialize subapp
- self.subapp.initialize(argv)
-
- def flatten_flags(self):
- """flatten flags and aliases, so cl-args override as expected.
-
- This prevents issues such as an alias pointing to InteractiveShell,
- but a config file setting the same trait in TerminalInteraciveShell
- getting inappropriate priority over the command-line arg.
-
- Only aliases with exactly one descendent in the class list
- will be promoted.
-
- """
- # build a tree of classes in our list that inherit from a particular
- # it will be a dict by parent classname of classes in our list
- # that are descendents
- mro_tree = defaultdict(list)
- for cls in self.classes:
- clsname = cls.__name__
- for parent in cls.mro()[1:-3]:
- # exclude cls itself and Configurable,HasTraits,object
- mro_tree[parent.__name__].append(clsname)
- # flatten aliases, which have the form:
- # { 'alias' : 'Class.trait' }
- aliases = {}
- for alias, cls_trait in self.aliases.items():
- cls,trait = cls_trait.split('.',1)
- children = mro_tree[cls]
- if len(children) == 1:
- # exactly one descendent, promote alias
- cls = children[0]
- aliases[alias] = '.'.join([cls,trait])
-
- # flatten flags, which are of the form:
- # { 'key' : ({'Cls' : {'trait' : value}}, 'help')}
- flags = {}
- for key, (flagdict, help) in self.flags.items():
- newflag = {}
- for cls, subdict in flagdict.items():
- children = mro_tree[cls]
- # exactly one descendent, promote flag section
- if len(children) == 1:
- cls = children[0]
- newflag[cls] = subdict
- flags[key] = (newflag, help)
- return flags, aliases
-
- @catch_config_error
- def parse_command_line(self, argv=None):
- """Parse the command line arguments."""
- argv = sys.argv[1:] if argv is None else argv
- self.argv = [ py3compat.cast_unicode(arg) for arg in argv ]
-
- if argv and argv[0] == 'help':
- # turn `ipython help notebook` into `ipython notebook -h`
- argv = argv[1:] + ['-h']
-
- if self.subcommands and len(argv) > 0:
- # we have subcommands, and one may have been specified
- subc, subargv = argv[0], argv[1:]
- if re.match(r'^\w(\-?\w)*$', subc) and subc in self.subcommands:
- # it's a subcommand, and *not* a flag or class parameter
- return self.initialize_subcommand(subc, subargv)
-
- # Arguments after a '--' argument are for the script IPython may be
- # about to run, not IPython iteslf. For arguments parsed here (help and
- # version), we want to only search the arguments up to the first
- # occurrence of '--', which we're calling interpreted_argv.
- try:
- interpreted_argv = argv[:argv.index('--')]
- except ValueError:
- interpreted_argv = argv
-
- if any(x in interpreted_argv for x in ('-h', '--help-all', '--help')):
- self.print_help('--help-all' in interpreted_argv)
- self.exit(0)
-
- if '--version' in interpreted_argv or '-V' in interpreted_argv:
- self.print_version()
- self.exit(0)
-
- # flatten flags&aliases, so cl-args get appropriate priority:
- flags,aliases = self.flatten_flags()
- loader = KVArgParseConfigLoader(argv=argv, aliases=aliases,
- flags=flags, log=self.log)
- self.cli_config = deepcopy(loader.load_config())
- self.update_config(self.cli_config)
- # store unparsed args in extra_args
- self.extra_args = loader.extra_args
-
- @classmethod
- def _load_config_files(cls, basefilename, path=None, log=None, raise_config_file_errors=False):
- """Load config files (py,json) by filename and path.
-
- yield each config object in turn.
- """
-
- if not isinstance(path, list):
- path = [path]
- for path in path[::-1]:
- # path list is in descending priority order, so load files backwards:
- pyloader = cls.python_config_loader_class(basefilename+'.py', path=path, log=log)
- if log:
- log.debug("Looking for %s in %s", basefilename, path or os.getcwd())
- jsonloader = cls.json_config_loader_class(basefilename+'.json', path=path, log=log)
- loaded = []
- filenames = []
- for loader in [pyloader, jsonloader]:
- config = None
- try:
- config = loader.load_config()
- except ConfigFileNotFound:
- pass
- except Exception:
- # try to get the full filename, but it will be empty in the
- # unlikely event that the error raised before filefind finished
- filename = loader.full_filename or basefilename
- # problem while running the file
- if raise_config_file_errors:
- raise
- if log:
- log.error("Exception while loading config file %s",
- filename, exc_info=True)
- else:
- if log:
- log.debug("Loaded config file: %s", loader.full_filename)
- if config:
- for filename, earlier_config in zip(filenames, loaded):
- collisions = earlier_config.collisions(config)
- if collisions and log:
- log.warning("Collisions detected in {0} and {1} config files."
- " {1} has higher priority: {2}".format(
- filename, loader.full_filename, json.dumps(collisions, indent=2),
- ))
- yield (config, loader.full_filename)
- loaded.append(config)
- filenames.append(loader.full_filename)
-
- @property
- def loaded_config_files(self):
- """Currently loaded configuration files"""
- return self._loaded_config_files[:]
-
- @catch_config_error
- def load_config_file(self, filename, path=None):
- """Load config files by filename and path."""
- filename, ext = os.path.splitext(filename)
- new_config = Config()
- for (config, filename) in self._load_config_files(filename, path=path, log=self.log,
- raise_config_file_errors=self.raise_config_file_errors,
- ):
- new_config.merge(config)
- if filename not in self._loaded_config_files: # only add to list of loaded files if not previously loaded
- self._loaded_config_files.append(filename)
- # add self.cli_config to preserve CLI config priority
- new_config.merge(self.cli_config)
- self.update_config(new_config)
-
-
- def _classes_in_config_sample(self):
- """
- Yields only classes with own traits, and their subclasses.
-
- Thus, produced sample config-file will contain all classes
- on which a trait-value may be overridden:
-
- - either on the class owning the trait,
- - or on its subclasses, even if those subclasses do not define
- any traits themselves.
- """
- cls_to_config = OrderedDict( (cls, bool(cls.class_own_traits(config=True)))
- for cls
- in self._classes_inc_parents())
-
- def is_any_parent_included(cls):
- return any(b in cls_to_config and cls_to_config[b] for b in cls.__bases__)
-
- ## Mark "empty" classes for inclusion if their parents own-traits,
- # and loop until no more classes gets marked.
- #
- while True:
- to_incl_orig = cls_to_config.copy()
- cls_to_config = OrderedDict( (cls, inc_yes or is_any_parent_included(cls))
- for cls, inc_yes
- in cls_to_config.items())
- if cls_to_config == to_incl_orig:
- break
- for cl, inc_yes in cls_to_config.items():
- if inc_yes:
- yield cl
-
- def generate_config_file(self):
- """generate default config file from Configurables"""
- lines = ["# Configuration file for %s." % self.name]
- lines.append('')
- for cls in self._classes_in_config_sample():
- lines.append(cls.class_config_section())
- return '\n'.join(lines)
-
- def exit(self, exit_status=0):
- self.log.debug("Exiting application: %s" % self.name)
- sys.exit(exit_status)
-
- @classmethod
- def launch_instance(cls, argv=None, **kwargs):
- """Launch a global instance of this Application
-
- If a global instance already exists, this reinitializes and starts it
- """
- app = cls.instance(**kwargs)
- app.initialize(argv)
- app.start()
-
-#-----------------------------------------------------------------------------
-# utility functions, for convenience
-#-----------------------------------------------------------------------------
-
-def boolean_flag(name, configurable, set_help='', unset_help=''):
- """Helper for building basic --trait, --no-trait flags.
-
- Parameters
- ----------
-
- name : str
- The name of the flag.
- configurable : str
- The 'Class.trait' string of the trait to be set/unset with the flag
- set_help : unicode
- help string for --name flag
- unset_help : unicode
- help string for --no-name flag
-
- Returns
- -------
-
- cfg : dict
- A dict with two keys: 'name', and 'no-name', for setting and unsetting
- the trait, respectively.
- """
- # default helpstrings
- set_help = set_help or "set %s=True"%configurable
- unset_help = unset_help or "set %s=False"%configurable
-
- cls,trait = configurable.split('.')
-
- setter = {cls : {trait : True}}
- unsetter = {cls : {trait : False}}
- return {name : (setter, set_help), 'no-'+name : (unsetter, unset_help)}
-
-
-def get_config():
- """Get the config object for the global Application instance, if there is one
-
- otherwise return an empty config object
- """
- if Application.initialized():
- return Application.instance().config
- else:
- return Config()
diff --git a/contrib/python/traitlets/py2/traitlets/config/configurable.py b/contrib/python/traitlets/py2/traitlets/config/configurable.py
deleted file mode 100644
index 1174fcf0177..00000000000
--- a/contrib/python/traitlets/py2/traitlets/config/configurable.py
+++ /dev/null
@@ -1,432 +0,0 @@
-# encoding: utf-8
-"""A base class for objects that are configurable."""
-
-# Copyright (c) IPython Development Team.
-# Distributed under the terms of the Modified BSD License.
-
-from __future__ import print_function, absolute_import
-
-from copy import deepcopy
-import warnings
-
-from .loader import Config, LazyConfigValue, _is_section_key
-from traitlets.traitlets import HasTraits, Instance, observe, observe_compat, default
-from ipython_genutils.text import indent, dedent, wrap_paragraphs
-
-
-#-----------------------------------------------------------------------------
-# Helper classes for Configurables
-#-----------------------------------------------------------------------------
-
-
-class ConfigurableError(Exception):
- pass
-
-
-class MultipleInstanceError(ConfigurableError):
- pass
-
-#-----------------------------------------------------------------------------
-# Configurable implementation
-#-----------------------------------------------------------------------------
-
-class Configurable(HasTraits):
-
- config = Instance(Config, (), {})
- parent = Instance('traitlets.config.configurable.Configurable', allow_none=True)
-
- def __init__(self, **kwargs):
- """Create a configurable given a config config.
-
- Parameters
- ----------
- config : Config
- If this is empty, default values are used. If config is a
- :class:`Config` instance, it will be used to configure the
- instance.
- parent : Configurable instance, optional
- The parent Configurable instance of this object.
-
- Notes
- -----
- Subclasses of Configurable must call the :meth:`__init__` method of
- :class:`Configurable` *before* doing anything else and using
- :func:`super`::
-
- class MyConfigurable(Configurable):
- def __init__(self, config=None):
- super(MyConfigurable, self).__init__(config=config)
- # Then any other code you need to finish initialization.
-
- This ensures that instances will be configured properly.
- """
- parent = kwargs.pop('parent', None)
- if parent is not None:
- # config is implied from parent
- if kwargs.get('config', None) is None:
- kwargs['config'] = parent.config
- self.parent = parent
-
- config = kwargs.pop('config', None)
-
- # load kwarg traits, other than config
- super(Configurable, self).__init__(**kwargs)
-
- # load config
- if config is not None:
- # We used to deepcopy, but for now we are trying to just save
- # by reference. This *could* have side effects as all components
- # will share config. In fact, I did find such a side effect in
- # _config_changed below. If a config attribute value was a mutable type
- # all instances of a component were getting the same copy, effectively
- # making that a class attribute.
- # self.config = deepcopy(config)
- self.config = config
- else:
- # allow _config_default to return something
- self._load_config(self.config)
-
- # Ensure explicit kwargs are applied after loading config.
- # This is usually redundant, but ensures config doesn't override
- # explicitly assigned values.
- for key, value in kwargs.items():
- setattr(self, key, value)
-
- #-------------------------------------------------------------------------
- # Static trait notifiations
- #-------------------------------------------------------------------------
-
- @classmethod
- def section_names(cls):
- """return section names as a list"""
- return [c.__name__ for c in reversed(cls.__mro__) if
- issubclass(c, Configurable) and issubclass(cls, c)
- ]
-
- def _find_my_config(self, cfg):
- """extract my config from a global Config object
-
- will construct a Config object of only the config values that apply to me
- based on my mro(), as well as those of my parent(s) if they exist.
-
- If I am Bar and my parent is Foo, and their parent is Tim,
- this will return merge following config sections, in this order::
-
- [Bar, Foo.bar, Tim.Foo.Bar]
-
- With the last item being the highest priority.
- """
- cfgs = [cfg]
- if self.parent:
- cfgs.append(self.parent._find_my_config(cfg))
- my_config = Config()
- for c in cfgs:
- for sname in self.section_names():
- # Don't do a blind getattr as that would cause the config to
- # dynamically create the section with name Class.__name__.
- if c._has_section(sname):
- my_config.merge(c[sname])
- return my_config
-
- def _load_config(self, cfg, section_names=None, traits=None):
- """load traits from a Config object"""
-
- if traits is None:
- traits = self.traits(config=True)
- if section_names is None:
- section_names = self.section_names()
-
- my_config = self._find_my_config(cfg)
-
- # hold trait notifications until after all config has been loaded
- with self.hold_trait_notifications():
- for name, config_value in my_config.items():
- if name in traits:
- if isinstance(config_value, LazyConfigValue):
- # ConfigValue is a wrapper for using append / update on containers
- # without having to copy the initial value
- initial = getattr(self, name)
- config_value = config_value.get_value(initial)
- # We have to do a deepcopy here if we don't deepcopy the entire
- # config object. If we don't, a mutable config_value will be
- # shared by all instances, effectively making it a class attribute.
- setattr(self, name, deepcopy(config_value))
- elif not _is_section_key(name) and not isinstance(config_value, Config):
- from difflib import get_close_matches
- if isinstance(self, LoggingConfigurable):
- warn = self.log.warning
- else:
- warn = lambda msg: warnings.warn(msg, stacklevel=9)
- matches = get_close_matches(name, traits)
- msg = u"Config option `{option}` not recognized by `{klass}`.".format(
- option=name, klass=self.__class__.__name__)
-
- if len(matches) == 1:
- msg += u" Did you mean `{matches}`?".format(matches=matches[0])
- elif len(matches) >= 1:
- msg +=" Did you mean one of: `{matches}`?".format(matches=', '.join(sorted(matches)))
- warn(msg)
-
- @observe('config')
- @observe_compat
- def _config_changed(self, change):
- """Update all the class traits having ``config=True`` in metadata.
-
- For any class trait with a ``config`` metadata attribute that is
- ``True``, we update the trait with the value of the corresponding
- config entry.
- """
- # Get all traits with a config metadata entry that is True
- traits = self.traits(config=True)
-
- # We auto-load config section for this class as well as any parent
- # classes that are Configurable subclasses. This starts with Configurable
- # and works down the mro loading the config for each section.
- section_names = self.section_names()
- self._load_config(change.new, traits=traits, section_names=section_names)
-
- def update_config(self, config):
- """Update config and load the new values"""
- # traitlets prior to 4.2 created a copy of self.config in order to trigger change events.
- # Some projects (IPython < 5) relied upon one side effect of this,
- # that self.config prior to update_config was not modified in-place.
- # For backward-compatibility, we must ensure that self.config
- # is a new object and not modified in-place,
- # but config consumers should not rely on this behavior.
- self.config = deepcopy(self.config)
- # load config
- self._load_config(config)
- # merge it into self.config
- self.config.merge(config)
- # TODO: trigger change event if/when dict-update change events take place
- # DO NOT trigger full trait-change
-
- @classmethod
- def class_get_help(cls, inst=None):
- """Get the help string for this class in ReST format.
-
- If `inst` is given, it's current trait values will be used in place of
- class defaults.
- """
- assert inst is None or isinstance(inst, cls)
- final_help = []
- final_help.append(u'%s options' % cls.__name__)
- final_help.append(len(final_help[0])*u'-')
- for k, v in sorted(cls.class_traits(config=True).items()):
- help = cls.class_get_trait_help(v, inst)
- final_help.append(help)
- return '\n'.join(final_help)
-
- @classmethod
- def class_get_trait_help(cls, trait, inst=None):
- """Get the help string for a single trait.
-
- If `inst` is given, it's current trait values will be used in place of
- the class default.
- """
- assert inst is None or isinstance(inst, cls)
- lines = []
- header = "--%s.%s=<%s>" % (cls.__name__, trait.name, trait.__class__.__name__)
- lines.append(header)
- if inst is not None:
- lines.append(indent('Current: %r' % getattr(inst, trait.name), 4))
- else:
- try:
- dvr = trait.default_value_repr()
- except Exception:
- dvr = None # ignore defaults we can't construct
- if dvr is not None:
- if len(dvr) > 64:
- dvr = dvr[:61]+'...'
- lines.append(indent('Default: %s' % dvr, 4))
- if 'Enum' in trait.__class__.__name__:
- # include Enum choices
- lines.append(indent('Choices: %r' % (trait.values,)))
-
- help = trait.help
- if help != '':
- help = '\n'.join(wrap_paragraphs(help, 76))
- lines.append(indent(help, 4))
- return '\n'.join(lines)
-
- @classmethod
- def class_print_help(cls, inst=None):
- """Get the help string for a single trait and print it."""
- print(cls.class_get_help(inst))
-
- @classmethod
- def class_config_section(cls):
- """Get the config class config section"""
- def c(s):
- """return a commented, wrapped block."""
- s = '\n\n'.join(wrap_paragraphs(s, 78))
-
- return '## ' + s.replace('\n', '\n# ')
-
- # section header
- breaker = '#' + '-'*78
- parent_classes = ','.join(p.__name__ for p in cls.__bases__)
- s = "# %s(%s) configuration" % (cls.__name__, parent_classes)
- lines = [breaker, s, breaker, '']
- # get the description trait
- desc = cls.class_traits().get('description')
- if desc:
- desc = desc.default_value
- if not desc:
- # no description from trait, use __doc__
- desc = getattr(cls, '__doc__', '')
- if desc:
- lines.append(c(desc))
- lines.append('')
-
- for name, trait in sorted(cls.class_own_traits(config=True).items()):
- lines.append(c(trait.help))
- lines.append('#c.%s.%s = %s' % (cls.__name__, name, trait.default_value_repr()))
- lines.append('')
- return '\n'.join(lines)
-
- @classmethod
- def class_config_rst_doc(cls):
- """Generate rST documentation for this class' config options.
-
- Excludes traits defined on parent classes.
- """
- lines = []
- classname = cls.__name__
- for k, trait in sorted(cls.class_own_traits(config=True).items()):
- ttype = trait.__class__.__name__
-
- termline = classname + '.' + trait.name
-
- # Choices or type
- if 'Enum' in ttype:
- # include Enum choices
- termline += ' : ' + '|'.join(repr(x) for x in trait.values)
- else:
- termline += ' : ' + ttype
- lines.append(termline)
-
- # Default value
- try:
- dvr = trait.default_value_repr()
- except Exception:
- dvr = None # ignore defaults we can't construct
- if dvr is not None:
- if len(dvr) > 64:
- dvr = dvr[:61]+'...'
- # Double up backslashes, so they get to the rendered docs
- dvr = dvr.replace('\\n', '\\\\n')
- lines.append(' Default: ``%s``' % dvr)
- lines.append('')
-
- help = trait.help or 'No description'
- lines.append(indent(dedent(help), 4))
-
- # Blank line
- lines.append('')
-
- return '\n'.join(lines)
-
-
-
-class LoggingConfigurable(Configurable):
- """A parent class for Configurables that log.
-
- Subclasses have a log trait, and the default behavior
- is to get the logger from the currently running Application.
- """
-
- log = Instance('logging.Logger')
- @default('log')
- def _log_default(self):
- from traitlets import log
- return log.get_logger()
-
-
-class SingletonConfigurable(LoggingConfigurable):
- """A configurable that only allows one instance.
-
- This class is for classes that should only have one instance of itself
- or *any* subclass. To create and retrieve such a class use the
- :meth:`SingletonConfigurable.instance` method.
- """
-
- _instance = None
-
- @classmethod
- def _walk_mro(cls):
- """Walk the cls.mro() for parent classes that are also singletons
-
- For use in instance()
- """
-
- for subclass in cls.mro():
- if issubclass(cls, subclass) and \
- issubclass(subclass, SingletonConfigurable) and \
- subclass != SingletonConfigurable:
- yield subclass
-
- @classmethod
- def clear_instance(cls):
- """unset _instance for this class and singleton parents.
- """
- if not cls.initialized():
- return
- for subclass in cls._walk_mro():
- if isinstance(subclass._instance, cls):
- # only clear instances that are instances
- # of the calling class
- subclass._instance = None
-
- @classmethod
- def instance(cls, *args, **kwargs):
- """Returns a global instance of this class.
-
- This method create a new instance if none have previously been created
- and returns a previously created instance is one already exists.
-
- The arguments and keyword arguments passed to this method are passed
- on to the :meth:`__init__` method of the class upon instantiation.
-
- Examples
- --------
-
- Create a singleton class using instance, and retrieve it::
-
- >>> from traitlets.config.configurable import SingletonConfigurable
- >>> class Foo(SingletonConfigurable): pass
- >>> foo = Foo.instance()
- >>> foo == Foo.instance()
- True
-
- Create a subclass that is retrived using the base class instance::
-
- >>> class Bar(SingletonConfigurable): pass
- >>> class Bam(Bar): pass
- >>> bam = Bam.instance()
- >>> bam == Bar.instance()
- True
- """
- # Create and save the instance
- if cls._instance is None:
- inst = cls(*args, **kwargs)
- # Now make sure that the instance will also be returned by
- # parent classes' _instance attribute.
- for subclass in cls._walk_mro():
- subclass._instance = inst
-
- if isinstance(cls._instance, cls):
- return cls._instance
- else:
- raise MultipleInstanceError(
- 'Multiple incompatible subclass instances of '
- '%s are being created.' % cls.__name__
- )
-
- @classmethod
- def initialized(cls):
- """Has an instance been created?"""
- return hasattr(cls, "_instance") and cls._instance is not None
-
-
-
diff --git a/contrib/python/traitlets/py2/traitlets/config/loader.py b/contrib/python/traitlets/py2/traitlets/config/loader.py
deleted file mode 100644
index 803b36276f2..00000000000
--- a/contrib/python/traitlets/py2/traitlets/config/loader.py
+++ /dev/null
@@ -1,857 +0,0 @@
-# encoding: utf-8
-"""A simple configuration system."""
-
-# Copyright (c) IPython Development Team.
-# Distributed under the terms of the Modified BSD License.
-
-import argparse
-import copy
-import logging
-import os
-import re
-import sys
-import json
-from ast import literal_eval
-
-from ipython_genutils.path import filefind
-from ipython_genutils import py3compat
-from ipython_genutils.encoding import DEFAULT_ENCODING
-from six import text_type
-from traitlets.traitlets import HasTraits, List, Any
-
-#-----------------------------------------------------------------------------
-# Exceptions
-#-----------------------------------------------------------------------------
-
-
-class ConfigError(Exception):
- pass
-
-class ConfigLoaderError(ConfigError):
- pass
-
-class ConfigFileNotFound(ConfigError):
- pass
-
-class ArgumentError(ConfigLoaderError):
- pass
-
-#-----------------------------------------------------------------------------
-# Argparse fix
-#-----------------------------------------------------------------------------
-
-# Unfortunately argparse by default prints help messages to stderr instead of
-# stdout. This makes it annoying to capture long help screens at the command
-# line, since one must know how to pipe stderr, which many users don't know how
-# to do. So we override the print_help method with one that defaults to
-# stdout and use our class instead.
-
-class ArgumentParser(argparse.ArgumentParser):
- """Simple argparse subclass that prints help to stdout by default."""
-
- def print_help(self, file=None):
- if file is None:
- file = sys.stdout
- return super(ArgumentParser, self).print_help(file)
-
- print_help.__doc__ = argparse.ArgumentParser.print_help.__doc__
-
-#-----------------------------------------------------------------------------
-# Config class for holding config information
-#-----------------------------------------------------------------------------
-
-class LazyConfigValue(HasTraits):
- """Proxy object for exposing methods on configurable containers
-
- Exposes:
-
- - append, extend, insert on lists
- - update on dicts
- - update, add on sets
- """
-
- _value = None
-
- # list methods
- _extend = List()
- _prepend = List()
-
- def append(self, obj):
- self._extend.append(obj)
-
- def extend(self, other):
- self._extend.extend(other)
-
- def prepend(self, other):
- """like list.extend, but for the front"""
- self._prepend[:0] = other
-
- _inserts = List()
- def insert(self, index, other):
- if not isinstance(index, int):
- raise TypeError("An integer is required")
- self._inserts.append((index, other))
-
- # dict methods
- # update is used for both dict and set
- _update = Any()
- def update(self, other):
- if self._update is None:
- if isinstance(other, dict):
- self._update = {}
- else:
- self._update = set()
- self._update.update(other)
-
- # set methods
- def add(self, obj):
- self.update({obj})
-
- def get_value(self, initial):
- """construct the value from the initial one
-
- after applying any insert / extend / update changes
- """
- if self._value is not None:
- return self._value
- value = copy.deepcopy(initial)
- if isinstance(value, list):
- for idx, obj in self._inserts:
- value.insert(idx, obj)
- value[:0] = self._prepend
- value.extend(self._extend)
-
- elif isinstance(value, dict):
- if self._update:
- value.update(self._update)
- elif isinstance(value, set):
- if self._update:
- value.update(self._update)
- self._value = value
- return value
-
- def to_dict(self):
- """return JSONable dict form of my data
-
- Currently update as dict or set, extend, prepend as lists, and inserts as list of tuples.
- """
- d = {}
- if self._update:
- d['update'] = self._update
- if self._extend:
- d['extend'] = self._extend
- if self._prepend:
- d['prepend'] = self._prepend
- elif self._inserts:
- d['inserts'] = self._inserts
- return d
-
-
-def _is_section_key(key):
- """Is a Config key a section name (does it start with a capital)?"""
- if key and key[0].upper()==key[0] and not key.startswith('_'):
- return True
- else:
- return False
-
-
-class Config(dict):
- """An attribute based dict that can do smart merges."""
-
- def __init__(self, *args, **kwds):
- dict.__init__(self, *args, **kwds)
- self._ensure_subconfig()
-
- def _ensure_subconfig(self):
- """ensure that sub-dicts that should be Config objects are
-
- casts dicts that are under section keys to Config objects,
- which is necessary for constructing Config objects from dict literals.
- """
- for key in self:
- obj = self[key]
- if _is_section_key(key) \
- and isinstance(obj, dict) \
- and not isinstance(obj, Config):
- setattr(self, key, Config(obj))
-
- def _merge(self, other):
- """deprecated alias, use Config.merge()"""
- self.merge(other)
-
- def merge(self, other):
- """merge another config object into this one"""
- to_update = {}
- for k, v in other.items():
- if k not in self:
- to_update[k] = v
- else: # I have this key
- if isinstance(v, Config) and isinstance(self[k], Config):
- # Recursively merge common sub Configs
- self[k].merge(v)
- else:
- # Plain updates for non-Configs
- to_update[k] = v
-
- self.update(to_update)
-
- def collisions(self, other):
- """Check for collisions between two config objects.
-
- Returns a dict of the form {"Class": {"trait": "collision message"}}`,
- indicating which values have been ignored.
-
- An empty dict indicates no collisions.
- """
- collisions = {}
- for section in self:
- if section not in other:
- continue
- mine = self[section]
- theirs = other[section]
- for key in mine:
- if key in theirs and mine[key] != theirs[key]:
- collisions.setdefault(section, {})
- collisions[section][key] = "%r ignored, using %r" % (mine[key], theirs[key])
- return collisions
-
- def __contains__(self, key):
- # allow nested contains of the form `"Section.key" in config`
- if '.' in key:
- first, remainder = key.split('.', 1)
- if first not in self:
- return False
- return remainder in self[first]
-
- return super(Config, self).__contains__(key)
-
- # .has_key is deprecated for dictionaries.
- has_key = __contains__
-
- def _has_section(self, key):
- return _is_section_key(key) and key in self
-
- def copy(self):
- return type(self)(dict.copy(self))
-
- def __copy__(self):
- return self.copy()
-
- def __deepcopy__(self, memo):
- new_config = type(self)()
- for key, value in self.items():
- if isinstance(value, (Config, LazyConfigValue)):
- # deep copy config objects
- value = copy.deepcopy(value, memo)
- elif type(value) in {dict, list, set, tuple}:
- # shallow copy plain container traits
- value = copy.copy(value)
- new_config[key] = value
- return new_config
-
- def __getitem__(self, key):
- try:
- return dict.__getitem__(self, key)
- except KeyError:
- if _is_section_key(key):
- c = Config()
- dict.__setitem__(self, key, c)
- return c
- elif not key.startswith('_'):
- # undefined, create lazy value, used for container methods
- v = LazyConfigValue()
- dict.__setitem__(self, key, v)
- return v
- else:
- raise KeyError
-
- def __setitem__(self, key, value):
- if _is_section_key(key):
- if not isinstance(value, Config):
- raise ValueError('values whose keys begin with an uppercase '
- 'char must be Config instances: %r, %r' % (key, value))
- dict.__setitem__(self, key, value)
-
- def __getattr__(self, key):
- if key.startswith('__'):
- return dict.__getattr__(self, key)
- try:
- return self.__getitem__(key)
- except KeyError as e:
- raise AttributeError(e)
-
- def __setattr__(self, key, value):
- if key.startswith('__'):
- return dict.__setattr__(self, key, value)
- try:
- self.__setitem__(key, value)
- except KeyError as e:
- raise AttributeError(e)
-
- def __delattr__(self, key):
- if key.startswith('__'):
- return dict.__delattr__(self, key)
- try:
- dict.__delitem__(self, key)
- except KeyError as e:
- raise AttributeError(e)
-
-
-#-----------------------------------------------------------------------------
-# Config loading classes
-#-----------------------------------------------------------------------------
-
-
-class ConfigLoader(object):
- """A object for loading configurations from just about anywhere.
-
- The resulting configuration is packaged as a :class:`Config`.
-
- Notes
- -----
- A :class:`ConfigLoader` does one thing: load a config from a source
- (file, command line arguments) and returns the data as a :class:`Config` object.
- There are lots of things that :class:`ConfigLoader` does not do. It does
- not implement complex logic for finding config files. It does not handle
- default values or merge multiple configs. These things need to be
- handled elsewhere.
- """
-
- def _log_default(self):
- from traitlets.log import get_logger
- return get_logger()
-
- def __init__(self, log=None):
- """A base class for config loaders.
-
- log : instance of :class:`logging.Logger` to use.
- By default loger of :meth:`traitlets.config.application.Application.instance()`
- will be used
-
- Examples
- --------
-
- >>> cl = ConfigLoader()
- >>> config = cl.load_config()
- >>> config
- {}
- """
- self.clear()
- if log is None:
- self.log = self._log_default()
- self.log.debug('Using default logger')
- else:
- self.log = log
-
- def clear(self):
- self.config = Config()
-
- def load_config(self):
- """Load a config from somewhere, return a :class:`Config` instance.
-
- Usually, this will cause self.config to be set and then returned.
- However, in most cases, :meth:`ConfigLoader.clear` should be called
- to erase any previous state.
- """
- self.clear()
- return self.config
-
-
-class FileConfigLoader(ConfigLoader):
- """A base class for file based configurations.
-
- As we add more file based config loaders, the common logic should go
- here.
- """
-
- def __init__(self, filename, path=None, **kw):
- """Build a config loader for a filename and path.
-
- Parameters
- ----------
- filename : str
- The file name of the config file.
- path : str, list, tuple
- The path to search for the config file on, or a sequence of
- paths to try in order.
- """
- super(FileConfigLoader, self).__init__(**kw)
- self.filename = filename
- self.path = path
- self.full_filename = ''
-
- def _find_file(self):
- """Try to find the file by searching the paths."""
- self.full_filename = filefind(self.filename, self.path)
-
-class JSONFileConfigLoader(FileConfigLoader):
- """A JSON file loader for config
-
- Can also act as a context manager that rewrite the configuration file to disk on exit.
-
- Example::
-
- with JSONFileConfigLoader('myapp.json','/home/jupyter/configurations/') as c:
- c.MyNewConfigurable.new_value = 'Updated'
-
- """
-
- def load_config(self):
- """Load the config from a file and return it as a Config object."""
- self.clear()
- try:
- self._find_file()
- except IOError as e:
- raise ConfigFileNotFound(str(e))
- dct = self._read_file_as_dict()
- self.config = self._convert_to_config(dct)
- return self.config
-
- def _read_file_as_dict(self):
- with open(self.full_filename) as f:
- return json.load(f)
-
- def _convert_to_config(self, dictionary):
- if 'version' in dictionary:
- version = dictionary.pop('version')
- else:
- version = 1
-
- if version == 1:
- return Config(dictionary)
- else:
- raise ValueError('Unknown version of JSON config file: {version}'.format(version=version))
-
- def __enter__(self):
- self.load_config()
- return self.config
-
- def __exit__(self, exc_type, exc_value, traceback):
- """
- Exit the context manager but do not handle any errors.
-
- In case of any error, we do not want to write the potentially broken
- configuration to disk.
- """
- self.config.version = 1
- json_config = json.dumps(self.config, indent=2)
- with open(self.full_filename, 'w') as f:
- f.write(json_config)
-
-
-
-class PyFileConfigLoader(FileConfigLoader):
- """A config loader for pure python files.
-
- This is responsible for locating a Python config file by filename and
- path, then executing it to construct a Config object.
- """
-
- def load_config(self):
- """Load the config from a file and return it as a Config object."""
- self.clear()
- try:
- self._find_file()
- except IOError as e:
- raise ConfigFileNotFound(str(e))
- self._read_file_as_dict()
- return self.config
-
- def load_subconfig(self, fname, path=None):
- """Injected into config file namespace as load_subconfig"""
- if path is None:
- path = self.path
-
- loader = self.__class__(fname, path)
- try:
- sub_config = loader.load_config()
- except ConfigFileNotFound:
- # Pass silently if the sub config is not there,
- # treat it as an empty config file.
- pass
- else:
- self.config.merge(sub_config)
-
- def _read_file_as_dict(self):
- """Load the config file into self.config, with recursive loading."""
- def get_config():
- """Unnecessary now, but a deprecation warning is more trouble than it's worth."""
- return self.config
-
- namespace = dict(
- c=self.config,
- load_subconfig=self.load_subconfig,
- get_config=get_config,
- __file__=self.full_filename,
- )
- fs_encoding = sys.getfilesystemencoding() or 'ascii'
- conf_filename = self.full_filename.encode(fs_encoding)
- py3compat.execfile(conf_filename, namespace)
-
-
-class CommandLineConfigLoader(ConfigLoader):
- """A config loader for command line arguments.
-
- As we add more command line based loaders, the common logic should go
- here.
- """
-
- def _exec_config_str(self, lhs, rhs):
- """execute self.config.<lhs> = <rhs>
-
- * expands ~ with expanduser
- * tries to assign with literal_eval, otherwise assigns with just the string,
- allowing `--C.a=foobar` and `--C.a="foobar"` to be equivalent. *Not*
- equivalent are `--C.a=4` and `--C.a='4'`.
- """
- rhs = os.path.expanduser(rhs)
- try:
- # Try to see if regular Python syntax will work. This
- # won't handle strings as the quote marks are removed
- # by the system shell.
- value = literal_eval(rhs)
- except (NameError, SyntaxError, ValueError):
- # This case happens if the rhs is a string.
- value = rhs
-
- exec(u'self.config.%s = value' % lhs)
-
- def _load_flag(self, cfg):
- """update self.config from a flag, which can be a dict or Config"""
- if isinstance(cfg, (dict, Config)):
- # don't clobber whole config sections, update
- # each section from config:
- for sec,c in cfg.items():
- self.config[sec].update(c)
- else:
- raise TypeError("Invalid flag: %r" % cfg)
-
-# raw --identifier=value pattern
-# but *also* accept '-' as wordsep, for aliases
-# accepts: --foo=a
-# --Class.trait=value
-# --alias-name=value
-# rejects: -foo=value
-# --foo
-# --Class.trait
-kv_pattern = re.compile(r'\-\-[A-Za-z][\w\-]*(\.[\w\-]+)*\=.*')
-
-# just flags, no assignments, with two *or one* leading '-'
-# accepts: --foo
-# -foo-bar-again
-# rejects: --anything=anything
-# --two.word
-
-flag_pattern = re.compile(r'\-\-?\w+[\-\w]*$')
-
-class KeyValueConfigLoader(CommandLineConfigLoader):
- """A config loader that loads key value pairs from the command line.
-
- This allows command line options to be gives in the following form::
-
- ipython --profile="foo" --InteractiveShell.autocall=False
- """
-
- def __init__(self, argv=None, aliases=None, flags=None, **kw):
- """Create a key value pair config loader.
-
- Parameters
- ----------
- argv : list
- A list that has the form of sys.argv[1:] which has unicode
- elements of the form u"key=value". If this is None (default),
- then sys.argv[1:] will be used.
- aliases : dict
- A dict of aliases for configurable traits.
- Keys are the short aliases, Values are the resolved trait.
- Of the form: `{'alias' : 'Configurable.trait'}`
- flags : dict
- A dict of flags, keyed by str name. Vaues can be Config objects,
- dicts, or "key=value" strings. If Config or dict, when the flag
- is triggered, The flag is loaded as `self.config.update(m)`.
-
- Returns
- -------
- config : Config
- The resulting Config object.
-
- Examples
- --------
-
- >>> from traitlets.config.loader import KeyValueConfigLoader
- >>> cl = KeyValueConfigLoader()
- >>> d = cl.load_config(["--A.name='brian'","--B.number=0"])
- >>> sorted(d.items())
- [('A', {'name': 'brian'}), ('B', {'number': 0})]
- """
- super(KeyValueConfigLoader, self).__init__(**kw)
- if argv is None:
- argv = sys.argv[1:]
- self.argv = argv
- self.aliases = aliases or {}
- self.flags = flags or {}
-
-
- def clear(self):
- super(KeyValueConfigLoader, self).clear()
- self.extra_args = []
-
-
- def _decode_argv(self, argv, enc=None):
- """decode argv if bytes, using stdin.encoding, falling back on default enc"""
- uargv = []
- if enc is None:
- enc = DEFAULT_ENCODING
- for arg in argv:
- if not isinstance(arg, text_type):
- # only decode if not already decoded
- arg = arg.decode(enc)
- uargv.append(arg)
- return uargv
-
-
- def load_config(self, argv=None, aliases=None, flags=None):
- """Parse the configuration and generate the Config object.
-
- After loading, any arguments that are not key-value or
- flags will be stored in self.extra_args - a list of
- unparsed command-line arguments. This is used for
- arguments such as input files or subcommands.
-
- Parameters
- ----------
- argv : list, optional
- A list that has the form of sys.argv[1:] which has unicode
- elements of the form u"key=value". If this is None (default),
- then self.argv will be used.
- aliases : dict
- A dict of aliases for configurable traits.
- Keys are the short aliases, Values are the resolved trait.
- Of the form: `{'alias' : 'Configurable.trait'}`
- flags : dict
- A dict of flags, keyed by str name. Values can be Config objects
- or dicts. When the flag is triggered, The config is loaded as
- `self.config.update(cfg)`.
- """
- self.clear()
- if argv is None:
- argv = self.argv
- if aliases is None:
- aliases = self.aliases
- if flags is None:
- flags = self.flags
-
- # ensure argv is a list of unicode strings:
- uargv = self._decode_argv(argv)
- for idx,raw in enumerate(uargv):
- # strip leading '-'
- item = raw.lstrip('-')
-
- if raw == '--':
- # don't parse arguments after '--'
- # this is useful for relaying arguments to scripts, e.g.
- # ipython -i foo.py --matplotlib=qt -- args after '--' go-to-foo.py
- self.extra_args.extend(uargv[idx+1:])
- break
-
- if kv_pattern.match(raw):
- lhs,rhs = item.split('=',1)
- # Substitute longnames for aliases.
- if lhs in aliases:
- lhs = aliases[lhs]
- if '.' not in lhs:
- # probably a mistyped alias, but not technically illegal
- self.log.warning("Unrecognized alias: '%s', it will probably have no effect.", raw)
- try:
- self._exec_config_str(lhs, rhs)
- except Exception:
- raise ArgumentError("Invalid argument: '%s'" % raw)
-
- elif flag_pattern.match(raw):
- if item in flags:
- cfg,help = flags[item]
- self._load_flag(cfg)
- else:
- raise ArgumentError("Unrecognized flag: '%s'"%raw)
- elif raw.startswith('-'):
- kv = '--'+item
- if kv_pattern.match(kv):
- raise ArgumentError("Invalid argument: '%s', did you mean '%s'?"%(raw, kv))
- else:
- raise ArgumentError("Invalid argument: '%s'"%raw)
- else:
- # keep all args that aren't valid in a list,
- # in case our parent knows what to do with them.
- self.extra_args.append(item)
- return self.config
-
-class ArgParseConfigLoader(CommandLineConfigLoader):
- """A loader that uses the argparse module to load from the command line."""
-
- def __init__(self, argv=None, aliases=None, flags=None, log=None, *parser_args, **parser_kw):
- """Create a config loader for use with argparse.
-
- Parameters
- ----------
-
- argv : optional, list
- If given, used to read command-line arguments from, otherwise
- sys.argv[1:] is used.
-
- parser_args : tuple
- A tuple of positional arguments that will be passed to the
- constructor of :class:`argparse.ArgumentParser`.
-
- parser_kw : dict
- A tuple of keyword arguments that will be passed to the
- constructor of :class:`argparse.ArgumentParser`.
-
- Returns
- -------
- config : Config
- The resulting Config object.
- """
- super(CommandLineConfigLoader, self).__init__(log=log)
- self.clear()
- if argv is None:
- argv = sys.argv[1:]
- self.argv = argv
- self.aliases = aliases or {}
- self.flags = flags or {}
-
- self.parser_args = parser_args
- self.version = parser_kw.pop("version", None)
- kwargs = dict(argument_default=argparse.SUPPRESS)
- kwargs.update(parser_kw)
- self.parser_kw = kwargs
-
- def load_config(self, argv=None, aliases=None, flags=None):
- """Parse command line arguments and return as a Config object.
-
- Parameters
- ----------
-
- args : optional, list
- If given, a list with the structure of sys.argv[1:] to parse
- arguments from. If not given, the instance's self.argv attribute
- (given at construction time) is used."""
- self.clear()
- if argv is None:
- argv = self.argv
- if aliases is None:
- aliases = self.aliases
- if flags is None:
- flags = self.flags
- self._create_parser(aliases, flags)
- self._parse_args(argv)
- self._convert_to_config()
- return self.config
-
- def get_extra_args(self):
- if hasattr(self, 'extra_args'):
- return self.extra_args
- else:
- return []
-
- def _create_parser(self, aliases=None, flags=None):
- self.parser = ArgumentParser(*self.parser_args, **self.parser_kw)
- self._add_arguments(aliases, flags)
-
- def _add_arguments(self, aliases=None, flags=None):
- raise NotImplementedError("subclasses must implement _add_arguments")
-
- def _parse_args(self, args):
- """self.parser->self.parsed_data"""
- # decode sys.argv to support unicode command-line options
- enc = DEFAULT_ENCODING
- uargs = [py3compat.cast_unicode(a, enc) for a in args]
- self.parsed_data, self.extra_args = self.parser.parse_known_args(uargs)
-
- def _convert_to_config(self):
- """self.parsed_data->self.config"""
- for k, v in vars(self.parsed_data).items():
- exec("self.config.%s = v"%k, locals(), globals())
-
-class KVArgParseConfigLoader(ArgParseConfigLoader):
- """A config loader that loads aliases and flags with argparse,
- but will use KVLoader for the rest. This allows better parsing
- of common args, such as `ipython -c 'print 5'`, but still gets
- arbitrary config with `ipython --InteractiveShell.use_readline=False`"""
-
- def _add_arguments(self, aliases=None, flags=None):
- self.alias_flags = {}
- # print aliases, flags
- if aliases is None:
- aliases = self.aliases
- if flags is None:
- flags = self.flags
- paa = self.parser.add_argument
- for key,value in aliases.items():
- if key in flags:
- # flags
- nargs = '?'
- else:
- nargs = None
- if len(key) is 1:
- paa('-'+key, '--'+key, type=text_type, dest=value, nargs=nargs)
- else:
- paa('--'+key, type=text_type, dest=value, nargs=nargs)
- for key, (value, help) in flags.items():
- if key in self.aliases:
- #
- self.alias_flags[self.aliases[key]] = value
- continue
- if len(key) is 1:
- paa('-'+key, '--'+key, action='append_const', dest='_flags', const=value)
- else:
- paa('--'+key, action='append_const', dest='_flags', const=value)
-
- def _convert_to_config(self):
- """self.parsed_data->self.config, parse unrecognized extra args via KVLoader."""
- # remove subconfigs list from namespace before transforming the Namespace
- if '_flags' in self.parsed_data:
- subcs = self.parsed_data._flags
- del self.parsed_data._flags
- else:
- subcs = []
-
- for k, v in vars(self.parsed_data).items():
- if v is None:
- # it was a flag that shares the name of an alias
- subcs.append(self.alias_flags[k])
- else:
- # eval the KV assignment
- self._exec_config_str(k, v)
-
- for subc in subcs:
- self._load_flag(subc)
-
- if self.extra_args:
- sub_parser = KeyValueConfigLoader(log=self.log)
- sub_parser.load_config(self.extra_args)
- self.config.merge(sub_parser.config)
- self.extra_args = sub_parser.extra_args
-
-
-def load_pyconfig_files(config_files, path):
- """Load multiple Python config files, merging each of them in turn.
-
- Parameters
- ==========
- config_files : list of str
- List of config files names to load and merge into the config.
- path : unicode
- The full path to the location of the config files.
- """
- config = Config()
- for cf in config_files:
- loader = PyFileConfigLoader(cf, path=path)
- try:
- next_config = loader.load_config()
- except ConfigFileNotFound:
- pass
- except:
- raise
- else:
- config.merge(next_config)
- return config
diff --git a/contrib/python/traitlets/py2/traitlets/config/manager.py b/contrib/python/traitlets/py2/traitlets/config/manager.py
deleted file mode 100644
index 5e5ebde9af3..00000000000
--- a/contrib/python/traitlets/py2/traitlets/config/manager.py
+++ /dev/null
@@ -1,88 +0,0 @@
-"""Manager to read and modify config data in JSON files.
-"""
-# Copyright (c) IPython Development Team.
-# Distributed under the terms of the Modified BSD License.
-import errno
-import io
-import json
-import os
-
-from six import PY3
-from traitlets.config import LoggingConfigurable
-from traitlets.traitlets import Unicode
-
-
-def recursive_update(target, new):
- """Recursively update one dictionary using another.
-
- None values will delete their keys.
- """
- for k, v in new.items():
- if isinstance(v, dict):
- if k not in target:
- target[k] = {}
- recursive_update(target[k], v)
- if not target[k]:
- # Prune empty subdicts
- del target[k]
-
- elif v is None:
- target.pop(k, None)
-
- else:
- target[k] = v
-
-
-class BaseJSONConfigManager(LoggingConfigurable):
- """General JSON config manager
-
- Deals with persisting/storing config in a json file
- """
-
- config_dir = Unicode('.')
-
- def ensure_config_dir_exists(self):
- try:
- os.makedirs(self.config_dir, 0o755)
- except OSError as e:
- if e.errno != errno.EEXIST:
- raise
-
- def file_name(self, section_name):
- return os.path.join(self.config_dir, section_name+'.json')
-
- def get(self, section_name):
- """Retrieve the config data for the specified section.
-
- Returns the data as a dictionary, or an empty dictionary if the file
- doesn't exist.
- """
- filename = self.file_name(section_name)
- if os.path.isfile(filename):
- with io.open(filename, encoding='utf-8') as f:
- return json.load(f)
- else:
- return {}
-
- def set(self, section_name, data):
- """Store the given config data.
- """
- filename = self.file_name(section_name)
- self.ensure_config_dir_exists()
-
- if PY3:
- f = io.open(filename, 'w', encoding='utf-8')
- else:
- f = open(filename, 'wb')
- with f:
- json.dump(data, f, indent=2)
-
- def update(self, section_name, new_data):
- """Modify the config section by recursively updating it with new_data.
-
- Returns the modified config data as a dictionary.
- """
- data = self.get(section_name)
- recursive_update(data, new_data)
- self.set(section_name, data)
- return data
diff --git a/contrib/python/traitlets/py2/traitlets/config/tests/__init__.py b/contrib/python/traitlets/py2/traitlets/config/tests/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/contrib/python/traitlets/py2/traitlets/config/tests/__init__.py
+++ /dev/null
diff --git a/contrib/python/traitlets/py2/traitlets/config/tests/test_application.py b/contrib/python/traitlets/py2/traitlets/config/tests/test_application.py
deleted file mode 100644
index 39bd9b786e8..00000000000
--- a/contrib/python/traitlets/py2/traitlets/config/tests/test_application.py
+++ /dev/null
@@ -1,421 +0,0 @@
-# coding: utf-8
-"""
-Tests for traitlets.config.application.Application
-"""
-
-# Copyright (c) IPython Development Team.
-# Distributed under the terms of the Modified BSD License.
-
-import json
-import logging
-import os
-from io import StringIO
-from unittest import TestCase
-
-try:
- from unittest import mock
-except ImportError:
- import mock
-
-pjoin = os.path.join
-
-from pytest import mark
-
-from traitlets.config.configurable import Configurable
-from traitlets.config.loader import Config
-from traitlets.tests.utils import check_help_output, check_help_all_output
-
-from traitlets.config.application import (
- Application
-)
-
-from ipython_genutils.tempdir import TemporaryDirectory
-from traitlets.traitlets import (
- Bool, Unicode, Integer, List, Dict
-)
-
-
-class Foo(Configurable):
-
- i = Integer(0, help="The integer i.").tag(config=True)
- j = Integer(1, help="The integer j.").tag(config=True)
- name = Unicode(u'Brian', help="First name.").tag(config=True)
-
-
-class Bar(Configurable):
-
- b = Integer(0, help="The integer b.").tag(config=True)
- enabled = Bool(True, help="Enable bar.").tag(config=True)
-
-
-class MyApp(Application):
-
- name = Unicode(u'myapp')
- running = Bool(False, help="Is the app running?").tag(config=True)
- classes = List([Bar, Foo])
- config_file = Unicode(u'', help="Load this config file").tag(config=True)
-
- warn_tpyo = Unicode(u"yes the name is wrong on purpose", config=True,
- help="Should print a warning if `MyApp.warn-typo=...` command is passed")
-
- aliases = Dict({
- 'i' : 'Foo.i',
- 'j' : 'Foo.j',
- 'name' : 'Foo.name',
- 'enabled' : 'Bar.enabled',
- 'log-level' : 'Application.log_level',
- })
-
- flags = Dict(dict(enable=({'Bar': {'enabled' : True}}, "Set Bar.enabled to True"),
- disable=({'Bar': {'enabled' : False}}, "Set Bar.enabled to False"),
- crit=({'Application' : {'log_level' : logging.CRITICAL}},
- "set level=CRITICAL"),
- ))
-
- def init_foo(self):
- self.foo = Foo(parent=self)
-
- def init_bar(self):
- self.bar = Bar(parent=self)
-
-
-class TestApplication(TestCase):
-
- def test_log(self):
- stream = StringIO()
- app = MyApp(log_level=logging.INFO)
- handler = logging.StreamHandler(stream)
- # trigger reconstruction of the log formatter
- app.log.handlers = [handler]
- app.log_format = "%(message)s"
- app.log_datefmt = "%Y-%m-%d %H:%M"
- app.log.info("hello")
- assert "hello" in stream.getvalue()
-
- def test_basic(self):
- app = MyApp()
- self.assertEqual(app.name, u'myapp')
- self.assertEqual(app.running, False)
- self.assertEqual(app.classes, [MyApp,Bar,Foo])
- self.assertEqual(app.config_file, u'')
-
- def test_config(self):
- app = MyApp()
- app.parse_command_line(["--i=10","--Foo.j=10","--enabled=False","--log-level=50"])
- config = app.config
- self.assertEqual(config.Foo.i, 10)
- self.assertEqual(config.Foo.j, 10)
- self.assertEqual(config.Bar.enabled, False)
- self.assertEqual(config.MyApp.log_level,50)
-
- def test_config_propagation(self):
- app = MyApp()
- app.parse_command_line(["--i=10","--Foo.j=10","--enabled=False","--log-level=50"])
- app.init_foo()
- app.init_bar()
- self.assertEqual(app.foo.i, 10)
- self.assertEqual(app.foo.j, 10)
- self.assertEqual(app.bar.enabled, False)
-
- def test_cli_priority(self):
- """Test that loading config files does not override CLI options"""
- name = 'config.py'
- class TestApp(Application):
- value = Unicode().tag(config=True)
- config_file_loaded = Bool().tag(config=True)
- aliases = {'v': 'TestApp.value'}
- app = TestApp()
- with TemporaryDirectory() as td:
- config_file = pjoin(td, name)
- with open(config_file, 'w') as f:
- f.writelines([
- "c.TestApp.value = 'config file'\n",
- "c.TestApp.config_file_loaded = True\n"
- ])
-
- app.parse_command_line(['--v=cli'])
- assert 'value' in app.config.TestApp
- assert app.config.TestApp.value == 'cli'
- assert app.value == 'cli'
-
- app.load_config_file(name, path=[td])
- assert app.config_file_loaded
- assert app.config.TestApp.value == 'cli'
- assert app.value == 'cli'
-
- def test_ipython_cli_priority(self):
- # this test is almost entirely redundant with above,
- # but we can keep it around in case of subtle issues creeping into
- # the exact sequence IPython follows.
- name = 'config.py'
- class TestApp(Application):
- value = Unicode().tag(config=True)
- config_file_loaded = Bool().tag(config=True)
- aliases = {'v': 'TestApp.value'}
- app = TestApp()
- with TemporaryDirectory() as td:
- config_file = pjoin(td, name)
- with open(config_file, 'w') as f:
- f.writelines([
- "c.TestApp.value = 'config file'\n",
- "c.TestApp.config_file_loaded = True\n"
- ])
- # follow IPython's config-loading sequence to ensure CLI priority is preserved
- app.parse_command_line(['--v=cli'])
- # this is where IPython makes a mistake:
- # it assumes app.config will not be modified,
- # and storing a reference is storing a copy
- cli_config = app.config
- assert 'value' in app.config.TestApp
- assert app.config.TestApp.value == 'cli'
- assert app.value == 'cli'
- app.load_config_file(name, path=[td])
- assert app.config_file_loaded
- # enforce cl-opts override config file opts:
- # this is where IPython makes a mistake: it assumes
- # that cl_config is a different object, but it isn't.
- app.update_config(cli_config)
- assert app.config.TestApp.value == 'cli'
- assert app.value == 'cli'
-
- def test_flags(self):
- app = MyApp()
- app.parse_command_line(["--disable"])
- app.init_bar()
- self.assertEqual(app.bar.enabled, False)
- app.parse_command_line(["--enable"])
- app.init_bar()
- self.assertEqual(app.bar.enabled, True)
-
- def test_aliases(self):
- app = MyApp()
- app.parse_command_line(["--i=5", "--j=10"])
- app.init_foo()
- self.assertEqual(app.foo.i, 5)
- app.init_foo()
- self.assertEqual(app.foo.j, 10)
-
- def test_flag_clobber(self):
- """test that setting flags doesn't clobber existing settings"""
- app = MyApp()
- app.parse_command_line(["--Bar.b=5", "--disable"])
- app.init_bar()
- self.assertEqual(app.bar.enabled, False)
- self.assertEqual(app.bar.b, 5)
- app.parse_command_line(["--enable", "--Bar.b=10"])
- app.init_bar()
- self.assertEqual(app.bar.enabled, True)
- self.assertEqual(app.bar.b, 10)
-
- def test_warn_autocorrect(self):
- stream = StringIO()
- app = MyApp(log_level=logging.INFO)
- app.log.handlers = [logging.StreamHandler(stream)]
-
- cfg = Config()
- cfg.MyApp.warn_typo = "WOOOO"
- app.config = cfg
-
- self.assertIn("warn_typo", stream.getvalue())
- self.assertIn("warn_tpyo", stream.getvalue())
-
-
- def test_flatten_flags(self):
- cfg = Config()
- cfg.MyApp.log_level = logging.WARN
- app = MyApp()
- app.update_config(cfg)
- self.assertEqual(app.log_level, logging.WARN)
- self.assertEqual(app.config.MyApp.log_level, logging.WARN)
- app.initialize(["--crit"])
- self.assertEqual(app.log_level, logging.CRITICAL)
- # this would be app.config.Application.log_level if it failed:
- self.assertEqual(app.config.MyApp.log_level, logging.CRITICAL)
-
- def test_flatten_aliases(self):
- cfg = Config()
- cfg.MyApp.log_level = logging.WARN
- app = MyApp()
- app.update_config(cfg)
- self.assertEqual(app.log_level, logging.WARN)
- self.assertEqual(app.config.MyApp.log_level, logging.WARN)
- app.initialize(["--log-level", "CRITICAL"])
- self.assertEqual(app.log_level, logging.CRITICAL)
- # this would be app.config.Application.log_level if it failed:
- self.assertEqual(app.config.MyApp.log_level, "CRITICAL")
-
- def test_extra_args(self):
- app = MyApp()
- app.parse_command_line(["--Bar.b=5", 'extra', "--disable", 'args'])
- app.init_bar()
- self.assertEqual(app.bar.enabled, False)
- self.assertEqual(app.bar.b, 5)
- self.assertEqual(app.extra_args, ['extra', 'args'])
- app = MyApp()
- app.parse_command_line(["--Bar.b=5", '--', 'extra', "--disable", 'args'])
- app.init_bar()
- self.assertEqual(app.bar.enabled, True)
- self.assertEqual(app.bar.b, 5)
- self.assertEqual(app.extra_args, ['extra', '--disable', 'args'])
-
- def test_unicode_argv(self):
- app = MyApp()
- app.parse_command_line(['ünîcødé'])
-
- def test_document_config_option(self):
- app = MyApp()
- app.document_config_options()
-
- def test_generate_config_file(self):
- app = MyApp()
- assert 'The integer b.' in app.generate_config_file()
-
- def test_generate_config_file_classes_to_include(self):
- class NoTraits(Foo, Bar):
- pass
-
- app = MyApp()
- app.classes.append(NoTraits)
- conf_txt = app.generate_config_file()
- self.assertIn('The integer b.', conf_txt)
- self.assertIn('# Bar(Configurable)', conf_txt)
- self.assertIn('# Foo(Configurable)', conf_txt)
- self.assertNotIn('# Configurable', conf_txt)
- self.assertIn('# NoTraits(Foo,Bar)', conf_txt)
-
- def test_multi_file(self):
- app = MyApp()
- app.log = logging.getLogger()
- name = 'config.py'
- with TemporaryDirectory('_1') as td1:
- with open(pjoin(td1, name), 'w') as f1:
- f1.write("get_config().MyApp.Bar.b = 1")
- with TemporaryDirectory('_2') as td2:
- with open(pjoin(td2, name), 'w') as f2:
- f2.write("get_config().MyApp.Bar.b = 2")
- app.load_config_file(name, path=[td2, td1])
- app.init_bar()
- self.assertEqual(app.bar.b, 2)
- app.load_config_file(name, path=[td1, td2])
- app.init_bar()
- self.assertEqual(app.bar.b, 1)
-
- @mark.skipif(not hasattr(TestCase, 'assertLogs'), reason='requires TestCase.assertLogs')
- def test_log_collisions(self):
- app = MyApp()
- app.log = logging.getLogger()
- app.log.setLevel(logging.INFO)
- name = 'config'
- with TemporaryDirectory('_1') as td:
- with open(pjoin(td, name + '.py'), 'w') as f:
- f.write("get_config().Bar.b = 1")
- with open(pjoin(td, name + '.json'), 'w') as f:
- json.dump({
- 'Bar': {
- 'b': 2
- }
- }, f)
- with self.assertLogs(app.log, logging.WARNING) as captured:
- app.load_config_file(name, path=[td])
- app.init_bar()
- assert app.bar.b == 2
- output = '\n'.join(captured.output)
- assert 'Collision' in output
- assert '1 ignored, using 2' in output
- assert pjoin(td, name + '.py') in output
- assert pjoin(td, name + '.json') in output
-
- @mark.skipif(not hasattr(TestCase, 'assertLogs'), reason='requires TestCase.assertLogs')
- def test_log_bad_config(self):
- app = MyApp()
- app.log = logging.getLogger()
- name = 'config.py'
- with TemporaryDirectory() as td:
- with open(pjoin(td, name), 'w') as f:
- f.write("syntax error()")
- with self.assertLogs(app.log, logging.ERROR) as captured:
- app.load_config_file(name, path=[td])
- output = '\n'.join(captured.output)
- self.assertIn('SyntaxError', output)
-
- def test_raise_on_bad_config(self):
- app = MyApp()
- app.raise_config_file_errors = True
- app.log = logging.getLogger()
- name = 'config.py'
- with TemporaryDirectory() as td:
- with open(pjoin(td, name), 'w') as f:
- f.write("syntax error()")
- with self.assertRaises(SyntaxError):
- app.load_config_file(name, path=[td])
-
- def test_loaded_config_files(self):
- app = MyApp()
- app.log = logging.getLogger()
- name = 'config.py'
- with TemporaryDirectory('_1') as td1:
- config_file = pjoin(td1, name)
- with open(config_file, 'w') as f:
- f.writelines([
- "c.MyApp.running = True\n"
- ])
-
- app.load_config_file(name, path=[td1])
- self.assertEqual(len(app.loaded_config_files), 1)
- self.assertEquals(app.loaded_config_files[0], config_file)
-
- app.start()
- self.assertEqual(app.running, True)
-
- # emulate an app that allows dynamic updates and update config file
- with open(config_file, 'w') as f:
- f.writelines([
- "c.MyApp.running = False\n"
- ])
-
- # reload and verify update, and that loaded_configs was not increased
- app.load_config_file(name, path=[td1])
- self.assertEqual(len(app.loaded_config_files), 1)
- self.assertEqual(app.running, False)
-
- # Attempt to update, ensure error...
- with self.assertRaises(AttributeError):
- app.loaded_config_files = "/foo"
-
- # ensure it can't be udpated via append
- app.loaded_config_files.append("/bar")
- self.assertEqual(len(app.loaded_config_files), 1)
-
- # repeat to ensure no unexpected changes occurred
- app.load_config_file(name, path=[td1])
- self.assertEqual(len(app.loaded_config_files), 1)
- self.assertEqual(app.running, False)
-
-
-class DeprecatedApp(Application):
- override_called = False
- parent_called = False
- def _config_changed(self, name, old, new):
- self.override_called = True
- def _capture(*args):
- self.parent_called = True
- with mock.patch.object(self.log, 'debug', _capture):
- super(DeprecatedApp, self)._config_changed(name, old, new)
-
-
-def test_deprecated_notifier():
- app = DeprecatedApp()
- assert not app.override_called
- assert not app.parent_called
- app.config = Config({'A': {'b': 'c'}})
- assert app.override_called
- assert app.parent_called
-
-
-def test_help_output():
- check_help_output(__name__)
- check_help_all_output(__name__)
-
-if __name__ == '__main__':
- # for test_help_output:
- MyApp.launch_instance() \ No newline at end of file
diff --git a/contrib/python/traitlets/py2/traitlets/config/tests/test_configurable.py b/contrib/python/traitlets/py2/traitlets/config/tests/test_configurable.py
deleted file mode 100644
index 9fbdb7209dc..00000000000
--- a/contrib/python/traitlets/py2/traitlets/config/tests/test_configurable.py
+++ /dev/null
@@ -1,459 +0,0 @@
-# encoding: utf-8
-"""Tests for traitlets.config.configurable"""
-
-# Copyright (c) IPython Development Team.
-# Distributed under the terms of the Modified BSD License.
-
-import logging
-from unittest import TestCase
-
-from pytest import mark
-
-from traitlets.config.configurable import (
- Configurable,
- LoggingConfigurable,
- SingletonConfigurable,
-)
-
-from traitlets.traitlets import (
- Integer, Float, Unicode, List, Dict, Set,
- _deprecations_shown,
-)
-
-from traitlets.config.loader import Config
-from six import PY3
-
-from ...tests._warnings import expected_warnings
-
-class MyConfigurable(Configurable):
- a = Integer(1, help="The integer a.").tag(config=True)
- b = Float(1.0, help="The integer b.").tag(config=True)
- c = Unicode('no config')
-
-
-mc_help=u"""MyConfigurable options
-----------------------
---MyConfigurable.a=<Integer>
- Default: 1
- The integer a.
---MyConfigurable.b=<Float>
- Default: 1.0
- The integer b."""
-
-mc_help_inst=u"""MyConfigurable options
-----------------------
---MyConfigurable.a=<Integer>
- Current: 5
- The integer a.
---MyConfigurable.b=<Float>
- Current: 4.0
- The integer b."""
-
-# On Python 3, the Integer trait is a synonym for Int
-if PY3:
- mc_help = mc_help.replace(u"<Integer>", u"<Int>")
- mc_help_inst = mc_help_inst.replace(u"<Integer>", u"<Int>")
-
-class Foo(Configurable):
- a = Integer(0, help="The integer a.").tag(config=True)
- b = Unicode('nope').tag(config=True)
-
-
-class Bar(Foo):
- b = Unicode('gotit', help="The string b.").tag(config=False)
- c = Float(help="The string c.").tag(config=True)
-
-
-class TestConfigurable(TestCase):
-
- def test_default(self):
- c1 = Configurable()
- c2 = Configurable(config=c1.config)
- c3 = Configurable(config=c2.config)
- self.assertEqual(c1.config, c2.config)
- self.assertEqual(c2.config, c3.config)
-
- def test_custom(self):
- config = Config()
- config.foo = 'foo'
- config.bar = 'bar'
- c1 = Configurable(config=config)
- c2 = Configurable(config=c1.config)
- c3 = Configurable(config=c2.config)
- self.assertEqual(c1.config, config)
- self.assertEqual(c2.config, config)
- self.assertEqual(c3.config, config)
- # Test that copies are not made
- self.assertTrue(c1.config is config)
- self.assertTrue(c2.config is config)
- self.assertTrue(c3.config is config)
- self.assertTrue(c1.config is c2.config)
- self.assertTrue(c2.config is c3.config)
-
- def test_inheritance(self):
- config = Config()
- config.MyConfigurable.a = 2
- config.MyConfigurable.b = 2.0
- c1 = MyConfigurable(config=config)
- c2 = MyConfigurable(config=c1.config)
- self.assertEqual(c1.a, config.MyConfigurable.a)
- self.assertEqual(c1.b, config.MyConfigurable.b)
- self.assertEqual(c2.a, config.MyConfigurable.a)
- self.assertEqual(c2.b, config.MyConfigurable.b)
-
- def test_parent(self):
- config = Config()
- config.Foo.a = 10
- config.Foo.b = "wow"
- config.Bar.b = 'later'
- config.Bar.c = 100.0
- f = Foo(config=config)
- with expected_warnings(['`b` not recognized']):
- b = Bar(config=f.config)
- self.assertEqual(f.a, 10)
- self.assertEqual(f.b, 'wow')
- self.assertEqual(b.b, 'gotit')
- self.assertEqual(b.c, 100.0)
-
- def test_override1(self):
- config = Config()
- config.MyConfigurable.a = 2
- config.MyConfigurable.b = 2.0
- c = MyConfigurable(a=3, config=config)
- self.assertEqual(c.a, 3)
- self.assertEqual(c.b, config.MyConfigurable.b)
- self.assertEqual(c.c, 'no config')
-
- def test_override2(self):
- config = Config()
- config.Foo.a = 1
- config.Bar.b = 'or' # Up above b is config=False, so this won't do it.
- config.Bar.c = 10.0
- with expected_warnings(['`b` not recognized']):
- c = Bar(config=config)
- self.assertEqual(c.a, config.Foo.a)
- self.assertEqual(c.b, 'gotit')
- self.assertEqual(c.c, config.Bar.c)
- with expected_warnings(['`b` not recognized']):
- c = Bar(a=2, b='and', c=20.0, config=config)
- self.assertEqual(c.a, 2)
- self.assertEqual(c.b, 'and')
- self.assertEqual(c.c, 20.0)
-
- def test_help(self):
- self.assertEqual(MyConfigurable.class_get_help(), mc_help)
-
- def test_help_inst(self):
- inst = MyConfigurable(a=5, b=4)
- self.assertEqual(MyConfigurable.class_get_help(inst), mc_help_inst)
-
-
-class TestSingletonConfigurable(TestCase):
-
- def test_instance(self):
- class Foo(SingletonConfigurable): pass
- self.assertEqual(Foo.initialized(), False)
- foo = Foo.instance()
- self.assertEqual(Foo.initialized(), True)
- self.assertEqual(foo, Foo.instance())
- self.assertEqual(SingletonConfigurable._instance, None)
-
- def test_inheritance(self):
- class Bar(SingletonConfigurable): pass
- class Bam(Bar): pass
- self.assertEqual(Bar.initialized(), False)
- self.assertEqual(Bam.initialized(), False)
- bam = Bam.instance()
- bam == Bar.instance()
- self.assertEqual(Bar.initialized(), True)
- self.assertEqual(Bam.initialized(), True)
- self.assertEqual(bam, Bam._instance)
- self.assertEqual(bam, Bar._instance)
- self.assertEqual(SingletonConfigurable._instance, None)
-
-
-class MyParent(Configurable):
- pass
-
-class MyParent2(MyParent):
- pass
-
-class TestParentConfigurable(TestCase):
-
- def test_parent_config(self):
- cfg = Config({
- 'MyParent' : {
- 'MyConfigurable' : {
- 'b' : 2.0,
- }
- }
- })
- parent = MyParent(config=cfg)
- myc = MyConfigurable(parent=parent)
- self.assertEqual(myc.b, parent.config.MyParent.MyConfigurable.b)
-
- def test_parent_inheritance(self):
- cfg = Config({
- 'MyParent' : {
- 'MyConfigurable' : {
- 'b' : 2.0,
- }
- }
- })
- parent = MyParent2(config=cfg)
- myc = MyConfigurable(parent=parent)
- self.assertEqual(myc.b, parent.config.MyParent.MyConfigurable.b)
-
- def test_multi_parent(self):
- cfg = Config({
- 'MyParent2' : {
- 'MyParent' : {
- 'MyConfigurable' : {
- 'b' : 2.0,
- }
- },
- # this one shouldn't count
- 'MyConfigurable' : {
- 'b' : 3.0,
- },
- }
- })
- parent2 = MyParent2(config=cfg)
- parent = MyParent(parent=parent2)
- myc = MyConfigurable(parent=parent)
- self.assertEqual(myc.b, parent.config.MyParent2.MyParent.MyConfigurable.b)
-
- def test_parent_priority(self):
- cfg = Config({
- 'MyConfigurable' : {
- 'b' : 2.0,
- },
- 'MyParent' : {
- 'MyConfigurable' : {
- 'b' : 3.0,
- }
- },
- 'MyParent2' : {
- 'MyConfigurable' : {
- 'b' : 4.0,
- }
- }
- })
- parent = MyParent2(config=cfg)
- myc = MyConfigurable(parent=parent)
- self.assertEqual(myc.b, parent.config.MyParent2.MyConfigurable.b)
-
- def test_multi_parent_priority(self):
- cfg = Config({
- 'MyConfigurable' : {
- 'b' : 2.0,
- },
- 'MyParent' : {
- 'MyConfigurable' : {
- 'b' : 3.0,
- }
- },
- 'MyParent2' : {
- 'MyConfigurable' : {
- 'b' : 4.0,
- }
- },
- 'MyParent2' : {
- 'MyParent' : {
- 'MyConfigurable' : {
- 'b' : 5.0,
- }
- }
- }
- })
- parent2 = MyParent2(config=cfg)
- parent = MyParent2(parent=parent2)
- myc = MyConfigurable(parent=parent)
- self.assertEqual(myc.b, parent.config.MyParent2.MyParent.MyConfigurable.b)
-
-class Containers(Configurable):
- lis = List().tag(config=True)
- def _lis_default(self):
- return [-1]
-
- s = Set().tag(config=True)
- def _s_default(self):
- return {'a'}
-
- d = Dict().tag(config=True)
- def _d_default(self):
- return {'a' : 'b'}
-
-class TestConfigContainers(TestCase):
- def test_extend(self):
- c = Config()
- c.Containers.lis.extend(list(range(5)))
- obj = Containers(config=c)
- self.assertEqual(obj.lis, list(range(-1,5)))
-
- def test_insert(self):
- c = Config()
- c.Containers.lis.insert(0, 'a')
- c.Containers.lis.insert(1, 'b')
- obj = Containers(config=c)
- self.assertEqual(obj.lis, ['a', 'b', -1])
-
- def test_prepend(self):
- c = Config()
- c.Containers.lis.prepend([1,2])
- c.Containers.lis.prepend([2,3])
- obj = Containers(config=c)
- self.assertEqual(obj.lis, [2,3,1,2,-1])
-
- def test_prepend_extend(self):
- c = Config()
- c.Containers.lis.prepend([1,2])
- c.Containers.lis.extend([2,3])
- obj = Containers(config=c)
- self.assertEqual(obj.lis, [1,2,-1,2,3])
-
- def test_append_extend(self):
- c = Config()
- c.Containers.lis.append([1,2])
- c.Containers.lis.extend([2,3])
- obj = Containers(config=c)
- self.assertEqual(obj.lis, [-1,[1,2],2,3])
-
- def test_extend_append(self):
- c = Config()
- c.Containers.lis.extend([2,3])
- c.Containers.lis.append([1,2])
- obj = Containers(config=c)
- self.assertEqual(obj.lis, [-1,2,3,[1,2]])
-
- def test_insert_extend(self):
- c = Config()
- c.Containers.lis.insert(0, 1)
- c.Containers.lis.extend([2,3])
- obj = Containers(config=c)
- self.assertEqual(obj.lis, [1,-1,2,3])
-
- def test_set_update(self):
- c = Config()
- c.Containers.s.update({0,1,2})
- c.Containers.s.update({3})
- obj = Containers(config=c)
- self.assertEqual(obj.s, {'a', 0, 1, 2, 3})
-
- def test_dict_update(self):
- c = Config()
- c.Containers.d.update({'c' : 'd'})
- c.Containers.d.update({'e' : 'f'})
- obj = Containers(config=c)
- self.assertEqual(obj.d, {'a':'b', 'c':'d', 'e':'f'})
-
- def test_update_twice(self):
- c = Config()
- c.MyConfigurable.a = 5
- m = MyConfigurable(config=c)
- self.assertEqual(m.a, 5)
-
- c2 = Config()
- c2.MyConfigurable.a = 10
- m.update_config(c2)
- self.assertEqual(m.a, 10)
-
- c2.MyConfigurable.a = 15
- m.update_config(c2)
- self.assertEqual(m.a, 15)
-
- def test_update_self(self):
- """update_config with same config object still triggers config_changed"""
- c = Config()
- c.MyConfigurable.a = 5
- m = MyConfigurable(config=c)
- self.assertEqual(m.a, 5)
- c.MyConfigurable.a = 10
- m.update_config(c)
- self.assertEqual(m.a, 10)
-
- def test_config_default(self):
- class SomeSingleton(SingletonConfigurable):
- pass
-
- class DefaultConfigurable(Configurable):
- a = Integer().tag(config=True)
- def _config_default(self):
- if SomeSingleton.initialized():
- return SomeSingleton.instance().config
- return Config()
-
- c = Config()
- c.DefaultConfigurable.a = 5
-
- d1 = DefaultConfigurable()
- self.assertEqual(d1.a, 0)
-
- single = SomeSingleton.instance(config=c)
-
- d2 = DefaultConfigurable()
- self.assertIs(d2.config, single.config)
- self.assertEqual(d2.a, 5)
-
- def test_config_default_deprecated(self):
- """Make sure configurables work even with the deprecations in traitlets"""
- class SomeSingleton(SingletonConfigurable):
- pass
-
- # reset deprecation limiter
- _deprecations_shown.clear()
- with expected_warnings([]):
- class DefaultConfigurable(Configurable):
- a = Integer(config=True)
- def _config_default(self):
- if SomeSingleton.initialized():
- return SomeSingleton.instance().config
- return Config()
-
- c = Config()
- c.DefaultConfigurable.a = 5
-
- d1 = DefaultConfigurable()
- self.assertEqual(d1.a, 0)
-
- single = SomeSingleton.instance(config=c)
-
- d2 = DefaultConfigurable()
- self.assertIs(d2.config, single.config)
- self.assertEqual(d2.a, 5)
-
-
-class TestLogger(TestCase):
-
- class A(LoggingConfigurable):
- foo = Integer(config=True)
- bar = Integer(config=True)
- baz = Integer(config=True)
-
- @mark.skipif(not hasattr(TestCase, 'assertLogs'), reason='requires TestCase.assertLogs')
- def test_warn_match(self):
- logger = logging.getLogger('test_warn_match')
- cfg = Config({'A': {'bat': 5}})
- with self.assertLogs(logger, logging.WARNING) as captured:
- a = TestLogger.A(config=cfg, log=logger)
-
- output = '\n'.join(captured.output)
- self.assertIn('Did you mean one of: `bar, baz`?', output)
- self.assertIn('Config option `bat` not recognized by `A`.', output)
-
- cfg = Config({'A': {'fool': 5}})
- with self.assertLogs(logger, logging.WARNING) as captured:
- a = TestLogger.A(config=cfg, log=logger)
-
- output = '\n'.join(captured.output)
- self.assertIn('Config option `fool` not recognized by `A`.', output)
- self.assertIn('Did you mean `foo`?', output)
-
- cfg = Config({'A': {'totally_wrong': 5}})
- with self.assertLogs(logger, logging.WARNING) as captured:
- a = TestLogger.A(config=cfg, log=logger)
-
- output = '\n'.join(captured.output)
- self.assertIn('Config option `totally_wrong` not recognized by `A`.', output)
- self.assertNotIn('Did you mean', output)
-
diff --git a/contrib/python/traitlets/py2/traitlets/config/tests/test_loader.py b/contrib/python/traitlets/py2/traitlets/config/tests/test_loader.py
deleted file mode 100644
index 50c8659f3c6..00000000000
--- a/contrib/python/traitlets/py2/traitlets/config/tests/test_loader.py
+++ /dev/null
@@ -1,453 +0,0 @@
-# encoding: utf-8
-"""Tests for traitlets.config.loader"""
-
-# Copyright (c) IPython Development Team.
-# Distributed under the terms of the Modified BSD License.
-
-import copy
-import logging
-import os
-import pickle
-import sys
-from tempfile import mkstemp
-from unittest import TestCase
-
-from pytest import skip
-
-from traitlets.config.loader import (
- Config,
- LazyConfigValue,
- PyFileConfigLoader,
- JSONFileConfigLoader,
- KeyValueConfigLoader,
- ArgParseConfigLoader,
- KVArgParseConfigLoader,
- ConfigError,
-)
-
-
-pyfile = """
-c = get_config()
-c.a=10
-c.b=20
-c.Foo.Bar.value=10
-c.Foo.Bam.value=list(range(10))
-c.D.C.value='hi there'
-"""
-
-json1file = """
-{
- "version": 1,
- "a": 10,
- "b": 20,
- "Foo": {
- "Bam": {
- "value": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
- },
- "Bar": {
- "value": 10
- }
- },
- "D": {
- "C": {
- "value": "hi there"
- }
- }
-}
-"""
-
-# should not load
-json2file = """
-{
- "version": 2
-}
-"""
-
-import logging
-log = logging.getLogger('devnull')
-log.setLevel(0)
-
-class TestFileCL(TestCase):
-
- def _check_conf(self, config):
- self.assertEqual(config.a, 10)
- self.assertEqual(config.b, 20)
- self.assertEqual(config.Foo.Bar.value, 10)
- self.assertEqual(config.Foo.Bam.value, list(range(10)))
- self.assertEqual(config.D.C.value, 'hi there')
-
- def test_python(self):
- fd, fname = mkstemp('.py')
- f = os.fdopen(fd, 'w')
- f.write(pyfile)
- f.close()
- # Unlink the file
- cl = PyFileConfigLoader(fname, log=log)
- config = cl.load_config()
- self._check_conf(config)
-
- def test_json(self):
- fd, fname = mkstemp('.json')
- f = os.fdopen(fd, 'w')
- f.write(json1file)
- f.close()
- # Unlink the file
- cl = JSONFileConfigLoader(fname, log=log)
- config = cl.load_config()
- self._check_conf(config)
-
- def test_context_manager(self):
-
- fd, fname = mkstemp('.json')
- f = os.fdopen(fd, 'w')
- f.write('{}')
- f.close()
-
- cl = JSONFileConfigLoader(fname, log=log)
-
- value = 'context_manager'
-
- with cl as c:
- c.MyAttr.value = value
-
- self.assertEqual(cl.config.MyAttr.value, value)
-
- # check that another loader does see the change
- cl2 = JSONFileConfigLoader(fname, log=log)
- self.assertEqual(cl.config.MyAttr.value, value)
-
- def test_json_context_bad_write(self):
- fd, fname = mkstemp('.json')
- f = os.fdopen(fd, 'w')
- f.write('{}')
- f.close()
-
- with JSONFileConfigLoader(fname, log=log) as config:
- config.A.b = 1
-
- with self.assertRaises(TypeError):
- with JSONFileConfigLoader(fname, log=log) as config:
- config.A.cant_json = lambda x: x
-
- loader = JSONFileConfigLoader(fname, log=log)
- cfg = loader.load_config()
- assert cfg.A.b == 1
- assert 'cant_json' not in cfg.A
-
- def test_collision(self):
- a = Config()
- b = Config()
- self.assertEqual(a.collisions(b), {})
- a.A.trait1 = 1
- b.A.trait2 = 2
- self.assertEqual(a.collisions(b), {})
- b.A.trait1 = 1
- self.assertEqual(a.collisions(b), {})
- b.A.trait1 = 0
- self.assertEqual(a.collisions(b), {
- 'A': {
- 'trait1': "1 ignored, using 0",
- }
- })
- self.assertEqual(b.collisions(a), {
- 'A': {
- 'trait1': "0 ignored, using 1",
- }
- })
- a.A.trait2 = 3
- self.assertEqual(b.collisions(a), {
- 'A': {
- 'trait1': "0 ignored, using 1",
- 'trait2': "2 ignored, using 3",
- }
- })
-
- def test_v2raise(self):
- fd, fname = mkstemp('.json')
- f = os.fdopen(fd, 'w')
- f.write(json2file)
- f.close()
- # Unlink the file
- cl = JSONFileConfigLoader(fname, log=log)
- with self.assertRaises(ValueError):
- cl.load_config()
-
-
-class MyLoader1(ArgParseConfigLoader):
- def _add_arguments(self, aliases=None, flags=None):
- p = self.parser
- p.add_argument('-f', '--foo', dest='Global.foo', type=str)
- p.add_argument('-b', dest='MyClass.bar', type=int)
- p.add_argument('-n', dest='n', action='store_true')
- p.add_argument('Global.bam', type=str)
-
-class MyLoader2(ArgParseConfigLoader):
- def _add_arguments(self, aliases=None, flags=None):
- subparsers = self.parser.add_subparsers(dest='subparser_name')
- subparser1 = subparsers.add_parser('1')
- subparser1.add_argument('-x',dest='Global.x')
- subparser2 = subparsers.add_parser('2')
- subparser2.add_argument('y')
-
-class TestArgParseCL(TestCase):
-
- def test_basic(self):
- cl = MyLoader1()
- config = cl.load_config('-f hi -b 10 -n wow'.split())
- self.assertEqual(config.Global.foo, 'hi')
- self.assertEqual(config.MyClass.bar, 10)
- self.assertEqual(config.n, True)
- self.assertEqual(config.Global.bam, 'wow')
- config = cl.load_config(['wow'])
- self.assertEqual(list(config.keys()), ['Global'])
- self.assertEqual(list(config.Global.keys()), ['bam'])
- self.assertEqual(config.Global.bam, 'wow')
-
- def test_add_arguments(self):
- cl = MyLoader2()
- config = cl.load_config('2 frobble'.split())
- self.assertEqual(config.subparser_name, '2')
- self.assertEqual(config.y, 'frobble')
- config = cl.load_config('1 -x frobble'.split())
- self.assertEqual(config.subparser_name, '1')
- self.assertEqual(config.Global.x, 'frobble')
-
- def test_argv(self):
- cl = MyLoader1(argv='-f hi -b 10 -n wow'.split())
- config = cl.load_config()
- self.assertEqual(config.Global.foo, 'hi')
- self.assertEqual(config.MyClass.bar, 10)
- self.assertEqual(config.n, True)
- self.assertEqual(config.Global.bam, 'wow')
-
-
-class TestKeyValueCL(TestCase):
- klass = KeyValueConfigLoader
-
- def test_eval(self):
- cl = self.klass(log=log)
- config = cl.load_config('--Class.str_trait=all --Class.int_trait=5 --Class.list_trait=["hello",5]'.split())
- self.assertEqual(config.Class.str_trait, 'all')
- self.assertEqual(config.Class.int_trait, 5)
- self.assertEqual(config.Class.list_trait, ["hello", 5])
-
- def test_basic(self):
- cl = self.klass(log=log)
- argv = [ '--' + s[2:] for s in pyfile.split('\n') if s.startswith('c.') ]
- print(argv)
- config = cl.load_config(argv)
- self.assertEqual(config.a, 10)
- self.assertEqual(config.b, 20)
- self.assertEqual(config.Foo.Bar.value, 10)
- # non-literal expressions are not evaluated
- self.assertEqual(config.Foo.Bam.value, 'list(range(10))')
- self.assertEqual(config.D.C.value, 'hi there')
-
- def test_expanduser(self):
- cl = self.klass(log=log)
- argv = ['--a=~/1/2/3', '--b=~', '--c=~/', '--d="~/"']
- config = cl.load_config(argv)
- self.assertEqual(config.a, os.path.expanduser('~/1/2/3'))
- self.assertEqual(config.b, os.path.expanduser('~'))
- self.assertEqual(config.c, os.path.expanduser('~/'))
- self.assertEqual(config.d, '~/')
-
- def test_extra_args(self):
- cl = self.klass(log=log)
- config = cl.load_config(['--a=5', 'b', '--c=10', 'd'])
- self.assertEqual(cl.extra_args, ['b', 'd'])
- self.assertEqual(config.a, 5)
- self.assertEqual(config.c, 10)
- config = cl.load_config(['--', '--a=5', '--c=10'])
- self.assertEqual(cl.extra_args, ['--a=5', '--c=10'])
-
- def test_unicode_args(self):
- cl = self.klass(log=log)
- argv = [u'--a=épsîlön']
- config = cl.load_config(argv)
- self.assertEqual(config.a, u'épsîlön')
-
- def test_unicode_bytes_args(self):
- uarg = u'--a=é'
- try:
- barg = uarg.encode(sys.stdin.encoding)
- except (TypeError, UnicodeEncodeError):
- raise skip("sys.stdin.encoding can't handle 'é'")
-
- cl = self.klass(log=log)
- config = cl.load_config([barg])
- self.assertEqual(config.a, u'é')
-
- def test_unicode_alias(self):
- cl = self.klass(log=log)
- argv = [u'--a=épsîlön']
- config = cl.load_config(argv, aliases=dict(a='A.a'))
- self.assertEqual(config.A.a, u'épsîlön')
-
-
-class TestArgParseKVCL(TestKeyValueCL):
- klass = KVArgParseConfigLoader
-
- def test_expanduser2(self):
- cl = self.klass(log=log)
- argv = ['-a', '~/1/2/3', '--b', "'~/1/2/3'"]
- config = cl.load_config(argv, aliases=dict(a='A.a', b='A.b'))
- self.assertEqual(config.A.a, os.path.expanduser('~/1/2/3'))
- self.assertEqual(config.A.b, '~/1/2/3')
-
- def test_eval(self):
- cl = self.klass(log=log)
- argv = ['-c', 'a=5']
- config = cl.load_config(argv, aliases=dict(c='A.c'))
- self.assertEqual(config.A.c, u"a=5")
-
-
-class TestConfig(TestCase):
-
- def test_setget(self):
- c = Config()
- c.a = 10
- self.assertEqual(c.a, 10)
- self.assertEqual('b' in c, False)
-
- def test_auto_section(self):
- c = Config()
- self.assertNotIn('A', c)
- assert not c._has_section('A')
- A = c.A
- A.foo = 'hi there'
- self.assertIn('A', c)
- assert c._has_section('A')
- self.assertEqual(c.A.foo, 'hi there')
- del c.A
- self.assertEqual(c.A, Config())
-
- def test_merge_doesnt_exist(self):
- c1 = Config()
- c2 = Config()
- c2.bar = 10
- c2.Foo.bar = 10
- c1.merge(c2)
- self.assertEqual(c1.Foo.bar, 10)
- self.assertEqual(c1.bar, 10)
- c2.Bar.bar = 10
- c1.merge(c2)
- self.assertEqual(c1.Bar.bar, 10)
-
- def test_merge_exists(self):
- c1 = Config()
- c2 = Config()
- c1.Foo.bar = 10
- c1.Foo.bam = 30
- c2.Foo.bar = 20
- c2.Foo.wow = 40
- c1.merge(c2)
- self.assertEqual(c1.Foo.bam, 30)
- self.assertEqual(c1.Foo.bar, 20)
- self.assertEqual(c1.Foo.wow, 40)
- c2.Foo.Bam.bam = 10
- c1.merge(c2)
- self.assertEqual(c1.Foo.Bam.bam, 10)
-
- def test_deepcopy(self):
- c1 = Config()
- c1.Foo.bar = 10
- c1.Foo.bam = 30
- c1.a = 'asdf'
- c1.b = range(10)
- c1.Test.logger = logging.Logger('test')
- c1.Test.get_logger = logging.getLogger('test')
- c2 = copy.deepcopy(c1)
- self.assertEqual(c1, c2)
- self.assertTrue(c1 is not c2)
- self.assertTrue(c1.Foo is not c2.Foo)
- self.assertTrue(c1.Test is not c2.Test)
- self.assertTrue(c1.Test.logger is c2.Test.logger)
- self.assertTrue(c1.Test.get_logger is c2.Test.get_logger)
-
- def test_builtin(self):
- c1 = Config()
- c1.format = "json"
-
- def test_fromdict(self):
- c1 = Config({'Foo' : {'bar' : 1}})
- self.assertEqual(c1.Foo.__class__, Config)
- self.assertEqual(c1.Foo.bar, 1)
-
- def test_fromdictmerge(self):
- c1 = Config()
- c2 = Config({'Foo' : {'bar' : 1}})
- c1.merge(c2)
- self.assertEqual(c1.Foo.__class__, Config)
- self.assertEqual(c1.Foo.bar, 1)
-
- def test_fromdictmerge2(self):
- c1 = Config({'Foo' : {'baz' : 2}})
- c2 = Config({'Foo' : {'bar' : 1}})
- c1.merge(c2)
- self.assertEqual(c1.Foo.__class__, Config)
- self.assertEqual(c1.Foo.bar, 1)
- self.assertEqual(c1.Foo.baz, 2)
- self.assertNotIn('baz', c2.Foo)
-
- def test_contains(self):
- c1 = Config({'Foo' : {'baz' : 2}})
- c2 = Config({'Foo' : {'bar' : 1}})
- self.assertIn('Foo', c1)
- self.assertIn('Foo.baz', c1)
- self.assertIn('Foo.bar', c2)
- self.assertNotIn('Foo.bar', c1)
-
- def test_pickle_config(self):
- cfg = Config()
- cfg.Foo.bar = 1
- pcfg = pickle.dumps(cfg)
- cfg2 = pickle.loads(pcfg)
- self.assertEqual(cfg2, cfg)
-
- def test_getattr_section(self):
- cfg = Config()
- self.assertNotIn('Foo', cfg)
- Foo = cfg.Foo
- assert isinstance(Foo, Config)
- self.assertIn('Foo', cfg)
-
- def test_getitem_section(self):
- cfg = Config()
- self.assertNotIn('Foo', cfg)
- Foo = cfg['Foo']
- assert isinstance(Foo, Config)
- self.assertIn('Foo', cfg)
-
- def test_getattr_not_section(self):
- cfg = Config()
- self.assertNotIn('foo', cfg)
- foo = cfg.foo
- assert isinstance(foo, LazyConfigValue)
- self.assertIn('foo', cfg)
-
- def test_getattr_private_missing(self):
- cfg = Config()
- self.assertNotIn('_repr_html_', cfg)
- with self.assertRaises(AttributeError):
- _ = cfg._repr_html_
- self.assertNotIn('_repr_html_', cfg)
- self.assertEqual(len(cfg), 0)
-
- def test_getitem_not_section(self):
- cfg = Config()
- self.assertNotIn('foo', cfg)
- foo = cfg['foo']
- assert isinstance(foo, LazyConfigValue)
- self.assertIn('foo', cfg)
-
- def test_merge_no_copies(self):
- c = Config()
- c2 = Config()
- c2.Foo.trait = []
- c.merge(c2)
- c2.Foo.trait.append(1)
- self.assertIs(c.Foo, c2.Foo)
- self.assertEqual(c.Foo.trait, [1])
- self.assertEqual(c2.Foo.trait, [1])
-
diff --git a/contrib/python/traitlets/py2/traitlets/log.py b/contrib/python/traitlets/py2/traitlets/log.py
deleted file mode 100644
index af86b325f51..00000000000
--- a/contrib/python/traitlets/py2/traitlets/log.py
+++ /dev/null
@@ -1,27 +0,0 @@
-"""Grab the global logger instance."""
-
-# Copyright (c) IPython Development Team.
-# Distributed under the terms of the Modified BSD License.
-
-import logging
-
-_logger = None
-
-def get_logger():
- """Grab the global logger instance.
-
- If a global Application is instantiated, grab its logger.
- Otherwise, grab the root logger.
- """
- global _logger
-
- if _logger is None:
- from .config import Application
- if Application.initialized():
- _logger = Application.instance().log
- else:
- _logger = logging.getLogger('traitlets')
- # Add a NullHandler to silence warnings about not being
- # initialized, per best practice for libraries.
- _logger.addHandler(logging.NullHandler())
- return _logger
diff --git a/contrib/python/traitlets/py2/traitlets/tests/__init__.py b/contrib/python/traitlets/py2/traitlets/tests/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/contrib/python/traitlets/py2/traitlets/tests/__init__.py
+++ /dev/null
diff --git a/contrib/python/traitlets/py2/traitlets/tests/_warnings.py b/contrib/python/traitlets/py2/traitlets/tests/_warnings.py
deleted file mode 100644
index f135d1f67ee..00000000000
--- a/contrib/python/traitlets/py2/traitlets/tests/_warnings.py
+++ /dev/null
@@ -1,107 +0,0 @@
-# From scikit-image: https://github.com/scikit-image/scikit-image/blob/c2f8c4ab123ebe5f7b827bc495625a32bb225c10/skimage/_shared/_warnings.py
-# Licensed under modified BSD license
-
-__all__ = ['all_warnings', 'expected_warnings']
-
-from contextlib import contextmanager
-import sys
-import warnings
-import inspect
-import re
-
-
-@contextmanager
-def all_warnings():
- """
- Context for use in testing to ensure that all warnings are raised.
- Examples
- --------
- >>> import warnings
- >>> def foo():
- ... warnings.warn(RuntimeWarning("bar"))
- We raise the warning once, while the warning filter is set to "once".
- Hereafter, the warning is invisible, even with custom filters:
- >>> with warnings.catch_warnings():
- ... warnings.simplefilter('once')
- ... foo()
- We can now run ``foo()`` without a warning being raised:
- >>> from numpy.testing import assert_warns
- >>> foo()
- To catch the warning, we call in the help of ``all_warnings``:
- >>> with all_warnings():
- ... assert_warns(RuntimeWarning, foo)
- """
-
- # Whenever a warning is triggered, Python adds a __warningregistry__
- # member to the *calling* module. The exercize here is to find
- # and eradicate all those breadcrumbs that were left lying around.
- #
- # We proceed by first searching all parent calling frames and explicitly
- # clearing their warning registries (necessary for the doctests above to
- # pass). Then, we search for all submodules of skimage and clear theirs
- # as well (necessary for the skimage test suite to pass).
-
- frame = inspect.currentframe()
- if frame:
- for f in inspect.getouterframes(frame):
- f[0].f_locals['__warningregistry__'] = {}
- del frame
-
- for mod_name, mod in list(sys.modules.items()):
- if 'six.moves' in mod_name:
- continue
- try:
- mod.__warningregistry__.clear()
- except AttributeError:
- pass
-
- with warnings.catch_warnings(record=True) as w:
- warnings.simplefilter("always")
- yield w
-
-
-@contextmanager
-def expected_warnings(matching):
- """Context for use in testing to catch known warnings matching regexes
-
- Parameters
- ----------
- matching : list of strings or compiled regexes
- Regexes for the desired warning to catch
- Examples
- --------
- >>> from skimage import data, img_as_ubyte, img_as_float
- >>> with expected_warnings(['precision loss']):
- ... d = img_as_ubyte(img_as_float(data.coins()))
- Notes
- -----
- Uses `all_warnings` to ensure all warnings are raised.
- Upon exiting, it checks the recorded warnings for the desired matching
- pattern(s).
- Raises a ValueError if any match was not found or an unexpected
- warning was raised.
- Allows for three types of behaviors: "and", "or", and "optional" matches.
- This is done to accomodate different build enviroments or loop conditions
- that may produce different warnings. The behaviors can be combined.
- If you pass multiple patterns, you get an orderless "and", where all of the
- warnings must be raised.
- If you use the "|" operator in a pattern, you can catch one of several warnings.
- Finally, you can use "|\A\Z" in a pattern to signify it as optional.
- """
- with all_warnings() as w:
- # enter context
- yield w
- # exited user context, check the recorded warnings
- remaining = [m for m in matching if not '\A\Z' in m.split('|')]
- for warn in w:
- found = False
- for match in matching:
- if re.search(match, str(warn.message)) is not None:
- found = True
- if match in remaining:
- remaining.remove(match)
- if not found:
- raise ValueError('Unexpected warning: %s' % str(warn.message))
- if len(remaining) > 0:
- msg = 'No warning raised matching:\n%s' % '\n'.join(remaining)
- raise ValueError(msg)
diff --git a/contrib/python/traitlets/py2/traitlets/tests/test_traitlets.py b/contrib/python/traitlets/py2/traitlets/tests/test_traitlets.py
deleted file mode 100644
index 11b334cb60a..00000000000
--- a/contrib/python/traitlets/py2/traitlets/tests/test_traitlets.py
+++ /dev/null
@@ -1,2419 +0,0 @@
-# encoding: utf-8
-"""Tests for traitlets.traitlets."""
-
-# Copyright (c) IPython Development Team.
-# Distributed under the terms of the Modified BSD License.
-#
-# Adapted from enthought.traits, Copyright (c) Enthought, Inc.,
-# also under the terms of the Modified BSD License.
-
-import pickle
-import re
-import sys
-from ._warnings import expected_warnings
-
-from unittest import TestCase
-import pytest
-from pytest import mark
-
-from traitlets import (
- HasTraits, MetaHasTraits, TraitType, Any, Bool, CBytes, Dict, Enum,
- Int, CInt, Long, CLong, Integer, Float, CFloat, Complex, Bytes, Unicode,
- TraitError, Union, All, Undefined, Type, This, Instance, TCPAddress,
- List, Tuple, ObjectName, DottedObjectName, CRegExp, link, directional_link,
- ForwardDeclaredType, ForwardDeclaredInstance, validate, observe, default,
- observe_compat, BaseDescriptor, HasDescriptors,
-)
-
-import six
-
-def change_dict(*ordered_values):
- change_names = ('name', 'old', 'new', 'owner', 'type')
- return dict(zip(change_names, ordered_values))
-
-#-----------------------------------------------------------------------------
-# Helper classes for testing
-#-----------------------------------------------------------------------------
-
-
-class HasTraitsStub(HasTraits):
-
- def notify_change(self, change):
- self._notify_name = change['name']
- self._notify_old = change['old']
- self._notify_new = change['new']
- self._notify_type = change['type']
-
-
-#-----------------------------------------------------------------------------
-# Test classes
-#-----------------------------------------------------------------------------
-
-
-class TestTraitType(TestCase):
-
- def test_get_undefined(self):
- class A(HasTraits):
- a = TraitType
- a = A()
- with self.assertRaises(TraitError):
- a.a
-
- def test_set(self):
- class A(HasTraitsStub):
- a = TraitType
-
- a = A()
- a.a = 10
- self.assertEqual(a.a, 10)
- self.assertEqual(a._notify_name, 'a')
- self.assertEqual(a._notify_old, Undefined)
- self.assertEqual(a._notify_new, 10)
-
- def test_validate(self):
- class MyTT(TraitType):
- def validate(self, inst, value):
- return -1
- class A(HasTraitsStub):
- tt = MyTT
-
- a = A()
- a.tt = 10
- self.assertEqual(a.tt, -1)
-
- def test_default_validate(self):
- class MyIntTT(TraitType):
- def validate(self, obj, value):
- if isinstance(value, int):
- return value
- self.error(obj, value)
- class A(HasTraits):
- tt = MyIntTT(10)
- a = A()
- self.assertEqual(a.tt, 10)
-
- # Defaults are validated when the HasTraits is instantiated
- class B(HasTraits):
- tt = MyIntTT('bad default')
- self.assertRaises(TraitError, B)
-
- def test_info(self):
- class A(HasTraits):
- tt = TraitType
- a = A()
- self.assertEqual(A.tt.info(), 'any value')
-
- def test_error(self):
- class A(HasTraits):
- tt = TraitType
- a = A()
- self.assertRaises(TraitError, A.tt.error, a, 10)
-
- def test_deprecated_dynamic_initializer(self):
- class A(HasTraits):
- x = Int(10)
- def _x_default(self):
- return 11
- class B(A):
- x = Int(20)
- class C(A):
- def _x_default(self):
- return 21
-
- a = A()
- self.assertEqual(a._trait_values, {})
- self.assertEqual(a.x, 11)
- self.assertEqual(a._trait_values, {'x': 11})
- b = B()
- self.assertEqual(b.x, 20)
- self.assertEqual(b._trait_values, {'x': 20})
- c = C()
- self.assertEqual(c._trait_values, {})
- self.assertEqual(c.x, 21)
- self.assertEqual(c._trait_values, {'x': 21})
- # Ensure that the base class remains unmolested when the _default
- # initializer gets overridden in a subclass.
- a = A()
- c = C()
- self.assertEqual(a._trait_values, {})
- self.assertEqual(a.x, 11)
- self.assertEqual(a._trait_values, {'x': 11})
-
- def test_dynamic_initializer(self):
-
- class A(HasTraits):
- x = Int(10)
-
- @default('x')
- def _default_x(self):
- return 11
-
- class B(A):
- x = Int(20)
-
- class C(A):
-
- @default('x')
- def _default_x(self):
- return 21
-
- a = A()
- self.assertEqual(a._trait_values, {})
- self.assertEqual(a.x, 11)
- self.assertEqual(a._trait_values, {'x': 11})
- b = B()
- self.assertEqual(b.x, 20)
- self.assertEqual(b._trait_values, {'x': 20})
- c = C()
- self.assertEqual(c._trait_values, {})
- self.assertEqual(c.x, 21)
- self.assertEqual(c._trait_values, {'x': 21})
- # Ensure that the base class remains unmolested when the _default
- # initializer gets overridden in a subclass.
- a = A()
- c = C()
- self.assertEqual(a._trait_values, {})
- self.assertEqual(a.x, 11)
- self.assertEqual(a._trait_values, {'x': 11})
-
- def test_tag_metadata(self):
- class MyIntTT(TraitType):
- metadata = {'a': 1, 'b': 2}
- a = MyIntTT(10).tag(b=3, c=4)
- self.assertEqual(a.metadata, {'a': 1, 'b': 3, 'c': 4})
-
- def test_metadata_localized_instance(self):
- class MyIntTT(TraitType):
- metadata = {'a': 1, 'b': 2}
- a = MyIntTT(10)
- b = MyIntTT(10)
- a.metadata['c'] = 3
- # make sure that changing a's metadata didn't change b's metadata
- self.assertNotIn('c', b.metadata)
-
- def test_union_metadata(self):
- class Foo(HasTraits):
- bar = (Int().tag(ta=1) | Dict().tag(ta=2, ti='b')).tag(ti='a')
- foo = Foo()
- # At this point, no value has been set for bar, so value-specific
- # is not set.
- self.assertEqual(foo.trait_metadata('bar', 'ta'), None)
- self.assertEqual(foo.trait_metadata('bar', 'ti'), 'a')
- foo.bar = {}
- self.assertEqual(foo.trait_metadata('bar', 'ta'), 2)
- self.assertEqual(foo.trait_metadata('bar', 'ti'), 'b')
- foo.bar = 1
- self.assertEqual(foo.trait_metadata('bar', 'ta'), 1)
- self.assertEqual(foo.trait_metadata('bar', 'ti'), 'a')
-
- def test_union_default_value(self):
- class Foo(HasTraits):
- bar = Union([Dict(), Int()], default_value=1)
- foo = Foo()
- self.assertEqual(foo.bar, 1)
-
- def test_deprecated_metadata_access(self):
- class MyIntTT(TraitType):
- metadata = {'a': 1, 'b': 2}
- a = MyIntTT(10)
- with expected_warnings(["use the instance .metadata dictionary directly"]*2):
- a.set_metadata('key', 'value')
- v = a.get_metadata('key')
- self.assertEqual(v, 'value')
- with expected_warnings(["use the instance .help string directly"]*2):
- a.set_metadata('help', 'some help')
- v = a.get_metadata('help')
- self.assertEqual(v, 'some help')
-
- def test_trait_types_deprecated(self):
- with expected_warnings(["Traits should be given as instances"]):
- class C(HasTraits):
- t = Int
-
- def test_trait_types_list_deprecated(self):
- with expected_warnings(["Traits should be given as instances"]):
- class C(HasTraits):
- t = List(Int)
-
- def test_trait_types_tuple_deprecated(self):
- with expected_warnings(["Traits should be given as instances"]):
- class C(HasTraits):
- t = Tuple(Int)
-
- def test_trait_types_dict_deprecated(self):
- with expected_warnings(["Traits should be given as instances"]):
- class C(HasTraits):
- t = Dict(Int)
-
-class TestHasDescriptorsMeta(TestCase):
-
- def test_metaclass(self):
- self.assertEqual(type(HasTraits), MetaHasTraits)
-
- class A(HasTraits):
- a = Int()
-
- a = A()
- self.assertEqual(type(a.__class__), MetaHasTraits)
- self.assertEqual(a.a,0)
- a.a = 10
- self.assertEqual(a.a,10)
-
- class B(HasTraits):
- b = Int()
-
- b = B()
- self.assertEqual(b.b,0)
- b.b = 10
- self.assertEqual(b.b,10)
-
- class C(HasTraits):
- c = Int(30)
-
- c = C()
- self.assertEqual(c.c,30)
- c.c = 10
- self.assertEqual(c.c,10)
-
- def test_this_class(self):
- class A(HasTraits):
- t = This()
- tt = This()
- class B(A):
- tt = This()
- ttt = This()
- self.assertEqual(A.t.this_class, A)
- self.assertEqual(B.t.this_class, A)
- self.assertEqual(B.tt.this_class, B)
- self.assertEqual(B.ttt.this_class, B)
-
-class TestHasDescriptors(TestCase):
-
- def test_setup_instance(self):
-
- class FooDescriptor(BaseDescriptor):
-
- def instance_init(self, inst):
- foo = inst.foo # instance should have the attr
-
- class HasFooDescriptors(HasDescriptors):
-
- fd = FooDescriptor()
-
- def setup_instance(self, *args, **kwargs):
- self.foo = kwargs.get('foo', None)
- super(HasFooDescriptors, self).setup_instance(*args, **kwargs)
-
- hfd = HasFooDescriptors(foo='bar')
-
-class TestHasTraitsNotify(TestCase):
-
- def setUp(self):
- self._notify1 = []
- self._notify2 = []
-
- def notify1(self, name, old, new):
- self._notify1.append((name, old, new))
-
- def notify2(self, name, old, new):
- self._notify2.append((name, old, new))
-
- def test_notify_all(self):
-
- class A(HasTraits):
- a = Int()
- b = Float()
-
- a = A()
- a.on_trait_change(self.notify1)
- a.a = 0
- self.assertEqual(len(self._notify1),0)
- a.b = 0.0
- self.assertEqual(len(self._notify1),0)
- a.a = 10
- self.assertTrue(('a',0,10) in self._notify1)
- a.b = 10.0
- self.assertTrue(('b',0.0,10.0) in self._notify1)
- self.assertRaises(TraitError,setattr,a,'a','bad string')
- self.assertRaises(TraitError,setattr,a,'b','bad string')
- self._notify1 = []
- a.on_trait_change(self.notify1,remove=True)
- a.a = 20
- a.b = 20.0
- self.assertEqual(len(self._notify1),0)
-
- def test_notify_one(self):
-
- class A(HasTraits):
- a = Int()
- b = Float()
-
- a = A()
- a.on_trait_change(self.notify1, 'a')
- a.a = 0
- self.assertEqual(len(self._notify1),0)
- a.a = 10
- self.assertTrue(('a',0,10) in self._notify1)
- self.assertRaises(TraitError,setattr,a,'a','bad string')
-
- def test_subclass(self):
-
- class A(HasTraits):
- a = Int()
-
- class B(A):
- b = Float()
-
- b = B()
- self.assertEqual(b.a,0)
- self.assertEqual(b.b,0.0)
- b.a = 100
- b.b = 100.0
- self.assertEqual(b.a,100)
- self.assertEqual(b.b,100.0)
-
- def test_notify_subclass(self):
-
- class A(HasTraits):
- a = Int()
-
- class B(A):
- b = Float()
-
- b = B()
- b.on_trait_change(self.notify1, 'a')
- b.on_trait_change(self.notify2, 'b')
- b.a = 0
- b.b = 0.0
- self.assertEqual(len(self._notify1),0)
- self.assertEqual(len(self._notify2),0)
- b.a = 10
- b.b = 10.0
- self.assertTrue(('a',0,10) in self._notify1)
- self.assertTrue(('b',0.0,10.0) in self._notify2)
-
- def test_static_notify(self):
-
- class A(HasTraits):
- a = Int()
- _notify1 = []
- def _a_changed(self, name, old, new):
- self._notify1.append((name, old, new))
-
- a = A()
- a.a = 0
- # This is broken!!!
- self.assertEqual(len(a._notify1),0)
- a.a = 10
- self.assertTrue(('a',0,10) in a._notify1)
-
- class B(A):
- b = Float()
- _notify2 = []
- def _b_changed(self, name, old, new):
- self._notify2.append((name, old, new))
-
- b = B()
- b.a = 10
- b.b = 10.0
- self.assertTrue(('a',0,10) in b._notify1)
- self.assertTrue(('b',0.0,10.0) in b._notify2)
-
- def test_notify_args(self):
-
- def callback0():
- self.cb = ()
- def callback1(name):
- self.cb = (name,)
- def callback2(name, new):
- self.cb = (name, new)
- def callback3(name, old, new):
- self.cb = (name, old, new)
- def callback4(name, old, new, obj):
- self.cb = (name, old, new, obj)
-
- class A(HasTraits):
- a = Int()
-
- a = A()
- a.on_trait_change(callback0, 'a')
- a.a = 10
- self.assertEqual(self.cb,())
- a.on_trait_change(callback0, 'a', remove=True)
-
- a.on_trait_change(callback1, 'a')
- a.a = 100
- self.assertEqual(self.cb,('a',))
- a.on_trait_change(callback1, 'a', remove=True)
-
- a.on_trait_change(callback2, 'a')
- a.a = 1000
- self.assertEqual(self.cb,('a',1000))
- a.on_trait_change(callback2, 'a', remove=True)
-
- a.on_trait_change(callback3, 'a')
- a.a = 10000
- self.assertEqual(self.cb,('a',1000,10000))
- a.on_trait_change(callback3, 'a', remove=True)
-
- a.on_trait_change(callback4, 'a')
- a.a = 100000
- self.assertEqual(self.cb,('a',10000,100000,a))
- self.assertEqual(len(a._trait_notifiers['a']['change']), 1)
- a.on_trait_change(callback4, 'a', remove=True)
-
- self.assertEqual(len(a._trait_notifiers['a']['change']), 0)
-
- def test_notify_only_once(self):
-
- class A(HasTraits):
- listen_to = ['a']
-
- a = Int(0)
- b = 0
-
- def __init__(self, **kwargs):
- super(A, self).__init__(**kwargs)
- self.on_trait_change(self.listener1, ['a'])
-
- def listener1(self, name, old, new):
- self.b += 1
-
- class B(A):
-
- c = 0
- d = 0
-
- def __init__(self, **kwargs):
- super(B, self).__init__(**kwargs)
- self.on_trait_change(self.listener2)
-
- def listener2(self, name, old, new):
- self.c += 1
-
- def _a_changed(self, name, old, new):
- self.d += 1
-
- b = B()
- b.a += 1
- self.assertEqual(b.b, b.c)
- self.assertEqual(b.b, b.d)
- b.a += 1
- self.assertEqual(b.b, b.c)
- self.assertEqual(b.b, b.d)
-
-class TestObserveDecorator(TestCase):
-
- def setUp(self):
- self._notify1 = []
- self._notify2 = []
-
- def notify1(self, change):
- self._notify1.append(change)
-
- def notify2(self, change):
- self._notify2.append(change)
-
- def test_notify_all(self):
-
- class A(HasTraits):
- a = Int()
- b = Float()
-
- a = A()
- a.observe(self.notify1)
- a.a = 0
- self.assertEqual(len(self._notify1),0)
- a.b = 0.0
- self.assertEqual(len(self._notify1),0)
- a.a = 10
- change = change_dict('a', 0, 10, a, 'change')
- self.assertTrue(change in self._notify1)
- a.b = 10.0
- change = change_dict('b', 0.0, 10.0, a, 'change')
- self.assertTrue(change in self._notify1)
- self.assertRaises(TraitError,setattr,a,'a','bad string')
- self.assertRaises(TraitError,setattr,a,'b','bad string')
- self._notify1 = []
- a.unobserve(self.notify1)
- a.a = 20
- a.b = 20.0
- self.assertEqual(len(self._notify1),0)
-
- def test_notify_one(self):
-
- class A(HasTraits):
- a = Int()
- b = Float()
-
- a = A()
- a.observe(self.notify1, 'a')
- a.a = 0
- self.assertEqual(len(self._notify1),0)
- a.a = 10
- change = change_dict('a', 0, 10, a, 'change')
- self.assertTrue(change in self._notify1)
- self.assertRaises(TraitError,setattr,a,'a','bad string')
-
- def test_subclass(self):
-
- class A(HasTraits):
- a = Int()
-
- class B(A):
- b = Float()
-
- b = B()
- self.assertEqual(b.a,0)
- self.assertEqual(b.b,0.0)
- b.a = 100
- b.b = 100.0
- self.assertEqual(b.a,100)
- self.assertEqual(b.b,100.0)
-
- def test_notify_subclass(self):
-
- class A(HasTraits):
- a = Int()
-
- class B(A):
- b = Float()
-
- b = B()
- b.observe(self.notify1, 'a')
- b.observe(self.notify2, 'b')
- b.a = 0
- b.b = 0.0
- self.assertEqual(len(self._notify1),0)
- self.assertEqual(len(self._notify2),0)
- b.a = 10
- b.b = 10.0
- change = change_dict('a', 0, 10, b, 'change')
- self.assertTrue(change in self._notify1)
- change = change_dict('b', 0.0, 10.0, b, 'change')
- self.assertTrue(change in self._notify2)
-
- def test_static_notify(self):
-
- class A(HasTraits):
- a = Int()
- b = Int()
- _notify1 = []
- _notify_any = []
-
- @observe('a')
- def _a_changed(self, change):
- self._notify1.append(change)
-
- @observe(All)
- def _any_changed(self, change):
- self._notify_any.append(change)
-
- a = A()
- a.a = 0
- self.assertEqual(len(a._notify1),0)
- a.a = 10
- change = change_dict('a', 0, 10, a, 'change')
- self.assertTrue(change in a._notify1)
- a.b = 1
- self.assertEqual(len(a._notify_any), 2)
- change = change_dict('b', 0, 1, a, 'change')
- self.assertTrue(change in a._notify_any)
-
- class B(A):
- b = Float()
- _notify2 = []
- @observe('b')
- def _b_changed(self, change):
- self._notify2.append(change)
-
- b = B()
- b.a = 10
- b.b = 10.0
- change = change_dict('a', 0, 10, b, 'change')
- self.assertTrue(change in b._notify1)
- change = change_dict('b', 0.0, 10.0, b, 'change')
- self.assertTrue(change in b._notify2)
-
- def test_notify_args(self):
-
- def callback0():
- self.cb = ()
- def callback1(change):
- self.cb = change
-
- class A(HasTraits):
- a = Int()
-
- a = A()
- a.on_trait_change(callback0, 'a')
- a.a = 10
- self.assertEqual(self.cb,())
- a.unobserve(callback0, 'a')
-
- a.observe(callback1, 'a')
- a.a = 100
- change = change_dict('a', 10, 100, a, 'change')
- self.assertEqual(self.cb, change)
- self.assertEqual(len(a._trait_notifiers['a']['change']), 1)
- a.unobserve(callback1, 'a')
-
- self.assertEqual(len(a._trait_notifiers['a']['change']), 0)
-
- def test_notify_only_once(self):
-
- class A(HasTraits):
- listen_to = ['a']
-
- a = Int(0)
- b = 0
-
- def __init__(self, **kwargs):
- super(A, self).__init__(**kwargs)
- self.observe(self.listener1, ['a'])
-
- def listener1(self, change):
- self.b += 1
-
- class B(A):
-
- c = 0
- d = 0
-
- def __init__(self, **kwargs):
- super(B, self).__init__(**kwargs)
- self.observe(self.listener2)
-
- def listener2(self, change):
- self.c += 1
-
- @observe('a')
- def _a_changed(self, change):
- self.d += 1
-
- b = B()
- b.a += 1
- self.assertEqual(b.b, b.c)
- self.assertEqual(b.b, b.d)
- b.a += 1
- self.assertEqual(b.b, b.c)
- self.assertEqual(b.b, b.d)
-
-
-class TestHasTraits(TestCase):
-
- def test_trait_names(self):
- class A(HasTraits):
- i = Int()
- f = Float()
- a = A()
- self.assertEqual(sorted(a.trait_names()),['f','i'])
- self.assertEqual(sorted(A.class_trait_names()),['f','i'])
- self.assertTrue(a.has_trait('f'))
- self.assertFalse(a.has_trait('g'))
-
- def test_trait_metadata_deprecated(self):
- with expected_warnings(['metadata should be set using the \.tag\(\) method']):
- class A(HasTraits):
- i = Int(config_key='MY_VALUE')
- a = A()
- self.assertEqual(a.trait_metadata('i','config_key'), 'MY_VALUE')
-
- def test_trait_metadata(self):
- class A(HasTraits):
- i = Int().tag(config_key='MY_VALUE')
- a = A()
- self.assertEqual(a.trait_metadata('i','config_key'), 'MY_VALUE')
-
- def test_trait_metadata_default(self):
- class A(HasTraits):
- i = Int()
- a = A()
- self.assertEqual(a.trait_metadata('i', 'config_key'), None)
- self.assertEqual(a.trait_metadata('i', 'config_key', 'default'), 'default')
-
- def test_traits(self):
- class A(HasTraits):
- i = Int()
- f = Float()
- a = A()
- self.assertEqual(a.traits(), dict(i=A.i, f=A.f))
- self.assertEqual(A.class_traits(), dict(i=A.i, f=A.f))
-
- def test_traits_metadata(self):
- class A(HasTraits):
- i = Int().tag(config_key='VALUE1', other_thing='VALUE2')
- f = Float().tag(config_key='VALUE3', other_thing='VALUE2')
- j = Int(0)
- a = A()
- self.assertEqual(a.traits(), dict(i=A.i, f=A.f, j=A.j))
- traits = a.traits(config_key='VALUE1', other_thing='VALUE2')
- self.assertEqual(traits, dict(i=A.i))
-
- # This passes, but it shouldn't because I am replicating a bug in
- # traits.
- traits = a.traits(config_key=lambda v: True)
- self.assertEqual(traits, dict(i=A.i, f=A.f, j=A.j))
-
- def test_traits_metadata_deprecated(self):
- with expected_warnings(['metadata should be set using the \.tag\(\) method']*2):
- class A(HasTraits):
- i = Int(config_key='VALUE1', other_thing='VALUE2')
- f = Float(config_key='VALUE3', other_thing='VALUE2')
- j = Int(0)
- a = A()
- self.assertEqual(a.traits(), dict(i=A.i, f=A.f, j=A.j))
- traits = a.traits(config_key='VALUE1', other_thing='VALUE2')
- self.assertEqual(traits, dict(i=A.i))
-
- # This passes, but it shouldn't because I am replicating a bug in
- # traits.
- traits = a.traits(config_key=lambda v: True)
- self.assertEqual(traits, dict(i=A.i, f=A.f, j=A.j))
-
-
- def test_init(self):
- class A(HasTraits):
- i = Int()
- x = Float()
- a = A(i=1, x=10.0)
- self.assertEqual(a.i, 1)
- self.assertEqual(a.x, 10.0)
-
- def test_positional_args(self):
- class A(HasTraits):
- i = Int(0)
- def __init__(self, i):
- super(A, self).__init__()
- self.i = i
-
- a = A(5)
- self.assertEqual(a.i, 5)
- # should raise TypeError if no positional arg given
- self.assertRaises(TypeError, A)
-
-#-----------------------------------------------------------------------------
-# Tests for specific trait types
-#-----------------------------------------------------------------------------
-
-
-class TestType(TestCase):
-
- def test_default(self):
-
- class B(object): pass
- class A(HasTraits):
- klass = Type(allow_none=True)
-
- a = A()
- self.assertEqual(a.klass, object)
-
- a.klass = B
- self.assertEqual(a.klass, B)
- self.assertRaises(TraitError, setattr, a, 'klass', 10)
-
- def test_default_options(self):
-
- class B(object): pass
- class C(B): pass
- class A(HasTraits):
- # Different possible combinations of options for default_value
- # and klass. default_value=None is only valid with allow_none=True.
- k1 = Type()
- k2 = Type(None, allow_none=True)
- k3 = Type(B)
- k4 = Type(klass=B)
- k5 = Type(default_value=None, klass=B, allow_none=True)
- k6 = Type(default_value=C, klass=B)
-
- self.assertIs(A.k1.default_value, object)
- self.assertIs(A.k1.klass, object)
- self.assertIs(A.k2.default_value, None)
- self.assertIs(A.k2.klass, object)
- self.assertIs(A.k3.default_value, B)
- self.assertIs(A.k3.klass, B)
- self.assertIs(A.k4.default_value, B)
- self.assertIs(A.k4.klass, B)
- self.assertIs(A.k5.default_value, None)
- self.assertIs(A.k5.klass, B)
- self.assertIs(A.k6.default_value, C)
- self.assertIs(A.k6.klass, B)
-
- a = A()
- self.assertIs(a.k1, object)
- self.assertIs(a.k2, None)
- self.assertIs(a.k3, B)
- self.assertIs(a.k4, B)
- self.assertIs(a.k5, None)
- self.assertIs(a.k6, C)
-
- def test_value(self):
-
- class B(object): pass
- class C(object): pass
- class A(HasTraits):
- klass = Type(B)
-
- a = A()
- self.assertEqual(a.klass, B)
- self.assertRaises(TraitError, setattr, a, 'klass', C)
- self.assertRaises(TraitError, setattr, a, 'klass', object)
- a.klass = B
-
- def test_allow_none(self):
-
- class B(object): pass
- class C(B): pass
- class A(HasTraits):
- klass = Type(B)
-
- a = A()
- self.assertEqual(a.klass, B)
- self.assertRaises(TraitError, setattr, a, 'klass', None)
- a.klass = C
- self.assertEqual(a.klass, C)
-
- def test_validate_klass(self):
-
- class A(HasTraits):
- klass = Type('no strings allowed')
-
- self.assertRaises(ImportError, A)
-
- class A(HasTraits):
- klass = Type('rub.adub.Duck')
-
- self.assertRaises(ImportError, A)
-
- def test_validate_default(self):
-
- class B(object): pass
- class A(HasTraits):
- klass = Type('bad default', B)
-
- self.assertRaises(ImportError, A)
-
- class C(HasTraits):
- klass = Type(None, B)
-
- self.assertRaises(TraitError, C)
-
- def test_str_klass(self):
-
- class A(HasTraits):
- klass = Type('ipython_genutils.ipstruct.Struct')
-
- from ipython_genutils.ipstruct import Struct
- a = A()
- a.klass = Struct
- self.assertEqual(a.klass, Struct)
-
- self.assertRaises(TraitError, setattr, a, 'klass', 10)
-
- def test_set_str_klass(self):
-
- class A(HasTraits):
- klass = Type()
-
- a = A(klass='ipython_genutils.ipstruct.Struct')
- from ipython_genutils.ipstruct import Struct
- self.assertEqual(a.klass, Struct)
-
-class TestInstance(TestCase):
-
- def test_basic(self):
- class Foo(object): pass
- class Bar(Foo): pass
- class Bah(object): pass
-
- class A(HasTraits):
- inst = Instance(Foo, allow_none=True)
-
- a = A()
- self.assertTrue(a.inst is None)
- a.inst = Foo()
- self.assertTrue(isinstance(a.inst, Foo))
- a.inst = Bar()
- self.assertTrue(isinstance(a.inst, Foo))
- self.assertRaises(TraitError, setattr, a, 'inst', Foo)
- self.assertRaises(TraitError, setattr, a, 'inst', Bar)
- self.assertRaises(TraitError, setattr, a, 'inst', Bah())
-
- def test_default_klass(self):
- class Foo(object): pass
- class Bar(Foo): pass
- class Bah(object): pass
-
- class FooInstance(Instance):
- klass = Foo
-
- class A(HasTraits):
- inst = FooInstance(allow_none=True)
-
- a = A()
- self.assertTrue(a.inst is None)
- a.inst = Foo()
- self.assertTrue(isinstance(a.inst, Foo))
- a.inst = Bar()
- self.assertTrue(isinstance(a.inst, Foo))
- self.assertRaises(TraitError, setattr, a, 'inst', Foo)
- self.assertRaises(TraitError, setattr, a, 'inst', Bar)
- self.assertRaises(TraitError, setattr, a, 'inst', Bah())
-
- def test_unique_default_value(self):
- class Foo(object): pass
- class A(HasTraits):
- inst = Instance(Foo,(),{})
-
- a = A()
- b = A()
- self.assertTrue(a.inst is not b.inst)
-
- def test_args_kw(self):
- class Foo(object):
- def __init__(self, c): self.c = c
- class Bar(object): pass
- class Bah(object):
- def __init__(self, c, d):
- self.c = c; self.d = d
-
- class A(HasTraits):
- inst = Instance(Foo, (10,))
- a = A()
- self.assertEqual(a.inst.c, 10)
-
- class B(HasTraits):
- inst = Instance(Bah, args=(10,), kw=dict(d=20))
- b = B()
- self.assertEqual(b.inst.c, 10)
- self.assertEqual(b.inst.d, 20)
-
- class C(HasTraits):
- inst = Instance(Foo, allow_none=True)
- c = C()
- self.assertTrue(c.inst is None)
-
- def test_bad_default(self):
- class Foo(object): pass
-
- class A(HasTraits):
- inst = Instance(Foo)
-
- a = A()
- with self.assertRaises(TraitError):
- a.inst
-
- def test_instance(self):
- class Foo(object): pass
-
- def inner():
- class A(HasTraits):
- inst = Instance(Foo())
-
- self.assertRaises(TraitError, inner)
-
-
-class TestThis(TestCase):
-
- def test_this_class(self):
- class Foo(HasTraits):
- this = This()
-
- f = Foo()
- self.assertEqual(f.this, None)
- g = Foo()
- f.this = g
- self.assertEqual(f.this, g)
- self.assertRaises(TraitError, setattr, f, 'this', 10)
-
- def test_this_inst(self):
- class Foo(HasTraits):
- this = This()
-
- f = Foo()
- f.this = Foo()
- self.assertTrue(isinstance(f.this, Foo))
-
- def test_subclass(self):
- class Foo(HasTraits):
- t = This()
- class Bar(Foo):
- pass
- f = Foo()
- b = Bar()
- f.t = b
- b.t = f
- self.assertEqual(f.t, b)
- self.assertEqual(b.t, f)
-
- def test_subclass_override(self):
- class Foo(HasTraits):
- t = This()
- class Bar(Foo):
- t = This()
- f = Foo()
- b = Bar()
- f.t = b
- self.assertEqual(f.t, b)
- self.assertRaises(TraitError, setattr, b, 't', f)
-
- def test_this_in_container(self):
-
- class Tree(HasTraits):
- value = Unicode()
- leaves = List(This())
-
- tree = Tree(
- value='foo',
- leaves=[Tree(value='bar'), Tree(value='buzz')]
- )
-
- with self.assertRaises(TraitError):
- tree.leaves = [1, 2]
-
-class TraitTestBase(TestCase):
- """A best testing class for basic trait types."""
-
- def assign(self, value):
- self.obj.value = value
-
- def coerce(self, value):
- return value
-
- def test_good_values(self):
- if hasattr(self, '_good_values'):
- for value in self._good_values:
- self.assign(value)
- self.assertEqual(self.obj.value, self.coerce(value))
-
- def test_bad_values(self):
- if hasattr(self, '_bad_values'):
- for value in self._bad_values:
- try:
- self.assertRaises(TraitError, self.assign, value)
- except AssertionError:
- assert False, value
-
- def test_default_value(self):
- if hasattr(self, '_default_value'):
- self.assertEqual(self._default_value, self.obj.value)
-
- def test_allow_none(self):
- if (hasattr(self, '_bad_values') and hasattr(self, '_good_values') and
- None in self._bad_values):
- trait=self.obj.traits()['value']
- try:
- trait.allow_none = True
- self._bad_values.remove(None)
- #skip coerce. Allow None casts None to None.
- self.assign(None)
- self.assertEqual(self.obj.value,None)
- self.test_good_values()
- self.test_bad_values()
- finally:
- #tear down
- trait.allow_none = False
- self._bad_values.append(None)
-
- def tearDown(self):
- # restore default value after tests, if set
- if hasattr(self, '_default_value'):
- self.obj.value = self._default_value
-
-
-class AnyTrait(HasTraits):
-
- value = Any()
-
-class AnyTraitTest(TraitTestBase):
-
- obj = AnyTrait()
-
- _default_value = None
- _good_values = [10.0, 'ten', u'ten', [10], {'ten': 10},(10,), None, 1j]
- _bad_values = []
-
-class UnionTrait(HasTraits):
-
- value = Union([Type(), Bool()])
-
-class UnionTraitTest(TraitTestBase):
-
- obj = UnionTrait(value='ipython_genutils.ipstruct.Struct')
- _good_values = [int, float, True]
- _bad_values = [[], (0,), 1j]
-
-class OrTrait(HasTraits):
-
- value = Bool() | Unicode()
-
-class OrTraitTest(TraitTestBase):
-
- obj = OrTrait()
- _good_values = [True, False, 'ten']
- _bad_values = [[], (0,), 1j]
-
-class IntTrait(HasTraits):
-
- value = Int(99, min=-100)
-
-class TestInt(TraitTestBase):
-
- obj = IntTrait()
- _default_value = 99
- _good_values = [10, -10]
- _bad_values = ['ten', u'ten', [10], {'ten': 10}, (10,), None, 1j,
- 10.1, -10.1, '10L', '-10L', '10.1', '-10.1', u'10L',
- u'-10L', u'10.1', u'-10.1', '10', '-10', u'10', -200]
- if not six.PY3:
- _bad_values.extend([long(10), long(-10), 10*sys.maxint, -10*sys.maxint])
-
-
-class CIntTrait(HasTraits):
- value = CInt('5')
-
-class TestCInt(TraitTestBase):
- obj = CIntTrait()
-
- _default_value = 5
- _good_values = ['10', '-10', u'10', u'-10', 10, 10.0, -10.0, 10.1]
- _bad_values = ['ten', u'ten', [10], {'ten': 10},(10,),
- None, 1j, '10.1', u'10.1']
-
- def coerce(self, n):
- return int(n)
-
-
-class MinBoundCIntTrait(HasTraits):
- value = CInt('5', min=3)
-
-class TestMinBoundCInt(TestCInt):
- obj = MinBoundCIntTrait()
-
- _default_value = 5
- _good_values = [3, 3.0, '3']
- _bad_values = [2.6, 2, -3, -3.0]
-
-
-class LongTrait(HasTraits):
-
- value = Long(99 if six.PY3 else long(99))
-
-class TestLong(TraitTestBase):
-
- obj = LongTrait()
-
- _default_value = 99 if six.PY3 else long(99)
- _good_values = [10, -10]
- _bad_values = ['ten', u'ten', [10], {'ten': 10},(10,),
- None, 1j, 10.1, -10.1, '10', '-10', '10L', '-10L', '10.1',
- '-10.1', u'10', u'-10', u'10L', u'-10L', u'10.1',
- u'-10.1']
- if not six.PY3:
- # maxint undefined on py3, because int == long
- _good_values.extend([long(10), long(-10), 10*sys.maxint, -10*sys.maxint])
- _bad_values.extend([[long(10)], (long(10),)])
-
- @mark.skipif(six.PY3, reason="not relevant on py3")
- def test_cast_small(self):
- """Long casts ints to long"""
- self.obj.value = 10
- self.assertEqual(type(self.obj.value), long)
-
-
-class MinBoundLongTrait(HasTraits):
- value = Long(99 if six.PY3 else long(99), min=5)
-
-class TestMinBoundLong(TraitTestBase):
- obj = MinBoundLongTrait()
-
- _default_value = 99 if six.PY3 else long(99)
- _good_values = [5, 10]
- _bad_values = [4, -10]
-
-
-class MaxBoundLongTrait(HasTraits):
- value = Long(5 if six.PY3 else long(5), max=10)
-
-class TestMaxBoundLong(TraitTestBase):
- obj = MaxBoundLongTrait()
-
- _default_value = 5 if six.PY3 else long(5)
- _good_values = [10, -2]
- _bad_values = [11, 20]
-
-
-class CLongTrait(HasTraits):
- value = CLong('5')
-
-class TestCLong(TraitTestBase):
- obj = CLongTrait()
-
- _default_value = 5 if six.PY3 else long(5)
- _good_values = ['10', '-10', u'10', u'-10', 10, 10.0, -10.0, 10.1]
- _bad_values = ['ten', u'ten', [10], {'ten': 10},(10,),
- None, 1j, '10.1', u'10.1']
-
- def coerce(self, n):
- return int(n) if six.PY3 else long(n)
-
-
-class MaxBoundCLongTrait(HasTraits):
- value = CLong('5', max=10)
-
-class TestMaxBoundCLong(TestCLong):
- obj = MaxBoundCLongTrait()
-
- _default_value = 5 if six.PY3 else long(5)
- _good_values = [10, '10', 10.3]
- _bad_values = [11.0, '11']
-
-
-class IntegerTrait(HasTraits):
- value = Integer(1)
-
-class TestInteger(TestLong):
- obj = IntegerTrait()
- _default_value = 1
-
- def coerce(self, n):
- return int(n)
-
- @mark.skipif(six.PY3, reason="not relevant on py3")
- def test_cast_small(self):
- """Integer casts small longs to int"""
-
- self.obj.value = long(100)
- self.assertEqual(type(self.obj.value), int)
-
-
-class MinBoundIntegerTrait(HasTraits):
- value = Integer(5, min=3)
-
-class TestMinBoundInteger(TraitTestBase):
- obj = MinBoundIntegerTrait()
-
- _default_value = 5
- _good_values = 3, 20
- _bad_values = [2, -10]
-
-
-class MaxBoundIntegerTrait(HasTraits):
- value = Integer(1, max=3)
-
-class TestMaxBoundInteger(TraitTestBase):
- obj = MaxBoundIntegerTrait()
-
- _default_value = 1
- _good_values = 3, -2
- _bad_values = [4, 10]
-
-
-class FloatTrait(HasTraits):
-
- value = Float(99.0, max=200.0)
-
-class TestFloat(TraitTestBase):
-
- obj = FloatTrait()
-
- _default_value = 99.0
- _good_values = [10, -10, 10.1, -10.1]
- _bad_values = ['ten', u'ten', [10], {'ten': 10}, (10,), None,
- 1j, '10', '-10', '10L', '-10L', '10.1', '-10.1', u'10',
- u'-10', u'10L', u'-10L', u'10.1', u'-10.1', 201.0]
- if not six.PY3:
- _bad_values.extend([long(10), long(-10)])
-
-
-class CFloatTrait(HasTraits):
-
- value = CFloat('99.0', max=200.0)
-
-class TestCFloat(TraitTestBase):
-
- obj = CFloatTrait()
-
- _default_value = 99.0
- _good_values = [10, 10.0, 10.5, '10.0', '10', '-10', '10.0', u'10']
- _bad_values = ['ten', u'ten', [10], {'ten': 10}, (10,), None, 1j,
- 200.1, '200.1']
-
- def coerce(self, v):
- return float(v)
-
-
-class ComplexTrait(HasTraits):
-
- value = Complex(99.0-99.0j)
-
-class TestComplex(TraitTestBase):
-
- obj = ComplexTrait()
-
- _default_value = 99.0-99.0j
- _good_values = [10, -10, 10.1, -10.1, 10j, 10+10j, 10-10j,
- 10.1j, 10.1+10.1j, 10.1-10.1j]
- _bad_values = [u'10L', u'-10L', 'ten', [10], {'ten': 10},(10,), None]
- if not six.PY3:
- _bad_values.extend([long(10), long(-10)])
-
-
-class BytesTrait(HasTraits):
-
- value = Bytes(b'string')
-
-class TestBytes(TraitTestBase):
-
- obj = BytesTrait()
-
- _default_value = b'string'
- _good_values = [b'10', b'-10', b'10L',
- b'-10L', b'10.1', b'-10.1', b'string']
- _bad_values = [10, -10, 10.1, -10.1, 1j, [10],
- ['ten'],{'ten': 10},(10,), None, u'string']
- if not six.PY3:
- _bad_values.extend([long(10), long(-10)])
-
-
-class UnicodeTrait(HasTraits):
-
- value = Unicode(u'unicode')
-
-class TestUnicode(TraitTestBase):
-
- obj = UnicodeTrait()
-
- _default_value = u'unicode'
- _good_values = ['10', '-10', '10L', '-10L', '10.1',
- '-10.1', '', u'', 'string', u'string', u"€"]
- _bad_values = [10, -10, 10.1, -10.1, 1j,
- [10], ['ten'], [u'ten'], {'ten': 10},(10,), None]
- if not six.PY3:
- _bad_values.extend([long(10), long(-10)])
-
-
-class ObjectNameTrait(HasTraits):
- value = ObjectName("abc")
-
-class TestObjectName(TraitTestBase):
- obj = ObjectNameTrait()
-
- _default_value = "abc"
- _good_values = ["a", "gh", "g9", "g_", "_G", u"a345_"]
- _bad_values = [1, "", u"€", "9g", "!", "#abc", "aj@", "a.b", "a()", "a[0]",
- None, object(), object]
- if sys.version_info[0] < 3:
- _bad_values.append(u"þ")
- else:
- _good_values.append(u"þ") # þ=1 is valid in Python 3 (PEP 3131).
-
-
-class DottedObjectNameTrait(HasTraits):
- value = DottedObjectName("a.b")
-
-class TestDottedObjectName(TraitTestBase):
- obj = DottedObjectNameTrait()
-
- _default_value = "a.b"
- _good_values = ["A", "y.t", "y765.__repr__", "os.path.join", u"os.path.join"]
- _bad_values = [1, u"abc.€", "_.@", ".", ".abc", "abc.", ".abc.", None]
- if sys.version_info[0] < 3:
- _bad_values.append(u"t.þ")
- else:
- _good_values.append(u"t.þ")
-
-
-class TCPAddressTrait(HasTraits):
- value = TCPAddress()
-
-class TestTCPAddress(TraitTestBase):
-
- obj = TCPAddressTrait()
-
- _default_value = ('127.0.0.1',0)
- _good_values = [('localhost',0),('192.168.0.1',1000),('www.google.com',80)]
- _bad_values = [(0,0),('localhost',10.0),('localhost',-1), None]
-
-class ListTrait(HasTraits):
-
- value = List(Int())
-
-class TestList(TraitTestBase):
-
- obj = ListTrait()
-
- _default_value = []
- _good_values = [[], [1], list(range(10)), (1,2)]
- _bad_values = [10, [1,'a'], 'a']
-
- def coerce(self, value):
- if value is not None:
- value = list(value)
- return value
-
-class Foo(object):
- pass
-
-class NoneInstanceListTrait(HasTraits):
-
- value = List(Instance(Foo))
-
-class TestNoneInstanceList(TraitTestBase):
-
- obj = NoneInstanceListTrait()
-
- _default_value = []
- _good_values = [[Foo(), Foo()], []]
- _bad_values = [[None], [Foo(), None]]
-
-
-class InstanceListTrait(HasTraits):
-
- value = List(Instance(__name__+'.Foo'))
-
-class TestInstanceList(TraitTestBase):
-
- obj = InstanceListTrait()
-
- def test_klass(self):
- """Test that the instance klass is properly assigned."""
- self.assertIs(self.obj.traits()['value']._trait.klass, Foo)
-
- _default_value = []
- _good_values = [[Foo(), Foo()], []]
- _bad_values = [['1', 2,], '1', [Foo], None]
-
-class UnionListTrait(HasTraits):
-
- value = List(Int() | Bool())
-
-class TestUnionListTrait(HasTraits):
-
- obj = UnionListTrait()
-
- _default_value = []
- _good_values = [[True, 1], [False, True]]
- _bad_values = [[1, 'True'], False]
-
-
-class LenListTrait(HasTraits):
-
- value = List(Int(), [0], minlen=1, maxlen=2)
-
-class TestLenList(TraitTestBase):
-
- obj = LenListTrait()
-
- _default_value = [0]
- _good_values = [[1], [1,2], (1,2)]
- _bad_values = [10, [1,'a'], 'a', [], list(range(3))]
-
- def coerce(self, value):
- if value is not None:
- value = list(value)
- return value
-
-class TupleTrait(HasTraits):
-
- value = Tuple(Int(allow_none=True), default_value=(1,))
-
-class TestTupleTrait(TraitTestBase):
-
- obj = TupleTrait()
-
- _default_value = (1,)
- _good_values = [(1,), (0,), [1]]
- _bad_values = [10, (1, 2), ('a'), (), None]
-
- def coerce(self, value):
- if value is not None:
- value = tuple(value)
- return value
-
- def test_invalid_args(self):
- self.assertRaises(TypeError, Tuple, 5)
- self.assertRaises(TypeError, Tuple, default_value='hello')
- t = Tuple(Int(), CBytes(), default_value=(1,5))
-
-class LooseTupleTrait(HasTraits):
-
- value = Tuple((1,2,3))
-
-class TestLooseTupleTrait(TraitTestBase):
-
- obj = LooseTupleTrait()
-
- _default_value = (1,2,3)
- _good_values = [(1,), [1], (0,), tuple(range(5)), tuple('hello'), ('a',5), ()]
- _bad_values = [10, 'hello', {}, None]
-
- def coerce(self, value):
- if value is not None:
- value = tuple(value)
- return value
-
- def test_invalid_args(self):
- self.assertRaises(TypeError, Tuple, 5)
- self.assertRaises(TypeError, Tuple, default_value='hello')
- t = Tuple(Int(), CBytes(), default_value=(1,5))
-
-
-class MultiTupleTrait(HasTraits):
-
- value = Tuple(Int(), Bytes(), default_value=[99,b'bottles'])
-
-class TestMultiTuple(TraitTestBase):
-
- obj = MultiTupleTrait()
-
- _default_value = (99,b'bottles')
- _good_values = [(1,b'a'), (2,b'b')]
- _bad_values = ((),10, b'a', (1,b'a',3), (b'a',1), (1, u'a'))
-
-class CRegExpTrait(HasTraits):
-
- value = CRegExp(r'')
-
-class TestCRegExp(TraitTestBase):
-
- def coerce(self, value):
- return re.compile(value)
-
- obj = CRegExpTrait()
-
- _default_value = re.compile(r'')
- _good_values = [r'\d+', re.compile(r'\d+')]
- _bad_values = ['(', None, ()]
-
-class DictTrait(HasTraits):
- value = Dict()
-
-def test_dict_assignment():
- d = dict()
- c = DictTrait()
- c.value = d
- d['a'] = 5
- assert d == c.value
- assert c.value is d
-
-
-class UniformlyValidatedDictTrait(HasTraits):
-
- value = Dict(trait=Unicode(),
- default_value={'foo': '1'})
-
-
-class TestInstanceUniformlyValidatedDict(TraitTestBase):
-
- obj = UniformlyValidatedDictTrait()
-
- _default_value = {'foo': '1'}
- _good_values = [{'foo': '0', 'bar': '1'}]
- _bad_values = [{'foo': 0, 'bar': '1'}]
-
-
-class KeyValidatedDictTrait(HasTraits):
-
- value = Dict(traits={'foo': Int()},
- default_value={'foo': 1})
-
-
-class TestInstanceKeyValidatedDict(TraitTestBase):
-
- obj = KeyValidatedDictTrait()
-
- _default_value = {'foo': 1}
- _good_values = [{'foo': 0, 'bar': '1'}, {'foo': 0, 'bar': 1}]
- _bad_values = [{'foo': '0', 'bar': '1'}]
-
-
-class FullyValidatedDictTrait(HasTraits):
-
- value = Dict(trait=Unicode(),
- traits={'foo': Int()},
- default_value={'foo': 1})
-
-
-class TestInstanceFullyValidatedDict(TraitTestBase):
-
- obj = FullyValidatedDictTrait()
-
- _default_value = {'foo': 1}
- _good_values = [{'foo': 0, 'bar': '1'}, {'foo': 1, 'bar': '2'}]
- _bad_values = [{'foo': 0, 'bar': 1}, {'foo': '0', 'bar': '1'}]
-
-
-def test_dict_default_value():
- """Check that the `{}` default value of the Dict traitlet constructor is
- actually copied."""
-
- class Foo(HasTraits):
- d1 = Dict()
- d2 = Dict()
-
- foo = Foo()
- assert foo.d1 == {}
- assert foo.d2 == {}
- assert foo.d1 is not foo.d2
-
-
-class TestValidationHook(TestCase):
-
- def test_parity_trait(self):
- """Verify that the early validation hook is effective"""
-
- class Parity(HasTraits):
-
- value = Int(0)
- parity = Enum(['odd', 'even'], default_value='even')
-
- @validate('value')
- def _value_validate(self, proposal):
- value = proposal['value']
- if self.parity == 'even' and value % 2:
- raise TraitError('Expected an even number')
- if self.parity == 'odd' and (value % 2 == 0):
- raise TraitError('Expected an odd number')
- return value
-
- u = Parity()
- u.parity = 'odd'
- u.value = 1 # OK
- with self.assertRaises(TraitError):
- u.value = 2 # Trait Error
-
- u.parity = 'even'
- u.value = 2 # OK
-
- def test_multiple_validate(self):
- """Verify that we can register the same validator to multiple names"""
-
- class OddEven(HasTraits):
-
- odd = Int(1)
- even = Int(0)
-
- @validate('odd', 'even')
- def check_valid(self, proposal):
- if proposal['trait'].name == 'odd' and not proposal['value'] % 2:
- raise TraitError('odd should be odd')
- if proposal['trait'].name == 'even' and proposal['value'] % 2:
- raise TraitError('even should be even')
-
- u = OddEven()
- u.odd = 3 # OK
- with self.assertRaises(TraitError):
- u.odd = 2 # Trait Error
-
- u.even = 2 # OK
- with self.assertRaises(TraitError):
- u.even = 3 # Trait Error
-
-
-
-class TestLink(TestCase):
-
- def test_connect_same(self):
- """Verify two traitlets of the same type can be linked together using link."""
-
- # Create two simple classes with Int traitlets.
- class A(HasTraits):
- value = Int()
- a = A(value=9)
- b = A(value=8)
-
- # Conenct the two classes.
- c = link((a, 'value'), (b, 'value'))
-
- # Make sure the values are the same at the point of linking.
- self.assertEqual(a.value, b.value)
-
- # Change one of the values to make sure they stay in sync.
- a.value = 5
- self.assertEqual(a.value, b.value)
- b.value = 6
- self.assertEqual(a.value, b.value)
-
- def test_link_different(self):
- """Verify two traitlets of different types can be linked together using link."""
-
- # Create two simple classes with Int traitlets.
- class A(HasTraits):
- value = Int()
- class B(HasTraits):
- count = Int()
- a = A(value=9)
- b = B(count=8)
-
- # Conenct the two classes.
- c = link((a, 'value'), (b, 'count'))
-
- # Make sure the values are the same at the point of linking.
- self.assertEqual(a.value, b.count)
-
- # Change one of the values to make sure they stay in sync.
- a.value = 5
- self.assertEqual(a.value, b.count)
- b.count = 4
- self.assertEqual(a.value, b.count)
-
- def test_unlink(self):
- """Verify two linked traitlets can be unlinked."""
-
- # Create two simple classes with Int traitlets.
- class A(HasTraits):
- value = Int()
- a = A(value=9)
- b = A(value=8)
-
- # Connect the two classes.
- c = link((a, 'value'), (b, 'value'))
- a.value = 4
- c.unlink()
-
- # Change one of the values to make sure they don't stay in sync.
- a.value = 5
- self.assertNotEqual(a.value, b.value)
-
- def test_callbacks(self):
- """Verify two linked traitlets have their callbacks called once."""
-
- # Create two simple classes with Int traitlets.
- class A(HasTraits):
- value = Int()
- class B(HasTraits):
- count = Int()
- a = A(value=9)
- b = B(count=8)
-
- # Register callbacks that count.
- callback_count = []
- def a_callback(name, old, new):
- callback_count.append('a')
- a.on_trait_change(a_callback, 'value')
- def b_callback(name, old, new):
- callback_count.append('b')
- b.on_trait_change(b_callback, 'count')
-
- # Connect the two classes.
- c = link((a, 'value'), (b, 'count'))
-
- # Make sure b's count was set to a's value once.
- self.assertEqual(''.join(callback_count), 'b')
- del callback_count[:]
-
- # Make sure a's value was set to b's count once.
- b.count = 5
- self.assertEqual(''.join(callback_count), 'ba')
- del callback_count[:]
-
- # Make sure b's count was set to a's value once.
- a.value = 4
- self.assertEqual(''.join(callback_count), 'ab')
- del callback_count[:]
-
-class TestDirectionalLink(TestCase):
- def test_connect_same(self):
- """Verify two traitlets of the same type can be linked together using directional_link."""
-
- # Create two simple classes with Int traitlets.
- class A(HasTraits):
- value = Int()
- a = A(value=9)
- b = A(value=8)
-
- # Conenct the two classes.
- c = directional_link((a, 'value'), (b, 'value'))
-
- # Make sure the values are the same at the point of linking.
- self.assertEqual(a.value, b.value)
-
- # Change one the value of the source and check that it synchronizes the target.
- a.value = 5
- self.assertEqual(b.value, 5)
- # Change one the value of the target and check that it has no impact on the source
- b.value = 6
- self.assertEqual(a.value, 5)
-
- def test_tranform(self):
- """Test transform link."""
-
- # Create two simple classes with Int traitlets.
- class A(HasTraits):
- value = Int()
- a = A(value=9)
- b = A(value=8)
-
- # Conenct the two classes.
- c = directional_link((a, 'value'), (b, 'value'), lambda x: 2 * x)
-
- # Make sure the values are correct at the point of linking.
- self.assertEqual(b.value, 2 * a.value)
-
- # Change one the value of the source and check that it modifies the target.
- a.value = 5
- self.assertEqual(b.value, 10)
- # Change one the value of the target and check that it has no impact on the source
- b.value = 6
- self.assertEqual(a.value, 5)
-
- def test_link_different(self):
- """Verify two traitlets of different types can be linked together using link."""
-
- # Create two simple classes with Int traitlets.
- class A(HasTraits):
- value = Int()
- class B(HasTraits):
- count = Int()
- a = A(value=9)
- b = B(count=8)
-
- # Conenct the two classes.
- c = directional_link((a, 'value'), (b, 'count'))
-
- # Make sure the values are the same at the point of linking.
- self.assertEqual(a.value, b.count)
-
- # Change one the value of the source and check that it synchronizes the target.
- a.value = 5
- self.assertEqual(b.count, 5)
- # Change one the value of the target and check that it has no impact on the source
- b.value = 6
- self.assertEqual(a.value, 5)
-
- def test_unlink(self):
- """Verify two linked traitlets can be unlinked."""
-
- # Create two simple classes with Int traitlets.
- class A(HasTraits):
- value = Int()
- a = A(value=9)
- b = A(value=8)
-
- # Connect the two classes.
- c = directional_link((a, 'value'), (b, 'value'))
- a.value = 4
- c.unlink()
-
- # Change one of the values to make sure they don't stay in sync.
- a.value = 5
- self.assertNotEqual(a.value, b.value)
-
-class Pickleable(HasTraits):
-
- i = Int()
- @observe('i')
- def _i_changed(self, change): pass
- @validate('i')
- def _i_validate(self, commit):
- return commit['value']
-
- j = Int()
-
- def __init__(self):
- with self.hold_trait_notifications():
- self.i = 1
- self.on_trait_change(self._i_changed, 'i')
-
-def test_pickle_hastraits():
- c = Pickleable()
- for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
- p = pickle.dumps(c, protocol)
- c2 = pickle.loads(p)
- assert c2.i == c.i
- assert c2.j == c.j
-
- c.i = 5
- for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
- p = pickle.dumps(c, protocol)
- c2 = pickle.loads(p)
- assert c2.i == c.i
- assert c2.j == c.j
-
-
-def test_hold_trait_notifications():
- changes = []
-
- class Test(HasTraits):
- a = Integer(0)
- b = Integer(0)
-
- def _a_changed(self, name, old, new):
- changes.append((old, new))
-
- def _b_validate(self, value, trait):
- if value != 0:
- raise TraitError('Only 0 is a valid value')
- return value
-
- # Test context manager and nesting
- t = Test()
- with t.hold_trait_notifications():
- with t.hold_trait_notifications():
- t.a = 1
- assert t.a == 1
- assert changes == []
- t.a = 2
- assert t.a == 2
- with t.hold_trait_notifications():
- t.a = 3
- assert t.a == 3
- assert changes == []
- t.a = 4
- assert t.a == 4
- assert changes == []
- t.a = 4
- assert t.a == 4
- assert changes == []
-
- assert changes == [(0, 4)]
- # Test roll-back
- try:
- with t.hold_trait_notifications():
- t.b = 1 # raises a Trait error
- except:
- pass
- assert t.b == 0
-
-
-class RollBack(HasTraits):
- bar = Int()
- def _bar_validate(self, value, trait):
- if value:
- raise TraitError('foobar')
- return value
-
-
-class TestRollback(TestCase):
-
- def test_roll_back(self):
-
- def assign_rollback():
- RollBack(bar=1)
-
- self.assertRaises(TraitError, assign_rollback)
-
-
-class CacheModification(HasTraits):
- foo = Int()
- bar = Int()
-
- def _bar_validate(self, value, trait):
- self.foo = value
- return value
-
- def _foo_validate(self, value, trait):
- self.bar = value
- return value
-
-
-def test_cache_modification():
- CacheModification(foo=1)
- CacheModification(bar=1)
-
-
-class OrderTraits(HasTraits):
- notified = Dict()
-
- a = Unicode()
- b = Unicode()
- c = Unicode()
- d = Unicode()
- e = Unicode()
- f = Unicode()
- g = Unicode()
- h = Unicode()
- i = Unicode()
- j = Unicode()
- k = Unicode()
- l = Unicode()
-
- def _notify(self, name, old, new):
- """check the value of all traits when each trait change is triggered
-
- This verifies that the values are not sensitive
- to dict ordering when loaded from kwargs
- """
- # check the value of the other traits
- # when a given trait change notification fires
- self.notified[name] = {
- c: getattr(self, c) for c in 'abcdefghijkl'
- }
-
- def __init__(self, **kwargs):
- self.on_trait_change(self._notify)
- super(OrderTraits, self).__init__(**kwargs)
-
-def test_notification_order():
- d = {c:c for c in 'abcdefghijkl'}
- obj = OrderTraits()
- assert obj.notified == {}
- obj = OrderTraits(**d)
- notifications = {
- c: d for c in 'abcdefghijkl'
- }
- assert obj.notified == notifications
-
-
-
-###
-# Traits for Forward Declaration Tests
-###
-class ForwardDeclaredInstanceTrait(HasTraits):
-
- value = ForwardDeclaredInstance('ForwardDeclaredBar', allow_none=True)
-
-class ForwardDeclaredTypeTrait(HasTraits):
-
- value = ForwardDeclaredType('ForwardDeclaredBar', allow_none=True)
-
-class ForwardDeclaredInstanceListTrait(HasTraits):
-
- value = List(ForwardDeclaredInstance('ForwardDeclaredBar'))
-
-class ForwardDeclaredTypeListTrait(HasTraits):
-
- value = List(ForwardDeclaredType('ForwardDeclaredBar'))
-###
-# End Traits for Forward Declaration Tests
-###
-
-###
-# Classes for Forward Declaration Tests
-###
-class ForwardDeclaredBar(object):
- pass
-
-class ForwardDeclaredBarSub(ForwardDeclaredBar):
- pass
-###
-# End Classes for Forward Declaration Tests
-###
-
-###
-# Forward Declaration Tests
-###
-class TestForwardDeclaredInstanceTrait(TraitTestBase):
-
- obj = ForwardDeclaredInstanceTrait()
- _default_value = None
- _good_values = [None, ForwardDeclaredBar(), ForwardDeclaredBarSub()]
- _bad_values = ['foo', 3, ForwardDeclaredBar, ForwardDeclaredBarSub]
-
-class TestForwardDeclaredTypeTrait(TraitTestBase):
-
- obj = ForwardDeclaredTypeTrait()
- _default_value = None
- _good_values = [None, ForwardDeclaredBar, ForwardDeclaredBarSub]
- _bad_values = ['foo', 3, ForwardDeclaredBar(), ForwardDeclaredBarSub()]
-
-class TestForwardDeclaredInstanceList(TraitTestBase):
-
- obj = ForwardDeclaredInstanceListTrait()
-
- def test_klass(self):
- """Test that the instance klass is properly assigned."""
- self.assertIs(self.obj.traits()['value']._trait.klass, ForwardDeclaredBar)
-
- _default_value = []
- _good_values = [
- [ForwardDeclaredBar(), ForwardDeclaredBarSub()],
- [],
- ]
- _bad_values = [
- ForwardDeclaredBar(),
- [ForwardDeclaredBar(), 3, None],
- '1',
- # Note that this is the type, not an instance.
- [ForwardDeclaredBar],
- [None],
- None,
- ]
-
-class TestForwardDeclaredTypeList(TraitTestBase):
-
- obj = ForwardDeclaredTypeListTrait()
-
- def test_klass(self):
- """Test that the instance klass is properly assigned."""
- self.assertIs(self.obj.traits()['value']._trait.klass, ForwardDeclaredBar)
-
- _default_value = []
- _good_values = [
- [ForwardDeclaredBar, ForwardDeclaredBarSub],
- [],
- ]
- _bad_values = [
- ForwardDeclaredBar,
- [ForwardDeclaredBar, 3],
- '1',
- # Note that this is an instance, not the type.
- [ForwardDeclaredBar()],
- [None],
- None,
- ]
-###
-# End Forward Declaration Tests
-###
-
-class TestDynamicTraits(TestCase):
-
- def setUp(self):
- self._notify1 = []
-
- def notify1(self, name, old, new):
- self._notify1.append((name, old, new))
-
- def test_notify_all(self):
-
- class A(HasTraits):
- pass
-
- a = A()
- self.assertTrue(not hasattr(a, 'x'))
- self.assertTrue(not hasattr(a, 'y'))
-
- # Dynamically add trait x.
- a.add_traits(x=Int())
- self.assertTrue(hasattr(a, 'x'))
- self.assertTrue(isinstance(a, (A, )))
-
- # Dynamically add trait y.
- a.add_traits(y=Float())
- self.assertTrue(hasattr(a, 'y'))
- self.assertTrue(isinstance(a, (A, )))
- self.assertEqual(a.__class__.__name__, A.__name__)
-
- # Create a new instance and verify that x and y
- # aren't defined.
- b = A()
- self.assertTrue(not hasattr(b, 'x'))
- self.assertTrue(not hasattr(b, 'y'))
-
- # Verify that notification works like normal.
- a.on_trait_change(self.notify1)
- a.x = 0
- self.assertEqual(len(self._notify1), 0)
- a.y = 0.0
- self.assertEqual(len(self._notify1), 0)
- a.x = 10
- self.assertTrue(('x', 0, 10) in self._notify1)
- a.y = 10.0
- self.assertTrue(('y', 0.0, 10.0) in self._notify1)
- self.assertRaises(TraitError, setattr, a, 'x', 'bad string')
- self.assertRaises(TraitError, setattr, a, 'y', 'bad string')
- self._notify1 = []
- a.on_trait_change(self.notify1, remove=True)
- a.x = 20
- a.y = 20.0
- self.assertEqual(len(self._notify1), 0)
-
-
-def test_enum_no_default():
- class C(HasTraits):
- t = Enum(['a', 'b'])
-
- c = C()
- c.t = 'a'
- assert c.t == 'a'
-
- c = C()
-
- with pytest.raises(TraitError):
- t = c.t
-
- c = C(t='b')
- assert c.t == 'b'
-
-
-def test_default_value_repr():
- class C(HasTraits):
- t = Type('traitlets.HasTraits')
- t2 = Type(HasTraits)
- n = Integer(0)
- lis = List()
- d = Dict()
-
- assert C.t.default_value_repr() == "'traitlets.HasTraits'"
- assert C.t2.default_value_repr() == "'traitlets.traitlets.HasTraits'"
- assert C.n.default_value_repr() == '0'
- assert C.lis.default_value_repr() == '[]'
- assert C.d.default_value_repr() == '{}'
-
-
-class TransitionalClass(HasTraits):
-
- d = Any()
- @default('d')
- def _d_default(self):
- return TransitionalClass
-
- parent_super = False
- calls_super = Integer(0)
-
- @default('calls_super')
- def _calls_super_default(self):
- return -1
-
- @observe('calls_super')
- @observe_compat
- def _calls_super_changed(self, change):
- self.parent_super = change
-
- parent_override = False
- overrides = Integer(0)
-
- @observe('overrides')
- @observe_compat
- def _overrides_changed(self, change):
- self.parent_override = change
-
-
-class SubClass(TransitionalClass):
- def _d_default(self):
- return SubClass
-
- subclass_super = False
- def _calls_super_changed(self, name, old, new):
- self.subclass_super = True
- super(SubClass, self)._calls_super_changed(name, old, new)
-
- subclass_override = False
- def _overrides_changed(self, name, old, new):
- self.subclass_override = True
-
-
-def test_subclass_compat():
- obj = SubClass()
- obj.calls_super = 5
- assert obj.parent_super
- assert obj.subclass_super
- obj.overrides = 5
- assert obj.subclass_override
- assert not obj.parent_override
- assert obj.d is SubClass
-
-
-class DefinesHandler(HasTraits):
- parent_called = False
-
- trait = Integer()
- @observe('trait')
- def handler(self, change):
- self.parent_called = True
-
-
-class OverridesHandler(DefinesHandler):
- child_called = False
-
- @observe('trait')
- def handler(self, change):
- self.child_called = True
-
-
-def test_subclass_override_observer():
- obj = OverridesHandler()
- obj.trait = 5
- assert obj.child_called
- assert not obj.parent_called
-
-
-class DoesntRegisterHandler(DefinesHandler):
- child_called = False
-
- def handler(self, change):
- self.child_called = True
-
-
-def test_subclass_override_not_registered():
- """Subclass that overrides observer and doesn't re-register unregisters both"""
- obj = DoesntRegisterHandler()
- obj.trait = 5
- assert not obj.child_called
- assert not obj.parent_called
-
-
-class AddsHandler(DefinesHandler):
- child_called = False
-
- @observe('trait')
- def child_handler(self, change):
- self.child_called = True
-
-def test_subclass_add_observer():
- obj = AddsHandler()
- obj.trait = 5
- assert obj.child_called
- assert obj.parent_called
-
-
-def test_observe_iterables():
-
- class C(HasTraits):
- i = Integer()
- s = Unicode()
-
- c = C()
- recorded = {}
- def record(change):
- recorded['change'] = change
-
- # observe with names=set
- c.observe(record, names={'i', 's'})
- c.i = 5
- assert recorded['change'].name == 'i'
- assert recorded['change'].new == 5
- c.s = 'hi'
- assert recorded['change'].name == 's'
- assert recorded['change'].new == 'hi'
-
- # observe with names=custom container with iter, contains
- class MyContainer(object):
- def __init__(self, container):
- self.container = container
-
- def __iter__(self):
- return iter(self.container)
-
- def __contains__(self, key):
- return key in self.container
-
- c.observe(record, names=MyContainer({'i', 's'}))
- c.i = 10
- assert recorded['change'].name == 'i'
- assert recorded['change'].new == 10
- c.s = 'ok'
- assert recorded['change'].name == 's'
- assert recorded['change'].new == 'ok'
-
-
-def test_super_args():
- class SuperRecorder(object):
- def __init__(self, *args, **kwargs):
- self.super_args = args
- self.super_kwargs = kwargs
-
- class SuperHasTraits(HasTraits, SuperRecorder):
- i = Integer()
-
- obj = SuperHasTraits('a1', 'a2', b=10, i=5, c='x')
- assert obj.i == 5
- assert not hasattr(obj, 'b')
- assert not hasattr(obj, 'c')
- assert obj.super_args == ('a1' , 'a2')
- assert obj.super_kwargs == {'b': 10 , 'c': 'x'}
-
-def test_super_bad_args():
- class SuperHasTraits(HasTraits):
- a = Integer()
-
- if sys.version_info < (3,):
- # Legacy Python, object.__init__ warns itself, instead of raising
- w = ['object.__init__']
- else:
- w = ["Passing unrecoginized arguments"]
- with expected_warnings(w):
- obj = SuperHasTraits(a=1, b=2)
- assert obj.a == 1
- assert not hasattr(obj, 'b')
diff --git a/contrib/python/traitlets/py2/traitlets/tests/test_traitlets_enum.py b/contrib/python/traitlets/py2/traitlets/tests/test_traitlets_enum.py
deleted file mode 100644
index 82259ae6c51..00000000000
--- a/contrib/python/traitlets/py2/traitlets/tests/test_traitlets_enum.py
+++ /dev/null
@@ -1,181 +0,0 @@
-# -*- coding: UTF-8 -*-
-# pylint: disable=missing-docstring, too-few-public-methods
-"""
-Test the trait-type ``UseEnum``.
-"""
-
-import unittest
-import enum
-from ipython_genutils.py3compat import string_types
-from traitlets import HasTraits, TraitError, UseEnum
-
-
-# -----------------------------------------------------------------------------
-# TEST SUPPORT:
-# -----------------------------------------------------------------------------
-class Color(enum.Enum):
- red = 1
- green = 2
- blue = 3
- yellow = 4
-
-class OtherColor(enum.Enum):
- red = 0
- green = 1
-
-
-# -----------------------------------------------------------------------------
-# TESTSUITE:
-# -----------------------------------------------------------------------------
-class TestUseEnum(unittest.TestCase):
- # pylint: disable=invalid-name
-
- class Example(HasTraits):
- color = UseEnum(Color, help="Color enum")
-
- def test_assign_enum_value(self):
- example = self.Example()
- example.color = Color.green
- self.assertEqual(example.color, Color.green)
-
- def test_assign_all_enum_values(self):
- # pylint: disable=no-member
- enum_values = [value for value in Color.__members__.values()]
- for value in enum_values:
- self.assertIsInstance(value, Color)
- example = self.Example()
- example.color = value
- self.assertEqual(example.color, value)
- self.assertIsInstance(value, Color)
-
- def test_assign_enum_value__with_other_enum_raises_error(self):
- example = self.Example()
- with self.assertRaises(TraitError):
- example.color = OtherColor.green
-
- def test_assign_enum_name_1(self):
- # -- CONVERT: string => Enum value (item)
- example = self.Example()
- example.color = "red"
- self.assertEqual(example.color, Color.red)
-
- def test_assign_enum_value_name(self):
- # -- CONVERT: string => Enum value (item)
- # pylint: disable=no-member
- enum_names = [enum_val.name for enum_val in Color.__members__.values()]
- for value in enum_names:
- self.assertIsInstance(value, string_types)
- example = self.Example()
- enum_value = Color.__members__.get(value)
- example.color = value
- self.assertIs(example.color, enum_value)
- self.assertEqual(example.color.name, value)
-
- def test_assign_scoped_enum_value_name(self):
- # -- CONVERT: string => Enum value (item)
- scoped_names = ["Color.red", "Color.green", "Color.blue", "Color.yellow"]
- for value in scoped_names:
- example = self.Example()
- example.color = value
- self.assertIsInstance(example.color, Color)
- self.assertEqual(str(example.color), value)
-
- def test_assign_bad_enum_value_name__raises_error(self):
- # -- CONVERT: string => Enum value (item)
- bad_enum_names = ["UNKNOWN_COLOR", "RED", "Green", "blue2"]
- for value in bad_enum_names:
- example = self.Example()
- with self.assertRaises(TraitError):
- example.color = value
-
- def test_assign_enum_value_number_1(self):
- # -- CONVERT: number => Enum value (item)
- example = self.Example()
- example.color = 1 # == Color.red.value
- example.color = Color.red.value
- self.assertEqual(example.color, Color.red)
-
- def test_assign_enum_value_number(self):
- # -- CONVERT: number => Enum value (item)
- # pylint: disable=no-member
- enum_numbers = [enum_val.value
- for enum_val in Color.__members__.values()]
- for value in enum_numbers:
- self.assertIsInstance(value, int)
- example = self.Example()
- example.color = value
- self.assertIsInstance(example.color, Color)
- self.assertEqual(example.color.value, value)
-
- def test_assign_bad_enum_value_number__raises_error(self):
- # -- CONVERT: number => Enum value (item)
- bad_numbers = [-1, 0, 5]
- for value in bad_numbers:
- self.assertIsInstance(value, int)
- assert UseEnum(Color).select_by_number(value, None) is None
- example = self.Example()
- with self.assertRaises(TraitError):
- example.color = value
-
- def test_ctor_without_default_value(self):
- # -- IMPLICIT: default_value = Color.red (first enum-value)
- class Example2(HasTraits):
- color = UseEnum(Color)
-
- example = Example2()
- self.assertEqual(example.color, Color.red)
-
- def test_ctor_with_default_value_as_enum_value(self):
- # -- CONVERT: number => Enum value (item)
- class Example2(HasTraits):
- color = UseEnum(Color, default_value=Color.green)
-
- example = Example2()
- self.assertEqual(example.color, Color.green)
-
-
- def test_ctor_with_default_value_none_and_not_allow_none(self):
- # -- IMPLICIT: default_value = Color.red (first enum-value)
- class Example2(HasTraits):
- color1 = UseEnum(Color, default_value=None, allow_none=False)
- color2 = UseEnum(Color, default_value=None)
- example = Example2()
- self.assertEqual(example.color1, Color.red)
- self.assertEqual(example.color2, Color.red)
-
- def test_ctor_with_default_value_none_and_allow_none(self):
- class Example2(HasTraits):
- color1 = UseEnum(Color, default_value=None, allow_none=True)
- color2 = UseEnum(Color, allow_none=True)
-
- example = Example2()
- self.assertIs(example.color1, None)
- self.assertIs(example.color2, None)
-
- def test_assign_none_without_allow_none_resets_to_default_value(self):
- class Example2(HasTraits):
- color1 = UseEnum(Color, allow_none=False)
- color2 = UseEnum(Color)
-
- example = Example2()
- example.color1 = None
- example.color2 = None
- self.assertIs(example.color1, Color.red)
- self.assertIs(example.color2, Color.red)
-
- def test_assign_none_to_enum_or_none(self):
- class Example2(HasTraits):
- color = UseEnum(Color, allow_none=True)
-
- example = Example2()
- example.color = None
- self.assertIs(example.color, None)
-
- def test_assign_bad_value_with_to_enum_or_none(self):
- class Example2(HasTraits):
- color = UseEnum(Color, allow_none=True)
-
- example = Example2()
- with self.assertRaises(TraitError):
- example.color = "BAD_VALUE"
-
diff --git a/contrib/python/traitlets/py2/traitlets/tests/utils.py b/contrib/python/traitlets/py2/traitlets/tests/utils.py
deleted file mode 100644
index 88845d8519d..00000000000
--- a/contrib/python/traitlets/py2/traitlets/tests/utils.py
+++ /dev/null
@@ -1,39 +0,0 @@
-import sys
-
-from subprocess import Popen, PIPE
-
-def get_output_error_code(cmd):
- """Get stdout, stderr, and exit code from running a command"""
- p = Popen(cmd, stdout=PIPE, stderr=PIPE)
- out, err = p.communicate()
- out = out.decode('utf8', 'replace')
- err = err.decode('utf8', 'replace')
- return out, err, p.returncode
-
-
-def check_help_output(pkg, subcommand=None):
- """test that `python -m PKG [subcommand] -h` works"""
- cmd = [sys.executable, '-m', pkg]
- if subcommand:
- cmd.extend(subcommand)
- cmd.append('-h')
- out, err, rc = get_output_error_code(cmd)
- assert rc == 0, err
- assert "Traceback" not in err
- assert "Options" in out
- assert "--help-all" in out
- return out, err
-
-
-def check_help_all_output(pkg, subcommand=None):
- """test that `python -m PKG --help-all` works"""
- cmd = [sys.executable, '-m', pkg]
- if subcommand:
- cmd.extend(subcommand)
- cmd.append('--help-all')
- out, err, rc = get_output_error_code(cmd)
- assert rc == 0, err
- assert "Traceback" not in err
- assert "Options" in out
- assert "Class parameters" in out
- return out, err
diff --git a/contrib/python/traitlets/py2/traitlets/traitlets.py b/contrib/python/traitlets/py2/traitlets/traitlets.py
deleted file mode 100644
index c07daf7400d..00000000000
--- a/contrib/python/traitlets/py2/traitlets/traitlets.py
+++ /dev/null
@@ -1,2690 +0,0 @@
-# encoding: utf-8
-"""
-A lightweight Traits like module.
-
-This is designed to provide a lightweight, simple, pure Python version of
-many of the capabilities of enthought.traits. This includes:
-
-* Validation
-* Type specification with defaults
-* Static and dynamic notification
-* Basic predefined types
-* An API that is similar to enthought.traits
-
-We don't support:
-
-* Delegation
-* Automatic GUI generation
-* A full set of trait types. Most importantly, we don't provide container
- traits (list, dict, tuple) that can trigger notifications if their
- contents change.
-* API compatibility with enthought.traits
-
-There are also some important difference in our design:
-
-* enthought.traits does not validate default values. We do.
-
-We choose to create this module because we need these capabilities, but
-we need them to be pure Python so they work in all Python implementations,
-including Jython and IronPython.
-
-Inheritance diagram:
-
-.. inheritance-diagram:: traitlets.traitlets
- :parts: 3
-"""
-
-# Copyright (c) IPython Development Team.
-# Distributed under the terms of the Modified BSD License.
-#
-# Adapted from enthought.traits, Copyright (c) Enthought, Inc.,
-# also under the terms of the Modified BSD License.
-
-import contextlib
-import inspect
-import os
-import re
-import sys
-import types
-import enum
-try:
- from types import ClassType, InstanceType
- ClassTypes = (ClassType, type)
-except:
- ClassTypes = (type,)
-from warnings import warn, warn_explicit
-
-import six
-
-from .utils.getargspec import getargspec
-from .utils.importstring import import_item
-from .utils.sentinel import Sentinel
-from .utils.bunch import Bunch
-
-SequenceTypes = (list, tuple, set, frozenset)
-
-#-----------------------------------------------------------------------------
-# Basic classes
-#-----------------------------------------------------------------------------
-
-
-Undefined = Sentinel('Undefined', 'traitlets',
-'''
-Used in Traitlets to specify that no defaults are set in kwargs
-'''
-)
-
-All = Sentinel('All', 'traitlets',
-'''
-Used in Traitlets to listen to all types of notification or to notifications
-from all trait attributes.
-'''
-)
-
-# Deprecated alias
-NoDefaultSpecified = Undefined
-
-class TraitError(Exception):
- pass
-
-#-----------------------------------------------------------------------------
-# Utilities
-#-----------------------------------------------------------------------------
-
-from ipython_genutils.py3compat import cast_unicode_py2
-
-_name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
-
-def isidentifier(s):
- if six.PY2:
- return bool(_name_re.match(s))
- else:
- return s.isidentifier()
-
-_deprecations_shown = set()
-def _should_warn(key):
- """Add our own checks for too many deprecation warnings.
-
- Limit to once per package.
- """
- env_flag = os.environ.get('TRAITLETS_ALL_DEPRECATIONS')
- if env_flag and env_flag != '0':
- return True
-
- if key not in _deprecations_shown:
- _deprecations_shown.add(key)
- return True
- else:
- return False
-
-def _deprecated_method(method, cls, method_name, msg):
- """Show deprecation warning about a magic method definition.
-
- Uses warn_explicit to bind warning to method definition instead of triggering code,
- which isn't relevant.
- """
- warn_msg = "{classname}.{method_name} is deprecated in traitlets 4.1: {msg}".format(
- classname=cls.__name__, method_name=method_name, msg=msg
- )
-
- for parent in inspect.getmro(cls):
- if method_name in parent.__dict__:
- cls = parent
- break
- # limit deprecation messages to once per package
- package_name = cls.__module__.split('.', 1)[0]
- key = (package_name, msg)
- if not _should_warn(key):
- return
- try:
- fname = inspect.getsourcefile(method) or "<unknown>"
- lineno = inspect.getsourcelines(method)[1] or 0
- except (IOError, TypeError) as e:
- # Failed to inspect for some reason
- warn(warn_msg + ('\n(inspection failed) %s' % e), DeprecationWarning)
- else:
- warn_explicit(warn_msg, DeprecationWarning, fname, lineno)
-
-def class_of(object):
- """ Returns a string containing the class name of an object with the
- correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
- 'a PlotValue').
- """
- if isinstance( object, six.string_types ):
- return add_article( object )
-
- return add_article( object.__class__.__name__ )
-
-
-def add_article(name):
- """ Returns a string containing the correct indefinite article ('a' or 'an')
- prefixed to the specified string.
- """
- if name[:1].lower() in 'aeiou':
- return 'an ' + name
-
- return 'a ' + name
-
-
-def repr_type(obj):
- """ Return a string representation of a value and its type for readable
- error messages.
- """
- the_type = type(obj)
- if six.PY2 and the_type is InstanceType:
- # Old-style class.
- the_type = obj.__class__
- msg = '%r %r' % (obj, the_type)
- return msg
-
-
-def is_trait(t):
- """ Returns whether the given value is an instance or subclass of TraitType.
- """
- return (isinstance(t, TraitType) or
- (isinstance(t, type) and issubclass(t, TraitType)))
-
-
-def parse_notifier_name(names):
- """Convert the name argument to a list of names.
-
- Examples
- --------
-
- >>> parse_notifier_name([])
- [All]
- >>> parse_notifier_name('a')
- ['a']
- >>> parse_notifier_name(['a', 'b'])
- ['a', 'b']
- >>> parse_notifier_name(All)
- [All]
- """
- if names is All or isinstance(names, six.string_types):
- return [names]
- else:
- if not names or All in names:
- return [All]
- for n in names:
- if not isinstance(n, six.string_types):
- raise TypeError("names must be strings, not %r" % n)
- return names
-
-
-class _SimpleTest:
- def __init__ ( self, value ): self.value = value
- def __call__ ( self, test ):
- return test == self.value
- def __repr__(self):
- return "<SimpleTest(%r)" % self.value
- def __str__(self):
- return self.__repr__()
-
-
-def getmembers(object, predicate=None):
- """A safe version of inspect.getmembers that handles missing attributes.
-
- This is useful when there are descriptor based attributes that for
- some reason raise AttributeError even though they exist. This happens
- in zope.inteface with the __provides__ attribute.
- """
- results = []
- for key in dir(object):
- try:
- value = getattr(object, key)
- except AttributeError:
- pass
- else:
- if not predicate or predicate(value):
- results.append((key, value))
- results.sort()
- return results
-
-def _validate_link(*tuples):
- """Validate arguments for traitlet link functions"""
- for t in tuples:
- if not len(t) == 2:
- raise TypeError("Each linked traitlet must be specified as (HasTraits, 'trait_name'), not %r" % t)
- obj, trait_name = t
- if not isinstance(obj, HasTraits):
- raise TypeError("Each object must be HasTraits, not %r" % type(obj))
- if not trait_name in obj.traits():
- raise TypeError("%r has no trait %r" % (obj, trait_name))
-
-class link(object):
- """Link traits from different objects together so they remain in sync.
-
- Parameters
- ----------
- source : (object / attribute name) pair
- target : (object / attribute name) pair
-
- Examples
- --------
-
- >>> c = link((src, 'value'), (tgt, 'value'))
- >>> src.value = 5 # updates other objects as well
- """
- updating = False
-
- def __init__(self, source, target):
- _validate_link(source, target)
- self.source, self.target = source, target
- try:
- setattr(target[0], target[1], getattr(source[0], source[1]))
- finally:
- source[0].observe(self._update_target, names=source[1])
- target[0].observe(self._update_source, names=target[1])
-
- @contextlib.contextmanager
- def _busy_updating(self):
- self.updating = True
- try:
- yield
- finally:
- self.updating = False
-
- def _update_target(self, change):
- if self.updating:
- return
- with self._busy_updating():
- setattr(self.target[0], self.target[1], change.new)
-
- def _update_source(self, change):
- if self.updating:
- return
- with self._busy_updating():
- setattr(self.source[0], self.source[1], change.new)
-
- def unlink(self):
- self.source[0].unobserve(self._update_target, names=self.source[1])
- self.target[0].unobserve(self._update_source, names=self.target[1])
- self.source, self.target = None, None
-
-
-class directional_link(object):
- """Link the trait of a source object with traits of target objects.
-
- Parameters
- ----------
- source : (object, attribute name) pair
- target : (object, attribute name) pair
- transform: callable (optional)
- Data transformation between source and target.
-
- Examples
- --------
-
- >>> c = directional_link((src, 'value'), (tgt, 'value'))
- >>> src.value = 5 # updates target objects
- >>> tgt.value = 6 # does not update source object
- """
- updating = False
-
- def __init__(self, source, target, transform=None):
- self._transform = transform if transform else lambda x: x
- _validate_link(source, target)
- self.source, self.target = source, target
- try:
- setattr(target[0], target[1],
- self._transform(getattr(source[0], source[1])))
- finally:
- self.source[0].observe(self._update, names=self.source[1])
-
- @contextlib.contextmanager
- def _busy_updating(self):
- self.updating = True
- try:
- yield
- finally:
- self.updating = False
-
- def _update(self, change):
- if self.updating:
- return
- with self._busy_updating():
- setattr(self.target[0], self.target[1],
- self._transform(change.new))
-
- def unlink(self):
- self.source[0].unobserve(self._update, names=self.source[1])
- self.source, self.target = None, None
-
-dlink = directional_link
-
-
-#-----------------------------------------------------------------------------
-# Base Descriptor Class
-#-----------------------------------------------------------------------------
-
-
-class BaseDescriptor(object):
- """Base descriptor class
-
- Notes
- -----
- This implements Python's descriptor prototol.
-
- This class is the base class for all such descriptors. The
- only magic we use is a custom metaclass for the main :class:`HasTraits`
- class that does the following:
-
- 1. Sets the :attr:`name` attribute of every :class:`BaseDescriptor`
- instance in the class dict to the name of the attribute.
- 2. Sets the :attr:`this_class` attribute of every :class:`BaseDescriptor`
- instance in the class dict to the *class* that declared the trait.
- This is used by the :class:`This` trait to allow subclasses to
- accept superclasses for :class:`This` values.
- """
-
- name = None
- this_class = None
-
- def class_init(self, cls, name):
- """Part of the initialization which may depend on the underlying
- HasDescriptors class.
-
- It is typically overloaded for specific types.
-
- This method is called by :meth:`MetaHasDescriptors.__init__`
- passing the class (`cls`) and `name` under which the descriptor
- has been assigned.
- """
- self.this_class = cls
- self.name = name
-
- def instance_init(self, obj):
- """Part of the initialization which may depend on the underlying
- HasDescriptors instance.
-
- It is typically overloaded for specific types.
-
- This method is called by :meth:`HasTraits.__new__` and in the
- :meth:`BaseDescriptor.instance_init` method of descriptors holding
- other descriptors.
- """
- pass
-
-
-class TraitType(BaseDescriptor):
- """A base class for all trait types.
- """
-
- metadata = {}
- default_value = Undefined
- allow_none = False
- read_only = False
- info_text = 'any value'
-
- def __init__(self, default_value=Undefined, allow_none=False, read_only=None, help=None,
- config=None, **kwargs):
- """Declare a traitlet.
-
- If *allow_none* is True, None is a valid value in addition to any
- values that are normally valid. The default is up to the subclass.
- For most trait types, the default value for ``allow_none`` is False.
-
- Extra metadata can be associated with the traitlet using the .tag() convenience method
- or by using the traitlet instance's .metadata dictionary.
- """
- if default_value is not Undefined:
- self.default_value = default_value
- if allow_none:
- self.allow_none = allow_none
- if read_only is not None:
- self.read_only = read_only
- self.help = help if help is not None else ''
-
- if len(kwargs) > 0:
- stacklevel = 1
- f = inspect.currentframe()
- # count supers to determine stacklevel for warning
- while f.f_code.co_name == '__init__':
- stacklevel += 1
- f = f.f_back
- mod = f.f_globals.get('__name__') or ''
- pkg = mod.split('.', 1)[0]
- key = tuple(['metadata-tag', pkg] + sorted(kwargs))
- if _should_warn(key):
- warn("metadata %s was set from the constructor. "
- "With traitlets 4.1, metadata should be set using the .tag() method, "
- "e.g., Int().tag(key1='value1', key2='value2')" % (kwargs,),
- DeprecationWarning, stacklevel=stacklevel)
- if len(self.metadata) > 0:
- self.metadata = self.metadata.copy()
- self.metadata.update(kwargs)
- else:
- self.metadata = kwargs
- else:
- self.metadata = self.metadata.copy()
- if config is not None:
- self.metadata['config'] = config
-
- # We add help to the metadata during a deprecation period so that
- # code that looks for the help string there can find it.
- if help is not None:
- self.metadata['help'] = help
-
- def get_default_value(self):
- """DEPRECATED: Retrieve the static default value for this trait.
-
- Use self.default_value instead
- """
- warn("get_default_value is deprecated in traitlets 4.0: use the .default_value attribute", DeprecationWarning,
- stacklevel=2)
- return self.default_value
-
- def init_default_value(self, obj):
- """DEPRECATED: Set the static default value for the trait type.
- """
- warn("init_default_value is deprecated in traitlets 4.0, and may be removed in the future", DeprecationWarning,
- stacklevel=2)
- value = self._validate(obj, self.default_value)
- obj._trait_values[self.name] = value
- return value
-
- def _dynamic_default_callable(self, obj):
- """Retrieve a callable to calculate the default for this traitlet.
-
- This looks for:
-
- * default generators registered with the @default descriptor.
- * obj._{name}_default() on the class with the traitlet, or a subclass
- that obj belongs to.
- * trait.make_dynamic_default, which is defined by Instance
-
- If neither exist, it returns None
- """
- # Traitlets without a name are not on the instance, e.g. in List or Union
- if self.name:
-
- # Only look for default handlers in classes derived from self.this_class.
- mro = type(obj).mro()
- meth_name = '_%s_default' % self.name
- for cls in mro[:mro.index(self.this_class) + 1]:
- if hasattr(cls, '_trait_default_generators'):
- default_handler = cls._trait_default_generators.get(self.name)
- if default_handler is not None and default_handler.this_class == cls:
- return types.MethodType(default_handler.func, obj)
-
- if meth_name in cls.__dict__:
- method = getattr(obj, meth_name)
- return method
-
- return getattr(self, 'make_dynamic_default', None)
-
- def instance_init(self, obj):
- # If no dynamic initialiser is present, and the trait implementation or
- # use provides a static default, transfer that to obj._trait_values.
- with obj.cross_validation_lock:
- if (self._dynamic_default_callable(obj) is None) \
- and (self.default_value is not Undefined):
- v = self._validate(obj, self.default_value)
- if self.name is not None:
- obj._trait_values[self.name] = v
-
- def get(self, obj, cls=None):
- try:
- value = obj._trait_values[self.name]
- except KeyError:
- # Check for a dynamic initializer.
- dynamic_default = self._dynamic_default_callable(obj)
- if dynamic_default is None:
- raise TraitError("No default value found for %s trait of %r"
- % (self.name, obj))
- value = self._validate(obj, dynamic_default())
- obj._trait_values[self.name] = value
- return value
- except Exception:
- # This should never be reached.
- raise TraitError('Unexpected error in TraitType: '
- 'default value not set properly')
- else:
- return value
-
- def __get__(self, obj, cls=None):
- """Get the value of the trait by self.name for the instance.
-
- Default values are instantiated when :meth:`HasTraits.__new__`
- is called. Thus by the time this method gets called either the
- default value or a user defined value (they called :meth:`__set__`)
- is in the :class:`HasTraits` instance.
- """
- if obj is None:
- return self
- else:
- return self.get(obj, cls)
-
- def set(self, obj, value):
- new_value = self._validate(obj, value)
- try:
- old_value = obj._trait_values[self.name]
- except KeyError:
- old_value = self.default_value
-
- obj._trait_values[self.name] = new_value
- try:
- silent = bool(old_value == new_value)
- except:
- # if there is an error in comparing, default to notify
- silent = False
- if silent is not True:
- # we explicitly compare silent to True just in case the equality
- # comparison above returns something other than True/False
- obj._notify_trait(self.name, old_value, new_value)
-
- def __set__(self, obj, value):
- """Set the value of the trait by self.name for the instance.
-
- Values pass through a validation stage where errors are raised when
- impropper types, or types that cannot be coerced, are encountered.
- """
- if self.read_only:
- raise TraitError('The "%s" trait is read-only.' % self.name)
- else:
- self.set(obj, value)
-
- def _validate(self, obj, value):
- if value is None and self.allow_none:
- return value
- if hasattr(self, 'validate'):
- value = self.validate(obj, value)
- if obj._cross_validation_lock is False:
- value = self._cross_validate(obj, value)
- return value
-
- def _cross_validate(self, obj, value):
- if self.name in obj._trait_validators:
- proposal = Bunch({'trait': self, 'value': value, 'owner': obj})
- value = obj._trait_validators[self.name](obj, proposal)
- elif hasattr(obj, '_%s_validate' % self.name):
- meth_name = '_%s_validate' % self.name
- cross_validate = getattr(obj, meth_name)
- _deprecated_method(cross_validate, obj.__class__, meth_name,
- "use @validate decorator instead.")
- value = cross_validate(value, self)
- return value
-
- def __or__(self, other):
- if isinstance(other, Union):
- return Union([self] + other.trait_types)
- else:
- return Union([self, other])
-
- def info(self):
- return self.info_text
-
- def error(self, obj, value):
- if obj is not None:
- e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
- % (self.name, class_of(obj),
- self.info(), repr_type(value))
- else:
- e = "The '%s' trait must be %s, but a value of %r was specified." \
- % (self.name, self.info(), repr_type(value))
- raise TraitError(e)
-
- def get_metadata(self, key, default=None):
- """DEPRECATED: Get a metadata value.
-
- Use .metadata[key] or .metadata.get(key, default) instead.
- """
- if key == 'help':
- msg = "use the instance .help string directly, like x.help"
- else:
- msg = "use the instance .metadata dictionary directly, like x.metadata[key] or x.metadata.get(key, default)"
- warn("Deprecated in traitlets 4.1, " + msg, DeprecationWarning, stacklevel=2)
- return self.metadata.get(key, default)
-
- def set_metadata(self, key, value):
- """DEPRECATED: Set a metadata key/value.
-
- Use .metadata[key] = value instead.
- """
- if key == 'help':
- msg = "use the instance .help string directly, like x.help = value"
- else:
- msg = "use the instance .metadata dictionary directly, like x.metadata[key] = value"
- warn("Deprecated in traitlets 4.1, " + msg, DeprecationWarning, stacklevel=2)
- self.metadata[key] = value
-
- def tag(self, **metadata):
- """Sets metadata and returns self.
-
- This allows convenient metadata tagging when initializing the trait, such as:
-
- >>> Int(0).tag(config=True, sync=True)
- """
- maybe_constructor_keywords = set(metadata.keys()).intersection({'help','allow_none', 'read_only', 'default_value'})
- if maybe_constructor_keywords:
- warn('The following attributes are set in using `tag`, but seem to be constructor keywords arguments: %s '%
- maybe_constructor_keywords, UserWarning, stacklevel=2)
-
- self.metadata.update(metadata)
- return self
-
- def default_value_repr(self):
- return repr(self.default_value)
-
-#-----------------------------------------------------------------------------
-# The HasTraits implementation
-#-----------------------------------------------------------------------------
-
-class _CallbackWrapper(object):
- """An object adapting a on_trait_change callback into an observe callback.
-
- The comparison operator __eq__ is implemented to enable removal of wrapped
- callbacks.
- """
-
- def __init__(self, cb):
- self.cb = cb
- # Bound methods have an additional 'self' argument.
- offset = -1 if isinstance(self.cb, types.MethodType) else 0
- self.nargs = len(getargspec(cb)[0]) + offset
- if (self.nargs > 4):
- raise TraitError('a trait changed callback must have 0-4 arguments.')
-
- def __eq__(self, other):
- # The wrapper is equal to the wrapped element
- if isinstance(other, _CallbackWrapper):
- return self.cb == other.cb
- else:
- return self.cb == other
-
- def __call__(self, change):
- # The wrapper is callable
- if self.nargs == 0:
- self.cb()
- elif self.nargs == 1:
- self.cb(change.name)
- elif self.nargs == 2:
- self.cb(change.name, change.new)
- elif self.nargs == 3:
- self.cb(change.name, change.old, change.new)
- elif self.nargs == 4:
- self.cb(change.name, change.old, change.new, change.owner)
-
-def _callback_wrapper(cb):
- if isinstance(cb, _CallbackWrapper):
- return cb
- else:
- return _CallbackWrapper(cb)
-
-
-class MetaHasDescriptors(type):
- """A metaclass for HasDescriptors.
-
- This metaclass makes sure that any TraitType class attributes are
- instantiated and sets their name attribute.
- """
-
- def __new__(mcls, name, bases, classdict):
- """Create the HasDescriptors class."""
- for k, v in classdict.items():
- # ----------------------------------------------------------------
- # Support of deprecated behavior allowing for TraitType types
- # to be used instead of TraitType instances.
- if inspect.isclass(v) and issubclass(v, TraitType):
- warn("Traits should be given as instances, not types (for example, `Int()`, not `Int`)."
- " Passing types is deprecated in traitlets 4.1.",
- DeprecationWarning, stacklevel=2)
- classdict[k] = v()
- # ----------------------------------------------------------------
-
- return super(MetaHasDescriptors, mcls).__new__(mcls, name, bases, classdict)
-
- def __init__(cls, name, bases, classdict):
- """Finish initializing the HasDescriptors class."""
- super(MetaHasDescriptors, cls).__init__(name, bases, classdict)
- cls.setup_class(classdict)
-
- def setup_class(cls, classdict):
- """Setup descriptor instance on the class
-
- This sets the :attr:`this_class` and :attr:`name` attributes of each
- BaseDescriptor in the class dict of the newly created ``cls`` before
- calling their :attr:`class_init` method.
- """
- for k, v in classdict.items():
- if isinstance(v, BaseDescriptor):
- v.class_init(cls, k)
-
-
-class MetaHasTraits(MetaHasDescriptors):
- """A metaclass for HasTraits."""
-
- def setup_class(cls, classdict):
- cls._trait_default_generators = {}
- super(MetaHasTraits, cls).setup_class(classdict)
-
-
-def observe(*names, **kwargs):
- """A decorator which can be used to observe Traits on a class.
-
- The handler passed to the decorator will be called with one ``change``
- dict argument. The change dictionary at least holds a 'type' key and a
- 'name' key, corresponding respectively to the type of notification and the
- name of the attribute that triggered the notification.
-
- Other keys may be passed depending on the value of 'type'. In the case
- where type is 'change', we also have the following keys:
- * ``owner`` : the HasTraits instance
- * ``old`` : the old value of the modified trait attribute
- * ``new`` : the new value of the modified trait attribute
- * ``name`` : the name of the modified trait attribute.
-
- Parameters
- ----------
- *names
- The str names of the Traits to observe on the object.
- type: str, kwarg-only
- The type of event to observe (e.g. 'change')
- """
- if not names:
- raise TypeError("Please specify at least one trait name to observe.")
- for name in names:
- if name is not All and not isinstance(name, six.string_types):
- raise TypeError("trait names to observe must be strings or All, not %r" % name)
- return ObserveHandler(names, type=kwargs.get('type', 'change'))
-
-
-def observe_compat(func):
- """Backward-compatibility shim decorator for observers
-
- Use with:
-
- @observe('name')
- @observe_compat
- def _foo_changed(self, change):
- ...
-
- With this, `super()._foo_changed(self, name, old, new)` in subclasses will still work.
- Allows adoption of new observer API without breaking subclasses that override and super.
- """
- def compatible_observer(self, change_or_name, old=Undefined, new=Undefined):
- if isinstance(change_or_name, dict):
- change = change_or_name
- else:
- clsname = self.__class__.__name__
- warn("A parent of %s._%s_changed has adopted the new (traitlets 4.1) @observe(change) API" % (
- clsname, change_or_name), DeprecationWarning)
- change = Bunch(
- type='change',
- old=old,
- new=new,
- name=change_or_name,
- owner=self,
- )
- return func(self, change)
- return compatible_observer
-
-
-def validate(*names):
- """A decorator to register cross validator of HasTraits object's state
- when a Trait is set.
-
- The handler passed to the decorator must have one ``proposal`` dict argument.
- The proposal dictionary must hold the following keys:
- * ``owner`` : the HasTraits instance
- * ``value`` : the proposed value for the modified trait attribute
- * ``trait`` : the TraitType instance associated with the attribute
-
- Parameters
- ----------
- names
- The str names of the Traits to validate.
-
- Notes
- -----
- Since the owner has access to the ``HasTraits`` instance via the 'owner' key,
- the registered cross validator could potentially make changes to attributes
- of the ``HasTraits`` instance. However, we recommend not to do so. The reason
- is that the cross-validation of attributes may run in arbitrary order when
- exiting the ``hold_trait_notifications`` context, and such changes may not
- commute.
- """
- if not names:
- raise TypeError("Please specify at least one trait name to validate.")
- for name in names:
- if name is not All and not isinstance(name, six.string_types):
- raise TypeError("trait names to validate must be strings or All, not %r" % name)
- return ValidateHandler(names)
-
-
-def default(name):
- """ A decorator which assigns a dynamic default for a Trait on a HasTraits object.
-
- Parameters
- ----------
- name
- The str name of the Trait on the object whose default should be generated.
-
- Notes
- -----
- Unlike observers and validators which are properties of the HasTraits
- instance, default value generators are class-level properties.
-
- Besides, default generators are only invoked if they are registered in
- subclasses of `this_type`.
-
- ::
-
- class A(HasTraits):
- bar = Int()
-
- @default('bar')
- def get_bar_default(self):
- return 11
-
-
- class B(A):
- bar = Float() # This trait ignores the default generator defined in
- # the base class A
-
-
- class C(B):
-
- @default('bar')
- def some_other_default(self): # This default generator should not be
- return 3.0 # ignored since it is defined in a
- # class derived from B.a.this_class.
- """
- if not isinstance(name, six.string_types):
- raise TypeError("Trait name must be a string or All, not %r" % name)
- return DefaultHandler(name)
-
-
-class EventHandler(BaseDescriptor):
-
- def _init_call(self, func):
- self.func = func
- return self
-
- def __call__(self, *args, **kwargs):
- """Pass `*args` and `**kwargs` to the handler's function if it exists."""
- if hasattr(self, 'func'):
- return self.func(*args, **kwargs)
- else:
- return self._init_call(*args, **kwargs)
-
- def __get__(self, inst, cls=None):
- if inst is None:
- return self
- return types.MethodType(self.func, inst)
-
-
-class ObserveHandler(EventHandler):
-
- def __init__(self, names, type):
- self.trait_names = names
- self.type = type
-
- def instance_init(self, inst):
- inst.observe(self, self.trait_names, type=self.type)
-
-
-class ValidateHandler(EventHandler):
-
- def __init__(self, names):
- self.trait_names = names
-
- def instance_init(self, inst):
- inst._register_validator(self, self.trait_names)
-
-
-class DefaultHandler(EventHandler):
-
- def __init__(self, name):
- self.trait_name = name
-
- def class_init(self, cls, name):
- super(DefaultHandler, self).class_init(cls, name)
- cls._trait_default_generators[self.trait_name] = self
-
-
-class HasDescriptors(six.with_metaclass(MetaHasDescriptors, object)):
- """The base class for all classes that have descriptors.
- """
-
- def __new__(cls, *args, **kwargs):
- # This is needed because object.__new__ only accepts
- # the cls argument.
- new_meth = super(HasDescriptors, cls).__new__
- if new_meth is object.__new__:
- inst = new_meth(cls)
- else:
- inst = new_meth(cls, *args, **kwargs)
- inst.setup_instance(*args, **kwargs)
- return inst
-
- def setup_instance(self, *args, **kwargs):
- """
- This is called **before** self.__init__ is called.
- """
- self._cross_validation_lock = False
- cls = self.__class__
- for key in dir(cls):
- # Some descriptors raise AttributeError like zope.interface's
- # __provides__ attributes even though they exist. This causes
- # AttributeErrors even though they are listed in dir(cls).
- try:
- value = getattr(cls, key)
- except AttributeError:
- pass
- else:
- if isinstance(value, BaseDescriptor):
- value.instance_init(self)
-
-
-class HasTraits(six.with_metaclass(MetaHasTraits, HasDescriptors)):
-
- def setup_instance(self, *args, **kwargs):
- self._trait_values = {}
- self._trait_notifiers = {}
- self._trait_validators = {}
- super(HasTraits, self).setup_instance(*args, **kwargs)
-
- def __init__(self, *args, **kwargs):
- # Allow trait values to be set using keyword arguments.
- # We need to use setattr for this to trigger validation and
- # notifications.
- super_args = args
- super_kwargs = {}
- with self.hold_trait_notifications():
- for key, value in kwargs.items():
- if self.has_trait(key):
- setattr(self, key, value)
- else:
- # passthrough args that don't set traits to super
- super_kwargs[key] = value
- try:
- super(HasTraits, self).__init__(*super_args, **super_kwargs)
- except TypeError as e:
- arg_s_list = [ repr(arg) for arg in super_args ]
- for k, v in super_kwargs.items():
- arg_s_list.append("%s=%r" % (k, v))
- arg_s = ', '.join(arg_s_list)
- warn(
- "Passing unrecoginized arguments to super({classname}).__init__({arg_s}).\n"
- "{error}\n"
- "This is deprecated in traitlets 4.2."
- "This error will be raised in a future release of traitlets."
- .format(
- arg_s=arg_s, classname=self.__class__.__name__,
- error=e,
- ),
- DeprecationWarning,
- stacklevel=2,
- )
-
- def __getstate__(self):
- d = self.__dict__.copy()
- # event handlers stored on an instance are
- # expected to be reinstantiated during a
- # recall of instance_init during __setstate__
- d['_trait_notifiers'] = {}
- d['_trait_validators'] = {}
- return d
-
- def __setstate__(self, state):
- self.__dict__ = state.copy()
-
- # event handlers are reassigned to self
- cls = self.__class__
- for key in dir(cls):
- # Some descriptors raise AttributeError like zope.interface's
- # __provides__ attributes even though they exist. This causes
- # AttributeErrors even though they are listed in dir(cls).
- try:
- value = getattr(cls, key)
- except AttributeError:
- pass
- else:
- if isinstance(value, EventHandler):
- value.instance_init(self)
-
- @property
- @contextlib.contextmanager
- def cross_validation_lock(self):
- """
- A contextmanager for running a block with our cross validation lock set
- to True.
-
- At the end of the block, the lock's value is restored to its value
- prior to entering the block.
- """
- if self._cross_validation_lock:
- yield
- return
- else:
- try:
- self._cross_validation_lock = True
- yield
- finally:
- self._cross_validation_lock = False
-
- @contextlib.contextmanager
- def hold_trait_notifications(self):
- """Context manager for bundling trait change notifications and cross
- validation.
-
- Use this when doing multiple trait assignments (init, config), to avoid
- race conditions in trait notifiers requesting other trait values.
- All trait notifications will fire after all values have been assigned.
- """
- if self._cross_validation_lock:
- yield
- return
- else:
- cache = {}
- notify_change = self.notify_change
-
- def compress(past_changes, change):
- """Merges the provided change with the last if possible."""
- if past_changes is None:
- return [change]
- else:
- if past_changes[-1]['type'] == 'change' and change.type == 'change':
- past_changes[-1]['new'] = change.new
- else:
- # In case of changes other than 'change', append the notification.
- past_changes.append(change)
- return past_changes
-
- def hold(change):
- name = change.name
- cache[name] = compress(cache.get(name), change)
-
- try:
- # Replace notify_change with `hold`, caching and compressing
- # notifications, disable cross validation and yield.
- self.notify_change = hold
- self._cross_validation_lock = True
- yield
- # Cross validate final values when context is released.
- for name in list(cache.keys()):
- trait = getattr(self.__class__, name)
- value = trait._cross_validate(self, getattr(self, name))
- self.set_trait(name, value)
- except TraitError as e:
- # Roll back in case of TraitError during final cross validation.
- self.notify_change = lambda x: None
- for name, changes in cache.items():
- for change in changes[::-1]:
- # TODO: Separate in a rollback function per notification type.
- if change.type == 'change':
- if change.old is not Undefined:
- self.set_trait(name, change.old)
- else:
- self._trait_values.pop(name)
- cache = {}
- raise e
- finally:
- self._cross_validation_lock = False
- # Restore method retrieval from class
- del self.notify_change
-
- # trigger delayed notifications
- for changes in cache.values():
- for change in changes:
- self.notify_change(change)
-
- def _notify_trait(self, name, old_value, new_value):
- self.notify_change(Bunch(
- name=name,
- old=old_value,
- new=new_value,
- owner=self,
- type='change',
- ))
-
- def notify_change(self, change):
- if not isinstance(change, Bunch):
- # cast to bunch if given a dict
- change = Bunch(change)
- name, type = change.name, change.type
-
- callables = []
- callables.extend(self._trait_notifiers.get(name, {}).get(type, []))
- callables.extend(self._trait_notifiers.get(name, {}).get(All, []))
- callables.extend(self._trait_notifiers.get(All, {}).get(type, []))
- callables.extend(self._trait_notifiers.get(All, {}).get(All, []))
-
- # Now static ones
- magic_name = '_%s_changed' % name
- if hasattr(self, magic_name):
- class_value = getattr(self.__class__, magic_name)
- if not isinstance(class_value, ObserveHandler):
- _deprecated_method(class_value, self.__class__, magic_name,
- "use @observe and @unobserve instead.")
- cb = getattr(self, magic_name)
- # Only append the magic method if it was not manually registered
- if cb not in callables:
- callables.append(_callback_wrapper(cb))
-
- # Call them all now
- # Traits catches and logs errors here. I allow them to raise
- for c in callables:
- # Bound methods have an additional 'self' argument.
-
- if isinstance(c, _CallbackWrapper):
- c = c.__call__
- elif isinstance(c, EventHandler) and c.name is not None:
- c = getattr(self, c.name)
-
- c(change)
-
- def _add_notifiers(self, handler, name, type):
- if name not in self._trait_notifiers:
- nlist = []
- self._trait_notifiers[name] = {type: nlist}
- else:
- if type not in self._trait_notifiers[name]:
- nlist = []
- self._trait_notifiers[name][type] = nlist
- else:
- nlist = self._trait_notifiers[name][type]
- if handler not in nlist:
- nlist.append(handler)
-
- def _remove_notifiers(self, handler, name, type):
- try:
- if handler is None:
- del self._trait_notifiers[name][type]
- else:
- self._trait_notifiers[name][type].remove(handler)
- except KeyError:
- pass
-
- def on_trait_change(self, handler=None, name=None, remove=False):
- """DEPRECATED: Setup a handler to be called when a trait changes.
-
- This is used to setup dynamic notifications of trait changes.
-
- Static handlers can be created by creating methods on a HasTraits
- subclass with the naming convention '_[traitname]_changed'. Thus,
- to create static handler for the trait 'a', create the method
- _a_changed(self, name, old, new) (fewer arguments can be used, see
- below).
-
- If `remove` is True and `handler` is not specified, all change
- handlers for the specified name are uninstalled.
-
- Parameters
- ----------
- handler : callable, None
- A callable that is called when a trait changes. Its
- signature can be handler(), handler(name), handler(name, new),
- handler(name, old, new), or handler(name, old, new, self).
- name : list, str, None
- If None, the handler will apply to all traits. If a list
- of str, handler will apply to all names in the list. If a
- str, the handler will apply just to that name.
- remove : bool
- If False (the default), then install the handler. If True
- then unintall it.
- """
- warn("on_trait_change is deprecated in traitlets 4.1: use observe instead",
- DeprecationWarning, stacklevel=2)
- if name is None:
- name = All
- if remove:
- self.unobserve(_callback_wrapper(handler), names=name)
- else:
- self.observe(_callback_wrapper(handler), names=name)
-
- def observe(self, handler, names=All, type='change'):
- """Setup a handler to be called when a trait changes.
-
- This is used to setup dynamic notifications of trait changes.
-
- Parameters
- ----------
- handler : callable
- A callable that is called when a trait changes. Its
- signature should be ``handler(change)``, where ``change`` is a
- dictionary. The change dictionary at least holds a 'type' key.
- * ``type``: the type of notification.
- Other keys may be passed depending on the value of 'type'. In the
- case where type is 'change', we also have the following keys:
- * ``owner`` : the HasTraits instance
- * ``old`` : the old value of the modified trait attribute
- * ``new`` : the new value of the modified trait attribute
- * ``name`` : the name of the modified trait attribute.
- names : list, str, All
- If names is All, the handler will apply to all traits. If a list
- of str, handler will apply to all names in the list. If a
- str, the handler will apply just to that name.
- type : str, All (default: 'change')
- The type of notification to filter by. If equal to All, then all
- notifications are passed to the observe handler.
- """
- names = parse_notifier_name(names)
- for n in names:
- self._add_notifiers(handler, n, type)
-
- def unobserve(self, handler, names=All, type='change'):
- """Remove a trait change handler.
-
- This is used to unregister handlers to trait change notifications.
-
- Parameters
- ----------
- handler : callable
- The callable called when a trait attribute changes.
- names : list, str, All (default: All)
- The names of the traits for which the specified handler should be
- uninstalled. If names is All, the specified handler is uninstalled
- from the list of notifiers corresponding to all changes.
- type : str or All (default: 'change')
- The type of notification to filter by. If All, the specified handler
- is uninstalled from the list of notifiers corresponding to all types.
- """
- names = parse_notifier_name(names)
- for n in names:
- self._remove_notifiers(handler, n, type)
-
- def unobserve_all(self, name=All):
- """Remove trait change handlers of any type for the specified name.
- If name is not specified, removes all trait notifiers."""
- if name is All:
- self._trait_notifiers = {}
- else:
- try:
- del self._trait_notifiers[name]
- except KeyError:
- pass
-
- def _register_validator(self, handler, names):
- """Setup a handler to be called when a trait should be cross validated.
-
- This is used to setup dynamic notifications for cross-validation.
-
- If a validator is already registered for any of the provided names, a
- TraitError is raised and no new validator is registered.
-
- Parameters
- ----------
- handler : callable
- A callable that is called when the given trait is cross-validated.
- Its signature is handler(proposal), where proposal is a Bunch (dictionary with attribute access)
- with the following attributes/keys:
- * ``owner`` : the HasTraits instance
- * ``value`` : the proposed value for the modified trait attribute
- * ``trait`` : the TraitType instance associated with the attribute
- names : List of strings
- The names of the traits that should be cross-validated
- """
- for name in names:
- magic_name = '_%s_validate' % name
- if hasattr(self, magic_name):
- class_value = getattr(self.__class__, magic_name)
- if not isinstance(class_value, ValidateHandler):
- _deprecated_method(class_value, self.__class, magic_name,
- "use @validate decorator instead.")
- for name in names:
- self._trait_validators[name] = handler
-
- def add_traits(self, **traits):
- """Dynamically add trait attributes to the HasTraits instance."""
- self.__class__ = type(self.__class__.__name__, (self.__class__,),
- traits)
- for trait in traits.values():
- trait.instance_init(self)
-
- def set_trait(self, name, value):
- """Forcibly sets trait attribute, including read-only attributes."""
- cls = self.__class__
- if not self.has_trait(name):
- raise TraitError("Class %s does not have a trait named %s" %
- (cls.__name__, name))
- else:
- getattr(cls, name).set(self, value)
-
- @classmethod
- def class_trait_names(cls, **metadata):
- """Get a list of all the names of this class' traits.
-
- This method is just like the :meth:`trait_names` method,
- but is unbound.
- """
- return list(cls.class_traits(**metadata))
-
- @classmethod
- def class_traits(cls, **metadata):
- """Get a ``dict`` of all the traits of this class. The dictionary
- is keyed on the name and the values are the TraitType objects.
-
- This method is just like the :meth:`traits` method, but is unbound.
-
- The TraitTypes returned don't know anything about the values
- that the various HasTrait's instances are holding.
-
- The metadata kwargs allow functions to be passed in which
- filter traits based on metadata values. The functions should
- take a single value as an argument and return a boolean. If
- any function returns False, then the trait is not included in
- the output. If a metadata key doesn't exist, None will be passed
- to the function.
- """
- traits = dict([memb for memb in getmembers(cls) if
- isinstance(memb[1], TraitType)])
-
- if len(metadata) == 0:
- return traits
-
- result = {}
- for name, trait in traits.items():
- for meta_name, meta_eval in metadata.items():
- if type(meta_eval) is not types.FunctionType:
- meta_eval = _SimpleTest(meta_eval)
- if not meta_eval(trait.metadata.get(meta_name, None)):
- break
- else:
- result[name] = trait
-
- return result
-
- @classmethod
- def class_own_traits(cls, **metadata):
- """Get a dict of all the traitlets defined on this class, not a parent.
-
- Works like `class_traits`, except for excluding traits from parents.
- """
- sup = super(cls, cls)
- return {n: t for (n, t) in cls.class_traits(**metadata).items()
- if getattr(sup, n, None) is not t}
-
- def has_trait(self, name):
- """Returns True if the object has a trait with the specified name."""
- return isinstance(getattr(self.__class__, name, None), TraitType)
-
- def trait_names(self, **metadata):
- """Get a list of all the names of this class' traits."""
- return list(self.traits(**metadata))
-
- def traits(self, **metadata):
- """Get a ``dict`` of all the traits of this class. The dictionary
- is keyed on the name and the values are the TraitType objects.
-
- The TraitTypes returned don't know anything about the values
- that the various HasTrait's instances are holding.
-
- The metadata kwargs allow functions to be passed in which
- filter traits based on metadata values. The functions should
- take a single value as an argument and return a boolean. If
- any function returns False, then the trait is not included in
- the output. If a metadata key doesn't exist, None will be passed
- to the function.
- """
- traits = dict([memb for memb in getmembers(self.__class__) if
- isinstance(memb[1], TraitType)])
-
- if len(metadata) == 0:
- return traits
-
- result = {}
- for name, trait in traits.items():
- for meta_name, meta_eval in metadata.items():
- if type(meta_eval) is not types.FunctionType:
- meta_eval = _SimpleTest(meta_eval)
- if not meta_eval(trait.metadata.get(meta_name, None)):
- break
- else:
- result[name] = trait
-
- return result
-
- def trait_metadata(self, traitname, key, default=None):
- """Get metadata values for trait by key."""
- try:
- trait = getattr(self.__class__, traitname)
- except AttributeError:
- raise TraitError("Class %s does not have a trait named %s" %
- (self.__class__.__name__, traitname))
- metadata_name = '_' + traitname + '_metadata'
- if hasattr(self, metadata_name) and key in getattr(self, metadata_name):
- return getattr(self, metadata_name).get(key, default)
- else:
- return trait.metadata.get(key, default)
-
- @classmethod
- def class_own_trait_events(cls, name):
- """Get a dict of all event handlers defined on this class, not a parent.
-
- Works like ``event_handlers``, except for excluding traits from parents.
- """
- sup = super(cls, cls)
- return {n: e for (n, e) in cls.events(name).items()
- if getattr(sup, n, None) is not e}
-
- @classmethod
- def trait_events(cls, name=None):
- """Get a ``dict`` of all the event handlers of this class.
-
- Parameters
- ----------
- name: str (default: None)
- The name of a trait of this class. If name is ``None`` then all
- the event handlers of this class will be returned instead.
-
- Returns
- -------
- The event handlers associated with a trait name, or all event handlers.
- """
- events = {}
- for k, v in getmembers(cls):
- if isinstance(v, EventHandler):
- if name is None:
- events[k] = v
- elif name in v.trait_names:
- events[k] = v
- elif hasattr(v, 'tags'):
- if cls.trait_names(**v.tags):
- events[k] = v
- return events
-
-#-----------------------------------------------------------------------------
-# Actual TraitTypes implementations/subclasses
-#-----------------------------------------------------------------------------
-
-#-----------------------------------------------------------------------------
-# TraitTypes subclasses for handling classes and instances of classes
-#-----------------------------------------------------------------------------
-
-
-class ClassBasedTraitType(TraitType):
- """
- A trait with error reporting and string -> type resolution for Type,
- Instance and This.
- """
-
- def _resolve_string(self, string):
- """
- Resolve a string supplied for a type into an actual object.
- """
- return import_item(string)
-
- def error(self, obj, value):
- kind = type(value)
- if six.PY2 and kind is InstanceType:
- msg = 'class %s' % value.__class__.__name__
- else:
- msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
-
- if obj is not None:
- e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
- % (self.name, class_of(obj),
- self.info(), msg)
- else:
- e = "The '%s' trait must be %s, but a value of %r was specified." \
- % (self.name, self.info(), msg)
-
- raise TraitError(e)
-
-
-class Type(ClassBasedTraitType):
- """A trait whose value must be a subclass of a specified class."""
-
- def __init__ (self, default_value=Undefined, klass=None, **kwargs):
- """Construct a Type trait
-
- A Type trait specifies that its values must be subclasses of
- a particular class.
-
- If only ``default_value`` is given, it is used for the ``klass`` as
- well. If neither are given, both default to ``object``.
-
- Parameters
- ----------
- default_value : class, str or None
- The default value must be a subclass of klass. If an str,
- the str must be a fully specified class name, like 'foo.bar.Bah'.
- The string is resolved into real class, when the parent
- :class:`HasTraits` class is instantiated.
- klass : class, str [ default object ]
- Values of this trait must be a subclass of klass. The klass
- may be specified in a string like: 'foo.bar.MyClass'.
- The string is resolved into real class, when the parent
- :class:`HasTraits` class is instantiated.
- allow_none : bool [ default False ]
- Indicates whether None is allowed as an assignable value.
- """
- if default_value is Undefined:
- new_default_value = object if (klass is None) else klass
- else:
- new_default_value = default_value
-
- if klass is None:
- if (default_value is None) or (default_value is Undefined):
- klass = object
- else:
- klass = default_value
-
- if not (inspect.isclass(klass) or isinstance(klass, six.string_types)):
- raise TraitError("A Type trait must specify a class.")
-
- self.klass = klass
-
- super(Type, self).__init__(new_default_value, **kwargs)
-
- def validate(self, obj, value):
- """Validates that the value is a valid object instance."""
- if isinstance(value, six.string_types):
- try:
- value = self._resolve_string(value)
- except ImportError:
- raise TraitError("The '%s' trait of %s instance must be a type, but "
- "%r could not be imported" % (self.name, obj, value))
- try:
- if issubclass(value, self.klass):
- return value
- except:
- pass
-
- self.error(obj, value)
-
- def info(self):
- """ Returns a description of the trait."""
- if isinstance(self.klass, six.string_types):
- klass = self.klass
- else:
- klass = self.klass.__module__ + '.' + self.klass.__name__
- result = "a subclass of '%s'" % klass
- if self.allow_none:
- return result + ' or None'
- return result
-
- def instance_init(self, obj):
- self._resolve_classes()
- super(Type, self).instance_init(obj)
-
- def _resolve_classes(self):
- if isinstance(self.klass, six.string_types):
- self.klass = self._resolve_string(self.klass)
- if isinstance(self.default_value, six.string_types):
- self.default_value = self._resolve_string(self.default_value)
-
- def default_value_repr(self):
- value = self.default_value
- if isinstance(value, six.string_types):
- return repr(value)
- else:
- return repr('{}.{}'.format(value.__module__, value.__name__))
-
-
-class Instance(ClassBasedTraitType):
- """A trait whose value must be an instance of a specified class.
-
- The value can also be an instance of a subclass of the specified class.
-
- Subclasses can declare default classes by overriding the klass attribute
- """
-
- klass = None
-
- def __init__(self, klass=None, args=None, kw=None, **kwargs):
- """Construct an Instance trait.
-
- This trait allows values that are instances of a particular
- class or its subclasses. Our implementation is quite different
- from that of enthough.traits as we don't allow instances to be used
- for klass and we handle the ``args`` and ``kw`` arguments differently.
-
- Parameters
- ----------
- klass : class, str
- The class that forms the basis for the trait. Class names
- can also be specified as strings, like 'foo.bar.Bar'.
- args : tuple
- Positional arguments for generating the default value.
- kw : dict
- Keyword arguments for generating the default value.
- allow_none : bool [ default False ]
- Indicates whether None is allowed as a value.
-
- Notes
- -----
- If both ``args`` and ``kw`` are None, then the default value is None.
- If ``args`` is a tuple and ``kw`` is a dict, then the default is
- created as ``klass(*args, **kw)``. If exactly one of ``args`` or ``kw`` is
- None, the None is replaced by ``()`` or ``{}``, respectively.
- """
- if klass is None:
- klass = self.klass
-
- if (klass is not None) and (inspect.isclass(klass) or isinstance(klass, six.string_types)):
- self.klass = klass
- else:
- raise TraitError('The klass attribute must be a class'
- ' not: %r' % klass)
-
- if (kw is not None) and not isinstance(kw, dict):
- raise TraitError("The 'kw' argument must be a dict or None.")
- if (args is not None) and not isinstance(args, tuple):
- raise TraitError("The 'args' argument must be a tuple or None.")
-
- self.default_args = args
- self.default_kwargs = kw
-
- super(Instance, self).__init__(**kwargs)
-
- def validate(self, obj, value):
- if isinstance(value, self.klass):
- return value
- else:
- self.error(obj, value)
-
- def info(self):
- if isinstance(self.klass, six.string_types):
- klass = self.klass
- else:
- klass = self.klass.__name__
- result = class_of(klass)
- if self.allow_none:
- return result + ' or None'
-
- return result
-
- def instance_init(self, obj):
- self._resolve_classes()
- super(Instance, self).instance_init(obj)
-
- def _resolve_classes(self):
- if isinstance(self.klass, six.string_types):
- self.klass = self._resolve_string(self.klass)
-
- def make_dynamic_default(self):
- if (self.default_args is None) and (self.default_kwargs is None):
- return None
- return self.klass(*(self.default_args or ()),
- **(self.default_kwargs or {}))
-
- def default_value_repr(self):
- return repr(self.make_dynamic_default())
-
-
-class ForwardDeclaredMixin(object):
- """
- Mixin for forward-declared versions of Instance and Type.
- """
- def _resolve_string(self, string):
- """
- Find the specified class name by looking for it in the module in which
- our this_class attribute was defined.
- """
- modname = self.this_class.__module__
- return import_item('.'.join([modname, string]))
-
-
-class ForwardDeclaredType(ForwardDeclaredMixin, Type):
- """
- Forward-declared version of Type.
- """
- pass
-
-
-class ForwardDeclaredInstance(ForwardDeclaredMixin, Instance):
- """
- Forward-declared version of Instance.
- """
- pass
-
-
-class This(ClassBasedTraitType):
- """A trait for instances of the class containing this trait.
-
- Because how how and when class bodies are executed, the ``This``
- trait can only have a default value of None. This, and because we
- always validate default values, ``allow_none`` is *always* true.
- """
-
- info_text = 'an instance of the same type as the receiver or None'
-
- def __init__(self, **kwargs):
- super(This, self).__init__(None, **kwargs)
-
- def validate(self, obj, value):
- # What if value is a superclass of obj.__class__? This is
- # complicated if it was the superclass that defined the This
- # trait.
- if isinstance(value, self.this_class) or (value is None):
- return value
- else:
- self.error(obj, value)
-
-
-class Union(TraitType):
- """A trait type representing a Union type."""
-
- def __init__(self, trait_types, **kwargs):
- """Construct a Union trait.
-
- This trait allows values that are allowed by at least one of the
- specified trait types. A Union traitlet cannot have metadata on
- its own, besides the metadata of the listed types.
-
- Parameters
- ----------
- trait_types: sequence
- The list of trait types of length at least 1.
-
- Notes
- -----
- Union([Float(), Bool(), Int()]) attempts to validate the provided values
- with the validation function of Float, then Bool, and finally Int.
- """
- self.trait_types = trait_types
- self.info_text = " or ".join([tt.info() for tt in self.trait_types])
- super(Union, self).__init__(**kwargs)
-
- def class_init(self, cls, name):
- for trait_type in self.trait_types:
- trait_type.class_init(cls, None)
- super(Union, self).class_init(cls, name)
-
- def instance_init(self, obj):
- for trait_type in self.trait_types:
- trait_type.instance_init(obj)
- super(Union, self).instance_init(obj)
-
- def validate(self, obj, value):
- with obj.cross_validation_lock:
- for trait_type in self.trait_types:
- try:
- v = trait_type._validate(obj, value)
- # In the case of an element trait, the name is None
- if self.name is not None:
- setattr(obj, '_' + self.name + '_metadata', trait_type.metadata)
- return v
- except TraitError:
- continue
- self.error(obj, value)
-
- def __or__(self, other):
- if isinstance(other, Union):
- return Union(self.trait_types + other.trait_types)
- else:
- return Union(self.trait_types + [other])
-
- def make_dynamic_default(self):
- if self.default_value is not Undefined:
- return self.default_value
- for trait_type in self.trait_types:
- if trait_type.default_value is not Undefined:
- return trait_type.default_value
- elif hasattr(trait_type, 'make_dynamic_default'):
- return trait_type.make_dynamic_default()
-
-
-#-----------------------------------------------------------------------------
-# Basic TraitTypes implementations/subclasses
-#-----------------------------------------------------------------------------
-
-
-class Any(TraitType):
- """A trait which allows any value."""
- default_value = None
- info_text = 'any value'
-
-
-def _validate_bounds(trait, obj, value):
- """
- Validate that a number to be applied to a trait is between bounds.
-
- If value is not between min_bound and max_bound, this raises a
- TraitError with an error message appropriate for this trait.
- """
- if trait.min is not None and value < trait.min:
- raise TraitError(
- "The value of the '{name}' trait of {klass} instance should "
- "not be less than {min_bound}, but a value of {value} was "
- "specified".format(
- name=trait.name, klass=class_of(obj),
- value=value, min_bound=trait.min))
- if trait.max is not None and value > trait.max:
- raise TraitError(
- "The value of the '{name}' trait of {klass} instance should "
- "not be greater than {max_bound}, but a value of {value} was "
- "specified".format(
- name=trait.name, klass=class_of(obj),
- value=value, max_bound=trait.max))
- return value
-
-
-class Int(TraitType):
- """An int trait."""
-
- default_value = 0
- info_text = 'an int'
-
- def __init__(self, default_value=Undefined, allow_none=False, **kwargs):
- self.min = kwargs.pop('min', None)
- self.max = kwargs.pop('max', None)
- super(Int, self).__init__(default_value=default_value,
- allow_none=allow_none, **kwargs)
-
- def validate(self, obj, value):
- if not isinstance(value, int):
- self.error(obj, value)
- return _validate_bounds(self, obj, value)
-
-
-class CInt(Int):
- """A casting version of the int trait."""
-
- def validate(self, obj, value):
- try:
- value = int(value)
- except:
- self.error(obj, value)
- return _validate_bounds(self, obj, value)
-
-
-if six.PY2:
- class Long(TraitType):
- """A long integer trait."""
-
- default_value = 0
- info_text = 'a long'
-
- def __init__(self, default_value=Undefined, allow_none=False, **kwargs):
- self.min = kwargs.pop('min', None)
- self.max = kwargs.pop('max', None)
- super(Long, self).__init__(
- default_value=default_value,
- allow_none=allow_none, **kwargs)
-
- def _validate_long(self, obj, value):
- if isinstance(value, long):
- return value
- if isinstance(value, int):
- return long(value)
- self.error(obj, value)
-
- def validate(self, obj, value):
- value = self._validate_long(obj, value)
- return _validate_bounds(self, obj, value)
-
-
- class CLong(Long):
- """A casting version of the long integer trait."""
-
- def validate(self, obj, value):
- try:
- value = long(value)
- except:
- self.error(obj, value)
- return _validate_bounds(self, obj, value)
-
-
- class Integer(TraitType):
- """An integer trait.
-
- Longs that are unnecessary (<= sys.maxint) are cast to ints."""
-
- default_value = 0
- info_text = 'an integer'
-
- def __init__(self, default_value=Undefined, allow_none=False, **kwargs):
- self.min = kwargs.pop('min', None)
- self.max = kwargs.pop('max', None)
- super(Integer, self).__init__(
- default_value=default_value,
- allow_none=allow_none, **kwargs)
-
- def _validate_int(self, obj, value):
- if isinstance(value, int):
- return value
- if isinstance(value, long):
- # downcast longs that fit in int:
- # note that int(n > sys.maxint) returns a long, so
- # we don't need a condition on this cast
- return int(value)
- if sys.platform == "cli":
- from System import Int64
- if isinstance(value, Int64):
- return int(value)
- self.error(obj, value)
-
- def validate(self, obj, value):
- value = self._validate_int(obj, value)
- return _validate_bounds(self, obj, value)
-
-else:
- Long, CLong = Int, CInt
- Integer = Int
-
-
-class Float(TraitType):
- """A float trait."""
-
- default_value = 0.0
- info_text = 'a float'
-
- def __init__(self, default_value=Undefined, allow_none=False, **kwargs):
- self.min = kwargs.pop('min', -float('inf'))
- self.max = kwargs.pop('max', float('inf'))
- super(Float, self).__init__(default_value=default_value,
- allow_none=allow_none, **kwargs)
-
- def validate(self, obj, value):
- if isinstance(value, int):
- value = float(value)
- if not isinstance(value, float):
- self.error(obj, value)
- return _validate_bounds(self, obj, value)
-
-
-class CFloat(Float):
- """A casting version of the float trait."""
-
- def validate(self, obj, value):
- try:
- value = float(value)
- except:
- self.error(obj, value)
- return _validate_bounds(self, obj, value)
-
-
-class Complex(TraitType):
- """A trait for complex numbers."""
-
- default_value = 0.0 + 0.0j
- info_text = 'a complex number'
-
- def validate(self, obj, value):
- if isinstance(value, complex):
- return value
- if isinstance(value, (float, int)):
- return complex(value)
- self.error(obj, value)
-
-
-class CComplex(Complex):
- """A casting version of the complex number trait."""
-
- def validate (self, obj, value):
- try:
- return complex(value)
- except:
- self.error(obj, value)
-
-# We should always be explicit about whether we're using bytes or unicode, both
-# for Python 3 conversion and for reliable unicode behaviour on Python 2. So
-# we don't have a Str type.
-class Bytes(TraitType):
- """A trait for byte strings."""
-
- default_value = b''
- info_text = 'a bytes object'
-
- def validate(self, obj, value):
- if isinstance(value, bytes):
- return value
- self.error(obj, value)
-
-
-class CBytes(Bytes):
- """A casting version of the byte string trait."""
-
- def validate(self, obj, value):
- try:
- return bytes(value)
- except:
- self.error(obj, value)
-
-
-class Unicode(TraitType):
- """A trait for unicode strings."""
-
- default_value = u''
- info_text = 'a unicode string'
-
- def validate(self, obj, value):
- if isinstance(value, six.text_type):
- return value
- if isinstance(value, bytes):
- try:
- return value.decode('ascii', 'strict')
- except UnicodeDecodeError:
- msg = "Could not decode {!r} for unicode trait '{}' of {} instance."
- raise TraitError(msg.format(value, self.name, class_of(obj)))
- self.error(obj, value)
-
-
-class CUnicode(Unicode):
- """A casting version of the unicode trait."""
-
- def validate(self, obj, value):
- try:
- return six.text_type(value)
- except:
- self.error(obj, value)
-
-
-class ObjectName(TraitType):
- """A string holding a valid object name in this version of Python.
-
- This does not check that the name exists in any scope."""
- info_text = "a valid object identifier in Python"
-
- if six.PY2:
- # Python 2:
- def coerce_str(self, obj, value):
- "In Python 2, coerce ascii-only unicode to str"
- if isinstance(value, unicode):
- try:
- return str(value)
- except UnicodeEncodeError:
- self.error(obj, value)
- return value
- else:
- coerce_str = staticmethod(lambda _,s: s)
-
- def validate(self, obj, value):
- value = self.coerce_str(obj, value)
-
- if isinstance(value, six.string_types) and isidentifier(value):
- return value
- self.error(obj, value)
-
-class DottedObjectName(ObjectName):
- """A string holding a valid dotted object name in Python, such as A.b3._c"""
- def validate(self, obj, value):
- value = self.coerce_str(obj, value)
-
- if isinstance(value, six.string_types) and all(isidentifier(a)
- for a in value.split('.')):
- return value
- self.error(obj, value)
-
-
-class Bool(TraitType):
- """A boolean (True, False) trait."""
-
- default_value = False
- info_text = 'a boolean'
-
- def validate(self, obj, value):
- if isinstance(value, bool):
- return value
- self.error(obj, value)
-
-
-class CBool(Bool):
- """A casting version of the boolean trait."""
-
- def validate(self, obj, value):
- try:
- return bool(value)
- except:
- self.error(obj, value)
-
-
-class Enum(TraitType):
- """An enum whose value must be in a given sequence."""
-
- def __init__(self, values, default_value=Undefined, **kwargs):
- self.values = values
- if kwargs.get('allow_none', False) and default_value is Undefined:
- default_value = None
- super(Enum, self).__init__(default_value, **kwargs)
-
- def validate(self, obj, value):
- if value in self.values:
- return value
- self.error(obj, value)
-
- def info(self):
- """ Returns a description of the trait."""
- result = 'any of ' + repr(self.values)
- if self.allow_none:
- return result + ' or None'
- return result
-
-class CaselessStrEnum(Enum):
- """An enum of strings where the case should be ignored."""
-
- def __init__(self, values, default_value=Undefined, **kwargs):
- values = [cast_unicode_py2(value) for value in values]
- super(CaselessStrEnum, self).__init__(values, default_value=default_value, **kwargs)
-
- def validate(self, obj, value):
- if isinstance(value, str):
- value = cast_unicode_py2(value)
- if not isinstance(value, six.string_types):
- self.error(obj, value)
-
- for v in self.values:
- if v.lower() == value.lower():
- return v
- self.error(obj, value)
-
-class Container(Instance):
- """An instance of a container (list, set, etc.)
-
- To be subclassed by overriding klass.
- """
- klass = None
- _cast_types = ()
- _valid_defaults = SequenceTypes
- _trait = None
-
- def __init__(self, trait=None, default_value=None, **kwargs):
- """Create a container trait type from a list, set, or tuple.
-
- The default value is created by doing ``List(default_value)``,
- which creates a copy of the ``default_value``.
-
- ``trait`` can be specified, which restricts the type of elements
- in the container to that TraitType.
-
- If only one arg is given and it is not a Trait, it is taken as
- ``default_value``:
-
- ``c = List([1, 2, 3])``
-
- Parameters
- ----------
-
- trait : TraitType [ optional ]
- the type for restricting the contents of the Container. If unspecified,
- types are not checked.
-
- default_value : SequenceType [ optional ]
- The default value for the Trait. Must be list/tuple/set, and
- will be cast to the container type.
-
- allow_none : bool [ default False ]
- Whether to allow the value to be None
-
- **kwargs : any
- further keys for extensions to the Trait (e.g. config)
-
- """
- # allow List([values]):
- if default_value is None and not is_trait(trait):
- default_value = trait
- trait = None
-
- if default_value is None:
- args = ()
- elif isinstance(default_value, self._valid_defaults):
- args = (default_value,)
- else:
- raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
-
- if is_trait(trait):
- if isinstance(trait, type):
- warn("Traits should be given as instances, not types (for example, `Int()`, not `Int`)."
- " Passing types is deprecated in traitlets 4.1.",
- DeprecationWarning, stacklevel=3)
- self._trait = trait() if isinstance(trait, type) else trait
- elif trait is not None:
- raise TypeError("`trait` must be a Trait or None, got %s" % repr_type(trait))
-
- super(Container,self).__init__(klass=self.klass, args=args, **kwargs)
-
- def element_error(self, obj, element, validator):
- e = "Element of the '%s' trait of %s instance must be %s, but a value of %s was specified." \
- % (self.name, class_of(obj), validator.info(), repr_type(element))
- raise TraitError(e)
-
- def validate(self, obj, value):
- if isinstance(value, self._cast_types):
- value = self.klass(value)
- value = super(Container, self).validate(obj, value)
- if value is None:
- return value
-
- value = self.validate_elements(obj, value)
-
- return value
-
- def validate_elements(self, obj, value):
- validated = []
- if self._trait is None or isinstance(self._trait, Any):
- return value
- for v in value:
- try:
- v = self._trait._validate(obj, v)
- except TraitError:
- self.element_error(obj, v, self._trait)
- else:
- validated.append(v)
- return self.klass(validated)
-
- def class_init(self, cls, name):
- if isinstance(self._trait, TraitType):
- self._trait.class_init(cls, None)
- super(Container, self).class_init(cls, name)
-
- def instance_init(self, obj):
- if isinstance(self._trait, TraitType):
- self._trait.instance_init(obj)
- super(Container, self).instance_init(obj)
-
-
-class List(Container):
- """An instance of a Python list."""
- klass = list
- _cast_types = (tuple,)
-
- def __init__(self, trait=None, default_value=None, minlen=0, maxlen=sys.maxsize, **kwargs):
- """Create a List trait type from a list, set, or tuple.
-
- The default value is created by doing ``list(default_value)``,
- which creates a copy of the ``default_value``.
-
- ``trait`` can be specified, which restricts the type of elements
- in the container to that TraitType.
-
- If only one arg is given and it is not a Trait, it is taken as
- ``default_value``:
-
- ``c = List([1, 2, 3])``
-
- Parameters
- ----------
-
- trait : TraitType [ optional ]
- the type for restricting the contents of the Container.
- If unspecified, types are not checked.
-
- default_value : SequenceType [ optional ]
- The default value for the Trait. Must be list/tuple/set, and
- will be cast to the container type.
-
- minlen : Int [ default 0 ]
- The minimum length of the input list
-
- maxlen : Int [ default sys.maxsize ]
- The maximum length of the input list
- """
- self._minlen = minlen
- self._maxlen = maxlen
- super(List, self).__init__(trait=trait, default_value=default_value,
- **kwargs)
-
- def length_error(self, obj, value):
- e = "The '%s' trait of %s instance must be of length %i <= L <= %i, but a value of %s was specified." \
- % (self.name, class_of(obj), self._minlen, self._maxlen, value)
- raise TraitError(e)
-
- def validate_elements(self, obj, value):
- length = len(value)
- if length < self._minlen or length > self._maxlen:
- self.length_error(obj, value)
-
- return super(List, self).validate_elements(obj, value)
-
- def validate(self, obj, value):
- value = super(List, self).validate(obj, value)
- value = self.validate_elements(obj, value)
- return value
-
-
-class Set(List):
- """An instance of a Python set."""
- klass = set
- _cast_types = (tuple, list)
-
- # Redefine __init__ just to make the docstring more accurate.
- def __init__(self, trait=None, default_value=None, minlen=0, maxlen=sys.maxsize,
- **kwargs):
- """Create a Set trait type from a list, set, or tuple.
-
- The default value is created by doing ``set(default_value)``,
- which creates a copy of the ``default_value``.
-
- ``trait`` can be specified, which restricts the type of elements
- in the container to that TraitType.
-
- If only one arg is given and it is not a Trait, it is taken as
- ``default_value``:
-
- ``c = Set({1, 2, 3})``
-
- Parameters
- ----------
-
- trait : TraitType [ optional ]
- the type for restricting the contents of the Container.
- If unspecified, types are not checked.
-
- default_value : SequenceType [ optional ]
- The default value for the Trait. Must be list/tuple/set, and
- will be cast to the container type.
-
- minlen : Int [ default 0 ]
- The minimum length of the input list
-
- maxlen : Int [ default sys.maxsize ]
- The maximum length of the input list
- """
- super(Set, self).__init__(trait, default_value, minlen, maxlen, **kwargs)
-
-
-class Tuple(Container):
- """An instance of a Python tuple."""
- klass = tuple
- _cast_types = (list,)
-
- def __init__(self, *traits, **kwargs):
- """Create a tuple from a list, set, or tuple.
-
- Create a fixed-type tuple with Traits:
-
- ``t = Tuple(Int(), Str(), CStr())``
-
- would be length 3, with Int,Str,CStr for each element.
-
- If only one arg is given and it is not a Trait, it is taken as
- default_value:
-
- ``t = Tuple((1, 2, 3))``
-
- Otherwise, ``default_value`` *must* be specified by keyword.
-
- Parameters
- ----------
-
- `*traits` : TraitTypes [ optional ]
- the types for restricting the contents of the Tuple. If unspecified,
- types are not checked. If specified, then each positional argument
- corresponds to an element of the tuple. Tuples defined with traits
- are of fixed length.
-
- default_value : SequenceType [ optional ]
- The default value for the Tuple. Must be list/tuple/set, and
- will be cast to a tuple. If ``traits`` are specified,
- ``default_value`` must conform to the shape and type they specify.
- """
- default_value = kwargs.pop('default_value', Undefined)
- # allow Tuple((values,)):
- if len(traits) == 1 and default_value is Undefined and not is_trait(traits[0]):
- default_value = traits[0]
- traits = ()
-
- if default_value is Undefined:
- args = ()
- elif isinstance(default_value, self._valid_defaults):
- args = (default_value,)
- else:
- raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
-
- self._traits = []
- for trait in traits:
- if isinstance(trait, type):
- warn("Traits should be given as instances, not types (for example, `Int()`, not `Int`)"
- " Passing types is deprecated in traitlets 4.1.",
- DeprecationWarning, stacklevel=2)
- t = trait() if isinstance(trait, type) else trait
- self._traits.append(t)
-
- if self._traits and default_value is None:
- # don't allow default to be an empty container if length is specified
- args = None
- super(Container,self).__init__(klass=self.klass, args=args, **kwargs)
-
- def validate_elements(self, obj, value):
- if not self._traits:
- # nothing to validate
- return value
- if len(value) != len(self._traits):
- e = "The '%s' trait of %s instance requires %i elements, but a value of %s was specified." \
- % (self.name, class_of(obj), len(self._traits), repr_type(value))
- raise TraitError(e)
-
- validated = []
- for t, v in zip(self._traits, value):
- try:
- v = t._validate(obj, v)
- except TraitError:
- self.element_error(obj, v, t)
- else:
- validated.append(v)
- return tuple(validated)
-
- def class_init(self, cls, name):
- for trait in self._traits:
- if isinstance(trait, TraitType):
- trait.class_init(cls, None)
- super(Container, self).class_init(cls, name)
-
- def instance_init(self, obj):
- for trait in self._traits:
- if isinstance(trait, TraitType):
- trait.instance_init(obj)
- super(Container, self).instance_init(obj)
-
-
-class Dict(Instance):
- """An instance of a Python dict."""
- _trait = None
-
- def __init__(self, trait=None, traits=None, default_value=Undefined,
- **kwargs):
- """Create a dict trait type from a Python dict.
-
- The default value is created by doing ``dict(default_value)``,
- which creates a copy of the ``default_value``.
-
- Parameters
- ----------
-
- trait : TraitType [ optional ]
- The specified trait type to check and use to restrict contents of
- the Container. If unspecified, trait types are not checked.
-
- traits : Dictionary of trait types [ optional ]
- A Python dictionary containing the types that are valid for
- restricting the content of the Dict Container for certain keys.
-
- default_value : SequenceType [ optional ]
- The default value for the Dict. Must be dict, tuple, or None, and
- will be cast to a dict if not None. If `trait` is specified, the
- `default_value` must conform to the constraints it specifies.
- """
- # Handling positional arguments
- if default_value is Undefined and trait is not None:
- if not is_trait(trait):
- default_value = trait
- trait = None
-
- # Handling default value
- if default_value is Undefined:
- default_value = {}
- if default_value is None:
- args = None
- elif isinstance(default_value, dict):
- args = (default_value,)
- elif isinstance(default_value, SequenceTypes):
- args = (default_value,)
- else:
- raise TypeError('default value of Dict was %s' % default_value)
-
- # Case where a type of TraitType is provided rather than an instance
- if is_trait(trait):
- if isinstance(trait, type):
- warn("Traits should be given as instances, not types (for example, `Int()`, not `Int`)"
- " Passing types is deprecated in traitlets 4.1.",
- DeprecationWarning, stacklevel=2)
- self._trait = trait() if isinstance(trait, type) else trait
- elif trait is not None:
- raise TypeError("`trait` must be a Trait or None, got %s" % repr_type(trait))
-
- self._traits = traits
-
- super(Dict, self).__init__(klass=dict, args=args, **kwargs)
-
- def element_error(self, obj, element, validator):
- e = "Element of the '%s' trait of %s instance must be %s, but a value of %s was specified." \
- % (self.name, class_of(obj), validator.info(), repr_type(element))
- raise TraitError(e)
-
- def validate(self, obj, value):
- value = super(Dict, self).validate(obj, value)
- if value is None:
- return value
- value = self.validate_elements(obj, value)
- return value
-
- def validate_elements(self, obj, value):
- use_dict = bool(self._traits)
- default_to = (self._trait or Any())
- if not use_dict and isinstance(default_to, Any):
- return value
-
- validated = {}
- for key in value:
- if use_dict and key in self._traits:
- validate_with = self._traits[key]
- else:
- validate_with = default_to
- try:
- v = value[key]
- if not isinstance(validate_with, Any):
- v = validate_with._validate(obj, v)
- except TraitError:
- self.element_error(obj, v, validate_with)
- else:
- validated[key] = v
-
- return self.klass(validated)
-
- def class_init(self, cls, name):
- if isinstance(self._trait, TraitType):
- self._trait.class_init(cls, None)
- if self._traits is not None:
- for trait in self._traits.values():
- trait.class_init(cls, None)
- super(Dict, self).class_init(cls, name)
-
- def instance_init(self, obj):
- if isinstance(self._trait, TraitType):
- self._trait.instance_init(obj)
- if self._traits is not None:
- for trait in self._traits.values():
- trait.instance_init(obj)
- super(Dict, self).instance_init(obj)
-
-
-class TCPAddress(TraitType):
- """A trait for an (ip, port) tuple.
-
- This allows for both IPv4 IP addresses as well as hostnames.
- """
-
- default_value = ('127.0.0.1', 0)
- info_text = 'an (ip, port) tuple'
-
- def validate(self, obj, value):
- if isinstance(value, tuple):
- if len(value) == 2:
- if isinstance(value[0], six.string_types) and isinstance(value[1], int):
- port = value[1]
- if port >= 0 and port <= 65535:
- return value
- self.error(obj, value)
-
-class CRegExp(TraitType):
- """A casting compiled regular expression trait.
-
- Accepts both strings and compiled regular expressions. The resulting
- attribute will be a compiled regular expression."""
-
- info_text = 'a regular expression'
-
- def validate(self, obj, value):
- try:
- return re.compile(value)
- except:
- self.error(obj, value)
-
-
-class UseEnum(TraitType):
- """Use a Enum class as model for the data type description.
- Note that if no default-value is provided, the first enum-value is used
- as default-value.
-
- .. sourcecode:: python
-
- # -- SINCE: Python 3.4 (or install backport: pip install enum34)
- import enum
- from traitlets import HasTraits, UseEnum
-
- class Color(enum.Enum):
- red = 1 # -- IMPLICIT: default_value
- blue = 2
- green = 3
-
- class MyEntity(HasTraits):
- color = UseEnum(Color, default_value=Color.blue)
-
- entity = MyEntity(color=Color.red)
- entity.color = Color.green # USE: Enum-value (preferred)
- entity.color = "green" # USE: name (as string)
- entity.color = "Color.green" # USE: scoped-name (as string)
- entity.color = 3 # USE: number (as int)
- assert entity.color is Color.green
- """
- default_value = None
- info_text = "Trait type adapter to a Enum class"
-
- def __init__(self, enum_class, default_value=None, **kwargs):
- assert issubclass(enum_class, enum.Enum), \
- "REQUIRE: enum.Enum, but was: %r" % enum_class
- allow_none = kwargs.get("allow_none", False)
- if default_value is None and not allow_none:
- default_value = list(enum_class.__members__.values())[0]
- super(UseEnum, self).__init__(default_value=default_value, **kwargs)
- self.enum_class = enum_class
- self.name_prefix = enum_class.__name__ + "."
-
- def select_by_number(self, value, default=Undefined):
- """Selects enum-value by using its number-constant."""
- assert isinstance(value, int)
- enum_members = self.enum_class.__members__
- for enum_item in enum_members.values():
- if enum_item.value == value:
- return enum_item
- # -- NOT FOUND:
- return default
-
- def select_by_name(self, value, default=Undefined):
- """Selects enum-value by using its name or scoped-name."""
- assert isinstance(value, six.string_types)
- if value.startswith(self.name_prefix):
- # -- SUPPORT SCOPED-NAMES, like: "Color.red" => "red"
- value = value.replace(self.name_prefix, "", 1)
- return self.enum_class.__members__.get(value, default)
-
- def validate(self, obj, value):
- if isinstance(value, self.enum_class):
- return value
- elif isinstance(value, int):
- # -- CONVERT: number => enum_value (item)
- value2 = self.select_by_number(value)
- if value2 is not Undefined:
- return value2
- elif isinstance(value, six.string_types):
- # -- CONVERT: name or scoped_name (as string) => enum_value (item)
- value2 = self.select_by_name(value)
- if value2 is not Undefined:
- return value2
- elif value is None:
- if self.allow_none:
- return None
- else:
- return self.default_value
- self.error(obj, value)
-
- def info(self):
- """Returns a description of this Enum trait (in case of errors)."""
- result = "Any of: %s" % ", ".join(self.enum_class.__members__.keys())
- if self.allow_none:
- return result + " or None"
- return result
diff --git a/contrib/python/traitlets/py2/traitlets/utils/__init__.py b/contrib/python/traitlets/py2/traitlets/utils/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/contrib/python/traitlets/py2/traitlets/utils/__init__.py
+++ /dev/null
diff --git a/contrib/python/traitlets/py2/traitlets/utils/bunch.py b/contrib/python/traitlets/py2/traitlets/utils/bunch.py
deleted file mode 100644
index 2edb830ad63..00000000000
--- a/contrib/python/traitlets/py2/traitlets/utils/bunch.py
+++ /dev/null
@@ -1,25 +0,0 @@
-"""Yet another implementation of bunch
-
-attribute-access of items on a dict.
-"""
-
-# Copyright (c) Jupyter Development Team.
-# Distributed under the terms of the Modified BSD License.
-
-class Bunch(dict):
- """A dict with attribute-access"""
- def __getattr__(self, key):
- try:
- return self.__getitem__(key)
- except KeyError:
- raise AttributeError(key)
-
- def __setattr__(self, key, value):
- self.__setitem__(key, value)
-
- def __dir__(self):
- # py2-compat: can't use super because dict doesn't have __dir__
- names = dir({})
- names.extend(self.keys())
- return names
-
diff --git a/contrib/python/traitlets/py2/traitlets/utils/getargspec.py b/contrib/python/traitlets/py2/traitlets/utils/getargspec.py
deleted file mode 100644
index 0a047379fec..00000000000
--- a/contrib/python/traitlets/py2/traitlets/utils/getargspec.py
+++ /dev/null
@@ -1,86 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- getargspec excerpted from:
-
- sphinx.util.inspect
- ~~~~~~~~~~~~~~~~~~~
- Helpers for inspecting Python modules.
- :copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-"""
-
-import inspect
-from six import PY3
-
-# Unmodified from sphinx below this line
-
-if PY3:
- from functools import partial
-
- def getargspec(func):
- """Like inspect.getargspec but supports functools.partial as well."""
- if inspect.ismethod(func):
- func = func.__func__
- if type(func) is partial:
- orig_func = func.func
- argspec = getargspec(orig_func)
- args = list(argspec[0])
- defaults = list(argspec[3] or ())
- kwoargs = list(argspec[4])
- kwodefs = dict(argspec[5] or {})
- if func.args:
- args = args[len(func.args):]
- for arg in func.keywords or ():
- try:
- i = args.index(arg) - len(args)
- del args[i]
- try:
- del defaults[i]
- except IndexError:
- pass
- except ValueError: # must be a kwonly arg
- i = kwoargs.index(arg)
- del kwoargs[i]
- del kwodefs[arg]
- return inspect.FullArgSpec(args, argspec[1], argspec[2],
- tuple(defaults), kwoargs,
- kwodefs, argspec[6])
- while hasattr(func, '__wrapped__'):
- func = func.__wrapped__
- if not inspect.isfunction(func):
- raise TypeError('%r is not a Python function' % func)
- return inspect.getfullargspec(func)
-
-else: # 2.6, 2.7
- from functools import partial
-
- def getargspec(func):
- """Like inspect.getargspec but supports functools.partial as well."""
- if inspect.ismethod(func):
- func = func.__func__
- parts = 0, ()
- if type(func) is partial:
- keywords = func.keywords
- if keywords is None:
- keywords = {}
- parts = len(func.args), keywords.keys()
- func = func.func
- if not inspect.isfunction(func):
- raise TypeError('%r is not a Python function' % func)
- args, varargs, varkw = inspect.getargs(func.__code__)
- func_defaults = func.__defaults__
- if func_defaults is None:
- func_defaults = []
- else:
- func_defaults = list(func_defaults)
- if parts[0]:
- args = args[parts[0]:]
- if parts[1]:
- for arg in parts[1]:
- i = args.index(arg) - len(args)
- del args[i]
- try:
- del func_defaults[i]
- except IndexError:
- pass
- return inspect.ArgSpec(args, varargs, varkw, func_defaults)
diff --git a/contrib/python/traitlets/py2/traitlets/utils/importstring.py b/contrib/python/traitlets/py2/traitlets/utils/importstring.py
deleted file mode 100644
index 5b4f643f418..00000000000
--- a/contrib/python/traitlets/py2/traitlets/utils/importstring.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# encoding: utf-8
-"""
-A simple utility to import something by its string name.
-"""
-# Copyright (c) IPython Development Team.
-# Distributed under the terms of the Modified BSD License.
-
-from ipython_genutils.py3compat import cast_bytes_py2
-from six import string_types
-
-def import_item(name):
- """Import and return ``bar`` given the string ``foo.bar``.
-
- Calling ``bar = import_item("foo.bar")`` is the functional equivalent of
- executing the code ``from foo import bar``.
-
- Parameters
- ----------
- name : string
- The fully qualified name of the module/package being imported.
-
- Returns
- -------
- mod : module object
- The module that was imported.
- """
- if not isinstance(name, string_types):
- raise TypeError("import_item accepts strings, not '%s'." % type(name))
- name = cast_bytes_py2(name)
- parts = name.rsplit('.', 1)
- if len(parts) == 2:
- # called with 'foo.bar....'
- package, obj = parts
- module = __import__(package, fromlist=[obj])
- try:
- pak = getattr(module, obj)
- except AttributeError:
- raise ImportError('No module named %s' % obj)
- return pak
- else:
- # called with un-dotted string
- return __import__(parts[0])
diff --git a/contrib/python/traitlets/py2/traitlets/utils/sentinel.py b/contrib/python/traitlets/py2/traitlets/utils/sentinel.py
deleted file mode 100644
index dc57a2591ca..00000000000
--- a/contrib/python/traitlets/py2/traitlets/utils/sentinel.py
+++ /dev/null
@@ -1,17 +0,0 @@
-"""Sentinel class for constants with useful reprs"""
-
-# Copyright (c) IPython Development Team.
-# Distributed under the terms of the Modified BSD License.
-
-class Sentinel(object):
-
- def __init__(self, name, module, docstring=None):
- self.name = name
- self.module = module
- if docstring:
- self.__doc__ = docstring
-
-
- def __repr__(self):
- return str(self.module)+'.'+self.name
-
diff --git a/contrib/python/traitlets/py2/traitlets/utils/tests/__init__.py b/contrib/python/traitlets/py2/traitlets/utils/tests/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/contrib/python/traitlets/py2/traitlets/utils/tests/__init__.py
+++ /dev/null
diff --git a/contrib/python/traitlets/py2/traitlets/utils/tests/test_bunch.py b/contrib/python/traitlets/py2/traitlets/utils/tests/test_bunch.py
deleted file mode 100644
index ef5c3c1384f..00000000000
--- a/contrib/python/traitlets/py2/traitlets/utils/tests/test_bunch.py
+++ /dev/null
@@ -1,14 +0,0 @@
-from ..bunch import Bunch
-
-def test_bunch():
- b = Bunch(x=5, y=10)
- assert 'y' in b
- assert 'x' in b
- assert b.x == 5
- b['a'] = 'hi'
- assert b.a == 'hi'
-
-def test_bunch_dir():
- b = Bunch(x=5, y=10)
- assert 'x' in dir(b)
- assert 'keys' in dir(b)
diff --git a/contrib/python/traitlets/py2/traitlets/utils/tests/test_importstring.py b/contrib/python/traitlets/py2/traitlets/utils/tests/test_importstring.py
deleted file mode 100644
index c86459ff423..00000000000
--- a/contrib/python/traitlets/py2/traitlets/utils/tests/test_importstring.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# encoding: utf-8
-# Copyright (c) IPython Development Team.
-# Distributed under the terms of the Modified BSD License.
-#
-# Adapted from enthought.traits, Copyright (c) Enthought, Inc.,
-# also under the terms of the Modified BSD License.
-"""Tests for traitlets.utils.importstring."""
-
-import os
-from unittest import TestCase
-
-from ..importstring import import_item
-
-
-class TestImportItem(TestCase):
-
- def test_import_unicode(self):
- self.assertIs(os, import_item(u'os'))
- self.assertIs(os.path, import_item(u'os.path'))
- self.assertIs(os.path.join, import_item(u'os.path.join'))
-
- def test_bad_input(self):
- class NotAString(object):
- pass
- msg = (
- "import_item accepts strings, "
- "not '%s'." % NotAString
- )
- with self.assertRaisesRegexp(TypeError, msg):
- import_item(NotAString())