From 4ccb4dbab3799d7c2f53ef0a5ec768883196e9b3 Mon Sep 17 00:00:00 2001 From: Mark McCahill Date: Mon, 14 Sep 2015 12:34:16 -0400 Subject: [PATCH 1/5] update for Jupyter 4 get rid of the traitlets warnings Signed-off-by: Mark McCahill --- setup.py | 8 ++------ src/sql/magic.py | 4 ++-- src/tests/test_parse.py | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/setup.py b/setup.py index 48555dc04..1153fbe9d 100644 --- a/setup.py +++ b/setup.py @@ -2,12 +2,8 @@ import sys, os here = os.path.abspath(os.path.dirname(__file__)) -README = open(os.path.join(here, 'README.rst')).read() -NEWS = open(os.path.join(here, 'NEWS.txt')).read() - - -version = '0.3.7.1' - +README = 'Slightly modified version for Jupyter 4 based on ipython-sql from Catherine Devlin at https://github.com/catherinedevlin/ipython-sql' +version = '0.3.7.2' install_requires = [ 'prettytable', 'ipython>=1.0', diff --git a/src/sql/magic.py b/src/sql/magic.py index 4e30fa51f..889c79a18 100644 --- a/src/sql/magic.py +++ b/src/sql/magic.py @@ -1,7 +1,7 @@ import re from IPython.core.magic import Magics, magics_class, cell_magic, line_magic, needs_local_scope -from IPython.config.configurable import Configurable -from IPython.utils.traitlets import Bool, Int, Unicode +from traitlets.config.configurable import Configurable +from traitlets import Bool, Int, Unicode try: from pandas.core.frame import DataFrame, Series except ImportError: diff --git a/src/tests/test_parse.py b/src/tests/test_parse.py index 84f65f50e..4b5079cf1 100644 --- a/src/tests/test_parse.py +++ b/src/tests/test_parse.py @@ -1,6 +1,6 @@ from sql.parse import parse from six.moves import configparser -from IPython.config.configurable import Configurable +from traitlets.config.configurable import Configurable empty_config = Configurable() From b8b5ca4752ce42fef4a2b009fab7e4b4b8253ae1 Mon Sep 17 00:00:00 2001 From: Mark McCahill Date: Mon, 14 Sep 2015 13:56:10 -0400 Subject: [PATCH 2/5] get rid of dangling NEWS reference Signed-off-by: Mark McCahill --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 1153fbe9d..f28526f68 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ setup(name='ipython-sql', version=version, description="RDBMS access via IPython", - long_description=README + '\n\n' + NEWS, + long_description=README + '\n\n', classifiers=[ 'Development Status :: 3 - Alpha', 'Environment :: Console', From 43b29492970a3fa6581f0537d42dd42f3509f10b Mon Sep 17 00:00:00 2001 From: Mark McCahill Date: Fri, 13 Nov 2015 14:59:13 -0500 Subject: [PATCH 3/5] set default limits on display and results For student use, default the limits for rows returned (100000) and rows displayed (1000) to sizes that will not crash their web browser or pound the SQL server. You can still reset the limits if you want, but this raises the barrier to shooting yourself in the foot. Signed-off-by: Mark McCahill --- README.rst | 17 ++++++++++------- src/sql/magic.py | 4 ++-- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/README.rst b/README.rst index 1436d1bc9..0bfe2ef15 100644 --- a/README.rst +++ b/README.rst @@ -123,11 +123,14 @@ Configuration ------------- Query results are loaded as lists, so very large result sets may use up -your system's memory and/or hang your browser. There is no autolimit -by default. However, `autolimit` (if set) limits the size of the result -set (usually with a `LIMIT` clause in the SQL). `displaylimit` is similar, -but the entire result set is still pulled into memory (for later analysis); -only the screen display is truncated. +your system's memory and/or hang your browser. Autolimit is set to 100000 +by default. The `autolimit` (if set) limits the size of the result +set (usually with a `LIMIT` clause in the SQL). The `displaylimit` is +similar, but the entire result set is still pulled into memory +(for later analysis); only the screen display is truncated. The +`displaylimit` is set to 1000 by default. These seem to be optimal limits +to protect students from killing their web browsers or the SQL server +with ill-formed queries. .. code-block:: python @@ -135,13 +138,13 @@ only the screen display is truncated. SqlMagic options -------------- SqlMagic.autolimit= - Current: 0 + Current: 100000 Automatically limit the size of the returned result sets SqlMagic.autopandas= Current: False Return Pandas DataFrames instead of regular result sets SqlMagic.displaylimit= - Current: 0 + Current: 1000 Automatically limit the number of rows displayed (full result set is still stored) SqlMagic.feedback= diff --git a/src/sql/magic.py b/src/sql/magic.py index 889c79a18..813bccc1f 100644 --- a/src/sql/magic.py +++ b/src/sql/magic.py @@ -21,10 +21,10 @@ class SqlMagic(Magics, Configurable): Provides the %%sql magic.""" - autolimit = Int(0, config=True, help="Automatically limit the size of the returned result sets") + autolimit = Int(100000, config=True, help="Automatically limit the size of the returned result sets") style = Unicode('DEFAULT', config=True, help="Set the table printing style to any of prettytable's defined styles (currently DEFAULT, MSWORD_FRIENDLY, PLAIN_COLUMNS, RANDOM)") short_errors = Bool(True, config=True, help="Don't display the full traceback on SQL Programming Error") - displaylimit = Int(0, config=True, help="Automatically limit the number of rows displayed (full result set is still stored)") + displaylimit = Int(1000, config=True, help="Automatically limit the number of rows displayed (full result set is still stored)") autopandas = Bool(False, config=True, help="Return Pandas DataFrames instead of regular result sets") column_local_vars = Bool(False, config=True, help="Return data into local variables from column names") feedback = Bool(True, config=True, help="Print number of rows affected by DML") From 94540d4993c69f4ddc25b344bf10975faa90db1b Mon Sep 17 00:00:00 2001 From: Mark McCahill Date: Fri, 9 Dec 2016 14:56:20 -0500 Subject: [PATCH 4/5] update to track new ipython-sql version Signed-off-by: Mark McCahill --- .gitignore | 1 + HACKING.txt | 6 ++---- LICENSE | 21 +++++++++++++++++++++ MANIFEST.in | 1 + NEWS.txt | 11 +++++++++++ README.rst | 32 ++++++++++++++++++++++++-------- run_tests.sh | 1 + setup.py | 13 +++++++++---- src/sql/magic.py | 10 +++++++--- src/tests/test_magic.py | 7 +++++++ src/tests/test_parse.py | 5 ++++- 11 files changed, 88 insertions(+), 20 deletions(-) create mode 100644 LICENSE diff --git a/.gitignore b/.gitignore index d2d6f360b..83fea0f27 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ nosetests.xml .mr.developer.cfg .project .pydevproject +.DS_Store diff --git a/HACKING.txt b/HACKING.txt index 5a16441f7..f53e1ef59 100644 --- a/HACKING.txt +++ b/HACKING.txt @@ -1,10 +1,8 @@ Development setup ================= -To create a buildout, - - $ python bootstrap.py - $ bin/buildout +Running nose tests with IPython is tricky, so there's a +run_tests.sh script for it. Release HOWTO ============= diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..fa5629966 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2014 Catherine Devlin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/MANIFEST.in b/MANIFEST.in index 1e7e56847..910adaed4 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,3 @@ include README.rst include NEWS.txt +include LICENSE diff --git a/NEWS.txt b/NEWS.txt index 4a2a8954e..23a10a56d 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -134,3 +134,14 @@ result sets ------- * Avoid "connection busy" error for SQL Server (thanks Andrés Celis) + +0.3.8 +----- + +* Stop warnings for deprecated use of IPython 3 traitlets in IPython 4 (thanks graphaelli; also stonebig, aebrahim, mccahill) +* README update for keeping connection info private, from eshilts + +0.3.9 +----- + +* Fix truth value of DataFrame error (thanks michael-erasmus) diff --git a/README.rst b/README.rst index 0bfe2ef15..7bf8a9a23 100644 --- a/README.rst +++ b/README.rst @@ -64,6 +64,16 @@ an existing connection by username@database ====================== Poet 733 +For secure access, you may dynamically access your credentials (e.g. from your system environment or `getpass.getpass`) to avoid storing your password in the notebook itself. Use the `$` before any variable to access it in your `%sql` command. + +.. code-block:: python + + In [11]: user = os.getenv('SOME_USER') + ....: password = os.getenv('SOME_PASSWORD') + ....: connection_string = "postgresql://{user}:{password}@localhost/some_database".format(user=user, password=password) + ....: %sql $connection_string + Out[11]: u'Connected: some_user@some_database' + You may use multiple SQL statements inside a single cell, but you will only see any query results from the last of them, so this really only makes sense for statements with no output @@ -123,14 +133,16 @@ Configuration ------------- Query results are loaded as lists, so very large result sets may use up -your system's memory and/or hang your browser. Autolimit is set to 100000 -by default. The `autolimit` (if set) limits the size of the result -set (usually with a `LIMIT` clause in the SQL). The `displaylimit` is -similar, but the entire result set is still pulled into memory -(for later analysis); only the screen display is truncated. The -`displaylimit` is set to 1000 by default. These seem to be optimal limits -to protect students from killing their web browsers or the SQL server -with ill-formed queries. +your system's memory and/or hang your browser. There is no autolimit +by default. However, `autolimit` (if set) limits the size of the result +set (usually with a `LIMIT` clause in the SQL). `displaylimit` is similar, +but the entire result set is still pulled into memory (for later analysis); +only the screen display is truncated. + +For student use, default the limits for rows returned (100000) and rows +displayed (1000) to sizes that will not crash their web browser or pound +the SQL server. You can still reset the limits if you +want, but this raises the barrier to shooting yourself in the foot. .. code-block:: python @@ -160,6 +172,8 @@ with ill-formed queries. In[3]: %config SqlMagic.feedback = False +Please note: if you have autopandas set to true, the displaylimit option will not apply. You can set the pandas display limit by using the pandas ``max_rows`` option as described in the `pandas documentation `_. + Pandas ------ @@ -237,6 +251,8 @@ Credits - Thomas Kluyver and Steve Holden for debugging help - Berton Earnshaw for DSN connection syntax - Andrés Celis for SQL Server bugfix +- Michael Erasmus for DataFrame truth bugfix +- Noam Finkelstein for README clarification .. _Distribute: http://pypi.python.org/pypi/distribute .. _Buildout: http://www.buildout.org/ diff --git a/run_tests.sh b/run_tests.sh index fbd434f75..99688775a 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -1 +1,2 @@ ipython -c "import nose; nose.run()" +# Insert breakpoints with `from nose.tools import set_trace; set_trace()` diff --git a/setup.py b/setup.py index f28526f68..c9f727b59 100644 --- a/setup.py +++ b/setup.py @@ -2,21 +2,26 @@ import sys, os here = os.path.abspath(os.path.dirname(__file__)) -README = 'Slightly modified version for Jupyter 4 based on ipython-sql from Catherine Devlin at https://github.com/catherinedevlin/ipython-sql' -version = '0.3.7.2' +README = open(os.path.join(here, 'README.rst')).read() +NEWS = open(os.path.join(here, 'NEWS.txt')).read() + + +version = '0.3.9' + install_requires = [ 'prettytable', 'ipython>=1.0', 'sqlalchemy>=0.6.7', 'sqlparse', 'six', + 'ipython-genutils>=0.1.0', ] setup(name='ipython-sql', version=version, description="RDBMS access via IPython", - long_description=README + '\n\n', + long_description=README + '\n\n' + NEWS, classifiers=[ 'Development Status :: 3 - Alpha', 'Environment :: Console', @@ -29,7 +34,7 @@ keywords='database ipython postgresql mysql', author='Catherine Devlin', author_email='catherine.devlin@gmail.com', - url='pypi.python.org/pypi/ipython-sql', + url='https://pypi.python.org/pypi/ipython-sql', license='MIT', packages=find_packages('src'), package_dir = {'': 'src'}, diff --git a/src/sql/magic.py b/src/sql/magic.py index 813bccc1f..0244fb3be 100644 --- a/src/sql/magic.py +++ b/src/sql/magic.py @@ -1,7 +1,11 @@ import re from IPython.core.magic import Magics, magics_class, cell_magic, line_magic, needs_local_scope -from traitlets.config.configurable import Configurable -from traitlets import Bool, Int, Unicode +try: + from traitlets.config.configurable import Configurable + from traitlets import Bool, Int, Unicode +except ImportError: + from IPython.config.configurable import Configurable + from IPython.utils.traitlets import Bool, Int, Unicode try: from pandas.core.frame import DataFrame, Series except ImportError: @@ -82,7 +86,7 @@ def execute(self, line, cell='', local_ns={}): try: result = sql.run.run(conn, parsed['sql'], self, user_ns) - if result and ~isinstance(result, str) and self.column_local_vars: + if result is not None and ~isinstance(result, str) and self.column_local_vars: #Instead of returning values, set variables directly in the #users namespace. Variable names given by column names diff --git a/src/tests/test_magic.py b/src/tests/test_magic.py index 527b6f417..0d553d720 100644 --- a/src/tests/test_magic.py +++ b/src/tests/test_magic.py @@ -125,3 +125,10 @@ def test_bind_vars(): ip.user_global_ns['x'] = 22 result = ip.run_line_magic('sql', "sqlite:// SELECT :x") assert result[0][0] == 22 + +@with_setup(_setup, _teardown) +def test_autopandas(): + ip.run_line_magic('config', "SqlMagic.autopandas = True") + dframe = ip.run_cell("%sql SELECT * FROM test;") + assert dframe.success + assert dframe.result.name[0] == 'foo' diff --git a/src/tests/test_parse.py b/src/tests/test_parse.py index 4b5079cf1..143c02be2 100644 --- a/src/tests/test_parse.py +++ b/src/tests/test_parse.py @@ -1,6 +1,9 @@ from sql.parse import parse from six.moves import configparser -from traitlets.config.configurable import Configurable +try: + from traitlets.config.configurable import Configurable +except ImportError: + from IPython.config.configurable import Configurable empty_config = Configurable() From 22c1c9c359f34d3eddd695d74a040440f3dd0314 Mon Sep 17 00:00:00 2001 From: Mark McCahill Date: Fri, 9 Dec 2016 15:38:19 -0500 Subject: [PATCH 5/5] update to new version Signed-off-by: Mark McCahill --- .gitignore | 1 + LICENSE | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 LICENSE diff --git a/.gitignore b/.gitignore index d2d6f360b..83fea0f27 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ nosetests.xml .mr.developer.cfg .project .pydevproject +.DS_Store diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..fa5629966 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2014 Catherine Devlin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.