Skip to content
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
17 changes: 0 additions & 17 deletions .flake8

This file was deleted.

11 changes: 8 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
repos:
- repo: local
hooks:
- id: pyupgrade
name: pyupgrade
entry: pyupgrade --exit-zero-even-if-changed
- id: ruff
name: ruff
entry: ruff check
language: system
types: [python]
- id: ruff-format
name: ruff-format
entry: ruff format
language: system
types: [python]
25 changes: 25 additions & 0 deletions .ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
target-version = "py39"
exclude = [
".eggs",
".tox",
".venv",
".cache",
]

[lint]
extend-select = [
"E", # pycodestyle errors
"F", # pyflakes
"I", # isort
"UP", # pyupgrade
"W", # pycodestyle warnings
]
ignore = [
"E501", # line too long
]

[lint.isort]
known-first-party = ["pgtoolkit"]

[format]
docstring-code-format = true
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
include .coveragerc
include .flake8
include .pre-commit-config.yaml
include .ruff.toml
include pyproject.toml
include *.md
include *.txt
Expand Down
43 changes: 23 additions & 20 deletions pgtoolkit/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ def serialize_value(value: Value) -> str:
# done everywhere in the string or nowhere.
if "''" not in value and r"\'" not in value:
value = value.replace("'", "''")
value = "'%s'" % value
value = f"'{value}'"
elif isinstance(value, timedelta):
seconds = value.days * _day + value.seconds
if value.microseconds:
Expand Down Expand Up @@ -340,7 +340,7 @@ def serialize(self) -> str:
return serialize_value(self.value)

def __str__(self) -> str:
line = "%(name)s = %(value)s" % dict(name=self.name, value=self.serialize())
line = "{name} = {value}".format(**dict(name=self.name, value=self.serialize()))
if self.comment:
line += " # " + self.comment
if self.commented:
Expand All @@ -351,33 +351,34 @@ def __str__(self) -> str:
class EntriesProxy(dict[str, Entry]):
"""Proxy object used during Configuration edition.

>>> p = EntriesProxy(port=Entry('port', '5432'),
... shared_buffers=Entry('shared_buffers', '1GB'))
>>> p = EntriesProxy(
... port=Entry("port", "5432"), shared_buffers=Entry("shared_buffers", "1GB")
... )

Existing entries can be edited:

>>> p['port'].value = '5433'
>>> p["port"].value = "5433"

New entries can be added as:

>>> p.add('listen_addresses', '*', commented=True, comment='IP address')
>>> p.add("listen_addresses", "*", commented=True, comment="IP address")
>>> p # doctest: +NORMALIZE_WHITESPACE
{'port': Entry(name='port', _value=5433, commented=False, comment=None),
'shared_buffers': Entry(name='shared_buffers', _value='1GB', commented=False, comment=None),
'listen_addresses': Entry(name='listen_addresses', _value='*', commented=True, comment='IP address')}
>>> del p['shared_buffers']
>>> del p["shared_buffers"]
>>> p # doctest: +NORMALIZE_WHITESPACE
{'port': Entry(name='port', _value=5433, commented=False, comment=None),
'listen_addresses': Entry(name='listen_addresses', _value='*', commented=True, comment='IP address')}

Adding an existing entry fails:
>>> p.add('port', 5433)
>>> p.add("port", 5433)
Traceback (most recent call last):
...
ValueError: 'port' key already present

So does adding a value to the underlying dict:
>>> p['bonjour_name'] = 'pgserver'
>>> p["bonjour_name"] = "pgserver"
Traceback (most recent call last):
...
TypeError: cannot set a key
Expand Down Expand Up @@ -407,16 +408,16 @@ class Configuration:

You can access parameter using attribute or dictionary syntax.

>>> conf = parse(['port=5432\n', 'pg_stat_statement.min_duration = 3s\n'])
>>> conf = parse(["port=5432\n", "pg_stat_statement.min_duration = 3s\n"])
>>> conf.port
5432
>>> conf.port = 5433
>>> conf.port
5433
>>> conf['port'] = 5434
>>> conf["port"] = 5434
>>> conf.port
5434
>>> conf['pg_stat_statement.min_duration'].total_seconds()
>>> conf["pg_stat_statement.min_duration"].total_seconds()
3.0
>>> conf.get("ssl")
>>> conf.get("ssl", False)
Expand Down Expand Up @@ -496,7 +497,7 @@ def parse(self, fo: Iterable[str]) -> Iterator[tuple[pathlib.Path, IncludeType]]
else:
m = self._parameter_re.match(line)
if not m:
raise ValueError("Bad line: %r." % raw_line)
raise ValueError(f"Bad line: {raw_line!r}.")
kwargs = m.groupdict()
name = kwargs.pop("name")
value = parse_value(kwargs.pop("value"))
Expand Down Expand Up @@ -621,12 +622,14 @@ def edit(self) -> Iterator[EntriesProxy]:
>>> import sys

>>> cfg = Configuration()
>>> includes = cfg.parse([
... "#listen_addresses = 'localhost' # what IP address(es) to listen on;\n",
... " # comma-separated list of addresses;\n",
... "port = 5432 # (change requires restart)\n",
... "max_connections = 100 # (change requires restart)\n",
... ])
>>> includes = cfg.parse(
... [
... "#listen_addresses = 'localhost' # what IP address(es) to listen on;\n",
... " # comma-separated list of addresses;\n",
... "port = 5432 # (change requires restart)\n",
... "max_connections = 100 # (change requires restart)\n",
... ]
... )
>>> list(includes)
[]
>>> cfg.save(sys.stdout)
Expand All @@ -638,7 +641,7 @@ def edit(self) -> Iterator[EntriesProxy]:
>>> with cfg.edit() as entries:
... entries["port"].value = 2345
... entries["port"].comment = None
... entries["listen_addresses"].value = '*'
... entries["listen_addresses"].value = "*"
... del entries["max_connections"]
... entries.add(
... "unix_socket_directories",
Expand Down
8 changes: 4 additions & 4 deletions pgtoolkit/ctl.py
Original file line number Diff line number Diff line change
Expand Up @@ -518,13 +518,13 @@ def parse_control_data(lines: Sequence[str]) -> dict[str, str]:
def num_version(text_version: str) -> int:
"""Return PostgreSQL numeric version as defined by LibPQ PQserverVersion

