pglift-cli 3.1.0__tar.gz → 3.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/PKG-INFO +1 -1
  2. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/src/pglift_cli/main.py +42 -28
  3. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/src/pglift_cli/model.py +3 -10
  4. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/src/pglift_cli/pgconf.py +1 -1
  5. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/src/pglift_cli/util.py +2 -2
  6. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/tests/expect/test-help.t +7 -5
  7. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/tests/unit/test_model.py +31 -3
  8. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/.gitignore +0 -0
  9. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/README.md +0 -0
  10. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/hatch.toml +0 -0
  11. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/pyproject.toml +0 -0
  12. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/pytest.ini +0 -0
  13. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/src/pglift_cli/__init__.py +0 -0
  14. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/src/pglift_cli/__main__.py +0 -0
  15. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/src/pglift_cli/_settings.py +0 -0
  16. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/src/pglift_cli/_site.py +0 -0
  17. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/src/pglift_cli/base.py +0 -0
  18. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/src/pglift_cli/console.py +0 -0
  19. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/src/pglift_cli/database.py +0 -0
  20. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/src/pglift_cli/hookspecs.py +0 -0
  21. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/src/pglift_cli/instance.py +0 -0
  22. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/src/pglift_cli/patroni.py +0 -0
  23. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/src/pglift_cli/pgbackrest/__init__.py +0 -0
  24. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/src/pglift_cli/pgbackrest/repo_path.py +0 -0
  25. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/src/pglift_cli/pghba.py +0 -0
  26. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/src/pglift_cli/pm.py +0 -0
  27. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/src/pglift_cli/postgres.py +0 -0
  28. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/src/pglift_cli/prometheus.py +0 -0
  29. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/src/pglift_cli/py.typed +0 -0
  30. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/src/pglift_cli/role.py +0 -0
  31. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/src/pglift_cli/wal.py +0 -0
  32. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/tests/expect/.gitignore +0 -0
  33. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/tests/expect/test-base.t +0 -0
  34. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/tests/expect/test-cli-walkthrough.t +0 -0
  35. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/tests/expect/test-demote.t +0 -0
  36. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/tests/expect/test-instance-name.t +0 -0
  37. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/tests/expect/test-port-validation.t +0 -0
  38. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/tests/expect/test-prometheus.t +0 -0
  39. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/tests/expect/test-standby-pgbackrest.t +0 -0
  40. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/tests/expect/test-standby.t +0 -0
  41. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/tests/expect/test-transactions.t +0 -0
  42. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/tests/expect/test-upgrade.t +0 -0
  43. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/tests/unit/__init__.py +0 -0
  44. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/tests/unit/conftest.py +0 -0
  45. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/tests/unit/test__site.py +0 -0
  46. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/tests/unit/test_audit.py +0 -0
  47. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/tests/unit/test_cli.py +0 -0
  48. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/tests/unit/test_main.py +0 -0
  49. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/tests/unit/test_pm.py +0 -0
  50. {pglift_cli-3.1.0 → pglift_cli-3.2.0}/tests/unit/test_util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pglift_cli
3
- Version: 3.1.0
3
+ Version: 3.2.0
4
4
  Summary: Command-line interface for pglift
5
5
  Project-URL: Documentation, https://pglift.readthedocs.io/
6
6
  Project-URL: Source, https://gitlab.com/dalibo/pglift/
@@ -11,7 +11,7 @@ import warnings
11
11
  from functools import partial
12
12
  from importlib.metadata import version
13
13
  from pathlib import Path
14
- from typing import Literal
14
+ from typing import Any, Literal
15
15
 
16
16
  import click
17
17
  import click.exceptions
@@ -24,7 +24,6 @@ from rich.highlighter import NullHighlighter
24
24
  from rich.syntax import Syntax
25
25
 
26
26
  from pglift import ui
27
- from pglift._compat import assert_never
28
27
  from pglift.system import install
29
28
  from pglift.types import LogLevel
30
29
 
