diff --git a/IPython/core/alias.py b/IPython/core/alias.py index 7dc81c7..28a9ccb 100644 --- a/IPython/core/alias.py +++ b/IPython/core/alias.py @@ -192,8 +192,8 @@ class Alias(object): class AliasManager(Configurable): - default_aliases = List(default_aliases(), config=True) - user_aliases = List(default_value=[], config=True) + default_aliases = List(default_aliases()).tag(config=True) + user_aliases = List(default_value=[]).tag(config=True) shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True) def __init__(self, shell=None, **kwargs): diff --git a/IPython/core/application.py b/IPython/core/application.py index 6374b7f..0c9f0a6 100644 --- a/IPython/core/application.py +++ b/IPython/core/application.py @@ -26,7 +26,10 @@ from IPython.core.profiledir import ProfileDir, ProfileDirError from IPython.paths import get_ipython_dir, get_ipython_package_dir from IPython.utils.path import ensure_dir_exists from IPython.utils import py3compat -from traitlets import List, Unicode, Type, Bool, Dict, Set, Instance, Undefined +from traitlets import ( + List, Unicode, Type, Bool, Dict, Set, Instance, Undefined, + default, observe, +) if os.name == 'nt': programdata = os.environ.get('PROGRAMDATA', None) @@ -96,11 +99,13 @@ class BaseIPythonApplication(Application): config_file_specified = Set() config_file_name = Unicode() + @default('config_file_name') def _config_file_name_default(self): return self.name.replace('-','_') + u'_config.py' - def _config_file_name_changed(self, name, old, new): - if new != old: - self.config_file_specified.add(new) + @observe('config_file_name') + def _config_file_name_changed(self, change): + if change['new'] != change['old']: + self.config_file_specified.add(change['new']) # The directory that contains IPython's builtin profiles. builtin_profile_dir = Unicode( @@ -108,15 +113,19 @@ class BaseIPythonApplication(Application): ) config_file_paths = List(Unicode()) + @default('config_file_paths') def _config_file_paths_default(self): return [py3compat.getcwd()] - extra_config_file = Unicode(config=True, + extra_config_file = Unicode( help="""Path to an extra config file to load. If specified, load this config file in addition to any other IPython config. - """) - def _extra_config_file_changed(self, name, old, new): + """).tag(config=True) + @observe('extra_config_file') + def _extra_config_file_changed(self, change): + old = change['old'] + new = change['new'] try: self.config_files.remove(old) except ValueError: @@ -124,30 +133,37 @@ class BaseIPythonApplication(Application): self.config_file_specified.add(new) self.config_files.append(new) - profile = Unicode(u'default', config=True, + profile = Unicode(u'default', help="""The IPython profile to use.""" - ) - - def _profile_changed(self, name, old, new): + ).tag(config=True) + + @observe('profile') + def _profile_changed(self, change): self.builtin_profile_dir = os.path.join( - get_ipython_package_dir(), u'config', u'profile', new + get_ipython_package_dir(), u'config', u'profile', change['new'] ) - ipython_dir = Unicode(config=True, + ipython_dir = Unicode( help=""" The name of the IPython directory. This directory is used for logging configuration (through profiles), history storage, etc. The default is usually $HOME/.ipython. This option can also be specified through the environment variable IPYTHONDIR. """ - ) + ).tag(config=True) + @default('ipython_dir') def _ipython_dir_default(self): d = get_ipython_dir() - self._ipython_dir_changed('ipython_dir', d, d) + self._ipython_dir_changed({ + 'name': 'ipython_dir', + 'old': d, + 'new': d, + }) return d _in_init_profile_dir = False profile_dir = Instance(ProfileDir, allow_none=True) + @default('profile_dir') def _profile_dir_default(self): # avoid recursion if self._in_init_profile_dir: @@ -156,26 +172,29 @@ class BaseIPythonApplication(Application): self.init_profile_dir() return self.profile_dir - overwrite = Bool(False, config=True, - help="""Whether to overwrite existing config files when copying""") - auto_create = Bool(False, config=True, - help="""Whether to create profile dir if it doesn't exist""") + overwrite = Bool(False, + help="""Whether to overwrite existing config files when copying""" + ).tag(config=True) + auto_create = Bool(False, + help="""Whether to create profile dir if it doesn't exist""" + ).tag(config=True) config_files = List(Unicode()) + @default('config_files') def _config_files_default(self): return [self.config_file_name] - copy_config_files = Bool(False, config=True, + copy_config_files = Bool(False, help="""Whether to install the default config files into the profile dir. If a new profile is being created, and IPython contains config files for that profile, then they will be staged into the new directory. Otherwise, default config files will be automatically generated. - """) + """).tag(config=True) - verbose_crash = Bool(False, config=True, + verbose_crash = Bool(False, help="""Create a massive crash report when IPython encounters what may be an internal error. The default is to append a short message to the - usual traceback""") + usual traceback""").tag(config=True) # The class to use as the crash handler. crash_handler_class = Type(crashhandler.CrashHandler) @@ -199,7 +218,6 @@ class BaseIPythonApplication(Application): def initialize_subcommand(self, subc, argv=None): if subc in self.deprecated_subcommands: - import time self.log.warning("Subcommand `ipython {sub}` is deprecated and will be removed " "in future versions.".format(sub=subc)) self.log.warning("You likely want to use `jupyter {sub}` in the " @@ -225,8 +243,11 @@ class BaseIPythonApplication(Application): return self.crash_handler(etype, evalue, tb) else: return crashhandler.crash_handler_lite(etype, evalue, tb) - - def _ipython_dir_changed(self, name, old, new): + + @observe('ipython_dir') + def _ipython_dir_changed(self, change): + old = change['old'] + new = change['new'] if old is not Undefined: str_old = py3compat.cast_bytes_py2(os.path.abspath(old), sys.getfilesystemencoding() diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 74d007a..21c9110 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -66,7 +66,7 @@ import sys import unicodedata import string -from traitlets.config.configurable import Configurable +from traitlets.config.configurable import Configurable from IPython.core.error import TryNext from IPython.core.inputsplitter import ESC_MAGIC from IPython.core.latex_symbols import latex_symbols, reverse_latex_symbol @@ -75,7 +75,7 @@ from IPython.utils.decorators import undoc from IPython.utils.dir2 import dir2, get_real_method from IPython.utils.process import arg_split from IPython.utils.py3compat import builtin_mod, string_types, PY3, cast_unicode_py2 -from traitlets import CBool, Enum +from traitlets import Bool, Enum, observe import jedi import jedi.api.helpers @@ -174,7 +174,6 @@ def compress_user(path, tilde_expand, tilde_val): return path - def completions_sorting_key(word): """key for sorting completions @@ -273,14 +272,14 @@ class CompletionSplitter(object): class Completer(Configurable): - greedy = CBool(False, config=True, + greedy = Bool(False, help="""Activate greedy completion PENDING DEPRECTION. this is now mostly taken care of with Jedi. This will enable completion on elements of lists, results of function calls, etc., but can be unsafe because the code is actually evaluated on TAB. """ - ) + ).tag(config=True) def __init__(self, namespace=None, global_namespace=None, **kwargs): @@ -505,7 +504,7 @@ def back_unicode_name_matches(text): try : unic = unicodedata.name(char) return '\\'+char,['\\'+unic] - except KeyError as e: + except KeyError: pass return u'', () @@ -532,17 +531,18 @@ def back_latex_name_matches(text): latex = reverse_latex_symbol[char] # '\\' replace the \ as well return '\\'+char,[latex] - except KeyError as e: + except KeyError: pass return u'', () class IPCompleter(Completer): """Extension of the completer class with IPython-specific features""" - - def _greedy_changed(self, name, old, new): + + @observe('greedy') + def _greedy_changed(self, change): """update the splitter and readline delims when greedy is changed""" - if new: + if change['new']: self.splitter.delims = GREEDY_DELIMS else: self.splitter.delims = DELIMS @@ -550,14 +550,14 @@ class IPCompleter(Completer): if self.readline: self.readline.set_completer_delims(self.splitter.delims) - merge_completions = CBool(True, config=True, + merge_completions = Bool(True, help="""Whether to merge completion results into a single list If False, only the completion results from the first non-empty completer will be returned. """ - ) - omit__names = Enum((0,1,2), default_value=2, config=True, + ).tag(config=True) + omit__names = Enum((0,1,2), default_value=2, help="""Instruct the completer to omit private method names Specifically, when completing on ``object.``. @@ -568,8 +568,8 @@ class IPCompleter(Completer): When 0: nothing will be excluded. """ - ) - limit_to__all__ = CBool(default_value=False, config=True, + ).tag(config=True) + limit_to__all__ = Bool(False, help=""" DEPRECATED as of version 5.0. @@ -580,8 +580,8 @@ class IPCompleter(Completer): When True: only those names in obj.__all__ will be included. When False [default]: the __all__ attribute is ignored - """ - ) + """, + ).tag(config=True) def __init__(self, shell=None, namespace=None, global_namespace=None, use_readline=True, config=None, **kwargs): @@ -1101,7 +1101,7 @@ class IPCompleter(Completer): # allow combining chars if ('a'+unic).isidentifier(): return '\\'+s,[unic] - except KeyError as e: + except KeyError: pass return u'', [] diff --git a/IPython/core/formatters.py b/IPython/core/formatters.py index 237a2d7..7265989 100644 --- a/IPython/core/formatters.py +++ b/IPython/core/formatters.py @@ -26,6 +26,7 @@ from IPython.lib import pretty from traitlets import ( Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List, ForwardDeclaredInstance, + default, observe, ) from IPython.utils.py3compat import ( with_metaclass, string_types, unicode_type, @@ -49,29 +50,34 @@ class DisplayFormatter(Configurable): else: self.active_types = self.format_types - active_types = List(Unicode()).tag(config=True, + active_types = List(Unicode(), help="""List of currently active mime-types to display. You can use this to set a white-list for formats to display. Most users will not need to change this value. - """) + """).tag(config=True) + + @default('active_types') def _active_types_default(self): return self.format_types - - def _active_types_changed(self, name, old, new): + + @observe('active_types') + def _active_types_changed(self, change): for key, formatter in self.formatters.items(): - if key in new: + if key in change['new']: formatter.enabled = True else: formatter.enabled = False ipython_display_formatter = ForwardDeclaredInstance('FormatterABC') - def _ipython_display_formatter_default(self): + @default('ipython_display_formatter') + def _default_formatter(self): return IPythonDisplayFormatter(parent=self) # A dict of formatter whose keys are format types (MIME types) and whose # values are subclasses of BaseFormatter. formatters = Dict() + @default('formatters') def _formatters_default(self): """Activate the default formatters.""" formatter_classes = [ @@ -570,12 +576,12 @@ class PlainTextFormatter(BaseFormatter): # something. enabled = Bool(True).tag(config=False) - max_seq_length = Integer(pretty.MAX_SEQ_LENGTH).tag(config=True, + max_seq_length = Integer(pretty.MAX_SEQ_LENGTH, help="""Truncate large collections (lists, dicts, tuples, sets) to this size. Set to 0 to disable truncation. """ - ) + ).tag(config=True) # Look for a _repr_pretty_ methods to use for pretty printing. print_method = ObjectName('_repr_pretty_') @@ -643,14 +649,17 @@ class PlainTextFormatter(BaseFormatter): self.float_format = fmt # Use the default pretty printers from IPython.lib.pretty. + @default('singleton_printers') def _singleton_printers_default(self): return pretty._singleton_pprinters.copy() + @default('type_printers') def _type_printers_default(self): d = pretty._type_pprinters.copy() d[float] = lambda obj,p,cycle: p.text(self.float_format%obj) return d + @default('deferred_printers') def _deferred_printers_default(self): return pretty._deferred_type_pprinters.copy() diff --git a/IPython/core/history.py b/IPython/core/history.py index be0afc2..5147ad9 100644 --- a/IPython/core/history.py +++ b/IPython/core/history.py @@ -25,6 +25,7 @@ from IPython.utils.path import locate_profile from IPython.utils import py3compat from traitlets import ( Any, Bool, Dict, Instance, Integer, List, Unicode, TraitError, + default, observe, ) from warnings import warn @@ -148,7 +149,7 @@ class HistoryAccessor(HistoryAccessorBase): _corrupt_db_limit = 2 # String holding the path to the history file - hist_file = Unicode(config=True, + hist_file = Unicode( help="""Path to file to use for SQLite history database. By default, IPython will put the history database in the IPython @@ -161,9 +162,9 @@ class HistoryAccessor(HistoryAccessorBase): ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite - """) + """).tag(config=True) - enabled = Bool(True, config=True, + enabled = Bool(True, help="""enable the SQLite history set enabled=False to disable the SQLite history, @@ -171,20 +172,22 @@ class HistoryAccessor(HistoryAccessorBase): and no background saving thread. This may be necessary in some threaded environments where IPython is embedded. """ - ) + ).tag(config=True) - connection_options = Dict(config=True, + connection_options = Dict( help="""Options for configuring the SQLite connection These options are passed as keyword args to sqlite3.connect when establishing database conenctions. """ - ) + ).tag(config=True) # The SQLite database db = Any() - def _db_changed(self, name, old, new): + @observe('db') + def _db_changed(self, change): """validate the db, since it can be an Instance of two different types""" + new = change['new'] connection_types = (DummyDB,) if sqlite3 is not None: connection_types = (DummyDB, sqlite3.Connection) @@ -479,6 +482,7 @@ class HistoryManager(HistoryAccessor): input_hist_raw = List([""]) # A list of directories visited during session dir_hist = List() + @default('dir_hist') def _dir_hist_default(self): try: return [py3compat.getcwd()] @@ -494,13 +498,13 @@ class HistoryManager(HistoryAccessor): # The number of the current session in the history database session_number = Integer() - db_log_output = Bool(False, config=True, + db_log_output = Bool(False, help="Should the history database include output? (default: no)" - ) - db_cache_size = Integer(0, config=True, + ).tag(config=True) + db_cache_size = Integer(0, help="Write to database every x commands (higher values save disk access & power).\n" "Values of 1 or less effectively disable caching." - ) + ).tag(config=True) # The input and output caches db_input_cache = List() db_output_cache = List() diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 04536a9..6a18ecd 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -49,7 +49,7 @@ from IPython.core.error import InputRejected, UsageError from IPython.core.extensions import ExtensionManager from IPython.core.formatters import DisplayFormatter from IPython.core.history import HistoryManager -from IPython.core.inputsplitter import IPythonInputSplitter, ESC_MAGIC, ESC_MAGIC2 +from IPython.core.inputsplitter import ESC_MAGIC, ESC_MAGIC2 from IPython.core.logger import Logger from IPython.core.macro import Macro from IPython.core.payload import PayloadManager @@ -75,8 +75,10 @@ from IPython.utils.strdispatch import StrDispatch from IPython.utils.syspathcontext import prepended_to_syspath from IPython.utils.text import (format_screen, LSString, SList, DollarFormatter) -from traitlets import (Integer, Bool, CBool, CaselessStrEnum, Enum, - List, Dict, Unicode, Instance, Type) +from traitlets import ( + Integer, Bool, CaselessStrEnum, Enum, List, Dict, Unicode, Instance, Type, + observe, default, +) from warnings import warn from logging import error import IPython.core.hooks @@ -114,9 +116,6 @@ def no_op(*a, **kw): pass class SpaceInInput(Exception): pass -@undoc -class Bunch: pass - def get_default_colors(): if sys.platform=='darwin': @@ -173,14 +172,14 @@ class InteractiveShell(SingletonConfigurable): _instance = None - ast_transformers = List([], config=True, help= + ast_transformers = List([], help= """ A list of ast.NodeTransformer subclass instances, which will be applied to user input before code is run. """ - ) + ).tag(config=True) - autocall = Enum((0,1,2), default_value=0, config=True, help= + autocall = Enum((0,1,2), default_value=0, help= """ Make IPython automatically call any callable object even if you didn't type explicit parentheses. For example, 'str 43' becomes 'str(43)' @@ -189,28 +188,28 @@ class InteractiveShell(SingletonConfigurable): arguments on the line, and '2' for 'full' autocall, where all callable objects are automatically called (even if no arguments are present). """ - ) + ).tag(config=True) # TODO: remove all autoindent logic and put into frontends. # We can't do this yet because even runlines uses the autoindent. - autoindent = CBool(True, config=True, help= + autoindent = Bool(True, help= """ Autoindent IPython code entered interactively. """ - ) - automagic = CBool(True, config=True, help= + ).tag(config=True) + automagic = Bool(True, help= """ Enable magic commands to be called without the leading %. """ - ) + ).tag(config=True) - banner1 = Unicode(default_banner, config=True, + banner1 = Unicode(default_banner, help="""The part of the banner to be printed before the profile""" - ) - banner2 = Unicode('', config=True, + ).tag(config=True) + banner2 = Unicode('', help="""The part of the banner to be printed after the profile""" - ) + ).tag(config=True) - cache_size = Integer(1000, config=True, help= + cache_size = Integer(1000, help= """ Set the size of the output cache. The default is 1000, you can change it permanently in your config file. Setting it to 0 completely @@ -219,19 +218,19 @@ class InteractiveShell(SingletonConfigurable): issued). This limit is defined because otherwise you'll spend more time re-flushing a too small cache than working """ - ) - color_info = CBool(True, config=True, help= + ).tag(config=True) + color_info = Bool(True, help= """ Use colors for displaying information about objects. Because this information is passed through a pager (like 'less'), and some pagers get confused with color codes, this capability can be turned off. """ - ) + ).tag(config=True) colors = CaselessStrEnum(('NoColor','LightBG','Linux'), - default_value=get_default_colors(), config=True, + default_value=get_default_colors(), help="Set the color scheme (NoColor, Linux, or LightBG)." - ) - colors_force = CBool(False, help= + ).tag(config=True) + colors_force = Bool(False, help= """ Force use of ANSI color codes, regardless of OS and readline availability. @@ -240,8 +239,8 @@ class InteractiveShell(SingletonConfigurable): # without readline on Win32. When the ZMQ formatting system is # refactored, this should be removed. ) - debug = CBool(False, config=True) - deep_reload = CBool(False, config=True, help= + debug = Bool(False).tag(config=True) + deep_reload = Bool(False, help= """ **Deprecated** @@ -255,23 +254,24 @@ class InteractiveShell(SingletonConfigurable): deep_reload is off, IPython will use the normal reload(), but deep_reload will still be available as dreload(). """ - ) - disable_failing_post_execute = CBool(False, config=True, + ).tag(config=True) + disable_failing_post_execute = Bool(False, help="Don't call post-execute functions that have failed in the past." - ) + ).tag(config=True) display_formatter = Instance(DisplayFormatter, allow_none=True) displayhook_class = Type(DisplayHook) display_pub_class = Type(DisplayPublisher) data_pub_class = None - exit_now = CBool(False) + exit_now = Bool(False) exiter = Instance(ExitAutocall) + @default('exiter') def _exiter_default(self): return ExitAutocall(self) # Monotonically increasing execution counter execution_count = Integer(1) filename = Unicode("") - ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__ + ipython_dir= Unicode('').tag(config=True) # Set to get_ipython_dir() in __init__ # Input splitter, to transform input line by line and detect when a block # is ready to be executed. @@ -283,88 +283,91 @@ class InteractiveShell(SingletonConfigurable): input_transformer_manager = Instance('IPython.core.inputsplitter.IPythonInputSplitter', (), {'line_input_checker': False}) - logstart = CBool(False, config=True, help= + logstart = Bool(False, help= """ Start logging to the default log file in overwrite mode. Use `logappend` to specify a log file to **append** logs to. """ - ) - logfile = Unicode('', config=True, help= + ).tag(config=True) + logfile = Unicode('', help= """ The name of the logfile to use. """ - ) - logappend = Unicode('', config=True, help= + ).tag(config=True) + logappend = Unicode('', help= """ Start logging to the given file in append mode. Use `logfile` to specify a log file to **overwrite** logs to. """ - ) + ).tag(config=True) object_info_string_level = Enum((0,1,2), default_value=0, - config=True) - pdb = CBool(False, config=True, help= + ).tag(config=True) + pdb = Bool(False, help= """ Automatically call the pdb debugger after every exception. """ - ) - multiline_history = CBool(sys.platform != 'win32', config=True, + ).tag(config=True) + multiline_history = Bool(sys.platform != 'win32', help="Save multi-line entries as one entry in readline history" - ) - display_page = Bool(False, config=True, + ).tag(config=True) + display_page = Bool(False, help="""If True, anything that would be passed to the pager will be displayed as regular output instead.""" - ) + ).tag(config=True) # deprecated prompt traits: - prompt_in1 = Unicode('In [\\#]: ', config=True, - help="Deprecated, will be removed in IPython 5.0, use PromptManager.in_template") - prompt_in2 = Unicode(' .\\D.: ', config=True, - help="Deprecated, will be removed in IPython 5.0, use PromptManager.in2_template") - prompt_out = Unicode('Out[\\#]: ', config=True, - help="Deprecated, will be removed in IPython 5.0, use PromptManager.out_template") - prompts_pad_left = CBool(True, config=True, - help="Deprecated, will be removed in IPython 5.0, use PromptManager.justify") + prompt_in1 = Unicode('In [\\#]: ', + help="Deprecated, will be removed in IPython 5.0, use PromptManager.in_template" + ).tag(config=True) + prompt_in2 = Unicode(' .\\D.: ', + help="Deprecated, will be removed in IPython 5.0, use PromptManager.in2_template" + ).tag(config=True) + prompt_out = Unicode('Out[\\#]: ', + help="Deprecated, will be removed in IPython 5.0, use PromptManager.out_template" + ).tag(config=True) + prompts_pad_left = Bool(True, + help="Deprecated, will be removed in IPython 5.0, use PromptManager.justify" + ).tag(config=True) - def _prompt_trait_changed(self, name, old, new): + @observe('prompt_in1', 'prompt_in2', 'prompt_out', 'prompt_pad_left') + def _prompt_trait_changed(self, change): table = { 'prompt_in1' : 'in_template', 'prompt_in2' : 'in2_template', 'prompt_out' : 'out_template', 'prompts_pad_left' : 'justify', } + name = change['name'] warn("InteractiveShell.{name} is deprecated, use PromptManager.{newname}".format( name=name, newname=table[name]) ) # protect against weird cases where self.config may not exist: if self.config is not None: # propagate to corresponding PromptManager trait - setattr(self.config.PromptManager, table[name], new) - - _prompt_in1_changed = _prompt_trait_changed - _prompt_in2_changed = _prompt_trait_changed - _prompt_out_changed = _prompt_trait_changed - _prompt_pad_left_changed = _prompt_trait_changed + setattr(self.config.PromptManager, table[name], change['new']) - show_rewritten_input = CBool(True, config=True, + show_rewritten_input = Bool(True, help="Show rewritten input, e.g. for autocall." - ) + ).tag(config=True) - quiet = CBool(False, config=True) + quiet = Bool(False).tag(config=True) - history_length = Integer(10000, config=True) + history_length = Integer(10000, + help='Total length of command history' + ).tag(config=True) - history_load_length = Integer(1000, config=True, help= + history_load_length = Integer(1000, help= """ The number of saved history entries to be loaded into the readline buffer at startup. """ - ) + ).tag(config=True) # The readline stuff will eventually be moved to the terminal subclass # but for now, we can't do that as readline is welded in everywhere. - readline_use = CBool(True, config=True) - readline_remove_delims = Unicode('-/~', config=True) + readline_use = Bool(True).tag(config=True) + readline_remove_delims = Unicode('-/~').tag(config=True) readline_delims = Unicode() # set by init_readline() # don't use \M- bindings by default, because they # conflict with 8-bit encodings. See gh-58,gh-88 @@ -381,29 +384,31 @@ class InteractiveShell(SingletonConfigurable): '"\e[B": history-search-forward', '"\C-k": kill-line', '"\C-u": unix-line-discard', - ], config=True) + ]).tag(config=True) _custom_readline_config = False - def _readline_parse_and_bind_changed(self, name, old, new): + @observe('readline_parse_and_bind') + def _readline_parse_and_bind_changed(self, change): # notice that readline config is customized # indicates that it should have higher priority than inputrc self._custom_readline_config = True ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none'], - default_value='last_expr', config=True, + default_value='last_expr', help=""" 'all', 'last', 'last_expr' or 'none', specifying which nodes should be - run interactively (displaying output from expressions).""") + run interactively (displaying output from expressions).""" + ).tag(config=True) # TODO: this part of prompt management should be moved to the frontends. # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n' - separate_in = SeparateUnicode('\n', config=True) - separate_out = SeparateUnicode('', config=True) - separate_out2 = SeparateUnicode('', config=True) - wildcards_case_sensitive = CBool(True, config=True) + separate_in = SeparateUnicode('\n').tag(config=True) + separate_out = SeparateUnicode('').tag(config=True) + separate_out2 = SeparateUnicode('').tag(config=True) + wildcards_case_sensitive = Bool(True).tag(config=True) xmode = CaselessStrEnum(('Context','Plain', 'Verbose'), - default_value='Context', config=True) + default_value='Context').tag(config=True) # Subcomponents of InteractiveShell alias_manager = Instance('IPython.core.alias.AliasManager', allow_none=True) @@ -522,9 +527,9 @@ class InteractiveShell(SingletonConfigurable): #------------------------------------------------------------------------- # Trait changed handlers #------------------------------------------------------------------------- - - def _ipython_dir_changed(self, name, new): - ensure_dir_exists(new) + @observe('ipython_dir') + def _ipython_dir_changed(self, change): + ensure_dir_exists(change['new']) def set_autoindent(self,value=None): """Set the autoindent flag. @@ -785,7 +790,7 @@ class InteractiveShell(SingletonConfigurable): def show_banner(self, banner=None): if banner is None: banner = self.banner - self.write(banner) + sys.stdout.write(banner) #------------------------------------------------------------------------- # Things related to hooks diff --git a/IPython/core/magic.py b/IPython/core/magic.py index 47d5ad0..c681606 100644 --- a/IPython/core/magic.py +++ b/IPython/core/magic.py @@ -12,17 +12,12 @@ from __future__ import print_function # the file COPYING, distributed as part of this software. #----------------------------------------------------------------------------- -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- -# Stdlib import os import re import sys import types from getopt import getopt, GetoptError -# Our own from traitlets.config.configurable import Configurable from IPython.core import oinspect from IPython.core.error import UsageError @@ -32,7 +27,7 @@ from IPython.utils.ipstruct import Struct from IPython.utils.process import arg_split from IPython.utils.py3compat import string_types, iteritems from IPython.utils.text import dedent -from traitlets import Bool, Dict, Instance +from traitlets import Bool, Dict, Instance, observe from logging import error #----------------------------------------------------------------------------- @@ -303,11 +298,12 @@ class MagicsManager(Configurable): shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True) - auto_magic = Bool(True, config=True, help= - "Automatically call line magics without requiring explicit % prefix") - - def _auto_magic_changed(self, name, value): - self.shell.automagic = value + auto_magic = Bool(True, help= + "Automatically call line magics without requiring explicit % prefix" + ).tag(config=True) + @observe('auto_magic') + def _auto_magic_changed(self, change): + self.shell.automagic = change['new'] _auto_status = [ 'Automagic is OFF, % prefix IS needed for line magics.', diff --git a/IPython/core/magics/script.py b/IPython/core/magics/script.py index 5dff1a3..be8fa94 100644 --- a/IPython/core/magics/script.py +++ b/IPython/core/magics/script.py @@ -1,18 +1,9 @@ """Magic functions for running cells in various scripts.""" from __future__ import print_function -#----------------------------------------------------------------------------- -# Copyright (c) 2012 The IPython Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#----------------------------------------------------------------------------- -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. -# Stdlib import errno import os import sys @@ -21,8 +12,6 @@ import time from subprocess import Popen, PIPE import atexit -# Our own packages -from traitlets.config.configurable import Configurable from IPython.core import magic_arguments from IPython.core.magic import ( Magics, magics_class, line_magic, cell_magic @@ -30,7 +19,7 @@ from IPython.core.magic import ( from IPython.lib.backgroundjobs import BackgroundJobManager from IPython.utils import py3compat from IPython.utils.process import arg_split -from traitlets import List, Dict +from traitlets import List, Dict, default #----------------------------------------------------------------------------- # Magic implementation classes @@ -79,7 +68,7 @@ class ScriptMagics(Magics): with a program in a subprocess, and registers a few top-level magics that call %%script with common interpreters. """ - script_magics = List(config=True, + script_magics = List( help="""Extra script cell magics to define This generates simple wrappers of `%%script foo` as `%%foo`. @@ -87,7 +76,8 @@ class ScriptMagics(Magics): If you want to add script magics that aren't on your path, specify them in script_paths """, - ) + ).tag(config=True) + @default('script_magics') def _script_magics_default(self): """default to a common list of programs""" @@ -108,13 +98,13 @@ class ScriptMagics(Magics): return defaults - script_paths = Dict(config=True, + script_paths = Dict( help="""Dict mapping short 'ruby' names to full paths, such as '/opt/secret/bin/ruby' Only necessary for items in script_magics where the default path will not find the right interpreter. """ - ) + ).tag(config=True) def __init__(self, shell=None): super(ScriptMagics, self).__init__(shell=shell) diff --git a/IPython/core/prefilter.py b/IPython/core/prefilter.py index af6d44e..cbed3fd 100644 --- a/IPython/core/prefilter.py +++ b/IPython/core/prefilter.py @@ -4,25 +4,10 @@ Prefiltering components. Prefilters transform user input before it is exec'd by Python. These transforms are used to implement additional syntax such as !ls and %magic. - -Authors: - -* Brian Granger -* Fernando Perez -* Dan Milstein -* Ville Vainio """ -#----------------------------------------------------------------------------- -# Copyright (C) 2008-2011 The IPython Development Team -# -# Distributed under the terms of the BSD License. The full license is in -# the file COPYING, distributed as part of this software. -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. from keyword import iskeyword import re @@ -39,7 +24,7 @@ from IPython.core.macro import Macro from IPython.core.splitinput import LineInfo from traitlets import ( - List, Integer, Unicode, CBool, Bool, Instance, CRegExp + List, Integer, Unicode, Bool, Instance, CRegExp ) #----------------------------------------------------------------------------- @@ -129,7 +114,7 @@ class PrefilterManager(Configurable): or :meth:`sort_transformers` method after changing the priority. """ - multi_line_specials = CBool(True).tag(config=True) + multi_line_specials = Bool(True).tag(config=True) shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True) def __init__(self, shell=None, **kwargs): diff --git a/IPython/core/profiledir.py b/IPython/core/profiledir.py index d855930..9c9e99c 100644 --- a/IPython/core/profiledir.py +++ b/IPython/core/profiledir.py @@ -12,7 +12,7 @@ from traitlets.config.configurable import LoggingConfigurable from IPython.paths import get_ipython_package_dir from IPython.utils.path import expand_path, ensure_dir_exists from IPython.utils import py3compat -from traitlets import Unicode, Bool +from traitlets import Unicode, Bool, observe #----------------------------------------------------------------------------- # Module errors @@ -47,17 +47,18 @@ class ProfileDir(LoggingConfigurable): pid_dir = Unicode(u'') static_dir = Unicode(u'') - location = Unicode(u'', config=True, + location = Unicode(u'', help="""Set the profile location directly. This overrides the logic used by the `profile` option.""", - ) + ).tag(config=True) _location_isset = Bool(False) # flag for detecting multiply set location - - def _location_changed(self, name, old, new): + @observe('location') + def _location_changed(self, change): if self._location_isset: raise RuntimeError("Cannot set profile location more than once.") self._location_isset = True + new = change['new'] ensure_dir_exists(new) # ensure config files exist: @@ -67,10 +68,7 @@ class ProfileDir(LoggingConfigurable): self.pid_dir = os.path.join(new, self.pid_dir_name) self.static_dir = os.path.join(new, self.static_dir_name) self.check_dirs() - - def _log_dir_changed(self, name, old, new): - self.check_log_dir() - + def _mkdir(self, path, mode=None): """ensure a directory exists at a given path @@ -104,14 +102,13 @@ class ProfileDir(LoggingConfigurable): raise return True - - def check_log_dir(self): + + @observe('log_dir') + def check_log_dir(self, change=None): self._mkdir(self.log_dir) - - def _startup_dir_changed(self, name, old, new): - self.check_startup_dir() - - def check_startup_dir(self): + + @observe('startup_dir') + def check_startup_dir(self, change=None): self._mkdir(self.startup_dir) readme = os.path.join(self.startup_dir, 'README') @@ -123,21 +120,14 @@ class ProfileDir(LoggingConfigurable): if os.path.exists(src) and not os.path.exists(readme): shutil.copy(src, readme) - def _security_dir_changed(self, name, old, new): - self.check_security_dir() - - def check_security_dir(self): + @observe('security_dir') + def check_security_dir(self, change=None): self._mkdir(self.security_dir, 0o40700) - def _pid_dir_changed(self, name, old, new): - self.check_pid_dir() - - def check_pid_dir(self): + @observe('pid_dir') + def check_pid_dir(self, change=None): self._mkdir(self.pid_dir, 0o40700) - def _static_dir_changed(self, name, old, new): - self.check_startup_dir() - def check_dirs(self): self.check_security_dir() self.check_log_dir() diff --git a/IPython/core/prompts.py b/IPython/core/prompts.py index eeb2e3f..70f2e30 100644 --- a/IPython/core/prompts.py +++ b/IPython/core/prompts.py @@ -1,24 +1,9 @@ # -*- coding: utf-8 -*- -"""Classes for handling input/output prompts. +"""Classes for handling input/output prompts.""" -Authors: - -* Fernando Perez -* Brian Granger -* Thomas Kluyver -""" - -#----------------------------------------------------------------------------- -# Copyright (C) 2008-2011 The IPython Development Team -# Copyright (C) 2001-2007 Fernando Perez -# -# Distributed under the terms of the BSD License. The full license is in -# the file COPYING, distributed as part of this software. -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- +# Copyright (c) 2001-2007 Fernando Perez +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. import os import re @@ -31,7 +16,7 @@ from string import Formatter from traitlets.config.configurable import Configurable from IPython.core import release from IPython.utils import coloransi, py3compat -from traitlets import Unicode, Instance, Dict, Bool, Int, observe +from traitlets import Unicode, Instance, Dict, Bool, Int, observe, default from IPython.utils.PyColorize import LightBGColors, LinuxColors, NoColor @@ -271,7 +256,6 @@ class PromptManager(Configurable): things like the current time in the prompts. Functions are only called if they are used in the prompt. """) - def _lazy_evaluate_fields_default(self): return lazily_evaluate.copy() in_template = Unicode('In [\\#]: ', help="Input prompt. '\\#' will be transformed to the prompt number" @@ -282,6 +266,10 @@ class PromptManager(Configurable): help="Output prompt. '\\#' will be transformed to the prompt number" ).tag(config=True) + @default('lazy_evaluate_fields') + def _lazy_evaluate_fields_default(self): + return lazily_evaluate.copy() + justify = Bool(True, help=""" If True (default), each prompt will be right-aligned with the preceding one. @@ -297,6 +285,7 @@ class PromptManager(Configurable): # The number of characters in each prompt which don't contribute to width invisible_chars = Dict() + @default('invisible_chars') def _invisible_chars_default(self): return {'in': 0, 'in2': 0, 'out': 0, 'rewrite':0} @@ -313,8 +302,8 @@ class PromptManager(Configurable): self.update_prompt('in2', self.in2_template) self.update_prompt('out', self.out_template) self.update_prompt('rewrite') - self.on_trait_change(self._update_prompt_trait, ['in_template', - 'in2_template', 'out_template']) + self.observe(self._update_prompt_trait, + names=['in_template', 'in2_template', 'out_template']) def update_prompt(self, name, new_template=None): """This is called when a prompt template is updated. It processes diff --git a/IPython/core/shellapp.py b/IPython/core/shellapp.py index 2b6b29c..9bc99af 100644 --- a/IPython/core/shellapp.py +++ b/IPython/core/shellapp.py @@ -22,7 +22,7 @@ from IPython.utils import py3compat from IPython.utils.contexts import preserve_keys from IPython.utils.path import filefind from traitlets import ( - Unicode, Instance, List, Bool, CaselessStrEnum + Unicode, Instance, List, Bool, CaselessStrEnum, default, observe, ) from IPython.lib.inputhook import guis @@ -135,76 +135,73 @@ class InteractiveShellApp(Configurable): - :meth:`init_extensions` - :meth:`init_code` """ - extensions = List(Unicode(), config=True, + extensions = List(Unicode(), help="A list of dotted module names of IPython extensions to load." - ) - extra_extension = Unicode('', config=True, + ).tag(config=True) + extra_extension = Unicode('', help="dotted module name of an IPython extension to load." - ) + ).tag(config=True) - reraise_ipython_extension_failures = Bool( - False, - config=True, + reraise_ipython_extension_failures = Bool(False, help="Reraise exceptions encountered loading IPython extensions?", - ) + ).tag(config=True) # Extensions that are always loaded (not configurable) - default_extensions = List(Unicode(), [u'storemagic'], config=False) + default_extensions = List(Unicode(), [u'storemagic']).tag(config=False) - hide_initial_ns = Bool(True, config=True, + hide_initial_ns = Bool(True, help="""Should variables loaded at startup (by startup files, exec_lines, etc.) be hidden from tools like %who?""" - ) + ).tag(config=True) - exec_files = List(Unicode(), config=True, + exec_files = List(Unicode(), help="""List of files to run at IPython startup.""" - ) - exec_PYTHONSTARTUP = Bool(True, config=True, + ).tag(config=True) + exec_PYTHONSTARTUP = Bool(True, help="""Run the file referenced by the PYTHONSTARTUP environment variable at IPython startup.""" - ) - file_to_run = Unicode('', config=True, - help="""A file to be run""") + ).tag(config=True) + file_to_run = Unicode('', + help="""A file to be run""").tag(config=True) - exec_lines = List(Unicode(), config=True, + exec_lines = List(Unicode(), help="""lines of code to run at IPython startup.""" - ) - code_to_run = Unicode('', config=True, + ).tag(config=True) + code_to_run = Unicode('', help="Execute the given command string." - ) - module_to_run = Unicode('', config=True, + ).tag(config=True) + module_to_run = Unicode('', help="Run the module as a script." - ) - gui = CaselessStrEnum(gui_keys, config=True, allow_none=True, + ).tag(config=True) + gui = CaselessStrEnum(gui_keys, allow_none=True, help="Enable GUI event loop integration with any of {0}.".format(gui_keys) - ) + ).tag(config=True) matplotlib = CaselessStrEnum(backend_keys, allow_none=True, - config=True, help="""Configure matplotlib for interactive use with the default matplotlib backend.""" - ) + ).tag(config=True) pylab = CaselessStrEnum(backend_keys, allow_none=True, - config=True, help="""Pre-load matplotlib and numpy for interactive use, selecting a particular matplotlib backend and loop integration. """ - ) - pylab_import_all = Bool(True, config=True, + ).tag(config=True) + pylab_import_all = Bool(True, help="""If true, IPython will populate the user namespace with numpy, pylab, etc. and an ``import *`` is done from numpy and pylab, when using pylab mode. When False, pylab mode should not import any names into the user namespace. """ - ) + ).tag(config=True) shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True) # whether interact-loop should start interact = Bool(True) user_ns = Instance(dict, args=None, allow_none=True) - def _user_ns_changed(self, name, old, new): + @observe('user_ns') + def _user_ns_changed(self, change): if self.shell is not None: - self.shell.user_ns = new + self.shell.user_ns = change['new'] self.shell.init_user_ns() def init_path(self): diff --git a/IPython/extensions/storemagic.py b/IPython/extensions/storemagic.py index f0ecbf3..2fd1abf 100644 --- a/IPython/extensions/storemagic.py +++ b/IPython/extensions/storemagic.py @@ -10,30 +10,17 @@ To automatically restore stored variables at startup, add this to your c.StoreMagics.autorestore = True """ from __future__ import print_function -#----------------------------------------------------------------------------- -# Copyright (c) 2012, The IPython Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- - -# Stdlib + +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. + import inspect, os, sys, textwrap -# Our own from IPython.core.error import UsageError from IPython.core.magic import Magics, magics_class, line_magic from traitlets import Bool from IPython.utils.py3compat import string_types -#----------------------------------------------------------------------------- -# Functions and classes -#----------------------------------------------------------------------------- def restore_aliases(ip): staliases = ip.db.get('stored_aliases', {}) @@ -74,11 +61,11 @@ class StoreMagics(Magics): Provides the %store magic.""" - autorestore = Bool(False, config=True, help= + autorestore = Bool(False, help= """If True, any %store-d variables will be automatically restored when IPython starts. """ - ) + ).tag(config=True) def __init__(self, shell): super(StoreMagics, self).__init__(shell=shell) diff --git a/IPython/terminal/ipapp.py b/IPython/terminal/ipapp.py index c1a3dad..02edabe 100755 --- a/IPython/terminal/ipapp.py +++ b/IPython/terminal/ipapp.py @@ -14,6 +14,7 @@ from __future__ import print_function import logging import os import sys +import warnings from traitlets.config.loader import Config from traitlets.config.application import boolean_flag, catch_config_error, Application @@ -33,10 +34,9 @@ from IPython.core.shellapp import ( ) from IPython.extensions.storemagic import StoreMagics from .ptshell import TerminalInteractiveShell -from IPython.utils import warn from IPython.paths import get_ipython_dir from traitlets import ( - Bool, List, Dict, + Bool, List, Dict, default, observe, ) #----------------------------------------------------------------------------- @@ -183,6 +183,7 @@ class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp): flags = Dict(flags) aliases = Dict(aliases) classes = List() + @default('classes') def _classes_default(self): """This has to be in a method, for TerminalIPythonApp to be available.""" return [ @@ -241,35 +242,37 @@ class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp): # *do* autocreate requested profile, but don't create the config file. auto_create=Bool(True) # configurables - quick = Bool(False, config=True, + quick = Bool(False, help="""Start IPython quickly by skipping the loading of config files.""" - ) - def _quick_changed(self, name, old, new): - if new: + ).tag(config=True) + @observe('quick') + def _quick_changed(self, change): + if change['new']: self.load_config_file = lambda *a, **kw: None - display_banner = Bool(True, config=True, + display_banner = Bool(True, help="Whether to display a banner upon starting IPython." - ) + ).tag(config=True) # if there is code of files to run from the cmd line, don't interact # unless the --i flag (App.force_interact) is true. - force_interact = Bool(False, config=True, + force_interact = Bool(False, help="""If a command or file is given via the command-line, e.g. 'ipython foo.py', start an interactive shell after executing the file or command.""" - ) - def _force_interact_changed(self, name, old, new): - if new: + ).tag(config=True) + @observe('force_interact') + def _force_interact_changed(self, change): + if change['new']: self.interact = True - def _file_to_run_changed(self, name, old, new): + @observe('file_to_run', 'code_to_run', 'module_to_run') + def _file_to_run_changed(self, change): + new = change['new'] if new: self.something_to_run = True if new and not self.force_interact: self.interact = False - _code_to_run_changed = _file_to_run_changed - _module_to_run_changed = _file_to_run_changed # internal, not-configurable something_to_run=Bool(False) @@ -284,7 +287,7 @@ class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp): # warn and transform into current syntax argv = argv[:] # copy, don't clobber idx = argv.index('-pylab') - warn.warn("`-pylab` flag has been deprecated.\n" + warnings.warn("`-pylab` flag has been deprecated.\n" " Use `--matplotlib ` and import pylab manually.") argv[idx] = '--pylab' @@ -331,7 +334,7 @@ class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp): def _pylab_changed(self, name, old, new): """Replace --pylab='inline' with --pylab='auto'""" if new == 'inline': - warn.warn("'inline' not available as pylab backend, " + warnings.warn("'inline' not available as pylab backend, " "using 'auto' instead.") self.pylab = 'auto' diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 85dbe22..fe84764 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -13,7 +13,7 @@ from IPython.core.interactiveshell import InteractiveShell from IPython.utils.py3compat import PY3, cast_unicode_py2, input from IPython.utils.terminal import toggle_set_term_title, set_term_title from IPython.utils.process import abbrev_cwd -from traitlets import Bool, CBool, Unicode, Dict, Integer, observe +from traitlets import Bool, Unicode, Dict, Integer, observe from prompt_toolkit.completion import Completer, Completion from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode @@ -100,15 +100,18 @@ class TerminalInteractiveShell(InteractiveShell): pt_cli = None - autoedit_syntax = CBool(False).tag(config=True, - help="auto editing of files with syntax errors.") + autoedit_syntax = Bool(False, + help="auto editing of files with syntax errors.", + ).tag(config=True) + - confirm_exit = CBool(True).tag(config=True, + confirm_exit = Bool(True, help=""" Set to confirm when you try to exit IPython with an EOF (Control-D in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit', you can force a direct exit without any confirmation.""", - ) + ).tag(config=True) + editing_mode = Unicode('emacs', help="Shortcut style to use at the prompt. 'vi' or 'emacs'.", ).tag(config=True) @@ -121,7 +124,9 @@ class TerminalInteractiveShell(InteractiveShell): help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles()) ).tag(config=True) - def _highlighting_style_changed(self, old, new): + + @observe('highlighting_style') + def _highlighting_style_changed(self, change): self._style = self._make_style_from_name(self.highlighting_style) highlighting_style_overrides = Dict( @@ -140,11 +145,9 @@ class TerminalInteractiveShell(InteractiveShell): help="Display a multi column completion menu.", ).tag(config=True) - @observe('term_title') - def _term_title_changed(self, change): - self.init_term_title() - def init_term_title(self): + @observe('term_title') + def init_term_title(self, change=None): # Enable or disable the terminal title. if self.term_title: toggle_set_term_title(True) diff --git a/IPython/utils/colorable.py b/IPython/utils/colorable.py index a885eef..77e9dbf 100644 --- a/IPython/utils/colorable.py +++ b/IPython/utils/colorable.py @@ -22,5 +22,5 @@ class Colorable(Configurable): """ A subclass of configurable for all the classes that have a `default_scheme` """ - default_style=Unicode('lightbg', config=True) + default_style=Unicode('lightbg').tag(config=True)