This mapping has 1 multi-map group: several pairings are equally correct there. The code view shows one arbitrary valid pairing, not the only one.

Code view:

A painting is a person's account of this edit as text, recorded independently of the node mapping - a rendering often has several equally defensible answers where the mapping has one. Deletions and insertions carry no position on the opposite side in a painting, so that panel draws no caret for them.

Before

1# Copyright (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
2# Copyright 2015 Abhijit Menon-Sen <ams@2ndQuadrant.com>
3# Copyright 2017 Toshio Kuratomi <tkuratomi@ansible.com>
4# Copyright (c) 2017 Ansible Project
5# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
6
7from __future__ import annotations
8
9DOCUMENTATION = """
10 name: ssh
11 short_description: connect via SSH client binary
12 description:
13 - This connection plugin allows Ansible to communicate to the target machines through normal SSH command line.
14 - Ansible does not expose a channel to allow communication between the user and the SSH process to accept
15 a password manually to decrypt an SSH key when using this connection plugin (which is the default). The
16 use of C(ssh-agent) is highly recommended.
…lines 17–261 unchanged (245 lines)
262 key: pipelining
263 - section: ssh_connection
264 key: pipelining
265 vars:
266 - name: ansible_pipelining
267 - name: ansible_ssh_pipelining
268
269 private_key_file:
270 description:
271 - Path to private key file to use for authentication.
272 type: string
273 ini:
274 - section: defaults
275 key: private_key_file
276 env:
277 - name: ANSIBLE_PRIVATE_KEY_FILE
278 vars:
279 - name: ansible_private_key_file
280 - name: ansible_ssh_private_key_file
281 cli:
282 - name: private_key_file
283 option: '--private-key'
284
285 control_path:
286 description:
287 - This is the location to save SSH's ControlPath sockets, it uses SSH's variable substitution.
288 - Since 2.3, if null (default), ansible will generate a unique hash. Use ``%(directory)s`` to indicate where to use the control dir path setting.
289 - Before 2.3 it defaulted to ``control_path=%(directory)s/ansible-ssh-%%h-%%p-%%r``.
290 - Be aware that this setting is ignored if C(-o ControlPath) is set in ssh args.
…lines 291–394 unchanged (104 lines)
395import re
396import selectors
397import shlex
398import shutil
399import subprocess
400import sys
401import time
402import typing as t
403from functools import wraps
404from multiprocessing.shared_memory import SharedMemory
405
406from ansible.errors import (
407 AnsibleAuthenticationFailure,
408 AnsibleConnectionFailure,
409 AnsibleError,
410 AnsibleFileNotFound,
411)
412from ansible.module_utils.six import text_type, binary_type
413from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
414from ansible.plugins.connection import ConnectionBase, BUFSIZE
415from ansible.plugins.shell.powershell import _replace_stderr_clixml
416from ansible.utils.display import Display
417from ansible.utils.path import unfrackpath, makedirs_safe
418
419display = Display()
420
421P = t.ParamSpec('P')
422
423# error messages that indicate 255 return code is not from ssh itself.
424b_NOT_SSH_ERRORS = (b'Traceback (most recent call last):', # Python-2.6 when there's an exception
…lines 425–633 unchanged (209 lines)
634 self.allow_executable = False
635
636 # parser to discover 'passed options', used later on for pipelining resolution
637 self._tty_parser = argparse.ArgumentParser()
638 self._tty_parser.add_argument('-t', action='count')
639 self._tty_parser.add_argument('-o', action='append')
640
641 # The connection is created by running ssh/scp/sftp from the exec_command,
642 # put_file, and fetch_file methods, so we don't need to do any connection
643 # management here.
644
645 def _connect(self) -> Connection:
646 return self
…lines 647–707 unchanged (61 lines)
708 :arg explanation: A text string containing explaining why the arguments
709 were added. It will be displayed with a high enough verbosity.
710 .. note:: This function does its work via side-effect. The b_command list has the new arguments appended.
711 """
712 display.vvvvv(u'SSH: %s: (%s)' % (explanation, ')('.join(to_text(a) for a in b_args)), host=self.host)
713 b_command += b_args
714
715 def _build_command(self, binary: str, subsystem: str, *other_args: bytes | str) -> list[bytes]:
716 """
717 Takes a executable (ssh, scp, sftp or wrapper) and optional extra arguments and returns the remote command
718 wrapped in local ssh shell commands and ready for execution.
719
720 :arg binary: actual executable to use to execute command.
…lines 721–793 unchanged (73 lines)
794
795 self.port = self.get_option('port')
796 if self.port is not None:
797 b_args = (b"-o", b"Port=" + to_bytes(self.port, nonstring='simplerepr', errors='surrogate_or_strict'))
798 self._add_args(b_command, b_args, u"ANSIBLE_REMOTE_PORT/remote_port/ansible_port set")
799
800 key = self.get_option('private_key_file')
801 if key:
802 b_args = (b"-o", b'IdentityFile="' + to_bytes(os.path.expanduser(key), errors='surrogate_or_strict') + b'"')
803 self._add_args(b_command, b_args, u"ANSIBLE_PRIVATE_KEY_FILE/private_key_file/ansible_ssh_private_key_file set")
804
805 if not conn_password:
806 self._add_args(
807 b_command, (
…lines 808–1536 unchanged (729 lines)

After

1# Copyright (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
2# Copyright 2015 Abhijit Menon-Sen <ams@2ndQuadrant.com>
3# Copyright 2017 Toshio Kuratomi <tkuratomi@ansible.com>
4# Copyright (c) 2017 Ansible Project
5# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
6
7from __future__ import annotations
8
9DOCUMENTATION = """
10 name: ssh
11 short_description: connect via SSH client binary
12 description:
13 - This connection plugin allows Ansible to communicate to the target machines through normal SSH command line.
14 - Ansible does not expose a channel to allow communication between the user and the SSH process to accept
15 a password manually to decrypt an SSH key when using this connection plugin (which is the default). The
16 use of C(ssh-agent) is highly recommended.
…lines 17–261 unchanged (245 lines)
262 key: pipelining
263 - section: ssh_connection
264 key: pipelining
265 vars:
266 - name: ansible_pipelining
267 - name: ansible_ssh_pipelining
268 private_key_file:
269 description:
270 - Path to private key file to use for authentication.
271 type: string
272 ini:
273 - section: defaults
274 key: private_key_file
275 env:
276 - name: ANSIBLE_PRIVATE_KEY_FILE
277 vars:
278 - name: ansible_private_key_file
279 - name: ansible_ssh_private_key_file
280 cli:
281 - name: private_key_file
282 option: '--private-key'
283 private_key:
284 description:
285 - Private key contents in PEM format. Requires the C(SSH_AGENT) configuration to be enabled.
286 type: string
287 env:
288 - name: ANSIBLE_PRIVATE_KEY
289 vars:
290 - name: ansible_private_key
291 - name: ansible_ssh_private_key
292 version_added: '2.19'
293 private_key_passphrase:
294 description:
295 - Private key passphrase, dependent on O(private_key).
296 - This does NOT have any effect when used with O(private_key_file).
297 type: string
298 env:
299 - name: ANSIBLE_PRIVATE_KEY_PASSPHRASE
300 vars:
301 - name: ansible_private_key_passphrase
302 - name: ansible_ssh_private_key_passphrase
303 version_added: '2.19'
304 control_path:
305 description:
306 - This is the location to save SSH's ControlPath sockets, it uses SSH's variable substitution.
307 - Since 2.3, if null (default), ansible will generate a unique hash. Use ``%(directory)s`` to indicate where to use the control dir path setting.
308 - Before 2.3 it defaulted to ``control_path=%(directory)s/ansible-ssh-%%h-%%p-%%r``.
309 - Be aware that this setting is ignored if C(-o ControlPath) is set in ssh args.
…lines 310–413 unchanged (104 lines)
414import re
415import selectors
416import shlex
417import shutil
418import subprocess
419import sys
420import tempfile
421import time
422import typing as t
423from functools import wraps
424from multiprocessing.shared_memory import SharedMemory
425
426from ansible import constants as C
427from ansible.errors import (
428 AnsibleAuthenticationFailure,
429 AnsibleConnectionFailure,
430 AnsibleError,
431 AnsibleFileNotFound,
432)
433from ansible.module_utils.six import text_type, binary_type
434from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
435from ansible.plugins.connection import ConnectionBase, BUFSIZE
436from ansible.plugins.shell.powershell import _replace_stderr_clixml
437from ansible.utils.display import Display
438from ansible.utils.path import unfrackpath, makedirs_safe
439from ansible.utils._ssh_agent import SshAgentClient, _key_data_into_crypto_objects
440
441try:
442 from cryptography.hazmat.primitives import serialization
443except ImportError:
444 HAS_CRYPTOGRAPHY = False
445else:
446 HAS_CRYPTOGRAPHY = True
447
448
449display = Display()
450
451P = t.ParamSpec('P')
452
…lines 453–664 unchanged (212 lines)
665
666 # parser to discover 'passed options', used later on for pipelining resolution
667 self._tty_parser = argparse.ArgumentParser()
668 self._tty_parser.add_argument('-t', action='count')
669 self._tty_parser.add_argument('-o', action='append')
670
671 self._populated_agent: pathlib.Path | None = None
672
673 # The connection is created by running ssh/scp/sftp from the exec_command,
674 # put_file, and fetch_file methods, so we don't need to do any connection
675 # management here.
676
677 def _connect(self) -> Connection:
…lines 678–740 unchanged (63 lines)
741 were added. It will be displayed with a high enough verbosity.
742 .. note:: This function does its work via side-effect. The b_command list has the new arguments appended.
743 """
744 display.vvvvv(u'SSH: %s: (%s)' % (explanation, ')('.join(to_text(a) for a in b_args)), host=self.host)
745 b_command += b_args
746
747 def _populate_agent(self) -> pathlib.Path:
748 """Adds configured private key identity to the SSH agent. Returns a path to a file containing the public key."""
749 if self._populated_agent:
750 return self._populated_agent
751
752 if (auth_sock := C.config.get_config_value('SSH_AGENT')) == 'none':
753 raise AnsibleError('Cannot utilize private_key with SSH_AGENT disabled')
754
755 key_data = self.get_option('private_key')
756 passphrase = self.get_option('private_key_passphrase')
757
758 private_key, public_key, fingerprint = _key_data_into_crypto_objects(
759 to_bytes(key_data),
760 to_bytes(passphrase) if passphrase else None,
761 )
762
763 with SshAgentClient(auth_sock) as client:
764 if public_key not in client:
765 display.vvv(f'SSH: SSH_AGENT adding {fingerprint} to agent', host=self.host)
766 client.add(
767 private_key,
768 f'[added by ansible: PID={os.getpid()}, UID={os.getuid()}, EUID={os.geteuid()}, TIME={time.time()}]',
769 C.config.get_config_value('SSH_AGENT_KEY_LIFETIME'),
770 )
771 else:
772 display.vvv(f'SSH: SSH_AGENT {fingerprint} exists in agent', host=self.host)
773 # Write the public key to disk, to be provided as IdentityFile.
774 # This allows ssh to pick an explicit key in the agent to use,
775 # preventing ssh from attempting all keys in the agent.
776 pubkey_path = self._populated_agent = pathlib.Path(C.DEFAULT_LOCAL_TMP).joinpath(
777 fingerprint.replace('/', '-') + '.pub'
778 )
779 if os.path.exists(pubkey_path):
780 return pubkey_path
781
782 with tempfile.NamedTemporaryFile(dir=C.DEFAULT_LOCAL_TMP, delete=False) as f:
783 f.write(public_key.public_bytes(
784 encoding=serialization.Encoding.OpenSSH,
785 format=serialization.PublicFormat.OpenSSH
786 ))
787 # move atomically to prevent race conditions, silently succeeds if the target exists
788 os.rename(f.name, pubkey_path)
789 os.chmod(pubkey_path, mode=0o400)
790
791 return self._populated_agent
792
793 def _build_command(self, binary: str, subsystem: str, *other_args: bytes | str) -> list[bytes]:
794 """
795 Takes a executable (ssh, scp, sftp or wrapper) and optional extra arguments and returns the remote command
796 wrapped in local ssh shell commands and ready for execution.
797
…lines 798–870 unchanged (73 lines)
871 self._add_args(b_command, b_args, u"ANSIBLE_HOST_KEY_CHECKING/host_key_checking disabled")
872
873 self.port = self.get_option('port')
874 if self.port is not None:
875 b_args = (b"-o", b"Port=" + to_bytes(self.port, nonstring='simplerepr', errors='surrogate_or_strict'))
876 self._add_args(b_command, b_args, u"ANSIBLE_REMOTE_PORT/remote_port/ansible_port set")
877
878 if self.get_option('private_key'):
879 try:
880 key = self._populate_agent()
881 except Exception as e:
882 raise AnsibleAuthenticationFailure(
883 'Failed to add configured private key into ssh-agent',
884 orig_exc=e,
885 )
886 b_args = (b'-o', b'IdentitiesOnly=yes', b'-o', to_bytes(f'IdentityFile="{key}"', errors='surrogate_or_strict'))
887 self._add_args(b_command, b_args, "ANSIBLE_PRIVATE_KEY/private_key set")
888 elif key := self.get_option('private_key_file'):
889 b_args = (b"-o", b'IdentityFile="' + to_bytes(os.path.expanduser(key), errors='surrogate_or_strict') + b'"')
890 self._add_args(b_command, b_args, u"ANSIBLE_PRIVATE_KEY_FILE/private_key_file/ansible_ssh_private_key_file set")
891
892 if not conn_password:
893 self._add_args(
894 b_command, (
…lines 895–1623 unchanged (729 lines)

Before

module
comment "# Copyright (c) 2012, Michael DeHaan <michael.dehaan@gmail.c"...
comment "# Copyright 2015 Abhijit Menon-Sen <ams@2ndQuadrant.com>"
comment "# Copyright 2017 Toshio Kuratomi <tkuratomi@ansible.com>"
comment "# Copyright (c) 2017 Ansible Project"
comment "# GNU General Public License v3.0+ (see COPYING or https://w"...
future_import_statement
from "from"
__future__ "__future__"
import "import"
dotted_name
identifier "annotations"
expression_statement
assignment
identifier "DOCUMENTATION"
= "="
string
string_start "\"\"\""
string_content "\n name: ssh\n short_description: connect via SSH client"...
string_end "\"\"\""
import_statement
import "import"
aliased_import
dotted_name
identifier "collections"
. "."
identifier "abc"
as "as"
identifier "c"
import_statement
import "import"
dotted_name
identifier "argparse"
import_statement
import "import"
dotted_name
identifier "errno"
import_statement
import "import"
dotted_name
identifier "contextlib"
import_statement
import "import"
dotted_name
identifier "fcntl"
import_statement
import "import"
dotted_name
identifier "hashlib"
import_statement
import "import"
dotted_name
identifier "io"
import_statement
import "import"
dotted_name
identifier "json"
import_statement
import "import"
dotted_name
identifier "os"
import_statement
import "import"
dotted_name
identifier "pathlib"
import_statement
import "import"
dotted_name
identifier "pty"
import_statement
import "import"
dotted_name
identifier "re"
import_statement
import "import"
dotted_name
identifier "selectors"
import_statement
import "import"
dotted_name
identifier "shlex"
import_statement
import "import"
dotted_name
identifier "shutil"
import_statement
import "import"
dotted_name
identifier "subprocess"
import_statement
import "import"
dotted_name
identifier "sys"
import_statement
import "import"
dotted_name
identifier "time"
import_statement
import "import"
aliased_import
dotted_name
identifier "typing"
as "as"
identifier "t"
import_from_statement
from "from"
dotted_name
identifier "functools"
import "import"
dotted_name
identifier "wraps"
import_from_statement
from "from"
dotted_name
identifier "multiprocessing"
. "."
identifier "shared_memory"
import "import"
dotted_name
identifier "SharedMemory"
import_from_statement (+21 nodes collapsed)
import_from_statement
from "from"
dotted_name
identifier "ansible"
. "."
identifier "module_utils"
. "."
identifier "six"
import "import"
dotted_name
identifier "text_type"
, ","
dotted_name
identifier "binary_type"
import_from_statement (+21 nodes collapsed)
import_from_statement
from "from"
dotted_name
identifier "ansible"
. "."
identifier "plugins"
. "."
identifier "connection"
import "import"
dotted_name
identifier "ConnectionBase"
, ","
dotted_name
identifier "BUFSIZE"
import_from_statement
from "from"
dotted_name
identifier "ansible"
. "."
identifier "plugins"
. "."
identifier "shell"
. "."
identifier "powershell"
import "import"
dotted_name
identifier "_replace_stderr_clixml"
import_from_statement
from "from"
dotted_name
identifier "ansible"
. "."
identifier "utils"
. "."
identifier "display"
import "import"
dotted_name
identifier "Display"
import_from_statement
from "from"
dotted_name
identifier "ansible"
. "."
identifier "utils"
. "."
identifier "path"
import "import"
dotted_name
identifier "unfrackpath"
, ","
dotted_name
identifier "makedirs_safe"
expression_statement
assignment
identifier "display"
= "="
call
identifier "Display"
argument_list
( "("
) ")"
expression_statement
assignment
identifier "P"
= "="
call
attribute
identifier "t"
. "."
identifier "ParamSpec"
argument_list
( "("
string
string_start "'"
string_content "P"
string_end "'"
) ")"
comment "# error messages that indicate 255 return code is not from s"...
expression_statement (+32 nodes collapsed)
expression_statement
assignment
identifier "SSHPASS_AVAILABLE"
= "="
none "None"
expression_statement
assignment
identifier "SSH_DEBUG"
= "="
call
attribute
identifier "re"
. "."
identifier "compile"
argument_list
( "("
string
string_start "r'"
string_content "^debug\\d+: .*"
string_end "'"
) ")"
expression_statement (+22 nodes collapsed)
expression_statement
assignment
identifier "PKCS11_DEFAULT_PROMPT"
= "="
string
string_start "'"
string_content "Enter PIN for "
string_end "'"
expression_statement
assignment
identifier "SSH_ASKPASS_DEFAULT_PROMPT"
= "="
string
string_start "'"
string_content "assword"
string_end "'"
class_definition
class "class"
identifier "AnsibleControlPersistBrokenPipeError"
argument_list
( "("
identifier "AnsibleError"
) ")"
: ":"
block
expression_statement
string
string_start "\"\"\""
string_content " ControlPersist broken pipe "
string_end "\"\"\""
pass_statement
pass "pass"
function_definition (+567 nodes collapsed)
function_definition (+792 nodes collapsed)
function_definition (+148 nodes collapsed)
class_definition
class "class"
identifier "Connection"
argument_list
( "("
identifier "ConnectionBase"
) ")"
: ":"
block
expression_statement
string
string_start "\"\"\""
string_content " ssh based connections "
string_end "\"\"\""
expression_statement
assignment
identifier "transport"
= "="
string
string_start "'"
string_content "ssh"
string_end "'"
expression_statement
assignment
identifier "has_pipelining"
= "="
true "True"
function_definition
def "def"
identifier "__init__"
parameters (+26 nodes collapsed)
-> "->"
type
none "None"
: ":"
block
expression_statement (+23 nodes collapsed)
comment "# TODO: all should come from get_option(), but not might be "...
expression_statement
assignment
attribute
identifier "self"
. "."
identifier "host"
= "="
attribute
attribute
identifier "self"
. "."
identifier "_play_context"
. "."
identifier "remote_addr"
expression_statement
assignment
attribute
identifier "self"
. "."
identifier "port"
= "="
attribute
attribute
identifier "self"
. "."
identifier "_play_context"
. "."
identifier "port"
expression_statement
assignment
attribute
identifier "self"
. "."
identifier "user"
= "="
attribute
attribute
identifier "self"
. "."
identifier "_play_context"
. "."
identifier "remote_user"
expression_statement
assignment
attribute
identifier "self"
. "."
identifier "control_path"
: ":"
type
binary_operator
identifier "str"
| "|"
none "None"
= "="
none "None"
expression_statement
assignment
attribute
identifier "self"
. "."
identifier "control_path_dir"
: ":"
type
binary_operator
identifier "str"
| "|"
none "None"
= "="
none "None"
expression_statement
assignment
attribute
identifier "self"
. "."
identifier "shm"
: ":"
type
binary_operator
identifier "SharedMemory"
| "|"
none "None"
= "="
none "None"
expression_statement (+25 nodes collapsed)
comment "# Windows operates differently from a POSIX connection/shell"...
comment "# we need to set various properties to ensure SSH on Windows"...
comment "# to work"
if_statement (+67 nodes collapsed)
comment "# parser to discover 'passed options', used later on for pip"...
expression_statement
assignment
attribute
identifier "self"
. "."
identifier "_tty_parser"
= "="
call
attribute
identifier "argparse"
. "."
identifier "ArgumentParser"
argument_list
( "("
) ")"
expression_statement (+24 nodes collapsed)
expression_statement (+24 nodes collapsed)
comment "# The connection is created by running ssh/scp/sftp from the"...
comment "# put_file, and fetch_file methods, so we don't need to do a"...
comment "# management here."
function_definition
def "def"
identifier "_connect"
parameters
( "("
identifier "self"
) ")"
-> "->"
type
identifier "Connection"
: ":"
block
return_statement
return "return"
identifier "self"
decorated_definition (+183 nodes collapsed)
decorated_definition (+51 nodes collapsed)
decorated_definition (+110 nodes collapsed)
function_definition (+103 nodes collapsed)
function_definition
def "def"
identifier "_build_command"
parameters (+27 nodes collapsed)
-> "->"
type
generic_type
identifier "list"
type_parameter
[ "["
type
identifier "bytes"
] "]"
: ":"
block
expression_statement
string
string_start "\"\"\""
string_content "\n Takes a executable (ssh, scp, sftp or wrapper) and "...
string_end "\"\"\""
expression_statement
assignment
identifier "b_command"
= "="
list
[ "["
] "]"
expression_statement (+25 nodes collapsed)
expression_statement
assignment
identifier "pkcs11_provider"
= "="
call
attribute
identifier "self"
. "."
identifier "get_option"
argument_list
( "("
string
string_start "\""
string_content "pkcs11_provider"
string_end "\""
) ")"
expression_statement
assignment
identifier "password_mechanism"
= "="
call
attribute
identifier "self"
. "."
identifier "get_option"
argument_list
( "("
string
string_start "'"
string_content "password_mechanism"
string_end "'"
) ")"
comment "#"
comment "# First, the command to invoke"
comment "#"
comment "# If we want to use sshpass for password authentication, we "...
comment "# write the password to sshpass."
if_statement (+191 nodes collapsed)
expression_statement (+21 nodes collapsed)
comment "#"
comment "# Next, additional arguments based on the configuration."
comment "#"
comment "# pkcs11 mode allows the use of Smartcards or Yubikey device"...
if_statement (+74 nodes collapsed)
comment "# sftp batch mode allows us to correctly catch failed transf"...
comment "# be disabled if the client side doesn't support the option."...
comment "# sftp batch mode does not prompt for passwords so it must b"...
comment "# if not using controlpersist and using password auth"
expression_statement
assignment
identifier "b_args"
: ":"
type
subscript
attribute
identifier "t"
. "."
identifier "Iterable"
[ "["
identifier "bytes"
] "]"
if_statement (+79 nodes collapsed)
if_statement (+36 nodes collapsed)
comment "# Next, we add ssh_args"
expression_statement
assignment
identifier "ssh_args"
= "="
call
attribute
identifier "self"
. "."
identifier "get_option"
argument_list
( "("
string
string_start "'"
string_content "ssh_args"
string_end "'"
) ")"
if_statement (+56 nodes collapsed)
comment "# Now we add various arguments that have their own specific "...
if_statement (+52 nodes collapsed)
expression_statement
assignment
attribute
identifier "self"
. "."
identifier "port"
= "="
call
attribute
identifier "self"
. "."
identifier "get_option"
argument_list
( "("
string
string_start "'"
string_content "port"
string_end "'"
) ")"
if_statement (+73 nodes collapsed)
expression_statement
assignment
identifier "key" any 2:1
= "="
call
attribute
identifier "self"
. "."
identifier "get_option"
argument_list
( "("
string
string_start "'"
string_content "private_key_file"
string_end "'"
) ")"
if_statement
if "if"
identifier "key" any 2:1
: ":"
block (+67 nodes collapsed)
if_statement (+55 nodes collapsed)
expression_statement
assignment
attribute
identifier "self"
. "."
identifier "user"
= "="
call
attribute
identifier "self"
. "."
identifier "get_option"
argument_list
( "("
string
string_start "'"
string_content "remote_user"
string_end "'"
) ")"
if_statement (+55 nodes collapsed)
expression_statement
assignment
identifier "timeout"
= "="
call
attribute
identifier "self"
. "."
identifier "get_option"
argument_list
( "("
string
string_start "'"
string_content "timeout"
string_end "'"
) ")"
expression_statement (+52 nodes collapsed)
comment "# Add in any common or binary-specific arguments from the Pl"...
comment "# (i.e. inventory or task settings or overrides on the comma"...
for_statement (+103 nodes collapsed)
comment "# Check if ControlPersist is enabled and add a ControlPath i"...
comment "# already been set."
expression_statement
assignment
pattern_list
identifier "controlpersist"
, ","
identifier "controlpath"
= "="
call
attribute
identifier "self"
. "."
identifier "_persistence_controls"
argument_list
( "("
identifier "b_command"
) ")"
if_statement (+240 nodes collapsed)
comment "# Finally, we add any caller-supplied extras."
if_statement (+23 nodes collapsed)
return_statement
return "return"
identifier "b_command"
function_definition (+195 nodes collapsed)
comment "# Used by _run() to kill processes on failures"
decorated_definition (+53 nodes collapsed)
comment "# This is separate from _run() because we need to do the sam"...
comment "# and stderr."
function_definition (+467 nodes collapsed)
function_definition (+494 nodes collapsed)
decorated_definition (+2401 nodes collapsed)
decorated_definition (+93 nodes collapsed)
decorated_definition (+911 nodes collapsed)
function_definition (+89 nodes collapsed)
comment "#"
comment "# Main public methods"
comment "#"
function_definition (+360 nodes collapsed)
function_definition (+226 nodes collapsed)
function_definition (+172 nodes collapsed)
function_definition (+411 nodes collapsed)
function_definition
def "def"
identifier "close"
parameters
( "("
identifier "self"
) ")"
-> "->"
type
none "None"
: ":"
block
expression_statement
assignment
attribute
identifier "self"
. "."
identifier "_connected"
= "="
false "False"
decorated_definition (+23 nodes collapsed)
function_definition (+247 nodes collapsed)
function_definition (+56 nodes collapsed)

After

module
comment "# Copyright (c) 2012, Michael DeHaan <michael.dehaan@gmail.c"...
comment "# Copyright 2015 Abhijit Menon-Sen <ams@2ndQuadrant.com>"
comment "# Copyright 2017 Toshio Kuratomi <tkuratomi@ansible.com>"
comment "# Copyright (c) 2017 Ansible Project"
comment "# GNU General Public License v3.0+ (see COPYING or https://w"...
future_import_statement
from "from"
__future__ "__future__"
import "import"
dotted_name
identifier "annotations"
expression_statement
assignment
identifier "DOCUMENTATION"
= "="
string
string_start "\"\"\""
string_content "\n name: ssh\n short_description: connect via SSH client"...
string_end "\"\"\""
import_statement
import "import"
aliased_import
dotted_name
identifier "collections"
. "."
identifier "abc"
as "as"
identifier "c"
import_statement
import "import"
dotted_name
identifier "argparse"
import_statement
import "import"
dotted_name
identifier "errno"
import_statement
import "import"
dotted_name
identifier "contextlib"
import_statement
import "import"
dotted_name
identifier "fcntl"
import_statement
import "import"
dotted_name
identifier "hashlib"
import_statement
import "import"
dotted_name
identifier "io"
import_statement
import "import"
dotted_name
identifier "json"
import_statement
import "import"
dotted_name
identifier "os"
import_statement
import "import"
dotted_name
identifier "pathlib"
import_statement
import "import"
dotted_name
identifier "pty"
import_statement
import "import"
dotted_name
identifier "re"
import_statement
import "import"
dotted_name
identifier "selectors"
import_statement
import "import"
dotted_name
identifier "shlex"
import_statement
import "import"
dotted_name
identifier "shutil"
import_statement
import "import"
dotted_name
identifier "subprocess"
import_statement
import "import"
dotted_name
identifier "sys"
import_statement
import "import"
dotted_name
identifier "tempfile"
import_statement
import "import"
dotted_name
identifier "time"
import_statement
import "import"
aliased_import
dotted_name
identifier "typing"
as "as"
identifier "t"
import_from_statement
from "from"
dotted_name
identifier "functools"
import "import"
dotted_name
identifier "wraps"
import_from_statement
from "from"
dotted_name
identifier "multiprocessing"
. "."
identifier "shared_memory"
import "import"
dotted_name
identifier "SharedMemory"
import_from_statement
from "from"
dotted_name
identifier "ansible"
import "import"
aliased_import
dotted_name
identifier "constants"
as "as"
identifier "C"
import_from_statement (+21 nodes collapsed)
import_from_statement
from "from"
dotted_name
identifier "ansible"
. "."
identifier "module_utils"
. "."
identifier "six"
import "import"
dotted_name
identifier "text_type"
, ","
dotted_name
identifier "binary_type"
import_from_statement (+21 nodes collapsed)
import_from_statement
from "from"
dotted_name
identifier "ansible"
. "."
identifier "plugins"
. "."
identifier "connection"
import "import"
dotted_name
identifier "ConnectionBase"
, ","
dotted_name
identifier "BUFSIZE"
import_from_statement
from "from"
dotted_name
identifier "ansible"
. "."
identifier "plugins"
. "."
identifier "shell"
. "."
identifier "powershell"
import "import"
dotted_name
identifier "_replace_stderr_clixml"
import_from_statement
from "from"
dotted_name
identifier "ansible"
. "."
identifier "utils"
. "."
identifier "display"
import "import"
dotted_name
identifier "Display"
import_from_statement
from "from"
dotted_name
identifier "ansible"
. "."
identifier "utils"
. "."
identifier "path"
import "import"
dotted_name
identifier "unfrackpath"
, ","
dotted_name
identifier "makedirs_safe"
import_from_statement
from "from"
dotted_name
identifier "ansible"
. "."
identifier "utils"
. "."
identifier "_ssh_agent"
import "import"
dotted_name
identifier "SshAgentClient"
, ","
dotted_name
identifier "_key_data_into_crypto_objects"
try_statement
try "try"
: ":"
block
import_from_statement
from "from"
dotted_name
identifier "cryptography"
. "."
identifier "hazmat"
. "."
identifier "primitives"
import "import"
dotted_name
identifier "serialization"
except_clause
except "except"
identifier "ImportError"
: ":"
block
expression_statement
assignment
identifier "HAS_CRYPTOGRAPHY"
= "="
false "False"
else_clause
else "else"
: ":"
block
expression_statement
assignment
identifier "HAS_CRYPTOGRAPHY"
= "="
true "True"
expression_statement
assignment
identifier "display"
= "="
call
identifier "Display"
argument_list
( "("
) ")"
expression_statement
assignment
identifier "P"
= "="
call
attribute
identifier "t"
. "."
identifier "ParamSpec"
argument_list
( "("
string
string_start "'"
string_content "P"
string_end "'"
) ")"
comment "# error messages that indicate 255 return code is not from s"...
expression_statement (+32 nodes collapsed)
expression_statement
assignment
identifier "SSHPASS_AVAILABLE"
= "="
none "None"
expression_statement
assignment
identifier "SSH_DEBUG"
= "="
call
attribute
identifier "re"
. "."
identifier "compile"
argument_list
( "("
string
string_start "r'"
string_content "^debug\\d+: .*"
string_end "'"
) ")"
expression_statement (+22 nodes collapsed)
expression_statement
assignment
identifier "PKCS11_DEFAULT_PROMPT"
= "="
string
string_start "'"
string_content "Enter PIN for "
string_end "'"
expression_statement
assignment
identifier "SSH_ASKPASS_DEFAULT_PROMPT"
= "="
string
string_start "'"
string_content "assword"
string_end "'"
class_definition
class "class"
identifier "AnsibleControlPersistBrokenPipeError"
argument_list
( "("
identifier "AnsibleError"
) ")"
: ":"
block
expression_statement
string
string_start "\"\"\""
string_content " ControlPersist broken pipe "
string_end "\"\"\""
pass_statement
pass "pass"
function_definition (+567 nodes collapsed)
function_definition (+792 nodes collapsed)
function_definition (+148 nodes collapsed)
class_definition
class "class"
identifier "Connection"
argument_list
( "("
identifier "ConnectionBase"
) ")"
: ":"
block
expression_statement
string
string_start "\"\"\""
string_content " ssh based connections "
string_end "\"\"\""
expression_statement
assignment
identifier "transport"
= "="
string
string_start "'"
string_content "ssh"
string_end "'"
expression_statement
assignment
identifier "has_pipelining"
= "="
true "True"
function_definition
def "def"
identifier "__init__"
parameters (+26 nodes collapsed)
-> "->"
type
none "None"
: ":"
block
expression_statement (+23 nodes collapsed)
comment "# TODO: all should come from get_option(), but not might be "...
expression_statement
assignment
attribute
identifier "self"
. "."
identifier "host"
= "="
attribute
attribute
identifier "self"
. "."
identifier "_play_context"
. "."
identifier "remote_addr"
expression_statement
assignment
attribute
identifier "self"
. "."
identifier "port"
= "="
attribute
attribute
identifier "self"
. "."
identifier "_play_context"
. "."
identifier "port"
expression_statement
assignment
attribute
identifier "self"
. "."
identifier "user"
= "="
attribute
attribute
identifier "self"
. "."
identifier "_play_context"
. "."
identifier "remote_user"
expression_statement
assignment
attribute
identifier "self"
. "."
identifier "control_path"
: ":"
type
binary_operator
identifier "str"
| "|"
none "None"
= "="
none "None"
expression_statement
assignment
attribute
identifier "self"
. "."
identifier "control_path_dir"
: ":"
type
binary_operator
identifier "str"
| "|"
none "None"
= "="
none "None"
expression_statement
assignment
attribute
identifier "self"
. "."
identifier "shm"
: ":"
type
binary_operator
identifier "SharedMemory"
| "|"
none "None"
= "="
none "None"
expression_statement (+25 nodes collapsed)
comment "# Windows operates differently from a POSIX connection/shell"...
comment "# we need to set various properties to ensure SSH on Windows"...
comment "# to work"
if_statement (+67 nodes collapsed)
comment "# parser to discover 'passed options', used later on for pip"...
expression_statement
assignment
attribute
identifier "self"
. "."
identifier "_tty_parser"
= "="
call
attribute
identifier "argparse"
. "."
identifier "ArgumentParser"
argument_list
( "("
) ")"
expression_statement (+24 nodes collapsed)
expression_statement (+24 nodes collapsed)
expression_statement
assignment
attribute
identifier "self"
. "."
identifier "_populated_agent"
: ":"
type
binary_operator
attribute
identifier "pathlib"
. "."
identifier "Path"
| "|"
none "None"
= "="
none "None"
comment "# The connection is created by running ssh/scp/sftp from the"...
comment "# put_file, and fetch_file methods, so we don't need to do a"...
comment "# management here."
function_definition
def "def"
identifier "_connect"
parameters
( "("
identifier "self"
) ")"
-> "->"
type
identifier "Connection"
: ":"
block
return_statement
return "return"
identifier "self"
decorated_definition (+183 nodes collapsed)
decorated_definition (+51 nodes collapsed)
decorated_definition (+110 nodes collapsed)
function_definition (+103 nodes collapsed)
function_definition
def "def"
identifier "_populate_agent"
parameters
( "("
identifier "self"
) ")"
-> "->"
type
attribute
identifier "pathlib"
. "."
identifier "Path"
: ":"
block
expression_statement
string
string_start "\"\"\""
string_content "Adds configured private key identity to the SSH agent. Retur"...
string_end "\"\"\""
if_statement
if "if"
attribute
identifier "self"
. "."
identifier "_populated_agent"
: ":"
block
return_statement
return "return"
attribute
identifier "self"
. "."
identifier "_populated_agent"
if_statement
if "if"
comparison_operator
parenthesized_expression
( "("
named_expression
identifier "auth_sock"
:= ":="
call
attribute
attribute
identifier "C"
. "."
identifier "config"
. "."
identifier "get_config_value"
argument_list
( "("
string
string_start "'"
string_content "SSH_AGENT"
string_end "'"
) ")"
) ")"
== "=="
string
string_start "'"
string_content "none"
string_end "'"
: ":"
block
raise_statement
raise "raise"
call
identifier "AnsibleError"
argument_list
( "("
string
string_start "'"
string_content "Cannot utilize private_key with SSH_AGENT disabled"
string_end "'"
) ")"
expression_statement
assignment
identifier "key_data"
= "="
call
attribute
identifier "self"
. "."
identifier "get_option"
argument_list
( "("
string
string_start "'"
string_content "private_key"
string_end "'"
) ")"
expression_statement
assignment
identifier "passphrase"
= "="
call
attribute
identifier "self"
. "."
identifier "get_option"
argument_list
( "("
string
string_start "'"
string_content "private_key_passphrase"
string_end "'"
) ")"
expression_statement
assignment
pattern_list
identifier "private_key"
, ","
identifier "public_key"
, ","
identifier "fingerprint"
= "="
call
identifier "_key_data_into_crypto_objects"
argument_list
( "("
call
identifier "to_bytes"
argument_list
( "("
identifier "key_data"
) ")"
, ","
conditional_expression
call
identifier "to_bytes"
argument_list
( "("
identifier "passphrase"
) ")"
if "if"
identifier "passphrase"
else "else"
none "None"
, ","
) ")"
with_statement
with "with"
with_clause
with_item
as_pattern
call
identifier "SshAgentClient"
argument_list
( "("
identifier "auth_sock"
) ")"
as "as"
as_pattern_target
identifier "client"
: ":"
block
if_statement
if "if"
comparison_operator
identifier "public_key"
not in
not "not"
in "in"
identifier "client"
: ":"
block
expression_statement
call
attribute
identifier "display"
. "."
identifier "vvv"
argument_list
( "("
string
string_start "f'"
string_content "SSH: SSH_AGENT adding "
interpolation
{ "{"
identifier "fingerprint"
} "}"
string_content " to agent"
string_end "'"
, ","
keyword_argument
identifier "host"
= "="
attribute
identifier "self"
. "."
identifier "host"
) ")"
expression_statement
call
attribute
identifier "client"
. "."
identifier "add"
argument_list
( "("
identifier "private_key"
, ","
string
string_start "f'"
string_content "[added by ansible: PID="
interpolation
{ "{"
call
attribute
identifier "os"
. "."
identifier "getpid"
argument_list
( "("
) ")"
} "}"
string_content ", UID="
interpolation
{ "{"
call
attribute
identifier "os"
. "."
identifier "getuid"
argument_list
( "("
) ")"
} "}"
string_content ", EUID="
interpolation
{ "{"
call
attribute
identifier "os"
. "."
identifier "geteuid"
argument_list
( "("
) ")"
} "}"
string_content ", TIME="
interpolation
{ "{"
call
attribute
identifier "time"
. "."
identifier "time"
argument_list
( "("
) ")"
} "}"
string_content "]"
string_end "'"
, ","
call
attribute
attribute
identifier "C"
. "."
identifier "config"
. "."
identifier "get_config_value"
argument_list
( "("
string
string_start "'"
string_content "SSH_AGENT_KEY_LIFETIME"
string_end "'"
) ")"
, ","
) ")"
else_clause
else "else"
: ":"
block
expression_statement
call
attribute
identifier "display"
. "."
identifier "vvv"
argument_list
( "("
string
string_start "f'"
string_content "SSH: SSH_AGENT "
interpolation
{ "{"
identifier "fingerprint"
} "}"
string_content " exists in agent"
string_end "'"
, ","
keyword_argument
identifier "host"
= "="
attribute
identifier "self"
. "."
identifier "host"
) ")"
comment "# Write the public key to disk, to be provided as IdentityFi"...
comment "# This allows ssh to pick an explicit key in the agent to us"...
comment "# preventing ssh from attempting all keys in the agent."
expression_statement
assignment
identifier "pubkey_path"
= "="
assignment
attribute
identifier "self"
. "."
identifier "_populated_agent"
= "="
call
attribute
call
attribute
identifier "pathlib"
. "."
identifier "Path"
argument_list
( "("
attribute
identifier "C"
. "."
identifier "DEFAULT_LOCAL_TMP"
) ")"
. "."
identifier "joinpath"
argument_list
( "("
binary_operator
call
attribute
identifier "fingerprint"
. "."
identifier "replace"
argument_list
( "("
string
string_start "'"
string_content "/"
string_end "'"
, ","
string
string_start "'"
string_content "-"
string_end "'"
) ")"
+ "+"
string
string_start "'"
string_content ".pub"
string_end "'"
) ")"
if_statement
if "if"
call
attribute
attribute
identifier "os"
. "."
identifier "path"
. "."
identifier "exists"
argument_list
( "("
identifier "pubkey_path"
) ")"
: ":"
block
return_statement
return "return"
identifier "pubkey_path"
with_statement
with "with"
with_clause
with_item
as_pattern
call
attribute
identifier "tempfile"
. "."
identifier "NamedTemporaryFile"
argument_list
( "("
keyword_argument
identifier "dir"
= "="
attribute
identifier "C"
. "."
identifier "DEFAULT_LOCAL_TMP"
, ","
keyword_argument
identifier "delete"
= "="
false "False"
) ")"
as "as"
as_pattern_target
identifier "f"
: ":"
block
expression_statement
call
attribute
identifier "f"
. "."
identifier "write"
argument_list
( "("
call
attribute
identifier "public_key"
. "."
identifier "public_bytes"
argument_list
( "("
keyword_argument
identifier "encoding"
= "="
attribute
attribute
identifier "serialization"
. "."
identifier "Encoding"
. "."
identifier "OpenSSH"
, ","
keyword_argument
identifier "format"
= "="
attribute
attribute
identifier "serialization"
. "."
identifier "PublicFormat"
. "."
identifier "OpenSSH"
) ")"
) ")"
comment "# move atomically to prevent race conditions, silently succe"...
expression_statement
call
attribute
identifier "os"
. "."
identifier "rename"
argument_list
( "("
attribute
identifier "f"
. "."
identifier "name"
, ","
identifier "pubkey_path"
) ")"
expression_statement
call
attribute
identifier "os"
. "."
identifier "chmod"
argument_list
( "("
identifier "pubkey_path"
, ","
keyword_argument
identifier "mode"
= "="
integer "0o400"
) ")"
return_statement
return "return"
attribute
identifier "self"
. "."
identifier "_populated_agent"
function_definition
def "def"
identifier "_build_command"
parameters (+27 nodes collapsed)
-> "->"
type
generic_type
identifier "list"
type_parameter
[ "["
type
identifier "bytes"
] "]"
: ":"
block
expression_statement
string
string_start "\"\"\""
string_content "\n Takes a executable (ssh, scp, sftp or wrapper) and "...
string_end "\"\"\""
expression_statement
assignment
identifier "b_command"
= "="
list
[ "["
] "]"
expression_statement (+25 nodes collapsed)
expression_statement
assignment
identifier "pkcs11_provider"
= "="
call
attribute
identifier "self"
. "."
identifier "get_option"
argument_list
( "("
string
string_start "\""
string_content "pkcs11_provider"
string_end "\""
) ")"
expression_statement
assignment
identifier "password_mechanism"
= "="
call
attribute
identifier "self"
. "."
identifier "get_option"
argument_list
( "("
string
string_start "'"
string_content "password_mechanism"
string_end "'"
) ")"
comment "#"
comment "# First, the command to invoke"
comment "#"
comment "# If we want to use sshpass for password authentication, we "...
comment "# write the password to sshpass."
if_statement (+191 nodes collapsed)
expression_statement (+21 nodes collapsed)
comment "#"
comment "# Next, additional arguments based on the configuration."
comment "#"
comment "# pkcs11 mode allows the use of Smartcards or Yubikey device"...
if_statement (+74 nodes collapsed)
comment "# sftp batch mode allows us to correctly catch failed transf"...
comment "# be disabled if the client side doesn't support the option."...
comment "# sftp batch mode does not prompt for passwords so it must b"...
comment "# if not using controlpersist and using password auth"
expression_statement
assignment
identifier "b_args"
: ":"
type
subscript
attribute
identifier "t"
. "."
identifier "Iterable"
[ "["
identifier "bytes"
] "]"
if_statement (+79 nodes collapsed)
if_statement (+36 nodes collapsed)
comment "# Next, we add ssh_args"
expression_statement
assignment
identifier "ssh_args"
= "="
call
attribute
identifier "self"
. "."
identifier "get_option"
argument_list
( "("
string
string_start "'"
string_content "ssh_args"
string_end "'"
) ")"
if_statement (+56 nodes collapsed)
comment "# Now we add various arguments that have their own specific "...
if_statement (+52 nodes collapsed)
expression_statement
assignment
attribute
identifier "self"
. "."
identifier "port"
= "="
call
attribute
identifier "self"
. "."
identifier "get_option"
argument_list
( "("
string
string_start "'"
string_content "port"
string_end "'"
) ")"
if_statement (+73 nodes collapsed)
if_statement
if "if"
call
attribute
identifier "self"
. "."
identifier "get_option"
argument_list
( "("
string
string_start "'"
string_content "private_key"
string_end "'"
) ")"
: ":"
block
try_statement
try "try"
: ":"
block
expression_statement
assignment
identifier "key"
= "="
call
attribute
identifier "self"
. "."
identifier "_populate_agent"
argument_list
( "("
) ")"
except_clause
except "except"
as_pattern
identifier "Exception"
as "as"
as_pattern_target
identifier "e"
: ":"
block
raise_statement
raise "raise"
call
identifier "AnsibleAuthenticationFailure"
argument_list
( "("
string
string_start "'"
string_content "Failed to add configured private key into ssh-agent"
string_end "'"
, ","
keyword_argument
identifier "orig_exc"
= "="
identifier "e"
, ","
) ")"
expression_statement
assignment
identifier "b_args"
= "="
tuple
( "("
string
string_start "b'"
string_content "-o"
string_end "'"
, ","
string
string_start "b'"
string_content "IdentitiesOnly=yes"
string_end "'"
, ","
string
string_start "b'"
string_content "-o"
string_end "'"
, ","
call
identifier "to_bytes"
argument_list
( "("
string
string_start "f'"
string_content "IdentityFile=\""
interpolation
{ "{"
identifier "key"
} "}"
string_content "\""
string_end "'"
, ","
keyword_argument
identifier "errors"
= "="
string
string_start "'"
string_content "surrogate_or_strict"
string_end "'"
) ")"
) ")"
expression_statement
call
attribute
identifier "self"
. "."
identifier "_add_args"
argument_list
( "("
identifier "b_command"
, ","
identifier "b_args"
, ","
string
string_start "\""
string_content "ANSIBLE_PRIVATE_KEY/private_key set"
string_end "\""
) ")"
elif_clause
elif "elif"
named_expression
identifier "key" any 2:1
:= ":="
call
attribute
identifier "self"
. "."
identifier "get_option"
argument_list
( "("
string
string_start "'"
string_content "private_key_file"
string_end "'"
) ")"
: ":"
block (+67 nodes collapsed)
if_statement (+55 nodes collapsed)
expression_statement
assignment
attribute
identifier "self"
. "."
identifier "user"
= "="
call
attribute
identifier "self"
. "."
identifier "get_option"
argument_list
( "("
string
string_start "'"
string_content "remote_user"
string_end "'"
) ")"
if_statement (+55 nodes collapsed)
expression_statement
assignment
identifier "timeout"
= "="
call
attribute
identifier "self"
. "."
identifier "get_option"
argument_list
( "("
string
string_start "'"
string_content "timeout"
string_end "'"
) ")"
expression_statement (+52 nodes collapsed)
comment "# Add in any common or binary-specific arguments from the Pl"...
comment "# (i.e. inventory or task settings or overrides on the comma"...
for_statement (+103 nodes collapsed)
comment "# Check if ControlPersist is enabled and add a ControlPath i"...
comment "# already been set."
expression_statement
assignment
pattern_list
identifier "controlpersist"
, ","
identifier "controlpath"
= "="
call
attribute
identifier "self"
. "."
identifier "_persistence_controls"
argument_list
( "("
identifier "b_command"
) ")"
if_statement (+240 nodes collapsed)
comment "# Finally, we add any caller-supplied extras."
if_statement (+23 nodes collapsed)
return_statement
return "return"
identifier "b_command"
function_definition (+195 nodes collapsed)
comment "# Used by _run() to kill processes on failures"
decorated_definition (+53 nodes collapsed)
comment "# This is separate from _run() because we need to do the sam"...
comment "# and stderr."
function_definition (+467 nodes collapsed)
function_definition (+494 nodes collapsed)
decorated_definition (+2401 nodes collapsed)
decorated_definition (+93 nodes collapsed)
decorated_definition (+911 nodes collapsed)
function_definition (+89 nodes collapsed)
comment "#"
comment "# Main public methods"
comment "#"
function_definition (+360 nodes collapsed)
function_definition (+226 nodes collapsed)
function_definition (+172 nodes collapsed)
function_definition (+411 nodes collapsed)
function_definition
def "def"
identifier "close"
parameters
( "("
identifier "self"
) ")"
-> "->"
type
none "None"
: ":"
block
expression_statement
assignment
attribute
identifier "self"
. "."
identifier "_connected"
= "="
false "False"
decorated_definition (+23 nodes collapsed)
function_definition (+247 nodes collapsed)
function_definition (+56 nodes collapsed)