pyinfra 3.0b1__py2.py3-none-any.whl → 3.0b2__py2.py3-none-any.whl

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 (104) hide show
  1. pyinfra/api/arguments.py +9 -3
  2. pyinfra/api/arguments_typed.py +8 -5
  3. pyinfra/api/command.py +5 -3
  4. pyinfra/api/config.py +115 -13
  5. pyinfra/api/connectors.py +5 -2
  6. pyinfra/api/facts.py +33 -32
  7. pyinfra/api/host.py +5 -5
  8. pyinfra/api/inventory.py +4 -0
  9. pyinfra/api/operation.py +22 -14
  10. pyinfra/api/util.py +24 -16
  11. pyinfra/connectors/base.py +3 -6
  12. pyinfra/connectors/docker.py +2 -9
  13. pyinfra/connectors/local.py +2 -2
  14. pyinfra/connectors/ssh.py +2 -2
  15. pyinfra/connectors/util.py +6 -7
  16. pyinfra/connectors/vagrant.py +5 -5
  17. pyinfra/context.py +1 -0
  18. pyinfra/facts/apk.py +2 -0
  19. pyinfra/facts/apt.py +2 -0
  20. pyinfra/facts/brew.py +2 -0
  21. pyinfra/facts/bsdinit.py +2 -0
  22. pyinfra/facts/cargo.py +2 -0
  23. pyinfra/facts/choco.py +2 -0
  24. pyinfra/facts/deb.py +7 -2
  25. pyinfra/facts/dnf.py +2 -0
  26. pyinfra/facts/docker.py +2 -0
  27. pyinfra/facts/files.py +2 -0
  28. pyinfra/facts/gem.py +2 -0
  29. pyinfra/facts/gpg.py +2 -0
  30. pyinfra/facts/hardware.py +30 -22
  31. pyinfra/facts/launchd.py +2 -0
  32. pyinfra/facts/lxd.py +2 -0
  33. pyinfra/facts/mysql.py +12 -6
  34. pyinfra/facts/npm.py +1 -0
  35. pyinfra/facts/openrc.py +2 -0
  36. pyinfra/facts/pacman.py +6 -2
  37. pyinfra/facts/pip.py +2 -0
  38. pyinfra/facts/pkg.py +2 -0
  39. pyinfra/facts/pkgin.py +2 -0
  40. pyinfra/facts/postgres.py +6 -6
  41. pyinfra/facts/postgresql.py +2 -0
  42. pyinfra/facts/rpm.py +12 -9
  43. pyinfra/facts/server.py +10 -13
  44. pyinfra/facts/snap.py +2 -0
  45. pyinfra/facts/systemd.py +2 -0
  46. pyinfra/facts/upstart.py +2 -0
  47. pyinfra/facts/util/packaging.py +3 -2
  48. pyinfra/facts/vzctl.py +2 -0
  49. pyinfra/facts/xbps.py +2 -0
  50. pyinfra/facts/yum.py +2 -0
  51. pyinfra/facts/zypper.py +2 -0
  52. pyinfra/operations/apk.py +3 -1
  53. pyinfra/operations/apt.py +16 -18
  54. pyinfra/operations/brew.py +10 -8
  55. pyinfra/operations/bsdinit.py +5 -3
  56. pyinfra/operations/cargo.py +3 -1
  57. pyinfra/operations/choco.py +3 -1
  58. pyinfra/operations/dnf.py +15 -19
  59. pyinfra/operations/files.py +81 -66
  60. pyinfra/operations/gem.py +3 -1
  61. pyinfra/operations/git.py +18 -16
  62. pyinfra/operations/iptables.py +27 -25
  63. pyinfra/operations/launchd.py +5 -6
  64. pyinfra/operations/lxd.py +7 -4
  65. pyinfra/operations/mysql.py +57 -53
  66. pyinfra/operations/npm.py +8 -1
  67. pyinfra/operations/openrc.py +5 -3
  68. pyinfra/operations/pacman.py +4 -5
  69. pyinfra/operations/pip.py +11 -9
  70. pyinfra/operations/pkg.py +3 -1
  71. pyinfra/operations/pkgin.py +3 -1
  72. pyinfra/operations/postgres.py +39 -37
  73. pyinfra/operations/postgresql.py +2 -0
  74. pyinfra/operations/puppet.py +3 -1
  75. pyinfra/operations/python.py +7 -3
  76. pyinfra/operations/selinux.py +42 -16
  77. pyinfra/operations/server.py +48 -43
  78. pyinfra/operations/snap.py +3 -1
  79. pyinfra/operations/ssh.py +12 -10
  80. pyinfra/operations/systemd.py +8 -6
  81. pyinfra/operations/sysvinit.py +6 -4
  82. pyinfra/operations/upstart.py +5 -3
  83. pyinfra/operations/util/files.py +24 -16
  84. pyinfra/operations/util/packaging.py +53 -37
  85. pyinfra/operations/util/service.py +18 -13
  86. pyinfra/operations/vzctl.py +12 -10
  87. pyinfra/operations/xbps.py +3 -1
  88. pyinfra/operations/yum.py +14 -18
  89. pyinfra/operations/zypper.py +8 -9
  90. pyinfra/version.py +5 -2
  91. {pyinfra-3.0b1.dist-info → pyinfra-3.0b2.dist-info}/METADATA +28 -26
  92. pyinfra-3.0b2.dist-info/RECORD +163 -0
  93. {pyinfra-3.0b1.dist-info → pyinfra-3.0b2.dist-info}/WHEEL +1 -1
  94. pyinfra_cli/exceptions.py +0 -5
  95. pyinfra_cli/inventory.py +38 -19
  96. pyinfra_cli/prints.py +15 -11
  97. pyinfra_cli/util.py +3 -1
  98. tests/test_api/test_api_operations.py +1 -1
  99. tests/test_connectors/test_ssh.py +66 -13
  100. tests/test_connectors/test_vagrant.py +3 -3
  101. pyinfra-3.0b1.dist-info/RECORD +0 -163
  102. {pyinfra-3.0b1.dist-info → pyinfra-3.0b2.dist-info}/LICENSE.md +0 -0
  103. {pyinfra-3.0b1.dist-info → pyinfra-3.0b2.dist-info}/entry_points.txt +0 -0
  104. {pyinfra-3.0b1.dist-info → pyinfra-3.0b2.dist-info}/top_level.txt +0 -0
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from pyinfra.api import operation
2
4
 