>>> num_version('pg_ctl (PostgreSQL) 9.6.3')
>>> num_version("pg_ctl (PostgreSQL) 9.6.3")
90603
>>> num_version('pg_ctl (PostgreSQL) 9.2.0')
>>> num_version("pg_ctl (PostgreSQL) 9.2.0")
90200
>>> num_version('pg_ctl (PostgreSQL) 11.10')
>>> num_version("pg_ctl (PostgreSQL) 11.10")
110010
>>> num_version('pg_ctl (PostgreSQL) 11.1')
>>> num_version("pg_ctl (PostgreSQL) 11.1")
110001
>>> num_version("pg_ctl (PostgreSQL) 14devel")
140000
Expand Down
12 changes: 2 additions & 10 deletions pgtoolkit/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,7 @@ def __init__(self, lineno: int, line: str, message: str) -> None:
self.line = line

def __repr__(self) -> str:
return "<%s at line %d: %.32s>" % (
self.__class__.__name__,
self.lineno,
self.args[0],
)
return f"<{self.__class__.__name__} at line {self.lineno}: {self.args[0]:.32}>"

def __str__(self) -> str:
return "Bad line #{} '{:.32}': {}".format(
self.lineno,
self.line.strip(),
self.args[0],
)
return f"Bad line #{self.lineno} '{self.line.strip():.32}': {self.args[0]}"
10 changes: 5 additions & 5 deletions pgtoolkit/hba.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ def parse(cls, line: str) -> HBARecord:
comment = " ".join(comments[1:])

if values[0] not in cls.CONNECTION_TYPES:
raise ValueError("Unknown connection type '%s'" % values[0])
raise ValueError(f"Unknown connection type '{values[0]}'")
if "local" != values[0]:
record_fields.append("address")
common_values = [v for v in values if "=" not in v]
Expand Down Expand Up @@ -220,14 +220,14 @@ def __str__(self) -> str:
continue

if width:
fmt += "%%(%s)-%ds " % (field, width - 1)
fmt += f"%%({field})-%ds " % (width - 1)
else:
fmt += f"%({field})s "
# Serialize database and user list using property.
values = dict(self.__dict__, databases=self.database, users=self.user)
line = fmt.rstrip() % values

auth_options = ['%s="%s"' % i for i in self.auth_options]
auth_options = ['{}="{}"'.format(*i) for i in self.auth_options]
if auth_options:
line += " " + " ".join(auth_options)

Expand Down Expand Up @@ -290,7 +290,7 @@ def matches(self, **attrs: str) -> bool:
# Provided attributes should be comparable to HBARecord attributes
for k in attrs.keys():
if k not in self.COMMON_FIELDS + ["database", "user"]:
raise AttributeError("%s is not a valid attribute" % k)
raise AttributeError(f"{k} is not a valid attribute")

