The first parameter (*argcount*) now represents the total number of positional arguments,
including positional-only.
- .. audit-event:: code.__new__ "code filename name argcount posonlyargcount kwonlyargcount nlocals stacksize flags"
+ .. audit-event:: code.__new__ code,filename,name,argcount,posonlyargcount,kwonlyargcount,nlocals,stacksize,flags c.PyCode_New
.. c:function:: PyCodeObject* PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
.. c:function:: int PySys_Audit(const char *event, const char *format, ...)
- .. index:: single: audit events
-
Raises an auditing event with any active hooks. Returns zero for success
and non-zero with an exception set on failure.
.. c:function:: int PySys_AddAuditHook(Py_AuditHookFunction hook, void *userData)
- .. index:: single: audit events
-
Adds to the collection of active auditing hooks. Returns zero for success
and non-zero on failure. If the runtime has been initialized, also sets an
error on failure. Hooks added through this API are called for all
to add initial items to the array. Otherwise, the iterable initializer is
passed to the :meth:`extend` method.
- .. audit-event:: array.__new__ "typecode initializer"
+ .. audit-event:: array.__new__ typecode,initializer array.array
.. data:: typecodes
--- /dev/null
+.. _audit-events:
+
+.. index:: single: audit events
+
+Audit events table
+==================
+
+This table contains all events raised by :func:`sys.audit` or
+:c:func:`PySys_Audit` calls throughout the CPython runtime and the
+standard library.
+
+See :func:`sys.addaudithook` and :c:func:`PySys_AddAuditHook` for
+information on handling these events.
+
+.. impl-detail::
+
+ This table is generated from the CPython documentation, and may not
+ represent events raised by other implementations. See your runtime
+ specific documentation for actual events raised.
+
+.. audit-event-table::
:c:type:`int`, which is of course not always the truth, so you have to assign
the correct :attr:`restype` attribute to use these functions.
-.. audit-event:: ctypes.dlopen name
+.. audit-event:: ctypes.dlopen name ctypes.LibraryLoader
Loading a library through any of these objects raises an
:ref:`auditing event <auditing>` ``ctypes.dlopen`` with string argument
``name``, the name used to load the library.
-.. audit-event:: ctypes.dlsym "library name"
+.. audit-event:: ctypes.dlsym library,name ctypes.LibraryLoader
Accessing a function on a loaded library raises an auditing event
``ctypes.dlsym`` with arguments ``library`` (the library object) and ``name``
This method returns a ctypes type instance using the memory specified by
*address* which must be an integer.
- .. audit-event:: ctypes.cdata address
+ .. audit-event:: ctypes.cdata address ctypes._CData.from_address
This method, and others that indirectly call this method, raises an
:ref:`auditing event <auditing>` ``ctypes.cdata`` with argument
These libraries help you with Python development: the debugger enables you to
step through code, analyze stack frames and set breakpoints etc., and the
profilers run code and give you a detailed breakdown of execution times,
-allowing you to identify bottlenecks in your programs.
+allowing you to identify bottlenecks in your programs. Auditing events
+provide visibility into runtime behaviors that would otherwise require
+intrusive debugging or patching.
.. toctree::
+ audit_events.rst
bdb.rst
faulthandler.rst
pdb.rst
*verbosity* controls the level of output to :data:`sys.stdout` from the
bootstrapping operation.
- .. audit-event:: ensurepip.bootstrap root
+ .. audit-event:: ensurepip.bootstrap root ensurepip.bootstrap
.. note::
*source_address* is a 2-tuple ``(host, port)`` for the socket to bind to as
its source address before connecting.
- .. audit-event:: ftplib.FTP.connect "self host port"
+ .. audit-event:: ftplib.connect self,host,port ftplib.FTP.connect
.. versionchanged:: 3.3
*source_address* parameter was added.
Send a simple command string to the server and return the response string.
- .. audit-event:: ftplib.FTP.sendcmd "self cmd"
+ .. audit-event:: ftplib.sendcmd self,cmd ftplib.FTP.sendcmd
.. method:: FTP.voidcmd(cmd)
nothing if a response code corresponding to success (codes in the range
200--299) is received. Raise :exc:`error_reply` otherwise.
- .. audit-event:: ftplib.FTP.sendcmd "self cmd"
+ .. audit-event:: ftplib.sendcmd self,cmd ftplib.FTP.voidcmd
.. method:: FTP.retrbinary(cmd, callback, blocksize=8192, rest=None)
:func:`breakpoint` will automatically call that, allowing you to drop into
the debugger of choice.
- .. audit-event:: builtins.breakpoint "sys.breakpointhook"
+ .. audit-event:: builtins.breakpoint breakpointhook breakpoint
.. versionadded:: 3.7
If you want to parse Python code into its AST representation, see
:func:`ast.parse`.
- .. audit-event:: compile "source filename"
+ .. audit-event:: compile source,filename compile
Raises an :ref:`auditing event <auditing>` ``compile`` with arguments
``source`` and ``filename``. This event may also be raised by implicit
See :func:`ast.literal_eval` for a function that can safely evaluate strings
with expressions containing only literals.
- .. audit-event:: exec code_object
+ .. audit-event:: exec code_object eval
Raises an :ref:`auditing event <auditing>` ``exec`` with the code object
as the argument. Code compilation events may also be raised.
builtins are available to the executed code by inserting your own
``__builtins__`` dictionary into *globals* before passing it to :func:`exec`.
- .. audit-event:: exec code_object
+ .. audit-event:: exec code_object exec
Raises an :ref:`auditing event <auditing>` ``exec`` with the code object
as the argument. Code compilation events may also be raised.
If the :mod:`readline` module was loaded, then :func:`input` will use it
to provide elaborate line editing and history features.
- .. audit-event:: builtins.input prompt
+ .. audit-event:: builtins.input prompt input
Raises an :ref:`auditing event <auditing>` ``builtins.input`` with
argument ``prompt`` before reading input
- .. audit-event:: builtins.input/result result
+ .. audit-event:: builtins.input/result result input
Raises an auditing event ``builtins.input/result`` with the result after
successfully reading input.
(where :func:`open` is declared), :mod:`os`, :mod:`os.path`, :mod:`tempfile`,
and :mod:`shutil`.
- .. audit-event:: open "file mode flags"
+ .. audit-event:: open file,mode,flags open
The ``mode`` and ``flags`` arguments may have been modified or inferred from
the original call.
more directories and subdirectories. If the pattern is followed by an
``os.sep``, only directories and subdirectories match.
- .. audit-event:: glob.glob "pathname recursive"
+ .. audit-event:: glob.glob pathname,recursive glob.glob
.. note::
Using the "``**``" pattern in large directory trees may consume
Return an :term:`iterator` which yields the same values as :func:`glob`
without actually storing them all simultaneously.
- .. audit-event:: glob.glob "pathname recursive"
+ .. audit-event:: glob.glob pathname,recursive glob.iglob
.. function:: escape(pathname)
:meth:`IMAP4.send`, and :meth:`IMAP4.shutdown` methods. You may override
this method.
- .. audit-event:: imaplib.IMAP4.open "self host port"
+ .. audit-event:: imaplib.open self,host,port imaplib.IMAP4.open
.. method:: IMAP4.partial(message_num, message_part, start, length)
Sends ``data`` to the remote server. You may override this method.
- .. audit-event:: imaplib.IMAP4.send "self data"
+ .. audit-event:: imaplib.send self,data imaplib.IMAP4.send
.. method:: IMAP4.setacl(mailbox, who, what)
This is an alias for the builtin :func:`open` function.
- .. audit-event:: open "path mode flags"
+ .. audit-event:: open path,mode,flags io.open
This function raises an :ref:`auditing event <auditing>` ``open`` with
arguments ``path``, ``mode`` and ``flags``. The ``mode`` and ``flags``
will be relative to the offset from the beginning of the file. *offset*
defaults to 0. *offset* must be a multiple of the :const:`ALLOCATIONGRANULARITY`.
- .. audit-event:: mmap.__new__ "fileno length access offset"
+ .. audit-event:: mmap.__new__ fileno,length,access,offset mmap.mmap
.. class:: mmap(fileno, length, flags=MAP_SHARED, prot=PROT_WRITE|PROT_READ, access=ACCESS_DEFAULT[, offset])
:noindex:
mm.close()
- .. audit-event:: mmap.__new__ "fileno length access offset"
+ .. audit-event:: mmap.__new__ fileno,length,access,offset mmap.mmap
Memory-mapped file objects support the following methods:
('211 1755 1 1755 gmane.comp.python.committers', 1755, 1, 1755, 'gmane.comp.python.committers')
>>>
- .. audit-event:: nntplib.NNTP "self host port"
+ .. audit-event:: nntplib.connect self,host,port nntplib.NNTP
- All commands will raise an :ref:`auditing event <auditing>`
- ``nntplib.NNTP.putline`` with arguments ``self`` and ``line``,
- where ``line`` is the bytes about to be sent to the remote host.
+ .. audit-event:: nntplib.putline self,line nntplib.NNTP
+
+ All commands will raise an :ref:`auditing event <auditing>`
+ ``nntplib.putline`` with arguments ``self`` and ``line``,
+ where ``line`` is the bytes about to be sent to the remote host.
.. versionchanged:: 3.2
*usenetrc* is now ``False`` by default.
STARTTLS as described below. However, some servers only support the
former.
- .. audit-event:: nntplib.NNTP "self host port"
+ .. audit-event:: nntplib.connect self,host,port nntplib.NNTP_SSL
+
+ .. audit-event:: nntplib.putline self,line nntplib.NNTP_SSL
- All commands will raise an :ref:`auditing event <auditing>`
- ``nntplib.NNTP.putline`` with arguments ``self`` and ``line``,
- where ``line`` is the bytes about to be sent to the remote host.
+ All commands will raise an :ref:`auditing event <auditing>`
+ ``nntplib.putline`` with arguments ``self`` and ``line``,
+ where ``line`` is the bytes about to be sent to the remote host.
.. versionadded:: 3.2
most *length* bytes in size. As of Python 3.3, this is equivalent to
``os.truncate(fd, length)``.
- .. audit-event:: os.truncate "fd length"
+ .. audit-event:: os.truncate fd,length os.ftruncate
.. availability:: Unix, Windows.
This function can support :ref:`paths relative to directory descriptors
<dir_fd>` with the *dir_fd* parameter.
- .. audit-event:: open "path mode flags"
+ .. audit-event:: open path,mode,flags os.open
.. versionchanged:: 3.4
The new file descriptor is now non-inheritable.
This function can also support :ref:`specifying a file descriptor
<path_fd>`; the file descriptor must refer to a directory.
- .. audit-event:: os.listdir path
+ .. audit-event:: os.listdir path os.listdir
.. note::
To encode ``str`` filenames to ``bytes``, use :func:`~os.fsencode`.
This function can also support :ref:`specifying a file descriptor
<path_fd>`; the file descriptor must refer to a directory.
- .. audit-event:: os.scandir path
+ .. audit-event:: os.scandir path os.scandir
The :func:`scandir` iterator supports the :term:`context manager` protocol
and has the following method:
This function can support :ref:`specifying a file descriptor <path_fd>`.
- .. audit-event:: os.truncate "path length"
+ .. audit-event:: os.truncate path,length os.truncate
.. availability:: Unix, Windows.
to using this function. See the :ref:`subprocess-replacements` section in
the :mod:`subprocess` documentation for some helpful recipes.
- .. audit-event:: os.system command
+ .. audit-event:: os.system command os.system
.. availability:: Unix, Windows.
import pdb; pdb.Pdb(skip=['django.*']).set_trace()
- .. audit-event:: pdb.Pdb
+ .. audit-event:: pdb.Pdb "" pdb.Pdb
.. versionadded:: 3.1
The *skip* argument.
how they can be loaded, potentially reducing security risks. Refer to
:ref:`pickle-restrict` for details.
- .. audit-event:: pickle.find_class "module name"
+ .. audit-event:: pickle.find_class module,name pickle.Unpickler.find_class
.. class:: PickleBuffer(buffer)
connection attempt (if not specified, the global default timeout setting will
be used).
- .. audit-event:: poplib.POP3 "self host port"
+ .. audit-event:: poplib.connect self,host,port poplib.POP3
- All commands will raise an :ref:`auditing event <auditing>`
- ``poplib.POP3.putline`` with arguments ``self`` and ``line``,
- where ``line`` is the bytes about to be sent to the remote host.
+ .. audit-event:: poplib.putline self,line poplib.POP3
+
+ All commands will raise an :ref:`auditing event <auditing>`
+ ``poplib.putline`` with arguments ``self`` and ``line``,
+ where ``line`` is the bytes about to be sent to the remote host.
.. class:: POP3_SSL(host, port=POP3_SSL_PORT, keyfile=None, certfile=None, timeout=None, context=None)
point to PEM-formatted private key and certificate chain files,
respectively, for the SSL connection.
- .. audit-event:: poplib.POP3 "self host port"
+ .. audit-event:: poplib.connect self,host,port poplib.POP3_SSL
+
+ .. audit-event:: poplib.putline self,line popplib.POP3_SSL
- All commands will raise an :ref:`auditing event <auditing>`
- ``poplib.POP3.putline`` with arguments ``self`` and ``line``,
- where ``line`` is the bytes about to be sent to the remote host.
+ All commands will raise an :ref:`auditing event <auditing>`
+ ``poplib.putline`` with arguments ``self`` and ``line``,
+ where ``line`` is the bytes about to be sent to the remote host.
.. versionchanged:: 3.2
*context* parameter added.
 as arguments. By default, :func:`~shutil.copy2` is used, but any function
 that supports the same signature (like :func:`~shutil.copy`) can be used.