3
5
  from . import postgres
@@ -1,8 +1,10 @@
1
+ from __future__ import annotations
2
+
1
3
  from pyinfra.api import operation
2
4
 
3
5
 
4
6
  @operation(is_idempotent=False)
5
- def agent(server=None, port=None):
7
+ def agent(server: str | None = None, port: int | None = None):
6
8
  """
7
9
  Run puppet agent
8
10
 
@@ -2,11 +2,15 @@
2
2
  The Python module allows you to execute Python code within the context of a deploy.
3
3
  """
4
4
 
5
+ from __future__ import annotations
6
+
7
+ from typing import Callable
8
+
5
9
  from pyinfra.api import FunctionCommand, operation
6
10
 
7
11
 
8
12
  @operation(is_idempotent=False, _set_in_op=False)
9
- def call(function, *args, **kwargs):
13
+ def call(function: Callable, *args, **kwargs):
10
14
  """
11
15
  Execute a Python function within a deploy.
12
16
 
@@ -43,7 +47,7 @@ def call(function, *args, **kwargs):
43
47
 
44
48
 
45
49
  @operation(is_idempotent=False, _set_in_op=False)
46
- def raise_exception(exception, *args, **kwargs):
50
+ def raise_exception(exception: Exception, *args, **kwargs):
47
51
  """
