diff options
author | Nikita Slyusarev <nslus@yandex-team.com> | 2022-02-10 16:46:53 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:46:53 +0300 |
commit | 469afdc4e2587bf62ecdd096b75a0baa444c4012 (patch) | |
tree | 49e222ea1c5804306084bb3ae065bb702625360f /contrib/python/traitlets | |
parent | cd77cecfc03a3eaf87816af28a33067c4f0cdb59 (diff) | |
download | ydb-469afdc4e2587bf62ecdd096b75a0baa444c4012.tar.gz |
Restoring authorship annotation for Nikita Slyusarev <nslus@yandex-team.com>. Commit 2 of 2.
Diffstat (limited to 'contrib/python/traitlets')
17 files changed, 1362 insertions, 1362 deletions
diff --git a/contrib/python/traitlets/py2/traitlets/config/application.py b/contrib/python/traitlets/py2/traitlets/config/application.py index 5f750b5138..d3a4c45e77 100644 --- a/contrib/python/traitlets/py2/traitlets/config/application.py +++ b/contrib/python/traitlets/py2/traitlets/config/application.py @@ -6,13 +6,13 @@ from __future__ import print_function -from copy import deepcopy +from copy import deepcopy import json import logging import os import re import sys -from collections import defaultdict, OrderedDict +from collections import defaultdict, OrderedDict from decorator import decorator @@ -22,14 +22,14 @@ from traitlets.config.loader import ( ) from traitlets.traitlets import ( - Bool, Unicode, List, Enum, Dict, Instance, TraitError, observe, observe_compat, default, + 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 - +import six + #----------------------------------------------------------------------------- # Descriptions for the various sections #----------------------------------------------------------------------------- @@ -63,24 +63,24 @@ subcommand 'cmd', do: `{app} cmd -h`. # 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 ) - - + + +_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: @@ -99,16 +99,16 @@ class ApplicationError(Exception): 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__ @@ -116,7 +116,7 @@ class LevelFormatter(logging.Formatter): record.highlevel = "" return super(LevelFormatter, self).format(record) - + class Application(SingletonConfigurable): """A singleton application with full configuration support.""" @@ -131,7 +131,7 @@ class Application(SingletonConfigurable): 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 @@ -158,13 +158,13 @@ class Application(SingletonConfigurable): # 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) - + # 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, @@ -174,15 +174,15 @@ class Application(SingletonConfigurable): @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 = 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", + + log_datefmt = Unicode("%Y-%m-%d %H:%M:%S", help="The date format used by logging formatters for %(asctime)s" ).tag(config=True) @@ -197,7 +197,7 @@ class Application(SingletonConfigurable): _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. @@ -217,7 +217,7 @@ class Application(SingletonConfigurable): break else: _log = _log.parent - if sys.executable and sys.executable.endswith('pythonw.exe'): + 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')) @@ -240,11 +240,11 @@ class Application(SingletonConfigurable): @observe_compat def _flags_changed(self, change): """ensure flags dict is valid""" - new = change.new + 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) + assert isinstance(value[1], six.string_types), "Bad flag: %r:%s" % (key, value) # subcommands for launching other applications @@ -259,34 +259,34 @@ class Application(SingletonConfigurable): # 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 + 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. + """ + ) - 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__) - + 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)) + self.log.debug(repr(change.new)) @catch_config_error def initialize(self, argv=None): @@ -317,7 +317,7 @@ class Application(SingletonConfigurable): for c in cls.mro()[:-3]: classdict[c.__name__] = c - for alias, longname in self.aliases.items(): + for alias, longname in self.aliases.items(): classname, traitname = longname.split('.',1) cls = classdict[classname] @@ -337,7 +337,7 @@ class Application(SingletonConfigurable): return lines = [] - for m, (cfg,help) in self.flags.items(): + for m, (cfg,help) in self.flags.items(): prefix = '--' if len(m) > 1 else '-' lines.append(prefix+m) lines.append(indent(dedent(help.strip()))) @@ -370,7 +370,7 @@ class Application(SingletonConfigurable): app=self.name)): lines.append(p) lines.append('') - for subc, (cls, help) in self.subcommands.items(): + for subc, (cls, help) in self.subcommands.items(): lines.append(subc) if help: lines.append(indent(dedent(help.strip()))) @@ -442,26 +442,26 @@ class Application(SingletonConfigurable): """Initialize a subcommand with argv.""" subapp,help = self.subcommands.get(subc) - if isinstance(subapp, six.string_types): + if isinstance(subapp, six.string_types): subapp = import_item(subapp) # clear existing instances self.__class__.clear_instance() # instantiate - self.subapp = subapp.instance(parent=self) + 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 @@ -475,20 +475,20 @@ class Application(SingletonConfigurable): # flatten aliases, which have the form: # { 'alias' : 'Class.trait' } aliases = {} - for alias, cls_trait in self.aliases.items(): + 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(): + for key, (flagdict, help) in self.flags.items(): newflag = {} - for cls, subdict in flagdict.items(): + for cls, subdict in flagdict.items(): children = mro_tree[cls] # exactly one descendent, promote flag section if len(children) == 1: @@ -502,7 +502,7 @@ class Application(SingletonConfigurable): """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'] @@ -530,33 +530,33 @@ class Application(SingletonConfigurable): 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) + 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): + 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()) + 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 = [] + loaded = [] + filenames = [] for loader in [pyloader, jsonloader]: config = None try: @@ -568,8 +568,8 @@ class Application(SingletonConfigurable): # 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 raise_config_file_errors: + raise if log: log.error("Exception while loading config file %s", filename, exc_info=True) @@ -577,16 +577,16 @@ class Application(SingletonConfigurable): 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), - )) + 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) + loaded.append(config) + filenames.append(loader.full_filename) @property def loaded_config_files(self): @@ -597,55 +597,55 @@ class Application(SingletonConfigurable): def load_config_file(self, filename, path=None): """Load config files by filename and path.""" filename, ext = os.path.splitext(filename) - new_config = Config() + 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) + 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 - + # 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(): + for cls in self._classes_in_config_sample(): lines.append(cls.class_config_section()) return '\n'.join(lines) @@ -656,7 +656,7 @@ class Application(SingletonConfigurable): @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) @@ -702,7 +702,7 @@ def boolean_flag(name, configurable, set_help='', 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(): diff --git a/contrib/python/traitlets/py2/traitlets/config/configurable.py b/contrib/python/traitlets/py2/traitlets/config/configurable.py index 7e34c5a84a..1174fcf017 100644 --- a/contrib/python/traitlets/py2/traitlets/config/configurable.py +++ b/contrib/python/traitlets/py2/traitlets/config/configurable.py @@ -4,12 +4,12 @@ # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. -from __future__ import print_function, absolute_import +from __future__ import print_function, absolute_import from copy import deepcopy -import warnings +import warnings -from .loader import Config, LazyConfigValue, _is_section_key +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 @@ -66,12 +66,12 @@ class Configurable(HasTraits): 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 @@ -85,7 +85,7 @@ class Configurable(HasTraits): 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. @@ -95,25 +95,25 @@ class Configurable(HasTraits): #------------------------------------------------------------------------- # 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] @@ -127,20 +127,20 @@ class Configurable(HasTraits): 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(): + 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 @@ -151,21 +151,21 @@ class Configurable(HasTraits): # 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): + 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) + 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__) - + 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]) + 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) + msg +=" Did you mean one of: `{matches}`?".format(matches=', '.join(sorted(matches))) + warn(msg) @observe('config') @observe_compat @@ -183,23 +183,23 @@ class Configurable(HasTraits): # 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) + 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 + """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 + # 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): @@ -220,7 +220,7 @@ class Configurable(HasTraits): @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. """ @@ -261,19 +261,19 @@ class Configurable(HasTraits): """return a commented, wrapped block.""" s = '\n\n'.join(wrap_paragraphs(s, 78)) - return '## ' + s.replace('\n', '\n# ') + 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) + 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__ + if not desc: + # no description from trait, use __doc__ desc = getattr(cls, '__doc__', '') if desc: lines.append(c(desc)) @@ -281,7 +281,7 @@ class Configurable(HasTraits): 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('#c.%s.%s = %s' % (cls.__name__, name, trait.default_value_repr())) lines.append('') return '\n'.join(lines) diff --git a/contrib/python/traitlets/py2/traitlets/config/loader.py b/contrib/python/traitlets/py2/traitlets/config/loader.py index a79a398c3d..803b36276f 100644 --- a/contrib/python/traitlets/py2/traitlets/config/loader.py +++ b/contrib/python/traitlets/py2/traitlets/config/loader.py @@ -16,7 +16,7 @@ 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 six import text_type from traitlets.traitlets import HasTraits, List, Any #----------------------------------------------------------------------------- @@ -182,7 +182,7 @@ class Config(dict): def merge(self, other): """merge another config object into this one""" to_update = {} - for k, v in other.items(): + for k, v in other.items(): if k not in self: to_update[k] = v else: # I have this key @@ -385,17 +385,17 @@ class FileConfigLoader(ConfigLoader): 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' - - """ - + """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() @@ -422,24 +422,24 @@ class JSONFileConfigLoader(FileConfigLoader): 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) - - - + 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. @@ -521,7 +521,7 @@ class CommandLineConfigLoader(ConfigLoader): if isinstance(cfg, (dict, Config)): # don't clobber whole config sections, update # each section from config: - for sec,c in cfg.items(): + for sec,c in cfg.items(): self.config[sec].update(c) else: raise TypeError("Invalid flag: %r" % cfg) @@ -603,7 +603,7 @@ class KeyValueConfigLoader(CommandLineConfigLoader): if enc is None: enc = DEFAULT_ENCODING for arg in argv: - if not isinstance(arg, text_type): + if not isinstance(arg, text_type): # only decode if not already decoded arg = arg.decode(enc) uargv.append(arg) @@ -769,7 +769,7 @@ class ArgParseConfigLoader(CommandLineConfigLoader): def _convert_to_config(self): """self.parsed_data->self.config""" - for k, v in vars(self.parsed_data).items(): + for k, v in vars(self.parsed_data).items(): exec("self.config.%s = v"%k, locals(), globals()) class KVArgParseConfigLoader(ArgParseConfigLoader): @@ -786,17 +786,17 @@ class KVArgParseConfigLoader(ArgParseConfigLoader): if flags is None: flags = self.flags paa = self.parser.add_argument - for key,value in aliases.items(): + 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) + 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(): + 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 @@ -815,7 +815,7 @@ class KVArgParseConfigLoader(ArgParseConfigLoader): else: subcs = [] - for k, v in vars(self.parsed_data).items(): + 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]) diff --git a/contrib/python/traitlets/py2/traitlets/config/manager.py b/contrib/python/traitlets/py2/traitlets/config/manager.py index f5cf21904e..5e5ebde9af 100644 --- a/contrib/python/traitlets/py2/traitlets/config/manager.py +++ b/contrib/python/traitlets/py2/traitlets/config/manager.py @@ -7,7 +7,7 @@ import io import json import os -from six import PY3 +from six import PY3 from traitlets.config import LoggingConfigurable from traitlets.traitlets import Unicode diff --git a/contrib/python/traitlets/py2/traitlets/log.py b/contrib/python/traitlets/py2/traitlets/log.py index c7166c14c8..af86b325f5 100644 --- a/contrib/python/traitlets/py2/traitlets/log.py +++ b/contrib/python/traitlets/py2/traitlets/log.py @@ -9,19 +9,19 @@ _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()) + _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/traitlets.py b/contrib/python/traitlets/py2/traitlets/traitlets.py index b3134c819b..c07daf7400 100644 --- a/contrib/python/traitlets/py2/traitlets/traitlets.py +++ b/contrib/python/traitlets/py2/traitlets/traitlets.py @@ -42,11 +42,11 @@ Inheritance diagram: import contextlib import inspect -import os +import os import re import sys import types -import enum +import enum try: from types import ClassType, InstanceType ClassTypes = (ClassType, type) @@ -54,12 +54,12 @@ except: ClassTypes = (type,) from warnings import warn, warn_explicit -import six +import six from .utils.getargspec import getargspec from .utils.importstring import import_item from .utils.sentinel import Sentinel -from .utils.bunch import Bunch +from .utils.bunch import Bunch SequenceTypes = (list, tuple, set, frozenset) @@ -91,39 +91,39 @@ class TraitError(Exception): # 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 - +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( + warn_msg = "{classname}.{method_name} is deprecated in traitlets 4.1: {msg}".format( classname=cls.__name__, method_name=method_name, msg=msg ) @@ -131,15 +131,15 @@ def _deprecated_method(method, cls, method_name, msg): 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 + # 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: + except (IOError, TypeError) as e: # Failed to inspect for some reason warn(warn_msg + ('\n(inspection failed) %s' % e), DeprecationWarning) else: @@ -150,7 +150,7 @@ def class_of(object): correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image', 'a PlotValue'). """ - if isinstance( object, six.string_types ): + if isinstance( object, six.string_types ): return add_article( object ) return add_article( object.__class__.__name__ ) @@ -171,7 +171,7 @@ def repr_type(obj): error messages. """ the_type = type(obj) - if six.PY2 and the_type is InstanceType: + if six.PY2 and the_type is InstanceType: # Old-style class. the_type = obj.__class__ msg = '%r %r' % (obj, the_type) @@ -200,14 +200,14 @@ def parse_notifier_name(names): >>> parse_notifier_name(All) [All] """ - if names is All or isinstance(names, six.string_types): + if names is All or isinstance(names, six.string_types): return [names] - else: + 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) + if not isinstance(n, six.string_types): + raise TypeError("names must be strings, not %r" % n) return names @@ -288,13 +288,13 @@ class link(object): if self.updating: return with self._busy_updating(): - setattr(self.target[0], self.target[1], change.new) + 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) + setattr(self.source[0], self.source[1], change.new) def unlink(self): self.source[0].unobserve(self._update_target, names=self.source[1]) @@ -344,7 +344,7 @@ class directional_link(object): return with self._busy_updating(): setattr(self.target[0], self.target[1], - self._transform(change.new)) + self._transform(change.new)) def unlink(self): self.source[0].unobserve(self._update, names=self.source[1]) @@ -354,7 +354,7 @@ dlink = directional_link #----------------------------------------------------------------------------- -# Base Descriptor Class +# Base Descriptor Class #----------------------------------------------------------------------------- @@ -429,32 +429,32 @@ class TraitType(BaseDescriptor): """ if default_value is not Undefined: self.default_value = default_value - if allow_none: + 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: + 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) + 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) + self.metadata.update(kwargs) else: - self.metadata = kwargs + self.metadata = kwargs else: self.metadata = self.metadata.copy() if config is not None: @@ -470,14 +470,14 @@ class TraitType(BaseDescriptor): Use self.default_value instead """ - warn("get_default_value is deprecated in traitlets 4.0: use the .default_value attribute", DeprecationWarning, + 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, + 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 @@ -488,7 +488,7 @@ class TraitType(BaseDescriptor): This looks for: - * default generators registered with the @default descriptor. + * 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 @@ -516,14 +516,14 @@ class TraitType(BaseDescriptor): 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): + 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: @@ -595,7 +595,7 @@ class TraitType(BaseDescriptor): def _cross_validate(self, obj, value): if self.name in obj._trait_validators: - proposal = Bunch({'trait': self, 'value': value, 'owner': obj}) + 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 @@ -633,7 +633,7 @@ class TraitType(BaseDescriptor): 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) + warn("Deprecated in traitlets 4.1, " + msg, DeprecationWarning, stacklevel=2) return self.metadata.get(key, default) def set_metadata(self, key, value): @@ -645,7 +645,7 @@ class TraitType(BaseDescriptor): 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) + warn("Deprecated in traitlets 4.1, " + msg, DeprecationWarning, stacklevel=2) self.metadata[key] = value def tag(self, **metadata): @@ -655,11 +655,11 @@ class TraitType(BaseDescriptor): >>> 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) - + 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 @@ -697,13 +697,13 @@ class _CallbackWrapper(object): if self.nargs == 0: self.cb() elif self.nargs == 1: - self.cb(change.name) + self.cb(change.name) elif self.nargs == 2: - self.cb(change.name, change.new) + self.cb(change.name, change.new) elif self.nargs == 3: - self.cb(change.name, change.old, change.new) + self.cb(change.name, change.old, change.new) elif self.nargs == 4: - self.cb(change.name, change.old, change.new, change.owner) + self.cb(change.name, change.old, change.new, change.owner) def _callback_wrapper(cb): if isinstance(cb, _CallbackWrapper): @@ -721,13 +721,13 @@ class MetaHasDescriptors(type): def __new__(mcls, name, bases, classdict): """Create the HasDescriptors class.""" - for k, v in classdict.items(): + 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.", + 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() # ---------------------------------------------------------------- @@ -746,7 +746,7 @@ class MetaHasDescriptors(type): BaseDescriptor in the class dict of the newly created ``cls`` before calling their :attr:`class_init` method. """ - for k, v in classdict.items(): + for k, v in classdict.items(): if isinstance(v, BaseDescriptor): v.class_init(cls, k) @@ -762,10 +762,10 @@ class MetaHasTraits(MetaHasDescriptors): 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. + 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: @@ -778,27 +778,27 @@ def observe(*names, **kwargs): ---------- *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') + 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) + 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. """ @@ -807,15 +807,15 @@ def observe_compat(func): 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" % ( + 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, - ) + change = Bunch( + type='change', + old=old, + new=new, + name=change_or_name, + owner=self, + ) return func(self, change) return compatible_observer @@ -837,18 +837,18 @@ def validate(*names): Notes ----- - Since the owner has access to the ``HasTraits`` instance via the 'owner' key, + 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 + 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) + 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) @@ -890,8 +890,8 @@ def default(name): 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) + if not isinstance(name, six.string_types): + raise TypeError("Trait name must be a string or All, not %r" % name) return DefaultHandler(name) @@ -902,7 +902,7 @@ class EventHandler(BaseDescriptor): return self def __call__(self, *args, **kwargs): - """Pass `*args` and `**kwargs` to the handler's function if it exists.""" + """Pass `*args` and `**kwargs` to the handler's function if it exists.""" if hasattr(self, 'func'): return self.func(*args, **kwargs) else: @@ -943,26 +943,26 @@ class DefaultHandler(EventHandler): cls._trait_default_generators[self.trait_name] = self -class HasDescriptors(six.with_metaclass(MetaHasDescriptors, object)): +class HasDescriptors(six.with_metaclass(MetaHasDescriptors, object)): """The base class for all classes that have descriptors. """ - def __new__(cls, *args, **kwargs): + 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) + 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 + 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 @@ -977,46 +977,46 @@ class HasDescriptors(six.with_metaclass(MetaHasDescriptors, object)): value.instance_init(self) -class HasTraits(six.with_metaclass(MetaHasTraits, HasDescriptors)): +class HasTraits(six.with_metaclass(MetaHasTraits, HasDescriptors)): - def setup_instance(self, *args, **kwargs): + def setup_instance(self, *args, **kwargs): self._trait_values = {} self._trait_notifiers = {} self._trait_validators = {} - super(HasTraits, self).setup_instance(*args, **kwargs) + super(HasTraits, self).setup_instance(*args, **kwargs) - def __init__(self, *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 = {} + 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, - ) + 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() @@ -1044,27 +1044,27 @@ class HasTraits(six.with_metaclass(MetaHasTraits, HasDescriptors)): if isinstance(value, EventHandler): value.instance_init(self) - @property + @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 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. @@ -1073,7 +1073,7 @@ class HasTraits(six.with_metaclass(MetaHasTraits, HasDescriptors)): 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: + if self._cross_validation_lock: yield return else: @@ -1085,15 +1085,15 @@ class HasTraits(six.with_metaclass(MetaHasTraits, HasDescriptors)): if past_changes is None: return [change] else: - if past_changes[-1]['type'] == 'change' and change.type == 'change': - past_changes[-1]['new'] = change.new + 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 + name = change.name cache[name] = compress(cache.get(name), change) try: @@ -1106,24 +1106,24 @@ class HasTraits(six.with_metaclass(MetaHasTraits, HasDescriptors)): for name in list(cache.keys()): trait = getattr(self.__class__, name) value = trait._cross_validate(self, getattr(self, name)) - self.set_trait(name, value) + 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) + 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 + # Restore method retrieval from class + del self.notify_change # trigger delayed notifications for changes in cache.values(): @@ -1131,19 +1131,19 @@ class HasTraits(six.with_metaclass(MetaHasTraits, HasDescriptors)): 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', - )) + 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 + 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, [])) @@ -1170,9 +1170,9 @@ class HasTraits(six.with_metaclass(MetaHasTraits, HasDescriptors)): if isinstance(c, _CallbackWrapper): c = c.__call__ - elif isinstance(c, EventHandler) and c.name is not None: + elif isinstance(c, EventHandler) and c.name is not None: c = getattr(self, c.name) - + c(change) def _add_notifiers(self, handler, name, type): @@ -1225,7 +1225,7 @@ class HasTraits(six.with_metaclass(MetaHasTraits, HasDescriptors)): 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", + warn("on_trait_change is deprecated in traitlets 4.1: use observe instead", DeprecationWarning, stacklevel=2) if name is None: name = All @@ -1243,8 +1243,8 @@ class HasTraits(six.with_metaclass(MetaHasTraits, HasDescriptors)): ---------- 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. + 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: @@ -1267,7 +1267,7 @@ class HasTraits(six.with_metaclass(MetaHasTraits, HasDescriptors)): def unobserve(self, handler, names=All, type='change'): """Remove a trait change handler. - This is used to unregister handlers to trait change notifications. + This is used to unregister handlers to trait change notifications. Parameters ---------- @@ -1297,19 +1297,19 @@ class HasTraits(six.with_metaclass(MetaHasTraits, HasDescriptors)): pass def _register_validator(self, handler, names): - """Setup a handler to be called when a trait should be cross validated. + """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. + 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: + 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 @@ -1326,22 +1326,22 @@ class HasTraits(six.with_metaclass(MetaHasTraits, HasDescriptors)): 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) - + 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. @@ -1349,7 +1349,7 @@ class HasTraits(six.with_metaclass(MetaHasTraits, HasDescriptors)): This method is just like the :meth:`trait_names` method, but is unbound. """ - return list(cls.class_traits(**metadata)) + return list(cls.class_traits(**metadata)) @classmethod def class_traits(cls, **metadata): @@ -1399,10 +1399,10 @@ class HasTraits(six.with_metaclass(MetaHasTraits, HasDescriptors)): 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)) + return list(self.traits(**metadata)) def traits(self, **metadata): """Get a ``dict`` of all the traits of this class. The dictionary @@ -1443,48 +1443,48 @@ class HasTraits(six.with_metaclass(MetaHasTraits, HasDescriptors)): 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) + 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 - + @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 #----------------------------------------------------------------------------- @@ -1508,7 +1508,7 @@ class ClassBasedTraitType(TraitType): def error(self, obj, value): kind = type(value) - if six.PY2 and kind is InstanceType: + 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 ) ) @@ -1527,7 +1527,7 @@ class ClassBasedTraitType(TraitType): class Type(ClassBasedTraitType): """A trait whose value must be a subclass of a specified class.""" - def __init__ (self, default_value=Undefined, klass=None, **kwargs): + def __init__ (self, default_value=Undefined, klass=None, **kwargs): """Construct a Type trait A Type trait specifies that its values must be subclasses of @@ -1562,16 +1562,16 @@ class Type(ClassBasedTraitType): else: klass = default_value - if not (inspect.isclass(klass) or isinstance(klass, six.string_types)): + 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) + 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): + if isinstance(value, six.string_types): try: value = self._resolve_string(value) except ImportError: @@ -1587,10 +1587,10 @@ class Type(ClassBasedTraitType): def info(self): """ Returns a description of the trait.""" - if isinstance(self.klass, six.string_types): + if isinstance(self.klass, six.string_types): klass = self.klass else: - klass = self.klass.__module__ + '.' + self.klass.__name__ + klass = self.klass.__module__ + '.' + self.klass.__name__ result = "a subclass of '%s'" % klass if self.allow_none: return result + ' or None' @@ -1601,14 +1601,14 @@ class Type(ClassBasedTraitType): super(Type, self).instance_init(obj) def _resolve_classes(self): - if isinstance(self.klass, six.string_types): + if isinstance(self.klass, six.string_types): self.klass = self._resolve_string(self.klass) - if isinstance(self.default_value, six.string_types): + 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): + if isinstance(value, six.string_types): return repr(value) else: return repr('{}.{}'.format(value.__module__, value.__name__)) @@ -1624,7 +1624,7 @@ class Instance(ClassBasedTraitType): klass = None - def __init__(self, klass=None, args=None, kw=None, **kwargs): + def __init__(self, klass=None, args=None, kw=None, **kwargs): """Construct an Instance trait. This trait allows values that are instances of a particular @@ -1653,8 +1653,8 @@ class Instance(ClassBasedTraitType): """ if klass is None: klass = self.klass - - if (klass is not None) and (inspect.isclass(klass) or isinstance(klass, six.string_types)): + + 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' @@ -1668,7 +1668,7 @@ class Instance(ClassBasedTraitType): self.default_args = args self.default_kwargs = kw - super(Instance, self).__init__(**kwargs) + super(Instance, self).__init__(**kwargs) def validate(self, obj, value): if isinstance(value, self.klass): @@ -1677,7 +1677,7 @@ class Instance(ClassBasedTraitType): self.error(obj, value) def info(self): - if isinstance(self.klass, six.string_types): + if isinstance(self.klass, six.string_types): klass = self.klass else: klass = self.klass.__name__ @@ -1692,7 +1692,7 @@ class Instance(ClassBasedTraitType): super(Instance, self).instance_init(obj) def _resolve_classes(self): - if isinstance(self.klass, six.string_types): + if isinstance(self.klass, six.string_types): self.klass = self._resolve_string(self.klass) def make_dynamic_default(self): @@ -1742,8 +1742,8 @@ class This(ClassBasedTraitType): info_text = 'an instance of the same type as the receiver or None' - def __init__(self, **kwargs): - super(This, self).__init__(None, **kwargs) + 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 @@ -1758,7 +1758,7 @@ class This(ClassBasedTraitType): class Union(TraitType): """A trait type representing a Union type.""" - def __init__(self, trait_types, **kwargs): + def __init__(self, trait_types, **kwargs): """Construct a Union trait. This trait allows values that are allowed by at least one of the @@ -1776,8 +1776,8 @@ class Union(TraitType): 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) + 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: @@ -1790,13 +1790,13 @@ class Union(TraitType): super(Union, self).instance_init(obj) def validate(self, obj, value): - with obj.cross_validation_lock: + 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) + # 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 @@ -1808,16 +1808,16 @@ class Union(TraitType): 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() - - + 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 #----------------------------------------------------------------------------- @@ -1829,37 +1829,37 @@ class Any(TraitType): 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 - - +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): + 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, @@ -1868,7 +1868,7 @@ class Int(TraitType): def validate(self, obj, value): if not isinstance(value, int): self.error(obj, value) - return _validate_bounds(self, obj, value) + return _validate_bounds(self, obj, value) class CInt(Int): @@ -1876,49 +1876,49 @@ class CInt(Int): def validate(self, obj, value): try: - value = int(value) + value = int(value) except: self.error(obj, value) - return _validate_bounds(self, obj, value) + return _validate_bounds(self, obj, value) + - -if six.PY2: +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): + 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) + 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) + value = long(value) except: self.error(obj, value) - return _validate_bounds(self, obj, value) + return _validate_bounds(self, obj, value) + - class Integer(TraitType): """An integer trait. @@ -1927,14 +1927,14 @@ if six.PY2: 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): + 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): @@ -1948,25 +1948,25 @@ if six.PY2: return int(value) self.error(obj, value) - def validate(self, obj, value): - value = self._validate_int(obj, value) - return _validate_bounds(self, 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 + -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): + 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, + super(Float, self).__init__(default_value=default_value, allow_none=allow_none, **kwargs) def validate(self, obj, value): @@ -1974,7 +1974,7 @@ class Float(TraitType): value = float(value) if not isinstance(value, float): self.error(obj, value) - return _validate_bounds(self, obj, value) + return _validate_bounds(self, obj, value) class CFloat(Float): @@ -1982,12 +1982,12 @@ class CFloat(Float): def validate(self, obj, value): try: - value = float(value) + value = float(value) except: self.error(obj, value) - return _validate_bounds(self, obj, value) + return _validate_bounds(self, obj, value) + - class Complex(TraitType): """A trait for complex numbers.""" @@ -2043,7 +2043,7 @@ class Unicode(TraitType): info_text = 'a unicode string' def validate(self, obj, value): - if isinstance(value, six.text_type): + if isinstance(value, six.text_type): return value if isinstance(value, bytes): try: @@ -2059,7 +2059,7 @@ class CUnicode(Unicode): def validate(self, obj, value): try: - return six.text_type(value) + return six.text_type(value) except: self.error(obj, value) @@ -2070,7 +2070,7 @@ class ObjectName(TraitType): This does not check that the name exists in any scope.""" info_text = "a valid object identifier in Python" - if six.PY2: + if six.PY2: # Python 2: def coerce_str(self, obj, value): "In Python 2, coerce ascii-only unicode to str" @@ -2080,13 +2080,13 @@ class ObjectName(TraitType): except UnicodeEncodeError: self.error(obj, value) return value - else: - coerce_str = staticmethod(lambda _,s: s) + 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): + if isinstance(value, six.string_types) and isidentifier(value): return value self.error(obj, value) @@ -2095,8 +2095,8 @@ class DottedObjectName(ObjectName): 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('.')): + if isinstance(value, six.string_types) and all(isidentifier(a) + for a in value.split('.')): return value self.error(obj, value) @@ -2126,11 +2126,11 @@ class CBool(Bool): class Enum(TraitType): """An enum whose value must be in a given sequence.""" - def __init__(self, values, default_value=Undefined, **kwargs): + def __init__(self, values, default_value=Undefined, **kwargs): self.values = values - if kwargs.get('allow_none', False) and default_value is Undefined: + if kwargs.get('allow_none', False) and default_value is Undefined: default_value = None - super(Enum, self).__init__(default_value, **kwargs) + super(Enum, self).__init__(default_value, **kwargs) def validate(self, obj, value): if value in self.values: @@ -2146,15 +2146,15 @@ class Enum(TraitType): 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 __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): + value = cast_unicode_py2(value) + if not isinstance(value, six.string_types): self.error(obj, value) for v in self.values: @@ -2172,7 +2172,7 @@ class Container(Instance): _valid_defaults = SequenceTypes _trait = None - def __init__(self, trait=None, default_value=None, **kwargs): + 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)``, @@ -2200,7 +2200,7 @@ class Container(Instance): allow_none : bool [ default False ] Whether to allow the value to be None - **kwargs : any + **kwargs : any further keys for extensions to the Trait (e.g. config) """ @@ -2218,14 +2218,14 @@ class Container(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.", + 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) + 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." \ @@ -2272,7 +2272,7 @@ class List(Container): klass = list _cast_types = (tuple,) - def __init__(self, trait=None, default_value=None, minlen=0, maxlen=sys.maxsize, **kwargs): + 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)``, @@ -2306,7 +2306,7 @@ class List(Container): self._minlen = minlen self._maxlen = maxlen super(List, self).__init__(trait=trait, default_value=default_value, - **kwargs) + **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." \ @@ -2333,7 +2333,7 @@ class Set(List): # Redefine __init__ just to make the docstring more accurate. def __init__(self, trait=None, default_value=None, minlen=0, maxlen=sys.maxsize, - **kwargs): + **kwargs): """Create a Set trait type from a list, set, or tuple. The default value is created by doing ``set(default_value)``, @@ -2364,7 +2364,7 @@ class Set(List): maxlen : Int [ default sys.maxsize ] The maximum length of the input list """ - super(Set, self).__init__(trait, default_value, minlen, maxlen, **kwargs) + super(Set, self).__init__(trait, default_value, minlen, maxlen, **kwargs) class Tuple(Container): @@ -2372,7 +2372,7 @@ class Tuple(Container): klass = tuple _cast_types = (list,) - def __init__(self, *traits, **kwargs): + def __init__(self, *traits, **kwargs): """Create a tuple from a list, set, or tuple. Create a fixed-type tuple with Traits: @@ -2402,7 +2402,7 @@ class Tuple(Container): 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) + 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] @@ -2418,8 +2418,8 @@ class Tuple(Container): 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.", + 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) @@ -2427,7 +2427,7 @@ class Tuple(Container): 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) + super(Container,self).__init__(klass=self.klass, args=args, **kwargs) def validate_elements(self, obj, value): if not self._traits: @@ -2466,22 +2466,22 @@ class Dict(Instance): _trait = None def __init__(self, trait=None, traits=None, default_value=Undefined, - **kwargs): - """Create a dict trait type from a Python dict. + **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 - ---------- - + 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. + 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. + 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 @@ -2509,8 +2509,8 @@ class Dict(Instance): # 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.", + 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: @@ -2518,7 +2518,7 @@ class Dict(Instance): self._traits = traits - super(Dict, self).__init__(klass=dict, args=args, **kwargs) + 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." \ @@ -2533,26 +2533,26 @@ class Dict(Instance): 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): + 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 + 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) + v = value[key] + if not isinstance(validate_with, Any): + v = validate_with._validate(obj, v) except TraitError: - self.element_error(obj, v, validate_with) + self.element_error(obj, v, validate_with) else: validated[key] = v - + return self.klass(validated) def class_init(self, cls, name): @@ -2584,7 +2584,7 @@ class TCPAddress(TraitType): 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): + if isinstance(value[0], six.string_types) and isinstance(value[1], int): port = value[1] if port >= 0 and port <= 65535: return value @@ -2603,88 +2603,88 @@ class CRegExp(TraitType): 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 + + +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/bunch.py b/contrib/python/traitlets/py2/traitlets/utils/bunch.py index dc40b5df7d..2edb830ad6 100644 --- a/contrib/python/traitlets/py2/traitlets/utils/bunch.py +++ b/contrib/python/traitlets/py2/traitlets/utils/bunch.py @@ -1,25 +1,25 @@ -"""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 - +"""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 index f23750cbc1..0a047379fe 100644 --- a/contrib/python/traitlets/py2/traitlets/utils/getargspec.py +++ b/contrib/python/traitlets/py2/traitlets/utils/getargspec.py @@ -10,7 +10,7 @@ """ import inspect -from six import PY3 +from six import PY3 # Unmodified from sphinx below this line diff --git a/contrib/python/traitlets/py2/traitlets/utils/importstring.py b/contrib/python/traitlets/py2/traitlets/utils/importstring.py index 0228367446..5b4f643f41 100644 --- a/contrib/python/traitlets/py2/traitlets/utils/importstring.py +++ b/contrib/python/traitlets/py2/traitlets/utils/importstring.py @@ -5,8 +5,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 +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``. diff --git a/contrib/python/traitlets/py2/ya.make b/contrib/python/traitlets/py2/ya.make index 1efff6da42..4a60107101 100644 --- a/contrib/python/traitlets/py2/ya.make +++ b/contrib/python/traitlets/py2/ya.make @@ -14,7 +14,7 @@ PEERDIR( contrib/python/decorator contrib/python/enum34 contrib/python/ipython-genutils - contrib/python/six + contrib/python/six ) NO_LINT() @@ -31,7 +31,7 @@ PY_SRCS( traitlets/log.py traitlets/traitlets.py traitlets/utils/__init__.py - traitlets/utils/bunch.py + traitlets/utils/bunch.py traitlets/utils/getargspec.py traitlets/utils/importstring.py traitlets/utils/sentinel.py diff --git a/contrib/python/traitlets/py3/traitlets/config/application.py b/contrib/python/traitlets/py3/traitlets/config/application.py index b81fd45b85..99a6ef7ee0 100644 --- a/contrib/python/traitlets/py3/traitlets/config/application.py +++ b/contrib/python/traitlets/py3/traitlets/config/application.py @@ -5,7 +5,7 @@ from collections import defaultdict, OrderedDict -from copy import deepcopy +from copy import deepcopy import functools import json import logging @@ -20,7 +20,7 @@ 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, + Bool, Unicode, List, Enum, Dict, Instance, TraitError, observe, observe_compat, default, ) from ..utils.importstring import import_item @@ -28,7 +28,7 @@ from ..utils import cast_unicode from traitlets.utils.text import indent, wrap_paragraphs from textwrap import dedent - + #----------------------------------------------------------------------------- # Descriptions for the various sections #----------------------------------------------------------------------------- @@ -63,23 +63,23 @@ subcommand 'cmd', do: `{app} cmd -h`. # 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 ) - - + + +_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 ) + + def catch_config_error(method): """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. """ @functools.wraps(method) @@ -99,16 +99,16 @@ class ApplicationError(Exception): 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__ @@ -116,7 +116,7 @@ class LevelFormatter(logging.Formatter): record.highlevel = "" return super(LevelFormatter, self).format(record) - + class Application(SingletonConfigurable): """A singleton application with full configuration support.""" @@ -131,7 +131,7 @@ class Application(SingletonConfigurable): 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 @@ -164,13 +164,13 @@ class Application(SingletonConfigurable): # The version string of this application. version = Unicode('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) - + # 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, @@ -180,15 +180,15 @@ class Application(SingletonConfigurable): @observe_compat def _log_level_changed(self, change): """Adjust the log level when log_level is set.""" - new = change.new + new = change.new if isinstance(new, str): 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", + + log_datefmt = Unicode("%Y-%m-%d %H:%M:%S", help="The date format used by logging formatters for %(asctime)s" ).tag(config=True) @@ -209,7 +209,7 @@ class Application(SingletonConfigurable): return _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. @@ -229,7 +229,7 @@ class Application(SingletonConfigurable): break else: _log = _log.parent - if sys.executable and sys.executable.endswith('pythonw.exe'): + 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')) @@ -279,16 +279,16 @@ class Application(SingletonConfigurable): # 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 + 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. + """ + ) - We re-load this configuration after loading config files, - to ensure that it maintains highest priority. - """ - ) - _loaded_config_files = List() - + show_config = Bool( help="Instead of starting the Application, dump configuration to stdout" ).tag(config=True) @@ -311,14 +311,14 @@ class Application(SingletonConfigurable): 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 = self.__class__ + if cls not in self.classes: + if self.classes is cls.classes: + # class attr, assign instead of insert self.classes = [cls] + self.classes - else: - self.classes.insert(0, self.__class__) - + else: + self.classes.insert(0, self.__class__) + @observe('config') @observe_compat def _config_changed(self, change): @@ -394,7 +394,7 @@ class Application(SingletonConfigurable): for c in cls.mro()[:-3]: classdict[c.__name__] = c - for alias, longname in self.aliases.items(): + for alias, longname in self.aliases.items(): try: if isinstance(longname, tuple): longname, fhelp = longname @@ -489,7 +489,7 @@ class Application(SingletonConfigurable): app=self.name)): yield p yield '' - for subc, (cls, help) in self.subcommands.items(): + for subc, (cls, help) in self.subcommands.items(): yield subc if help: yield indent(dedent(help.strip())) @@ -602,10 +602,10 @@ class Application(SingletonConfigurable): # ... and finally initialize subapp. self.subapp.initialize(argv) - + def flatten_flags(self): """Flatten flags and aliases for loaders, 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. @@ -613,7 +613,7 @@ class Application(SingletonConfigurable): 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 @@ -639,13 +639,13 @@ class Application(SingletonConfigurable): alias = (alias, ) for al in alias: aliases[al] = '.'.join([cls,trait]) - + # flatten flags, which are of the form: # { 'key' : ({'Cls' : {'trait' : value}}, 'help')} flags = {} - for key, (flagdict, help) in self.flags.items(): + for key, (flagdict, help) in self.flags.items(): newflag = {} - for cls, subdict in flagdict.items(): + for cls, subdict in flagdict.items(): children = mro_tree[cls] # exactly one descendent, promote flag section if len(children) == 1: @@ -672,7 +672,7 @@ class Application(SingletonConfigurable): assert not isinstance(argv, str) argv = sys.argv[1:] if argv is None else argv self.argv = [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'] @@ -700,7 +700,7 @@ class Application(SingletonConfigurable): 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() classes = tuple(self._classes_with_config_traits()) @@ -711,27 +711,27 @@ class Application(SingletonConfigurable): # traitlets 5: no longer print help output on error # help output is huge, and comes after the error raise - self.update_config(self.cli_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): + 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()) + 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 = [] + loaded = [] + filenames = [] for loader in [pyloader, jsonloader]: config = None try: @@ -743,8 +743,8 @@ class Application(SingletonConfigurable): # 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 raise_config_file_errors: + raise if log: log.error("Exception while loading config file %s", filename, exc_info=True) @@ -752,16 +752,16 @@ class Application(SingletonConfigurable): 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), - )) + 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) + loaded.append(config) + filenames.append(loader.full_filename) @property def loaded_config_files(self): @@ -772,55 +772,55 @@ class Application(SingletonConfigurable): def load_config_file(self, filename, path=None): """Load config files by filename and path.""" filename, ext = os.path.splitext(filename) - new_config = Config() + 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) + 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) + # add self.cli_config to preserve CLI config priority + new_config.merge(self.cli_config) + self.update_config(new_config) def _classes_with_config_traits(self, classes=None): - """ + """ Yields only classes with configurable traits, and their subclasses. - + :param classes: The list of classes to iterate; if not set, uses :attr:`classes`. - 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. - """ + 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. + """ if classes is None: classes = self.classes - cls_to_config = OrderedDict( (cls, bool(cls.class_own_traits(config=True))) - for cls + cls_to_config = OrderedDict( (cls, bool(cls.class_own_traits(config=True))) + for cls in self._classes_inc_parents(classes)) - - 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 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, classes=None): """generate default config file from Configurables""" lines = ["# Configuration file for %s." % self.name] @@ -838,7 +838,7 @@ class Application(SingletonConfigurable): @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) @@ -885,7 +885,7 @@ def boolean_flag(name, configurable, set_help='', 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(): diff --git a/contrib/python/traitlets/py3/traitlets/config/configurable.py b/contrib/python/traitlets/py3/traitlets/config/configurable.py index 0f80aa3a0b..3b2044a01b 100644 --- a/contrib/python/traitlets/py3/traitlets/config/configurable.py +++ b/contrib/python/traitlets/py3/traitlets/config/configurable.py @@ -6,7 +6,7 @@ from copy import deepcopy import logging -import warnings +import warnings from .loader import Config, LazyConfigValue, DeferredConfig, _is_section_key from traitlets.traitlets import ( @@ -78,12 +78,12 @@ class Configurable(HasTraits): 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) - + # record traits set by config config_override_names = set() def notice_config_override(change): @@ -109,7 +109,7 @@ class Configurable(HasTraits): # allow _config_default to return something self._load_config(self.config) self.unobserve(notice_config_override) - + for name in config_override_names: setattr(self, name, kwargs[name]) @@ -117,25 +117,25 @@ class Configurable(HasTraits): #------------------------------------------------------------------------- # 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] @@ -149,20 +149,20 @@ class Configurable(HasTraits): 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(): + 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 @@ -176,21 +176,21 @@ class Configurable(HasTraits): # 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): + 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) + if isinstance(self, LoggingConfigurable): + warn = self.log.warning + else: + warn = lambda msg: warnings.warn(msg, stacklevel=9) matches = get_close_matches(name, traits) msg = "Config option `{option}` not recognized by `{klass}`.".format( - option=name, klass=self.__class__.__name__) - + option=name, klass=self.__class__.__name__) + if len(matches) == 1: msg += " 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) + msg +=" Did you mean one of: `{matches}`?".format(matches=', '.join(sorted(matches))) + warn(msg) @observe('config') @observe_compat @@ -208,23 +208,23 @@ class Configurable(HasTraits): # 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) + 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 + """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 + # 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): @@ -246,7 +246,7 @@ class Configurable(HasTraits): @classmethod def class_get_trait_help(cls, trait, inst=None, helptext=None): """Get the helptext string for a single trait. - + :param inst: If given, it's current trait values will be used in place of the class default. @@ -340,7 +340,7 @@ class Configurable(HasTraits): """return a commented, wrapped block.""" s = '\n\n'.join(wrap_paragraphs(s, 78)) - return '## ' + s.replace('\n', '\n# ') + return '## ' + s.replace('\n', '\n# ') # section header breaker = '#' + '-' * 78 @@ -349,14 +349,14 @@ class Configurable(HasTraits): if issubclass(p, Configurable) ) - s = "# %s(%s) configuration" % (cls.__name__, parent_classes) + 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__ + if not desc: + # no description from trait, use __doc__ desc = getattr(cls, '__doc__', '') if desc: lines.append(c(desc)) diff --git a/contrib/python/traitlets/py3/traitlets/config/loader.py b/contrib/python/traitlets/py3/traitlets/config/loader.py index bbab151db8..5360f889ab 100644 --- a/contrib/python/traitlets/py3/traitlets/config/loader.py +++ b/contrib/python/traitlets/py3/traitlets/config/loader.py @@ -255,7 +255,7 @@ class Config(dict): def merge(self, other): """merge another config object into this one""" to_update = {} - for k, v in other.items(): + for k, v in other.items(): if k not in self: to_update[k] = v else: # I have this key @@ -542,17 +542,17 @@ class FileConfigLoader(ConfigLoader): 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' - - """ - + """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() @@ -579,24 +579,24 @@ class JSONFileConfigLoader(FileConfigLoader): 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) - - - + 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. @@ -910,7 +910,7 @@ class ArgParseConfigLoader(CommandLineConfigLoader): def _convert_to_config(self): """self.parsed_data->self.config""" - for k, v in vars(self.parsed_data).items(): + for k, v in vars(self.parsed_data).items(): *path, key = k.split(".") section = self.config for p in path: diff --git a/contrib/python/traitlets/py3/traitlets/log.py b/contrib/python/traitlets/py3/traitlets/log.py index c7166c14c8..af86b325f5 100644 --- a/contrib/python/traitlets/py3/traitlets/log.py +++ b/contrib/python/traitlets/py3/traitlets/log.py @@ -9,19 +9,19 @@ _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()) + _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/py3/traitlets/traitlets.py b/contrib/python/traitlets/py3/traitlets/traitlets.py index 7643cbd132..6bdf7414d3 100644 --- a/contrib/python/traitlets/py3/traitlets/traitlets.py +++ b/contrib/python/traitlets/py3/traitlets/traitlets.py @@ -42,17 +42,17 @@ Inheritance diagram: from ast import literal_eval import contextlib import inspect -import os +import os import re import sys import types -import enum +import enum from warnings import warn, warn_explicit from .utils.getargspec import getargspec from .utils.importstring import import_item from .utils.sentinel import Sentinel -from .utils.bunch import Bunch +from .utils.bunch import Bunch from .utils.descriptions import describe, class_of, add_article, repr_type SequenceTypes = (list, tuple, set, frozenset) @@ -113,34 +113,34 @@ class TraitError(Exception): # Utilities #----------------------------------------------------------------------------- -_name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$") - -def isidentifier(s): +_name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$") + +def isidentifier(s): 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 - + +_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( + warn_msg = "{classname}.{method_name} is deprecated in traitlets 4.1: {msg}".format( classname=cls.__name__, method_name=method_name, msg=msg ) @@ -148,11 +148,11 @@ def _deprecated_method(method, cls, method_name, msg): 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 + # 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 @@ -197,12 +197,12 @@ def parse_notifier_name(names): """ if names is All or isinstance(names, str): return [names] - else: + else: if not names or All in names: return [All] for n in names: if not isinstance(n, str): - raise TypeError("names must be strings, not %r" % n) + raise TypeError("names must be strings, not %r" % n) return names @@ -358,7 +358,7 @@ class directional_link(object): return with self._busy_updating(): setattr(self.target[0], self.target[1], - self._transform(change.new)) + self._transform(change.new)) def unlink(self): self.source[0].unobserve(self._update, names=self.source[1]) @@ -367,7 +367,7 @@ dlink = directional_link #----------------------------------------------------------------------------- -# Base Descriptor Class +# Base Descriptor Class #----------------------------------------------------------------------------- @@ -447,32 +447,32 @@ class TraitType(BaseDescriptor): """ if default_value is not Undefined: self.default_value = default_value - if allow_none: + 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: + 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) + 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) + self.metadata.update(kwargs) else: - self.metadata = kwargs + self.metadata = kwargs else: self.metadata = self.metadata.copy() if config is not None: @@ -519,20 +519,20 @@ class TraitType(BaseDescriptor): """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, + 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, + 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 get(self, obj, cls=None): + def get(self, obj, cls=None): try: value = obj._trait_values[self.name] except KeyError: @@ -616,7 +616,7 @@ class TraitType(BaseDescriptor): def _cross_validate(self, obj, value): if self.name in obj._trait_validators: - proposal = Bunch({'trait': self, 'value': value, 'owner': obj}) + 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 @@ -700,7 +700,7 @@ class TraitType(BaseDescriptor): 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) + warn("Deprecated in traitlets 4.1, " + msg, DeprecationWarning, stacklevel=2) return self.metadata.get(key, default) def set_metadata(self, key, value): @@ -712,7 +712,7 @@ class TraitType(BaseDescriptor): 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) + warn("Deprecated in traitlets 4.1, " + msg, DeprecationWarning, stacklevel=2) self.metadata[key] = value def tag(self, **metadata): @@ -722,11 +722,11 @@ class TraitType(BaseDescriptor): >>> 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) - + 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 @@ -764,13 +764,13 @@ class _CallbackWrapper(object): if self.nargs == 0: self.cb() elif self.nargs == 1: - self.cb(change.name) + self.cb(change.name) elif self.nargs == 2: - self.cb(change.name, change.new) + self.cb(change.name, change.new) elif self.nargs == 3: - self.cb(change.name, change.old, change.new) + self.cb(change.name, change.old, change.new) elif self.nargs == 4: - self.cb(change.name, change.old, change.new, change.owner) + self.cb(change.name, change.old, change.new, change.owner) def _callback_wrapper(cb): if isinstance(cb, _CallbackWrapper): @@ -788,13 +788,13 @@ class MetaHasDescriptors(type): def __new__(mcls, name, bases, classdict): """Create the HasDescriptors class.""" - for k, v in classdict.items(): + 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.", + 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() # ---------------------------------------------------------------- @@ -813,7 +813,7 @@ class MetaHasDescriptors(type): BaseDescriptor in the class dict of the newly created ``cls`` before calling their :attr:`class_init` method. """ - for k, v in classdict.items(): + for k, v in classdict.items(): if isinstance(v, BaseDescriptor): v.class_init(cls, k) @@ -833,10 +833,10 @@ class MetaHasTraits(MetaHasDescriptors): def observe(*names, type="change"): """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. + 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: @@ -850,26 +850,26 @@ def observe(*names, type="change"): *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') + 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 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, str): - raise TypeError("trait names to observe must be strings or All, not %r" % name) + raise TypeError("trait names to observe must be strings or All, not %r" % name) return ObserveHandler(names, type=type) 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. """ @@ -878,15 +878,15 @@ def observe_compat(func): 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" % ( + 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, - ) + change = Bunch( + type='change', + old=old, + new=new, + name=change_or_name, + owner=self, + ) return func(self, change) return compatible_observer @@ -909,18 +909,18 @@ def validate(*names): Notes ----- - Since the owner has access to the ``HasTraits`` instance via the 'owner' key, + 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 + 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 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, str): - raise TypeError("trait names to validate must be strings or All, not %r" % name) + raise TypeError("trait names to validate must be strings or All, not %r" % name) return ValidateHandler(names) @@ -961,7 +961,7 @@ def default(name): # class derived from B.a.this_class. """ if not isinstance(name, str): - raise TypeError("Trait name must be a string or All, not %r" % name) + raise TypeError("Trait name must be a string or All, not %r" % name) return DefaultHandler(name) @@ -972,7 +972,7 @@ class EventHandler(BaseDescriptor): return self def __call__(self, *args, **kwargs): - """Pass `*args` and `**kwargs` to the handler's function if it exists.""" + """Pass `*args` and `**kwargs` to the handler's function if it exists.""" if hasattr(self, 'func'): return self.func(*args, **kwargs) else: @@ -1028,19 +1028,19 @@ class HasDescriptors(metaclass=MetaHasDescriptors): if new_meth is object.__new__: inst = new_meth(cls) else: - inst = new_meth(cls, *args, **kwargs) - inst.setup_instance(*args, **kwargs) + inst = new_meth(cls, *args, **kwargs) + inst.setup_instance(*args, **kwargs) return inst def setup_instance(*args, **kwargs): - """ - This is called **before** self.__init__ is called. - """ + """ + This is called **before** self.__init__ is called. + """ # Pass self as args[0] to allow "self" as keyword argument self = args[0] args = args[1:] - self._cross_validation_lock = False + self._cross_validation_lock = False cls = self.__class__ for key in dir(cls): # Some descriptors raise AttributeError like zope.interface's @@ -1065,40 +1065,40 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): self._trait_values = {} self._trait_notifiers = {} self._trait_validators = {} - super(HasTraits, self).setup_instance(*args, **kwargs) + super(HasTraits, self).setup_instance(*args, **kwargs) - def __init__(self, *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 = {} + 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( + 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 unrecognized 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, - ) + "{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() @@ -1129,27 +1129,27 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): if isinstance(value, EventHandler): value.instance_init(self) - @property + @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 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. @@ -1158,7 +1158,7 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): 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: + if self._cross_validation_lock: yield return else: @@ -1170,15 +1170,15 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): if past_changes is None: return [change] else: - if past_changes[-1]['type'] == 'change' and change.type == 'change': - past_changes[-1]['new'] = change.new + 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 + name = change.name cache[name] = compress(cache.get(name), change) try: @@ -1191,24 +1191,24 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): for name in list(cache.keys()): trait = getattr(self.__class__, name) value = trait._cross_validate(self, getattr(self, name)) - self.set_trait(name, value) + 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) + 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 + # Restore method retrieval from class + del self.notify_change # trigger delayed notifications for changes in cache.values(): @@ -1216,13 +1216,13 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): 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', - )) + self.notify_change(Bunch( + name=name, + old=old_value, + new=new_value, + owner=self, + type='change', + )) def notify_change(self, change): """Notify observers of a change event""" @@ -1231,7 +1231,7 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): def _notify_observers(self, event): """Notify observers of any event""" if not isinstance(event, Bunch): - # cast to bunch if given a dict + # cast to bunch if given a dict event = Bunch(event) name, type = event.name, event.type @@ -1260,9 +1260,9 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): if isinstance(c, _CallbackWrapper): c = c.__call__ - elif isinstance(c, EventHandler) and c.name is not None: + elif isinstance(c, EventHandler) and c.name is not None: c = getattr(self, c.name) - + c(event) def _add_notifiers(self, handler, name, type): @@ -1315,7 +1315,7 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): 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", + warn("on_trait_change is deprecated in traitlets 4.1: use observe instead", DeprecationWarning, stacklevel=2) if name is None: name = All @@ -1333,8 +1333,8 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): ---------- 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. + 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: @@ -1357,7 +1357,7 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): def unobserve(self, handler, names=All, type='change'): """Remove a trait change handler. - This is used to unregister handlers to trait change notifications. + This is used to unregister handlers to trait change notifications. Parameters ---------- @@ -1387,19 +1387,19 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): pass def _register_validator(self, handler, names): - """Setup a handler to be called when a trait should be cross validated. + """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. + 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: + 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 @@ -1416,8 +1416,8 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): for name in names: self._trait_validators[name] = handler - def add_traits(self, **traits): - """Dynamically add trait attributes to the HasTraits instance.""" + def add_traits(self, **traits): + """Dynamically add trait attributes to the HasTraits instance.""" cls = self.__class__ attrs = {"__module__": cls.__module__} if hasattr(cls, "__qualname__"): @@ -1425,18 +1425,18 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): attrs["__qualname__"] = cls.__qualname__ attrs.update(traits) self.__class__ = type(cls.__name__, (cls,), attrs) - 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) - + 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. @@ -1444,7 +1444,7 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): This method is just like the :meth:`trait_names` method, but is unbound. """ - return list(cls.class_traits(**metadata)) + return list(cls.class_traits(**metadata)) @classmethod def class_traits(cls, **metadata): @@ -1494,7 +1494,7 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): 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_has_value(self, name): """Returns True if the specified trait has a value. @@ -1589,7 +1589,7 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): def trait_names(self, **metadata): """Get a list of all the names of this class' traits.""" - return list(self.traits(**metadata)) + return list(self.traits(**metadata)) def traits(self, **metadata): """Get a ``dict`` of all the traits of this class. The dictionary @@ -1630,48 +1630,48 @@ class HasTraits(HasDescriptors, metaclass=MetaHasTraits): 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) + 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 - ---------- + @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 - + 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 #----------------------------------------------------------------------------- @@ -1762,7 +1762,7 @@ class Type(ClassBasedTraitType): if isinstance(self.klass, str): klass = self.klass else: - klass = self.klass.__module__ + '.' + self.klass.__name__ + klass = self.klass.__module__ + '.' + self.klass.__name__ result = "a subclass of '%s'" % klass if self.allow_none: return result + ' or None' @@ -1796,7 +1796,7 @@ class Instance(ClassBasedTraitType): klass = None - def __init__(self, klass=None, args=None, kw=None, **kwargs): + def __init__(self, klass=None, args=None, kw=None, **kwargs): """Construct an Instance trait. This trait allows values that are instances of a particular @@ -1827,7 +1827,7 @@ class Instance(ClassBasedTraitType): """ if klass is None: klass = self.klass - + if (klass is not None) and (inspect.isclass(klass) or isinstance(klass, str)): self.klass = klass else: @@ -1842,7 +1842,7 @@ class Instance(ClassBasedTraitType): self.default_args = args self.default_kwargs = kw - super(Instance, self).__init__(**kwargs) + super(Instance, self).__init__(**kwargs) def validate(self, obj, value): if isinstance(value, self.klass): @@ -1917,8 +1917,8 @@ class This(ClassBasedTraitType): info_text = 'an instance of the same type as the receiver or None' - def __init__(self, **kwargs): - super(This, self).__init__(None, **kwargs) + 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 @@ -1933,7 +1933,7 @@ class This(ClassBasedTraitType): class Union(TraitType): """A trait type representing a Union type.""" - def __init__(self, trait_types, **kwargs): + def __init__(self, trait_types, **kwargs): """Construct a Union trait. This trait allows values that are allowed by at least one of the @@ -1951,8 +1951,8 @@ class Union(TraitType): with the validation function of Float, then Bool, and finally Int. """ self.trait_types = list(trait_types) - self.info_text = " or ".join([tt.info() for tt in self.trait_types]) - super(Union, self).__init__(**kwargs) + self.info_text = " or ".join([tt.info() for tt in self.trait_types]) + super(Union, self).__init__(**kwargs) def default(self, obj=None): default = super(Union, self).default(obj) @@ -1974,13 +1974,13 @@ class Union(TraitType): super(Union, self).instance_init(obj) def validate(self, obj, value): - with obj.cross_validation_lock: + 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) + # 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 @@ -1992,7 +1992,7 @@ class Union(TraitType): else: return Union(self.trait_types + [other]) - + #----------------------------------------------------------------------------- # Basic TraitTypes implementations/subclasses #----------------------------------------------------------------------------- @@ -2005,37 +2005,37 @@ class Any(TraitType): 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 - - +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): + 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, @@ -2044,7 +2044,7 @@ class Int(TraitType): def validate(self, obj, value): if not isinstance(value, int): self.error(obj, value) - return _validate_bounds(self, obj, value) + return _validate_bounds(self, obj, value) def from_string(self, s): if self.allow_none and s == 'None': @@ -2057,12 +2057,12 @@ class CInt(Int): def validate(self, obj, value): try: - value = int(value) + value = int(value) except Exception: self.error(obj, value) - return _validate_bounds(self, obj, value) + return _validate_bounds(self, obj, value) + - Long, CLong = Int, CInt Integer = Int @@ -2073,10 +2073,10 @@ class Float(TraitType): default_value = 0.0 info_text = 'a float' - def __init__(self, default_value=Undefined, allow_none=False, **kwargs): + 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, + super(Float, self).__init__(default_value=default_value, allow_none=allow_none, **kwargs) def validate(self, obj, value): @@ -2084,7 +2084,7 @@ class Float(TraitType): value = float(value) if not isinstance(value, float): self.error(obj, value) - return _validate_bounds(self, obj, value) + return _validate_bounds(self, obj, value) def from_string(self, s): if self.allow_none and s == 'None': @@ -2097,12 +2097,12 @@ class CFloat(Float): def validate(self, obj, value): try: - value = float(value) + value = float(value) except Exception: self.error(obj, value) - return _validate_bounds(self, obj, value) + return _validate_bounds(self, obj, value) + - class Complex(TraitType): """A trait for complex numbers.""" @@ -2243,7 +2243,7 @@ class DottedObjectName(ObjectName): value = self.coerce_str(obj, value) if isinstance(value, str) and all(isidentifier(a) - for a in value.split('.')): + for a in value.split('.')): return value self.error(obj, value) @@ -2289,11 +2289,11 @@ class CBool(Bool): class Enum(TraitType): """An enum whose value must be in a given sequence.""" - def __init__(self, values, default_value=Undefined, **kwargs): + def __init__(self, values, default_value=Undefined, **kwargs): self.values = values - if kwargs.get('allow_none', False) and default_value is Undefined: + if kwargs.get('allow_none', False) and default_value is Undefined: default_value = None - super(Enum, self).__init__(default_value, **kwargs) + super(Enum, self).__init__(default_value, **kwargs) def validate(self, obj, value): if value in self.values: @@ -2331,10 +2331,10 @@ class Enum(TraitType): class CaselessStrEnum(Enum): """An enum of strings where the case should be ignored.""" - - def __init__(self, values, default_value=Undefined, **kwargs): + + def __init__(self, values, default_value=Undefined, **kwargs): super().__init__(values, default_value=default_value, **kwargs) - + def validate(self, obj, value): if not isinstance(value, str): self.error(obj, value) @@ -2444,7 +2444,7 @@ class Container(Instance): will be cast to the container type. allow_none : bool [ default False ] Whether to allow the value to be None - **kwargs : any + **kwargs : any further keys for extensions to the Trait (e.g. config) """ @@ -2630,7 +2630,7 @@ class List(Container): self._minlen = minlen self._maxlen = maxlen super(List, self).__init__(trait=trait, default_value=default_value, - **kwargs) + **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." \ @@ -2693,7 +2693,7 @@ class Set(List): maxlen : Int [ default sys.maxsize ] The maximum length of the input list """ - super(Set, self).__init__(trait, default_value, minlen, maxlen, **kwargs) + super(Set, self).__init__(trait, default_value, minlen, maxlen, **kwargs) def default_value_repr(self): # Ensure default value is sorted for a reproducible build @@ -2709,7 +2709,7 @@ class Tuple(Container): klass = tuple _cast_types = (list,) - def __init__(self, *traits, **kwargs): + def __init__(self, *traits, **kwargs): """Create a tuple from a list, set, or tuple. Create a fixed-type tuple with Traits: @@ -2849,14 +2849,14 @@ class Dict(Instance): _key_trait = None def __init__(self, value_trait=None, per_key_traits=None, key_trait=None, default_value=Undefined, - **kwargs): - """Create a dict trait type from a Python dict. + **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 - ---------- + Parameters + ---------- value_trait : TraitType [ optional ] The specified trait type to check and use to restrict the values of the dict. If unspecified, values are not checked. @@ -2871,7 +2871,7 @@ class Dict(Instance): The default value for the Dict. Must be dict, tuple, or None, and will be cast to a dict if not None. If any key or value traits are specified, the `default_value` must conform to the constraints. - + Examples -------- >>> d = Dict(Unicode()) @@ -2934,8 +2934,8 @@ class Dict(Instance): # Case where a type of TraitType is provided rather than an instance if is_trait(value_trait): if isinstance(value_trait, type): - warn("Traits should be given as instances, not types (for example, `Int()`, not `Int`)" - " Passing types is deprecated in traitlets 4.1.", + 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) value_trait = value_trait() self._value_trait = value_trait @@ -2954,7 +2954,7 @@ class Dict(Instance): self._per_key_traits = per_key_traits - super(Dict, self).__init__(klass=dict, args=args, **kwargs) + super(Dict, self).__init__(klass=dict, args=args, **kwargs) def element_error(self, obj, element, validator, side='Values'): e = side + " of the '%s' trait of %s instance must be %s, but a value of %s was specified." \ @@ -2974,7 +2974,7 @@ class Dict(Instance): value_trait = self._value_trait if not (key_trait or value_trait or per_key_override): return value - + validated = {} for key in value: v = value[key] @@ -2990,7 +2990,7 @@ class Dict(Instance): except TraitError: self.element_error(obj, v, active_value_trait, 'Values') validated[key] = v - + return self.klass(validated) def class_init(self, cls, name): @@ -3127,85 +3127,85 @@ class CRegExp(TraitType): return re.compile(value) except Exception: 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.""" + + +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, str) - 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 + 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, str): - # -- 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) - + # -- 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 _choices_str(self, as_rst=False): """ Returns a description of the trait choices (not none).""" choices = self.enum_class.__members__.keys() @@ -3221,7 +3221,7 @@ class UseEnum(TraitType): '') return 'any of %s%s' % (self._choices_str(as_rst), none) - def info(self): + def info(self): return self._info(as_rst=False) def info_rst(self): diff --git a/contrib/python/traitlets/py3/traitlets/utils/bunch.py b/contrib/python/traitlets/py3/traitlets/utils/bunch.py index dc40b5df7d..2edb830ad6 100644 --- a/contrib/python/traitlets/py3/traitlets/utils/bunch.py +++ b/contrib/python/traitlets/py3/traitlets/utils/bunch.py @@ -1,25 +1,25 @@ -"""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 - +"""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/py3/ya.make b/contrib/python/traitlets/py3/ya.make index 99460fa8ed..46980f21b3 100644 --- a/contrib/python/traitlets/py3/ya.make +++ b/contrib/python/traitlets/py3/ya.make @@ -9,7 +9,7 @@ OWNER(borman nslus g:python-contrib) VERSION(5.1.1) LICENSE(BSD-3-Clause) - + NO_LINT() PY_SRCS( @@ -28,7 +28,7 @@ PY_SRCS( traitlets/tests/utils.py traitlets/traitlets.py traitlets/utils/__init__.py - traitlets/utils/bunch.py + traitlets/utils/bunch.py traitlets/utils/decorators.py traitlets/utils/descriptions.py traitlets/utils/getargspec.py |