ansible-core 2.19.0b5__py3-none-any.whl → 2.19.0b6__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.
- ansible/_internal/_ansiballz/__init__.py +0 -0
- ansible/_internal/_ansiballz/_builder.py +101 -0
- ansible/_internal/{_ansiballz.py → _ansiballz/_wrapper.py} +11 -11
- ansible/_internal/_templating/_jinja_bits.py +7 -4
- ansible/_internal/_templating/_jinja_plugins.py +5 -2
- ansible/_internal/_templating/_template_vars.py +72 -0
- ansible/_internal/_templating/_transform.py +6 -0
- ansible/_internal/_yaml/_constructor.py +4 -4
- ansible/_internal/_yaml/_dumper.py +26 -18
- ansible/cli/__init__.py +7 -12
- ansible/cli/arguments/option_helpers.py +1 -1
- ansible/cli/console.py +1 -1
- ansible/cli/doc.py +2 -2
- ansible/cli/inventory.py +5 -7
- ansible/config/base.yml +24 -0
- ansible/errors/__init__.py +2 -1
- ansible/executor/module_common.py +67 -39
- ansible/executor/process/worker.py +2 -2
- ansible/galaxy/api.py +1 -4
- ansible/galaxy/collection/__init__.py +1 -6
- ansible/galaxy/collection/concrete_artifact_manager.py +2 -8
- ansible/galaxy/role.py +2 -2
- ansible/module_utils/_internal/__init__.py +7 -4
- ansible/module_utils/_internal/_ansiballz/__init__.py +0 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/__init__.py +0 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/_coverage.py +45 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/_pydevd.py +62 -0
- ansible/module_utils/_internal/{_ansiballz.py → _ansiballz/_loader.py} +10 -38
- ansible/module_utils/_internal/_ansiballz/_respawn.py +32 -0
- ansible/module_utils/_internal/_ansiballz/_respawn_wrapper.py +23 -0
- ansible/module_utils/_internal/_datatag/__init__.py +23 -1
- ansible/module_utils/_internal/_deprecator.py +27 -33
- ansible/module_utils/_internal/_json/_profiles/__init__.py +1 -0
- ansible/module_utils/_internal/_messages.py +26 -2
- ansible/module_utils/_internal/_plugin_info.py +14 -1
- ansible/module_utils/ansible_release.py +1 -1
- ansible/module_utils/basic.py +46 -56
- ansible/module_utils/common/respawn.py +4 -41
- ansible/module_utils/connection.py +8 -11
- ansible/module_utils/facts/hardware/linux.py +1 -1
- ansible/module_utils/facts/sysctl.py +4 -6
- ansible/module_utils/facts/system/caps.py +2 -2
- ansible/module_utils/facts/system/local.py +1 -1
- ansible/module_utils/facts/virtual/linux.py +1 -1
- ansible/module_utils/service.py +1 -1
- ansible/module_utils/urls.py +4 -4
- ansible/modules/apt_repository.py +10 -10
- ansible/modules/assemble.py +2 -2
- ansible/modules/async_wrapper.py +7 -17
- ansible/modules/command.py +3 -3
- ansible/modules/copy.py +4 -4
- ansible/modules/cron.py +1 -1
- ansible/modules/file.py +16 -17
- ansible/modules/find.py +3 -3
- ansible/modules/get_url.py +17 -0
- ansible/modules/git.py +9 -7
- ansible/modules/known_hosts.py +12 -14
- ansible/modules/package.py +6 -0
- ansible/modules/replace.py +2 -2
- ansible/modules/slurp.py +10 -13
- ansible/modules/stat.py +5 -7
- ansible/modules/unarchive.py +6 -6
- ansible/modules/user.py +1 -1
- ansible/modules/wait_for.py +28 -30
- ansible/modules/yum_repository.py +4 -3
- ansible/parsing/dataloader.py +2 -2
- ansible/parsing/vault/__init__.py +6 -10
- ansible/playbook/base.py +7 -2
- ansible/playbook/included_file.py +3 -1
- ansible/playbook/play_context.py +2 -0
- ansible/playbook/taggable.py +19 -5
- ansible/playbook/task.py +2 -0
- ansible/plugins/action/fetch.py +3 -3
- ansible/plugins/action/template.py +8 -2
- ansible/plugins/cache/__init__.py +17 -19
- ansible/plugins/callback/tree.py +5 -5
- ansible/plugins/connection/local.py +4 -4
- ansible/plugins/connection/paramiko_ssh.py +5 -5
- ansible/plugins/connection/ssh.py +8 -6
- ansible/plugins/connection/winrm.py +1 -1
- ansible/plugins/filter/core.py +19 -21
- ansible/plugins/filter/encryption.py +10 -2
- ansible/plugins/list.py +5 -4
- ansible/plugins/lookup/template.py +9 -4
- ansible/plugins/shell/powershell.py +3 -2
- ansible/plugins/shell/sh.py +3 -2
- ansible/plugins/strategy/__init__.py +3 -3
- ansible/plugins/test/core.py +2 -2
- ansible/release.py +1 -1
- ansible/template/__init__.py +9 -53
- ansible/utils/collection_loader/_collection_finder.py +3 -3
- ansible/utils/display.py +23 -12
- ansible/utils/galaxy.py +2 -2
- ansible/utils/hashing.py +6 -7
- ansible/utils/path.py +5 -7
- ansible/utils/py3compat.py +2 -1
- ansible/utils/ssh_functions.py +3 -2
- ansible/vars/plugins.py +3 -3
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b6.dist-info}/METADATA +1 -1
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b6.dist-info}/RECORD +117 -108
- ansible_test/_internal/commands/integration/coverage.py +7 -2
- ansible_test/_internal/host_profiles.py +62 -10
- ansible_test/_internal/provisioning.py +10 -4
- ansible_test/_internal/ssh.py +1 -5
- ansible_test/_internal/thread.py +2 -1
- ansible_test/_internal/timeout.py +1 -1
- ansible_test/_internal/util.py +20 -12
- ansible_test/_util/target/setup/requirements.py +3 -9
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b6.dist-info}/WHEEL +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b6.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/COPYING +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/Apache-License.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/MIT-license.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/PSF-license.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b6.dist-info}/top_level.txt +0 -0
ansible/plugins/shell/sh.py
CHANGED
@@ -48,8 +48,9 @@ class ShellModule(ShellBase):
|
|
48
48
|
|
49
49
|
def checksum(self, path, python_interp):
|
50
50
|
display.deprecated(
|
51
|
-
"The
|
52
|
-
version="2.23"
|
51
|
+
msg="The `ShellModule.checksum` method is deprecated.",
|
52
|
+
version="2.23",
|
53
|
+
help_text="Use `ActionBase._execute_remote_stat()` instead.",
|
53
54
|
)
|
54
55
|
# In the following test, each condition is a check and logical
|
55
56
|
# comparison (|| or &&) that sets the rc value. Every check is run so
|
@@ -128,7 +128,7 @@ def results_thread_main(strategy: StrategyBase) -> None:
|
|
128
128
|
strategy._workers[result.worker_id].worker_queue.put(value)
|
129
129
|
else:
|
130
130
|
display.warning('Received an invalid object (%s) in the result queue: %r' % (type(result), result))
|
131
|
-
except (
|
131
|
+
except (OSError, EOFError):
|
132
132
|
break
|
133
133
|
except queue.Empty:
|
134
134
|
pass
|
@@ -402,9 +402,9 @@ class StrategyBase:
|
|
402
402
|
time.sleep(0.0001)
|
403
403
|
|
404
404
|
self._pending_results += 1
|
405
|
-
except (EOFError,
|
405
|
+
except (EOFError, OSError, AssertionError) as ex:
|
406
406
|
# most likely an abort
|
407
|
-
display.debug("got an error while queuing:
|
407
|
+
display.debug(f"got an error while queuing: {ex}")
|
408
408
|
return
|
409
409
|
display.debug("exiting _queue_task() for %s/%s" % (host.name, task.action))
|
410
410
|
|
ansible/plugins/test/core.py
CHANGED
@@ -175,8 +175,8 @@ def vaulted_file(value):
|
|
175
175
|
try:
|
176
176
|
with open(to_bytes(value), 'rb') as f:
|
177
177
|
return is_encrypted_file(f)
|
178
|
-
except
|
179
|
-
raise errors.AnsibleFilterError(f"Cannot test if the file {value} is a vault.") from
|
178
|
+
except OSError as ex:
|
179
|
+
raise errors.AnsibleFilterError(f"Cannot test if the file {value!r} is a vault.") from ex
|
180
180
|
|
181
181
|
|
182
182
|
def match(value, pattern='', ignorecase=False, multiline=False):
|
ansible/release.py
CHANGED
ansible/template/__init__.py
CHANGED
@@ -1,22 +1,18 @@
|
|
1
1
|
from __future__ import annotations as _annotations
|
2
2
|
|
3
3
|
import contextlib as _contextlib
|
4
|
-
import datetime as _datetime
|
5
4
|
import io as _io
|
6
5
|
import os as _os
|
7
|
-
import pwd as _pwd
|
8
|
-
import time as _time
|
9
6
|
import typing as _t
|
10
7
|
|
11
8
|
from jinja2 import environment as _environment
|
12
9
|
|
13
10
|
from ansible import _internal
|
14
|
-
from ansible import constants as _constants
|
15
11
|
from ansible import errors as _errors
|
16
12
|
from ansible._internal._datatag import _tags, _wrappers
|
17
|
-
from ansible._internal._templating import _jinja_bits, _engine, _jinja_common
|
13
|
+
from ansible._internal._templating import _jinja_bits, _engine, _jinja_common, _template_vars
|
14
|
+
|
18
15
|
from ansible.module_utils import datatag as _module_utils_datatag
|
19
|
-
from ansible.module_utils._internal import _datatag
|
20
16
|
from ansible.utils.display import Display as _Display
|
21
17
|
|
22
18
|
if _t.TYPE_CHECKING: # pragma: nocover
|
@@ -352,57 +348,17 @@ class Templar:
|
|
352
348
|
)
|
353
349
|
|
354
350
|
|
355
|
-
def generate_ansible_template_vars(
|
351
|
+
def generate_ansible_template_vars(
|
352
|
+
path: str,
|
353
|
+
fullpath: str | None = None,
|
354
|
+
dest_path: str | None = None,
|
355
|
+
) -> dict[str, object]:
|
356
356
|
"""
|
357
357
|
Generate and return a dictionary with variable metadata about the template specified by `fullpath`.
|
358
358
|
If `fullpath` is `None`, `path` will be used instead.
|
359
359
|
"""
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
template_path = fullpath
|
364
|
-
template_stat = _os.stat(template_path)
|
365
|
-
|
366
|
-
template_uid: int | str
|
367
|
-
|
368
|
-
try:
|
369
|
-
template_uid = _pwd.getpwuid(template_stat.st_uid).pw_name
|
370
|
-
except KeyError:
|
371
|
-
template_uid = template_stat.st_uid
|
372
|
-
|
373
|
-
managed_default = _constants.config.get_config_value('DEFAULT_MANAGED_STR')
|
374
|
-
|
375
|
-
managed_str = managed_default.format(
|
376
|
-
# IMPORTANT: These values must be constant strings to avoid template injection.
|
377
|
-
# Use Jinja template expressions where variables are needed.
|
378
|
-
host="{{ template_host }}",
|
379
|
-
uid="{{ template_uid }}",
|
380
|
-
file="{{ template_path }}",
|
381
|
-
)
|
382
|
-
|
383
|
-
ansible_managed = _time.strftime(managed_str, _time.localtime(template_stat.st_mtime))
|
384
|
-
# DTFIX7: this should not be tag_copy, it should either be an origin copy or some kind of derived origin
|
385
|
-
ansible_managed = _datatag.AnsibleTagHelper.tag_copy(managed_default, ansible_managed)
|
386
|
-
ansible_managed = trust_as_template(ansible_managed)
|
387
|
-
ansible_managed = _module_utils_datatag.deprecate_value(
|
388
|
-
value=ansible_managed,
|
389
|
-
msg="The `ansible_managed` variable is deprecated.",
|
390
|
-
help_text="Define and use a custom variable instead.",
|
391
|
-
version='2.23',
|
392
|
-
)
|
393
|
-
|
394
|
-
temp_vars = dict(
|
395
|
-
template_host=_os.uname()[1],
|
396
|
-
template_path=path,
|
397
|
-
template_mtime=_datetime.datetime.fromtimestamp(template_stat.st_mtime),
|
398
|
-
template_uid=template_uid,
|
399
|
-
template_run_date=_datetime.datetime.now(),
|
400
|
-
template_destpath=dest_path,
|
401
|
-
template_fullpath=fullpath,
|
402
|
-
ansible_managed=ansible_managed,
|
403
|
-
)
|
404
|
-
|
405
|
-
return temp_vars
|
360
|
+
# deprecated description="deprecate `generate_ansible_template_vars`, collections should inline the necessary variables" core_version="2.23"
|
361
|
+
return _template_vars.generate_ansible_template_vars(path=path, fullpath=fullpath, dest_path=dest_path, include_ansible_managed=True)
|
406
362
|
|
407
363
|
|
408
364
|
def trust_as_template(value: _TTrustable) -> _TTrustable:
|
@@ -1095,8 +1095,8 @@ def _get_collection_playbook_path(playbook):
|
|
1095
1095
|
try:
|
1096
1096
|
# get_collection_path
|
1097
1097
|
pkg = import_module(acr.n_python_collection_package_name)
|
1098
|
-
except (
|
1099
|
-
# leaving
|
1098
|
+
except (OSError, ModuleNotFoundError) as ex:
|
1099
|
+
# leaving ex as debug target, even though not used in normal code
|
1100
1100
|
pkg = None
|
1101
1101
|
|
1102
1102
|
if pkg:
|
@@ -1151,7 +1151,7 @@ def _get_collection_resource_path(name, ref_type, collection_list=None):
|
|
1151
1151
|
path = os.path.dirname(_to_bytes(sys.modules[acr.n_python_package_name].__file__))
|
1152
1152
|
return resource, _to_text(path), collection_name
|
1153
1153
|
|
1154
|
-
except (
|
1154
|
+
except (OSError, ModuleNotFoundError) as ex:
|
1155
1155
|
continue
|
1156
1156
|
except Exception as ex:
|
1157
1157
|
# FIXME: pick out typical import errors first, then error logging
|
ansible/utils/display.py
CHANGED
@@ -17,6 +17,7 @@
|
|
17
17
|
|
18
18
|
from __future__ import annotations
|
19
19
|
|
20
|
+
import contextlib
|
20
21
|
import dataclasses
|
21
22
|
|
22
23
|
try:
|
@@ -216,10 +217,22 @@ b_COW_PATHS = (
|
|
216
217
|
|
217
218
|
|
218
219
|
def _synchronize_textiowrapper(tio: t.TextIO, lock: threading.RLock):
|
219
|
-
|
220
|
-
|
221
|
-
|
220
|
+
"""
|
221
|
+
This decorator ensures that the supplied RLock is held before invoking the wrapped methods.
|
222
|
+
It is intended to prevent background threads from holding the Python stdout/stderr buffer lock on a file object during a fork.
|
223
|
+
Since background threads are abandoned in child forks, locks they hold are orphaned in a locked state.
|
224
|
+
Attempts to acquire an orphaned lock in this state will block forever, effectively hanging the child process on stdout/stderr writes.
|
225
|
+
The shared lock is permanently disabled immediately after a fork.
|
226
|
+
This prevents hangs in early post-fork code (e.g., stdio writes from pydevd, coverage, etc.) before user code has resumed and released the lock.
|
227
|
+
"""
|
228
|
+
|
222
229
|
def _wrap_with_lock(f, lock):
|
230
|
+
def disable_lock():
|
231
|
+
nonlocal lock
|
232
|
+
lock = contextlib.nullcontext()
|
233
|
+
|
234
|
+
os.register_at_fork(after_in_child=disable_lock)
|
235
|
+
|
223
236
|
@wraps(f)
|
224
237
|
def locking_wrapper(*args, **kwargs):
|
225
238
|
with lock:
|
@@ -474,7 +487,7 @@ class Display(metaclass=Singleton):
|
|
474
487
|
# final flush at shutdown.
|
475
488
|
# try:
|
476
489
|
# fileobj.flush()
|
477
|
-
# except
|
490
|
+
# except OSError as e:
|
478
491
|
# # Ignore EPIPE in case fileobj has been prematurely closed, eg.
|
479
492
|
# # when piping to "head -n1"
|
480
493
|
# if e.errno != errno.EPIPE:
|
@@ -603,20 +616,18 @@ class Display(metaclass=Singleton):
|
|
603
616
|
else:
|
604
617
|
removal_fragment = 'This feature will be removed'
|
605
618
|
|
606
|
-
if not deprecator or deprecator.type
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
collection = deprecator.resolved_name
|
619
|
+
if not deprecator or not deprecator.type:
|
620
|
+
# indeterminate has no resolved_name or type
|
621
|
+
# collections have a resolved_name but no type
|
622
|
+
collection = deprecator.resolved_name if deprecator else None
|
611
623
|
plugin_fragment = ''
|
612
624
|
else:
|
613
625
|
parts = deprecator.resolved_name.split('.')
|
614
626
|
plugin_name = parts[-1]
|
615
|
-
|
616
|
-
plugin_type = "module" if deprecator.type in ("module", "modules") else f'{deprecator.type} plugin'
|
627
|
+
plugin_type_name = str(deprecator.type) if deprecator.type is _messages.PluginType.MODULE else f'{deprecator.type} plugin'
|
617
628
|
|
618
629
|
collection = '.'.join(parts[:2]) if len(parts) > 2 else None
|
619
|
-
plugin_fragment = f'{
|
630
|
+
plugin_fragment = f'{plugin_type_name} {plugin_name!r}'
|
620
631
|
|
621
632
|
if collection and plugin_fragment:
|
622
633
|
plugin_fragment += ' in'
|
ansible/utils/galaxy.py
CHANGED
@@ -57,8 +57,8 @@ def scm_archive_resource(src, scm='git', name=None, version='HEAD', keep_scm_met
|
|
57
57
|
|
58
58
|
try:
|
59
59
|
scm_path = get_bin_path(scm)
|
60
|
-
except (ValueError, OSError
|
61
|
-
raise AnsibleError("
|
60
|
+
except (ValueError, OSError) as ex:
|
61
|
+
raise AnsibleError(f"Could not find/use {scm!r}, it is required to continue with installing {src!r}.") from ex
|
62
62
|
|
63
63
|
tempdir = tempfile.mkdtemp(dir=C.DEFAULT_LOCAL_TMP)
|
64
64
|
clone_cmd = [scm_path, 'clone']
|
ansible/utils/hashing.py
CHANGED
@@ -48,14 +48,13 @@ def secure_hash(filename, hash_func=sha1):
|
|
48
48
|
digest = hash_func()
|
49
49
|
blocksize = 64 * 1024
|
50
50
|
try:
|
51
|
-
|
52
|
-
block = infile.read(blocksize)
|
53
|
-
while block:
|
54
|
-
digest.update(block)
|
51
|
+
with open(filename, 'rb') as infile:
|
55
52
|
block = infile.read(blocksize)
|
56
|
-
|
57
|
-
|
58
|
-
|
53
|
+
while block:
|
54
|
+
digest.update(block)
|
55
|
+
block = infile.read(blocksize)
|
56
|
+
except OSError as ex:
|
57
|
+
raise AnsibleError(f"Error while accessing the file {filename!r}.") from ex
|
59
58
|
return digest.hexdigest()
|
60
59
|
|
61
60
|
|
ansible/utils/path.py
CHANGED
@@ -19,9 +19,8 @@ from __future__ import annotations
|
|
19
19
|
import os
|
20
20
|
import shutil
|
21
21
|
|
22
|
-
from errno import EEXIST
|
23
22
|
from ansible.errors import AnsibleError
|
24
|
-
from ansible.module_utils.common.text.converters import to_bytes,
|
23
|
+
from ansible.module_utils.common.text.converters import to_bytes, to_text
|
25
24
|
|
26
25
|
|
27
26
|
__all__ = ['unfrackpath', 'makedirs_safe']
|
@@ -84,12 +83,11 @@ def makedirs_safe(path, mode=None):
|
|
84
83
|
if not os.path.exists(b_rpath):
|
85
84
|
try:
|
86
85
|
if mode:
|
87
|
-
os.makedirs(b_rpath, mode)
|
86
|
+
os.makedirs(b_rpath, mode, exist_ok=True)
|
88
87
|
else:
|
89
|
-
os.makedirs(b_rpath)
|
90
|
-
except OSError as
|
91
|
-
|
92
|
-
raise AnsibleError("Unable to create local directories(%s): %s" % (to_native(rpath), to_native(e)))
|
88
|
+
os.makedirs(b_rpath, exist_ok=True)
|
89
|
+
except OSError as ex:
|
90
|
+
raise AnsibleError(f"Unable to create local directories {rpath!r}.") from ex
|
93
91
|
|
94
92
|
|
95
93
|
def basedir(source):
|
ansible/utils/py3compat.py
CHANGED
@@ -19,8 +19,9 @@ def __getattr__(name):
|
|
19
19
|
raise AttributeError(name)
|
20
20
|
|
21
21
|
display.deprecated(
|
22
|
-
msg='ansible.utils.py3compat.environ is deprecated
|
22
|
+
msg='`ansible.utils.py3compat.environ` is deprecated.',
|
23
23
|
version='2.20',
|
24
|
+
help_text='Use `os.environ` from the Python standard library instead.',
|
24
25
|
)
|
25
26
|
|
26
27
|
return os.environ
|
ansible/utils/ssh_functions.py
CHANGED
@@ -57,8 +57,9 @@ def set_default_transport():
|
|
57
57
|
# deal with 'smart' connection .. one time ..
|
58
58
|
if C.DEFAULT_TRANSPORT == 'smart':
|
59
59
|
display.deprecated(
|
60
|
-
msg="The
|
61
|
-
version=
|
60
|
+
msg="The `smart` option for connections is deprecated.",
|
61
|
+
version="2.20",
|
62
|
+
help_text="Set the connection plugin directly instead.",
|
62
63
|
)
|
63
64
|
|
64
65
|
# see if SSH can support ControlPersist if not use paramiko
|
ansible/vars/plugins.py
CHANGED
@@ -35,10 +35,10 @@ def get_plugin_vars(loader, plugin, path, entities):
|
|
35
35
|
if hasattr(plugin, 'get_host_vars') or hasattr(plugin, 'get_group_vars'):
|
36
36
|
display.deprecated(
|
37
37
|
msg=f"The vars plugin {plugin.ansible_name} from {plugin._original_path} is relying "
|
38
|
-
"on the deprecated entrypoints
|
39
|
-
"This plugin should be updated to inherit from BaseVarsPlugin and define "
|
40
|
-
"a 'get_vars' method as the main entrypoint instead.",
|
38
|
+
"on the deprecated entrypoints `get_host_vars` and `get_group_vars`.",
|
41
39
|
version="2.20",
|
40
|
+
help_text="This plugin should be updated to inherit from `BaseVarsPlugin` and define "
|
41
|
+
"a `get_vars` method as the main entrypoint instead.",
|
42
42
|
)
|
43
43
|
try:
|
44
44
|
for entity in entities:
|