48
52
  Raise a Python exception within a deploy.
49
53
 
@@ -63,6 +67,6 @@ def raise_exception(exception, *args, **kwargs):
63
67
  """
64
68
 
65
69
  def raise_exc(*args, **kwargs): # pragma: no cover
66
- raise exception(*args, **kwargs)
70
+ raise exception(*args, **kwargs) # type: ignore[operator]
67
71
 
68
72
  yield FunctionCommand(raise_exc, args, kwargs)
@@ -1,19 +1,36 @@
1
1
  """
2
2
  Provides operations to set SELinux file contexts, booleans and port types.
3
3
  """
4
+
5
+ from __future__ import annotations
6
+
7
+ from enum import Enum
8
+
4
9
  from pyinfra import host
5
- from pyinfra.api import QuoteString, StringCommand, operation
10
+ from pyinfra.api import OperationValueError, QuoteString, StringCommand, operation
6
11
  from pyinfra.facts.selinux import FileContext, FileContextMapping, SEBoolean, SEPort, SEPorts
7
12
  from pyinfra.facts.server import Which
8
13
 
9
14
 
15
+ class Boolean(Enum):
16
+ ON = "on"
17
+ OFF = "off"
18
+
19
+
20
+ class Protocol(Enum):
21
+ UDP = "udp"
22
+ TCP = "tcp"
23
+ SCTP = "sctp"
24
+ DCCP = "dccp"
25
+
26
+
10
27
  @operation()
11
- def boolean(bool_name, value, persistent=False):
28
+ def boolean(bool_name: str, value: Boolean, persistent=False):
12
29
  """
13
30
  Set the specified SELinux boolean to the desired state.
14
31
 
15
32
  + boolean: name of an SELinux boolean
16
- + state: 'on' or 'off'
33
+ + value: desired state of the boolean
17
34
  + persistent: whether to write updated policy or not
18
35
 
19
36
  Note: This operation requires root privileges.
@@ -25,26 +42,31 @@ def boolean(bool_name, value, persistent=False):
25
42
  selinux.boolean(
26
43
  name='Allow Apache to connect to LDAP server',
27
44
  'httpd_can_network_connect',
28
- 'on',
45
+ Boolean.ON,
29
46
  persistent=True
30
47
  )
31
48
  """
32
- _valid_states = ["on", "off"]
33
49
 
34
- if value not in _valid_states:
35
- raise ValueError(
36
- f'\'value\' must be one of \'{",".join(_valid_states)}\' but found \'{value}\'',
37
- )
50
+ value_str: str
51
+ if value in ["on", "off"]: # compatibility with the old version
52
+ assert isinstance(value, str)
53
+ value_str = value
54
+ elif value is Boolean.ON:
55
+ value_str = "on"
56
+ elif value is Boolean.OFF:
57
+ value_str = "off"
58
+ else:
59
+ raise OperationValueError(f"Invalid value '{value}' for boolean operation")
38
60
 
39
- if host.get_fact(SEBoolean, boolean=bool_name) != value:
61
+ if host.get_fact(SEBoolean, boolean=bool_name) != value_str:
40
62
  persist = "-P " if persistent else ""
41
- yield StringCommand("setsebool", f"{persist}{bool_name}", value)
63
+ yield StringCommand("setsebool", f"{persist}{bool_name}", value_str)
42
64
  else:
43
- host.noop(f"boolean '{bool_name}' already had the value '{value}'")
65
+ host.noop(f"boolean '{bool_name}' already had the value '{value_str}'")
44
66
 
45
67
 
46
68
  @operation()
47
- def file_context(path, se_type):
69
+ def file_context(path: str, se_type: str):
48
70
  """
49
71
  Set the SELinux type for the specified path to the specified value.
50
72
 
@@ -70,7 +92,7 @@ def file_context(path, se_type):
70
92
 
71
93
 