- .. audit-event:: shutil.copytree "src dst"
+ .. audit-event:: shutil.copytree src,dst shutil.copytree
.. versionchanged:: 3.3
Copy metadata when *symlinks* is false.
*excinfo*, will be the exception information returned by
:func:`sys.exc_info`. Exceptions raised by *onerror* will not be caught.
- .. audit-event:: shutil.rmtree path
+ .. audit-event:: shutil.rmtree path shutil.rmtree
.. versionchanged:: 3.3
Added a symlink attack resistant version that is used automatically
The *verbose* argument is unused and deprecated.
- .. audit-event:: shutil.make_archive "base_name format root_dir base_dir"
+ .. audit-event:: shutil.make_archive base_name,format,root_dir,base_dir shutil.make_archive
.. versionchanged:: 3.8
The modern pax (POSIX.1-2001) format is now used instead of
(250, b'Ok')
>>>
- All commands will raise an :ref:`auditing event <auditing>`
- ``smtplib.SMTP.send`` with arguments ``self`` and ``data``,
- where ``data`` is the bytes about to be sent to the remote host.
+ .. audit-event:: smtplib.send self,data smtplib.SMTP
+
+ All commands will raise an :ref:`auditing event <auditing>`
+ ``smtplib.SMTP.send`` with arguments ``self`` and ``data``,
+ where ``data`` is the bytes about to be sent to the remote host.
.. versionchanged:: 3.3
Support for the :keyword:`with` statement was added.
2-tuple of the response code and message sent by the server in its
connection response.
- .. audit-event:: smtplib.SMTP.connect "self host port"
+ .. audit-event:: smtplib.connect self,host,port smtplib.SMTP.connect
.. method:: SMTP.helo(name='')
The newly created socket is :ref:`non-inheritable <fd_inheritance>`.
- .. audit-event:: socket.__new__ "self family type protocol"
+ .. audit-event:: socket.__new__ self,family,type,protocol socket.socket
.. versionchanged:: 3.3
The AF_CAN family was added.
:const:`AF_INET6`), and is meant to be passed to the :meth:`socket.connect`
method.
- .. audit-event:: socket.getaddrinfo "host port family type protocol"
+ .. audit-event:: socket.getaddrinfo host,port,family,type,protocol socket.getaddrinfo
The following example fetches address information for a hypothetical TCP
connection to ``example.org`` on port 80 (results may differ on your
interface. :func:`gethostbyname` does not support IPv6 name resolution, and
:func:`getaddrinfo` should be used instead for IPv4/v6 dual stack support.
- .. audit-event:: socket.gethostbyname hostname
+ .. audit-event:: socket.gethostbyname hostname socket.gethostbyname
.. function:: gethostbyname_ex(hostname)
resolution, and :func:`getaddrinfo` should be used instead for IPv4/v6 dual
stack support.
- .. audit-event:: socket.gethostbyname hostname
+ .. audit-event:: socket.gethostbyname hostname socket.gethostbyname_ex
.. function:: gethostname()
Return a string containing the hostname of the machine where the Python
interpreter is currently executing.
- .. audit-event:: socket.gethostname
+ .. audit-event:: socket.gethostname "" socket.gethostname
Note: :func:`gethostname` doesn't always return the fully qualified domain
name; use :func:`getfqdn` for that.
domain name, use the function :func:`getfqdn`. :func:`gethostbyaddr` supports
both IPv4 and IPv6.
- .. audit-event:: socket.gethostbyaddr ip_address
+ .. audit-event:: socket.gethostbyaddr ip_address socket.gethostbyaddr
.. function:: getnameinfo(sockaddr, flags)
For more information about *flags* you can consult :manpage:`getnameinfo(3)`.
- .. audit-event:: socket.getnameinfo sockaddr
+ .. audit-event:: socket.getnameinfo sockaddr socket.getnameinfo
.. function:: getprotobyname(protocolname)
service. The optional protocol name, if given, should be ``'tcp'`` or
``'udp'``, otherwise any protocol will match.
- .. audit-event:: socket.getservbyname "servicename protocolname"
+ .. audit-event:: socket.getservbyname servicename,protocolname socket.getservbyname
.. function:: getservbyport(port[, protocolname])
service. The optional protocol name, if given, should be ``'tcp'`` or
``'udp'``, otherwise any protocol will match.
- .. audit-event:: socket.getservbyport "port protocolname"
+ .. audit-event:: socket.getservbyport port,protocolname socket.getservbyport
.. function:: ntohl(x)
Set the machine's hostname to *name*. This will raise an
:exc:`OSError` if you don't have enough rights.
- .. audit-event:: socket.sethostname name
+ .. audit-event:: socket.sethostname name socket.sethostname
.. availability:: Unix.
Bind the socket to *address*. The socket must not already be bound. (The format
of *address* depends on the address family --- see above.)
- .. audit-event:: socket.bind "self address"
+ .. audit-event:: socket.bind self,address socket.socket.bind
.. method:: socket.close()
:exc:`InterruptedError` exception if the connection is interrupted by a
signal (or the exception raised by the signal handler).
- .. audit-event:: socket.connect "self address"
+ .. audit-event:: socket.connect self,address socket.socket.connect
.. versionchanged:: 3.5
The method now waits until the connection completes instead of raising an
:c:data:`errno` variable. This is useful to support, for example, asynchronous
connects.
- .. audit-event:: socket.connect "self address"
+ .. audit-event:: socket.connect self,address socket.socket.connect_ex
.. method:: socket.detach()
bytes sent. (The format of *address* depends on the address family --- see
above.)
- .. audit-event:: socket.sendto "self address"
+ .. audit-event:: socket.sendto self,address socket.socket.sendto
.. versionchanged:: 3.5
If the system call is interrupted and the signal handler does not raise
.. availability:: most Unix platforms, possibly others.
- .. audit-event:: socket.sendmsg "self address"
+ .. audit-event:: socket.sendmsg self,address socket.socket.sendmsg
.. versionadded:: 3.3
More information about this feature, including a list of recognized options, can
be found in the `SQLite URI documentation <https://www.sqlite.org/uri.html>`_.
- .. audit-event:: sqlite3.connect "database"
+ .. audit-event:: sqlite3.connect database sqlite3.connect
.. versionchanged:: 3.4
Added the *uri* parameter.
with Popen(["ifconfig"], stdout=PIPE) as proc:
log.write(proc.stdout.read())
- .. audit-event:: subprocess.Popen "executable args cwd env"
+ .. audit-event:: subprocess.Popen executable,args,cwd,env subprocess.Popen
Popen and the other functions in this module that use it raise an
:ref:`auditing event <auditing>` ``subprocess.Popen`` with arguments
The native equivalent of this function is :c:func:`PySys_Audit`. Using the
native function is preferred when possible.
+ See the :ref:`audit events table <audit-events>` for all events raised by
+ ``CPython``.
+
.. versionadded:: 3.8
This function should be used for internal and specialized purposes only.
- .. audit-event:: sys._current_frames
+ .. audit-event:: sys._current_frames "" sys._current_frames
.. function:: breakpointhook()
that is deeper than the call stack, :exc:`ValueError` is raised. The default
for *depth* is zero, returning the frame at the top of the call stack.
- .. audit-event:: sys._getframe
+ .. audit-event:: sys._getframe "" sys._getframe
.. impl-detail::
``'return'``, ``'c_call'``, ``'c_return'``, or ``'c_exception'``. *arg* depends
on the event type.
- .. audit-event:: sys.setprofile
+ .. audit-event:: sys.setprofile "" sys.setprofile
The events have the following meaning:
For more information on code and frame objects, refer to :ref:`types`.
- .. audit-event:: sys.settrace
+ .. audit-event:: sys.settrace "" sys.settrace
.. impl-detail::
first time. The *finalizer* will be called when an asynchronous generator
is about to be garbage collected.
- .. audit-event:: sys.set_asyncgen_hooks_firstiter
+ .. audit-event:: sys.set_asyncgen_hooks_firstiter "" sys.set_asyncgen_hooks
- .. audit-event:: sys.set_asyncgen_hooks_finalizer
+ .. audit-event:: sys.set_asyncgen_hooks_finalizer "" sys.set_asyncgen_hooks
Two auditing events are raised because the underlying API consists of two
calls, each of which must raise its own event.
Do not try to reopen an already connected instance.
- .. audit-event:: telnetlib.Telnet.open "self host port"
+ .. audit-event:: telnetlib.Telnet.open self,host,port telnetlib.Telnet.open
.. method:: Telnet.msg(msg, *args)
block if the connection is blocked. May raise :exc:`OSError` if the
connection is closed.
- .. audit-event:: telnetlib.Telnet.write "self buffer"
+ .. audit-event:: telnetlib.Telnet.write self,buffer telnetlib.Telnet.write
.. versionchanged:: 3.3
This method used to raise :exc:`socket.error`, which is now an alias
The :py:data:`os.O_TMPFILE` flag is used if it is available and works
(Linux-specific, requires Linux kernel 3.11 or later).
- .. audit-event:: tempfile.mkstemp "full-path"
+ .. audit-event:: tempfile.mkstemp fullpath tempfile.TemporaryFile
.. versionchanged:: 3.5
attribute is the underlying true file object. This file-like object can
be used in a :keyword:`with` statement, just like a normal file.
- .. audit-event:: tempfile.mkstemp "full-path"
+ .. audit-event:: tempfile.mkstemp fullpath tempfile.NamedTemporaryFile
.. versionchanged:: 3.8
Added *errors* parameter.
The directory can be explicitly cleaned up by calling the
:func:`cleanup` method.
- .. audit-event:: tempfile.mkdtemp "full-path"
+ .. audit-event:: tempfile.mkdtemp fullpath tempfile.TemporaryDirectory
.. versionadded:: 3.2
file (as would be returned by :func:`os.open`) and the absolute pathname
of that file, in that order.
- .. audit-event:: tempfile.mkstemp "full-path"
+ .. audit-event:: tempfile.mkstemp fullpath tempfile.mkstemp
.. versionchanged:: 3.5
*suffix*, *prefix*, and *dir* may now be supplied in bytes in order to
:func:`mkdtemp` returns the absolute pathname of the new directory.
- .. audit-event:: tempfile.mkdtemp "full-path"
+ .. audit-event:: tempfile.mkdtemp fullpath tempfile.mkdtemp
.. versionchanged:: 3.5
*suffix*, *prefix*, and *dir* may now be supplied in bytes in order to
parameter to ``urllib.urlopen``, can be obtained by using
:class:`ProxyHandler` objects.
- .. audit-event:: urllib.Request "fullurl data headers method"
+ .. audit-event:: urllib.Request fullurl,data,headers,method urllib.request.urlopen
The default opener raises an :ref:`auditing event <auditing>`
``urllib.Request`` with arguments ``fullurl``, ``data``, ``headers``,
may work and start the operating system's associated program. However, this
is neither supported nor portable.
- .. audit-event:: webbrowser.open "url"
+ .. audit-event:: webbrowser.open url webbrowser.open
.. function:: open_new(url)
from sphinx import addnodes
from sphinx.builders import Builder
from sphinx.locale import translators
-from sphinx.util import status_iterator
+from sphinx.util import status_iterator, logging
from sphinx.util.nodes import split_explicit_title
from sphinx.writers.html import HTMLTranslator
from sphinx.writers.text import TextWriter, TextTranslator
has_content = True
required_arguments = 1
- optional_arguments = 1
+ optional_arguments = 2
final_argument_whitespace = True
_label = [
"Raises an :ref:`auditing event <auditing>` {name} with arguments {args}.",
]
+ @property
+ def logger(self):
+ cls = type(self)
+ return logging.getLogger(cls.__module__ + "." + cls.__name__)
+
def run(self):
+ name = self.arguments[0]
if len(self.arguments) >= 2 and self.arguments[1]:
- args = [
- "``{}``".format(a.strip())
- for a in self.arguments[1].strip("'\"").split()
- if a.strip()
- ]
+ args = (a.strip() for a in self.arguments[1].strip("'\"").split(","))
+ args = [a for a in args if a]
else:
args = []
label = translators['sphinx'].gettext(self._label[min(2, len(args))])
- text = label.format(name="``{}``".format(self.arguments[0]),
- args=", ".join(args))
+ text = label.format(name="``{}``".format(name),
+ args=", ".join("``{}``".format(a) for a in args if a))
+
+ env = self.state.document.settings.env
+ if not hasattr(env, 'all_audit_events'):
+ env.all_audit_events = {}
+
+ new_info = {
+ 'source': [],
+ 'args': args
+ }
+ info = env.all_audit_events.setdefault(name, new_info)
+ if info is not new_info:
+ if not self._do_args_match(info['args'], new_info['args']):
+ self.logger.warn(
+ "Mismatched arguments for audit-event {}: {!r} != {!r}"
+ .format(name, info['args'], new_info['args'])
+ )
+
+ if len(self.arguments) >= 3 and self.arguments[2]:
+ target = self.arguments[2]
+ ids = []
+ else:
+ target = "audit_event_{}_{}".format(name, len(info['source']))
+ target = re.sub(r'\W', '_', label)
+ ids = [target]
+ info['source'].append((env.docname, target))
- pnode = nodes.paragraph(text, classes=["audit-hook"])
+ pnode = nodes.paragraph(text, classes=["audit-hook"], ids=ids)
if self.content:
self.state.nested_parse(self.content, self.content_offset, pnode)
else:
return [pnode]
+ # This list of sets are allowable synonyms for event argument names.
+ # If two names are in the same set, they are treated as equal for the
+ # purposes of warning. This won't help if number of arguments is
+ # different!
+ _SYNONYMS = [
+ {"file", "path", "fd"},
+ ]
+
+ def _do_args_match(self, args1, args2):
+ if args1 == args2:
+ return True
+ if len(args1) != len(args2):
+ return False
+ for a1, a2 in zip(args1, args2):
+ if a1 == a2:
+ continue
+ if any(a1 in s and a2 in s for s in self._SYNONYMS):
+ continue
+ return False
+ return True
+
+
+class audit_event_list(nodes.General, nodes.Element):
+ pass
+
+
+class AuditEventListDirective(Directive):
+
+ def run(self):
+ return [audit_event_list('')]
+
# Support for documenting decorators
'building topics... ',
length=len(pydoc_topic_labels)):
if label not in self.env.domaindata['std']['labels']:
- self.warn('label %r not in documentation' % label)
+ self.env.logger.warn('label %r not in documentation' % label)
continue
docname, labelid, sectname = self.env.domaindata['std']['labels'][label]
doctree = self.env.get_and_resolve_doctree(docname, self)
return fullname
+def process_audit_events(app, doctree, fromdocname):
+ for node in doctree.traverse(audit_event_list):
+ break
+ else:
+ return
+
+ env = app.builder.env
+
+ table = nodes.table(cols=3)
+ group = nodes.tgroup(
+ '',
+ nodes.colspec(colwidth=30),
+ nodes.colspec(colwidth=55),
+ nodes.colspec(colwidth=15),
+ )
+ head = nodes.thead()
+ body = nodes.tbody()
+
+ table += group
+ group += head
+ group += body
+
+ row = nodes.row()
+ row += nodes.entry('', nodes.paragraph('', nodes.Text('Audit event')))
+ row += nodes.entry('', nodes.paragraph('', nodes.Text('Arguments')))
+ row += nodes.entry('', nodes.paragraph('', nodes.Text('References')))
+ head += row
+
+ for name in sorted(getattr(env, "all_audit_events", ())):
+ audit_event = env.all_audit_events[name]
+
+ row = nodes.row()
+ node = nodes.paragraph('', nodes.Text(name))
+ row += nodes.entry('', node)
+
+ node = nodes.paragraph()
+ for i, a in enumerate(audit_event['args']):
+ if i:
+ node += nodes.Text(", ")
+ node += nodes.literal(a, nodes.Text(a))
+ row += nodes.entry('', node)
+
+ node = nodes.paragraph()
+ for i, (doc, label) in enumerate(audit_event['source'], start=1):
+ if isinstance(label, str):
+ ref = nodes.reference("", nodes.Text("[{}]".format(i)), internal=True)
+ ref['refuri'] = "{}#{}".format(
+ app.builder.get_relative_uri(fromdocname, doc),
+ label,
+ )
+ node += ref
+ row += nodes.entry('', node)
+
+ body += row
+
+ for node in doctree.traverse(audit_event_list):
+ node.replace_self(table)
+
+
def setup(app):
app.add_role('issue', issue_role)
app.add_role('source', source_role)
app.add_directive('impl-detail', ImplementationDetail)
app.add_directive('availability', Availability)
app.add_directive('audit-event', AuditEvent)
+ app.add_directive('audit-event-table', AuditEventListDirective)
app.add_directive('deprecated-removed', DeprecatedRemoved)
app.add_builder(PydocTopicsBuilder)
app.add_builder(suspicious.CheckSuspiciousMarkupBuilder)
app.add_directive_to_domain('py', 'awaitablemethod', PyAwaitableMethod)
app.add_directive_to_domain('py', 'abstractmethod', PyAbstractMethod)
app.add_directive('miscnews', MiscNews)
+ app.connect('doctree-resolved', process_audit_events)
return {'version': '1.0', 'parallel_read_safe': True}
self.timeout = timeout
if source_address is not None:
self.source_address = source_address
- sys.audit("ftplib.FTP.connect", self, self.host, self.port)
+ sys.audit("ftplib.connect", self, self.host, self.port)
self.sock = socket.create_connection((self.host, self.port), self.timeout,
source_address=self.source_address)
self.af = self.sock.family
def putline(self, line):
if '\r' in line or '\n' in line:
raise ValueError('an illegal newline character should not be contained')
- sys.audit("ftplib.FTP.sendcmd", self, line)
+ sys.audit("ftplib.sendcmd", self, line)
line = line + CRLF
if self.debugging > 1:
print('*put*', self.sanitize(line))
# (which is used by socket.create_connection()) expects None
# as a default value for host.
host = None if not self.host else self.host
- sys.audit("imaplib.IMAP4.open", self, self.host, self.port)
+ sys.audit("imaplib.open", self, self.host, self.port)
return socket.create_connection((host, self.port))
def open(self, host = '', port = IMAP4_PORT):
def send(self, data):
"""Send data to remote."""
- sys.audit("imaplib.IMAP4.send", self, data)
+ sys.audit("imaplib.send", self, data)
self.sock.sendall(data)
def _putline(self, line):
"""Internal: send one line to the server, appending CRLF.
The `line` must be a bytes-like object."""
- sys.audit("nntplib.NNTP.putline", self, line)
+ sys.audit("nntplib.putline", self, line)
line = line + _CRLF
if self.debugging > 1: print('*put*', repr(line))
self.file.write(line)
"""
self.host = host
self.port = port
- sys.audit("nntplib.NNTP", self, host, port)
+ sys.audit("nntplib.connect", self, host, port)
self.sock = socket.create_connection((host, port), timeout)
file = None
try:
"""This works identically to NNTP.__init__, except for the change
in default port and the `ssl_context` argument for SSL connections.
"""
- sys.audit("nntplib.NNTP", self, host, port)
+ sys.audit("nntplib.connect", self, host, port)
self.sock = socket.create_connection((host, port), timeout)
file = None
try:
self.host = host
self.port = port
self._tls_established = False
- sys.audit("poplib.POP3", self, host, port)
+ sys.audit("poplib.connect", self, host, port)
self.sock = self._create_socket(timeout)
self.file = self.sock.makefile('rb')
self._debugging = 0
def _putline(self, line):
if self._debugging > 1: print('*put*', repr(line))
- sys.audit("poplib.POP3.putline", self, line)
+ sys.audit("poplib.putline", self, line)
self.sock.sendall(line + CRLF)
port = self.default_port
if self.debuglevel > 0:
self._print_debug('connect:', (host, port))
- sys.audit("smtplib.SMTP.connect", self, host, port)
+ sys.audit("smtplib.connect", self, host, port)
self.sock = self._get_socket(host, port, self.timeout)
self.file = None
(code, msg) = self.getreply()
# should not be used, but 'data' needs to convert the string to
# binary itself anyway, so that's not a problem.
s = s.encode(self.command_encoding)
- sys.audit("smtplib.SMTP.send", self, s)
+ sys.audit("smtplib.send", self, s)
try:
self.sock.sendall(s)
except OSError: