[Python-modules-commits] [python-pgspecial] 01/07: Import python-pgspecial_1.8.0.orig.tar.gz
ChangZhuo Chen
czchen at moszumanska.debian.org
Tue Jun 6 12:24:33 UTC 2017
This is an automated email from the git hooks/post-receive script.
czchen pushed a commit to branch debian/experimental
in repository python-pgspecial.
commit fdcdce524a54bf568ac753d60b62d560cbd1826f
Author: ChangZhuo Chen (陳昌倬) <czchen at debian.org>
Date: Tue Jun 6 20:15:50 2017 +0800
Import python-pgspecial_1.8.0.orig.tar.gz
---
PKG-INFO | 2 +-
pgspecial.egg-info/PKG-INFO | 2 +-
pgspecial/__init__.py | 2 +-
pgspecial/dbcommands.py | 89 +++++----
pgspecial/iocommands.py | 25 ++-
pgspecial/main.py | 1 -
.../test_specials.cpython-27-PYTEST.pyc | Bin 19482 -> 32806 bytes
tests/dbutils.py | 11 +-
tests/dbutils.pyc | Bin 2497 -> 2692 bytes
tests/test_specials.py | 208 ++++++++++++++++++++-
10 files changed, 284 insertions(+), 56 deletions(-)
diff --git a/PKG-INFO b/PKG-INFO
index 7ecc020..d557cc3 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: pgspecial
-Version: 1.7.0
+Version: 1.8.0
Summary: Meta-commands handler for Postgres Database.
Home-page: http://pgcli.com
Author: Amjith Ramanujam
diff --git a/pgspecial.egg-info/PKG-INFO b/pgspecial.egg-info/PKG-INFO
index 7ecc020..d557cc3 100644
--- a/pgspecial.egg-info/PKG-INFO
+++ b/pgspecial.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: pgspecial
-Version: 1.7.0
+Version: 1.8.0
Summary: Meta-commands handler for Postgres Database.
Home-page: http://pgcli.com
Author: Amjith Ramanujam
diff --git a/pgspecial/__init__.py b/pgspecial/__init__.py
index 32d911c..8851104 100644
--- a/pgspecial/__init__.py
+++ b/pgspecial/__init__.py
@@ -1,5 +1,5 @@
__all__ = []
-__version__ = '1.7.0'
+__version__ = '1.8.0'
def export(defn):
diff --git a/pgspecial/dbcommands.py b/pgspecial/dbcommands.py
index 4091ac0..99b6208 100644
--- a/pgspecial/dbcommands.py
+++ b/pgspecial/dbcommands.py
@@ -1,5 +1,6 @@
import logging
from collections import namedtuple
+
from .main import special_command, RAW_QUERY
TableInfo = namedtuple("TableInfo", ['checks', 'relkind', 'hasindex',
@@ -75,7 +76,7 @@ def list_roles(cur, pattern, verbose):
@special_command('\\db', '\\db[+] [pattern]', 'List tablespaces.')
-def list_tablestpaces(cur, pattern, **_):
+def list_tablespaces(cur, pattern, **_):
"""
Returns (title, rows, headers, status)
"""
@@ -192,13 +193,13 @@ def _find_extensions(cur, pattern):
def _describe_extension(cur, oid):
sql = '''
- SELECT pg_catalog.pg_describe_object(classid, objid, 0)
+ SELECT pg_catalog.pg_describe_object(classid, objid, 0)
AS "Object Description"
- FROM pg_catalog.pg_depend
+ FROM pg_catalog.pg_depend
WHERE refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass
AND refobjid = %s
AND deptype = 'e'
- ORDER BY 1 '''
+ ORDER BY 1'''
sql = cur.mogrify(sql, [oid])
log.debug(sql)
cur.execute(sql)
@@ -211,7 +212,8 @@ def list_objects(cur, pattern, verbose, relkinds):
"""
Returns (title, rows, header, status)
- This method is used by list_tables, list_views, and list_indexes
+ This method is used by list_tables, list_views, list_materialized views
+ and list_indexes
relkinds is a list of strings to filter pg_class.relkind
@@ -276,6 +278,11 @@ def list_views(cur, pattern, verbose):
return list_objects(cur, pattern, verbose, ['v', 's', ''])
+ at special_command('\\dm', '\\dm[+] [pattern]', 'List materialized views.')
+def list_materialized_views(cur, pattern, verbose):
+ return list_objects(cur, pattern, verbose, ['m', 's', ''])
+
+
@special_command('\\ds', '\\ds[+] [pattern]', 'List sequences.')
def list_sequences(cur, pattern, verbose):
return list_objects(cur, pattern, verbose, ['S', 's', ''])
@@ -448,38 +455,15 @@ def list_datatypes(cur, pattern, verbose):
@special_command('describe', 'DESCRIBE [pattern]', '', hidden=True, case_sensitive=False)
- at special_command('\\d', '\\d [pattern]', 'List or describe tables, views and sequences.')
+ at special_command('\\d', '\\d[+] [pattern]', 'List or describe tables, views and sequences.')
def describe_table_details(cur, pattern, verbose):
"""
Returns (title, rows, headers, status)
"""
- # This is a simple \d command. No table name to follow.
+ # This is a simple \d[+] command. No table name to follow.
if not pattern:
- sql = """SELECT n.nspname as "Schema", c.relname as "Name",
- CASE c.relkind WHEN 'r' THEN 'table'
- WHEN 'v' THEN 'view'
- WHEN 'm' THEN 'materialized view'
- WHEN 'i' THEN 'index'
- WHEN 'S' THEN 'sequence'
- WHEN 's' THEN 'special'
- WHEN 'f' THEN 'foreign table'
- END as "Type",
- pg_catalog.pg_get_userbyid(c.relowner) as "Owner"
- FROM pg_catalog.pg_class c
- LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
- WHERE c.relkind IN ('r','v','m','S','f','')
- AND n.nspname <> 'pg_catalog'
- AND n.nspname <> 'information_schema'
- AND n.nspname !~ '^pg_toast'
- AND pg_catalog.pg_table_is_visible(c.oid)
- ORDER BY 1,2 """
-
- log.debug(sql)
- cur.execute(sql)
- if cur.description:
- headers = [x[0] for x in cur.description]
- return [(None, cur, headers, cur.statusmessage)]
+ return list_objects(cur, pattern, verbose, ['r', 'v', 'm', 'S', 'f', ''])
# This is a \d <tablename> command. A royal pain in the ass.
schema, relname = sql_name_pattern(pattern)
@@ -656,8 +640,6 @@ def describe_one_table_details(cur, schema_name, relation_name, oid, verbose):
cur.execute(sql)
res = cur.fetchall()
- title = (tableinfo.relkind, schema_name, relation_name)
-
# Set the column names.
headers = ['Column', 'Type']
@@ -996,7 +978,7 @@ def describe_one_table_details(cur, schema_name, relation_name, oid, verbose):
for row in cur:
#/* untranslated contraint name and def */
status.append(" \"%s\" %s" % row)
- status.append('\n')
+ status.append('\n')
#/* print foreign-key constraints (there are none if no triggers) */
if (tableinfo.hastriggers):
@@ -1310,3 +1292,42 @@ def sql_name_pattern(pattern):
schema = '^(' + schema + ')$'
return schema, relname
+
+
+class _FakeCursor(list):
+ "Minimalistic wrapper simulating a real cursor, as far as pgcli is concerned."
+
+ def rowcount(self):
+ return len(self)
+
+
+ at special_command('\\sf', '\\sf[+] FUNCNAME', 'Show a function\'s definition.')
+def show_function_definition(cur, pattern, verbose):
+ if '(' in pattern:
+ sql = cur.mogrify("SELECT %s::pg_catalog.regprocedure::pg_catalog.oid", [pattern])
+ else:
+ sql = cur.mogrify("SELECT %s::pg_catalog.regproc::pg_catalog.oid", [pattern])
+ log.debug(sql)
+ cur.execute(sql)
+ (foid,) = cur.fetchone()
+
+ sql = cur.mogrify("SELECT pg_catalog.pg_get_functiondef(%s) as source", [foid])
+ log.debug(sql)
+ cur.execute(sql)
+ if cur.description:
+ headers = [x[0] for x in cur.description]
+ if verbose:
+ (source,) = cur.fetchone()
+ rows = _FakeCursor()
+ rown = None
+ for row in source.splitlines():
+ if rown is None:
+ if row.startswith('AS '):
+ rown = 1
+ else:
+ rown += 1
+ rows.append('%-7s %s' % ('' if rown is None else rown, row))
+ cur = [('\n'.join(rows) + '\n',)]
+ else:
+ headers = None
+ return [(None, cur, headers, None)]
diff --git a/pgspecial/iocommands.py b/pgspecial/iocommands.py
index 14a869c..5544a70 100644
--- a/pgspecial/iocommands.py
+++ b/pgspecial/iocommands.py
@@ -43,13 +43,8 @@ def get_watch_command(command):
@export
-def open_external_editor(filename=None, sql=''):
- """
- Open external editor, wait for the user to type in his query,
- return the query.
- :return: list with one tuple, query as first element.
- """
-
+def get_editor_query(sql):
+ """Get the query part of an editor command."""
sql = sql.strip()
# The reason we can't simply do .strip('\e') is that it strips characters,
@@ -59,15 +54,27 @@ def open_external_editor(filename=None, sql=''):
while pattern.search(sql):
sql = pattern.sub('', sql)
+ return sql
+
+
+ at export
+def open_external_editor(filename=None, sql=None):
+ """
+ Open external editor, wait for the user to type in his query,
+ return the query.
+ :return: list with one tuple, query as first element.
+ """
+
message = None
filename = filename.strip().split(' ', 1)[0] if filename else None
+ sql = sql or ''
MARKER = '# Type your query above this line.\n'
# Populate the editor buffer with the partial sql (if available) and a
# placeholder comment.
- query = click.edit(sql + '\n\n' + MARKER, filename=filename,
- extension='.sql')
+ query = click.edit('{sql}\n\n{marker}'.format(sql=sql, marker=MARKER),
+ filename=filename, extension='.sql')
if filename:
try:
diff --git a/pgspecial/main.py b/pgspecial/main.py
index 202f5d0..d9e0f02 100644
--- a/pgspecial/main.py
+++ b/pgspecial/main.py
@@ -240,7 +240,6 @@ def doc_only():
@special_command('\\ef', '\\ef [funcname [line]]', 'Edit the contents of the query buffer.', arg_type=NO_QUERY, hidden=True)
- at special_command('\\sf', '\\sf[+] FUNCNAME', 'Show a function\'s definition.', arg_type=NO_QUERY, hidden=True)
@special_command('\\do', '\\do[S] [pattern]', 'List operators.', arg_type=NO_QUERY, hidden=True)
@special_command('\\dp', '\\dp [pattern]', 'List table, view, and sequence access privileges.', arg_type=NO_QUERY, hidden=True)
@special_command('\\z', '\\z [pattern]', 'Same as \\dp.', arg_type=NO_QUERY, hidden=True)
diff --git a/tests/__pycache__/test_specials.cpython-27-PYTEST.pyc b/tests/__pycache__/test_specials.cpython-27-PYTEST.pyc
index 16f8c12..7f67762 100644
Binary files a/tests/__pycache__/test_specials.cpython-27-PYTEST.pyc and b/tests/__pycache__/test_specials.cpython-27-PYTEST.pyc differ
diff --git a/tests/dbutils.py b/tests/dbutils.py
index 4d13527..a454f65 100644
--- a/tests/dbutils.py
+++ b/tests/dbutils.py
@@ -45,13 +45,18 @@ def setup_db(conn):
# tables
cur.execute('create table tbl1(id1 integer, txt1 text, CONSTRAINT id_text PRIMARY KEY(id1, txt1))')
- cur.execute('create table tbl2(id2 integer, txt2 text)')
+ cur.execute('create table tbl2(id2 serial, txt2 text)')
cur.execute('create table schema1.s1_tbl1(id1 integer, txt1 text)')
# views
cur.execute('create view vw1 as select * from tbl1')
- cur.execute('''create view schema1.s1_vw1 as select * from
- schema1.s1_tbl1''')
+ cur.execute('''create view schema1.s1_vw1 as
+ select * from schema1.s1_tbl1''')
+
+ # materialized views
+ cur.execute('create materialized view mvw1 as select * from tbl1')
+ cur.execute('''create materialized view schema1.s1_mvw1 as
+ select * from schema1.s1_tbl1''')
# datatype
cur.execute('create type foo AS (a int, b text)')
diff --git a/tests/dbutils.pyc b/tests/dbutils.pyc
index a464794..9aaa852 100644
Binary files a/tests/dbutils.pyc and b/tests/dbutils.pyc differ
diff --git a/tests/test_specials.py b/tests/test_specials.py
index 5499e3f..4b4aa6f 100644
--- a/tests/test_specials.py
+++ b/tests/test_specials.py
@@ -3,18 +3,37 @@
from dbutils import dbtest, POSTGRES_USER
import itertools
-from codecs import open
+
+objects_listing_headers = ['Schema', 'Name', 'Type', 'Owner', 'Size', 'Description']
@dbtest
def test_slash_d(executor):
results = executor('\d')
title = None
- rows = [('public', 'tbl1', 'table', POSTGRES_USER),
+ rows = [('public', 'mvw1', 'materialized view', POSTGRES_USER),
+ ('public', 'tbl1', 'table', POSTGRES_USER),
('public', 'tbl2', 'table', POSTGRES_USER),
+ ('public', 'tbl2_id2_seq', 'sequence', POSTGRES_USER),
('public', 'vw1', 'view', POSTGRES_USER)]
- headers = ['Schema', 'Name', 'Type', 'Owner']
- status = 'SELECT 3'
+ headers = objects_listing_headers[:-2]
+ status = 'SELECT 5'
+ expected = [title, rows, headers, status]
+
+ assert results == expected
+
+
+ at dbtest
+def test_slash_d_verbose(executor):
+ results = executor('\d+')
+ title = None
+ rows = [('public', 'mvw1', 'materialized view', POSTGRES_USER, '8192 bytes', None),
+ ('public', 'tbl1', 'table', POSTGRES_USER, '8192 bytes', None),
+ ('public', 'tbl2', 'table', POSTGRES_USER, '8192 bytes', None),
+ ('public', 'tbl2_id2_seq', 'sequence', POSTGRES_USER, '8192 bytes', None),
+ ('public', 'vw1', 'view', POSTGRES_USER, '0 bytes', None)]
+ headers = objects_listing_headers
+ status = 'SELECT 5'
expected = [title, rows, headers, status]
assert results == expected
@@ -34,6 +53,19 @@ def test_slash_d_table(executor):
@dbtest
+def test_slash_d_table_verbose(executor):
+ results = executor('\d+ tbl1')
+ title = None
+ rows = [['id1', 'integer', ' not null', 'plain', None, None],
+ ['txt1', 'text', ' not null', 'extended', None, None],
+ ]
+ headers = ['Column', 'Type', 'Modifiers', 'Storage', 'Stats target', 'Description']
+ status = 'Indexes:\n "id_text" PRIMARY KEY, btree (id1, txt1)\nHas OIDs: no\n'
+ expected = [title, rows, headers, status]
+ assert results == expected
+
+
+ at dbtest
def test_slash_dn(executor):
"""List all schemas."""
results = executor('\dn')
@@ -54,13 +86,122 @@ def test_slash_dt(executor):
title = None
rows = [('public', 'tbl1', 'table', POSTGRES_USER),
('public', 'tbl2', 'table', POSTGRES_USER)]
- headers = ['Schema', 'Name', 'Type', 'Owner']
+ headers = objects_listing_headers[:-2]
+ status = 'SELECT 2'
+ expected = [title, rows, headers, status]
+ assert results == expected
+
+
+ at dbtest
+def test_slash_dt_verbose(executor):
+ """List all tables in public schema in verbose mode."""
+ results = executor('\dt+')
+ title = None
+ rows = [('public', 'tbl1', 'table', POSTGRES_USER, '8192 bytes', None),
+ ('public', 'tbl2', 'table', POSTGRES_USER, '8192 bytes', None)]
+ headers = objects_listing_headers
status = 'SELECT 2'
expected = [title, rows, headers, status]
assert results == expected
@dbtest
+def test_slash_dv(executor):
+ """List all views in public schema."""
+ results = executor('\dv')
+ title = None
+ row = [('public', 'vw1', 'view', POSTGRES_USER)]
+ headers = objects_listing_headers[:-2]
+ status = 'SELECT 1'
+ expected = [title, row, headers, status]
+ assert results == expected
+
+
+ at dbtest
+def test_slash_dv_verbose(executor):
+ """List all views in s1 schema in verbose mode."""
+ results = executor('\dv+ schema1.*')
+ title = None
+ row = [('schema1', 's1_vw1', 'view', POSTGRES_USER, '0 bytes', None)]
+ headers = objects_listing_headers
+ status = 'SELECT 1'
+ expected = [title, row, headers, status]
+ assert results == expected
+
+
+ at dbtest
+def test_slash_dm(executor):
+ """List all materialized views in schema1."""
+ results = executor('\dm schema1.*')
+ title = None
+ row = [('schema1', 's1_mvw1', 'materialized view', POSTGRES_USER)]
+ headers = objects_listing_headers[:-2]
+ status = 'SELECT 1'
+ expected = [title, row, headers, status]
+ assert results == expected
+
+
+ at dbtest
+def test_slash_dm_verbose(executor):
+ """List all materialized views in public schema in verbose mode."""
+ results = executor('\dm+')
+ title = None
+ row = [('public', 'mvw1', 'materialized view', POSTGRES_USER, '8192 bytes', None)]
+ headers = objects_listing_headers
+ status = 'SELECT 1'
+ expected = [title, row, headers, status]
+ assert results == expected
+
+
+ at dbtest
+def test_slash_ds(executor):
+ """List all sequences in public schema."""
+ results = executor('\ds')
+ title = None
+ row = [('public', 'tbl2_id2_seq', 'sequence', POSTGRES_USER)]
+ headers = objects_listing_headers[:-2]
+ status = 'SELECT 1'
+ expected = [title, row, headers, status]
+ assert results == expected
+
+
+ at dbtest
+def test_slash_ds_verbose(executor):
+ """List all sequences in public schema in verbose mode."""
+ results = executor('\ds+')
+ title = None
+ row = [('public', 'tbl2_id2_seq', 'sequence', POSTGRES_USER, '8192 bytes', None)]
+ headers = objects_listing_headers
+ status = 'SELECT 1'
+ expected = [title, row, headers, status]
+ assert results == expected
+
+
+ at dbtest
+def test_slash_di(executor):
+ """List all indexes in public schema."""
+ results = executor('\di')
+ title = None
+ row = [('public', 'id_text', 'index', POSTGRES_USER)]
+ headers = objects_listing_headers[:-2]
+ status = 'SELECT 1'
+ expected = [title, row, headers, status]
+ assert results == expected
+
+
+ at dbtest
+def test_slash_di_verbose(executor):
+ """List all indexes in public schema in verbose mode."""
+ results = executor('\di+')
+ title = None
+ row = [('public', 'id_text', 'index', POSTGRES_USER, '8192 bytes', None)]
+ headers = objects_listing_headers
+ status = 'SELECT 1'
+ expected = [title, row, headers, status]
+ assert results == expected
+
+
+ at dbtest
def test_slash_dT(executor):
"""List all datatypes."""
results = executor('\dT')
@@ -150,7 +291,7 @@ def test_slash_copy_to_csv(executor, tmpdir):
filepath = tmpdir.join('pycons.tsv')
executor(u"\copy (SELECT 'Montréal', 'Portland', 'Cleveland') TO '{0}' WITH csv"
.format(filepath))
- infile =filepath.open(encoding='utf-8')
+ infile = filepath.open(encoding='utf-8')
contents = infile.read()
assert len(contents.splitlines()) == 1
assert u'Montréal' in contents
@@ -167,3 +308,58 @@ def test_slash_copy_from_csv(executor, connection, tmpdir):
cur.execute("SELECT * FROM tbl1 WHERE id1 = 22")
row = cur.fetchone()
assert row[1] == 'elephant'
+
+
+ at dbtest
+def test_slash_sf(executor):
+ results = executor('\sf func1')
+ title = None
+ rows = [('CREATE OR REPLACE FUNCTION public.func1()\n'
+ ' RETURNS integer\n'
+ ' LANGUAGE sql\n'
+ 'AS $function$select 1$function$\n',),
+ ]
+ headers = ['source']
+ status = None
+ expected = [title, rows, headers, status]
+ assert results == expected
+
+
+ at dbtest
+def test_slash_sf_unknown(executor):
+ try:
+ executor('\sf non_existing')
+ except Exception as e:
+ assert 'non_existing' in str(e)
+ else:
+ assert False, "Expected an exception"
+
+
+ at dbtest
+def test_slash_sf_parens(executor):
+ results = executor('\sf func1()')
+ title = None
+ rows = [('CREATE OR REPLACE FUNCTION public.func1()\n'
+ ' RETURNS integer\n'
+ ' LANGUAGE sql\n'
+ 'AS $function$select 1$function$\n',),
+ ]
+ headers = ['source']
+ status = None
+ expected = [title, rows, headers, status]
+ assert results == expected
+
+
+ at dbtest
+def test_slash_sf_verbose(executor):
+ results = executor('\sf+ schema1.s1_func1')
+ title = None
+ rows = [(' CREATE OR REPLACE FUNCTION schema1.s1_func1()\n'
+ ' RETURNS integer\n'
+ ' LANGUAGE sql\n'
+ '1 AS $function$select 2$function$\n',),
+ ]
+ headers = ['source']
+ status = None
+ expected = [title, rows, headers, status]
+ assert results == expected
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-pgspecial.git
More information about the Python-modules-commits
mailing list