72
94
  @operation()
73
- def file_context_mapping(target, se_type=None, present=True):
95
+ def file_context_mapping(target: str, se_type: str | None = None, present=True):
74
96
  """
75
97
  Set the SELinux file context mapping for paths matching the target.
76
98
 
@@ -110,7 +132,7 @@ def file_context_mapping(target, se_type=None, present=True):
110
132
 
111
133
 
112
134
  @operation()
113
- def port(protocol, port_num, se_type=None, present=True):
135
+ def port(protocol: Protocol | str, port_num: int, se_type: str | None = None, present=True):
114
136
  """
115
137
  Set the SELinux type for the specified protocol and port.
116
138
 
@@ -127,12 +149,16 @@ def port(protocol, port_num, se_type=None, present=True):
127
149
 
128
150
  selinux.port(
129
151
  name='Allow Apache to provide service on port 2222',
130
- 'tcp',
152
+ Protocol.TCP,
131
153
  2222,
132
154
  'http_port_t',
133
155
  )
134
156
  """
135
157
 
158
+ if protocol is Protocol:
159
+ assert isinstance(protocol, Protocol)
160
+ protocol = protocol.value
161
+
136
162
  if present and (se_type is None):
137
163
  raise ValueError("se_type must have a valid value if present is set")
138
164
 
@@ -3,6 +3,8 @@ The server module takes care of os-level state. Targets POSIX compatibility, tes
3
3
  Linux/BSD.
4
4
  """
5
5
 
6
+ from __future__ import annotations
7
+
6
8
  import shlex
7
9
  from io import StringIO
8
10
  from itertools import filterfalse, tee
@@ -18,6 +20,7 @@ from pyinfra.facts.files import Directory, FindInFile, Link
18
20
  from pyinfra.facts.server import (
19
21
  Crontab,
20
22
  Groups,
23
+ Home,
21
24
  Hostname,
22
25
  KernelModules,
23
26
  Locales,
@@ -139,7 +142,7 @@ def wait(port: int):
139
142
 
140
143
 
141
144
  @operation(is_idempotent=False)
142
- def shell(commands):
145
+ def shell(commands: str | list[str]):
143
146
  """
144
147
  Run raw shell code on server during a deploy. If the command would
145
148
  modify data that would be in a fact, the fact would not be updated
@@ -166,7 +169,7 @@ def shell(commands):
166
169
 
167
170
 
168
171
  @operation(is_idempotent=False)
169
- def script(src, args=()):
172
+ def script(src: str, args=()):
170
173
  """
171
174
  Upload and execute a local script on the remote host.
172
175
 
@@ -199,7 +202,7 @@ def script(src, args=()):
199
202
 
200
203
 
201
204
  @operation(is_idempotent=False)
202
- def script_template(src, args=(), **data):
205
+ def script_template(src: str, args=(), **data):
203
206
  """
204
207
  Generate, upload and execute a local script template on the remote host.
205
208
 
@@ -229,7 +232,7 @@ def script_template(src, args=(), **data):
229
232
 
230
233
 
231
234
  @operation()
232
- def modprobe(module, present=True, force=False):
235
+ def modprobe(module: str, present=True, force=False):
233
236
  """
234
237
  Load/unload kernel modules.
235
238
 
@@ -281,11 +284,11 @@ def modprobe(module, present=True, force=False):
281
284
 
282
285
  @operation()
283
286
  def mount(
284
- path,
287
+ path: str,
285
288
  mounted=True,
286
- options=None,
287
- device=None,
288
- fs_type=None,
289
+ options: list[str] | None = None,
290
+ device: str | None = None,
291
+ fs_type: str | None = None,
289
292
  # TODO: do we want to manage fstab here?
290
293
  # update_fstab=False,
291
294
  ):
@@ -344,7 +347,7 @@ def mount(
344
347
 
345
348
 
346
349
  @operation()
347
- def hostname(hostname, hostname_file=None):
350
+ def hostname(hostname: str, hostname_file: str | None = None):
348
351
  """
349
352
  Set the system hostname using ``hostnamectl`` or ``hostname`` on older systems.
350
353
 
@@ -402,8 +405,8 @@ def hostname(hostname, hostname_file=None):
402
405
 
403
406
  @operation()
404
407
  def sysctl(
405
- key,
406
- value,
408
+ key: str,
409
+ value: str | int | list[str | int],
407
410
  persist=False,
408
411
  persist_file="/etc/sysctl.conf",
409
412
  ):
@@ -449,12 +452,12 @@ def sysctl(
449
452
 
450
453
  @operation()
451
454
  def service(
452
- service,
455
+ service: str,
453
456
  running=True,
454
457
  restarted=False,
455
458
  reloaded=False,
456
- command=None,
457
- enabled=None,
459
+ command: str | None = None,
460
+ enabled: bool | None = None,
458
461
  ):
459
462
  """
460
463
  Manage the state of services. This command checks for the presence of all the
@@ -518,7 +521,7 @@ def service(
518
521
 
519
522
  @operation()
520
523
  def packages(
521
- packages,
524
+ packages: str | list[str],
522
525
  present=True,
523
526
  ):
524
527
  """
@@ -583,16 +586,16 @@ def packages(
583
586
 
584
587
  @operation()
585
588
  def crontab(
586
- command,
589
+ command: str,
587
590
  present=True,
588
- user=None,
589
- cron_name=None,
591
+ user: str | None = None,
592
+ cron_name: str | None = None,
590
593
  minute="*",
591
594
  hour="*",
592
595
  month="*",
593
596
  day_of_week="*",
594
597
  day_of_month="*",
595
- special_time=None,
598
+ special_time: str | None = None,
596
599
  interpolate_variables=False,
597
600
  ):
598
601
  """
@@ -663,7 +666,7 @@ def crontab(
663
666
 
664
667
  exists = existing_crontab is not None
665
668
 
666
- edit_commands = []
669
+ edit_commands: list[str | StringCommand] = []
667
670
  temp_filename = host.get_temp_filename()
668
671
 
669
672
  if special_time:
@@ -758,7 +761,7 @@ def crontab(
758
761
 
759
762
 
760
763
  @operation()
761
- def group(group, present=True, system=False, gid=None):
764
+ def group(group: str, present=True, system=False, gid: int | str | None = None):
762
765
  """
763
766
  Add/remove system groups.
764
767
 
@@ -827,12 +830,12 @@ def group(group, present=True, system=False, gid=None):
827
830
 
828
831
  @operation()
829
832
  def user_authorized_keys(
830
- user,
831
- public_keys,
832
- group=None,
833
+ user: str,
834
+ public_keys: str | list[str],
835
+ group: str | None = None,
833
836
  delete_keys=False,
834
- authorized_key_directory=None,
835
- authorized_key_filename=None,
837
+ authorized_key_directory: str | None = None,
838
+ authorized_key_filename: str | None = None,
836
839
  ):
837
840
  """
838
841
  Manage `authorized_keys` of system users.
@@ -858,7 +861,9 @@ def user_authorized_keys(
858
861
  """
859
862
 
860
863
  if not authorized_key_directory:
861
- authorized_key_directory = f"/home/{user}/.ssh/"
864
+ home = host.get_fact(Home, user=user)
865
+ authorized_key_directory = f"{home}/.ssh"
866
+
862
867
  if not authorized_key_filename:
863
868
  authorized_key_filename = "authorized_keys"
864
869
 
@@ -923,22 +928,22 @@ def user_authorized_keys(
923
928
 
924
929
  @operation()
925
930
  def user(
926
- user,
931
+ user: str,
927
932
  present=True,
928
- home=None,
929
- shell=None,
930
- group=None,
931
- groups=None,
932
- public_keys=None,
933
+ home: str | None = None,
934
+ shell: str | None = None,
935
+ group: str | None = None,
936
+ groups: list[str] | None = None,
937
+ public_keys: str | list[str] | None = None,
933
938
  delete_keys=False,
934
939
  ensure_home=True,
935
940
  create_home=False,
936
941
  system=False,
937
- uid=None,
938
- comment=None,
942
+ uid: int | None = None,
943
+ comment: str | None = None,
939
944
  add_deploy_dir=True,
940
945
  unique=True,
941
- password=None,
946
+ password: str | None = None,
942
947
  ):
943
948
  """
944
949
  Add/remove/update system users & their ssh `authorized_keys`.
@@ -1124,7 +1129,7 @@ def user(
1124
1129
  existing_user["password"] = password
1125
1130
 
1126
1131
  # Ensure home directory ownership
1127
- if ensure_home:
1132
+ if ensure_home and home:
1128
1133
  yield from files.directory._inner(
1129
1134
  path=home,
1130
1135
  user=user,
@@ -1147,7 +1152,7 @@ def user(
1147
1152
 
1148
1153
  @operation()
1149
1154
  def locale(
1150
- locale,
1155
+ locale: str,
1151
1156
  present=True,
1152
1157
  ):
1153
1158
  """
@@ -1217,10 +1222,10 @@ def locale(
1217
1222
 
1218
1223
  @operation()
1219
1224
  def security_limit(
1220
- domain,
1221
- limit_type,
1222
- item,
1223
- value,
1225
+ domain: str,
1226
+ limit_type: str,
1227
+ item: str,
1228
+ value: int,
1224
1229
  ):
1225
1230
  """
1226
1231
  Edit /etc/security/limits.conf configuration.
@@ -1239,7 +1244,7 @@ def security_limit(
1239
1244
  domain='*',
1240
1245
  limit_type='soft',
1241
1246
  item='nofile',
1242
- value='1024',
1247
+ value=1024,
1243
1248
  )
1244
1249
  """
1245
1250
 
@@ -2,6 +2,8 @@
2
2
  Manage snap packages. See https://snapcraft.io/
3
3
  """
4
4
 
5
+ from __future__ import annotations
6
+
5
7
  from pyinfra import host
6
8
  from pyinfra.api import operation
7
9
  from pyinfra.facts.snap import SnapPackage, SnapPackages
@@ -9,7 +11,7 @@ from pyinfra.facts.snap import SnapPackage, SnapPackages
9
11
 
10
12
  @operation()
11
13
  def package(
12
- packages=None,
14
+ packages: str | list[str] | None = None,
13
15
  channel="latest/stable",
14
16
  classic=False,
15
17
  present=True,
pyinfra/operations/ssh.py CHANGED
@@ -4,6 +4,8 @@ Execute commands and up/download files *from* the remote host.
4
4
  Eg: ``pyinfra -> inventory-host.net <-> another-host.net``
5
5
  """
6
6
 
7
+ from __future__ import annotations
8
+
7
9
  import shlex
8
10
 
9
11
  from pyinfra import host
@@ -15,7 +17,7 @@ from . import files
15
17
 
16
18
 
17
19
  @operation()
18
- def keyscan(hostname, force=False, port=22):
20
+ def keyscan(hostname: str, force=False, port=22):
19
21
  """
20
22
  Check/add hosts to the ``~/.ssh/known_hosts`` file.
21
23
 
@@ -63,7 +65,7 @@ def keyscan(hostname, force=False, port=22):
63
65
 
64
66
 
65
67
  @operation(is_idempotent=False)
66
- def command(hostname, command, user=None, port=22):
68
+ def command(hostname: str, command: str, user: str | None = None, port=22):
67
69
  """
68
70
  Execute commands on other servers over SSH.
69
71
 
@@ -95,11 +97,11 @@ def command(hostname, command, user=None, port=22):
95
97
 
96
98
  @operation(is_idempotent=False)
97
99
  def upload(
98
- hostname,
99
- filename,
100
- remote_filename=None,
100
+ hostname: str,
101
+ filename: str,
102
+ remote_filename: str | None = None,
101
103
  port=22,
102
- user=None,
104
+ user: str | None = None,
103
105
  use_remote_sudo=False,
104
106
  ssh_keyscan=False,
105
107
  ):
@@ -159,12 +161,12 @@ def upload(
159
161
 
160
162
  @operation()
161
163
  def download(
162
- hostname,
163
- filename,
164
- local_filename=None,
164
+ hostname: str,
165
+ filename: str,
166
+ local_filename: str | None = None,
165
167
  force=False,
166
168
  port=22,
167
- user=None,
169
+ user: str | None = None,
168
170
  ssh_keyscan=False,
169
171
  ):
170
172
  """
@@ -2,6 +2,8 @@
2
2
  Manage systemd services.
3
3
  """
4
4
 
5
+ from __future__ import annotations
6
+
5
7
  from pyinfra import host
6
8
  from pyinfra.api import StringCommand, operation
7
9
  from pyinfra.facts.systemd import SystemdEnabled, SystemdStatus, _make_systemctl_cmd
@@ -10,7 +12,7 @@ from .util.service import handle_service_control
10
12
 
11
13
 
12
14
  @operation(is_idempotent=False)
13
- def daemon_reload(user_mode=False, machine=None, user_name=None):
15
+ def daemon_reload(user_mode=False, machine: str | None = None, user_name: str | None = None):
14
16
  """
15
17
  Reload the systemd daemon to read unit file changes.
16
18
 
@@ -33,16 +35,16 @@ _daemon_reload = daemon_reload._inner # noqa: E305
33
35
 
34
36
  @operation()
35
37
  def service(
36
- service,
38
+ service: str,
37
39
  running=True,
38
40
  restarted=False,
39
41
  reloaded=False,
40
- command=None,
41
- enabled=None,
42
+ command: str | None = None,
43
+ enabled: bool | None = None,
42
44
  daemon_reload=False,
43
45
  user_mode=False,
44
- machine=None,
45
- user_name=None,
46
+ machine: str | None = None,
47
+ user_name: str | None = None,
46
48
  ):
47
49
  """
48
50
  Manage the state of systemd managed units.
@@ -2,6 +2,8 @@
2
2
  Manage sysvinit services (``/etc/init.d``).
3
3
  """
4
4
 
5
+ from __future__ import annotations
6
+
5
7
  from pyinfra import host
6
8
  from pyinfra.api import operation
7
9
  from pyinfra.facts.files import FindLinks
@@ -14,12 +16,12 @@ from .util.service import handle_service_control
14
16
 
15
17
  @operation()
16
18
  def service(
17
- service,
19
+ service: str,
18
20
  running=True,
19
21
  restarted=False,
20
22
  reloaded=False,
21
- enabled=None,
22
- command=None,
23
+ enabled: bool | None = None,
24
+ command: str | None = None,
23
25
  ):
24
26
  """
25
27
  Manage the state of SysV Init (/etc/init.d) services.
@@ -95,7 +97,7 @@ def service(
95
97
 
96
98
  @operation()
97
99
  def enable(
98
- service,
100
+ service: str,
99
101
  start_priority=20,
100
102
  stop_priority=80,
101
103
  start_levels=(2, 3, 4, 5),
@@ -2,6 +2,8 @@
2
2
  Manage upstart services.
3
3
  """
4
4
 
5
+ from __future__ import annotations
6
+
5
7
  from io import StringIO
6
8
 
7
9
  from pyinfra import host
@@ -14,12 +16,12 @@ from .util.service import handle_service_control
14
16
 
15
17
  @operation()
16
18
  def service(
17
- service,
19
+ service: str,
18
20
  running=True,
19
21
  restarted=False,
20
22
  reloaded=False,
21
- command=None,
22
- enabled=None,
23
+ command: str | None = None,
24
+ enabled: bool | None = None,
23
25
  ):
24
26
  """
25
27
  Manage the state of upstart managed services.
@@ -1,16 +1,18 @@
1
+ from __future__ import annotations
2
+
1
3
  import re
2
4
  from datetime import datetime
3
5
 
4
6
  from pyinfra.api import QuoteString, StringCommand
5
7
 
6
8
 
7
- def unix_path_join(*path_parts):
8
- parts = list(path_parts)
9
- parts[0:-1] = [part.rstrip("/") for part in parts[0:-1]]
10
- return "/".join(parts)
9
+ def unix_path_join(*parts) -> str:
10
+ part_list = list(parts)
11
+ part_list[0:-1] = [part.rstrip("/") for part in part_list[0:-1]]
12
+ return "/".join(part_list)
11
13
 
12
14
 
13
- def ensure_mode_int(mode):
15
+ def ensure_mode_int(mode: str | int | None) -> int | str | None:
14
16
  # Already an int (/None)?
15
17
  if isinstance(mode, int) or mode is None:
16
18
  return mode
@@ -26,19 +28,19 @@ def ensure_mode_int(mode):
26
28
  return mode
27
29
 
28
30
 
29
- def get_timestamp():
31
+ def get_timestamp() -> str:
30
32
  return datetime.now().strftime("%y%m%d%H%M")
31
33
 
32
34
 
33
35
  def sed_replace(
34
- filename,
35
- line,
36
- replace,
37
- flags=None,
36
+ filename: str,
37
+ line: str,
38
+ replace: str,
39
+ flags: list[str] | None = None,
38
40
  backup=False,
39
41
  interpolate_variables=False,
40
- ):
41
- flags = "".join(flags) if flags else ""
42
+ ) -> StringCommand:
43
+ flags_str = "".join(flags) if flags else ""
42
44
 
43
45
  line = line.replace("/", r"\/")
44
46
  replace = str(replace)
@@ -57,7 +59,7 @@ def sed_replace(
57
59
  replace = replace.replace("'", "'\"'\"'")
58
60
  sed_script_formatter = "'s/{0}/{1}/{2}'"
59
61
 
60
- sed_script = sed_script_formatter.format(line, replace, flags)
62
+ sed_script = sed_script_formatter.format(line, replace, flags_str)
61
63
 
62
64
  sed_command = StringCommand(
63
65
  "sed",
@@ -73,7 +75,7 @@ def sed_replace(
73
75
  return sed_command
74
76
 
75
77
 
76
- def chmod(target, mode, recursive=False):
78
+ def chmod(target: str, mode: str | int, recursive=False) -> StringCommand:
77
79
  args = ["chmod"]
78
80
  if recursive:
79
81
  args.append("-R")
@@ -83,7 +85,13 @@ def chmod(target, mode, recursive=False):
83
85
  return StringCommand(" ".join(args), QuoteString(target))
84
86
 
85
87
 
86
- def chown(target, user, group=None, recursive=False, dereference=True):
88
+ def chown(
89
+ target: str,
90
+ user: str | None = None,
91
+ group: str | None = None,
92
+ recursive=False,
93
+ dereference=True,
94
+ ) -> StringCommand:
87
95
  command = "chown"
88
96
  user_group = None
89
97
 
@@ -107,7 +115,7 @@ def chown(target, user, group=None, recursive=False, dereference=True):
107
115
  return StringCommand(" ".join(args), user_group, QuoteString(target))
108
116
 
109
117
 
110
- def adjust_regex(line, escape_regex_characters):
118
+ def adjust_regex(line: str, escape_regex_characters: bool) -> str:
111
119
  """
112
120
  Ensure the regex starts with '^' and ends with '$' and escape regex characters if requested
113
121
  """