diff --git a/.travis.yml b/.travis.yml index 0ec705b..26986ac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,8 @@ language: python python: - - "2.6" - "2.7" - - "3.3" - "3.4" -install: - - if [[ $TRAVIS_PYTHON_VERSION == 2.6 ]]; then pip install unittest2; fi + - "3.5" + - "3.5" + - "3.6" script: python setup.py test diff --git a/Makefile b/Makefile index b579d27..aa6539b 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,10 @@ APP=postdoc VERSION=0.4.0 -clean: +help: ## Shows this help + @echo "$$(grep -h '#\{2\}' $(MAKEFILE_LIST) | sed 's/: #\{2\} / /' | column -t -s ' ')" + +clean: ## Clean project find . -name "*.pyc" -delete find . -name ".DS_Store" -delete rm -rf *.egg @@ -11,17 +14,13 @@ clean: rm -rf build rm -rf dist - -test: +test: ## Run test suite python setup.py test - -# Set the version. Done this way to avoid fancy, brittle Python import magic -version: +version: ## Set version number @sed -i -r /version/s/[0-9.]+/$(VERSION)/ setup.py @sed -i -r /__version__\ =/s/[0-9.]+/$(VERSION)/ postdoc.py - # Release Instructions: # # 1. bump version number at the top of this file @@ -33,8 +32,6 @@ release: clean version @-pip install wheel > /dev/null python setup.py sdist bdist_wheel upload - -# makes it easier to test setup.py's entry points -install: +install: ## Install (makes it easier to test setup.py's entry points) -pip uninstall $(APP) --yes pip install . diff --git a/postdoc.py b/postdoc.py index c4fc861..878e0c5 100755 --- a/postdoc.py +++ b/postdoc.py @@ -24,29 +24,6 @@ __version__ = '0.4.0' -# DEPRECATED, too many commands to whitelist now -# http://www.postgresql.org/docs/9.3/static/reference-client.html -VALID_COMMANDS = ( - 'clusterdb', - 'createdb', - 'createlang', - 'createuser', - 'dropdb', - 'droplang', - 'dropuser', - 'ecpg', - 'pg_basebackup', - 'pg_config', - 'pg_dump', - 'pg_dumpall', - 'pg_isready', - 'pg_receivexlog', - 'pg_restore', - 'psql', - 'reindexdb', - 'vacuumdb', -) - def get_uri(env='DATABASE_URL'): """Grab and parse the url from the environment.""" @@ -115,10 +92,6 @@ def get_command(command, meta): def make_tokens_and_env(sys_argv): """Get the tokens or quit with help.""" - # if sys_argv[1] not in VALID_COMMANDS: - # exit('Usage: phd COMMAND [additional-options]\n\n' - # ' ERROR: "%s" is not a known postgres command' % sys_argv[1]) - if sys_argv[1].isupper(): environ_key = sys_argv[1] args = sys_argv[2:] @@ -133,7 +106,7 @@ def make_tokens_and_env(sys_argv): tokens = get_command(args[0], meta) except AttributeError: exit('Usage: phd COMMAND [additional-options]\n\n' - ' ERROR: "{0}" is not set in the environment'.format(environ_key)) + ' ERROR: "{0}" is not set in the environment'.format(environ_key)) env = os.environ.copy() # password as environment variable, set it for non-postgres schemas anyways if meta.password: diff --git a/test_postdoc.py b/test_postdoc.py index a61568a..02a427a 100644 --- a/test_postdoc.py +++ b/test_postdoc.py @@ -1,11 +1,7 @@ # -*- coding: utf-8 -*- import os -try: - # for python 2.6 compatibility - import unittest2 as unittest -except ImportError: - import unittest +import unittest import mock @@ -21,13 +17,13 @@ class ConnectBitsTest(unittest.TestCase): def test_pg_connect_bits_trivial_case(self): meta = type('mock', (object, ), - {'username': '', 'hostname': '', 'port': ''}) + {'username': '', 'hostname': '', 'port': ''}) result = postdoc.pg_connect_bits(meta) self.assertEqual(result, []) def test_pg_connect_bits_works(self): meta = type('mock', (object, ), - {'scheme': 'postgres', 'username': '1', 'hostname': '2', 'port': 3}) + {'scheme': 'postgres', 'username': '1', 'hostname': '2', 'port': 3}) result = postdoc.pg_connect_bits(meta) self.assertEqual(result, ['-U', '1', '-h', '2', '-p', '3']) result = postdoc.connect_bits(meta) @@ -35,14 +31,14 @@ def test_pg_connect_bits_works(self): def test_mysql_connect_bits_trivial_case(self): meta = type('mock', (object, ), - {'username': '', 'password': '', 'hostname': '', 'port': ''}) + {'username': '', 'password': '', 'hostname': '', 'port': ''}) result = postdoc.mysql_connect_bits(meta) self.assertEqual(result, []) def test_mysql_connect_bits_works(self): meta = type('mock', (object, ), - {'scheme': 'mysql', 'username': 'u', 'password': 'p', - 'hostname': 'h', 'port': '3306'}) + {'scheme': 'mysql', 'username': 'u', 'password': 'p', + 'hostname': 'h', 'port': '3306'}) result = postdoc.mysql_connect_bits(meta) self.assertEqual(result, ['-u', 'u', '-pp', '-h', 'h', '-P', '3306']) result = postdoc.connect_bits(meta) @@ -50,7 +46,7 @@ def test_mysql_connect_bits_works(self): def test_connect_bits_supported_schemas(self): meta = type('mock', (object, ), - {'username': '', 'password': '', 'hostname': 'h', 'port': ''}) + {'username': '', 'password': '', 'hostname': 'h', 'port': ''}) # assert defaults to postgres self.assertTrue(postdoc.connect_bits(meta)) @@ -78,50 +74,50 @@ def test_get_uri(self): def test_get_command_assembles_bits_in_right_order(self): meta = type('mock', (object, ), - {'username': '', 'hostname': '', 'port': '', 'password': '', - 'path': '/database'}) + {'username': '', 'hostname': '', 'port': '', 'password': '', + 'path': '/database'}) with mock.patch('postdoc.pg_connect_bits') as mock_bits: mock_bits.return_value = ['lol'] self.assertEqual(postdoc.get_command('foo', meta), - ['foo', 'lol', 'database']) + ['foo', 'lol', 'database']) def test_get_command_ignores_password(self): meta = type('mock', (object, ), - {'username': '', 'hostname': '', 'port': '', 'password': 'oops', - 'path': '/database'}) + {'username': '', 'hostname': '', 'port': '', 'password': 'oops', + 'path': '/database'}) with mock.patch('postdoc.pg_connect_bits') as mock_bits: mock_bits.return_value = ['rofl'] self.assertEqual(postdoc.get_command('bar', meta), - ['bar', 'rofl', 'database']) + ['bar', 'rofl', 'database']) def test_get_commands_can_ignore_database_name(self): meta = type('mock', (object, ), - {'scheme': 'mysql', 'username': 'u', 'hostname': 'h', 'port': '', - 'password': 'oops', 'path': '/database'}) + {'scheme': 'mysql', 'username': 'u', 'hostname': 'h', 'port': '', + 'password': 'oops', 'path': '/database'}) result = postdoc.get_command('mysqladmin', meta) # assert database name is not an argument self.assertNotIn('database', result) # sanity check the connect args are still passed self.assertEqual(result, - ['mysqladmin', '-u', 'u', '-poops', '-h', 'h']) + ['mysqladmin', '-u', 'u', '-poops', '-h', 'h']) def test_get_command_special_syntax_for_pg_restore(self): meta = type('mock', (object, ), - {'username': '', 'hostname': '', 'port': '', 'password': 'oops', - 'path': '/database'}) + {'username': '', 'hostname': '', 'port': '', 'password': 'oops', + 'path': '/database'}) with mock.patch('postdoc.pg_connect_bits') as mock_bits: mock_bits.return_value = ['rofl'] self.assertEqual(postdoc.get_command('pg_restore', meta), - ['pg_restore', 'rofl', '--dbname', 'database']) + ['pg_restore', 'rofl', '--dbname', 'database']) def test_get_command_special_syntax_for_mysql(self): meta = type('mock', (object, ), - {'scheme': 'mysql', 'username': '', 'hostname': '', 'port': '', - 'password': 'oops', 'path': '/database'}) + {'scheme': 'mysql', 'username': '', 'hostname': '', 'port': '', + 'password': 'oops', 'path': '/database'}) with mock.patch('postdoc.connect_bits') as mock_bits: mock_bits.return_value = ['rofl'] self.assertEqual(postdoc.get_command('mysql', meta), - ['mysql', 'rofl', '--database', 'database']) + ['mysql', 'rofl', '--database', 'database']) def test_make_tokens_and_env_exits_with_bad_command(self): with self.assertRaises(SystemExit): @@ -149,7 +145,7 @@ def test_make_tokens_and_env_can_use_alternate_url(self): tokens, env = postdoc.make_tokens_and_env( ['argv1', 'FATTYBASE_URL', 'psql', 'extra_arg']) self.assertEqual(tokens, - ['psql', '-U', 'u', '-h', 'h', 'test', 'extra_arg']) + ['psql', '-U', 'u', '-h', 'h', 'test', 'extra_arg']) # INTEGRATION TESTING AROUND main() # @@ -218,7 +214,7 @@ def test_main_command_debug_can_be_quiet(self): def test_main_passes_password_in_env(self): my_password = 'hunter2' meta = type('mock', (object, ), - {'password': my_password}) + {'password': my_password}) mock_subprocess = mock.MagicMock() mock_get_command = mock.MagicMock(return_value=['get_command']) mock_get_uri = mock.MagicMock(return_value=meta)