pgtoolkit.pgpass

This module provides support for .pgpass file format. Here are some highlights :

  • Supports : and \ escape.

  • Sorts entry by precision (even if commented).

  • Preserves comments order when sorting.

See The Password File section in PostgreSQL documentation.

pgtoolkit.pgpass.parse(file: Path | str | IO[str]) PassFile[source]

Parses a .pgpass file.

Parameters:

file – Either a line iterator such as a file-like object or a file path to open and parse.

Return type:

PassFile

pgtoolkit.pgpass.edit(fpath: Path | str) Iterator[PassFile][source]

Context manager to edit a .pgpass file.

If the file does not exists, it is created with 600 permissions. Upon exit of the context manager, the file is saved, if no error occurred.

class pgtoolkit.pgpass.PassEntry(hostname: str, port: int | str, database: str, username: str, password: str)[source]

Holds a .pgpass entry.

classmethod parse(line: str) PassEntry[source]

Parse a single line.

Parameters:

line – string containing a serialized .pgpass entry.

Returns:

PassEntry object holding entry data.

Raises:

ValueError – on invalid line.

matches(**attrs: int | str) bool[source]

Tells if the current entry is matching provided attributes.

Parameters:

attrs – keyword/values pairs correspond to one or more PassEntry attributes (ie. hostname, port, etc…)

hostname

Server hostname, the first field.

port

Server port, the second field.

database

Database, the third field.

username

Username, the fourth field.

password

Password, the fifth field.

PassEntry object is sortable. A PassEntry object is lower than another if it is more specific. The more an entry has wildcard, the less it is specific.

class pgtoolkit.pgpass.PassComment[source]

A .pgpass comment, including spaces and #.

It’s a child of str.

>>> comm = PassComment("# my comment")
>>> comm.comment
'my comment'
matches(**attrs: int | str) bool[source]

In case of a commented entry, tells if it is matching provided attributes. Returns False otherwise.

Parameters:

attrs – keyword/values pairs correspond to one or more PassEntry attributes (ie. hostname, port, etc…)

comment

The actual message of the comment. Surrounding whitespaces stripped.

class pgtoolkit.pgpass.PassFile(entries: list[PassComment | PassEntry] | None = None, *, path: str | None = None)[source]

Holds .pgpass file entries and comments.

parse(fo: Iterable[str]) None[source]

Parse lines

Parameters:

fo – A line iterator such as a file-like object.

Raises ParseError if a bad line is found.

__iter__() Iterator[PassEntry][source]

Iterate entries

Yield PassEntry instance from parsed file, ignoring comments.

sort() None[source]

Sort entries preserving comments.

libpq use the first entry from .pgpass matching connexion informations. Thus, less specific entries should be last in the file. This is the purpose of sort() method.

About comments. Comments are supposed to bear with the entrie below. Thus comments block are sorted according to the first entry below.

Commented entries are sorted like entries, not like comment.

save(fo: IO[str] | None = None) None[source]

Save entries and comment in a file.

Parameters:

fo – a file-like object. Is not required if path is set.

remove(filter: Callable[[PassComment | PassEntry | str], bool] | None = None, **attrs: int | str) None[source]

Remove entries matching the provided attributes.

One can for example remove all entries for which port is 5433.

Note: commented entries matching will also be removed.

Parameters:
  • filter – a function to be used as filter. It is passed the line to test against. If it returns True, the line is removed. It is kept otherwise.

  • attrs – keyword/values pairs correspond to one or more PassEntry attributes (ie. hostname, port, etc…)

Usage examples:

pgpass.remove(port=5432)
pgpass.remove(filter=lambda r: r.port != 5432)
lines

List of either PassEntry or PassFile. You can add lines by appending PassEntry or PassFile instances to this list.

path

Path to a file. Is automatically set when calling parse() with a path to a file. save() will write to this file if set.

Editing a .pgpass file

with open('.pgpass') as fo:
    pgpass = parse(fo)
pgpass.lines.append(PassEntry(username='toto', password='confidentiel'))
pgpass.sort()
with open('.pgpass', 'w') as fo:
    pgpass.save(fo)

Shorter version using the file directly in parse:

pgpass = parse('.pgpass')
pgpass.lines.append(PassEntry(username='toto', password='confidentiel'))
pgpass.sort()
pgpass.save()

Alternatively, this can be done with the edit context manager:

with edit('.pgpass') as pgpass:
    pgpass.lines.append((PassEntry(username='toto', password='confidentiel'))
    passfile.sort()

Using as a script

You can call pgtoolkit.pgpass module as a CLI script. It accepts a file path as first argument, read it, validate it, sort it and output it in stdout.

$ python -m pgtoolkit.pgpass ~/.pgpass
more:5432:precise:entry:0revea\\ed
#disabled:5432:*:entry:0secret

# Multiline
# comment.
other:5432:*:username:0unveiled
*:*:*:postgres:c0nfident\:el