Skip to content
This repository was archived by the owner on Oct 15, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion pgpasslib.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,37 @@

PATTERN = re.compile(r'^(.*):(.*):(.*):(.*):(.*)$', re.MULTILINE)

def getuser(host=DEFAULT_HOST, port=DEFAULT_PORT, dbname=DEFAULT_DBNAME):
"""Return the first matching user for the specified host, port, and dbname.
:py:const:`None` will be returned if a user can not be found for the
specified connection parameters.

If the password file can not be located, a :py:class:`FileNotFound`
exception will be raised.

If the password file is group or world readable, the file will not be read,
per the specification, and a :py:class:`InvalidPermissions` exception will
be raised.

If an entry in the password file is not parsable, a
:py:class:`InvalidPermissions` exception will be raised.

:param str host: PostgreSQL hostname
:param port: PostgreSQL port
:type port: int or str
:param str dbname: Database name
:rtype: str
:raises: FileNotFound
:raises: InvalidPermissions
:raises: InvalidEntry

"""
if not isinstance(port, int):
port = int(port)
for entry in _get_entries():
if entry.match(host, port, dbname, None):
return entry.user
return None

def getpass(host=DEFAULT_HOST, port=DEFAULT_PORT, dbname=DEFAULT_DBNAME,
user=DEFAULT_USER):
Expand Down Expand Up @@ -147,7 +178,7 @@ def match(self, host, port, dbname, user):
return all([any([self.host == '*', self.host == host]),
any([self.port == '*', self.port == port]),
any([self.dbname == '*', self.dbname == dbname]),
any([self.user == '*', self.user == user])])
any([user is None and self.user != '*', self.user == '*', self.user == user])])

@staticmethod
def _sanitize_port(value):
Expand Down
44 changes: 44 additions & 0 deletions tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,50 @@ def test_getpass_returns_expected_result(self):
read_file.return_value = MOCK_CONTENT
self.assertIsNone(pgpasslib.getpass('fail', '5432', 'foo', 'bar'))

class GetUserMatch1Test(unittest.TestCase):

def test_getuser_returns_expected_result(self):
with mock.patch('pgpasslib._read_file') as read_file:
read_file.return_value = MOCK_CONTENT
self.assertEqual(pgpasslib.getuser('localhost', 5432,
'foo'), 'kermit')


class GetUserMatch2Test(unittest.TestCase):

def test_getuser_returns_expected_result(self):
with mock.patch('pgpasslib._read_file') as read_file:
read_file.return_value = MOCK_CONTENT
self.assertEqual(pgpasslib.getuser('bouncer', 6000,
'bumpers'), 'rubber')


class GetUserMatch3Test(unittest.TestCase):

def test_getuser_returns_expected_result(self):
with mock.patch('pgpasslib._read_file') as read_file:
read_file.return_value = MOCK_CONTENT
self.assertEqual(pgpasslib.getuser('foo.abjdite.us-east-1.'
'redshift.amazonaws.com', 5439,
'redshift'), 'fonzy')


class GetUserMatch4Test(unittest.TestCase):

def test_getuser_returns_expected_result(self):
with mock.patch('pgpasslib._read_file') as read_file:
read_file.return_value = MOCK_CONTENT
self.assertEqual(pgpasslib.getuser('foo:bar', '6000',
'corgie'), 'baz')


class GetUserNoMatchTest(unittest.TestCase):

def test_getuser_returns_expected_result(self):
with mock.patch('pgpasslib._read_file') as read_file:
read_file.return_value = MOCK_CONTENT
self.assertIsNone(pgpasslib.getuser('fail', '5432', 'foo'))


class FileNotFoundStrFormatting(unittest.TestCase):

Expand Down