RBTools Shell command for preconfigured Python shell environment
Review Request #7936 — Created Jan. 31, 2016 and submitted
This new command
rbt shell
opens a Python shell. Works with Ipython and bpython. Imports configuration files and command options into that shell as dictionaries.Makes a client connection to a server if one is provided either as a command option or configuration option.
Can work with Ipython and bpython if installed.
Also added the command to rbtools' setup.py.
Also added documentation to rbtools/docs/rbtools/rbt/commands/shell.rst
Created test cases for shell rbtools/rbtools/commands/tests.py
Manual Testing:
Ran the command to see if it works.
Automatically made a client connection by typing
rbt shell
, and also with providing a server url.Automatically made a client connection by providing configuration keys.
Successfully made api calls from within the shell.
Installed Ipython and bpython with
pip
and made sure that both opened.Tested to see that shell would still open if an invalid shell was specified.
Automated Testing:
Test to see if Ipython module import is called
Test to see if bpython module import is called
Test messages being logged to the shell
Description | From | Last Updated |
---|---|---|
Col: 6 E113 unexpected indentation |
reviewbot | |
Col: 6 E111 indentation is not a multiple of four |
reviewbot | |
Col: 1 E302 expected 2 blank lines, found 1 |
reviewbot | |
Col: 9 E265 block comment should start with '# ' |
reviewbot | |
This looks good as a first draft You may want to have a look at https://github.com/django/django/blob/master/django/core/management/commands/shell.py Also, I'd personally love … |
brennie | |
Blank line between these. |
brennie | |
'logging' imported but unused |
reviewbot | |
'Option' imported but unused |
reviewbot | |
'LogLevelFilter' imported but unused |
reviewbot | |
'OptionGroup' imported but unused |
reviewbot | |
'get_config_paths' imported but unused |
reviewbot | |
'load_config' imported but unused |
reviewbot | |
'parse_config_file' imported but unused |
reviewbot | |
'execute' imported but unused |
reviewbot | |
'die' imported but unused |
reviewbot | |
New commands should not use die(). They should raise an exception. |
brennie | |
This should be written in the imperitive mood. i.e., 'Start a ...' |
brennie | |
How about: 'This command will inject variables into a new interactive shell from your .reviewboardrc.` |
brennie | |
You probably don't want to copy wholesale from django's shell for the final version. |
brennie | |
Col: 32 E231 missing whitespace after ':' |
reviewbot | |
Col: 34 E231 missing whitespace after ',' |
reviewbot | |
Col: 38 E231 missing whitespace after ':' |
reviewbot | |
Single quotes for strings. |
brennie | |
Why not just have readline and rlcompleter be dependencies (in setup.py) so that we're guaranteed they exist? |
brennie | |
Col: 80 E501 line too long (84 > 79 characters) |
reviewbot | |
Col: 30 E225 missing whitespace around operator |
reviewbot | |
Col: 80 E501 line too long (80 > 79 characters) |
reviewbot | |
Col: 34 E711 comparison to None should be 'if cond is not None:' |
reviewbot | |
Col: 36 E711 comparison to None should be 'if cond is not None:' |
reviewbot | |
Col: 80 E501 line too long (83 > 79 characters) |
reviewbot | |
What, exactly, are these config files going to be? |
brennie | |
Should use sentence casing. Needs a period. |
brennie | |
Parens not necessary here. |
brennie | |
Parens not necessary here. |
brennie | |
'RBClient' imported but unused |
reviewbot | |
'CONFIG_FILE' imported but unused |
reviewbot | |
Col: 1 E302 expected 2 blank lines, found 1 |
reviewbot | |
Col: 13 E128 continuation line under-indented for visual indent |
reviewbot | |
Col: 13 E128 continuation line under-indented for visual indent |
reviewbot | |
Col: 13 E128 continuation line under-indented for visual indent |
reviewbot | |
Col: 13 E128 continuation line under-indented for visual indent |
reviewbot | |
local variable 'e' is assigned to but never used |
reviewbot | |
Col: 18 E127 continuation line over-indented for visual indent |
reviewbot | |
I don't think we need to include this, since the attribute is being added at the same time as the … |
david | |
No blank line necessary here. |
david | |
This is a little cleaner as: except Exception as e: logging.error('Could not run script "%s" for RBTools shell: %s", script_path, … |
david | |
You can skip the conditional if you do this instead; for import_command in config.get('SHELL_IMPORTS', []): |
david | |
A better way to wrap this is to put the stuff in the parens on the next line: readline.set_completer( rlcompleter.Completer(namespace).complete) … |
david | |
'logging' imported but unused |
reviewbot | |
'os' imported but unused |
reviewbot | |
'sys' imported but unused |
reviewbot | |
'Option' imported but unused |
reviewbot | |
'load_config' imported but unused |
reviewbot | |
Col: 1 E302 expected 2 blank lines, found 1 |
reviewbot | |
Col: 9 E124 closing bracket does not match visual indentation |
reviewbot | |
Col: 9 E124 closing bracket does not match visual indentation |
reviewbot | |
I think it would be useful to have a config key that allows you to use ipython or bpython. e.g., … |
brennie | |
"pre-configured" |
brennie | |
I would have these both use the same config key and use store_const e.g. option_list = [ Option('-i', '--ipython', config_key='SHELL', … |
brennie | |
I feel like we should have namespace[config] = self.config namespace[options] = vars(self.options) so that we don't pollute namespace. |
brennie | |
Not necessary. |
brennie | |
Not necessary. |
brennie | |
We should inform the user that, if we can't find their server settings, that client and root are not defined. … |
brennie | |
Not necessary. |
brennie | |
You can move the code.interact() call to below the except: block if you return early in the iPython or bpython … |
brennie | |
Doesn't need parentheses. |
brennie | |
Use a dict literal: namespace = { 'config': self.config, 'options': vars(self.options), } |
brennie | |
Can we add a --quiet/ -q option (that can be controlled by a .reviewboardrc option too) to disable these statements? |
brennie | |
This should use logging.exception and print an error message about what failed. |
brennie | |
Same comment about -q. |
brennie | |
This should probably be: elif shell Otherwise if shell is None (for default Python shell), it will always print this. |
brennie | |
I dont think we need this. |
brennie | |
Python |
brennie | |
Suppress |
brennie | |
Docstring w/ args? |
brennie | |
Blank line between these. |
brennie | |
Blank line between these. |
brennie | |
'spy_on' imported but unused |
reviewbot | |
Col: 1 E302 expected 2 blank lines, found 1 |
reviewbot | |
Your test case should inheirit from SpyAgency. Then in unit tests you can use self.spy_on(foo, ...) without having to set … |
brennie | |
Not too sure what this line is doing. Did the test intend to call shell.ipython() instead of assigning the classmethod … |
SS ssengar | |
local variable 'ipython_module' is assigned to but never used |
reviewbot | |
If the objective of the test was to make sure shell.bpython wasn't called, it should probably spy on it explicitly … |
SS ssengar | |
Again, did the test intend to call shell.bpython() instead of assigning the classmethod to a variable? |
SS ssengar | |
local variable 'bpython_module' is assigned to but never used |
reviewbot | |
If you add SpyAgency as a parent class, you can use self.spy_on(shell.method_name). This has several advantages: you don't have to … |
SS ssengar | |
local variable 'bpython_module' is assigned to but never used |
reviewbot | |
Maybe I'm missing something but is there a need to spy on shell.ipython at the end of the test? If … |
SS ssengar | |
local variable 'ipython_module' is assigned to but never used |
reviewbot | |
Same as comment for line 61. |
SS ssengar | |
local variable 'client' is assigned to but never used |
reviewbot | |
Again, is the spy operation on shell.bpython repated for a particular reason? |
SS ssengar | |
Col: 25 E128 continuation line under-indented for visual indent |
reviewbot | |
Col: 33 E128 continuation line under-indented for visual indent |
reviewbot | |
Col: 80 E501 line too long (80 > 79 characters) |
reviewbot | |
'spy_on' imported but unused |
reviewbot | |
Col: 1 E302 expected 2 blank lines, found 1 |
reviewbot | |
Col: 1 W391 blank line at end of file |
reviewbot | |
Col: 34 W292 no newline at end of file |
reviewbot | |
Can you break these up into multiple test cases, e.g.: def test_ipython(self): # raise SkipTest if we don't have ipython … |
brennie | |
These tests aren't actually testing anything. |
brennie | |
shell.ipython can never return None. maybe update the method to return none if it cant get the shell? |
brennie | |
These tests dont test the results. See above comments. |
brennie | |
These don't test the results of calling log_message. |
brennie | |
Needs "Returns" |
brennie | |
Needs "returns" |
brennie | |
Blank line between these. |
brennie | |
No periods at the end of test cases. Same for all test cases in this file. |
brennie | |
You don't need unspy calls at the end of test -- they will automatically be called. |
brennie | |
Can you split this into multiple tests? |
brennie |
- Commit:
-
d92f33e6b0756abe507018c2d8eb8d12297f4dcf83520bf4dd3fc4e4ccc6f16fe90ef79480a85b74
- Diff:
-
Revision 2 (+32)
- Commit:
-
83520bf4dd3fc4e4ccc6f16fe90ef79480a85b74c73fa56e0919bd5eafbf6e131fa1731499f54497
- Diff:
-
Revision 3 (+56)
-
Tool: Pyflakes Processed Files: rbtools/commands/shell.py setup.py Tool: PEP8 Style Checker Processed Files: rbtools/commands/shell.py setup.py
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Tool: PEP8 Style Checker Processed Files: rbtools/commands/shell.py setup.py Tool: Pyflakes Processed Files: rbtools/commands/shell.py setup.py
-
Tool: Pyflakes Processed Files: rbtools/commands/shell.py setup.py Tool: PEP8 Style Checker Processed Files: rbtools/commands/shell.py setup.py
-
-
-
-
-
-
-
-
-
Tool: Pyflakes Processed Files: rbtools/commands/shell.py setup.py Tool: PEP8 Style Checker Processed Files: rbtools/commands/shell.py setup.py
-
This is looking pretty great!
-
I don't think we need to include this, since the attribute is being added at the same time as the command as a whole. These are there so we can document when new attributes were added to existing commands.
We probably should have a top-level "added_in" for the command, that will generate the appropriate note in the documentation.
-
-
This is a little cleaner as:
except Exception as e: logging.error('Could not run script "%s" for RBTools shell: %s", script_path, e)
-
You can skip the conditional if you do this instead;
for import_command in config.get('SHELL_IMPORTS', []):
-
A better way to wrap this is to put the stuff in the parens on the next line:
readline.set_completer( rlcompleter.Completer(namespace).complete)
Alternatively, you could do
from rlcompleter import Completer
at the top and then just useCompleter(...)
here.
-
Tool: Pyflakes Processed Files: rbtools/commands/shell.py setup.py Tool: PEP8 Style Checker Processed Files: rbtools/commands/shell.py setup.py
-
-
-
-
-
Tool: Pyflakes Processed Files: rbtools/commands/shell.py setup.py Tool: PEP8 Style Checker Processed Files: rbtools/commands/shell.py setup.py
-
Hey, this change looks good. I've got some suggestions for you.
Also, this command will need documentation. Have a look in
docs/rbtools/rbt/commands/
for examples. -
I think it would be useful to have a config key that allows you to use ipython or bpython. e.g., you could set the following in your .reviewboardrc:
SHELL = 'ipython'
or
SHELL = 'bpython'
Then you can have
-i
and-b
override this setting. -
-
I would have these both use the same config key and use
store_const
e.g.
option_list = [ Option('-i', '--ipython', config_key='SHELL', dest='shell', action='store_const', const='ipython', ...), Option('-i', '--bpython', dest='shell', action='store_const', const='bpython', ...) ]
NB: This also takes into account the above suggestion for
SHELL
, which only has to be on one option I believe. -
I feel like we should have
namespace[config] = self.config namespace[options] = vars(self.options)
so that we don't pollute
namespace
. -
-
-
We should inform the user that, if we can't find their server settings, that
client
androot
are not defined. (Or inform them of the opposite when they are defined. Either one is fine.) -
-
You can move the
code.interact()
call to below theexcept:
block if you return early in the iPython or bpython cases.
-
Tool: PEP8 Style Checker Processed Files: rbtools/commands/shell.py setup.py Tool: Pyflakes Processed Files: rbtools/commands/shell.py setup.py
-
Tool: PEP8 Style Checker Processed Files: rbtools/commands/shell.py setup.py Ignored Files: docs/rbtools/rbt/commands/shell.rst Tool: Pyflakes Processed Files: rbtools/commands/shell.py setup.py Ignored Files: docs/rbtools/rbt/commands/shell.rst
-
Tool: Pyflakes Processed Files: rbtools/commands/shell.py setup.py Ignored Files: docs/rbtools/rbt/commands/shell.rst Tool: PEP8 Style Checker Processed Files: rbtools/commands/shell.py setup.py Ignored Files: docs/rbtools/rbt/commands/shell.rst
- Description:
-
~ Created basic template for shell command by emulating how other commands were done. Looked around the commands and util directories for modules I thought I might need and imported them.
~ This new command
rbt shell
opens a python shell. Works with ipython and bpython. Imports configuration files and command options into that shell as dictionaries.+ + Makes a client connection to a server if one is provided either as a command option or configuration option.
Also added the command to rbtools' setup.py.
+ + Also added documentation to rbtools/docs/rbtools/rbt/commands/shell.rst
- Testing Done:
-
~ Nothing yet.
~ Rbt shell doesn't use any of the API so only manual testing was done:
+ + Ran the command to see if it works.
+ + Automatically made a connection connection by typing
rbt shell
, and also with providing a server url.+ + Successfully made api calls from within the shell.
+ + Installed ipython and bpython with
pip
and made sure that both opened.+ + Tested to see that shell would still open if an invalid shell was specified.
-
Tool: Pyflakes Processed Files: rbtools/commands/shell.py setup.py Ignored Files: docs/rbtools/rbt/commands/shell.rst Tool: PEP8 Style Checker Processed Files: rbtools/commands/shell.py setup.py Ignored Files: docs/rbtools/rbt/commands/shell.rst
- Description:
-
This new command
rbt shell
opens a python shell. Works with ipython and bpython. Imports configuration files and command options into that shell as dictionaries.Makes a client connection to a server if one is provided either as a command option or configuration option.
+ Can work with ipython and bpython if installed.
+ Also added the command to rbtools' setup.py.
Also added documentation to rbtools/docs/rbtools/rbt/commands/shell.rst
- Summary:
-
RBTools Shell command for preconfigured python shell environmentRBTools Shell command for preconfigured Python shell environment
- Description:
-
~ This new command
rbt shell
opens a python shell. Works with ipython and bpython. Imports configuration files and command options into that shell as dictionaries.~ This new command
rbt shell
opens a Python shell. Works with Ipython and bpython. Imports configuration files and command options into that shell as dictionaries.Makes a client connection to a server if one is provided either as a command option or configuration option.
~ Can work with ipython and bpython if installed.
~ Can work with Ipython and bpython if installed.
Also added the command to rbtools' setup.py.
Also added documentation to rbtools/docs/rbtools/rbt/commands/shell.rst
- Testing Done:
-
Rbt shell doesn't use any of the API so only manual testing was done:
Ran the command to see if it works.
Automatically made a connection connection by typing
rbt shell
, and also with providing a server url.Successfully made api calls from within the shell.
~ Installed ipython and bpython with
pip
and made sure that both opened.~ Installed Ipython and bpython with
pip
and made sure that both opened.Tested to see that shell would still open if an invalid shell was specified.
-
Tool: PEP8 Style Checker Processed Files: rbtools/commands/shell.py setup.py Ignored Files: docs/rbtools/rbt/commands/shell.rst Tool: Pyflakes Processed Files: rbtools/commands/shell.py setup.py Ignored Files: docs/rbtools/rbt/commands/shell.rst
-
Tool: Pyflakes Processed Files: rbtools/commands/shell.py rbtools/commands/tests.py setup.py Ignored Files: docs/rbtools/rbt/commands/shell.rst Tool: PEP8 Style Checker Processed Files: rbtools/commands/shell.py rbtools/commands/tests.py setup.py Ignored Files: docs/rbtools/rbt/commands/shell.rst
-
-
-
-
-
-
-
-
Great work, your project seems awesome! In this review, I gave you some feedback on your test cases. I apologize in advance if some of my feedback is irrelevant/incorrect. I'm not very familiar with the rbt shell command, so most of my feedback was based on intuition + my limited knowledge of kgb spies.
-
-
-
Not too sure what this line is doing. Did the test intend to call shell.ipython() instead of assigning the classmethod to a variable?
-
If the objective of the test was to make sure shell.bpython wasn't called, it should probably spy on it explicitly using agency.spy_on(shell.bpython) at the start of the test.
-
Again, did the test intend to call shell.bpython() instead of assigning the classmethod to a variable?
-
If you add SpyAgency as a parent class, you can use self.spy_on(shell.method_name). This has several advantages: you don't have to create a new SpyAgency for each test, and it will automatically unspy after each test case (which is both less code and more robust if there are unexpected exceptions). Documentation on how to do this can be found in the README at https://github.com/beanbaginc/kgb
-
Maybe I'm missing something but is there a need to spy on shell.ipython at the end of the test? If not, it's probably a good idea to take this line out.
-
-
-
Tool: PEP8 Style Checker Processed Files: rbtools/commands/shell.py rbtools/commands/tests.py setup.py Ignored Files: docs/rbtools/rbt/commands/shell.rst Tool: Pyflakes Processed Files: rbtools/commands/shell.py rbtools/commands/tests.py setup.py Ignored Files: docs/rbtools/rbt/commands/shell.rst
-
-
-
-
-
-
- Description:
-
This new command
rbt shell
opens a Python shell. Works with Ipython and bpython. Imports configuration files and command options into that shell as dictionaries.Makes a client connection to a server if one is provided either as a command option or configuration option.
Can work with Ipython and bpython if installed.
Also added the command to rbtools' setup.py.
Also added documentation to rbtools/docs/rbtools/rbt/commands/shell.rst
+ + Created test cases for shell rbtools/rbtools/commands/tests.py
- Testing Done:
-
~ Rbt shell doesn't use any of the API so only manual testing was done:
~ Manual Testing:
Ran the command to see if it works.
~ Automatically made a connection connection by typing
rbt shell
, and also with providing a server url.~ Automatically made a client connection by typing
rbt shell
, and also with providing a server url.+ + Automatically made a client connection by providing configuration keys.
Successfully made api calls from within the shell.
Installed Ipython and bpython with
pip
and made sure that both opened.Tested to see that shell would still open if an invalid shell was specified.
+ + Automated Testing:
+ + Test to see if Ipython module import is called
+ + Test to see if bpython module import is called
+ + Test messages being logged to the shell
-
Tool: PEP8 Style Checker Processed Files: rbtools/commands/shell.py rbtools/commands/tests.py setup.py Ignored Files: docs/rbtools/rbt/commands/shell.rst Tool: Pyflakes Processed Files: rbtools/commands/shell.py rbtools/commands/tests.py setup.py Ignored Files: docs/rbtools/rbt/commands/shell.rst
-
-
Tool: PEP8 Style Checker Processed Files: rbtools/commands/shell.py rbtools/commands/tests.py setup.py Ignored Files: docs/rbtools/rbt/commands/shell.rst Tool: Pyflakes Processed Files: rbtools/commands/shell.py rbtools/commands/tests.py setup.py Ignored Files: docs/rbtools/rbt/commands/shell.rst
-
-
Can you break these up into multiple test cases, e.g.:
def test_ipython(self): # raise SkipTest if we don't have ipython installed. pass def test_ipython_not_installed(self): # Ensure that `ipython()` returns `None`. pass # ...
-
-
shell.ipython
can never return None. maybe update the method to return none if it cant get the shell? -
-
-
Tool: Pyflakes Processed Files: rbtools/commands/shell.py rbtools/commands/tests.py setup.py Ignored Files: docs/rbtools/rbt/commands/shell.rst Tool: PEP8 Style Checker Processed Files: rbtools/commands/shell.py rbtools/commands/tests.py setup.py Ignored Files: docs/rbtools/rbt/commands/shell.rst
-
Tool: Pyflakes Processed Files: rbtools/commands/shell.py rbtools/commands/tests.py setup.py Ignored Files: docs/rbtools/rbt/commands/shell.rst Tool: PEP8 Style Checker Processed Files: rbtools/commands/shell.py rbtools/commands/tests.py setup.py Ignored Files: docs/rbtools/rbt/commands/shell.rst