@@ -234,35 +233,50 @@ def site_settings(
234
233
  console.print(syntax)
235
234
 
236
235
 
237
- @cli.command(
238
- "site-configure",
239
- hidden=True,
240
- )
241
- @click.argument(
242
- "action",
243
- type=click.Choice(["install", "uninstall", "check", "list"]),
244
- default="install",
236
+ @cli.group(hidden=True)
237
+ def site_configure(**kwargs: Any) -> None:
238
+ """Manage installation of extra data files for pglift.
239
+
240
+ This is an INTERNAL command.
241
+ """
242
+
243
+
244
+ @site_configure.command("install")
245
+ @click.option(
246
+ "--force",
247
+ is_flag=True,
248
+ default=False,
249
+ help="Force the overwrite of installed files",
245
250
  )
246
251
  @click.pass_obj
252
+ @async_command
253
+ async def site_configure_install(obj: Obj, force: bool) -> None:
254
+ with obj.lock, audit():
255
+ await install.do(_site.SETTINGS, force=force)
256
+
257
+
258
+ @site_configure.command("uninstall")
259
+ @click.pass_obj
260
+ @async_command
261
+ async def site_configure_uninstall(obj: Obj) -> None:
262
+ with obj.lock, audit():
263
+ await install.undo(_site.SETTINGS)
264
+
265
+
266
+ @site_configure.command("check")
267
+ @click.pass_obj
247
268
  @click.pass_context
248
269
  @async_command
249
- async def site_configure(
250
- context: click.Context, obj: Obj, action: Literal["install", "uninstall", "check"]
251
- ) -> None:
252
- """Manage installation of extra data files for pglift.
270
+ async def site_configure_check(context: click.Context, obj: Obj) -> None:
271
+ with obj.lock, audit():
272
+ if not install.check(_site.SETTINGS):
273
+ context.exit(1)
253
274
 
254
- This is an INTERNAL command.
255
- """
275
+
276
+ @site_configure.command("list")
277
+ @click.pass_obj
278
+ @async_command
279
+ async def site_configure_list(obj: Obj) -> None:
256
280
  with obj.lock, audit():
257
- if action == "install":
258
- await install.do(_site.SETTINGS)
259
- elif action == "uninstall":
260
- await install.undo(_site.SETTINGS)
261
- elif action == "check":
262
- if not install.check(_site.SETTINGS):
263
- context.exit(1)
264
- elif action == "list":
265
- for p in install.ls(_site.SETTINGS):
266
- click.echo(p)
267
- else:
268
- assert_never(action)
281
+ for p in install.ls(_site.SETTINGS):
282
+ click.echo(p)
@@ -18,7 +18,7 @@ import pydantic
18
18
  from pydantic.fields import FieldInfo
19
19
  from pydantic_core import ErrorDetails
20
20
 
21
- from pglift.annotations import cli
21
+ from pglift.annotations import CreateOnly, cli
22
22
  from pglift.exceptions import MutuallyExclusiveError
23
23
  from pglift.models.helpers import is_optional, optional_type
24
24
  from pglift.models.interface import PresenceState
@@ -169,7 +169,7 @@ class ParamSpec(ABC):
169
169
  loc: tuple[str, ...]
170
170
  description: str | None = None
171
171
 
172
- objtype: ClassVar[type[click.Parameter]] = click.Parameter
172
+ objtype: ClassVar[type[click.Parameter]]
173
173
 
174
174
  @property
175
175
  def param(self) -> click.Parameter:
@@ -340,11 +340,7 @@ def _paramspecs_from_model(
340
340
  for fname, field in model_type.model_fields.items():
341
341
  if field_annotation(field, cli.Hidden):
342
342
  continue
343
- if (
344
- operation == "update"
345
- and isinstance(field.json_schema_extra, dict)
346
- and field.json_schema_extra.get("readOnly")
347
- ):
343
+ if field_annotation(field, CreateOnly) and operation == "update":
348
344
  continue
349
345
 
350
346
  modelname = argname = field.alias or fname
@@ -372,9 +368,6 @@ def _paramspecs_from_model(
372
368
  if not _parents and required:
373
369
  if origin_type is typing.Literal:
374
370
  choices = list(typing.get_args(ftype))
375
- if config is not None:
376
- assert isinstance(config, cli.Choices)
377
- choices = config.choices
378
371
  attrs["type"] = click.Choice(choices)
379
372
  if config is not None and isinstance(config, cli.Option):
380
373
  attrs["required"] = True
@@ -58,7 +58,7 @@ def show_configuration_changes(
58
58
  @cli.command("show")
59
59
  @click.argument("parameter", nargs=-1)
60
60
  @pass_postgresql_instance
61
- def show(instance: PostgreSQLInstance, parameter: tuple[str]) -> None:
61
+ def show(instance: PostgreSQLInstance, parameter: tuple[str, ...]) -> None:
62
62
  """Show configuration (all parameters or specified ones).
63
63
 
64
64
  Only uncommented parameters are shown when no PARAMETER is specified. When
@@ -273,7 +273,7 @@ def nameversion_from_id(instance_id: str) -> tuple[str, PostgreSQLVersion | None
273
273
 
274
274
 
275
275
  def postgresql_instance_lookup(
276
- context: click.Context, param: click.Parameter, value: None | str | tuple[str]
276
+ context: click.Context, param: click.Parameter, value: None | str | tuple[str, ...]
277
277
  ) -> PostgreSQLInstance | tuple[PostgreSQLInstance, ...]:
278
278
  """Return one or more PostgreSQLInstance, possibly guessed if there
279
279
  is only one on system, depending on 'param' variadic flag (nargs).
@@ -764,7 +764,7 @@ class PluggableCommandGroup(abc.ABC, Group):
764
764
  if obj is None:
765
765
  obj = context.ensure_object(Obj)
766
766
  if obj is None:
767
- return
767
+ return # type: ignore[unreachable]
768
768
  self.register_plugin_commands(obj)
769
769
  self._plugin_commands_loaded = True
770
770
 
@@ -249,13 +249,13 @@ Instance commands
249
249
  --locale LOCALE Default locale.
250
250
  --encoding ENCODING Character encoding of the PostgreSQL
251
251
  instance.
252
- --auth-local [trust|reject|md5|password|scram-sha-256|sspi|ident|peer|pam|ldap|radius]
252
+ --auth-local [trust|reject|md5|password|scram-sha-256|sspi|ident|pam|ldap|radius|peer]
253
253
  Authentication method for local-socket
254
254
  connections.
255
- --auth-host [trust|reject|md5|password|scram-sha-256|gss|sspi|ident|pam|ldap|radius]
255
+ --auth-host [trust|reject|md5|password|scram-sha-256|sspi|ident|pam|ldap|radius|gss]
256
256
  Authentication method for local TCP/IP
257
257
  connections.
258
- --auth-hostssl [trust|reject|md5|password|scram-sha-256|gss|sspi|ident|pam|ldap|radius|cert]
258
+ --auth-hostssl [trust|reject|md5|password|scram-sha-256|sspi|ident|pam|ldap|radius|gss|cert]
259
259
  Authentication method for SSL-encrypted
260
260
  TCP/IP connections.
261
261
  --surole-password PASSWORD Super-user role password.
@@ -947,7 +947,8 @@ HBA configuration management commands
947
947
  --database DATABASE Database name(s). Multiple database names
948
948
  can be supplied by separating them with
949
949
  commas.
950
- --method TEXT Authentication method. [required]
950
+ --method [trust|reject|md5|password|scram-sha-256|sspi|ident|pam|ldap|radius|peer|gss|cert]
951
+ Authentication method. [required]
951
952
  --user USER User name(s). Multiple user names can be
952
953
  supplied by separating them with commas.
953
954
  --dry-run Simulate change operations.
@@ -970,7 +971,8 @@ HBA configuration management commands
970
971
  --database DATABASE Database name(s). Multiple database names
971
972
  can be supplied by separating them with
972
973
  commas.
973
- --method TEXT Authentication method. [required]
974
+ --method [trust|reject|md5|password|scram-sha-256|sspi|ident|pam|ldap|radius|peer|gss|cert]
975
+ Authentication method. [required]
974
976
  --user USER User name(s). Multiple user names can be
975
977
  supplied by separating them with commas.
976
978
  --dry-run Simulate change operations.
@@ -76,6 +76,8 @@ def test_as_parameters(runner: CliRunner) -> None:
76
76
  "Options:\n"
77
77
  " --exclude-none\n"
78
78
  " --nickname TEXT Your secret nickname. [required]\n"
79
+ " --gender [female|male|nonbinary|prefer not to say]\n"
80
+ " Gender. [required]\n"
79
81
  " --age AGE Age.\n"
80
82
  " --address-street STREET Street lines. (Can be used multiple times.)\n"
81
83
  " --address-zip-code ZIP_CODE ZIP code.\n"
@@ -102,6 +104,7 @@ def test_as_parameters(runner: CliRunner) -> None:
102
104
  "alice",
103
105
  "friend",
104
106
  "--exclude-none",
107
+ "--gender=female",
105
108
  "--age=42",
106
109
  "--address-street=bd montparnasse",
107
110
  "--address-street=far far away",
@@ -126,6 +129,7 @@ def test_as_parameters(runner: CliRunner) -> None:
126
129
  "zip_code": 0,
127
130
  "primary": True,
128
131
  },
132
+ "gender": "female",
129
133
  "age": 42,
130
134
  "birth": {"date": "1981-02-18"},
131
135
  "is_dead": False,
@@ -157,6 +161,7 @@ def test_as_parameters(runner: CliRunner) -> None:
157
161
  [
158
162
  "foo",
159
163
  "friend",
164
+ "--gender=female",
160
165
  "--age=17",
161
166
  "--birth-date=1987-06-05",
162
167
  "--nickname=aaa",
@@ -186,6 +191,8 @@ def test_as_parameters_update() -> None:
186
191
  "\n"
187
192
  "Options:\n"
188
193
  " --nickname TEXT Your secret nickname. [required]\n"
194
+ " --gender [female|male|nonbinary|prefer not to say]\n"
195
+ " Gender. [required]\n"
189
196
  " --age AGE Age.\n"
190
197
  " --address-zip-code ZIP_CODE ZIP code.\n"
191
198
  " --address-town CITY City.\n"
@@ -209,16 +216,24 @@ def test_as_parameters_update() -> None:
209
216
  ["alice", "--age=5", "--birthdate=2042-02-31"],
210
217
  )
211
218
  assert result.exit_code == 2, result.output
212
- assert "Error: No such option: --birthdate" in result.output
219
+ assert "Error: No such option '--birthdate'" in result.output
213
220
 
214
221
  result = runner.invoke(
215
222
  update_person,
216
- ["alice", "other", "--nickname=a", "--age=5", "--birth-date=1987-06-05"],
223
+ [
224
+ "alice",
225
+ "other",
226
+ "--nickname=a",
227
+ "--gender=female",
228
+ "--age=5",
229
+ "--birth-date=1987-06-05",
230
+ ],
217
231
  )
218
232
  assert result.exit_code == 0, result.output
219
233
  assert json.loads(result.output) == {
220
234
  "name": "alice",
221
235
  "nickname": "**********",
236
+ "gender": "female",
222
237
  "relation": "other",
223
238
  "age": 5,
224
239
  "birth": {"date": "1987-06-05"},
@@ -228,7 +243,14 @@ def test_as_parameters_update() -> None:
228
243
 
229
244
  result = runner.invoke(
230
245
  update_person,
231
- ["alice", "friend", "--nickname=a", "--age=abc", "--birth-date=2010-02-03"],
246
+ [
247
+ "alice",
248
+ "friend",
249
+ "--nickname=a",
250
+ "--gender=female",
251
+ "--age=abc",
252
+ "--birth-date=2010-02-03",
253
+ ],
232
254
  )
233
255
  assert result.exit_code == 2
234
256
  assert (
@@ -242,6 +264,7 @@ def test_as_parameters_update() -> None:
242
264
  "bob",
243
265
  "family",
244
266
  "--nickname=b",
267
+ "--gender=male",
245
268
  "--birth-date=1987-06-05",
246
269
  "--address-town=laville",
247
270
  "--address-country=be",
@@ -262,6 +285,7 @@ def test_as_parameters_update() -> None:
262
285
  "marcel",
263
286
  "other",
264
287
  "--nickname=a",
288
+ "--gender=male",
265
289
  "--age=46",
266
290
  "--birth-date=1978-03-09",
267
291
  "--add-pet=snoopy",
@@ -275,6 +299,7 @@ def test_as_parameters_update() -> None:
275
299
  "name": "marcel",
276
300
  "nickname": "**********",
277
301
  "relation": "other",
302
+ "gender": "male",
278
303
  "age": 46,
279
304
  "birth": {"date": "1978-03-09"},
280
305
  "pets": [
@@ -339,6 +364,7 @@ def test_parse_params_as() -> None:
339
364
  "name": "alice",
340
365
  "relation": "other",
341
366
  "nickname": "la malice",
367
+ "gender": "female",
342
368
  "age": 42,
343
369
  "address": address_params,
344
370
  "birth": {"date": "1976-05-04"},
@@ -347,6 +373,7 @@ def test_parse_params_as() -> None:
347
373
  name="alice",
348
374
  nickname="la malice",
349
375
  relation="other",
376
+ gender="female",
350
377
  age=42,
351
378
  address=address,
352
379
  birth=models.BirthInformation(date=date(1976, 5, 4)), # type: ignore[call-arg]
@@ -357,6 +384,7 @@ def test_parse_params_as() -> None:
357
384
  "name": "alice",
358
385
  "relation": "other",
359
386
  "nickname": "la malice",
387
+ "gender": "female",
360
388
  "age": 42,
361
389
  "birth_date": "1976-05-04",
362
390
  }
File without changes
File without changes
File without changes
File without changes
File without changes