for k, v in attrs.items():
if getattr(self, k, None) != v:
Expand Down Expand Up @@ -326,7 +326,7 @@ def __init__(self, entries: Iterable[HBAComment | HBARecord] | None = None) -> N
:param entries: A list of HBAComment or HBARecord. Optional.
"""
if entries and not isinstance(entries, list):
raise ValueError("%s should be a list" % entries)
raise ValueError(f"{entries} should be a list")
self.lines = list(entries) if entries is not None else []
self.path = None

Expand Down
4 changes: 2 additions & 2 deletions pgtoolkit/log/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,11 @@ def parse_isodatetime(raw: str) -> datetime:
int(raw[20:23]) if raw[19] == "." else 0,
)
except ValueError:
raise ValueError("%s is not a known date" % raw)
raise ValueError(f"{raw} is not a known date")

if raw[-3:] != "UTC":
# We need tzdata for that.
raise ValueError("%s not in UTC." % raw)
raise ValueError(f"{raw} not in UTC.")

return datetime(*infos)

Expand Down
12 changes: 3 additions & 9 deletions pgtoolkit/pgpass.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,13 +244,7 @@ def __lt__(self, other: PassComment | PassEntry) -> bool:
return NotImplemented

def __repr__(self) -> str:
return "<{} {}@{}:{}/{}>".format(
self.__class__.__name__,
self.username,
self.hostname,
self.port,
self.database,
)
return f"<{self.__class__.__name__} {self.username}@{self.hostname}:{self.port}/{self.database}>"

def __str__(self) -> str:
return ":".join(
Expand Down Expand Up @@ -284,7 +278,7 @@ def matches(self, **attrs: int | str) -> bool:
expected_attributes = self.__dict__.keys()
for k in attrs.keys():
if k not in expected_attributes:
raise AttributeError("%s is not a valid attribute" % k)
raise AttributeError(f"{k} is not a valid attribute")

for k, v in attrs.items():
if getattr(self, k) != v:
Expand Down Expand Up @@ -328,7 +322,7 @@ def __init__(
:param entries: A list of PassEntry or PassComment. Optional.
"""
if entries and not isinstance(entries, list):
raise ValueError("%s should be a list" % entries)
raise ValueError(f"{entries} should be a list")
self.lines = entries or []
self.path = path

Expand Down
8 changes: 4 additions & 4 deletions pgtoolkit/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,14 @@ class Service(dict[str, Parameter]):
Each parameters can be accessed either as a dictionary entry or as an
attributes.

>>> myservice = Service('myservice', {'dbname': 'mydb'}, host='myhost')
>>> myservice = Service("myservice", {"dbname": "mydb"}, host="myhost")
>>> myservice.name
'myservice'
>>> myservice.dbname
'mydb'
>>> myservice['dbname']
>>> myservice["dbname"]
'mydb'
>>> myservice.user = 'myuser'
>>> myservice.user = "myuser"
>>> list(sorted(myservice.items()))
[('dbname', 'mydb'), ('host', 'myhost'), ('user', 'myuser')]

Expand Down Expand Up @@ -179,7 +179,7 @@ def __init__(self) -> None:
)

def __repr__(self) -> str:
return "<%s>" % (self.__class__.__name__)
return f"<{self.__class__.__name__}>"

def __getitem__(self, key: str) -> Service:
parameters = {
Expand Down
9 changes: 1 addition & 8 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,8 @@ dev = [
"pgtoolkit[lint,typing,test,doc]",
]
lint = [
"black",
"ruff",
"check-manifest",
"flake8",
"isort",
"pyupgrade",
]
typing = [
"mypy",
Expand All @@ -57,10 +54,6 @@ doc = [
Repository = "https://github.com/dalibo/pgtoolkit"
Documentation = "https://pgtoolkit.readthedocs.io/"

[tool.isort]
profile = "black"
multi_line_output = 3

[tool.setuptools.packages.find]
where = ["."]

Expand Down
3 changes: 1 addition & 2 deletions tests/test_conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ def test_parse_value():
assert "user=foo password=secret'" == parse_value("'user=foo password=secret'''")
assert (
# this one does not work in parse_dsn()
"user=foo password='secret"
== parse_value("'user=foo password=''secret'")
"user=foo password='secret" == parse_value("'user=foo password=''secret'")
)
assert "%m [%p] %q%u@%d " == parse_value(r"'%m [%p] %q%u@%d '")
assert "124.7MB" == parse_value("124.7MB")
Expand Down
4 changes: 1 addition & 3 deletions tests/test_hba.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,7 @@ def test_parse_local_line():
with pytest.raises(AttributeError):
record.address

wanted = (
"local all all trust" # noqa
)
wanted = "local all all trust" # noqa
assert wanted == str(record)


Expand Down
Loading