summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xcmd2.py140
-rw-r--r--docs/conf.py2
-rw-r--r--docs/settingchanges.rst52
-rw-r--r--tests/conftest.py4
-rw-r--r--tests/test_cmd2.py3
5 files changed, 104 insertions, 97 deletions
diff --git a/cmd2.py b/cmd2.py
index d8c8583a..3a198f8c 100755
--- a/cmd2.py
+++ b/cmd2.py
@@ -496,45 +496,95 @@ class EmptyStatement(Exception):
class Cmd(cmd.Cmd):
- echo = False
- case_insensitive = True # Commands recognized regardless of case
- continuation_prompt = '> '
- timing = False # Prints elapsed time for each command
+ # TODO: Move all instance member initializations inside __init__()
+
+ # Attributes which are NOT dynamically settable at runtime
+ _STOP_AND_EXIT = True # distinguish end of script file from actual exit
+ _STOP_SCRIPT_NO_EXIT = -999
+ blankLinesAllowed = False
+ colorcodes = {'bold': {True: '\x1b[1m', False: '\x1b[22m'},
+ 'cyan': {True: '\x1b[36m', False: '\x1b[39m'},
+ 'blue': {True: '\x1b[34m', False: '\x1b[39m'},
+ 'red': {True: '\x1b[31m', False: '\x1b[39m'},
+ 'magenta': {True: '\x1b[35m', False: '\x1b[39m'},
+ 'green': {True: '\x1b[32m', False: '\x1b[39m'},
+ 'underline': {True: '\x1b[4m', False: '\x1b[24m'},
+ 'yellow': {True: '\x1b[33m', False: '\x1b[39m'},
+ }
+ commentGrammars = pyparsing.Or([pyparsing.pythonStyleComment, pyparsing.cStyleComment])
+ commentGrammars.addParseAction(lambda x: '')
+ commentInProgress = pyparsing.Literal('/*') + pyparsing.SkipTo(pyparsing.stringEnd ^ '*/')
+ current_script_dir = None
+ default_to_shell = False
+ defaultExtension = 'txt' # For ``save``, ``load``, etc.
+ excludeFromHistory = '''run r list l history hi ed edit li eof'''.split()
+ kept_state = None
# make sure your terminators are not in legalChars!
legalChars = u'!#$%.:?@_' + pyparsing.alphanums + pyparsing.alphas8bit
- shortcuts = {'?': 'help', '!': 'shell', '@': 'load', '@@': '_relative_load'}
- excludeFromHistory = '''run r list l history hi ed edit li eof'''.split()
- default_to_shell = False
+ multilineCommands = []
noSpecialParse = 'set ed edit exit'.split()
- defaultExtension = 'txt' # For ``save``, ``load``, etc.
- default_file_name = 'command.txt' # For ``save``, ``load``, etc.
- abbrev = True # Abbreviated commands recognized
- current_script_dir = None
+ prefixParser = pyparsing.Empty()
+ redirector = '>' # for sending output to file
reserved_words = []
- feedback_to_output = False # Do include nonessentials in >, | output
- quiet = False # Do not suppress nonessential output
+ saveparser = (pyparsing.Optional(pyparsing.Word(pyparsing.nums) ^ '*')("idx") +
+ pyparsing.Optional(pyparsing.Word(legalChars + '/\\'))("fname") +
+ pyparsing.stringEnd)
+ shortcuts = {'?': 'help', '!': 'shell', '@': 'load', '@@': '_relative_load'}
+ terminators = [';']
+ urlre = re.compile('(https?://[-\\w\\./]+)')
+
+ # Attributes which ARE dynamicaly settable at runtime
+ abbrev = True # Abbreviated commands recognized
+ autorun_on_edit = True # Should files automatically run after editing (doesn't apply to commands)
+ case_insensitive = True # Commands recognized regardless of case
+ colors = (platform.system() != 'Windows')
+ continuation_prompt = '> '
debug = False
+ default_file_name = 'command.txt' # For ``save``, ``load``, etc.
+ echo = False
+ editor = os.environ.get('EDITOR')
+ if not editor:
+ if sys.platform[:3] == 'win':
+ editor = 'notepad'
+ else:
+ # Favor command-line editors first so we don't leave the terminal to edit
+ for editor in ['vim', 'vi', 'emacs', 'nano', 'pico', 'gedit', 'kate', 'subl', 'geany', 'atom']:
+ if _which(editor):
+ break
+ feedback_to_output = False # Do include nonessentials in >, | output
locals_in_py = True
- kept_state = None
- redirector = '>' # for sending output to file
- autorun_on_edit = True # Should files automatically run after editing (doesn't apply to commands)
+ quiet = False # Do not suppress nonessential output
+ timing = False # Prints elapsed time for each command
+ # To make an attribute settable with the "do_set" command, add it to this ...
settable = stubbornDict('''
- prompt
+ abbrev Accept abbreviated commands
+ autorun_on_edit Automatically run files after editing
+ case_insensitive upper- and lower-case both OK
colors Colorized output (*nix only)
continuation_prompt On 2nd+ line of input
debug Show full error stack on error
default_file_name for ``save``, ``load``, etc.
+ echo Echo command issued into output
editor Program used by ``edit``
- case_insensitive upper- and lower-case both OK
feedback_to_output include nonessentials in `|`, `>` results
+ locals_in_py Allow access to your application in py via self
+ prompt The prompt issued to solicit input
quiet Don't print nonessential feedback
- echo Echo command issued into output
timing Report execution times
- abbrev Accept abbreviated commands
- autorun_on_edit Automatically run files after editing
''')
+ def __init__(self, *args, **kwargs):
+ cmd.Cmd.__init__(self, *args, **kwargs)
+ self.initial_stdout = sys.stdout
+ self.history = History()
+ self.pystate = {}
+ self.shortcuts = sorted(self.shortcuts.items(), reverse=True)
+ self.keywords = self.reserved_words + [fname[3:] for fname in dir(self)
+ if fname.startswith('do_')]
+ self._init_parser()
+ self._temp_filename = None
+
def poutput(self, msg):
'''Convenient shortcut for self.stdout.write(); adds newline if necessary.'''
if msg:
@@ -573,29 +623,6 @@ class Cmd(cmd.Cmd):
else:
print(msg)
- _STOP_AND_EXIT = True # distinguish end of script file from actual exit
- _STOP_SCRIPT_NO_EXIT = -999
- editor = os.environ.get('EDITOR')
- if not editor:
- if sys.platform[:3] == 'win':
- editor = 'notepad'
- else:
- # Favor command-line editors first so we don't leave the terminal to edit
- for editor in ['vim', 'vi', 'emacs', 'nano', 'pico', 'gedit', 'kate', 'subl', 'geany', 'atom']:
- if _which(editor):
- break
-
- colorcodes = {'bold': {True: '\x1b[1m', False: '\x1b[22m'},
- 'cyan': {True: '\x1b[36m', False: '\x1b[39m'},
- 'blue': {True: '\x1b[34m', False: '\x1b[39m'},
- 'red': {True: '\x1b[31m', False: '\x1b[39m'},
- 'magenta': {True: '\x1b[35m', False: '\x1b[39m'},
- 'green': {True: '\x1b[32m', False: '\x1b[39m'},
- 'underline': {True: '\x1b[4m', False: '\x1b[24m'},
- 'yellow': {True: '\x1b[33m', False: '\x1b[39m'},
- }
- colors = (platform.system() != 'Windows')
-
def colorize(self, val, color):
'''Given a string (``val``), returns that string wrapped in UNIX-style
special characters that turn on (and then off) text color and style.
@@ -631,30 +658,11 @@ class Cmd(cmd.Cmd):
else:
cmd.Cmd.do_help(self, arg)
- def __init__(self, *args, **kwargs):
- cmd.Cmd.__init__(self, *args, **kwargs)
- self.initial_stdout = sys.stdout
- self.history = History()
- self.pystate = {}
- self.shortcuts = sorted(self.shortcuts.items(), reverse=True)
- self.keywords = self.reserved_words + [fname[3:] for fname in dir(self)
- if fname.startswith('do_')]
- self._init_parser()
- self._temp_filename = None
-
def do_shortcuts(self, args):
"""Lists single-key shortcuts available."""
result = "\n".join('%s: %s' % (sc[0], sc[1]) for sc in sorted(self.shortcuts))
self.stdout.write("Single-key shortcuts for other commands:\n{}\n".format(result))
- prefixParser = pyparsing.Empty()
- commentGrammars = pyparsing.Or([pyparsing.pythonStyleComment, pyparsing.cStyleComment])
- commentGrammars.addParseAction(lambda x: '')
- commentInProgress = pyparsing.Literal('/*') + pyparsing.SkipTo(pyparsing.stringEnd ^ '*/')
- terminators = [';']
- blankLinesAllowed = False
- multilineCommands = []
-
def _init_parser(self):
r'''
>>> c = Cmd()
@@ -1388,10 +1396,6 @@ class Cmd(cmd.Cmd):
if self.autorun_on_edit or buffer:
self.do_load(filename)
- saveparser = (pyparsing.Optional(pyparsing.Word(pyparsing.nums) ^ '*')("idx") +
- pyparsing.Optional(pyparsing.Word(legalChars + '/\\'))("fname") +
- pyparsing.stringEnd)
-
def do_save(self, arg):
"""`save [N] [filename.ext]`
@@ -1450,8 +1454,6 @@ class Cmd(cmd.Cmd):
targetname = os.path.join(self.current_script_dir or '', targetname)
self.do_load('%s %s' % (targetname, args))
- urlre = re.compile('(https?://[-\\w\\./]+)')
-
def do_load(self, arg=None):
"""Runs script of command(s) from a file or URL."""
# If arg is None or arg is an empty string, use the default filename
diff --git a/docs/conf.py b/docs/conf.py
index 59dfb8d8..fdd6db8c 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -70,7 +70,7 @@ language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
-exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', 'pycon2010']
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
diff --git a/docs/settingchanges.rst b/docs/settingchanges.rst
index 290e4e08..d2bf2cc7 100644
--- a/docs/settingchanges.rst
+++ b/docs/settingchanges.rst
@@ -4,21 +4,21 @@ Features requiring only parameter changes
Several aspects of a ``cmd2`` application's behavior
can be controlled simply by setting attributes of ``App``.
-A parameter can also be changed at runtime by the user *if*
+A parameter can also be changed at runtime by the user *if*
its name is included in the dictionary ``app.settable``.
(To define your own user-settable parameters, see :ref:`parameters`)
Case-insensitivity
==================
-By default, all ``cmd2`` command names are case-insensitive;
-``sing the blues`` and ``SiNg the blues`` are equivalent. To change this,
+By default, all ``cmd2`` command names are case-insensitive;
+``sing the blues`` and ``SiNg the blues`` are equivalent. To change this,
set ``App.case_insensitive`` to False.
Whether or not you set ``case_insensitive``, *please do not* define
command method names with any uppercase letters. ``cmd2`` will probably
do something evil if you do.
-
+
Shortcuts
=========
@@ -28,16 +28,16 @@ like ``!ls``. By default, the following shortcuts are defined:
``?``
help
-
- ``!``
+
+ ``!``
shell: run as OS-level command
-
+
``@``
load script file
-
+
``@@``
load script file; filename is relative to current script location
-
+
To define more shortcuts, update the dict ``App.shortcuts`` with the
{'shortcut': 'command_name'} (omit ``do_``)::
@@ -56,7 +56,7 @@ shortcut::
(Cmd) !which python
/usr/bin/python
-However, if the parameter ``default_to_shell`` is
+However, if the parameter ``default_to_shell`` is
``True``, then *every* command will be attempted on
the operating system. Only if that attempt fails
(i.e., produces a nonzero return value) will the
@@ -90,9 +90,10 @@ Setting ``App.debug`` to ``True`` will produce detailed error stacks
whenever the application generates an error. |settable|
.. |settable| replace:: The user can ``set`` this parameter
- during application execution.
+ during application execution.
(See :ref:`parameters`)
+.. _parameters:
Other user-settable parameters
==============================
@@ -101,18 +102,19 @@ A list of all user-settable parameters, with brief
comments, is viewable from within a running application
with::
- (Cmd) set --long
- abbrev: True # Accept abbreviated commands
- case_insensitive: True # upper- and lower-case both OK
- colors: True # Colorized output (*nix only)
- continuation_prompt: > # On 2nd+ line of input
- debug: False # Show full error stack on error
- default_file_name: command.txt # for ``save``, ``load``, etc.
- echo: False # Echo command issued into output
- editor: gedit # Program used by ``edit``
- feedback_to_output: False # include nonessentials in `|`, `>` results
- prompt: (Cmd) #
- quiet: False # Don't print nonessential feedback
- timing: False # Report execution times
-
+ (Cmd) set --long
+ abbrev: True # Accept abbreviated commands
+ autorun_on_edit: True # Automatically run files after editing
+ case_insensitive: True # upper- and lower-case both OK
+ colors: True # Colorized output (*nix only)
+ continuation_prompt: > # On 2nd+ line of input
+ debug: False # Show full error stack on error
+ default_file_name: command.txt # for ``save``, ``load``, etc.
+ echo: False # Echo command issued into output
+ editor: vim # Program used by ``edit``
+ feedback_to_output: False # include nonessentials in `|`, `>` results
+ locals_in_py: True # Allow access to your application in py via self
+ prompt: (Cmd) # The prompt issued to solicit input
+ quiet: False # Don't print nonessential feedback
+ timing: False # Report execution times
diff --git a/tests/conftest.py b/tests/conftest.py
index 4b12f5cd..8bc11497 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -55,6 +55,7 @@ default_file_name: command.txt
echo: False
editor: vim
feedback_to_output: False
+locals_in_py: True
prompt: (Cmd)
quiet: False
timing: False
@@ -74,7 +75,8 @@ default_file_name: command.txt # for ``save``, ``load``, etc.
echo: False # Echo command issued into output
editor: vim # Program used by ``edit``
feedback_to_output: False # include nonessentials in `|`, `>` results
-prompt: (Cmd) #
+locals_in_py: True # Allow access to your application in py via self
+prompt: (Cmd) # The prompt issued to solicit input
quiet: False # Don't print nonessential feedback
timing: False # Report execution times
""".format(color_str)
diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py
index b89f96d4..39669397 100644
--- a/tests/test_cmd2.py
+++ b/tests/test_cmd2.py
@@ -206,7 +206,8 @@ def test_base_cmdenvironment(base_app):
# Settable parameters can be listed in any order, so need to validate carefully using unordered sets
settable_params = {'continuation_prompt', 'default_file_name', 'prompt', 'abbrev', 'quiet', 'case_insensitive',
- 'colors', 'echo', 'timing', 'editor', 'feedback_to_output', 'debug', 'autorun_on_edit'}
+ 'colors', 'echo', 'timing', 'editor', 'feedback_to_output', 'debug', 'autorun_on_edit',
+ 'locals_in_py'}
out_params = set(out[2].split("Settable parameters: ")[1].split())
assert settable_params == out_params