diff --git a/.gitattributes b/.gitattributes
index af1a465afa15b4aff3845167280cdcbd853ec7f3..b82fa1b76c5ebd85aca49d3ee01c6f6ce077618f 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -148,3 +148,5 @@ my_container_sandbox/workspace/anaconda3/lib/libnppial.so filter=lfs diff=lfs me
my_container_sandbox/workspace/anaconda3/lib/libsqlite3.so.0.8.6 filter=lfs diff=lfs merge=lfs -text
my_container_sandbox/workspace/anaconda3/lib/libcudart.so filter=lfs diff=lfs merge=lfs -text
my_container_sandbox/workspace/anaconda3/lib/libz.so.1.2.13 filter=lfs diff=lfs merge=lfs -text
+my_container_sandbox/workspace/anaconda3/lib/libnppicc.so filter=lfs diff=lfs merge=lfs -text
+my_container_sandbox/workspace/anaconda3/lib/libnppitc.so.11 filter=lfs diff=lfs merge=lfs -text
diff --git a/my_container_sandbox/workspace/anaconda3/lib/itcl4.2.2/libitclstub4.2.2.a b/my_container_sandbox/workspace/anaconda3/lib/itcl4.2.2/libitclstub4.2.2.a
new file mode 100644
index 0000000000000000000000000000000000000000..b72a075991d88910f8af8a69111d1d854ee05afe
Binary files /dev/null and b/my_container_sandbox/workspace/anaconda3/lib/itcl4.2.2/libitclstub4.2.2.a differ
diff --git a/my_container_sandbox/workspace/anaconda3/lib/libnppicc.so b/my_container_sandbox/workspace/anaconda3/lib/libnppicc.so
new file mode 100644
index 0000000000000000000000000000000000000000..481d423bb6f78fc6e2de2ee781ae1a6f6f5944e4
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/libnppicc.so
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c7c756f65b011b05e8bc1dfcd7d2856159d3dacb2e7753caa97965d862ca08b0
+size 6357432
diff --git a/my_container_sandbox/workspace/anaconda3/lib/libnppitc.so.11 b/my_container_sandbox/workspace/anaconda3/lib/libnppitc.so.11
new file mode 100644
index 0000000000000000000000000000000000000000..a9aed02bfa815157d581065cc61cca70600c5901
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/libnppitc.so.11
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e59c811a2478ca8f1335e787c046eabaaa9a0ac1589b898f3f5bc10b57527503
+size 4306408
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/__future__.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/__future__.py
new file mode 100644
index 0000000000000000000000000000000000000000..0e7b5552343356d75cd17b64c33c0db276bc5848
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/__future__.py
@@ -0,0 +1,147 @@
+"""Record of phased-in incompatible language changes.
+
+Each line is of the form:
+
+ FeatureName = "_Feature(" OptionalRelease "," MandatoryRelease ","
+ CompilerFlag ")"
+
+where, normally, OptionalRelease < MandatoryRelease, and both are 5-tuples
+of the same form as sys.version_info:
+
+ (PY_MAJOR_VERSION, # the 2 in 2.1.0a3; an int
+ PY_MINOR_VERSION, # the 1; an int
+ PY_MICRO_VERSION, # the 0; an int
+ PY_RELEASE_LEVEL, # "alpha", "beta", "candidate" or "final"; string
+ PY_RELEASE_SERIAL # the 3; an int
+ )
+
+OptionalRelease records the first release in which
+
+ from __future__ import FeatureName
+
+was accepted.
+
+In the case of MandatoryReleases that have not yet occurred,
+MandatoryRelease predicts the release in which the feature will become part
+of the language.
+
+Else MandatoryRelease records when the feature became part of the language;
+in releases at or after that, modules no longer need
+
+ from __future__ import FeatureName
+
+to use the feature in question, but may continue to use such imports.
+
+MandatoryRelease may also be None, meaning that a planned feature got
+dropped.
+
+Instances of class _Feature have two corresponding methods,
+.getOptionalRelease() and .getMandatoryRelease().
+
+CompilerFlag is the (bitfield) flag that should be passed in the fourth
+argument to the builtin function compile() to enable the feature in
+dynamically compiled code. This flag is stored in the .compiler_flag
+attribute on _Future instances. These values must match the appropriate
+#defines of CO_xxx flags in Include/compile.h.
+
+No feature line is ever to be deleted from this file.
+"""
+
+all_feature_names = [
+ "nested_scopes",
+ "generators",
+ "division",
+ "absolute_import",
+ "with_statement",
+ "print_function",
+ "unicode_literals",
+ "barry_as_FLUFL",
+ "generator_stop",
+ "annotations",
+]
+
+__all__ = ["all_feature_names"] + all_feature_names
+
+# The CO_xxx symbols are defined here under the same names defined in
+# code.h and used by compile.h, so that an editor search will find them here.
+# However, they're not exported in __all__, because they don't really belong to
+# this module.
+CO_NESTED = 0x0010 # nested_scopes
+CO_GENERATOR_ALLOWED = 0 # generators (obsolete, was 0x1000)
+CO_FUTURE_DIVISION = 0x20000 # division
+CO_FUTURE_ABSOLUTE_IMPORT = 0x40000 # perform absolute imports by default
+CO_FUTURE_WITH_STATEMENT = 0x80000 # with statement
+CO_FUTURE_PRINT_FUNCTION = 0x100000 # print function
+CO_FUTURE_UNICODE_LITERALS = 0x200000 # unicode string literals
+CO_FUTURE_BARRY_AS_BDFL = 0x400000
+CO_FUTURE_GENERATOR_STOP = 0x800000 # StopIteration becomes RuntimeError in generators
+CO_FUTURE_ANNOTATIONS = 0x1000000 # annotations become strings at runtime
+
+
+class _Feature:
+
+ def __init__(self, optionalRelease, mandatoryRelease, compiler_flag):
+ self.optional = optionalRelease
+ self.mandatory = mandatoryRelease
+ self.compiler_flag = compiler_flag
+
+ def getOptionalRelease(self):
+ """Return first release in which this feature was recognized.
+
+ This is a 5-tuple, of the same form as sys.version_info.
+ """
+ return self.optional
+
+ def getMandatoryRelease(self):
+ """Return release in which this feature will become mandatory.
+
+ This is a 5-tuple, of the same form as sys.version_info, or, if
+ the feature was dropped, is None.
+ """
+ return self.mandatory
+
+ def __repr__(self):
+ return "_Feature" + repr((self.optional,
+ self.mandatory,
+ self.compiler_flag))
+
+
+nested_scopes = _Feature((2, 1, 0, "beta", 1),
+ (2, 2, 0, "alpha", 0),
+ CO_NESTED)
+
+generators = _Feature((2, 2, 0, "alpha", 1),
+ (2, 3, 0, "final", 0),
+ CO_GENERATOR_ALLOWED)
+
+division = _Feature((2, 2, 0, "alpha", 2),
+ (3, 0, 0, "alpha", 0),
+ CO_FUTURE_DIVISION)
+
+absolute_import = _Feature((2, 5, 0, "alpha", 1),
+ (3, 0, 0, "alpha", 0),
+ CO_FUTURE_ABSOLUTE_IMPORT)
+
+with_statement = _Feature((2, 5, 0, "alpha", 1),
+ (2, 6, 0, "alpha", 0),
+ CO_FUTURE_WITH_STATEMENT)
+
+print_function = _Feature((2, 6, 0, "alpha", 2),
+ (3, 0, 0, "alpha", 0),
+ CO_FUTURE_PRINT_FUNCTION)
+
+unicode_literals = _Feature((2, 6, 0, "alpha", 2),
+ (3, 0, 0, "alpha", 0),
+ CO_FUTURE_UNICODE_LITERALS)
+
+barry_as_FLUFL = _Feature((3, 1, 0, "alpha", 2),
+ (4, 0, 0, "alpha", 0),
+ CO_FUTURE_BARRY_AS_BDFL)
+
+generator_stop = _Feature((3, 5, 0, "beta", 1),
+ (3, 7, 0, "alpha", 0),
+ CO_FUTURE_GENERATOR_STOP)
+
+annotations = _Feature((3, 7, 0, "beta", 1),
+ (3, 10, 0, "alpha", 0),
+ CO_FUTURE_ANNOTATIONS)
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/_markupbase.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/_markupbase.py
new file mode 100644
index 0000000000000000000000000000000000000000..2af5f1c23b6066284938fb1cc697bc1fc2fea6ea
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/_markupbase.py
@@ -0,0 +1,395 @@
+"""Shared support for scanning document type declarations in HTML and XHTML.
+
+This module is used as a foundation for the html.parser module. It has no
+documented public API and should not be used directly.
+
+"""
+
+import re
+
+_declname_match = re.compile(r'[a-zA-Z][-_.a-zA-Z0-9]*\s*').match
+_declstringlit_match = re.compile(r'(\'[^\']*\'|"[^"]*")\s*').match
+_commentclose = re.compile(r'--\s*>')
+_markedsectionclose = re.compile(r']\s*]\s*>')
+
+# An analysis of the MS-Word extensions is available at
+# http://www.planetpublish.com/xmlarena/xap/Thursday/WordtoXML.pdf
+
+_msmarkedsectionclose = re.compile(r']\s*>')
+
+del re
+
+
+class ParserBase:
+ """Parser base class which provides some common support methods used
+ by the SGML/HTML and XHTML parsers."""
+
+ def __init__(self):
+ if self.__class__ is ParserBase:
+ raise RuntimeError(
+ "_markupbase.ParserBase must be subclassed")
+
+ def error(self, message):
+ raise NotImplementedError(
+ "subclasses of ParserBase must override error()")
+
+ def reset(self):
+ self.lineno = 1
+ self.offset = 0
+
+ def getpos(self):
+ """Return current line number and offset."""
+ return self.lineno, self.offset
+
+ # Internal -- update line number and offset. This should be
+ # called for each piece of data exactly once, in order -- in other
+ # words the concatenation of all the input strings to this
+ # function should be exactly the entire input.
+ def updatepos(self, i, j):
+ if i >= j:
+ return j
+ rawdata = self.rawdata
+ nlines = rawdata.count("\n", i, j)
+ if nlines:
+ self.lineno = self.lineno + nlines
+ pos = rawdata.rindex("\n", i, j) # Should not fail
+ self.offset = j-(pos+1)
+ else:
+ self.offset = self.offset + j-i
+ return j
+
+ _decl_otherchars = ''
+
+ # Internal -- parse declaration (for use by subclasses).
+ def parse_declaration(self, i):
+ # This is some sort of declaration; in "HTML as
+ # deployed," this should only be the document type
+ # declaration ("").
+ # ISO 8879:1986, however, has more complex
+ # declaration syntax for elements in , including:
+ # --comment--
+ # [marked section]
+ # name in the following list: ENTITY, DOCTYPE, ELEMENT,
+ # ATTLIST, NOTATION, SHORTREF, USEMAP,
+ # LINKTYPE, LINK, IDLINK, USELINK, SYSTEM
+ rawdata = self.rawdata
+ j = i + 2
+ assert rawdata[i:j] == "":
+ # the empty comment
+ return j + 1
+ if rawdata[j:j+1] in ("-", ""):
+ # Start of comment followed by buffer boundary,
+ # or just a buffer boundary.
+ return -1
+ # A simple, practical version could look like: ((name|stringlit) S*) + '>'
+ n = len(rawdata)
+ if rawdata[j:j+2] == '--': #comment
+ # Locate --.*-- as the body of the comment
+ return self.parse_comment(i)
+ elif rawdata[j] == '[': #marked section
+ # Locate [statusWord [...arbitrary SGML...]] as the body of the marked section
+ # Where statusWord is one of TEMP, CDATA, IGNORE, INCLUDE, RCDATA
+ # Note that this is extended by Microsoft Office "Save as Web" function
+ # to include [if...] and [endif].
+ return self.parse_marked_section(i)
+ else: #all other declaration elements
+ decltype, j = self._scan_name(j, i)
+ if j < 0:
+ return j
+ if decltype == "doctype":
+ self._decl_otherchars = ''
+ while j < n:
+ c = rawdata[j]
+ if c == ">":
+ # end of declaration syntax
+ data = rawdata[i+2:j]
+ if decltype == "doctype":
+ self.handle_decl(data)
+ else:
+ # According to the HTML5 specs sections "8.2.4.44 Bogus
+ # comment state" and "8.2.4.45 Markup declaration open
+ # state", a comment token should be emitted.
+ # Calling unknown_decl provides more flexibility though.
+ self.unknown_decl(data)
+ return j + 1
+ if c in "\"'":
+ m = _declstringlit_match(rawdata, j)
+ if not m:
+ return -1 # incomplete
+ j = m.end()
+ elif c in "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ":
+ name, j = self._scan_name(j, i)
+ elif c in self._decl_otherchars:
+ j = j + 1
+ elif c == "[":
+ # this could be handled in a separate doctype parser
+ if decltype == "doctype":
+ j = self._parse_doctype_subset(j + 1, i)
+ elif decltype in {"attlist", "linktype", "link", "element"}:
+ # must tolerate []'d groups in a content model in an element declaration
+ # also in data attribute specifications of attlist declaration
+ # also link type declaration subsets in linktype declarations
+ # also link attribute specification lists in link declarations
+ self.error("unsupported '[' char in %s declaration" % decltype)
+ else:
+ self.error("unexpected '[' char in declaration")
+ else:
+ self.error(
+ "unexpected %r char in declaration" % rawdata[j])
+ if j < 0:
+ return j
+ return -1 # incomplete
+
+ # Internal -- parse a marked section
+ # Override this to handle MS-word extension syntax content
+ def parse_marked_section(self, i, report=1):
+ rawdata= self.rawdata
+ assert rawdata[i:i+3] == ' ending
+ match= _markedsectionclose.search(rawdata, i+3)
+ elif sectName in {"if", "else", "endif"}:
+ # look for MS Office ]> ending
+ match= _msmarkedsectionclose.search(rawdata, i+3)
+ else:
+ self.error('unknown status keyword %r in marked section' % rawdata[i+3:j])
+ if not match:
+ return -1
+ if report:
+ j = match.start(0)
+ self.unknown_decl(rawdata[i+3: j])
+ return match.end(0)
+
+ # Internal -- parse comment, return length or -1 if not terminated
+ def parse_comment(self, i, report=1):
+ rawdata = self.rawdata
+ if rawdata[i:i+4] != '
+
--> -->
+
+ '''
+
+__UNDEF__ = [] # a special sentinel object
+def small(text):
+ if text:
+ return '' + text + ''
+ else:
+ return ''
+
+def strong(text):
+ if text:
+ return '' + text + ''
+ else:
+ return ''
+
+def grey(text):
+ if text:
+ return '' + text + ''
+ else:
+ return ''
+
+def lookup(name, frame, locals):
+ """Find the value for a given name in the given environment."""
+ if name in locals:
+ return 'local', locals[name]
+ if name in frame.f_globals:
+ return 'global', frame.f_globals[name]
+ if '__builtins__' in frame.f_globals:
+ builtins = frame.f_globals['__builtins__']
+ if type(builtins) is type({}):
+ if name in builtins:
+ return 'builtin', builtins[name]
+ else:
+ if hasattr(builtins, name):
+ return 'builtin', getattr(builtins, name)
+ return None, __UNDEF__
+
+def scanvars(reader, frame, locals):
+ """Scan one logical line of Python and look up values of variables used."""
+ vars, lasttoken, parent, prefix, value = [], None, None, '', __UNDEF__
+ for ttype, token, start, end, line in tokenize.generate_tokens(reader):
+ if ttype == tokenize.NEWLINE: break
+ if ttype == tokenize.NAME and token not in keyword.kwlist:
+ if lasttoken == '.':
+ if parent is not __UNDEF__:
+ value = getattr(parent, token, __UNDEF__)
+ vars.append((prefix + token, prefix, value))
+ else:
+ where, value = lookup(token, frame, locals)
+ vars.append((token, where, value))
+ elif token == '.':
+ prefix += lasttoken + '.'
+ parent = value
+ else:
+ parent, prefix = None, ''
+ lasttoken = token
+ return vars
+
+def html(einfo, context=5):
+ """Return a nice HTML document describing a given traceback."""
+ etype, evalue, etb = einfo
+ if isinstance(etype, type):
+ etype = etype.__name__
+ pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
+ date = time.ctime(time.time())
+ head = '' + pydoc.html.heading(
+ '%s' %
+ strong(pydoc.html.escape(str(etype))),
+ '#ffffff', '#6622aa', pyver + ' ' + date) + '''
+
A problem occurred in a Python script. Here is the sequence of
+function calls leading up to the error, in the order they occurred.
' %
+ (' ', link, call)]
+ if index is not None:
+ i = lnum - index
+ for line in lines:
+ num = small(' ' * (5-len(str(i))) + str(i)) + ' '
+ if i in highlight:
+ line = '=>%s%s' % (num, pydoc.html.preformat(line))
+ rows.append('
' % grey(line))
+ i += 1
+
+ done, dump = {}, []
+ for name, where, value in vars:
+ if name in done: continue
+ done[name] = 1
+ if value is not __UNDEF__:
+ if where in ('global', 'builtin'):
+ name = ('%s ' % where) + strong(name)
+ elif where == 'local':
+ name = strong(name)
+ else:
+ name = where + strong(name.split('.')[-1])
+ dump.append('%s = %s' % (name, pydoc.html.repr(value)))
+ else:
+ dump.append(name + ' undefined')
+
+ rows.append('
A problem occurred in a Python script.\n')
+
+ if self.logdir is not None:
+ suffix = ['.txt', '.html'][self.format=="html"]
+ (fd, path) = tempfile.mkstemp(suffix=suffix, dir=self.logdir)
+
+ try:
+ with os.fdopen(fd, 'w') as file:
+ file.write(doc)
+ msg = '%s contains the description of this error.' % path
+ except:
+ msg = 'Tried to save traceback to %s, but failed.' % path
+
+ if self.format == 'html':
+ self.file.write('
%s
\n' % msg)
+ else:
+ self.file.write(msg + '\n')
+ try:
+ self.file.flush()
+ except: pass
+
+handler = Hook().handle
+def enable(display=1, logdir=None, context=5, format="html"):
+ """Install an exception handler that formats tracebacks as HTML.
+
+ The optional argument 'display' can be set to 0 to suppress sending the
+ traceback to the browser, and 'logdir' can be set to a directory to cause
+ tracebacks to be written to files there."""
+ sys.excepthook = Hook(display=display, logdir=logdir,
+ context=context, format=format)
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/code.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/code.py
new file mode 100644
index 0000000000000000000000000000000000000000..76000f8c8b2c1e1c98f8fb4c831c2ea3e2de268d
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/code.py
@@ -0,0 +1,315 @@
+"""Utilities needed to emulate Python's interactive interpreter.
+
+"""
+
+# Inspired by similar code by Jeff Epler and Fredrik Lundh.
+
+
+import sys
+import traceback
+from codeop import CommandCompiler, compile_command
+
+__all__ = ["InteractiveInterpreter", "InteractiveConsole", "interact",
+ "compile_command"]
+
+class InteractiveInterpreter:
+ """Base class for InteractiveConsole.
+
+ This class deals with parsing and interpreter state (the user's
+ namespace); it doesn't deal with input buffering or prompting or
+ input file naming (the filename is always passed in explicitly).
+
+ """
+
+ def __init__(self, locals=None):
+ """Constructor.
+
+ The optional 'locals' argument specifies the dictionary in
+ which code will be executed; it defaults to a newly created
+ dictionary with key "__name__" set to "__console__" and key
+ "__doc__" set to None.
+
+ """
+ if locals is None:
+ locals = {"__name__": "__console__", "__doc__": None}
+ self.locals = locals
+ self.compile = CommandCompiler()
+
+ def runsource(self, source, filename="", symbol="single"):
+ """Compile and run some source in the interpreter.
+
+ Arguments are as for compile_command().
+
+ One of several things can happen:
+
+ 1) The input is incorrect; compile_command() raised an
+ exception (SyntaxError or OverflowError). A syntax traceback
+ will be printed by calling the showsyntaxerror() method.
+
+ 2) The input is incomplete, and more input is required;
+ compile_command() returned None. Nothing happens.
+
+ 3) The input is complete; compile_command() returned a code
+ object. The code is executed by calling self.runcode() (which
+ also handles run-time exceptions, except for SystemExit).
+
+ The return value is True in case 2, False in the other cases (unless
+ an exception is raised). The return value can be used to
+ decide whether to use sys.ps1 or sys.ps2 to prompt the next
+ line.
+
+ """
+ try:
+ code = self.compile(source, filename, symbol)
+ except (OverflowError, SyntaxError, ValueError):
+ # Case 1
+ self.showsyntaxerror(filename)
+ return False
+
+ if code is None:
+ # Case 2
+ return True
+
+ # Case 3
+ self.runcode(code)
+ return False
+
+ def runcode(self, code):
+ """Execute a code object.
+
+ When an exception occurs, self.showtraceback() is called to
+ display a traceback. All exceptions are caught except
+ SystemExit, which is reraised.
+
+ A note about KeyboardInterrupt: this exception may occur
+ elsewhere in this code, and may not always be caught. The
+ caller should be prepared to deal with it.
+
+ """
+ try:
+ exec(code, self.locals)
+ except SystemExit:
+ raise
+ except:
+ self.showtraceback()
+
+ def showsyntaxerror(self, filename=None):
+ """Display the syntax error that just occurred.
+
+ This doesn't display a stack trace because there isn't one.
+
+ If a filename is given, it is stuffed in the exception instead
+ of what was there before (because Python's parser always uses
+ "" when reading from a string).
+
+ The output is written by self.write(), below.
+
+ """
+ type, value, tb = sys.exc_info()
+ sys.last_type = type
+ sys.last_value = value
+ sys.last_traceback = tb
+ if filename and type is SyntaxError:
+ # Work hard to stuff the correct filename in the exception
+ try:
+ msg, (dummy_filename, lineno, offset, line) = value.args
+ except ValueError:
+ # Not the format we expect; leave it alone
+ pass
+ else:
+ # Stuff in the right filename
+ value = SyntaxError(msg, (filename, lineno, offset, line))
+ sys.last_value = value
+ if sys.excepthook is sys.__excepthook__:
+ lines = traceback.format_exception_only(type, value)
+ self.write(''.join(lines))
+ else:
+ # If someone has set sys.excepthook, we let that take precedence
+ # over self.write
+ sys.excepthook(type, value, tb)
+
+ def showtraceback(self):
+ """Display the exception that just occurred.
+
+ We remove the first stack item because it is our own code.
+
+ The output is written by self.write(), below.
+
+ """
+ sys.last_type, sys.last_value, last_tb = ei = sys.exc_info()
+ sys.last_traceback = last_tb
+ try:
+ lines = traceback.format_exception(ei[0], ei[1], last_tb.tb_next)
+ if sys.excepthook is sys.__excepthook__:
+ self.write(''.join(lines))
+ else:
+ # If someone has set sys.excepthook, we let that take precedence
+ # over self.write
+ sys.excepthook(ei[0], ei[1], last_tb)
+ finally:
+ last_tb = ei = None
+
+ def write(self, data):
+ """Write a string.
+
+ The base implementation writes to sys.stderr; a subclass may
+ replace this with a different implementation.
+
+ """
+ sys.stderr.write(data)
+
+
+class InteractiveConsole(InteractiveInterpreter):
+ """Closely emulate the behavior of the interactive Python interpreter.
+
+ This class builds on InteractiveInterpreter and adds prompting
+ using the familiar sys.ps1 and sys.ps2, and input buffering.
+
+ """
+
+ def __init__(self, locals=None, filename=""):
+ """Constructor.
+
+ The optional locals argument will be passed to the
+ InteractiveInterpreter base class.
+
+ The optional filename argument should specify the (file)name
+ of the input stream; it will show up in tracebacks.
+
+ """
+ InteractiveInterpreter.__init__(self, locals)
+ self.filename = filename
+ self.resetbuffer()
+
+ def resetbuffer(self):
+ """Reset the input buffer."""
+ self.buffer = []
+
+ def interact(self, banner=None, exitmsg=None):
+ """Closely emulate the interactive Python console.
+
+ The optional banner argument specifies the banner to print
+ before the first interaction; by default it prints a banner
+ similar to the one printed by the real Python interpreter,
+ followed by the current class name in parentheses (so as not
+ to confuse this with the real interpreter -- since it's so
+ close!).
+
+ The optional exitmsg argument specifies the exit message
+ printed when exiting. Pass the empty string to suppress
+ printing an exit message. If exitmsg is not given or None,
+ a default message is printed.
+
+ """
+ try:
+ sys.ps1
+ except AttributeError:
+ sys.ps1 = ">>> "
+ try:
+ sys.ps2
+ except AttributeError:
+ sys.ps2 = "... "
+ cprt = 'Type "help", "copyright", "credits" or "license" for more information.'
+ if banner is None:
+ self.write("Python %s on %s\n%s\n(%s)\n" %
+ (sys.version, sys.platform, cprt,
+ self.__class__.__name__))
+ elif banner:
+ self.write("%s\n" % str(banner))
+ more = 0
+ while 1:
+ try:
+ if more:
+ prompt = sys.ps2
+ else:
+ prompt = sys.ps1
+ try:
+ line = self.raw_input(prompt)
+ except EOFError:
+ self.write("\n")
+ break
+ else:
+ more = self.push(line)
+ except KeyboardInterrupt:
+ self.write("\nKeyboardInterrupt\n")
+ self.resetbuffer()
+ more = 0
+ if exitmsg is None:
+ self.write('now exiting %s...\n' % self.__class__.__name__)
+ elif exitmsg != '':
+ self.write('%s\n' % exitmsg)
+
+ def push(self, line):
+ """Push a line to the interpreter.
+
+ The line should not have a trailing newline; it may have
+ internal newlines. The line is appended to a buffer and the
+ interpreter's runsource() method is called with the
+ concatenated contents of the buffer as source. If this
+ indicates that the command was executed or invalid, the buffer
+ is reset; otherwise, the command is incomplete, and the buffer
+ is left as it was after the line was appended. The return
+ value is 1 if more input is required, 0 if the line was dealt
+ with in some way (this is the same as runsource()).
+
+ """
+ self.buffer.append(line)
+ source = "\n".join(self.buffer)
+ more = self.runsource(source, self.filename)
+ if not more:
+ self.resetbuffer()
+ return more
+
+ def raw_input(self, prompt=""):
+ """Write a prompt and read a line.
+
+ The returned line does not include the trailing newline.
+ When the user enters the EOF key sequence, EOFError is raised.
+
+ The base implementation uses the built-in function
+ input(); a subclass may replace this with a different
+ implementation.
+
+ """
+ return input(prompt)
+
+
+
+def interact(banner=None, readfunc=None, local=None, exitmsg=None):
+ """Closely emulate the interactive Python interpreter.
+
+ This is a backwards compatible interface to the InteractiveConsole
+ class. When readfunc is not specified, it attempts to import the
+ readline module to enable GNU readline if it is available.
+
+ Arguments (all optional, all default to None):
+
+ banner -- passed to InteractiveConsole.interact()
+ readfunc -- if not None, replaces InteractiveConsole.raw_input()
+ local -- passed to InteractiveInterpreter.__init__()
+ exitmsg -- passed to InteractiveConsole.interact()
+
+ """
+ console = InteractiveConsole(local)
+ if readfunc is not None:
+ console.raw_input = readfunc
+ else:
+ try:
+ import readline
+ except ImportError:
+ pass
+ console.interact(banner, exitmsg)
+
+
+if __name__ == "__main__":
+ import argparse
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument('-q', action='store_true',
+ help="don't print version and copyright messages")
+ args = parser.parse_args()
+ if args.q or sys.flags.quiet:
+ banner = ''
+ else:
+ banner = None
+ interact(banner)
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/codecs.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/codecs.py
new file mode 100644
index 0000000000000000000000000000000000000000..7f23e9775df804e79e4d0869a29dc05e1396a892
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/codecs.py
@@ -0,0 +1,1126 @@
+""" codecs -- Python Codec Registry, API and helpers.
+
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+
+"""
+
+import builtins
+import sys
+
+### Registry and builtin stateless codec functions
+
+try:
+ from _codecs import *
+except ImportError as why:
+ raise SystemError('Failed to load the builtin codecs: %s' % why)
+
+__all__ = ["register", "lookup", "open", "EncodedFile", "BOM", "BOM_BE",
+ "BOM_LE", "BOM32_BE", "BOM32_LE", "BOM64_BE", "BOM64_LE",
+ "BOM_UTF8", "BOM_UTF16", "BOM_UTF16_LE", "BOM_UTF16_BE",
+ "BOM_UTF32", "BOM_UTF32_LE", "BOM_UTF32_BE",
+ "CodecInfo", "Codec", "IncrementalEncoder", "IncrementalDecoder",
+ "StreamReader", "StreamWriter",
+ "StreamReaderWriter", "StreamRecoder",
+ "getencoder", "getdecoder", "getincrementalencoder",
+ "getincrementaldecoder", "getreader", "getwriter",
+ "encode", "decode", "iterencode", "iterdecode",
+ "strict_errors", "ignore_errors", "replace_errors",
+ "xmlcharrefreplace_errors",
+ "backslashreplace_errors", "namereplace_errors",
+ "register_error", "lookup_error"]
+
+### Constants
+
+#
+# Byte Order Mark (BOM = ZERO WIDTH NO-BREAK SPACE = U+FEFF)
+# and its possible byte string values
+# for UTF8/UTF16/UTF32 output and little/big endian machines
+#
+
+# UTF-8
+BOM_UTF8 = b'\xef\xbb\xbf'
+
+# UTF-16, little endian
+BOM_LE = BOM_UTF16_LE = b'\xff\xfe'
+
+# UTF-16, big endian
+BOM_BE = BOM_UTF16_BE = b'\xfe\xff'
+
+# UTF-32, little endian
+BOM_UTF32_LE = b'\xff\xfe\x00\x00'
+
+# UTF-32, big endian
+BOM_UTF32_BE = b'\x00\x00\xfe\xff'
+
+if sys.byteorder == 'little':
+
+ # UTF-16, native endianness
+ BOM = BOM_UTF16 = BOM_UTF16_LE
+
+ # UTF-32, native endianness
+ BOM_UTF32 = BOM_UTF32_LE
+
+else:
+
+ # UTF-16, native endianness
+ BOM = BOM_UTF16 = BOM_UTF16_BE
+
+ # UTF-32, native endianness
+ BOM_UTF32 = BOM_UTF32_BE
+
+# Old broken names (don't use in new code)
+BOM32_LE = BOM_UTF16_LE
+BOM32_BE = BOM_UTF16_BE
+BOM64_LE = BOM_UTF32_LE
+BOM64_BE = BOM_UTF32_BE
+
+
+### Codec base classes (defining the API)
+
+class CodecInfo(tuple):
+ """Codec details when looking up the codec registry"""
+
+ # Private API to allow Python 3.4 to blacklist the known non-Unicode
+ # codecs in the standard library. A more general mechanism to
+ # reliably distinguish test encodings from other codecs will hopefully
+ # be defined for Python 3.5
+ #
+ # See http://bugs.python.org/issue19619
+ _is_text_encoding = True # Assume codecs are text encodings by default
+
+ def __new__(cls, encode, decode, streamreader=None, streamwriter=None,
+ incrementalencoder=None, incrementaldecoder=None, name=None,
+ *, _is_text_encoding=None):
+ self = tuple.__new__(cls, (encode, decode, streamreader, streamwriter))
+ self.name = name
+ self.encode = encode
+ self.decode = decode
+ self.incrementalencoder = incrementalencoder
+ self.incrementaldecoder = incrementaldecoder
+ self.streamwriter = streamwriter
+ self.streamreader = streamreader
+ if _is_text_encoding is not None:
+ self._is_text_encoding = _is_text_encoding
+ return self
+
+ def __repr__(self):
+ return "<%s.%s object for encoding %s at %#x>" % \
+ (self.__class__.__module__, self.__class__.__qualname__,
+ self.name, id(self))
+
+class Codec:
+
+ """ Defines the interface for stateless encoders/decoders.
+
+ The .encode()/.decode() methods may use different error
+ handling schemes by providing the errors argument. These
+ string values are predefined:
+
+ 'strict' - raise a ValueError error (or a subclass)
+ 'ignore' - ignore the character and continue with the next
+ 'replace' - replace with a suitable replacement character;
+ Python will use the official U+FFFD REPLACEMENT
+ CHARACTER for the builtin Unicode codecs on
+ decoding and '?' on encoding.
+ 'surrogateescape' - replace with private code points U+DCnn.
+ 'xmlcharrefreplace' - Replace with the appropriate XML
+ character reference (only for encoding).
+ 'backslashreplace' - Replace with backslashed escape sequences.
+ 'namereplace' - Replace with \\N{...} escape sequences
+ (only for encoding).
+
+ The set of allowed values can be extended via register_error.
+
+ """
+ def encode(self, input, errors='strict'):
+
+ """ Encodes the object input and returns a tuple (output
+ object, length consumed).
+
+ errors defines the error handling to apply. It defaults to
+ 'strict' handling.
+
+ The method may not store state in the Codec instance. Use
+ StreamWriter for codecs which have to keep state in order to
+ make encoding efficient.
+
+ The encoder must be able to handle zero length input and
+ return an empty object of the output object type in this
+ situation.
+
+ """
+ raise NotImplementedError
+
+ def decode(self, input, errors='strict'):
+
+ """ Decodes the object input and returns a tuple (output
+ object, length consumed).
+
+ input must be an object which provides the bf_getreadbuf
+ buffer slot. Python strings, buffer objects and memory
+ mapped files are examples of objects providing this slot.
+
+ errors defines the error handling to apply. It defaults to
+ 'strict' handling.
+
+ The method may not store state in the Codec instance. Use
+ StreamReader for codecs which have to keep state in order to
+ make decoding efficient.
+
+ The decoder must be able to handle zero length input and
+ return an empty object of the output object type in this
+ situation.
+
+ """
+ raise NotImplementedError
+
+class IncrementalEncoder(object):
+ """
+ An IncrementalEncoder encodes an input in multiple steps. The input can
+ be passed piece by piece to the encode() method. The IncrementalEncoder
+ remembers the state of the encoding process between calls to encode().
+ """
+ def __init__(self, errors='strict'):
+ """
+ Creates an IncrementalEncoder instance.
+
+ The IncrementalEncoder may use different error handling schemes by
+ providing the errors keyword argument. See the module docstring
+ for a list of possible values.
+ """
+ self.errors = errors
+ self.buffer = ""
+
+ def encode(self, input, final=False):
+ """
+ Encodes input and returns the resulting object.
+ """
+ raise NotImplementedError
+
+ def reset(self):
+ """
+ Resets the encoder to the initial state.
+ """
+
+ def getstate(self):
+ """
+ Return the current state of the encoder.
+ """
+ return 0
+
+ def setstate(self, state):
+ """
+ Set the current state of the encoder. state must have been
+ returned by getstate().
+ """
+
+class BufferedIncrementalEncoder(IncrementalEncoder):
+ """
+ This subclass of IncrementalEncoder can be used as the baseclass for an
+ incremental encoder if the encoder must keep some of the output in a
+ buffer between calls to encode().
+ """
+ def __init__(self, errors='strict'):
+ IncrementalEncoder.__init__(self, errors)
+ # unencoded input that is kept between calls to encode()
+ self.buffer = ""
+
+ def _buffer_encode(self, input, errors, final):
+ # Overwrite this method in subclasses: It must encode input
+ # and return an (output, length consumed) tuple
+ raise NotImplementedError
+
+ def encode(self, input, final=False):
+ # encode input (taking the buffer into account)
+ data = self.buffer + input
+ (result, consumed) = self._buffer_encode(data, self.errors, final)
+ # keep unencoded input until the next call
+ self.buffer = data[consumed:]
+ return result
+
+ def reset(self):
+ IncrementalEncoder.reset(self)
+ self.buffer = ""
+
+ def getstate(self):
+ return self.buffer or 0
+
+ def setstate(self, state):
+ self.buffer = state or ""
+
+class IncrementalDecoder(object):
+ """
+ An IncrementalDecoder decodes an input in multiple steps. The input can
+ be passed piece by piece to the decode() method. The IncrementalDecoder
+ remembers the state of the decoding process between calls to decode().
+ """
+ def __init__(self, errors='strict'):
+ """
+ Create an IncrementalDecoder instance.
+
+ The IncrementalDecoder may use different error handling schemes by
+ providing the errors keyword argument. See the module docstring
+ for a list of possible values.
+ """
+ self.errors = errors
+
+ def decode(self, input, final=False):
+ """
+ Decode input and returns the resulting object.
+ """
+ raise NotImplementedError
+
+ def reset(self):
+ """
+ Reset the decoder to the initial state.
+ """
+
+ def getstate(self):
+ """
+ Return the current state of the decoder.
+
+ This must be a (buffered_input, additional_state_info) tuple.
+ buffered_input must be a bytes object containing bytes that
+ were passed to decode() that have not yet been converted.
+ additional_state_info must be a non-negative integer
+ representing the state of the decoder WITHOUT yet having
+ processed the contents of buffered_input. In the initial state
+ and after reset(), getstate() must return (b"", 0).
+ """
+ return (b"", 0)
+
+ def setstate(self, state):
+ """
+ Set the current state of the decoder.
+
+ state must have been returned by getstate(). The effect of
+ setstate((b"", 0)) must be equivalent to reset().
+ """
+
+class BufferedIncrementalDecoder(IncrementalDecoder):
+ """
+ This subclass of IncrementalDecoder can be used as the baseclass for an
+ incremental decoder if the decoder must be able to handle incomplete
+ byte sequences.
+ """
+ def __init__(self, errors='strict'):
+ IncrementalDecoder.__init__(self, errors)
+ # undecoded input that is kept between calls to decode()
+ self.buffer = b""
+
+ def _buffer_decode(self, input, errors, final):
+ # Overwrite this method in subclasses: It must decode input
+ # and return an (output, length consumed) tuple
+ raise NotImplementedError
+
+ def decode(self, input, final=False):
+ # decode input (taking the buffer into account)
+ data = self.buffer + input
+ (result, consumed) = self._buffer_decode(data, self.errors, final)
+ # keep undecoded input until the next call
+ self.buffer = data[consumed:]
+ return result
+
+ def reset(self):
+ IncrementalDecoder.reset(self)
+ self.buffer = b""
+
+ def getstate(self):
+ # additional state info is always 0
+ return (self.buffer, 0)
+
+ def setstate(self, state):
+ # ignore additional state info
+ self.buffer = state[0]
+
+#
+# The StreamWriter and StreamReader class provide generic working
+# interfaces which can be used to implement new encoding submodules
+# very easily. See encodings/utf_8.py for an example on how this is
+# done.
+#
+
+class StreamWriter(Codec):
+
+ def __init__(self, stream, errors='strict'):
+
+ """ Creates a StreamWriter instance.
+
+ stream must be a file-like object open for writing.
+
+ The StreamWriter may use different error handling
+ schemes by providing the errors keyword argument. These
+ parameters are predefined:
+
+ 'strict' - raise a ValueError (or a subclass)
+ 'ignore' - ignore the character and continue with the next
+ 'replace'- replace with a suitable replacement character
+ 'xmlcharrefreplace' - Replace with the appropriate XML
+ character reference.
+ 'backslashreplace' - Replace with backslashed escape
+ sequences.
+ 'namereplace' - Replace with \\N{...} escape sequences.
+
+ The set of allowed parameter values can be extended via
+ register_error.
+ """
+ self.stream = stream
+ self.errors = errors
+
+ def write(self, object):
+
+ """ Writes the object's contents encoded to self.stream.
+ """
+ data, consumed = self.encode(object, self.errors)
+ self.stream.write(data)
+
+ def writelines(self, list):
+
+ """ Writes the concatenated list of strings to the stream
+ using .write().
+ """
+ self.write(''.join(list))
+
+ def reset(self):
+
+ """ Flushes and resets the codec buffers used for keeping state.
+
+ Calling this method should ensure that the data on the
+ output is put into a clean state, that allows appending
+ of new fresh data without having to rescan the whole
+ stream to recover state.
+
+ """
+ pass
+
+ def seek(self, offset, whence=0):
+ self.stream.seek(offset, whence)
+ if whence == 0 and offset == 0:
+ self.reset()
+
+ def __getattr__(self, name,
+ getattr=getattr):
+
+ """ Inherit all other methods from the underlying stream.
+ """
+ return getattr(self.stream, name)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, type, value, tb):
+ self.stream.close()
+
+###
+
+class StreamReader(Codec):
+
+ charbuffertype = str
+
+ def __init__(self, stream, errors='strict'):
+
+ """ Creates a StreamReader instance.
+
+ stream must be a file-like object open for reading.
+
+ The StreamReader may use different error handling
+ schemes by providing the errors keyword argument. These
+ parameters are predefined:
+
+ 'strict' - raise a ValueError (or a subclass)
+ 'ignore' - ignore the character and continue with the next
+ 'replace'- replace with a suitable replacement character
+ 'backslashreplace' - Replace with backslashed escape sequences;
+
+ The set of allowed parameter values can be extended via
+ register_error.
+ """
+ self.stream = stream
+ self.errors = errors
+ self.bytebuffer = b""
+ self._empty_charbuffer = self.charbuffertype()
+ self.charbuffer = self._empty_charbuffer
+ self.linebuffer = None
+
+ def decode(self, input, errors='strict'):
+ raise NotImplementedError
+
+ def read(self, size=-1, chars=-1, firstline=False):
+
+ """ Decodes data from the stream self.stream and returns the
+ resulting object.
+
+ chars indicates the number of decoded code points or bytes to
+ return. read() will never return more data than requested,
+ but it might return less, if there is not enough available.
+
+ size indicates the approximate maximum number of decoded
+ bytes or code points to read for decoding. The decoder
+ can modify this setting as appropriate. The default value
+ -1 indicates to read and decode as much as possible. size
+ is intended to prevent having to decode huge files in one
+ step.
+
+ If firstline is true, and a UnicodeDecodeError happens
+ after the first line terminator in the input only the first line
+ will be returned, the rest of the input will be kept until the
+ next call to read().
+
+ The method should use a greedy read strategy, meaning that
+ it should read as much data as is allowed within the
+ definition of the encoding and the given size, e.g. if
+ optional encoding endings or state markers are available
+ on the stream, these should be read too.
+ """
+ # If we have lines cached, first merge them back into characters
+ if self.linebuffer:
+ self.charbuffer = self._empty_charbuffer.join(self.linebuffer)
+ self.linebuffer = None
+
+ if chars < 0:
+ # For compatibility with other read() methods that take a
+ # single argument
+ chars = size
+
+ # read until we get the required number of characters (if available)
+ while True:
+ # can the request be satisfied from the character buffer?
+ if chars >= 0:
+ if len(self.charbuffer) >= chars:
+ break
+ # we need more data
+ if size < 0:
+ newdata = self.stream.read()
+ else:
+ newdata = self.stream.read(size)
+ # decode bytes (those remaining from the last call included)
+ data = self.bytebuffer + newdata
+ if not data:
+ break
+ try:
+ newchars, decodedbytes = self.decode(data, self.errors)
+ except UnicodeDecodeError as exc:
+ if firstline:
+ newchars, decodedbytes = \
+ self.decode(data[:exc.start], self.errors)
+ lines = newchars.splitlines(keepends=True)
+ if len(lines)<=1:
+ raise
+ else:
+ raise
+ # keep undecoded bytes until the next call
+ self.bytebuffer = data[decodedbytes:]
+ # put new characters in the character buffer
+ self.charbuffer += newchars
+ # there was no data available
+ if not newdata:
+ break
+ if chars < 0:
+ # Return everything we've got
+ result = self.charbuffer
+ self.charbuffer = self._empty_charbuffer
+ else:
+ # Return the first chars characters
+ result = self.charbuffer[:chars]
+ self.charbuffer = self.charbuffer[chars:]
+ return result
+
+ def readline(self, size=None, keepends=True):
+
+ """ Read one line from the input stream and return the
+ decoded data.
+
+ size, if given, is passed as size argument to the
+ read() method.
+
+ """
+ # If we have lines cached from an earlier read, return
+ # them unconditionally
+ if self.linebuffer:
+ line = self.linebuffer[0]
+ del self.linebuffer[0]
+ if len(self.linebuffer) == 1:
+ # revert to charbuffer mode; we might need more data
+ # next time
+ self.charbuffer = self.linebuffer[0]
+ self.linebuffer = None
+ if not keepends:
+ line = line.splitlines(keepends=False)[0]
+ return line
+
+ readsize = size or 72
+ line = self._empty_charbuffer
+ # If size is given, we call read() only once
+ while True:
+ data = self.read(readsize, firstline=True)
+ if data:
+ # If we're at a "\r" read one extra character (which might
+ # be a "\n") to get a proper line ending. If the stream is
+ # temporarily exhausted we return the wrong line ending.
+ if (isinstance(data, str) and data.endswith("\r")) or \
+ (isinstance(data, bytes) and data.endswith(b"\r")):
+ data += self.read(size=1, chars=1)
+
+ line += data
+ lines = line.splitlines(keepends=True)
+ if lines:
+ if len(lines) > 1:
+ # More than one line result; the first line is a full line
+ # to return
+ line = lines[0]
+ del lines[0]
+ if len(lines) > 1:
+ # cache the remaining lines
+ lines[-1] += self.charbuffer
+ self.linebuffer = lines
+ self.charbuffer = None
+ else:
+ # only one remaining line, put it back into charbuffer
+ self.charbuffer = lines[0] + self.charbuffer
+ if not keepends:
+ line = line.splitlines(keepends=False)[0]
+ break
+ line0withend = lines[0]
+ line0withoutend = lines[0].splitlines(keepends=False)[0]
+ if line0withend != line0withoutend: # We really have a line end
+ # Put the rest back together and keep it until the next call
+ self.charbuffer = self._empty_charbuffer.join(lines[1:]) + \
+ self.charbuffer
+ if keepends:
+ line = line0withend
+ else:
+ line = line0withoutend
+ break
+ # we didn't get anything or this was our only try
+ if not data or size is not None:
+ if line and not keepends:
+ line = line.splitlines(keepends=False)[0]
+ break
+ if readsize < 8000:
+ readsize *= 2
+ return line
+
+ def readlines(self, sizehint=None, keepends=True):
+
+ """ Read all lines available on the input stream
+ and return them as a list.
+
+ Line breaks are implemented using the codec's decoder
+ method and are included in the list entries.
+
+ sizehint, if given, is ignored since there is no efficient
+ way to finding the true end-of-line.
+
+ """
+ data = self.read()
+ return data.splitlines(keepends)
+
+ def reset(self):
+
+ """ Resets the codec buffers used for keeping state.
+
+ Note that no stream repositioning should take place.
+ This method is primarily intended to be able to recover
+ from decoding errors.
+
+ """
+ self.bytebuffer = b""
+ self.charbuffer = self._empty_charbuffer
+ self.linebuffer = None
+
+ def seek(self, offset, whence=0):
+ """ Set the input stream's current position.
+
+ Resets the codec buffers used for keeping state.
+ """
+ self.stream.seek(offset, whence)
+ self.reset()
+
+ def __next__(self):
+
+ """ Return the next decoded line from the input stream."""
+ line = self.readline()
+ if line:
+ return line
+ raise StopIteration
+
+ def __iter__(self):
+ return self
+
+ def __getattr__(self, name,
+ getattr=getattr):
+
+ """ Inherit all other methods from the underlying stream.
+ """
+ return getattr(self.stream, name)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, type, value, tb):
+ self.stream.close()
+
+###
+
+class StreamReaderWriter:
+
+ """ StreamReaderWriter instances allow wrapping streams which
+ work in both read and write modes.
+
+ The design is such that one can use the factory functions
+ returned by the codec.lookup() function to construct the
+ instance.
+
+ """
+ # Optional attributes set by the file wrappers below
+ encoding = 'unknown'
+
+ def __init__(self, stream, Reader, Writer, errors='strict'):
+
+ """ Creates a StreamReaderWriter instance.
+
+ stream must be a Stream-like object.
+
+ Reader, Writer must be factory functions or classes
+ providing the StreamReader, StreamWriter interface resp.
+
+ Error handling is done in the same way as defined for the
+ StreamWriter/Readers.
+
+ """
+ self.stream = stream
+ self.reader = Reader(stream, errors)
+ self.writer = Writer(stream, errors)
+ self.errors = errors
+
+ def read(self, size=-1):
+
+ return self.reader.read(size)
+
+ def readline(self, size=None):
+
+ return self.reader.readline(size)
+
+ def readlines(self, sizehint=None):
+
+ return self.reader.readlines(sizehint)
+
+ def __next__(self):
+
+ """ Return the next decoded line from the input stream."""
+ return next(self.reader)
+
+ def __iter__(self):
+ return self
+
+ def write(self, data):
+
+ return self.writer.write(data)
+
+ def writelines(self, list):
+
+ return self.writer.writelines(list)
+
+ def reset(self):
+
+ self.reader.reset()
+ self.writer.reset()
+
+ def seek(self, offset, whence=0):
+ self.stream.seek(offset, whence)
+ self.reader.reset()
+ if whence == 0 and offset == 0:
+ self.writer.reset()
+
+ def __getattr__(self, name,
+ getattr=getattr):
+
+ """ Inherit all other methods from the underlying stream.
+ """
+ return getattr(self.stream, name)
+
+ # these are needed to make "with StreamReaderWriter(...)" work properly
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, type, value, tb):
+ self.stream.close()
+
+###
+
+class StreamRecoder:
+
+ """ StreamRecoder instances translate data from one encoding to another.
+
+ They use the complete set of APIs returned by the
+ codecs.lookup() function to implement their task.
+
+ Data written to the StreamRecoder is first decoded into an
+ intermediate format (depending on the "decode" codec) and then
+ written to the underlying stream using an instance of the provided
+ Writer class.
+
+ In the other direction, data is read from the underlying stream using
+ a Reader instance and then encoded and returned to the caller.
+
+ """
+ # Optional attributes set by the file wrappers below
+ data_encoding = 'unknown'
+ file_encoding = 'unknown'
+
+ def __init__(self, stream, encode, decode, Reader, Writer,
+ errors='strict'):
+
+ """ Creates a StreamRecoder instance which implements a two-way
+ conversion: encode and decode work on the frontend (the
+ data visible to .read() and .write()) while Reader and Writer
+ work on the backend (the data in stream).
+
+ You can use these objects to do transparent
+ transcodings from e.g. latin-1 to utf-8 and back.
+
+ stream must be a file-like object.
+
+ encode and decode must adhere to the Codec interface; Reader and
+ Writer must be factory functions or classes providing the
+ StreamReader and StreamWriter interfaces resp.
+
+ Error handling is done in the same way as defined for the
+ StreamWriter/Readers.
+
+ """
+ self.stream = stream
+ self.encode = encode
+ self.decode = decode
+ self.reader = Reader(stream, errors)
+ self.writer = Writer(stream, errors)
+ self.errors = errors
+
+ def read(self, size=-1):
+
+ data = self.reader.read(size)
+ data, bytesencoded = self.encode(data, self.errors)
+ return data
+
+ def readline(self, size=None):
+
+ if size is None:
+ data = self.reader.readline()
+ else:
+ data = self.reader.readline(size)
+ data, bytesencoded = self.encode(data, self.errors)
+ return data
+
+ def readlines(self, sizehint=None):
+
+ data = self.reader.read()
+ data, bytesencoded = self.encode(data, self.errors)
+ return data.splitlines(keepends=True)
+
+ def __next__(self):
+
+ """ Return the next decoded line from the input stream."""
+ data = next(self.reader)
+ data, bytesencoded = self.encode(data, self.errors)
+ return data
+
+ def __iter__(self):
+ return self
+
+ def write(self, data):
+
+ data, bytesdecoded = self.decode(data, self.errors)
+ return self.writer.write(data)
+
+ def writelines(self, list):
+
+ data = b''.join(list)
+ data, bytesdecoded = self.decode(data, self.errors)
+ return self.writer.write(data)
+
+ def reset(self):
+
+ self.reader.reset()
+ self.writer.reset()
+
+ def seek(self, offset, whence=0):
+ # Seeks must be propagated to both the readers and writers
+ # as they might need to reset their internal buffers.
+ self.reader.seek(offset, whence)
+ self.writer.seek(offset, whence)
+
+ def __getattr__(self, name,
+ getattr=getattr):
+
+ """ Inherit all other methods from the underlying stream.
+ """
+ return getattr(self.stream, name)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, type, value, tb):
+ self.stream.close()
+
+### Shortcuts
+
+def open(filename, mode='r', encoding=None, errors='strict', buffering=-1):
+
+ """ Open an encoded file using the given mode and return
+ a wrapped version providing transparent encoding/decoding.
+
+ Note: The wrapped version will only accept the object format
+ defined by the codecs, i.e. Unicode objects for most builtin
+ codecs. Output is also codec dependent and will usually be
+ Unicode as well.
+
+ Underlying encoded files are always opened in binary mode.
+ The default file mode is 'r', meaning to open the file in read mode.
+
+ encoding specifies the encoding which is to be used for the
+ file.
+
+ errors may be given to define the error handling. It defaults
+ to 'strict' which causes ValueErrors to be raised in case an
+ encoding error occurs.
+
+ buffering has the same meaning as for the builtin open() API.
+ It defaults to -1 which means that the default buffer size will
+ be used.
+
+ The returned wrapped file object provides an extra attribute
+ .encoding which allows querying the used encoding. This
+ attribute is only available if an encoding was specified as
+ parameter.
+
+ """
+ if encoding is not None and \
+ 'b' not in mode:
+ # Force opening of the file in binary mode
+ mode = mode + 'b'
+ file = builtins.open(filename, mode, buffering)
+ if encoding is None:
+ return file
+
+ try:
+ info = lookup(encoding)
+ srw = StreamReaderWriter(file, info.streamreader, info.streamwriter, errors)
+ # Add attributes to simplify introspection
+ srw.encoding = encoding
+ return srw
+ except:
+ file.close()
+ raise
+
+def EncodedFile(file, data_encoding, file_encoding=None, errors='strict'):
+
+ """ Return a wrapped version of file which provides transparent
+ encoding translation.
+
+ Data written to the wrapped file is decoded according
+ to the given data_encoding and then encoded to the underlying
+ file using file_encoding. The intermediate data type
+ will usually be Unicode but depends on the specified codecs.
+
+ Bytes read from the file are decoded using file_encoding and then
+ passed back to the caller encoded using data_encoding.
+
+ If file_encoding is not given, it defaults to data_encoding.
+
+ errors may be given to define the error handling. It defaults
+ to 'strict' which causes ValueErrors to be raised in case an
+ encoding error occurs.
+
+ The returned wrapped file object provides two extra attributes
+ .data_encoding and .file_encoding which reflect the given
+ parameters of the same name. The attributes can be used for
+ introspection by Python programs.
+
+ """
+ if file_encoding is None:
+ file_encoding = data_encoding
+ data_info = lookup(data_encoding)
+ file_info = lookup(file_encoding)
+ sr = StreamRecoder(file, data_info.encode, data_info.decode,
+ file_info.streamreader, file_info.streamwriter, errors)
+ # Add attributes to simplify introspection
+ sr.data_encoding = data_encoding
+ sr.file_encoding = file_encoding
+ return sr
+
+### Helpers for codec lookup
+
+def getencoder(encoding):
+
+ """ Lookup up the codec for the given encoding and return
+ its encoder function.
+
+ Raises a LookupError in case the encoding cannot be found.
+
+ """
+ return lookup(encoding).encode
+
+def getdecoder(encoding):
+
+ """ Lookup up the codec for the given encoding and return
+ its decoder function.
+
+ Raises a LookupError in case the encoding cannot be found.
+
+ """
+ return lookup(encoding).decode
+
+def getincrementalencoder(encoding):
+
+ """ Lookup up the codec for the given encoding and return
+ its IncrementalEncoder class or factory function.
+
+ Raises a LookupError in case the encoding cannot be found
+ or the codecs doesn't provide an incremental encoder.
+
+ """
+ encoder = lookup(encoding).incrementalencoder
+ if encoder is None:
+ raise LookupError(encoding)
+ return encoder
+
+def getincrementaldecoder(encoding):
+
+ """ Lookup up the codec for the given encoding and return
+ its IncrementalDecoder class or factory function.
+
+ Raises a LookupError in case the encoding cannot be found
+ or the codecs doesn't provide an incremental decoder.
+
+ """
+ decoder = lookup(encoding).incrementaldecoder
+ if decoder is None:
+ raise LookupError(encoding)
+ return decoder
+
+def getreader(encoding):
+
+ """ Lookup up the codec for the given encoding and return
+ its StreamReader class or factory function.
+
+ Raises a LookupError in case the encoding cannot be found.
+
+ """
+ return lookup(encoding).streamreader
+
+def getwriter(encoding):
+
+ """ Lookup up the codec for the given encoding and return
+ its StreamWriter class or factory function.
+
+ Raises a LookupError in case the encoding cannot be found.
+
+ """
+ return lookup(encoding).streamwriter
+
+def iterencode(iterator, encoding, errors='strict', **kwargs):
+ """
+ Encoding iterator.
+
+ Encodes the input strings from the iterator using an IncrementalEncoder.
+
+ errors and kwargs are passed through to the IncrementalEncoder
+ constructor.
+ """
+ encoder = getincrementalencoder(encoding)(errors, **kwargs)
+ for input in iterator:
+ output = encoder.encode(input)
+ if output:
+ yield output
+ output = encoder.encode("", True)
+ if output:
+ yield output
+
+def iterdecode(iterator, encoding, errors='strict', **kwargs):
+ """
+ Decoding iterator.
+
+ Decodes the input strings from the iterator using an IncrementalDecoder.
+
+ errors and kwargs are passed through to the IncrementalDecoder
+ constructor.
+ """
+ decoder = getincrementaldecoder(encoding)(errors, **kwargs)
+ for input in iterator:
+ output = decoder.decode(input)
+ if output:
+ yield output
+ output = decoder.decode(b"", True)
+ if output:
+ yield output
+
+### Helpers for charmap-based codecs
+
+def make_identity_dict(rng):
+
+ """ make_identity_dict(rng) -> dict
+
+ Return a dictionary where elements of the rng sequence are
+ mapped to themselves.
+
+ """
+ return {i:i for i in rng}
+
+def make_encoding_map(decoding_map):
+
+ """ Creates an encoding map from a decoding map.
+
+ If a target mapping in the decoding map occurs multiple
+ times, then that target is mapped to None (undefined mapping),
+ causing an exception when encountered by the charmap codec
+ during translation.
+
+ One example where this happens is cp875.py which decodes
+ multiple character to \\u001a.
+
+ """
+ m = {}
+ for k,v in decoding_map.items():
+ if not v in m:
+ m[v] = k
+ else:
+ m[v] = None
+ return m
+
+### error handlers
+
+try:
+ strict_errors = lookup_error("strict")
+ ignore_errors = lookup_error("ignore")
+ replace_errors = lookup_error("replace")
+ xmlcharrefreplace_errors = lookup_error("xmlcharrefreplace")
+ backslashreplace_errors = lookup_error("backslashreplace")
+ namereplace_errors = lookup_error("namereplace")
+except LookupError:
+ # In --disable-unicode builds, these error handler are missing
+ strict_errors = None
+ ignore_errors = None
+ replace_errors = None
+ xmlcharrefreplace_errors = None
+ backslashreplace_errors = None
+ namereplace_errors = None
+
+# Tell modulefinder that using codecs probably needs the encodings
+# package
+_false = 0
+if _false:
+ import encodings
+
+### Tests
+
+if __name__ == '__main__':
+
+ # Make stdout translate Latin-1 output into UTF-8 output
+ sys.stdout = EncodedFile(sys.stdout, 'latin-1', 'utf-8')
+
+ # Have stdin translate Latin-1 input into UTF-8 input
+ sys.stdin = EncodedFile(sys.stdin, 'utf-8', 'latin-1')
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/codeop.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/codeop.py
new file mode 100644
index 0000000000000000000000000000000000000000..04ca6b9317087c07c907d2d9a9fd035ba1cc11d1
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/codeop.py
@@ -0,0 +1,178 @@
+r"""Utilities to compile possibly incomplete Python source code.
+
+This module provides two interfaces, broadly similar to the builtin
+function compile(), which take program text, a filename and a 'mode'
+and:
+
+- Return code object if the command is complete and valid
+- Return None if the command is incomplete
+- Raise SyntaxError, ValueError or OverflowError if the command is a
+ syntax error (OverflowError and ValueError can be produced by
+ malformed literals).
+
+Approach:
+
+First, check if the source consists entirely of blank lines and
+comments; if so, replace it with 'pass', because the built-in
+parser doesn't always do the right thing for these.
+
+Compile three times: as is, with \n, and with \n\n appended. If it
+compiles as is, it's complete. If it compiles with one \n appended,
+we expect more. If it doesn't compile either way, we compare the
+error we get when compiling with \n or \n\n appended. If the errors
+are the same, the code is broken. But if the errors are different, we
+expect more. Not intuitive; not even guaranteed to hold in future
+releases; but this matches the compiler's behavior from Python 1.4
+through 2.2, at least.
+
+Caveat:
+
+It is possible (but not likely) that the parser stops parsing with a
+successful outcome before reaching the end of the source; in this
+case, trailing symbols may be ignored instead of causing an error.
+For example, a backslash followed by two newlines may be followed by
+arbitrary garbage. This will be fixed once the API for the parser is
+better.
+
+The two interfaces are:
+
+compile_command(source, filename, symbol):
+
+ Compiles a single command in the manner described above.
+
+CommandCompiler():
+
+ Instances of this class have __call__ methods identical in
+ signature to compile_command; the difference is that if the
+ instance compiles program text containing a __future__ statement,
+ the instance 'remembers' and compiles all subsequent program texts
+ with the statement in force.
+
+The module also provides another class:
+
+Compile():
+
+ Instances of this class act like the built-in function compile,
+ but with 'memory' in the sense described above.
+"""
+
+import __future__
+import warnings
+
+_features = [getattr(__future__, fname)
+ for fname in __future__.all_feature_names]
+
+__all__ = ["compile_command", "Compile", "CommandCompiler"]
+
+PyCF_DONT_IMPLY_DEDENT = 0x200 # Matches pythonrun.h
+
+def _maybe_compile(compiler, source, filename, symbol):
+ # Check for source consisting of only blank lines and comments
+ for line in source.split("\n"):
+ line = line.strip()
+ if line and line[0] != '#':
+ break # Leave it alone
+ else:
+ if symbol != "eval":
+ source = "pass" # Replace it with a 'pass' statement
+
+ err = err1 = err2 = None
+ code = code1 = code2 = None
+
+ try:
+ code = compiler(source, filename, symbol)
+ except SyntaxError as err:
+ pass
+
+ # Catch syntax warnings after the first compile
+ # to emit warnings (SyntaxWarning, DeprecationWarning) at most once.
+ with warnings.catch_warnings():
+ warnings.simplefilter("error")
+
+ try:
+ code1 = compiler(source + "\n", filename, symbol)
+ except SyntaxError as e:
+ err1 = e
+
+ try:
+ code2 = compiler(source + "\n\n", filename, symbol)
+ except SyntaxError as e:
+ err2 = e
+
+ try:
+ if code:
+ return code
+ if not code1 and repr(err1) == repr(err2):
+ raise err1
+ finally:
+ err1 = err2 = None
+
+def _compile(source, filename, symbol):
+ return compile(source, filename, symbol, PyCF_DONT_IMPLY_DEDENT)
+
+def compile_command(source, filename="", symbol="single"):
+ r"""Compile a command and determine whether it is incomplete.
+
+ Arguments:
+
+ source -- the source string; may contain \n characters
+ filename -- optional filename from which source was read; default
+ ""
+ symbol -- optional grammar start symbol; "single" (default), "exec"
+ or "eval"
+
+ Return value / exceptions raised:
+
+ - Return a code object if the command is complete and valid
+ - Return None if the command is incomplete
+ - Raise SyntaxError, ValueError or OverflowError if the command is a
+ syntax error (OverflowError and ValueError can be produced by
+ malformed literals).
+ """
+ return _maybe_compile(_compile, source, filename, symbol)
+
+class Compile:
+ """Instances of this class behave much like the built-in compile
+ function, but if one is used to compile text containing a future
+ statement, it "remembers" and compiles all subsequent program texts
+ with the statement in force."""
+ def __init__(self):
+ self.flags = PyCF_DONT_IMPLY_DEDENT
+
+ def __call__(self, source, filename, symbol):
+ codeob = compile(source, filename, symbol, self.flags, 1)
+ for feature in _features:
+ if codeob.co_flags & feature.compiler_flag:
+ self.flags |= feature.compiler_flag
+ return codeob
+
+class CommandCompiler:
+ """Instances of this class have __call__ methods identical in
+ signature to compile_command; the difference is that if the
+ instance compiles program text containing a __future__ statement,
+ the instance 'remembers' and compiles all subsequent program texts
+ with the statement in force."""
+
+ def __init__(self,):
+ self.compiler = Compile()
+
+ def __call__(self, source, filename="", symbol="single"):
+ r"""Compile a command and determine whether it is incomplete.
+
+ Arguments:
+
+ source -- the source string; may contain \n characters
+ filename -- optional filename from which source was read;
+ default ""
+ symbol -- optional grammar start symbol; "single" (default) or
+ "eval"
+
+ Return value / exceptions raised:
+
+ - Return a code object if the command is complete and valid
+ - Return None if the command is incomplete
+ - Raise SyntaxError, ValueError or OverflowError if the command is a
+ syntax error (OverflowError and ValueError can be produced by
+ malformed literals).
+ """
+ return _maybe_compile(self.compiler, source, filename, symbol)
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/crypt.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/crypt.py
new file mode 100644
index 0000000000000000000000000000000000000000..8846602d7613ec76c365021ab500252a3f0546e9
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/crypt.py
@@ -0,0 +1,112 @@
+"""Wrapper to the POSIX crypt library call and associated functionality."""
+
+import sys as _sys
+
+try:
+ import _crypt
+except ModuleNotFoundError:
+ if _sys.platform == 'win32':
+ raise ImportError("The crypt module is not supported on Windows")
+ else:
+ raise ImportError("The required _crypt module was not built as part of CPython")
+
+import string as _string
+from random import SystemRandom as _SystemRandom
+from collections import namedtuple as _namedtuple
+
+
+_saltchars = _string.ascii_letters + _string.digits + './'
+_sr = _SystemRandom()
+
+
+class _Method(_namedtuple('_Method', 'name ident salt_chars total_size')):
+
+ """Class representing a salt method per the Modular Crypt Format or the
+ legacy 2-character crypt method."""
+
+ def __repr__(self):
+ return ''.format(self.name)
+
+
+def mksalt(method=None, *, rounds=None):
+ """Generate a salt for the specified method.
+
+ If not specified, the strongest available method will be used.
+
+ """
+ if method is None:
+ method = methods[0]
+ if rounds is not None and not isinstance(rounds, int):
+ raise TypeError(f'{rounds.__class__.__name__} object cannot be '
+ f'interpreted as an integer')
+ if not method.ident: # traditional
+ s = ''
+ else: # modular
+ s = f'${method.ident}$'
+
+ if method.ident and method.ident[0] == '2': # Blowfish variants
+ if rounds is None:
+ log_rounds = 12
+ else:
+ log_rounds = int.bit_length(rounds-1)
+ if rounds != 1 << log_rounds:
+ raise ValueError('rounds must be a power of 2')
+ if not 4 <= log_rounds <= 31:
+ raise ValueError('rounds out of the range 2**4 to 2**31')
+ s += f'{log_rounds:02d}$'
+ elif method.ident in ('5', '6'): # SHA-2
+ if rounds is not None:
+ if not 1000 <= rounds <= 999_999_999:
+ raise ValueError('rounds out of the range 1000 to 999_999_999')
+ s += f'rounds={rounds}$'
+ elif rounds is not None:
+ raise ValueError(f"{method} doesn't support the rounds argument")
+
+ s += ''.join(_sr.choice(_saltchars) for char in range(method.salt_chars))
+ return s
+
+
+def crypt(word, salt=None):
+ """Return a string representing the one-way hash of a password, with a salt
+ prepended.
+
+ If ``salt`` is not specified or is ``None``, the strongest
+ available method will be selected and a salt generated. Otherwise,
+ ``salt`` may be one of the ``crypt.METHOD_*`` values, or a string as
+ returned by ``crypt.mksalt()``.
+
+ """
+ if salt is None or isinstance(salt, _Method):
+ salt = mksalt(salt)
+ return _crypt.crypt(word, salt)
+
+
+# available salting/crypto methods
+methods = []
+
+def _add_method(name, *args, rounds=None):
+ method = _Method(name, *args)
+ globals()['METHOD_' + name] = method
+ salt = mksalt(method, rounds=rounds)
+ result = crypt('', salt)
+ if result and len(result) == method.total_size:
+ methods.append(method)
+ return True
+ return False
+
+_add_method('SHA512', '6', 16, 106)
+_add_method('SHA256', '5', 16, 63)
+
+# Choose the strongest supported version of Blowfish hashing.
+# Early versions have flaws. Version 'a' fixes flaws of
+# the initial implementation, 'b' fixes flaws of 'a'.
+# 'y' is the same as 'b', for compatibility
+# with openwall crypt_blowfish.
+for _v in 'b', 'y', 'a', '':
+ if _add_method('BLOWFISH', '2' + _v, 22, 59 + len(_v), rounds=1<<4):
+ break
+
+_add_method('MD5', '1', 8, 34)
+_add_method('CRYPT', None, 2, 13)
+
+del _v, _add_method
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/decimal.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/decimal.py
new file mode 100644
index 0000000000000000000000000000000000000000..7746ea2601024ceb7e750472753fcfc80fa2bd01
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/decimal.py
@@ -0,0 +1,11 @@
+
+try:
+ from _decimal import *
+ from _decimal import __doc__
+ from _decimal import __version__
+ from _decimal import __libmpdec_version__
+except ImportError:
+ from _pydecimal import *
+ from _pydecimal import __doc__
+ from _pydecimal import __version__
+ from _pydecimal import __libmpdec_version__
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/dis.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/dis.py
new file mode 100644
index 0000000000000000000000000000000000000000..e289e176c78ffd78ee6e42a6b41acc0298f63933
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/dis.py
@@ -0,0 +1,553 @@
+"""Disassembler of Python byte code into mnemonics."""
+
+import sys
+import types
+import collections
+import io
+
+from opcode import *
+from opcode import __all__ as _opcodes_all
+
+__all__ = ["code_info", "dis", "disassemble", "distb", "disco",
+ "findlinestarts", "findlabels", "show_code",
+ "get_instructions", "Instruction", "Bytecode"] + _opcodes_all
+del _opcodes_all
+
+_have_code = (types.MethodType, types.FunctionType, types.CodeType,
+ classmethod, staticmethod, type)
+
+FORMAT_VALUE = opmap['FORMAT_VALUE']
+FORMAT_VALUE_CONVERTERS = (
+ (None, ''),
+ (str, 'str'),
+ (repr, 'repr'),
+ (ascii, 'ascii'),
+)
+MAKE_FUNCTION = opmap['MAKE_FUNCTION']
+MAKE_FUNCTION_FLAGS = ('defaults', 'kwdefaults', 'annotations', 'closure')
+
+
+def _try_compile(source, name):
+ """Attempts to compile the given source, first as an expression and
+ then as a statement if the first approach fails.
+
+ Utility function to accept strings in functions that otherwise
+ expect code objects
+ """
+ try:
+ c = compile(source, name, 'eval')
+ except SyntaxError:
+ c = compile(source, name, 'exec')
+ return c
+
+def dis(x=None, *, file=None, depth=None):
+ """Disassemble classes, methods, functions, and other compiled objects.
+
+ With no argument, disassemble the last traceback.
+
+ Compiled objects currently include generator objects, async generator
+ objects, and coroutine objects, all of which store their code object
+ in a special attribute.
+ """
+ if x is None:
+ distb(file=file)
+ return
+ # Extract functions from methods.
+ if hasattr(x, '__func__'):
+ x = x.__func__
+ # Extract compiled code objects from...
+ if hasattr(x, '__code__'): # ...a function, or
+ x = x.__code__
+ elif hasattr(x, 'gi_code'): #...a generator object, or
+ x = x.gi_code
+ elif hasattr(x, 'ag_code'): #...an asynchronous generator object, or
+ x = x.ag_code
+ elif hasattr(x, 'cr_code'): #...a coroutine.
+ x = x.cr_code
+ # Perform the disassembly.
+ if hasattr(x, '__dict__'): # Class or module
+ items = sorted(x.__dict__.items())
+ for name, x1 in items:
+ if isinstance(x1, _have_code):
+ print("Disassembly of %s:" % name, file=file)
+ try:
+ dis(x1, file=file, depth=depth)
+ except TypeError as msg:
+ print("Sorry:", msg, file=file)
+ print(file=file)
+ elif hasattr(x, 'co_code'): # Code object
+ _disassemble_recursive(x, file=file, depth=depth)
+ elif isinstance(x, (bytes, bytearray)): # Raw bytecode
+ _disassemble_bytes(x, file=file)
+ elif isinstance(x, str): # Source code
+ _disassemble_str(x, file=file, depth=depth)
+ else:
+ raise TypeError("don't know how to disassemble %s objects" %
+ type(x).__name__)
+
+def distb(tb=None, *, file=None):
+ """Disassemble a traceback (default: last traceback)."""
+ if tb is None:
+ try:
+ tb = sys.last_traceback
+ except AttributeError:
+ raise RuntimeError("no last traceback to disassemble") from None
+ while tb.tb_next: tb = tb.tb_next
+ disassemble(tb.tb_frame.f_code, tb.tb_lasti, file=file)
+
+# The inspect module interrogates this dictionary to build its
+# list of CO_* constants. It is also used by pretty_flags to
+# turn the co_flags field into a human readable list.
+COMPILER_FLAG_NAMES = {
+ 1: "OPTIMIZED",
+ 2: "NEWLOCALS",
+ 4: "VARARGS",
+ 8: "VARKEYWORDS",
+ 16: "NESTED",
+ 32: "GENERATOR",
+ 64: "NOFREE",
+ 128: "COROUTINE",
+ 256: "ITERABLE_COROUTINE",
+ 512: "ASYNC_GENERATOR",
+}
+
+def pretty_flags(flags):
+ """Return pretty representation of code flags."""
+ names = []
+ for i in range(32):
+ flag = 1<")
+ # By now, if we don't have a code object, we can't disassemble x.
+ if hasattr(x, 'co_code'):
+ return x
+ raise TypeError("don't know how to disassemble %s objects" %
+ type(x).__name__)
+
+def code_info(x):
+ """Formatted details of methods, functions, or code."""
+ return _format_code_info(_get_code_object(x))
+
+def _format_code_info(co):
+ lines = []
+ lines.append("Name: %s" % co.co_name)
+ lines.append("Filename: %s" % co.co_filename)
+ lines.append("Argument count: %s" % co.co_argcount)
+ lines.append("Positional-only arguments: %s" % co.co_posonlyargcount)
+ lines.append("Kw-only arguments: %s" % co.co_kwonlyargcount)
+ lines.append("Number of locals: %s" % co.co_nlocals)
+ lines.append("Stack size: %s" % co.co_stacksize)
+ lines.append("Flags: %s" % pretty_flags(co.co_flags))
+ if co.co_consts:
+ lines.append("Constants:")
+ for i_c in enumerate(co.co_consts):
+ lines.append("%4d: %r" % i_c)
+ if co.co_names:
+ lines.append("Names:")
+ for i_n in enumerate(co.co_names):
+ lines.append("%4d: %s" % i_n)
+ if co.co_varnames:
+ lines.append("Variable names:")
+ for i_n in enumerate(co.co_varnames):
+ lines.append("%4d: %s" % i_n)
+ if co.co_freevars:
+ lines.append("Free variables:")
+ for i_n in enumerate(co.co_freevars):
+ lines.append("%4d: %s" % i_n)
+ if co.co_cellvars:
+ lines.append("Cell variables:")
+ for i_n in enumerate(co.co_cellvars):
+ lines.append("%4d: %s" % i_n)
+ return "\n".join(lines)
+
+def show_code(co, *, file=None):
+ """Print details of methods, functions, or code to *file*.
+
+ If *file* is not provided, the output is printed on stdout.
+ """
+ print(code_info(co), file=file)
+
+_Instruction = collections.namedtuple("_Instruction",
+ "opname opcode arg argval argrepr offset starts_line is_jump_target")
+
+_Instruction.opname.__doc__ = "Human readable name for operation"
+_Instruction.opcode.__doc__ = "Numeric code for operation"
+_Instruction.arg.__doc__ = "Numeric argument to operation (if any), otherwise None"
+_Instruction.argval.__doc__ = "Resolved arg value (if known), otherwise same as arg"
+_Instruction.argrepr.__doc__ = "Human readable description of operation argument"
+_Instruction.offset.__doc__ = "Start index of operation within bytecode sequence"
+_Instruction.starts_line.__doc__ = "Line started by this opcode (if any), otherwise None"
+_Instruction.is_jump_target.__doc__ = "True if other code jumps to here, otherwise False"
+
+_OPNAME_WIDTH = 20
+_OPARG_WIDTH = 5
+
+class Instruction(_Instruction):
+ """Details for a bytecode operation
+
+ Defined fields:
+ opname - human readable name for operation
+ opcode - numeric code for operation
+ arg - numeric argument to operation (if any), otherwise None
+ argval - resolved arg value (if known), otherwise same as arg
+ argrepr - human readable description of operation argument
+ offset - start index of operation within bytecode sequence
+ starts_line - line started by this opcode (if any), otherwise None
+ is_jump_target - True if other code jumps to here, otherwise False
+ """
+
+ def _disassemble(self, lineno_width=3, mark_as_current=False, offset_width=4):
+ """Format instruction details for inclusion in disassembly output
+
+ *lineno_width* sets the width of the line number field (0 omits it)
+ *mark_as_current* inserts a '-->' marker arrow as part of the line
+ *offset_width* sets the width of the instruction offset field
+ """
+ fields = []
+ # Column: Source code line number
+ if lineno_width:
+ if self.starts_line is not None:
+ lineno_fmt = "%%%dd" % lineno_width
+ fields.append(lineno_fmt % self.starts_line)
+ else:
+ fields.append(' ' * lineno_width)
+ # Column: Current instruction indicator
+ if mark_as_current:
+ fields.append('-->')
+ else:
+ fields.append(' ')
+ # Column: Jump target marker
+ if self.is_jump_target:
+ fields.append('>>')
+ else:
+ fields.append(' ')
+ # Column: Instruction offset from start of code sequence
+ fields.append(repr(self.offset).rjust(offset_width))
+ # Column: Opcode name
+ fields.append(self.opname.ljust(_OPNAME_WIDTH))
+ # Column: Opcode argument
+ if self.arg is not None:
+ fields.append(repr(self.arg).rjust(_OPARG_WIDTH))
+ # Column: Opcode argument details
+ if self.argrepr:
+ fields.append('(' + self.argrepr + ')')
+ return ' '.join(fields).rstrip()
+
+
+def get_instructions(x, *, first_line=None):
+ """Iterator for the opcodes in methods, functions or code
+
+ Generates a series of Instruction named tuples giving the details of
+ each operations in the supplied code.
+
+ If *first_line* is not None, it indicates the line number that should
+ be reported for the first source line in the disassembled code.
+ Otherwise, the source line information (if any) is taken directly from
+ the disassembled code object.
+ """
+ co = _get_code_object(x)
+ cell_names = co.co_cellvars + co.co_freevars
+ linestarts = dict(findlinestarts(co))
+ if first_line is not None:
+ line_offset = first_line - co.co_firstlineno
+ else:
+ line_offset = 0
+ return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
+ co.co_consts, cell_names, linestarts,
+ line_offset)
+
+def _get_const_info(const_index, const_list):
+ """Helper to get optional details about const references
+
+ Returns the dereferenced constant and its repr if the constant
+ list is defined.
+ Otherwise returns the constant index and its repr().
+ """
+ argval = const_index
+ if const_list is not None:
+ argval = const_list[const_index]
+ return argval, repr(argval)
+
+def _get_name_info(name_index, name_list):
+ """Helper to get optional details about named references
+
+ Returns the dereferenced name as both value and repr if the name
+ list is defined.
+ Otherwise returns the name index and its repr().
+ """
+ argval = name_index
+ if name_list is not None:
+ argval = name_list[name_index]
+ argrepr = argval
+ else:
+ argrepr = repr(argval)
+ return argval, argrepr
+
+
+def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
+ cells=None, linestarts=None, line_offset=0):
+ """Iterate over the instructions in a bytecode string.
+
+ Generates a sequence of Instruction namedtuples giving the details of each
+ opcode. Additional information about the code's runtime environment
+ (e.g. variable names, constants) can be specified using optional
+ arguments.
+
+ """
+ labels = findlabels(code)
+ starts_line = None
+ for offset, op, arg in _unpack_opargs(code):
+ if linestarts is not None:
+ starts_line = linestarts.get(offset, None)
+ if starts_line is not None:
+ starts_line += line_offset
+ is_jump_target = offset in labels
+ argval = None
+ argrepr = ''
+ if arg is not None:
+ # Set argval to the dereferenced value of the argument when
+ # available, and argrepr to the string representation of argval.
+ # _disassemble_bytes needs the string repr of the
+ # raw name index for LOAD_GLOBAL, LOAD_CONST, etc.
+ argval = arg
+ if op in hasconst:
+ argval, argrepr = _get_const_info(arg, constants)
+ elif op in hasname:
+ argval, argrepr = _get_name_info(arg, names)
+ elif op in hasjrel:
+ argval = offset + 2 + arg
+ argrepr = "to " + repr(argval)
+ elif op in haslocal:
+ argval, argrepr = _get_name_info(arg, varnames)
+ elif op in hascompare:
+ argval = cmp_op[arg]
+ argrepr = argval
+ elif op in hasfree:
+ argval, argrepr = _get_name_info(arg, cells)
+ elif op == FORMAT_VALUE:
+ argval, argrepr = FORMAT_VALUE_CONVERTERS[arg & 0x3]
+ argval = (argval, bool(arg & 0x4))
+ if argval[1]:
+ if argrepr:
+ argrepr += ', '
+ argrepr += 'with format'
+ elif op == MAKE_FUNCTION:
+ argrepr = ', '.join(s for i, s in enumerate(MAKE_FUNCTION_FLAGS)
+ if arg & (1< 0:
+ if depth is not None:
+ depth = depth - 1
+ for x in co.co_consts:
+ if hasattr(x, 'co_code'):
+ print(file=file)
+ print("Disassembly of %r:" % (x,), file=file)
+ _disassemble_recursive(x, file=file, depth=depth)
+
+def _disassemble_bytes(code, lasti=-1, varnames=None, names=None,
+ constants=None, cells=None, linestarts=None,
+ *, file=None, line_offset=0):
+ # Omit the line number column entirely if we have no line number info
+ show_lineno = linestarts is not None
+ if show_lineno:
+ maxlineno = max(linestarts.values()) + line_offset
+ if maxlineno >= 1000:
+ lineno_width = len(str(maxlineno))
+ else:
+ lineno_width = 3
+ else:
+ lineno_width = 0
+ maxoffset = len(code) - 2
+ if maxoffset >= 10000:
+ offset_width = len(str(maxoffset))
+ else:
+ offset_width = 4
+ for instr in _get_instructions_bytes(code, varnames, names,
+ constants, cells, linestarts,
+ line_offset=line_offset):
+ new_source_line = (show_lineno and
+ instr.starts_line is not None and
+ instr.offset > 0)
+ if new_source_line:
+ print(file=file)
+ is_current_instr = instr.offset == lasti
+ print(instr._disassemble(lineno_width, is_current_instr, offset_width),
+ file=file)
+
+def _disassemble_str(source, **kwargs):
+ """Compile the source string, then disassemble the code object."""
+ _disassemble_recursive(_try_compile(source, ''), **kwargs)
+
+disco = disassemble # XXX For backwards compatibility
+
+def _unpack_opargs(code):
+ extended_arg = 0
+ for i in range(0, len(code), 2):
+ op = code[i]
+ if op >= HAVE_ARGUMENT:
+ arg = code[i+1] | extended_arg
+ extended_arg = (arg << 8) if op == EXTENDED_ARG else 0
+ else:
+ arg = None
+ yield (i, op, arg)
+
+def findlabels(code):
+ """Detect all offsets in a byte code which are jump targets.
+
+ Return the list of offsets.
+
+ """
+ labels = []
+ for offset, op, arg in _unpack_opargs(code):
+ if arg is not None:
+ if op in hasjrel:
+ label = offset + 2 + arg
+ elif op in hasjabs:
+ label = arg
+ else:
+ continue
+ if label not in labels:
+ labels.append(label)
+ return labels
+
+def findlinestarts(code):
+ """Find the offsets in a byte code which are start of lines in the source.
+
+ Generate pairs (offset, lineno) as described in Python/compile.c.
+
+ """
+ byte_increments = code.co_lnotab[0::2]
+ line_increments = code.co_lnotab[1::2]
+ bytecode_len = len(code.co_code)
+
+ lastlineno = None
+ lineno = code.co_firstlineno
+ addr = 0
+ for byte_incr, line_incr in zip(byte_increments, line_increments):
+ if byte_incr:
+ if lineno != lastlineno:
+ yield (addr, lineno)
+ lastlineno = lineno
+ addr += byte_incr
+ if addr >= bytecode_len:
+ # The rest of the lnotab byte offsets are past the end of
+ # the bytecode, so the lines were optimized away.
+ return
+ if line_incr >= 0x80:
+ # line_increments is an array of 8-bit signed integers
+ line_incr -= 0x100
+ lineno += line_incr
+ if lineno != lastlineno:
+ yield (addr, lineno)
+
+class Bytecode:
+ """The bytecode operations of a piece of code
+
+ Instantiate this with a function, method, other compiled object, string of
+ code, or a code object (as returned by compile()).
+
+ Iterating over this yields the bytecode operations as Instruction instances.
+ """
+ def __init__(self, x, *, first_line=None, current_offset=None):
+ self.codeobj = co = _get_code_object(x)
+ if first_line is None:
+ self.first_line = co.co_firstlineno
+ self._line_offset = 0
+ else:
+ self.first_line = first_line
+ self._line_offset = first_line - co.co_firstlineno
+ self._cell_names = co.co_cellvars + co.co_freevars
+ self._linestarts = dict(findlinestarts(co))
+ self._original_object = x
+ self.current_offset = current_offset
+
+ def __iter__(self):
+ co = self.codeobj
+ return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,
+ co.co_consts, self._cell_names,
+ self._linestarts,
+ line_offset=self._line_offset)
+
+ def __repr__(self):
+ return "{}({!r})".format(self.__class__.__name__,
+ self._original_object)
+
+ @classmethod
+ def from_traceback(cls, tb):
+ """ Construct a Bytecode from the given traceback """
+ while tb.tb_next:
+ tb = tb.tb_next
+ return cls(tb.tb_frame.f_code, current_offset=tb.tb_lasti)
+
+ def info(self):
+ """Return formatted information about the code object."""
+ return _format_code_info(self.codeobj)
+
+ def dis(self):
+ """Return a formatted view of the bytecode operations."""
+ co = self.codeobj
+ if self.current_offset is not None:
+ offset = self.current_offset
+ else:
+ offset = -1
+ with io.StringIO() as output:
+ _disassemble_bytes(co.co_code, varnames=co.co_varnames,
+ names=co.co_names, constants=co.co_consts,
+ cells=self._cell_names,
+ linestarts=self._linestarts,
+ line_offset=self._line_offset,
+ file=output,
+ lasti=offset)
+ return output.getvalue()
+
+
+def _test():
+ """Simple test program to disassemble a file."""
+ import argparse
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument('infile', type=argparse.FileType('rb'), nargs='?', default='-')
+ args = parser.parse_args()
+ with args.infile as infile:
+ source = infile.read()
+ code = compile(source, args.infile.name, "exec")
+ dis(code)
+
+if __name__ == "__main__":
+ _test()
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/enum.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/enum.py
new file mode 100644
index 0000000000000000000000000000000000000000..3d0b1797aebe0c0653de386454482d549e7c98c7
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/enum.py
@@ -0,0 +1,1018 @@
+import sys
+from types import MappingProxyType, DynamicClassAttribute
+
+
+__all__ = [
+ 'EnumMeta',
+ 'Enum', 'IntEnum', 'Flag', 'IntFlag',
+ 'auto', 'unique',
+ ]
+
+
+def _is_descriptor(obj):
+ """
+ Returns True if obj is a descriptor, False otherwise.
+ """
+ return (
+ hasattr(obj, '__get__') or
+ hasattr(obj, '__set__') or
+ hasattr(obj, '__delete__')
+ )
+
+def _is_dunder(name):
+ """
+ Returns True if a __dunder__ name, False otherwise.
+ """
+ return (
+ len(name) > 4 and
+ name[:2] == name[-2:] == '__' and
+ name[2] != '_' and
+ name[-3] != '_'
+ )
+
+def _is_sunder(name):
+ """
+ Returns True if a _sunder_ name, False otherwise.
+ """
+ return (
+ len(name) > 2 and
+ name[0] == name[-1] == '_' and
+ name[1:2] != '_' and
+ name[-2:-1] != '_'
+ )
+
+def _make_class_unpicklable(cls):
+ """
+ Make the given class un-picklable.
+ """
+ def _break_on_call_reduce(self, proto):
+ raise TypeError('%r cannot be pickled' % self)
+ cls.__reduce_ex__ = _break_on_call_reduce
+ cls.__module__ = ''
+
+_auto_null = object()
+class auto:
+ """
+ Instances are replaced with an appropriate value in Enum class suites.
+ """
+ value = _auto_null
+
+
+class _EnumDict(dict):
+ """
+ Track enum member order and ensure member names are not reused.
+
+ EnumMeta will use the names found in self._member_names as the
+ enumeration member names.
+ """
+ def __init__(self):
+ super().__init__()
+ self._member_names = []
+ self._last_values = []
+ self._ignore = []
+ self._auto_called = False
+
+ def __setitem__(self, key, value):
+ """
+ Changes anything not dundered or not a descriptor.
+
+ If an enum member name is used twice, an error is raised; duplicate
+ values are not checked for.
+
+ Single underscore (sunder) names are reserved.
+ """
+ if _is_sunder(key):
+ if key not in (
+ '_order_', '_create_pseudo_member_',
+ '_generate_next_value_', '_missing_', '_ignore_',
+ ):
+ raise ValueError('_names_ are reserved for future Enum use')
+ if key == '_generate_next_value_':
+ # check if members already defined as auto()
+ if self._auto_called:
+ raise TypeError("_generate_next_value_ must be defined before members")
+ setattr(self, '_generate_next_value', value)
+ elif key == '_ignore_':
+ if isinstance(value, str):
+ value = value.replace(',',' ').split()
+ else:
+ value = list(value)
+ self._ignore = value
+ already = set(value) & set(self._member_names)
+ if already:
+ raise ValueError(
+ '_ignore_ cannot specify already set names: %r'
+ % (already, )
+ )
+ elif _is_dunder(key):
+ if key == '__order__':
+ key = '_order_'
+ elif key in self._member_names:
+ # descriptor overwriting an enum?
+ raise TypeError('Attempted to reuse key: %r' % key)
+ elif key in self._ignore:
+ pass
+ elif not _is_descriptor(value):
+ if key in self:
+ # enum overwriting a descriptor?
+ raise TypeError('%r already defined as: %r' % (key, self[key]))
+ if isinstance(value, auto):
+ if value.value == _auto_null:
+ value.value = self._generate_next_value(
+ key,
+ 1,
+ len(self._member_names),
+ self._last_values[:],
+ )
+ self._auto_called = True
+ value = value.value
+ self._member_names.append(key)
+ self._last_values.append(value)
+ super().__setitem__(key, value)
+
+
+# Dummy value for Enum as EnumMeta explicitly checks for it, but of course
+# until EnumMeta finishes running the first time the Enum class doesn't exist.
+# This is also why there are checks in EnumMeta like `if Enum is not None`
+Enum = None
+
+class EnumMeta(type):
+ """
+ Metaclass for Enum
+ """
+ @classmethod
+ def __prepare__(metacls, cls, bases):
+ # check that previous enum members do not exist
+ metacls._check_for_existing_members(cls, bases)
+ # create the namespace dict
+ enum_dict = _EnumDict()
+ # inherit previous flags and _generate_next_value_ function
+ member_type, first_enum = metacls._get_mixins_(cls, bases)
+ if first_enum is not None:
+ enum_dict['_generate_next_value_'] = getattr(
+ first_enum, '_generate_next_value_', None,
+ )
+ return enum_dict
+
+ def __new__(metacls, cls, bases, classdict):
+ # an Enum class is final once enumeration items have been defined; it
+ # cannot be mixed with other types (int, float, etc.) if it has an
+ # inherited __new__ unless a new __new__ is defined (or the resulting
+ # class will fail).
+ #
+ # remove any keys listed in _ignore_
+ classdict.setdefault('_ignore_', []).append('_ignore_')
+ ignore = classdict['_ignore_']
+ for key in ignore:
+ classdict.pop(key, None)
+ member_type, first_enum = metacls._get_mixins_(cls, bases)
+ __new__, save_new, use_args = metacls._find_new_(
+ classdict, member_type, first_enum,
+ )
+
+ # save enum items into separate mapping so they don't get baked into
+ # the new class
+ enum_members = {k: classdict[k] for k in classdict._member_names}
+ for name in classdict._member_names:
+ del classdict[name]
+
+ # adjust the sunders
+ _order_ = classdict.pop('_order_', None)
+
+ # check for illegal enum names (any others?)
+ invalid_names = set(enum_members) & {'mro', ''}
+ if invalid_names:
+ raise ValueError('Invalid enum member name: {0}'.format(
+ ','.join(invalid_names)))
+
+ # create a default docstring if one has not been provided
+ if '__doc__' not in classdict:
+ classdict['__doc__'] = 'An enumeration.'
+
+ # create our new Enum type
+ enum_class = super().__new__(metacls, cls, bases, classdict)
+ enum_class._member_names_ = [] # names in definition order
+ enum_class._member_map_ = {} # name->value map
+ enum_class._member_type_ = member_type
+
+ # save DynamicClassAttribute attributes from super classes so we know
+ # if we can take the shortcut of storing members in the class dict
+ dynamic_attributes = {
+ k for c in enum_class.mro()
+ for k, v in c.__dict__.items()
+ if isinstance(v, DynamicClassAttribute)
+ }
+
+ # Reverse value->name map for hashable values.
+ enum_class._value2member_map_ = {}
+
+ # If a custom type is mixed into the Enum, and it does not know how
+ # to pickle itself, pickle.dumps will succeed but pickle.loads will
+ # fail. Rather than have the error show up later and possibly far
+ # from the source, sabotage the pickle protocol for this class so
+ # that pickle.dumps also fails.
+ #
+ # However, if the new class implements its own __reduce_ex__, do not
+ # sabotage -- it's on them to make sure it works correctly. We use
+ # __reduce_ex__ instead of any of the others as it is preferred by
+ # pickle over __reduce__, and it handles all pickle protocols.
+ if '__reduce_ex__' not in classdict:
+ if member_type is not object:
+ methods = ('__getnewargs_ex__', '__getnewargs__',
+ '__reduce_ex__', '__reduce__')
+ if not any(m in member_type.__dict__ for m in methods):
+ _make_class_unpicklable(enum_class)
+
+ # instantiate them, checking for duplicates as we go
+ # we instantiate first instead of checking for duplicates first in case
+ # a custom __new__ is doing something funky with the values -- such as
+ # auto-numbering ;)
+ for member_name in classdict._member_names:
+ value = enum_members[member_name]
+ if not isinstance(value, tuple):
+ args = (value, )
+ else:
+ args = value
+ if member_type is tuple: # special case for tuple enums
+ args = (args, ) # wrap it one more time
+ if not use_args:
+ enum_member = __new__(enum_class)
+ if not hasattr(enum_member, '_value_'):
+ enum_member._value_ = value
+ else:
+ enum_member = __new__(enum_class, *args)
+ if not hasattr(enum_member, '_value_'):
+ if member_type is object:
+ enum_member._value_ = value
+ else:
+ enum_member._value_ = member_type(*args)
+ value = enum_member._value_
+ enum_member._name_ = member_name
+ enum_member.__objclass__ = enum_class
+ enum_member.__init__(*args)
+ # If another member with the same value was already defined, the
+ # new member becomes an alias to the existing one.
+ for name, canonical_member in enum_class._member_map_.items():
+ if canonical_member._value_ == enum_member._value_:
+ enum_member = canonical_member
+ break
+ else:
+ # Aliases don't appear in member names (only in __members__).
+ enum_class._member_names_.append(member_name)
+ # performance boost for any member that would not shadow
+ # a DynamicClassAttribute
+ if member_name not in dynamic_attributes:
+ setattr(enum_class, member_name, enum_member)
+ # now add to _member_map_
+ enum_class._member_map_[member_name] = enum_member
+ try:
+ # This may fail if value is not hashable. We can't add the value
+ # to the map, and by-value lookups for this value will be
+ # linear.
+ enum_class._value2member_map_[value] = enum_member
+ except TypeError:
+ pass
+
+ # double check that repr and friends are not the mixin's or various
+ # things break (such as pickle)
+ # however, if the method is defined in the Enum itself, don't replace
+ # it
+ for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'):
+ if name in classdict:
+ continue
+ class_method = getattr(enum_class, name)
+ obj_method = getattr(member_type, name, None)
+ enum_method = getattr(first_enum, name, None)
+ if obj_method is not None and obj_method is class_method:
+ setattr(enum_class, name, enum_method)
+
+ # replace any other __new__ with our own (as long as Enum is not None,
+ # anyway) -- again, this is to support pickle
+ if Enum is not None:
+ # if the user defined their own __new__, save it before it gets
+ # clobbered in case they subclass later
+ if save_new:
+ enum_class.__new_member__ = __new__
+ enum_class.__new__ = Enum.__new__
+
+ # py3 support for definition order (helps keep py2/py3 code in sync)
+ if _order_ is not None:
+ if isinstance(_order_, str):
+ _order_ = _order_.replace(',', ' ').split()
+ if _order_ != enum_class._member_names_:
+ raise TypeError('member order does not match _order_')
+
+ return enum_class
+
+ def __bool__(self):
+ """
+ classes/types should always be True.
+ """
+ return True
+
+ def __call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1):
+ """
+ Either returns an existing member, or creates a new enum class.
+
+ This method is used both when an enum class is given a value to match
+ to an enumeration member (i.e. Color(3)) and for the functional API
+ (i.e. Color = Enum('Color', names='RED GREEN BLUE')).
+
+ When used for the functional API:
+
+ `value` will be the name of the new class.
+
+ `names` should be either a string of white-space/comma delimited names
+ (values will start at `start`), or an iterator/mapping of name, value pairs.
+
+ `module` should be set to the module this class is being created in;
+ if it is not set, an attempt to find that module will be made, but if
+ it fails the class will not be picklable.
+
+ `qualname` should be set to the actual location this class can be found
+ at in its module; by default it is set to the global scope. If this is
+ not correct, unpickling will fail in some circumstances.
+
+ `type`, if set, will be mixed in as the first base class.
+ """
+ if names is None: # simple value lookup
+ return cls.__new__(cls, value)
+ # otherwise, functional API: we're creating a new Enum type
+ return cls._create_(
+ value,
+ names,
+ module=module,
+ qualname=qualname,
+ type=type,
+ start=start,
+ )
+
+ def __contains__(cls, member):
+ if not isinstance(member, Enum):
+ raise TypeError(
+ "unsupported operand type(s) for 'in': '%s' and '%s'" % (
+ type(member).__qualname__, cls.__class__.__qualname__))
+ return isinstance(member, cls) and member._name_ in cls._member_map_
+
+ def __delattr__(cls, attr):
+ # nicer error message when someone tries to delete an attribute
+ # (see issue19025).
+ if attr in cls._member_map_:
+ raise AttributeError("%s: cannot delete Enum member." % cls.__name__)
+ super().__delattr__(attr)
+
+ def __dir__(self):
+ return (
+ ['__class__', '__doc__', '__members__', '__module__']
+ + self._member_names_
+ )
+
+ def __getattr__(cls, name):
+ """
+ Return the enum member matching `name`
+
+ We use __getattr__ instead of descriptors or inserting into the enum
+ class' __dict__ in order to support `name` and `value` being both
+ properties for enum members (which live in the class' __dict__) and
+ enum members themselves.
+ """
+ if _is_dunder(name):
+ raise AttributeError(name)
+ try:
+ return cls._member_map_[name]
+ except KeyError:
+ raise AttributeError(name) from None
+
+ def __getitem__(cls, name):
+ return cls._member_map_[name]
+
+ def __iter__(cls):
+ """
+ Returns members in definition order.
+ """
+ return (cls._member_map_[name] for name in cls._member_names_)
+
+ def __len__(cls):
+ return len(cls._member_names_)
+
+ @property
+ def __members__(cls):
+ """
+ Returns a mapping of member name->value.
+
+ This mapping lists all enum members, including aliases. Note that this
+ is a read-only view of the internal mapping.
+ """
+ return MappingProxyType(cls._member_map_)
+
+ def __repr__(cls):
+ return "" % cls.__name__
+
+ def __reversed__(cls):
+ """
+ Returns members in reverse definition order.
+ """
+ return (cls._member_map_[name] for name in reversed(cls._member_names_))
+
+ def __setattr__(cls, name, value):
+ """
+ Block attempts to reassign Enum members.
+
+ A simple assignment to the class namespace only changes one of the
+ several possible ways to get an Enum member from the Enum class,
+ resulting in an inconsistent Enumeration.
+ """
+ member_map = cls.__dict__.get('_member_map_', {})
+ if name in member_map:
+ raise AttributeError('Cannot reassign members.')
+ super().__setattr__(name, value)
+
+ def _create_(cls, class_name, names, *, module=None, qualname=None, type=None, start=1):
+ """
+ Convenience method to create a new Enum class.
+
+ `names` can be:
+
+ * A string containing member names, separated either with spaces or
+ commas. Values are incremented by 1 from `start`.
+ * An iterable of member names. Values are incremented by 1 from `start`.
+ * An iterable of (member name, value) pairs.
+ * A mapping of member name -> value pairs.
+ """
+ metacls = cls.__class__
+ bases = (cls, ) if type is None else (type, cls)
+ _, first_enum = cls._get_mixins_(cls, bases)
+ classdict = metacls.__prepare__(class_name, bases)
+
+ # special processing needed for names?
+ if isinstance(names, str):
+ names = names.replace(',', ' ').split()
+ if isinstance(names, (tuple, list)) and names and isinstance(names[0], str):
+ original_names, names = names, []
+ last_values = []
+ for count, name in enumerate(original_names):
+ value = first_enum._generate_next_value_(name, start, count, last_values[:])
+ last_values.append(value)
+ names.append((name, value))
+
+ # Here, names is either an iterable of (name, value) or a mapping.
+ for item in names:
+ if isinstance(item, str):
+ member_name, member_value = item, names[item]
+ else:
+ member_name, member_value = item
+ classdict[member_name] = member_value
+ enum_class = metacls.__new__(metacls, class_name, bases, classdict)
+
+ # TODO: replace the frame hack if a blessed way to know the calling
+ # module is ever developed
+ if module is None:
+ try:
+ module = sys._getframe(2).f_globals['__name__']
+ except (AttributeError, ValueError, KeyError) as exc:
+ pass
+ if module is None:
+ _make_class_unpicklable(enum_class)
+ else:
+ enum_class.__module__ = module
+ if qualname is not None:
+ enum_class.__qualname__ = qualname
+
+ return enum_class
+
+ def _convert_(cls, name, module, filter, source=None):
+ """
+ Create a new Enum subclass that replaces a collection of global constants
+ """
+ # convert all constants from source (or module) that pass filter() to
+ # a new Enum called name, and export the enum and its members back to
+ # module;
+ # also, replace the __reduce_ex__ method so unpickling works in
+ # previous Python versions
+ module_globals = vars(sys.modules[module])
+ if source:
+ source = vars(source)
+ else:
+ source = module_globals
+ # _value2member_map_ is populated in the same order every time
+ # for a consistent reverse mapping of number to name when there
+ # are multiple names for the same number.
+ members = [
+ (name, value)
+ for name, value in source.items()
+ if filter(name)]
+ try:
+ # sort by value
+ members.sort(key=lambda t: (t[1], t[0]))
+ except TypeError:
+ # unless some values aren't comparable, in which case sort by name
+ members.sort(key=lambda t: t[0])
+ cls = cls(name, members, module=module)
+ cls.__reduce_ex__ = _reduce_ex_by_name
+ module_globals.update(cls.__members__)
+ module_globals[name] = cls
+ return cls
+
+ def _convert(cls, *args, **kwargs):
+ import warnings
+ warnings.warn("_convert is deprecated and will be removed in 3.9, use "
+ "_convert_ instead.", DeprecationWarning, stacklevel=2)
+ return cls._convert_(*args, **kwargs)
+
+ @staticmethod
+ def _check_for_existing_members(class_name, bases):
+ for chain in bases:
+ for base in chain.__mro__:
+ if issubclass(base, Enum) and base._member_names_:
+ raise TypeError(
+ "%s: cannot extend enumeration %r"
+ % (class_name, base.__name__)
+ )
+
+ @staticmethod
+ def _get_mixins_(class_name, bases):
+ """
+ Returns the type for creating enum members, and the first inherited
+ enum class.
+
+ bases: the tuple of bases that was given to __new__
+ """
+ if not bases:
+ return object, Enum
+
+ def _find_data_type(bases):
+ data_types = []
+ for chain in bases:
+ candidate = None
+ for base in chain.__mro__:
+ if base is object:
+ continue
+ elif issubclass(base, Enum):
+ if base._member_type_ is not object:
+ data_types.append(base._member_type_)
+ break
+ elif '__new__' in base.__dict__:
+ if issubclass(base, Enum):
+ continue
+ data_types.append(candidate or base)
+ break
+ else:
+ candidate = base
+ if len(data_types) > 1:
+ raise TypeError('%r: too many data types: %r' % (class_name, data_types))
+ elif data_types:
+ return data_types[0]
+ else:
+ return None
+
+ # ensure final parent class is an Enum derivative, find any concrete
+ # data type, and check that Enum has no members
+ first_enum = bases[-1]
+ if not issubclass(first_enum, Enum):
+ raise TypeError("new enumerations should be created as "
+ "`EnumName([mixin_type, ...] [data_type,] enum_type)`")
+ member_type = _find_data_type(bases) or object
+ if first_enum._member_names_:
+ raise TypeError("Cannot extend enumerations")
+ return member_type, first_enum
+
+ @staticmethod
+ def _find_new_(classdict, member_type, first_enum):
+ """
+ Returns the __new__ to be used for creating the enum members.
+
+ classdict: the class dictionary given to __new__
+ member_type: the data type whose __new__ will be used by default
+ first_enum: enumeration to check for an overriding __new__
+ """
+ # now find the correct __new__, checking to see of one was defined
+ # by the user; also check earlier enum classes in case a __new__ was
+ # saved as __new_member__
+ __new__ = classdict.get('__new__', None)
+
+ # should __new__ be saved as __new_member__ later?
+ save_new = __new__ is not None
+
+ if __new__ is None:
+ # check all possibles for __new_member__ before falling back to
+ # __new__
+ for method in ('__new_member__', '__new__'):
+ for possible in (member_type, first_enum):
+ target = getattr(possible, method, None)
+ if target not in {
+ None,
+ None.__new__,
+ object.__new__,
+ Enum.__new__,
+ }:
+ __new__ = target
+ break
+ if __new__ is not None:
+ break
+ else:
+ __new__ = object.__new__
+
+ # if a non-object.__new__ is used then whatever value/tuple was
+ # assigned to the enum member name will be passed to __new__ and to the
+ # new enum member's __init__
+ if __new__ is object.__new__:
+ use_args = False
+ else:
+ use_args = True
+ return __new__, save_new, use_args
+
+
+class Enum(metaclass=EnumMeta):
+ """
+ Generic enumeration.
+
+ Derive from this class to define new enumerations.
+ """
+ def __new__(cls, value):
+ # all enum instances are actually created during class construction
+ # without calling this method; this method is called by the metaclass'
+ # __call__ (i.e. Color(3) ), and by pickle
+ if type(value) is cls:
+ # For lookups like Color(Color.RED)
+ return value
+ # by-value search for a matching enum member
+ # see if it's in the reverse mapping (for hashable values)
+ try:
+ return cls._value2member_map_[value]
+ except KeyError:
+ # Not found, no need to do long O(n) search
+ pass
+ except TypeError:
+ # not there, now do long search -- O(n) behavior
+ for member in cls._member_map_.values():
+ if member._value_ == value:
+ return member
+ # still not found -- try _missing_ hook
+ try:
+ exc = None
+ result = cls._missing_(value)
+ except Exception as e:
+ exc = e
+ result = None
+ try:
+ if isinstance(result, cls):
+ return result
+ else:
+ ve_exc = ValueError("%r is not a valid %s" % (value, cls.__name__))
+ if result is None and exc is None:
+ raise ve_exc
+ elif exc is None:
+ exc = TypeError(
+ 'error in %s._missing_: returned %r instead of None or a valid member'
+ % (cls.__name__, result)
+ )
+ exc.__context__ = ve_exc
+ raise exc
+ finally:
+ # ensure all variables that could hold an exception are destroyed
+ exc = None
+ ve_exc = None
+
+ def _generate_next_value_(name, start, count, last_values):
+ """
+ Generate the next value when not given.
+
+ name: the name of the member
+ start: the initial start value or None
+ count: the number of existing members
+ last_value: the last value assigned or None
+ """
+ for last_value in reversed(last_values):
+ try:
+ return last_value + 1
+ except TypeError:
+ pass
+ else:
+ return start
+
+ @classmethod
+ def _missing_(cls, value):
+ return None
+
+ def __repr__(self):
+ return "<%s.%s: %r>" % (
+ self.__class__.__name__, self._name_, self._value_)
+
+ def __str__(self):
+ return "%s.%s" % (self.__class__.__name__, self._name_)
+
+ def __dir__(self):
+ """
+ Returns all members and all public methods
+ """
+ added_behavior = [
+ m
+ for cls in self.__class__.mro()
+ for m in cls.__dict__
+ if m[0] != '_' and m not in self._member_map_
+ ] + [m for m in self.__dict__ if m[0] != '_']
+ return (['__class__', '__doc__', '__module__'] + added_behavior)
+
+ def __format__(self, format_spec):
+ """
+ Returns format using actual value type unless __str__ has been overridden.
+ """
+ # mixed-in Enums should use the mixed-in type's __format__, otherwise
+ # we can get strange results with the Enum name showing up instead of
+ # the value
+
+ # pure Enum branch, or branch with __str__ explicitly overridden
+ str_overridden = type(self).__str__ not in (Enum.__str__, Flag.__str__)
+ if self._member_type_ is object or str_overridden:
+ cls = str
+ val = str(self)
+ # mix-in branch
+ else:
+ cls = self._member_type_
+ val = self._value_
+ return cls.__format__(val, format_spec)
+
+ def __hash__(self):
+ return hash(self._name_)
+
+ def __reduce_ex__(self, proto):
+ return self.__class__, (self._value_, )
+
+ # DynamicClassAttribute is used to provide access to the `name` and
+ # `value` properties of enum members while keeping some measure of
+ # protection from modification, while still allowing for an enumeration
+ # to have members named `name` and `value`. This works because enumeration
+ # members are not set directly on the enum class -- __getattr__ is
+ # used to look them up.
+
+ @DynamicClassAttribute
+ def name(self):
+ """The name of the Enum member."""
+ return self._name_
+
+ @DynamicClassAttribute
+ def value(self):
+ """The value of the Enum member."""
+ return self._value_
+
+
+class IntEnum(int, Enum):
+ """Enum where members are also (and must be) ints"""
+
+
+def _reduce_ex_by_name(self, proto):
+ return self.name
+
+class Flag(Enum):
+ """
+ Support for flags
+ """
+
+ def _generate_next_value_(name, start, count, last_values):
+ """
+ Generate the next value when not given.
+
+ name: the name of the member
+ start: the initial start value or None
+ count: the number of existing members
+ last_value: the last value assigned or None
+ """
+ if not count:
+ return start if start is not None else 1
+ for last_value in reversed(last_values):
+ try:
+ high_bit = _high_bit(last_value)
+ break
+ except Exception:
+ raise TypeError('Invalid Flag value: %r' % last_value) from None
+ return 2 ** (high_bit+1)
+
+ @classmethod
+ def _missing_(cls, value):
+ """
+ Returns member (possibly creating it) if one can be found for value.
+ """
+ original_value = value
+ if value < 0:
+ value = ~value
+ possible_member = cls._create_pseudo_member_(value)
+ if original_value < 0:
+ possible_member = ~possible_member
+ return possible_member
+
+ @classmethod
+ def _create_pseudo_member_(cls, value):
+ """
+ Create a composite member iff value contains only members.
+ """
+ pseudo_member = cls._value2member_map_.get(value, None)
+ if pseudo_member is None:
+ # verify all bits are accounted for
+ _, extra_flags = _decompose(cls, value)
+ if extra_flags:
+ raise ValueError("%r is not a valid %s" % (value, cls.__name__))
+ # construct a singleton enum pseudo-member
+ pseudo_member = object.__new__(cls)
+ pseudo_member._name_ = None
+ pseudo_member._value_ = value
+ # use setdefault in case another thread already created a composite
+ # with this value
+ pseudo_member = cls._value2member_map_.setdefault(value, pseudo_member)
+ return pseudo_member
+
+ def __contains__(self, other):
+ """
+ Returns True if self has at least the same flags set as other.
+ """
+ if not isinstance(other, self.__class__):
+ raise TypeError(
+ "unsupported operand type(s) for 'in': '%s' and '%s'" % (
+ type(other).__qualname__, self.__class__.__qualname__))
+ return other._value_ & self._value_ == other._value_
+
+ def __repr__(self):
+ cls = self.__class__
+ if self._name_ is not None:
+ return '<%s.%s: %r>' % (cls.__name__, self._name_, self._value_)
+ members, uncovered = _decompose(cls, self._value_)
+ return '<%s.%s: %r>' % (
+ cls.__name__,
+ '|'.join([str(m._name_ or m._value_) for m in members]),
+ self._value_,
+ )
+
+ def __str__(self):
+ cls = self.__class__
+ if self._name_ is not None:
+ return '%s.%s' % (cls.__name__, self._name_)
+ members, uncovered = _decompose(cls, self._value_)
+ if len(members) == 1 and members[0]._name_ is None:
+ return '%s.%r' % (cls.__name__, members[0]._value_)
+ else:
+ return '%s.%s' % (
+ cls.__name__,
+ '|'.join([str(m._name_ or m._value_) for m in members]),
+ )
+
+ def __bool__(self):
+ return bool(self._value_)
+
+ def __or__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return self.__class__(self._value_ | other._value_)
+
+ def __and__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return self.__class__(self._value_ & other._value_)
+
+ def __xor__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return self.__class__(self._value_ ^ other._value_)
+
+ def __invert__(self):
+ members, uncovered = _decompose(self.__class__, self._value_)
+ inverted = self.__class__(0)
+ for m in self.__class__:
+ if m not in members and not (m._value_ & self._value_):
+ inverted = inverted | m
+ return self.__class__(inverted)
+
+
+class IntFlag(int, Flag):
+ """
+ Support for integer-based Flags
+ """
+
+ @classmethod
+ def _missing_(cls, value):
+ """
+ Returns member (possibly creating it) if one can be found for value.
+ """
+ if not isinstance(value, int):
+ raise ValueError("%r is not a valid %s" % (value, cls.__name__))
+ new_member = cls._create_pseudo_member_(value)
+ return new_member
+
+ @classmethod
+ def _create_pseudo_member_(cls, value):
+ """
+ Create a composite member iff value contains only members.
+ """
+ pseudo_member = cls._value2member_map_.get(value, None)
+ if pseudo_member is None:
+ need_to_create = [value]
+ # get unaccounted for bits
+ _, extra_flags = _decompose(cls, value)
+ # timer = 10
+ while extra_flags:
+ # timer -= 1
+ bit = _high_bit(extra_flags)
+ flag_value = 2 ** bit
+ if (flag_value not in cls._value2member_map_ and
+ flag_value not in need_to_create
+ ):
+ need_to_create.append(flag_value)
+ if extra_flags == -flag_value:
+ extra_flags = 0
+ else:
+ extra_flags ^= flag_value
+ for value in reversed(need_to_create):
+ # construct singleton pseudo-members
+ pseudo_member = int.__new__(cls, value)
+ pseudo_member._name_ = None
+ pseudo_member._value_ = value
+ # use setdefault in case another thread already created a composite
+ # with this value
+ pseudo_member = cls._value2member_map_.setdefault(value, pseudo_member)
+ return pseudo_member
+
+ def __or__(self, other):
+ if not isinstance(other, (self.__class__, int)):
+ return NotImplemented
+ result = self.__class__(self._value_ | self.__class__(other)._value_)
+ return result
+
+ def __and__(self, other):
+ if not isinstance(other, (self.__class__, int)):
+ return NotImplemented
+ return self.__class__(self._value_ & self.__class__(other)._value_)
+
+ def __xor__(self, other):
+ if not isinstance(other, (self.__class__, int)):
+ return NotImplemented
+ return self.__class__(self._value_ ^ self.__class__(other)._value_)
+
+ __ror__ = __or__
+ __rand__ = __and__
+ __rxor__ = __xor__
+
+ def __invert__(self):
+ result = self.__class__(~self._value_)
+ return result
+
+
+def _high_bit(value):
+ """
+ returns index of highest bit, or -1 if value is zero or negative
+ """
+ return value.bit_length() - 1
+
+def unique(enumeration):
+ """
+ Class decorator for enumerations ensuring unique member values.
+ """
+ duplicates = []
+ for name, member in enumeration.__members__.items():
+ if name != member.name:
+ duplicates.append((name, member.name))
+ if duplicates:
+ alias_details = ', '.join(
+ ["%s -> %s" % (alias, name) for (alias, name) in duplicates])
+ raise ValueError('duplicate values found in %r: %s' %
+ (enumeration, alias_details))
+ return enumeration
+
+def _decompose(flag, value):
+ """
+ Extract all members from the value.
+ """
+ # _decompose is only called if the value is not named
+ not_covered = value
+ negative = value < 0
+ # issue29167: wrap accesses to _value2member_map_ in a list to avoid race
+ # conditions between iterating over it and having more pseudo-
+ # members added to it
+ if negative:
+ # only check for named flags
+ flags_to_check = [
+ (m, v)
+ for v, m in list(flag._value2member_map_.items())
+ if m.name is not None
+ ]
+ else:
+ # check for named flags and powers-of-two flags
+ flags_to_check = [
+ (m, v)
+ for v, m in list(flag._value2member_map_.items())
+ if m.name is not None or _power_of_two(v)
+ ]
+ members = []
+ for member, member_value in flags_to_check:
+ if member_value and member_value & value == member_value:
+ members.append(member)
+ not_covered &= ~member_value
+ if not members and value in flag._value2member_map_:
+ members.append(flag._value2member_map_[value])
+ members.sort(key=lambda m: m._value_, reverse=True)
+ if len(members) > 1 and members[0].value == value:
+ # we have the breakdown, don't need the value member itself
+ members.pop(0)
+ return members, not_covered
+
+def _power_of_two(value):
+ if value < 1:
+ return False
+ return value == 2 ** _high_bit(value)
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/filecmp.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/filecmp.py
new file mode 100644
index 0000000000000000000000000000000000000000..e5ad8397e4c53956c1503d8abba134015da0a24f
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/filecmp.py
@@ -0,0 +1,305 @@
+"""Utilities for comparing files and directories.
+
+Classes:
+ dircmp
+
+Functions:
+ cmp(f1, f2, shallow=True) -> int
+ cmpfiles(a, b, common) -> ([], [], [])
+ clear_cache()
+
+"""
+
+import os
+import stat
+from itertools import filterfalse
+
+__all__ = ['clear_cache', 'cmp', 'dircmp', 'cmpfiles', 'DEFAULT_IGNORES']
+
+_cache = {}
+BUFSIZE = 8*1024
+
+DEFAULT_IGNORES = [
+ 'RCS', 'CVS', 'tags', '.git', '.hg', '.bzr', '_darcs', '__pycache__']
+
+def clear_cache():
+ """Clear the filecmp cache."""
+ _cache.clear()
+
+def cmp(f1, f2, shallow=True):
+ """Compare two files.
+
+ Arguments:
+
+ f1 -- First file name
+
+ f2 -- Second file name
+
+ shallow -- Just check stat signature (do not read the files).
+ defaults to True.
+
+ Return value:
+
+ True if the files are the same, False otherwise.
+
+ This function uses a cache for past comparisons and the results,
+ with cache entries invalidated if their stat information
+ changes. The cache may be cleared by calling clear_cache().
+
+ """
+
+ s1 = _sig(os.stat(f1))
+ s2 = _sig(os.stat(f2))
+ if s1[0] != stat.S_IFREG or s2[0] != stat.S_IFREG:
+ return False
+ if shallow and s1 == s2:
+ return True
+ if s1[1] != s2[1]:
+ return False
+
+ outcome = _cache.get((f1, f2, s1, s2))
+ if outcome is None:
+ outcome = _do_cmp(f1, f2)
+ if len(_cache) > 100: # limit the maximum size of the cache
+ clear_cache()
+ _cache[f1, f2, s1, s2] = outcome
+ return outcome
+
+def _sig(st):
+ return (stat.S_IFMT(st.st_mode),
+ st.st_size,
+ st.st_mtime)
+
+def _do_cmp(f1, f2):
+ bufsize = BUFSIZE
+ with open(f1, 'rb') as fp1, open(f2, 'rb') as fp2:
+ while True:
+ b1 = fp1.read(bufsize)
+ b2 = fp2.read(bufsize)
+ if b1 != b2:
+ return False
+ if not b1:
+ return True
+
+# Directory comparison class.
+#
+class dircmp:
+ """A class that manages the comparison of 2 directories.
+
+ dircmp(a, b, ignore=None, hide=None)
+ A and B are directories.
+ IGNORE is a list of names to ignore,
+ defaults to DEFAULT_IGNORES.
+ HIDE is a list of names to hide,
+ defaults to [os.curdir, os.pardir].
+
+ High level usage:
+ x = dircmp(dir1, dir2)
+ x.report() -> prints a report on the differences between dir1 and dir2
+ or
+ x.report_partial_closure() -> prints report on differences between dir1
+ and dir2, and reports on common immediate subdirectories.
+ x.report_full_closure() -> like report_partial_closure,
+ but fully recursive.
+
+ Attributes:
+ left_list, right_list: The files in dir1 and dir2,
+ filtered by hide and ignore.
+ common: a list of names in both dir1 and dir2.
+ left_only, right_only: names only in dir1, dir2.
+ common_dirs: subdirectories in both dir1 and dir2.
+ common_files: files in both dir1 and dir2.
+ common_funny: names in both dir1 and dir2 where the type differs between
+ dir1 and dir2, or the name is not stat-able.
+ same_files: list of identical files.
+ diff_files: list of filenames which differ.
+ funny_files: list of files which could not be compared.
+ subdirs: a dictionary of dircmp objects, keyed by names in common_dirs.
+ """
+
+ def __init__(self, a, b, ignore=None, hide=None): # Initialize
+ self.left = a
+ self.right = b
+ if hide is None:
+ self.hide = [os.curdir, os.pardir] # Names never to be shown
+ else:
+ self.hide = hide
+ if ignore is None:
+ self.ignore = DEFAULT_IGNORES
+ else:
+ self.ignore = ignore
+
+ def phase0(self): # Compare everything except common subdirectories
+ self.left_list = _filter(os.listdir(self.left),
+ self.hide+self.ignore)
+ self.right_list = _filter(os.listdir(self.right),
+ self.hide+self.ignore)
+ self.left_list.sort()
+ self.right_list.sort()
+
+ def phase1(self): # Compute common names
+ a = dict(zip(map(os.path.normcase, self.left_list), self.left_list))
+ b = dict(zip(map(os.path.normcase, self.right_list), self.right_list))
+ self.common = list(map(a.__getitem__, filter(b.__contains__, a)))
+ self.left_only = list(map(a.__getitem__, filterfalse(b.__contains__, a)))
+ self.right_only = list(map(b.__getitem__, filterfalse(a.__contains__, b)))
+
+ def phase2(self): # Distinguish files, directories, funnies
+ self.common_dirs = []
+ self.common_files = []
+ self.common_funny = []
+
+ for x in self.common:
+ a_path = os.path.join(self.left, x)
+ b_path = os.path.join(self.right, x)
+
+ ok = 1
+ try:
+ a_stat = os.stat(a_path)
+ except OSError as why:
+ # print('Can\'t stat', a_path, ':', why.args[1])
+ ok = 0
+ try:
+ b_stat = os.stat(b_path)
+ except OSError as why:
+ # print('Can\'t stat', b_path, ':', why.args[1])
+ ok = 0
+
+ if ok:
+ a_type = stat.S_IFMT(a_stat.st_mode)
+ b_type = stat.S_IFMT(b_stat.st_mode)
+ if a_type != b_type:
+ self.common_funny.append(x)
+ elif stat.S_ISDIR(a_type):
+ self.common_dirs.append(x)
+ elif stat.S_ISREG(a_type):
+ self.common_files.append(x)
+ else:
+ self.common_funny.append(x)
+ else:
+ self.common_funny.append(x)
+
+ def phase3(self): # Find out differences between common files
+ xx = cmpfiles(self.left, self.right, self.common_files)
+ self.same_files, self.diff_files, self.funny_files = xx
+
+ def phase4(self): # Find out differences between common subdirectories
+ # A new dircmp object is created for each common subdirectory,
+ # these are stored in a dictionary indexed by filename.
+ # The hide and ignore properties are inherited from the parent
+ self.subdirs = {}
+ for x in self.common_dirs:
+ a_x = os.path.join(self.left, x)
+ b_x = os.path.join(self.right, x)
+ self.subdirs[x] = dircmp(a_x, b_x, self.ignore, self.hide)
+
+ def phase4_closure(self): # Recursively call phase4() on subdirectories
+ self.phase4()
+ for sd in self.subdirs.values():
+ sd.phase4_closure()
+
+ def report(self): # Print a report on the differences between a and b
+ # Output format is purposely lousy
+ print('diff', self.left, self.right)
+ if self.left_only:
+ self.left_only.sort()
+ print('Only in', self.left, ':', self.left_only)
+ if self.right_only:
+ self.right_only.sort()
+ print('Only in', self.right, ':', self.right_only)
+ if self.same_files:
+ self.same_files.sort()
+ print('Identical files :', self.same_files)
+ if self.diff_files:
+ self.diff_files.sort()
+ print('Differing files :', self.diff_files)
+ if self.funny_files:
+ self.funny_files.sort()
+ print('Trouble with common files :', self.funny_files)
+ if self.common_dirs:
+ self.common_dirs.sort()
+ print('Common subdirectories :', self.common_dirs)
+ if self.common_funny:
+ self.common_funny.sort()
+ print('Common funny cases :', self.common_funny)
+
+ def report_partial_closure(self): # Print reports on self and on subdirs
+ self.report()
+ for sd in self.subdirs.values():
+ print()
+ sd.report()
+
+ def report_full_closure(self): # Report on self and subdirs recursively
+ self.report()
+ for sd in self.subdirs.values():
+ print()
+ sd.report_full_closure()
+
+ methodmap = dict(subdirs=phase4,
+ same_files=phase3, diff_files=phase3, funny_files=phase3,
+ common_dirs = phase2, common_files=phase2, common_funny=phase2,
+ common=phase1, left_only=phase1, right_only=phase1,
+ left_list=phase0, right_list=phase0)
+
+ def __getattr__(self, attr):
+ if attr not in self.methodmap:
+ raise AttributeError(attr)
+ self.methodmap[attr](self)
+ return getattr(self, attr)
+
+def cmpfiles(a, b, common, shallow=True):
+ """Compare common files in two directories.
+
+ a, b -- directory names
+ common -- list of file names found in both directories
+ shallow -- if true, do comparison based solely on stat() information
+
+ Returns a tuple of three lists:
+ files that compare equal
+ files that are different
+ filenames that aren't regular files.
+
+ """
+ res = ([], [], [])
+ for x in common:
+ ax = os.path.join(a, x)
+ bx = os.path.join(b, x)
+ res[_cmp(ax, bx, shallow)].append(x)
+ return res
+
+
+# Compare two files.
+# Return:
+# 0 for equal
+# 1 for different
+# 2 for funny cases (can't stat, etc.)
+#
+def _cmp(a, b, sh, abs=abs, cmp=cmp):
+ try:
+ return not abs(cmp(a, b, sh))
+ except OSError:
+ return 2
+
+
+# Return a copy with items that occur in skip removed.
+#
+def _filter(flist, skip):
+ return list(filterfalse(skip.__contains__, flist))
+
+
+# Demonstration and testing.
+#
+def demo():
+ import sys
+ import getopt
+ options, args = getopt.getopt(sys.argv[1:], 'r')
+ if len(args) != 2:
+ raise getopt.GetoptError('need exactly two args', None)
+ dd = dircmp(args[0], args[1])
+ if ('-r', '') in options:
+ dd.report_full_closure()
+ else:
+ dd.report()
+
+if __name__ == '__main__':
+ demo()
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/formatter.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/formatter.py
new file mode 100644
index 0000000000000000000000000000000000000000..e2394de8c291952cf960132319d6b59831ea1a18
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/formatter.py
@@ -0,0 +1,452 @@
+"""Generic output formatting.
+
+Formatter objects transform an abstract flow of formatting events into
+specific output events on writer objects. Formatters manage several stack
+structures to allow various properties of a writer object to be changed and
+restored; writers need not be able to handle relative changes nor any sort
+of ``change back'' operation. Specific writer properties which may be
+controlled via formatter objects are horizontal alignment, font, and left
+margin indentations. A mechanism is provided which supports providing
+arbitrary, non-exclusive style settings to a writer as well. Additional
+interfaces facilitate formatting events which are not reversible, such as
+paragraph separation.
+
+Writer objects encapsulate device interfaces. Abstract devices, such as
+file formats, are supported as well as physical devices. The provided
+implementations all work with abstract devices. The interface makes
+available mechanisms for setting the properties which formatter objects
+manage and inserting data into the output.
+"""
+
+import sys
+import warnings
+warnings.warn('the formatter module is deprecated', DeprecationWarning,
+ stacklevel=2)
+
+
+AS_IS = None
+
+
+class NullFormatter:
+ """A formatter which does nothing.
+
+ If the writer parameter is omitted, a NullWriter instance is created.
+ No methods of the writer are called by NullFormatter instances.
+
+ Implementations should inherit from this class if implementing a writer
+ interface but don't need to inherit any implementation.
+
+ """
+
+ def __init__(self, writer=None):
+ if writer is None:
+ writer = NullWriter()
+ self.writer = writer
+ def end_paragraph(self, blankline): pass
+ def add_line_break(self): pass
+ def add_hor_rule(self, *args, **kw): pass
+ def add_label_data(self, format, counter, blankline=None): pass
+ def add_flowing_data(self, data): pass
+ def add_literal_data(self, data): pass
+ def flush_softspace(self): pass
+ def push_alignment(self, align): pass
+ def pop_alignment(self): pass
+ def push_font(self, x): pass
+ def pop_font(self): pass
+ def push_margin(self, margin): pass
+ def pop_margin(self): pass
+ def set_spacing(self, spacing): pass
+ def push_style(self, *styles): pass
+ def pop_style(self, n=1): pass
+ def assert_line_data(self, flag=1): pass
+
+
+class AbstractFormatter:
+ """The standard formatter.
+
+ This implementation has demonstrated wide applicability to many writers,
+ and may be used directly in most circumstances. It has been used to
+ implement a full-featured World Wide Web browser.
+
+ """
+
+ # Space handling policy: blank spaces at the boundary between elements
+ # are handled by the outermost context. "Literal" data is not checked
+ # to determine context, so spaces in literal data are handled directly
+ # in all circumstances.
+
+ def __init__(self, writer):
+ self.writer = writer # Output device
+ self.align = None # Current alignment
+ self.align_stack = [] # Alignment stack
+ self.font_stack = [] # Font state
+ self.margin_stack = [] # Margin state
+ self.spacing = None # Vertical spacing state
+ self.style_stack = [] # Other state, e.g. color
+ self.nospace = 1 # Should leading space be suppressed
+ self.softspace = 0 # Should a space be inserted
+ self.para_end = 1 # Just ended a paragraph
+ self.parskip = 0 # Skipped space between paragraphs?
+ self.hard_break = 1 # Have a hard break
+ self.have_label = 0
+
+ def end_paragraph(self, blankline):
+ if not self.hard_break:
+ self.writer.send_line_break()
+ self.have_label = 0
+ if self.parskip < blankline and not self.have_label:
+ self.writer.send_paragraph(blankline - self.parskip)
+ self.parskip = blankline
+ self.have_label = 0
+ self.hard_break = self.nospace = self.para_end = 1
+ self.softspace = 0
+
+ def add_line_break(self):
+ if not (self.hard_break or self.para_end):
+ self.writer.send_line_break()
+ self.have_label = self.parskip = 0
+ self.hard_break = self.nospace = 1
+ self.softspace = 0
+
+ def add_hor_rule(self, *args, **kw):
+ if not self.hard_break:
+ self.writer.send_line_break()
+ self.writer.send_hor_rule(*args, **kw)
+ self.hard_break = self.nospace = 1
+ self.have_label = self.para_end = self.softspace = self.parskip = 0
+
+ def add_label_data(self, format, counter, blankline = None):
+ if self.have_label or not self.hard_break:
+ self.writer.send_line_break()
+ if not self.para_end:
+ self.writer.send_paragraph((blankline and 1) or 0)
+ if isinstance(format, str):
+ self.writer.send_label_data(self.format_counter(format, counter))
+ else:
+ self.writer.send_label_data(format)
+ self.nospace = self.have_label = self.hard_break = self.para_end = 1
+ self.softspace = self.parskip = 0
+
+ def format_counter(self, format, counter):
+ label = ''
+ for c in format:
+ if c == '1':
+ label = label + ('%d' % counter)
+ elif c in 'aA':
+ if counter > 0:
+ label = label + self.format_letter(c, counter)
+ elif c in 'iI':
+ if counter > 0:
+ label = label + self.format_roman(c, counter)
+ else:
+ label = label + c
+ return label
+
+ def format_letter(self, case, counter):
+ label = ''
+ while counter > 0:
+ counter, x = divmod(counter-1, 26)
+ # This makes a strong assumption that lowercase letters
+ # and uppercase letters form two contiguous blocks, with
+ # letters in order!
+ s = chr(ord(case) + x)
+ label = s + label
+ return label
+
+ def format_roman(self, case, counter):
+ ones = ['i', 'x', 'c', 'm']
+ fives = ['v', 'l', 'd']
+ label, index = '', 0
+ # This will die of IndexError when counter is too big
+ while counter > 0:
+ counter, x = divmod(counter, 10)
+ if x == 9:
+ label = ones[index] + ones[index+1] + label
+ elif x == 4:
+ label = ones[index] + fives[index] + label
+ else:
+ if x >= 5:
+ s = fives[index]
+ x = x-5
+ else:
+ s = ''
+ s = s + ones[index]*x
+ label = s + label
+ index = index + 1
+ if case == 'I':
+ return label.upper()
+ return label
+
+ def add_flowing_data(self, data):
+ if not data: return
+ prespace = data[:1].isspace()
+ postspace = data[-1:].isspace()
+ data = " ".join(data.split())
+ if self.nospace and not data:
+ return
+ elif prespace or self.softspace:
+ if not data:
+ if not self.nospace:
+ self.softspace = 1
+ self.parskip = 0
+ return
+ if not self.nospace:
+ data = ' ' + data
+ self.hard_break = self.nospace = self.para_end = \
+ self.parskip = self.have_label = 0
+ self.softspace = postspace
+ self.writer.send_flowing_data(data)
+
+ def add_literal_data(self, data):
+ if not data: return
+ if self.softspace:
+ self.writer.send_flowing_data(" ")
+ self.hard_break = data[-1:] == '\n'
+ self.nospace = self.para_end = self.softspace = \
+ self.parskip = self.have_label = 0
+ self.writer.send_literal_data(data)
+
+ def flush_softspace(self):
+ if self.softspace:
+ self.hard_break = self.para_end = self.parskip = \
+ self.have_label = self.softspace = 0
+ self.nospace = 1
+ self.writer.send_flowing_data(' ')
+
+ def push_alignment(self, align):
+ if align and align != self.align:
+ self.writer.new_alignment(align)
+ self.align = align
+ self.align_stack.append(align)
+ else:
+ self.align_stack.append(self.align)
+
+ def pop_alignment(self):
+ if self.align_stack:
+ del self.align_stack[-1]
+ if self.align_stack:
+ self.align = align = self.align_stack[-1]
+ self.writer.new_alignment(align)
+ else:
+ self.align = None
+ self.writer.new_alignment(None)
+
+ def push_font(self, font):
+ size, i, b, tt = font
+ if self.softspace:
+ self.hard_break = self.para_end = self.softspace = 0
+ self.nospace = 1
+ self.writer.send_flowing_data(' ')
+ if self.font_stack:
+ csize, ci, cb, ctt = self.font_stack[-1]
+ if size is AS_IS: size = csize
+ if i is AS_IS: i = ci
+ if b is AS_IS: b = cb
+ if tt is AS_IS: tt = ctt
+ font = (size, i, b, tt)
+ self.font_stack.append(font)
+ self.writer.new_font(font)
+
+ def pop_font(self):
+ if self.font_stack:
+ del self.font_stack[-1]
+ if self.font_stack:
+ font = self.font_stack[-1]
+ else:
+ font = None
+ self.writer.new_font(font)
+
+ def push_margin(self, margin):
+ self.margin_stack.append(margin)
+ fstack = [m for m in self.margin_stack if m]
+ if not margin and fstack:
+ margin = fstack[-1]
+ self.writer.new_margin(margin, len(fstack))
+
+ def pop_margin(self):
+ if self.margin_stack:
+ del self.margin_stack[-1]
+ fstack = [m for m in self.margin_stack if m]
+ if fstack:
+ margin = fstack[-1]
+ else:
+ margin = None
+ self.writer.new_margin(margin, len(fstack))
+
+ def set_spacing(self, spacing):
+ self.spacing = spacing
+ self.writer.new_spacing(spacing)
+
+ def push_style(self, *styles):
+ if self.softspace:
+ self.hard_break = self.para_end = self.softspace = 0
+ self.nospace = 1
+ self.writer.send_flowing_data(' ')
+ for style in styles:
+ self.style_stack.append(style)
+ self.writer.new_styles(tuple(self.style_stack))
+
+ def pop_style(self, n=1):
+ del self.style_stack[-n:]
+ self.writer.new_styles(tuple(self.style_stack))
+
+ def assert_line_data(self, flag=1):
+ self.nospace = self.hard_break = not flag
+ self.para_end = self.parskip = self.have_label = 0
+
+
+class NullWriter:
+ """Minimal writer interface to use in testing & inheritance.
+
+ A writer which only provides the interface definition; no actions are
+ taken on any methods. This should be the base class for all writers
+ which do not need to inherit any implementation methods.
+
+ """
+ def __init__(self): pass
+ def flush(self): pass
+ def new_alignment(self, align): pass
+ def new_font(self, font): pass
+ def new_margin(self, margin, level): pass
+ def new_spacing(self, spacing): pass
+ def new_styles(self, styles): pass
+ def send_paragraph(self, blankline): pass
+ def send_line_break(self): pass
+ def send_hor_rule(self, *args, **kw): pass
+ def send_label_data(self, data): pass
+ def send_flowing_data(self, data): pass
+ def send_literal_data(self, data): pass
+
+
+class AbstractWriter(NullWriter):
+ """A writer which can be used in debugging formatters, but not much else.
+
+ Each method simply announces itself by printing its name and
+ arguments on standard output.
+
+ """
+
+ def new_alignment(self, align):
+ print("new_alignment(%r)" % (align,))
+
+ def new_font(self, font):
+ print("new_font(%r)" % (font,))
+
+ def new_margin(self, margin, level):
+ print("new_margin(%r, %d)" % (margin, level))
+
+ def new_spacing(self, spacing):
+ print("new_spacing(%r)" % (spacing,))
+
+ def new_styles(self, styles):
+ print("new_styles(%r)" % (styles,))
+
+ def send_paragraph(self, blankline):
+ print("send_paragraph(%r)" % (blankline,))
+
+ def send_line_break(self):
+ print("send_line_break()")
+
+ def send_hor_rule(self, *args, **kw):
+ print("send_hor_rule()")
+
+ def send_label_data(self, data):
+ print("send_label_data(%r)" % (data,))
+
+ def send_flowing_data(self, data):
+ print("send_flowing_data(%r)" % (data,))
+
+ def send_literal_data(self, data):
+ print("send_literal_data(%r)" % (data,))
+
+
+class DumbWriter(NullWriter):
+ """Simple writer class which writes output on the file object passed in
+ as the file parameter or, if file is omitted, on standard output. The
+ output is simply word-wrapped to the number of columns specified by
+ the maxcol parameter. This class is suitable for reflowing a sequence
+ of paragraphs.
+
+ """
+
+ def __init__(self, file=None, maxcol=72):
+ self.file = file or sys.stdout
+ self.maxcol = maxcol
+ NullWriter.__init__(self)
+ self.reset()
+
+ def reset(self):
+ self.col = 0
+ self.atbreak = 0
+
+ def send_paragraph(self, blankline):
+ self.file.write('\n'*blankline)
+ self.col = 0
+ self.atbreak = 0
+
+ def send_line_break(self):
+ self.file.write('\n')
+ self.col = 0
+ self.atbreak = 0
+
+ def send_hor_rule(self, *args, **kw):
+ self.file.write('\n')
+ self.file.write('-'*self.maxcol)
+ self.file.write('\n')
+ self.col = 0
+ self.atbreak = 0
+
+ def send_literal_data(self, data):
+ self.file.write(data)
+ i = data.rfind('\n')
+ if i >= 0:
+ self.col = 0
+ data = data[i+1:]
+ data = data.expandtabs()
+ self.col = self.col + len(data)
+ self.atbreak = 0
+
+ def send_flowing_data(self, data):
+ if not data: return
+ atbreak = self.atbreak or data[0].isspace()
+ col = self.col
+ maxcol = self.maxcol
+ write = self.file.write
+ for word in data.split():
+ if atbreak:
+ if col + len(word) >= maxcol:
+ write('\n')
+ col = 0
+ else:
+ write(' ')
+ col = col + 1
+ write(word)
+ col = col + len(word)
+ atbreak = 1
+ self.col = col
+ self.atbreak = data[-1].isspace()
+
+
+def test(file = None):
+ w = DumbWriter()
+ f = AbstractFormatter(w)
+ if file is not None:
+ fp = open(file)
+ elif sys.argv[1:]:
+ fp = open(sys.argv[1])
+ else:
+ fp = sys.stdin
+ try:
+ for line in fp:
+ if line == '\n':
+ f.end_paragraph(1)
+ else:
+ f.add_flowing_data(line)
+ finally:
+ if fp is not sys.stdin:
+ fp.close()
+ f.end_paragraph(0)
+
+
+if __name__ == '__main__':
+ test()
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/functools.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/functools.py
new file mode 100644
index 0000000000000000000000000000000000000000..4cde5f590cf29043e8a15ad582001025eb27cf96
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/functools.py
@@ -0,0 +1,976 @@
+"""functools.py - Tools for working with functions and callable objects
+"""
+# Python module wrapper for _functools C module
+# to allow utilities written in Python to be added
+# to the functools module.
+# Written by Nick Coghlan ,
+# Raymond Hettinger ,
+# and Łukasz Langa .
+# Copyright (C) 2006-2013 Python Software Foundation.
+# See C source code for _functools credits/copyright
+
+__all__ = ['update_wrapper', 'wraps', 'WRAPPER_ASSIGNMENTS', 'WRAPPER_UPDATES',
+ 'total_ordering', 'cmp_to_key', 'lru_cache', 'reduce', 'partial',
+ 'partialmethod', 'singledispatch', 'singledispatchmethod',
+ "cached_property"]
+
+from abc import get_cache_token
+from collections import namedtuple
+# import types, weakref # Deferred to single_dispatch()
+from reprlib import recursive_repr
+from _thread import RLock
+
+
+################################################################################
+### update_wrapper() and wraps() decorator
+################################################################################
+
+# update_wrapper() and wraps() are tools to help write
+# wrapper functions that can handle naive introspection
+
+WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',
+ '__annotations__')
+WRAPPER_UPDATES = ('__dict__',)
+def update_wrapper(wrapper,
+ wrapped,
+ assigned = WRAPPER_ASSIGNMENTS,
+ updated = WRAPPER_UPDATES):
+ """Update a wrapper function to look like the wrapped function
+
+ wrapper is the function to be updated
+ wrapped is the original function
+ assigned is a tuple naming the attributes assigned directly
+ from the wrapped function to the wrapper function (defaults to
+ functools.WRAPPER_ASSIGNMENTS)
+ updated is a tuple naming the attributes of the wrapper that
+ are updated with the corresponding attribute from the wrapped
+ function (defaults to functools.WRAPPER_UPDATES)
+ """
+ for attr in assigned:
+ try:
+ value = getattr(wrapped, attr)
+ except AttributeError:
+ pass
+ else:
+ setattr(wrapper, attr, value)
+ for attr in updated:
+ getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
+ # Issue #17482: set __wrapped__ last so we don't inadvertently copy it
+ # from the wrapped function when updating __dict__
+ wrapper.__wrapped__ = wrapped
+ # Return the wrapper so this can be used as a decorator via partial()
+ return wrapper
+
+def wraps(wrapped,
+ assigned = WRAPPER_ASSIGNMENTS,
+ updated = WRAPPER_UPDATES):
+ """Decorator factory to apply update_wrapper() to a wrapper function
+
+ Returns a decorator that invokes update_wrapper() with the decorated
+ function as the wrapper argument and the arguments to wraps() as the
+ remaining arguments. Default arguments are as for update_wrapper().
+ This is a convenience function to simplify applying partial() to
+ update_wrapper().
+ """
+ return partial(update_wrapper, wrapped=wrapped,
+ assigned=assigned, updated=updated)
+
+
+################################################################################
+### total_ordering class decorator
+################################################################################
+
+# The total ordering functions all invoke the root magic method directly
+# rather than using the corresponding operator. This avoids possible
+# infinite recursion that could occur when the operator dispatch logic
+# detects a NotImplemented result and then calls a reflected method.
+
+def _gt_from_lt(self, other, NotImplemented=NotImplemented):
+ 'Return a > b. Computed by @total_ordering from (not a < b) and (a != b).'
+ op_result = self.__lt__(other)
+ if op_result is NotImplemented:
+ return op_result
+ return not op_result and self != other
+
+def _le_from_lt(self, other, NotImplemented=NotImplemented):
+ 'Return a <= b. Computed by @total_ordering from (a < b) or (a == b).'
+ op_result = self.__lt__(other)
+ return op_result or self == other
+
+def _ge_from_lt(self, other, NotImplemented=NotImplemented):
+ 'Return a >= b. Computed by @total_ordering from (not a < b).'
+ op_result = self.__lt__(other)
+ if op_result is NotImplemented:
+ return op_result
+ return not op_result
+
+def _ge_from_le(self, other, NotImplemented=NotImplemented):
+ 'Return a >= b. Computed by @total_ordering from (not a <= b) or (a == b).'
+ op_result = self.__le__(other)
+ if op_result is NotImplemented:
+ return op_result
+ return not op_result or self == other
+
+def _lt_from_le(self, other, NotImplemented=NotImplemented):
+ 'Return a < b. Computed by @total_ordering from (a <= b) and (a != b).'
+ op_result = self.__le__(other)
+ if op_result is NotImplemented:
+ return op_result
+ return op_result and self != other
+
+def _gt_from_le(self, other, NotImplemented=NotImplemented):
+ 'Return a > b. Computed by @total_ordering from (not a <= b).'
+ op_result = self.__le__(other)
+ if op_result is NotImplemented:
+ return op_result
+ return not op_result
+
+def _lt_from_gt(self, other, NotImplemented=NotImplemented):
+ 'Return a < b. Computed by @total_ordering from (not a > b) and (a != b).'
+ op_result = self.__gt__(other)
+ if op_result is NotImplemented:
+ return op_result
+ return not op_result and self != other
+
+def _ge_from_gt(self, other, NotImplemented=NotImplemented):
+ 'Return a >= b. Computed by @total_ordering from (a > b) or (a == b).'
+ op_result = self.__gt__(other)
+ return op_result or self == other
+
+def _le_from_gt(self, other, NotImplemented=NotImplemented):
+ 'Return a <= b. Computed by @total_ordering from (not a > b).'
+ op_result = self.__gt__(other)
+ if op_result is NotImplemented:
+ return op_result
+ return not op_result
+
+def _le_from_ge(self, other, NotImplemented=NotImplemented):
+ 'Return a <= b. Computed by @total_ordering from (not a >= b) or (a == b).'
+ op_result = self.__ge__(other)
+ if op_result is NotImplemented:
+ return op_result
+ return not op_result or self == other
+
+def _gt_from_ge(self, other, NotImplemented=NotImplemented):
+ 'Return a > b. Computed by @total_ordering from (a >= b) and (a != b).'
+ op_result = self.__ge__(other)
+ if op_result is NotImplemented:
+ return op_result
+ return op_result and self != other
+
+def _lt_from_ge(self, other, NotImplemented=NotImplemented):
+ 'Return a < b. Computed by @total_ordering from (not a >= b).'
+ op_result = self.__ge__(other)
+ if op_result is NotImplemented:
+ return op_result
+ return not op_result
+
+_convert = {
+ '__lt__': [('__gt__', _gt_from_lt),
+ ('__le__', _le_from_lt),
+ ('__ge__', _ge_from_lt)],
+ '__le__': [('__ge__', _ge_from_le),
+ ('__lt__', _lt_from_le),
+ ('__gt__', _gt_from_le)],
+ '__gt__': [('__lt__', _lt_from_gt),
+ ('__ge__', _ge_from_gt),
+ ('__le__', _le_from_gt)],
+ '__ge__': [('__le__', _le_from_ge),
+ ('__gt__', _gt_from_ge),
+ ('__lt__', _lt_from_ge)]
+}
+
+def total_ordering(cls):
+ """Class decorator that fills in missing ordering methods"""
+ # Find user-defined comparisons (not those inherited from object).
+ roots = {op for op in _convert if getattr(cls, op, None) is not getattr(object, op, None)}
+ if not roots:
+ raise ValueError('must define at least one ordering operation: < > <= >=')
+ root = max(roots) # prefer __lt__ to __le__ to __gt__ to __ge__
+ for opname, opfunc in _convert[root]:
+ if opname not in roots:
+ opfunc.__name__ = opname
+ setattr(cls, opname, opfunc)
+ return cls
+
+
+################################################################################
+### cmp_to_key() function converter
+################################################################################
+
+def cmp_to_key(mycmp):
+ """Convert a cmp= function into a key= function"""
+ class K(object):
+ __slots__ = ['obj']
+ def __init__(self, obj):
+ self.obj = obj
+ def __lt__(self, other):
+ return mycmp(self.obj, other.obj) < 0
+ def __gt__(self, other):
+ return mycmp(self.obj, other.obj) > 0
+ def __eq__(self, other):
+ return mycmp(self.obj, other.obj) == 0
+ def __le__(self, other):
+ return mycmp(self.obj, other.obj) <= 0
+ def __ge__(self, other):
+ return mycmp(self.obj, other.obj) >= 0
+ __hash__ = None
+ return K
+
+try:
+ from _functools import cmp_to_key
+except ImportError:
+ pass
+
+
+################################################################################
+### reduce() sequence to a single item
+################################################################################
+
+_initial_missing = object()
+
+def reduce(function, sequence, initial=_initial_missing):
+ """
+ reduce(function, sequence[, initial]) -> value
+
+ Apply a function of two arguments cumulatively to the items of a sequence,
+ from left to right, so as to reduce the sequence to a single value.
+ For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
+ ((((1+2)+3)+4)+5). If initial is present, it is placed before the items
+ of the sequence in the calculation, and serves as a default when the
+ sequence is empty.
+ """
+
+ it = iter(sequence)
+
+ if initial is _initial_missing:
+ try:
+ value = next(it)
+ except StopIteration:
+ raise TypeError("reduce() of empty sequence with no initial value") from None
+ else:
+ value = initial
+
+ for element in it:
+ value = function(value, element)
+
+ return value
+
+try:
+ from _functools import reduce
+except ImportError:
+ pass
+
+
+################################################################################
+### partial() argument application
+################################################################################
+
+# Purely functional, no descriptor behaviour
+class partial:
+ """New function with partial application of the given arguments
+ and keywords.
+ """
+
+ __slots__ = "func", "args", "keywords", "__dict__", "__weakref__"
+
+ def __new__(cls, func, /, *args, **keywords):
+ if not callable(func):
+ raise TypeError("the first argument must be callable")
+
+ if hasattr(func, "func"):
+ args = func.args + args
+ keywords = {**func.keywords, **keywords}
+ func = func.func
+
+ self = super(partial, cls).__new__(cls)
+
+ self.func = func
+ self.args = args
+ self.keywords = keywords
+ return self
+
+ def __call__(self, /, *args, **keywords):
+ keywords = {**self.keywords, **keywords}
+ return self.func(*self.args, *args, **keywords)
+
+ @recursive_repr()
+ def __repr__(self):
+ qualname = type(self).__qualname__
+ args = [repr(self.func)]
+ args.extend(repr(x) for x in self.args)
+ args.extend(f"{k}={v!r}" for (k, v) in self.keywords.items())
+ if type(self).__module__ == "functools":
+ return f"functools.{qualname}({', '.join(args)})"
+ return f"{qualname}({', '.join(args)})"
+
+ def __reduce__(self):
+ return type(self), (self.func,), (self.func, self.args,
+ self.keywords or None, self.__dict__ or None)
+
+ def __setstate__(self, state):
+ if not isinstance(state, tuple):
+ raise TypeError("argument to __setstate__ must be a tuple")
+ if len(state) != 4:
+ raise TypeError(f"expected 4 items in state, got {len(state)}")
+ func, args, kwds, namespace = state
+ if (not callable(func) or not isinstance(args, tuple) or
+ (kwds is not None and not isinstance(kwds, dict)) or
+ (namespace is not None and not isinstance(namespace, dict))):
+ raise TypeError("invalid partial state")
+
+ args = tuple(args) # just in case it's a subclass
+ if kwds is None:
+ kwds = {}
+ elif type(kwds) is not dict: # XXX does it need to be *exactly* dict?
+ kwds = dict(kwds)
+ if namespace is None:
+ namespace = {}
+
+ self.__dict__ = namespace
+ self.func = func
+ self.args = args
+ self.keywords = kwds
+
+try:
+ from _functools import partial
+except ImportError:
+ pass
+
+# Descriptor version
+class partialmethod(object):
+ """Method descriptor with partial application of the given arguments
+ and keywords.
+
+ Supports wrapping existing descriptors and handles non-descriptor
+ callables as instance methods.
+ """
+
+ def __init__(*args, **keywords):
+ if len(args) >= 2:
+ self, func, *args = args
+ elif not args:
+ raise TypeError("descriptor '__init__' of partialmethod "
+ "needs an argument")
+ elif 'func' in keywords:
+ func = keywords.pop('func')
+ self, *args = args
+ import warnings
+ warnings.warn("Passing 'func' as keyword argument is deprecated",
+ DeprecationWarning, stacklevel=2)
+ else:
+ raise TypeError("type 'partialmethod' takes at least one argument, "
+ "got %d" % (len(args)-1))
+ args = tuple(args)
+
+ if not callable(func) and not hasattr(func, "__get__"):
+ raise TypeError("{!r} is not callable or a descriptor"
+ .format(func))
+
+ # func could be a descriptor like classmethod which isn't callable,
+ # so we can't inherit from partial (it verifies func is callable)
+ if isinstance(func, partialmethod):
+ # flattening is mandatory in order to place cls/self before all
+ # other arguments
+ # it's also more efficient since only one function will be called
+ self.func = func.func
+ self.args = func.args + args
+ self.keywords = {**func.keywords, **keywords}
+ else:
+ self.func = func
+ self.args = args
+ self.keywords = keywords
+ __init__.__text_signature__ = '($self, func, /, *args, **keywords)'
+
+ def __repr__(self):
+ args = ", ".join(map(repr, self.args))
+ keywords = ", ".join("{}={!r}".format(k, v)
+ for k, v in self.keywords.items())
+ format_string = "{module}.{cls}({func}, {args}, {keywords})"
+ return format_string.format(module=self.__class__.__module__,
+ cls=self.__class__.__qualname__,
+ func=self.func,
+ args=args,
+ keywords=keywords)
+
+ def _make_unbound_method(self):
+ def _method(cls_or_self, /, *args, **keywords):
+ keywords = {**self.keywords, **keywords}
+ return self.func(cls_or_self, *self.args, *args, **keywords)
+ _method.__isabstractmethod__ = self.__isabstractmethod__
+ _method._partialmethod = self
+ return _method
+
+ def __get__(self, obj, cls=None):
+ get = getattr(self.func, "__get__", None)
+ result = None
+ if get is not None:
+ new_func = get(obj, cls)
+ if new_func is not self.func:
+ # Assume __get__ returning something new indicates the
+ # creation of an appropriate callable
+ result = partial(new_func, *self.args, **self.keywords)
+ try:
+ result.__self__ = new_func.__self__
+ except AttributeError:
+ pass
+ if result is None:
+ # If the underlying descriptor didn't do anything, treat this
+ # like an instance method
+ result = self._make_unbound_method().__get__(obj, cls)
+ return result
+
+ @property
+ def __isabstractmethod__(self):
+ return getattr(self.func, "__isabstractmethod__", False)
+
+# Helper functions
+
+def _unwrap_partial(func):
+ while isinstance(func, partial):
+ func = func.func
+ return func
+
+################################################################################
+### LRU Cache function decorator
+################################################################################
+
+_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])
+
+class _HashedSeq(list):
+ """ This class guarantees that hash() will be called no more than once
+ per element. This is important because the lru_cache() will hash
+ the key multiple times on a cache miss.
+
+ """
+
+ __slots__ = 'hashvalue'
+
+ def __init__(self, tup, hash=hash):
+ self[:] = tup
+ self.hashvalue = hash(tup)
+
+ def __hash__(self):
+ return self.hashvalue
+
+def _make_key(args, kwds, typed,
+ kwd_mark = (object(),),
+ fasttypes = {int, str},
+ tuple=tuple, type=type, len=len):
+ """Make a cache key from optionally typed positional and keyword arguments
+
+ The key is constructed in a way that is flat as possible rather than
+ as a nested structure that would take more memory.
+
+ If there is only a single argument and its data type is known to cache
+ its hash value, then that argument is returned without a wrapper. This
+ saves space and improves lookup speed.
+
+ """
+ # All of code below relies on kwds preserving the order input by the user.
+ # Formerly, we sorted() the kwds before looping. The new way is *much*
+ # faster; however, it means that f(x=1, y=2) will now be treated as a
+ # distinct call from f(y=2, x=1) which will be cached separately.
+ key = args
+ if kwds:
+ key += kwd_mark
+ for item in kwds.items():
+ key += item
+ if typed:
+ key += tuple(type(v) for v in args)
+ if kwds:
+ key += tuple(type(v) for v in kwds.values())
+ elif len(key) == 1 and type(key[0]) in fasttypes:
+ return key[0]
+ return _HashedSeq(key)
+
+def lru_cache(maxsize=128, typed=False):
+ """Least-recently-used cache decorator.
+
+ If *maxsize* is set to None, the LRU features are disabled and the cache
+ can grow without bound.
+
+ If *typed* is True, arguments of different types will be cached separately.
+ For example, f(3.0) and f(3) will be treated as distinct calls with
+ distinct results.
+
+ Arguments to the cached function must be hashable.
+
+ View the cache statistics named tuple (hits, misses, maxsize, currsize)
+ with f.cache_info(). Clear the cache and statistics with f.cache_clear().
+ Access the underlying function with f.__wrapped__.
+
+ See: http://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)
+
+ """
+
+ # Users should only access the lru_cache through its public API:
+ # cache_info, cache_clear, and f.__wrapped__
+ # The internals of the lru_cache are encapsulated for thread safety and
+ # to allow the implementation to change (including a possible C version).
+
+ if isinstance(maxsize, int):
+ # Negative maxsize is treated as 0
+ if maxsize < 0:
+ maxsize = 0
+ elif callable(maxsize) and isinstance(typed, bool):
+ # The user_function was passed in directly via the maxsize argument
+ user_function, maxsize = maxsize, 128
+ wrapper = _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo)
+ return update_wrapper(wrapper, user_function)
+ elif maxsize is not None:
+ raise TypeError(
+ 'Expected first argument to be an integer, a callable, or None')
+
+ def decorating_function(user_function):
+ wrapper = _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo)
+ return update_wrapper(wrapper, user_function)
+
+ return decorating_function
+
+def _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo):
+ # Constants shared by all lru cache instances:
+ sentinel = object() # unique object used to signal cache misses
+ make_key = _make_key # build a key from the function arguments
+ PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 # names for the link fields
+
+ cache = {}
+ hits = misses = 0
+ full = False
+ cache_get = cache.get # bound method to lookup a key or return None
+ cache_len = cache.__len__ # get cache size without calling len()
+ lock = RLock() # because linkedlist updates aren't threadsafe
+ root = [] # root of the circular doubly linked list
+ root[:] = [root, root, None, None] # initialize by pointing to self
+
+ if maxsize == 0:
+
+ def wrapper(*args, **kwds):
+ # No caching -- just a statistics update
+ nonlocal misses
+ misses += 1
+ result = user_function(*args, **kwds)
+ return result
+
+ elif maxsize is None:
+
+ def wrapper(*args, **kwds):
+ # Simple caching without ordering or size limit
+ nonlocal hits, misses
+ key = make_key(args, kwds, typed)
+ result = cache_get(key, sentinel)
+ if result is not sentinel:
+ hits += 1
+ return result
+ misses += 1
+ result = user_function(*args, **kwds)
+ cache[key] = result
+ return result
+
+ else:
+
+ def wrapper(*args, **kwds):
+ # Size limited caching that tracks accesses by recency
+ nonlocal root, hits, misses, full
+ key = make_key(args, kwds, typed)
+ with lock:
+ link = cache_get(key)
+ if link is not None:
+ # Move the link to the front of the circular queue
+ link_prev, link_next, _key, result = link
+ link_prev[NEXT] = link_next
+ link_next[PREV] = link_prev
+ last = root[PREV]
+ last[NEXT] = root[PREV] = link
+ link[PREV] = last
+ link[NEXT] = root
+ hits += 1
+ return result
+ misses += 1
+ result = user_function(*args, **kwds)
+ with lock:
+ if key in cache:
+ # Getting here means that this same key was added to the
+ # cache while the lock was released. Since the link
+ # update is already done, we need only return the
+ # computed result and update the count of misses.
+ pass
+ elif full:
+ # Use the old root to store the new key and result.
+ oldroot = root
+ oldroot[KEY] = key
+ oldroot[RESULT] = result
+ # Empty the oldest link and make it the new root.
+ # Keep a reference to the old key and old result to
+ # prevent their ref counts from going to zero during the
+ # update. That will prevent potentially arbitrary object
+ # clean-up code (i.e. __del__) from running while we're
+ # still adjusting the links.
+ root = oldroot[NEXT]
+ oldkey = root[KEY]
+ oldresult = root[RESULT]
+ root[KEY] = root[RESULT] = None
+ # Now update the cache dictionary.
+ del cache[oldkey]
+ # Save the potentially reentrant cache[key] assignment
+ # for last, after the root and links have been put in
+ # a consistent state.
+ cache[key] = oldroot
+ else:
+ # Put result in a new link at the front of the queue.
+ last = root[PREV]
+ link = [last, root, key, result]
+ last[NEXT] = root[PREV] = cache[key] = link
+ # Use the cache_len bound method instead of the len() function
+ # which could potentially be wrapped in an lru_cache itself.
+ full = (cache_len() >= maxsize)
+ return result
+
+ def cache_info():
+ """Report cache statistics"""
+ with lock:
+ return _CacheInfo(hits, misses, maxsize, cache_len())
+
+ def cache_clear():
+ """Clear the cache and cache statistics"""
+ nonlocal hits, misses, full
+ with lock:
+ cache.clear()
+ root[:] = [root, root, None, None]
+ hits = misses = 0
+ full = False
+
+ wrapper.cache_info = cache_info
+ wrapper.cache_clear = cache_clear
+ return wrapper
+
+try:
+ from _functools import _lru_cache_wrapper
+except ImportError:
+ pass
+
+
+################################################################################
+### singledispatch() - single-dispatch generic function decorator
+################################################################################
+
+def _c3_merge(sequences):
+ """Merges MROs in *sequences* to a single MRO using the C3 algorithm.
+
+ Adapted from http://www.python.org/download/releases/2.3/mro/.
+
+ """
+ result = []
+ while True:
+ sequences = [s for s in sequences if s] # purge empty sequences
+ if not sequences:
+ return result
+ for s1 in sequences: # find merge candidates among seq heads
+ candidate = s1[0]
+ for s2 in sequences:
+ if candidate in s2[1:]:
+ candidate = None
+ break # reject the current head, it appears later
+ else:
+ break
+ if candidate is None:
+ raise RuntimeError("Inconsistent hierarchy")
+ result.append(candidate)
+ # remove the chosen candidate
+ for seq in sequences:
+ if seq[0] == candidate:
+ del seq[0]
+
+def _c3_mro(cls, abcs=None):
+ """Computes the method resolution order using extended C3 linearization.
+
+ If no *abcs* are given, the algorithm works exactly like the built-in C3
+ linearization used for method resolution.
+
+ If given, *abcs* is a list of abstract base classes that should be inserted
+ into the resulting MRO. Unrelated ABCs are ignored and don't end up in the
+ result. The algorithm inserts ABCs where their functionality is introduced,
+ i.e. issubclass(cls, abc) returns True for the class itself but returns
+ False for all its direct base classes. Implicit ABCs for a given class
+ (either registered or inferred from the presence of a special method like
+ __len__) are inserted directly after the last ABC explicitly listed in the
+ MRO of said class. If two implicit ABCs end up next to each other in the
+ resulting MRO, their ordering depends on the order of types in *abcs*.
+
+ """
+ for i, base in enumerate(reversed(cls.__bases__)):
+ if hasattr(base, '__abstractmethods__'):
+ boundary = len(cls.__bases__) - i
+ break # Bases up to the last explicit ABC are considered first.
+ else:
+ boundary = 0
+ abcs = list(abcs) if abcs else []
+ explicit_bases = list(cls.__bases__[:boundary])
+ abstract_bases = []
+ other_bases = list(cls.__bases__[boundary:])
+ for base in abcs:
+ if issubclass(cls, base) and not any(
+ issubclass(b, base) for b in cls.__bases__
+ ):
+ # If *cls* is the class that introduces behaviour described by
+ # an ABC *base*, insert said ABC to its MRO.
+ abstract_bases.append(base)
+ for base in abstract_bases:
+ abcs.remove(base)
+ explicit_c3_mros = [_c3_mro(base, abcs=abcs) for base in explicit_bases]
+ abstract_c3_mros = [_c3_mro(base, abcs=abcs) for base in abstract_bases]
+ other_c3_mros = [_c3_mro(base, abcs=abcs) for base in other_bases]
+ return _c3_merge(
+ [[cls]] +
+ explicit_c3_mros + abstract_c3_mros + other_c3_mros +
+ [explicit_bases] + [abstract_bases] + [other_bases]
+ )
+
+def _compose_mro(cls, types):
+ """Calculates the method resolution order for a given class *cls*.
+
+ Includes relevant abstract base classes (with their respective bases) from
+ the *types* iterable. Uses a modified C3 linearization algorithm.
+
+ """
+ bases = set(cls.__mro__)
+ # Remove entries which are already present in the __mro__ or unrelated.
+ def is_related(typ):
+ return (typ not in bases and hasattr(typ, '__mro__')
+ and issubclass(cls, typ))
+ types = [n for n in types if is_related(n)]
+ # Remove entries which are strict bases of other entries (they will end up
+ # in the MRO anyway.
+ def is_strict_base(typ):
+ for other in types:
+ if typ != other and typ in other.__mro__:
+ return True
+ return False
+ types = [n for n in types if not is_strict_base(n)]
+ # Subclasses of the ABCs in *types* which are also implemented by
+ # *cls* can be used to stabilize ABC ordering.
+ type_set = set(types)
+ mro = []
+ for typ in types:
+ found = []
+ for sub in typ.__subclasses__():
+ if sub not in bases and issubclass(cls, sub):
+ found.append([s for s in sub.__mro__ if s in type_set])
+ if not found:
+ mro.append(typ)
+ continue
+ # Favor subclasses with the biggest number of useful bases
+ found.sort(key=len, reverse=True)
+ for sub in found:
+ for subcls in sub:
+ if subcls not in mro:
+ mro.append(subcls)
+ return _c3_mro(cls, abcs=mro)
+
+def _find_impl(cls, registry):
+ """Returns the best matching implementation from *registry* for type *cls*.
+
+ Where there is no registered implementation for a specific type, its method
+ resolution order is used to find a more generic implementation.
+
+ Note: if *registry* does not contain an implementation for the base
+ *object* type, this function may return None.
+
+ """
+ mro = _compose_mro(cls, registry.keys())
+ match = None
+ for t in mro:
+ if match is not None:
+ # If *match* is an implicit ABC but there is another unrelated,
+ # equally matching implicit ABC, refuse the temptation to guess.
+ if (t in registry and t not in cls.__mro__
+ and match not in cls.__mro__
+ and not issubclass(match, t)):
+ raise RuntimeError("Ambiguous dispatch: {} or {}".format(
+ match, t))
+ break
+ if t in registry:
+ match = t
+ return registry.get(match)
+
+def singledispatch(func):
+ """Single-dispatch generic function decorator.
+
+ Transforms a function into a generic function, which can have different
+ behaviours depending upon the type of its first argument. The decorated
+ function acts as the default implementation, and additional
+ implementations can be registered using the register() attribute of the
+ generic function.
+ """
+ # There are many programs that use functools without singledispatch, so we
+ # trade-off making singledispatch marginally slower for the benefit of
+ # making start-up of such applications slightly faster.
+ import types, weakref
+
+ registry = {}
+ dispatch_cache = weakref.WeakKeyDictionary()
+ cache_token = None
+
+ def dispatch(cls):
+ """generic_func.dispatch(cls) ->
+
+ Runs the dispatch algorithm to return the best available implementation
+ for the given *cls* registered on *generic_func*.
+
+ """
+ nonlocal cache_token
+ if cache_token is not None:
+ current_token = get_cache_token()
+ if cache_token != current_token:
+ dispatch_cache.clear()
+ cache_token = current_token
+ try:
+ impl = dispatch_cache[cls]
+ except KeyError:
+ try:
+ impl = registry[cls]
+ except KeyError:
+ impl = _find_impl(cls, registry)
+ dispatch_cache[cls] = impl
+ return impl
+
+ def register(cls, func=None):
+ """generic_func.register(cls, func) -> func
+
+ Registers a new implementation for the given *cls* on a *generic_func*.
+
+ """
+ nonlocal cache_token
+ if func is None:
+ if isinstance(cls, type):
+ return lambda f: register(cls, f)
+ ann = getattr(cls, '__annotations__', {})
+ if not ann:
+ raise TypeError(
+ f"Invalid first argument to `register()`: {cls!r}. "
+ f"Use either `@register(some_class)` or plain `@register` "
+ f"on an annotated function."
+ )
+ func = cls
+
+ # only import typing if annotation parsing is necessary
+ from typing import get_type_hints
+ argname, cls = next(iter(get_type_hints(func).items()))
+ if not isinstance(cls, type):
+ raise TypeError(
+ f"Invalid annotation for {argname!r}. "
+ f"{cls!r} is not a class."
+ )
+ registry[cls] = func
+ if cache_token is None and hasattr(cls, '__abstractmethods__'):
+ cache_token = get_cache_token()
+ dispatch_cache.clear()
+ return func
+
+ def wrapper(*args, **kw):
+ if not args:
+ raise TypeError(f'{funcname} requires at least '
+ '1 positional argument')
+
+ return dispatch(args[0].__class__)(*args, **kw)
+
+ funcname = getattr(func, '__name__', 'singledispatch function')
+ registry[object] = func
+ wrapper.register = register
+ wrapper.dispatch = dispatch
+ wrapper.registry = types.MappingProxyType(registry)
+ wrapper._clear_cache = dispatch_cache.clear
+ update_wrapper(wrapper, func)
+ return wrapper
+
+
+# Descriptor version
+class singledispatchmethod:
+ """Single-dispatch generic method descriptor.
+
+ Supports wrapping existing descriptors and handles non-descriptor
+ callables as instance methods.
+ """
+
+ def __init__(self, func):
+ if not callable(func) and not hasattr(func, "__get__"):
+ raise TypeError(f"{func!r} is not callable or a descriptor")
+
+ self.dispatcher = singledispatch(func)
+ self.func = func
+
+ def register(self, cls, method=None):
+ """generic_method.register(cls, func) -> func
+
+ Registers a new implementation for the given *cls* on a *generic_method*.
+ """
+ return self.dispatcher.register(cls, func=method)
+
+ def __get__(self, obj, cls=None):
+ def _method(*args, **kwargs):
+ method = self.dispatcher.dispatch(args[0].__class__)
+ return method.__get__(obj, cls)(*args, **kwargs)
+
+ _method.__isabstractmethod__ = self.__isabstractmethod__
+ _method.register = self.register
+ update_wrapper(_method, self.func)
+ return _method
+
+ @property
+ def __isabstractmethod__(self):
+ return getattr(self.func, '__isabstractmethod__', False)
+
+
+################################################################################
+### cached_property() - computed once per instance, cached as attribute
+################################################################################
+
+_NOT_FOUND = object()
+
+
+class cached_property:
+ def __init__(self, func):
+ self.func = func
+ self.attrname = None
+ self.__doc__ = func.__doc__
+ self.lock = RLock()
+
+ def __set_name__(self, owner, name):
+ if self.attrname is None:
+ self.attrname = name
+ elif name != self.attrname:
+ raise TypeError(
+ "Cannot assign the same cached_property to two different names "
+ f"({self.attrname!r} and {name!r})."
+ )
+
+ def __get__(self, instance, owner=None):
+ if instance is None:
+ return self
+ if self.attrname is None:
+ raise TypeError(
+ "Cannot use cached_property instance without calling __set_name__ on it.")
+ try:
+ cache = instance.__dict__
+ except AttributeError: # not all objects have __dict__ (e.g. class defines slots)
+ msg = (
+ f"No '__dict__' attribute on {type(instance).__name__!r} "
+ f"instance to cache {self.attrname!r} property."
+ )
+ raise TypeError(msg) from None
+ val = cache.get(self.attrname, _NOT_FOUND)
+ if val is _NOT_FOUND:
+ with self.lock:
+ # check if another thread filled cache while we awaited lock
+ val = cache.get(self.attrname, _NOT_FOUND)
+ if val is _NOT_FOUND:
+ val = self.func(instance)
+ try:
+ cache[self.attrname] = val
+ except TypeError:
+ msg = (
+ f"The '__dict__' attribute on {type(instance).__name__!r} instance "
+ f"does not support item assignment for caching {self.attrname!r} property."
+ )
+ raise TypeError(msg) from None
+ return val
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/getpass.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/getpass.py
new file mode 100644
index 0000000000000000000000000000000000000000..36e17e4cb6965db548f445e8e9f156da27d2109b
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/getpass.py
@@ -0,0 +1,185 @@
+"""Utilities to get a password and/or the current user name.
+
+getpass(prompt[, stream]) - Prompt for a password, with echo turned off.
+getuser() - Get the user name from the environment or password database.
+
+GetPassWarning - This UserWarning is issued when getpass() cannot prevent
+ echoing of the password contents while reading.
+
+On Windows, the msvcrt module will be used.
+
+"""
+
+# Authors: Piers Lauder (original)
+# Guido van Rossum (Windows support and cleanup)
+# Gregory P. Smith (tty support & GetPassWarning)
+
+import contextlib
+import io
+import os
+import sys
+import warnings
+
+__all__ = ["getpass","getuser","GetPassWarning"]
+
+
+class GetPassWarning(UserWarning): pass
+
+
+def unix_getpass(prompt='Password: ', stream=None):
+ """Prompt for a password, with echo turned off.
+
+ Args:
+ prompt: Written on stream to ask for the input. Default: 'Password: '
+ stream: A writable file object to display the prompt. Defaults to
+ the tty. If no tty is available defaults to sys.stderr.
+ Returns:
+ The seKr3t input.
+ Raises:
+ EOFError: If our input tty or stdin was closed.
+ GetPassWarning: When we were unable to turn echo off on the input.
+
+ Always restores terminal settings before returning.
+ """
+ passwd = None
+ with contextlib.ExitStack() as stack:
+ try:
+ # Always try reading and writing directly on the tty first.
+ fd = os.open('/dev/tty', os.O_RDWR|os.O_NOCTTY)
+ tty = io.FileIO(fd, 'w+')
+ stack.enter_context(tty)
+ input = io.TextIOWrapper(tty)
+ stack.enter_context(input)
+ if not stream:
+ stream = input
+ except OSError as e:
+ # If that fails, see if stdin can be controlled.
+ stack.close()
+ try:
+ fd = sys.stdin.fileno()
+ except (AttributeError, ValueError):
+ fd = None
+ passwd = fallback_getpass(prompt, stream)
+ input = sys.stdin
+ if not stream:
+ stream = sys.stderr
+
+ if fd is not None:
+ try:
+ old = termios.tcgetattr(fd) # a copy to save
+ new = old[:]
+ new[3] &= ~termios.ECHO # 3 == 'lflags'
+ tcsetattr_flags = termios.TCSAFLUSH
+ if hasattr(termios, 'TCSASOFT'):
+ tcsetattr_flags |= termios.TCSASOFT
+ try:
+ termios.tcsetattr(fd, tcsetattr_flags, new)
+ passwd = _raw_input(prompt, stream, input=input)
+ finally:
+ termios.tcsetattr(fd, tcsetattr_flags, old)
+ stream.flush() # issue7208
+ except termios.error:
+ if passwd is not None:
+ # _raw_input succeeded. The final tcsetattr failed. Reraise
+ # instead of leaving the terminal in an unknown state.
+ raise
+ # We can't control the tty or stdin. Give up and use normal IO.
+ # fallback_getpass() raises an appropriate warning.
+ if stream is not input:
+ # clean up unused file objects before blocking
+ stack.close()
+ passwd = fallback_getpass(prompt, stream)
+
+ stream.write('\n')
+ return passwd
+
+
+def win_getpass(prompt='Password: ', stream=None):
+ """Prompt for password with echo off, using Windows getch()."""
+ if sys.stdin is not sys.__stdin__:
+ return fallback_getpass(prompt, stream)
+
+ for c in prompt:
+ msvcrt.putwch(c)
+ pw = ""
+ while 1:
+ c = msvcrt.getwch()
+ if c == '\r' or c == '\n':
+ break
+ if c == '\003':
+ raise KeyboardInterrupt
+ if c == '\b':
+ pw = pw[:-1]
+ else:
+ pw = pw + c
+ msvcrt.putwch('\r')
+ msvcrt.putwch('\n')
+ return pw
+
+
+def fallback_getpass(prompt='Password: ', stream=None):
+ warnings.warn("Can not control echo on the terminal.", GetPassWarning,
+ stacklevel=2)
+ if not stream:
+ stream = sys.stderr
+ print("Warning: Password input may be echoed.", file=stream)
+ return _raw_input(prompt, stream)
+
+
+def _raw_input(prompt="", stream=None, input=None):
+ # This doesn't save the string in the GNU readline history.
+ if not stream:
+ stream = sys.stderr
+ if not input:
+ input = sys.stdin
+ prompt = str(prompt)
+ if prompt:
+ try:
+ stream.write(prompt)
+ except UnicodeEncodeError:
+ # Use replace error handler to get as much as possible printed.
+ prompt = prompt.encode(stream.encoding, 'replace')
+ prompt = prompt.decode(stream.encoding)
+ stream.write(prompt)
+ stream.flush()
+ # NOTE: The Python C API calls flockfile() (and unlock) during readline.
+ line = input.readline()
+ if not line:
+ raise EOFError
+ if line[-1] == '\n':
+ line = line[:-1]
+ return line
+
+
+def getuser():
+ """Get the username from the environment or password database.
+
+ First try various environment variables, then the password
+ database. This works on Windows as long as USERNAME is set.
+
+ """
+
+ for name in ('LOGNAME', 'USER', 'LNAME', 'USERNAME'):
+ user = os.environ.get(name)
+ if user:
+ return user
+
+ # If this fails, the exception will "explain" why
+ import pwd
+ return pwd.getpwuid(os.getuid())[0]
+
+# Bind the name getpass to the appropriate function
+try:
+ import termios
+ # it's possible there is an incompatible termios from the
+ # McMillan Installer, make sure we have a UNIX-compatible termios
+ termios.tcgetattr, termios.tcsetattr
+except (ImportError, AttributeError):
+ try:
+ import msvcrt
+ except ImportError:
+ getpass = fallback_getpass
+ else:
+ getpass = win_getpass
+else:
+ getpass = unix_getpass
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/gettext.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/gettext.py
new file mode 100644
index 0000000000000000000000000000000000000000..b98f501884b75a4e7d14ca124ad672938a99e541
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/gettext.py
@@ -0,0 +1,782 @@
+"""Internationalization and localization support.
+
+This module provides internationalization (I18N) and localization (L10N)
+support for your Python programs by providing an interface to the GNU gettext
+message catalog library.
+
+I18N refers to the operation by which a program is made aware of multiple
+languages. L10N refers to the adaptation of your program, once
+internationalized, to the local language and cultural habits.
+
+"""
+
+# This module represents the integration of work, contributions, feedback, and
+# suggestions from the following people:
+#
+# Martin von Loewis, who wrote the initial implementation of the underlying
+# C-based libintlmodule (later renamed _gettext), along with a skeletal
+# gettext.py implementation.
+#
+# Peter Funk, who wrote fintl.py, a fairly complete wrapper around intlmodule,
+# which also included a pure-Python implementation to read .mo files if
+# intlmodule wasn't available.
+#
+# James Henstridge, who also wrote a gettext.py module, which has some
+# interesting, but currently unsupported experimental features: the notion of
+# a Catalog class and instances, and the ability to add to a catalog file via
+# a Python API.
+#
+# Barry Warsaw integrated these modules, wrote the .install() API and code,
+# and conformed all C and Python code to Python's coding standards.
+#
+# Francois Pinard and Marc-Andre Lemburg also contributed valuably to this
+# module.
+#
+# J. David Ibanez implemented plural forms. Bruno Haible fixed some bugs.
+#
+# TODO:
+# - Lazy loading of .mo files. Currently the entire catalog is loaded into
+# memory, but that's probably bad for large translated programs. Instead,
+# the lexical sort of original strings in GNU .mo files should be exploited
+# to do binary searches and lazy initializations. Or you might want to use
+# the undocumented double-hash algorithm for .mo files with hash tables, but
+# you'll need to study the GNU gettext code to do this.
+#
+# - Support Solaris .mo file formats. Unfortunately, we've been unable to
+# find this format documented anywhere.
+
+
+import locale
+import os
+import re
+import sys
+
+
+__all__ = ['NullTranslations', 'GNUTranslations', 'Catalog',
+ 'find', 'translation', 'install', 'textdomain', 'bindtextdomain',
+ 'bind_textdomain_codeset',
+ 'dgettext', 'dngettext', 'gettext', 'lgettext', 'ldgettext',
+ 'ldngettext', 'lngettext', 'ngettext',
+ 'pgettext', 'dpgettext', 'npgettext', 'dnpgettext',
+ ]
+
+_default_localedir = os.path.join(sys.base_prefix, 'share', 'locale')
+
+# Expression parsing for plural form selection.
+#
+# The gettext library supports a small subset of C syntax. The only
+# incompatible difference is that integer literals starting with zero are
+# decimal.
+#
+# https://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms
+# http://git.savannah.gnu.org/cgit/gettext.git/tree/gettext-runtime/intl/plural.y
+
+_token_pattern = re.compile(r"""
+ (?P[ \t]+) | # spaces and horizontal tabs
+ (?P[0-9]+\b) | # decimal integer
+ (?Pn\b) | # only n is allowed
+ (?P[()]) |
+ (?P[-*/%+?:]|[>,
+ # <=, >=, ==, !=, &&, ||,
+ # ? :
+ # unary and bitwise ops
+ # not allowed
+ (?P\w+|.) # invalid token
+ """, re.VERBOSE|re.DOTALL)
+
+def _tokenize(plural):
+ for mo in re.finditer(_token_pattern, plural):
+ kind = mo.lastgroup
+ if kind == 'WHITESPACES':
+ continue
+ value = mo.group(kind)
+ if kind == 'INVALID':
+ raise ValueError('invalid token in plural form: %s' % value)
+ yield value
+ yield ''
+
+def _error(value):
+ if value:
+ return ValueError('unexpected token in plural form: %s' % value)
+ else:
+ return ValueError('unexpected end of plural form')
+
+_binary_ops = (
+ ('||',),
+ ('&&',),
+ ('==', '!='),
+ ('<', '>', '<=', '>='),
+ ('+', '-'),
+ ('*', '/', '%'),
+)
+_binary_ops = {op: i for i, ops in enumerate(_binary_ops, 1) for op in ops}
+_c2py_ops = {'||': 'or', '&&': 'and', '/': '//'}
+
+def _parse(tokens, priority=-1):
+ result = ''
+ nexttok = next(tokens)
+ while nexttok == '!':
+ result += 'not '
+ nexttok = next(tokens)
+
+ if nexttok == '(':
+ sub, nexttok = _parse(tokens)
+ result = '%s(%s)' % (result, sub)
+ if nexttok != ')':
+ raise ValueError('unbalanced parenthesis in plural form')
+ elif nexttok == 'n':
+ result = '%s%s' % (result, nexttok)
+ else:
+ try:
+ value = int(nexttok, 10)
+ except ValueError:
+ raise _error(nexttok) from None
+ result = '%s%d' % (result, value)
+ nexttok = next(tokens)
+
+ j = 100
+ while nexttok in _binary_ops:
+ i = _binary_ops[nexttok]
+ if i < priority:
+ break
+ # Break chained comparisons
+ if i in (3, 4) and j in (3, 4): # '==', '!=', '<', '>', '<=', '>='
+ result = '(%s)' % result
+ # Replace some C operators by their Python equivalents
+ op = _c2py_ops.get(nexttok, nexttok)
+ right, nexttok = _parse(tokens, i + 1)
+ result = '%s %s %s' % (result, op, right)
+ j = i
+ if j == priority == 4: # '<', '>', '<=', '>='
+ result = '(%s)' % result
+
+ if nexttok == '?' and priority <= 0:
+ if_true, nexttok = _parse(tokens, 0)
+ if nexttok != ':':
+ raise _error(nexttok)
+ if_false, nexttok = _parse(tokens)
+ result = '%s if %s else %s' % (if_true, result, if_false)
+ if priority == 0:
+ result = '(%s)' % result
+
+ return result, nexttok
+
+def _as_int(n):
+ try:
+ i = round(n)
+ except TypeError:
+ raise TypeError('Plural value must be an integer, got %s' %
+ (n.__class__.__name__,)) from None
+ import warnings
+ warnings.warn('Plural value must be an integer, got %s' %
+ (n.__class__.__name__,),
+ DeprecationWarning, 4)
+ return n
+
+def c2py(plural):
+ """Gets a C expression as used in PO files for plural forms and returns a
+ Python function that implements an equivalent expression.
+ """
+
+ if len(plural) > 1000:
+ raise ValueError('plural form expression is too long')
+ try:
+ result, nexttok = _parse(_tokenize(plural))
+ if nexttok:
+ raise _error(nexttok)
+
+ depth = 0
+ for c in result:
+ if c == '(':
+ depth += 1
+ if depth > 20:
+ # Python compiler limit is about 90.
+ # The most complex example has 2.
+ raise ValueError('plural form expression is too complex')
+ elif c == ')':
+ depth -= 1
+
+ ns = {'_as_int': _as_int}
+ exec('''if True:
+ def func(n):
+ if not isinstance(n, int):
+ n = _as_int(n)
+ return int(%s)
+ ''' % result, ns)
+ return ns['func']
+ except RecursionError:
+ # Recursion error can be raised in _parse() or exec().
+ raise ValueError('plural form expression is too complex')
+
+
+def _expand_lang(loc):
+ loc = locale.normalize(loc)
+ COMPONENT_CODESET = 1 << 0
+ COMPONENT_TERRITORY = 1 << 1
+ COMPONENT_MODIFIER = 1 << 2
+ # split up the locale into its base components
+ mask = 0
+ pos = loc.find('@')
+ if pos >= 0:
+ modifier = loc[pos:]
+ loc = loc[:pos]
+ mask |= COMPONENT_MODIFIER
+ else:
+ modifier = ''
+ pos = loc.find('.')
+ if pos >= 0:
+ codeset = loc[pos:]
+ loc = loc[:pos]
+ mask |= COMPONENT_CODESET
+ else:
+ codeset = ''
+ pos = loc.find('_')
+ if pos >= 0:
+ territory = loc[pos:]
+ loc = loc[:pos]
+ mask |= COMPONENT_TERRITORY
+ else:
+ territory = ''
+ language = loc
+ ret = []
+ for i in range(mask+1):
+ if not (i & ~mask): # if all components for this combo exist ...
+ val = language
+ if i & COMPONENT_TERRITORY: val += territory
+ if i & COMPONENT_CODESET: val += codeset
+ if i & COMPONENT_MODIFIER: val += modifier
+ ret.append(val)
+ ret.reverse()
+ return ret
+
+
+
+class NullTranslations:
+ def __init__(self, fp=None):
+ self._info = {}
+ self._charset = None
+ self._output_charset = None
+ self._fallback = None
+ if fp is not None:
+ self._parse(fp)
+
+ def _parse(self, fp):
+ pass
+
+ def add_fallback(self, fallback):
+ if self._fallback:
+ self._fallback.add_fallback(fallback)
+ else:
+ self._fallback = fallback
+
+ def gettext(self, message):
+ if self._fallback:
+ return self._fallback.gettext(message)
+ return message
+
+ def lgettext(self, message):
+ import warnings
+ warnings.warn('lgettext() is deprecated, use gettext() instead',
+ DeprecationWarning, 2)
+ if self._fallback:
+ with warnings.catch_warnings():
+ warnings.filterwarnings('ignore', r'.*\blgettext\b.*',
+ DeprecationWarning)
+ return self._fallback.lgettext(message)
+ if self._output_charset:
+ return message.encode(self._output_charset)
+ return message.encode(locale.getpreferredencoding())
+
+ def ngettext(self, msgid1, msgid2, n):
+ if self._fallback:
+ return self._fallback.ngettext(msgid1, msgid2, n)
+ if n == 1:
+ return msgid1
+ else:
+ return msgid2
+
+ def lngettext(self, msgid1, msgid2, n):
+ import warnings
+ warnings.warn('lngettext() is deprecated, use ngettext() instead',
+ DeprecationWarning, 2)
+ if self._fallback:
+ with warnings.catch_warnings():
+ warnings.filterwarnings('ignore', r'.*\blngettext\b.*',
+ DeprecationWarning)
+ return self._fallback.lngettext(msgid1, msgid2, n)
+ if n == 1:
+ tmsg = msgid1
+ else:
+ tmsg = msgid2
+ if self._output_charset:
+ return tmsg.encode(self._output_charset)
+ return tmsg.encode(locale.getpreferredencoding())
+
+ def pgettext(self, context, message):
+ if self._fallback:
+ return self._fallback.pgettext(context, message)
+ return message
+
+ def npgettext(self, context, msgid1, msgid2, n):
+ if self._fallback:
+ return self._fallback.npgettext(context, msgid1, msgid2, n)
+ if n == 1:
+ return msgid1
+ else:
+ return msgid2
+
+ def info(self):
+ return self._info
+
+ def charset(self):
+ return self._charset
+
+ def output_charset(self):
+ import warnings
+ warnings.warn('output_charset() is deprecated',
+ DeprecationWarning, 2)
+ return self._output_charset
+
+ def set_output_charset(self, charset):
+ import warnings
+ warnings.warn('set_output_charset() is deprecated',
+ DeprecationWarning, 2)
+ self._output_charset = charset
+
+ def install(self, names=None):
+ import builtins
+ builtins.__dict__['_'] = self.gettext
+ if names is not None:
+ allowed = {'gettext', 'lgettext', 'lngettext',
+ 'ngettext', 'npgettext', 'pgettext'}
+ for name in allowed & set(names):
+ builtins.__dict__[name] = getattr(self, name)
+
+
+class GNUTranslations(NullTranslations):
+ # Magic number of .mo files
+ LE_MAGIC = 0x950412de
+ BE_MAGIC = 0xde120495
+
+ # The encoding of a msgctxt and a msgid in a .mo file is
+ # msgctxt + "\x04" + msgid (gettext version >= 0.15)
+ CONTEXT = "%s\x04%s"
+
+ # Acceptable .mo versions
+ VERSIONS = (0, 1)
+
+ def _get_versions(self, version):
+ """Returns a tuple of major version, minor version"""
+ return (version >> 16, version & 0xffff)
+
+ def _parse(self, fp):
+ """Override this method to support alternative .mo formats."""
+ # Delay struct import for speeding up gettext import when .mo files
+ # are not used.
+ from struct import unpack
+ filename = getattr(fp, 'name', '')
+ # Parse the .mo file header, which consists of 5 little endian 32
+ # bit words.
+ self._catalog = catalog = {}
+ self.plural = lambda n: int(n != 1) # germanic plural by default
+ buf = fp.read()
+ buflen = len(buf)
+ # Are we big endian or little endian?
+ magic = unpack('4I', buf[4:20])
+ ii = '>II'
+ else:
+ raise OSError(0, 'Bad magic number', filename)
+
+ major_version, minor_version = self._get_versions(version)
+
+ if major_version not in self.VERSIONS:
+ raise OSError(0, 'Bad version number ' + str(major_version), filename)
+
+ # Now put all messages from the .mo file buffer into the catalog
+ # dictionary.
+ for i in range(0, msgcount):
+ mlen, moff = unpack(ii, buf[masteridx:masteridx+8])
+ mend = moff + mlen
+ tlen, toff = unpack(ii, buf[transidx:transidx+8])
+ tend = toff + tlen
+ if mend < buflen and tend < buflen:
+ msg = buf[moff:mend]
+ tmsg = buf[toff:tend]
+ else:
+ raise OSError(0, 'File is corrupt', filename)
+ # See if we're looking at GNU .mo conventions for metadata
+ if mlen == 0:
+ # Catalog description
+ lastk = None
+ for b_item in tmsg.split(b'\n'):
+ item = b_item.decode().strip()
+ if not item:
+ continue
+ # Skip over comment lines:
+ if item.startswith('#-#-#-#-#') and item.endswith('#-#-#-#-#'):
+ continue
+ k = v = None
+ if ':' in item:
+ k, v = item.split(':', 1)
+ k = k.strip().lower()
+ v = v.strip()
+ self._info[k] = v
+ lastk = k
+ elif lastk:
+ self._info[lastk] += '\n' + item
+ if k == 'content-type':
+ self._charset = v.split('charset=')[1]
+ elif k == 'plural-forms':
+ v = v.split(';')
+ plural = v[1].split('plural=')[1]
+ self.plural = c2py(plural)
+ # Note: we unconditionally convert both msgids and msgstrs to
+ # Unicode using the character encoding specified in the charset
+ # parameter of the Content-Type header. The gettext documentation
+ # strongly encourages msgids to be us-ascii, but some applications
+ # require alternative encodings (e.g. Zope's ZCML and ZPT). For
+ # traditional gettext applications, the msgid conversion will
+ # cause no problems since us-ascii should always be a subset of
+ # the charset encoding. We may want to fall back to 8-bit msgids
+ # if the Unicode conversion fails.
+ charset = self._charset or 'ascii'
+ if b'\x00' in msg:
+ # Plural forms
+ msgid1, msgid2 = msg.split(b'\x00')
+ tmsg = tmsg.split(b'\x00')
+ msgid1 = str(msgid1, charset)
+ for i, x in enumerate(tmsg):
+ catalog[(msgid1, i)] = str(x, charset)
+ else:
+ catalog[str(msg, charset)] = str(tmsg, charset)
+ # advance to next entry in the seek tables
+ masteridx += 8
+ transidx += 8
+
+ def lgettext(self, message):
+ import warnings
+ warnings.warn('lgettext() is deprecated, use gettext() instead',
+ DeprecationWarning, 2)
+ missing = object()
+ tmsg = self._catalog.get(message, missing)
+ if tmsg is missing:
+ if self._fallback:
+ return self._fallback.lgettext(message)
+ tmsg = message
+ if self._output_charset:
+ return tmsg.encode(self._output_charset)
+ return tmsg.encode(locale.getpreferredencoding())
+
+ def lngettext(self, msgid1, msgid2, n):
+ import warnings
+ warnings.warn('lngettext() is deprecated, use ngettext() instead',
+ DeprecationWarning, 2)
+ try:
+ tmsg = self._catalog[(msgid1, self.plural(n))]
+ except KeyError:
+ if self._fallback:
+ return self._fallback.lngettext(msgid1, msgid2, n)
+ if n == 1:
+ tmsg = msgid1
+ else:
+ tmsg = msgid2
+ if self._output_charset:
+ return tmsg.encode(self._output_charset)
+ return tmsg.encode(locale.getpreferredencoding())
+
+ def gettext(self, message):
+ missing = object()
+ tmsg = self._catalog.get(message, missing)
+ if tmsg is missing:
+ if self._fallback:
+ return self._fallback.gettext(message)
+ return message
+ return tmsg
+
+ def ngettext(self, msgid1, msgid2, n):
+ try:
+ tmsg = self._catalog[(msgid1, self.plural(n))]
+ except KeyError:
+ if self._fallback:
+ return self._fallback.ngettext(msgid1, msgid2, n)
+ if n == 1:
+ tmsg = msgid1
+ else:
+ tmsg = msgid2
+ return tmsg
+
+ def pgettext(self, context, message):
+ ctxt_msg_id = self.CONTEXT % (context, message)
+ missing = object()
+ tmsg = self._catalog.get(ctxt_msg_id, missing)
+ if tmsg is missing:
+ if self._fallback:
+ return self._fallback.pgettext(context, message)
+ return message
+ return tmsg
+
+ def npgettext(self, context, msgid1, msgid2, n):
+ ctxt_msg_id = self.CONTEXT % (context, msgid1)
+ try:
+ tmsg = self._catalog[ctxt_msg_id, self.plural(n)]
+ except KeyError:
+ if self._fallback:
+ return self._fallback.npgettext(context, msgid1, msgid2, n)
+ if n == 1:
+ tmsg = msgid1
+ else:
+ tmsg = msgid2
+ return tmsg
+
+
+# Locate a .mo file using the gettext strategy
+def find(domain, localedir=None, languages=None, all=False):
+ # Get some reasonable defaults for arguments that were not supplied
+ if localedir is None:
+ localedir = _default_localedir
+ if languages is None:
+ languages = []
+ for envar in ('LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG'):
+ val = os.environ.get(envar)
+ if val:
+ languages = val.split(':')
+ break
+ if 'C' not in languages:
+ languages.append('C')
+ # now normalize and expand the languages
+ nelangs = []
+ for lang in languages:
+ for nelang in _expand_lang(lang):
+ if nelang not in nelangs:
+ nelangs.append(nelang)
+ # select a language
+ if all:
+ result = []
+ else:
+ result = None
+ for lang in nelangs:
+ if lang == 'C':
+ break
+ mofile = os.path.join(localedir, lang, 'LC_MESSAGES', '%s.mo' % domain)
+ if os.path.exists(mofile):
+ if all:
+ result.append(mofile)
+ else:
+ return mofile
+ return result
+
+
+
+# a mapping between absolute .mo file path and Translation object
+_translations = {}
+_unspecified = ['unspecified']
+
+def translation(domain, localedir=None, languages=None,
+ class_=None, fallback=False, codeset=_unspecified):
+ if class_ is None:
+ class_ = GNUTranslations
+ mofiles = find(domain, localedir, languages, all=True)
+ if not mofiles:
+ if fallback:
+ return NullTranslations()
+ from errno import ENOENT
+ raise FileNotFoundError(ENOENT,
+ 'No translation file found for domain', domain)
+ # Avoid opening, reading, and parsing the .mo file after it's been done
+ # once.
+ result = None
+ for mofile in mofiles:
+ key = (class_, os.path.abspath(mofile))
+ t = _translations.get(key)
+ if t is None:
+ with open(mofile, 'rb') as fp:
+ t = _translations.setdefault(key, class_(fp))
+ # Copy the translation object to allow setting fallbacks and
+ # output charset. All other instance data is shared with the
+ # cached object.
+ # Delay copy import for speeding up gettext import when .mo files
+ # are not used.
+ import copy
+ t = copy.copy(t)
+ if codeset is not _unspecified:
+ import warnings
+ warnings.warn('parameter codeset is deprecated',
+ DeprecationWarning, 2)
+ if codeset:
+ with warnings.catch_warnings():
+ warnings.filterwarnings('ignore', r'.*\bset_output_charset\b.*',
+ DeprecationWarning)
+ t.set_output_charset(codeset)
+ if result is None:
+ result = t
+ else:
+ result.add_fallback(t)
+ return result
+
+
+def install(domain, localedir=None, codeset=_unspecified, names=None):
+ t = translation(domain, localedir, fallback=True, codeset=codeset)
+ t.install(names)
+
+
+
+# a mapping b/w domains and locale directories
+_localedirs = {}
+# a mapping b/w domains and codesets
+_localecodesets = {}
+# current global domain, `messages' used for compatibility w/ GNU gettext
+_current_domain = 'messages'
+
+
+def textdomain(domain=None):
+ global _current_domain
+ if domain is not None:
+ _current_domain = domain
+ return _current_domain
+
+
+def bindtextdomain(domain, localedir=None):
+ global _localedirs
+ if localedir is not None:
+ _localedirs[domain] = localedir
+ return _localedirs.get(domain, _default_localedir)
+
+
+def bind_textdomain_codeset(domain, codeset=None):
+ import warnings
+ warnings.warn('bind_textdomain_codeset() is deprecated',
+ DeprecationWarning, 2)
+ global _localecodesets
+ if codeset is not None:
+ _localecodesets[domain] = codeset
+ return _localecodesets.get(domain)
+
+
+def dgettext(domain, message):
+ try:
+ t = translation(domain, _localedirs.get(domain, None))
+ except OSError:
+ return message
+ return t.gettext(message)
+
+def ldgettext(domain, message):
+ import warnings
+ warnings.warn('ldgettext() is deprecated, use dgettext() instead',
+ DeprecationWarning, 2)
+ codeset = _localecodesets.get(domain)
+ try:
+ with warnings.catch_warnings():
+ warnings.filterwarnings('ignore', r'.*\bparameter codeset\b.*',
+ DeprecationWarning)
+ t = translation(domain, _localedirs.get(domain, None), codeset=codeset)
+ except OSError:
+ return message.encode(codeset or locale.getpreferredencoding())
+ with warnings.catch_warnings():
+ warnings.filterwarnings('ignore', r'.*\blgettext\b.*',
+ DeprecationWarning)
+ return t.lgettext(message)
+
+def dngettext(domain, msgid1, msgid2, n):
+ try:
+ t = translation(domain, _localedirs.get(domain, None))
+ except OSError:
+ if n == 1:
+ return msgid1
+ else:
+ return msgid2
+ return t.ngettext(msgid1, msgid2, n)
+
+def ldngettext(domain, msgid1, msgid2, n):
+ import warnings
+ warnings.warn('ldngettext() is deprecated, use dngettext() instead',
+ DeprecationWarning, 2)
+ codeset = _localecodesets.get(domain)
+ try:
+ with warnings.catch_warnings():
+ warnings.filterwarnings('ignore', r'.*\bparameter codeset\b.*',
+ DeprecationWarning)
+ t = translation(domain, _localedirs.get(domain, None), codeset=codeset)
+ except OSError:
+ if n == 1:
+ tmsg = msgid1
+ else:
+ tmsg = msgid2
+ return tmsg.encode(codeset or locale.getpreferredencoding())
+ with warnings.catch_warnings():
+ warnings.filterwarnings('ignore', r'.*\blngettext\b.*',
+ DeprecationWarning)
+ return t.lngettext(msgid1, msgid2, n)
+
+
+def dpgettext(domain, context, message):
+ try:
+ t = translation(domain, _localedirs.get(domain, None))
+ except OSError:
+ return message
+ return t.pgettext(context, message)
+
+
+def dnpgettext(domain, context, msgid1, msgid2, n):
+ try:
+ t = translation(domain, _localedirs.get(domain, None))
+ except OSError:
+ if n == 1:
+ return msgid1
+ else:
+ return msgid2
+ return t.npgettext(context, msgid1, msgid2, n)
+
+
+def gettext(message):
+ return dgettext(_current_domain, message)
+
+def lgettext(message):
+ import warnings
+ warnings.warn('lgettext() is deprecated, use gettext() instead',
+ DeprecationWarning, 2)
+ with warnings.catch_warnings():
+ warnings.filterwarnings('ignore', r'.*\bldgettext\b.*',
+ DeprecationWarning)
+ return ldgettext(_current_domain, message)
+
+def ngettext(msgid1, msgid2, n):
+ return dngettext(_current_domain, msgid1, msgid2, n)
+
+def lngettext(msgid1, msgid2, n):
+ import warnings
+ warnings.warn('lngettext() is deprecated, use ngettext() instead',
+ DeprecationWarning, 2)
+ with warnings.catch_warnings():
+ warnings.filterwarnings('ignore', r'.*\bldngettext\b.*',
+ DeprecationWarning)
+ return ldngettext(_current_domain, msgid1, msgid2, n)
+
+
+def pgettext(context, message):
+ return dpgettext(_current_domain, context, message)
+
+
+def npgettext(context, msgid1, msgid2, n):
+ return dnpgettext(_current_domain, context, msgid1, msgid2, n)
+
+
+# dcgettext() has been deemed unnecessary and is not implemented.
+
+# James Henstridge's Catalog constructor from GNOME gettext. Documented usage
+# was:
+#
+# import gettext
+# cat = gettext.Catalog(PACKAGE, localedir=LOCALEDIR)
+# _ = cat.gettext
+# print _('Hello World')
+
+# The resulting catalog object currently don't support access through a
+# dictionary API, which was supported (but apparently unused) in GNOME
+# gettext.
+
+Catalog = translation
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/gzip.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/gzip.py
new file mode 100644
index 0000000000000000000000000000000000000000..1101d35a5f1bd7d89c9e349402b973d96d8275cd
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/gzip.py
@@ -0,0 +1,600 @@
+"""Functions that read and write gzipped files.
+
+The user of the file doesn't have to worry about the compression,
+but random access is not allowed."""
+
+# based on Andrew Kuchling's minigzip.py distributed with the zlib module
+
+import struct, sys, time, os
+import zlib
+import builtins
+import io
+import _compression
+
+__all__ = ["BadGzipFile", "GzipFile", "open", "compress", "decompress"]
+
+FTEXT, FHCRC, FEXTRA, FNAME, FCOMMENT = 1, 2, 4, 8, 16
+
+READ, WRITE = 1, 2
+
+_COMPRESS_LEVEL_FAST = 1
+_COMPRESS_LEVEL_TRADEOFF = 6
+_COMPRESS_LEVEL_BEST = 9
+
+
+def open(filename, mode="rb", compresslevel=_COMPRESS_LEVEL_BEST,
+ encoding=None, errors=None, newline=None):
+ """Open a gzip-compressed file in binary or text mode.
+
+ The filename argument can be an actual filename (a str or bytes object), or
+ an existing file object to read from or write to.
+
+ The mode argument can be "r", "rb", "w", "wb", "x", "xb", "a" or "ab" for
+ binary mode, or "rt", "wt", "xt" or "at" for text mode. The default mode is
+ "rb", and the default compresslevel is 9.
+
+ For binary mode, this function is equivalent to the GzipFile constructor:
+ GzipFile(filename, mode, compresslevel). In this case, the encoding, errors
+ and newline arguments must not be provided.
+
+ For text mode, a GzipFile object is created, and wrapped in an
+ io.TextIOWrapper instance with the specified encoding, error handling
+ behavior, and line ending(s).
+
+ """
+ if "t" in mode:
+ if "b" in mode:
+ raise ValueError("Invalid mode: %r" % (mode,))
+ else:
+ if encoding is not None:
+ raise ValueError("Argument 'encoding' not supported in binary mode")
+ if errors is not None:
+ raise ValueError("Argument 'errors' not supported in binary mode")
+ if newline is not None:
+ raise ValueError("Argument 'newline' not supported in binary mode")
+
+ gz_mode = mode.replace("t", "")
+ if isinstance(filename, (str, bytes, os.PathLike)):
+ binary_file = GzipFile(filename, gz_mode, compresslevel)
+ elif hasattr(filename, "read") or hasattr(filename, "write"):
+ binary_file = GzipFile(None, gz_mode, compresslevel, filename)
+ else:
+ raise TypeError("filename must be a str or bytes object, or a file")
+
+ if "t" in mode:
+ return io.TextIOWrapper(binary_file, encoding, errors, newline)
+ else:
+ return binary_file
+
+def write32u(output, value):
+ # The L format writes the bit pattern correctly whether signed
+ # or unsigned.
+ output.write(struct.pack("'
+
+ def _init_write(self, filename):
+ self.name = filename
+ self.crc = zlib.crc32(b"")
+ self.size = 0
+ self.writebuf = []
+ self.bufsize = 0
+ self.offset = 0 # Current file offset for seek(), tell(), etc
+
+ def _write_gzip_header(self, compresslevel):
+ self.fileobj.write(b'\037\213') # magic header
+ self.fileobj.write(b'\010') # compression method
+ try:
+ # RFC 1952 requires the FNAME field to be Latin-1. Do not
+ # include filenames that cannot be represented that way.
+ fname = os.path.basename(self.name)
+ if not isinstance(fname, bytes):
+ fname = fname.encode('latin-1')
+ if fname.endswith(b'.gz'):
+ fname = fname[:-3]
+ except UnicodeEncodeError:
+ fname = b''
+ flags = 0
+ if fname:
+ flags = FNAME
+ self.fileobj.write(chr(flags).encode('latin-1'))
+ mtime = self._write_mtime
+ if mtime is None:
+ mtime = time.time()
+ write32u(self.fileobj, int(mtime))
+ if compresslevel == _COMPRESS_LEVEL_BEST:
+ xfl = b'\002'
+ elif compresslevel == _COMPRESS_LEVEL_FAST:
+ xfl = b'\004'
+ else:
+ xfl = b'\000'
+ self.fileobj.write(xfl)
+ self.fileobj.write(b'\377')
+ if fname:
+ self.fileobj.write(fname + b'\000')
+
+ def write(self,data):
+ self._check_not_closed()
+ if self.mode != WRITE:
+ import errno
+ raise OSError(errno.EBADF, "write() on read-only GzipFile object")
+
+ if self.fileobj is None:
+ raise ValueError("write() on closed GzipFile object")
+
+ if isinstance(data, bytes):
+ length = len(data)
+ else:
+ # accept any data that supports the buffer protocol
+ data = memoryview(data)
+ length = data.nbytes
+
+ if length > 0:
+ self.fileobj.write(self.compress.compress(data))
+ self.size += length
+ self.crc = zlib.crc32(data, self.crc)
+ self.offset += length
+
+ return length
+
+ def read(self, size=-1):
+ self._check_not_closed()
+ if self.mode != READ:
+ import errno
+ raise OSError(errno.EBADF, "read() on write-only GzipFile object")
+ return self._buffer.read(size)
+
+ def read1(self, size=-1):
+ """Implements BufferedIOBase.read1()
+
+ Reads up to a buffer's worth of data if size is negative."""
+ self._check_not_closed()
+ if self.mode != READ:
+ import errno
+ raise OSError(errno.EBADF, "read1() on write-only GzipFile object")
+
+ if size < 0:
+ size = io.DEFAULT_BUFFER_SIZE
+ return self._buffer.read1(size)
+
+ def peek(self, n):
+ self._check_not_closed()
+ if self.mode != READ:
+ import errno
+ raise OSError(errno.EBADF, "peek() on write-only GzipFile object")
+ return self._buffer.peek(n)
+
+ @property
+ def closed(self):
+ return self.fileobj is None
+
+ def close(self):
+ fileobj = self.fileobj
+ if fileobj is None:
+ return
+ self.fileobj = None
+ try:
+ if self.mode == WRITE:
+ fileobj.write(self.compress.flush())
+ write32u(fileobj, self.crc)
+ # self.size may exceed 2 GiB, or even 4 GiB
+ write32u(fileobj, self.size & 0xffffffff)
+ elif self.mode == READ:
+ self._buffer.close()
+ finally:
+ myfileobj = self.myfileobj
+ if myfileobj:
+ self.myfileobj = None
+ myfileobj.close()
+
+ def flush(self,zlib_mode=zlib.Z_SYNC_FLUSH):
+ self._check_not_closed()
+ if self.mode == WRITE:
+ # Ensure the compressor's buffer is flushed
+ self.fileobj.write(self.compress.flush(zlib_mode))
+ self.fileobj.flush()
+
+ def fileno(self):
+ """Invoke the underlying file object's fileno() method.
+
+ This will raise AttributeError if the underlying file object
+ doesn't support fileno().
+ """
+ return self.fileobj.fileno()
+
+ def rewind(self):
+ '''Return the uncompressed stream file position indicator to the
+ beginning of the file'''
+ if self.mode != READ:
+ raise OSError("Can't rewind in write mode")
+ self._buffer.seek(0)
+
+ def readable(self):
+ return self.mode == READ
+
+ def writable(self):
+ return self.mode == WRITE
+
+ def seekable(self):
+ return True
+
+ def seek(self, offset, whence=io.SEEK_SET):
+ if self.mode == WRITE:
+ if whence != io.SEEK_SET:
+ if whence == io.SEEK_CUR:
+ offset = self.offset + offset
+ else:
+ raise ValueError('Seek from end not supported')
+ if offset < self.offset:
+ raise OSError('Negative seek in write mode')
+ count = offset - self.offset
+ chunk = b'\0' * 1024
+ for i in range(count // 1024):
+ self.write(chunk)
+ self.write(b'\0' * (count % 1024))
+ elif self.mode == READ:
+ self._check_not_closed()
+ return self._buffer.seek(offset, whence)
+
+ return self.offset
+
+ def readline(self, size=-1):
+ self._check_not_closed()
+ return self._buffer.readline(size)
+
+
+class _GzipReader(_compression.DecompressReader):
+ def __init__(self, fp):
+ super().__init__(_PaddedFile(fp), zlib.decompressobj,
+ wbits=-zlib.MAX_WBITS)
+ # Set flag indicating start of a new member
+ self._new_member = True
+ self._last_mtime = None
+
+ def _init_read(self):
+ self._crc = zlib.crc32(b"")
+ self._stream_size = 0 # Decompressed size of unconcatenated stream
+
+ def _read_exact(self, n):
+ '''Read exactly *n* bytes from `self._fp`
+
+ This method is required because self._fp may be unbuffered,
+ i.e. return short reads.
+ '''
+
+ data = self._fp.read(n)
+ while len(data) < n:
+ b = self._fp.read(n - len(data))
+ if not b:
+ raise EOFError("Compressed file ended before the "
+ "end-of-stream marker was reached")
+ data += b
+ return data
+
+ def _read_gzip_header(self):
+ magic = self._fp.read(2)
+ if magic == b'':
+ return False
+
+ if magic != b'\037\213':
+ raise BadGzipFile('Not a gzipped file (%r)' % magic)
+
+ (method, flag,
+ self._last_mtime) = struct.unpack(">> import hashlib
+ >>> m = hashlib.md5()
+ >>> m.update(b"Nobody inspects")
+ >>> m.update(b" the spammish repetition")
+ >>> m.digest()
+ b'\\xbbd\\x9c\\x83\\xdd\\x1e\\xa5\\xc9\\xd9\\xde\\xc9\\xa1\\x8d\\xf0\\xff\\xe9'
+
+More condensed:
+
+ >>> hashlib.sha224(b"Nobody inspects the spammish repetition").hexdigest()
+ 'a4337bc45a8fc544c03f52dc550cd6e1e87021bc896588bd79e901e2'
+
+"""
+
+# This tuple and __get_builtin_constructor() must be modified if a new
+# always available algorithm is added.
+__always_supported = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512',
+ 'blake2b', 'blake2s',
+ 'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512',
+ 'shake_128', 'shake_256')
+
+
+algorithms_guaranteed = set(__always_supported)
+algorithms_available = set(__always_supported)
+
+__all__ = __always_supported + ('new', 'algorithms_guaranteed',
+ 'algorithms_available', 'pbkdf2_hmac')
+
+
+__builtin_constructor_cache = {}
+
+__block_openssl_constructor = {
+ 'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512',
+ 'shake_128', 'shake_256',
+ 'blake2b', 'blake2s',
+}
+
+def __get_builtin_constructor(name):
+ cache = __builtin_constructor_cache
+ constructor = cache.get(name)
+ if constructor is not None:
+ return constructor
+ try:
+ if name in {'SHA1', 'sha1'}:
+ import _sha1
+ cache['SHA1'] = cache['sha1'] = _sha1.sha1
+ elif name in {'MD5', 'md5'}:
+ import _md5
+ cache['MD5'] = cache['md5'] = _md5.md5
+ elif name in {'SHA256', 'sha256', 'SHA224', 'sha224'}:
+ import _sha256
+ cache['SHA224'] = cache['sha224'] = _sha256.sha224
+ cache['SHA256'] = cache['sha256'] = _sha256.sha256
+ elif name in {'SHA512', 'sha512', 'SHA384', 'sha384'}:
+ import _sha512
+ cache['SHA384'] = cache['sha384'] = _sha512.sha384
+ cache['SHA512'] = cache['sha512'] = _sha512.sha512
+ elif name in {'blake2b', 'blake2s'}:
+ import _blake2
+ cache['blake2b'] = _blake2.blake2b
+ cache['blake2s'] = _blake2.blake2s
+ elif name in {'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512'}:
+ import _sha3
+ cache['sha3_224'] = _sha3.sha3_224
+ cache['sha3_256'] = _sha3.sha3_256
+ cache['sha3_384'] = _sha3.sha3_384
+ cache['sha3_512'] = _sha3.sha3_512
+ elif name in {'shake_128', 'shake_256'}:
+ import _sha3
+ cache['shake_128'] = _sha3.shake_128
+ cache['shake_256'] = _sha3.shake_256
+ except ImportError:
+ pass # no extension module, this hash is unsupported.
+
+ constructor = cache.get(name)
+ if constructor is not None:
+ return constructor
+
+ raise ValueError('unsupported hash type ' + name)
+
+
+def __get_openssl_constructor(name):
+ if name in __block_openssl_constructor:
+ # Prefer our blake2 and sha3 implementation.
+ return __get_builtin_constructor(name)
+ try:
+ f = getattr(_hashlib, 'openssl_' + name)
+ # Allow the C module to raise ValueError. The function will be
+ # defined but the hash not actually available thanks to OpenSSL.
+ f()
+ # Use the C function directly (very fast)
+ return f
+ except (AttributeError, ValueError):
+ return __get_builtin_constructor(name)
+
+
+def __py_new(name, data=b'', **kwargs):
+ """new(name, data=b'', **kwargs) - Return a new hashing object using the
+ named algorithm; optionally initialized with data (which must be
+ a bytes-like object).
+ """
+ return __get_builtin_constructor(name)(data, **kwargs)
+
+
+def __hash_new(name, data=b'', **kwargs):
+ """new(name, data=b'') - Return a new hashing object using the named algorithm;
+ optionally initialized with data (which must be a bytes-like object).
+ """
+ if name in __block_openssl_constructor:
+ # Prefer our blake2 and sha3 implementation
+ # OpenSSL 1.1.0 comes with a limited implementation of blake2b/s.
+ # It does neither support keyed blake2 nor advanced features like
+ # salt, personal, tree hashing or SSE.
+ return __get_builtin_constructor(name)(data, **kwargs)
+ try:
+ return _hashlib.new(name, data)
+ except ValueError:
+ # If the _hashlib module (OpenSSL) doesn't support the named
+ # hash, try using our builtin implementations.
+ # This allows for SHA224/256 and SHA384/512 support even though
+ # the OpenSSL library prior to 0.9.8 doesn't provide them.
+ return __get_builtin_constructor(name)(data)
+
+
+try:
+ import _hashlib
+ new = __hash_new
+ __get_hash = __get_openssl_constructor
+ algorithms_available = algorithms_available.union(
+ _hashlib.openssl_md_meth_names)
+except ImportError:
+ new = __py_new
+ __get_hash = __get_builtin_constructor
+
+try:
+ # OpenSSL's PKCS5_PBKDF2_HMAC requires OpenSSL 1.0+ with HMAC and SHA
+ from _hashlib import pbkdf2_hmac
+except ImportError:
+ _trans_5C = bytes((x ^ 0x5C) for x in range(256))
+ _trans_36 = bytes((x ^ 0x36) for x in range(256))
+
+ def pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None):
+ """Password based key derivation function 2 (PKCS #5 v2.0)
+
+ This Python implementations based on the hmac module about as fast
+ as OpenSSL's PKCS5_PBKDF2_HMAC for short passwords and much faster
+ for long passwords.
+ """
+ if not isinstance(hash_name, str):
+ raise TypeError(hash_name)
+
+ if not isinstance(password, (bytes, bytearray)):
+ password = bytes(memoryview(password))
+ if not isinstance(salt, (bytes, bytearray)):
+ salt = bytes(memoryview(salt))
+
+ # Fast inline HMAC implementation
+ inner = new(hash_name)
+ outer = new(hash_name)
+ blocksize = getattr(inner, 'block_size', 64)
+ if len(password) > blocksize:
+ password = new(hash_name, password).digest()
+ password = password + b'\x00' * (blocksize - len(password))
+ inner.update(password.translate(_trans_36))
+ outer.update(password.translate(_trans_5C))
+
+ def prf(msg, inner=inner, outer=outer):
+ # PBKDF2_HMAC uses the password as key. We can re-use the same
+ # digest objects and just update copies to skip initialization.
+ icpy = inner.copy()
+ ocpy = outer.copy()
+ icpy.update(msg)
+ ocpy.update(icpy.digest())
+ return ocpy.digest()
+
+ if iterations < 1:
+ raise ValueError(iterations)
+ if dklen is None:
+ dklen = outer.digest_size
+ if dklen < 1:
+ raise ValueError(dklen)
+
+ dkey = b''
+ loop = 1
+ from_bytes = int.from_bytes
+ while len(dkey) < dklen:
+ prev = prf(salt + loop.to_bytes(4, 'big'))
+ # endianness doesn't matter here as long to / from use the same
+ rkey = int.from_bytes(prev, 'big')
+ for i in range(iterations - 1):
+ prev = prf(prev)
+ # rkey = rkey ^ prev
+ rkey ^= from_bytes(prev, 'big')
+ loop += 1
+ dkey += rkey.to_bytes(inner.digest_size, 'big')
+
+ return dkey[:dklen]
+
+try:
+ # OpenSSL's scrypt requires OpenSSL 1.1+
+ from _hashlib import scrypt
+except ImportError:
+ pass
+
+
+for __func_name in __always_supported:
+ # try them all, some may not work due to the OpenSSL
+ # version not supporting that algorithm.
+ try:
+ globals()[__func_name] = __get_hash(__func_name)
+ except ValueError:
+ import logging
+ logging.exception('code for hash %s was not found.', __func_name)
+
+
+# Cleanup locals()
+del __always_supported, __func_name, __get_hash
+del __py_new, __hash_new, __get_openssl_constructor
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/imp.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/imp.py
new file mode 100644
index 0000000000000000000000000000000000000000..31f8c766381adc3c125fedcc704277b1f6fa7968
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/imp.py
@@ -0,0 +1,345 @@
+"""This module provides the components needed to build your own __import__
+function. Undocumented functions are obsolete.
+
+In most cases it is preferred you consider using the importlib module's
+functionality over this module.
+
+"""
+# (Probably) need to stay in _imp
+from _imp import (lock_held, acquire_lock, release_lock,
+ get_frozen_object, is_frozen_package,
+ init_frozen, is_builtin, is_frozen,
+ _fix_co_filename)
+try:
+ from _imp import create_dynamic
+except ImportError:
+ # Platform doesn't support dynamic loading.
+ create_dynamic = None
+
+from importlib._bootstrap import _ERR_MSG, _exec, _load, _builtin_from_name
+from importlib._bootstrap_external import SourcelessFileLoader
+
+from importlib import machinery
+from importlib import util
+import importlib
+import os
+import sys
+import tokenize
+import types
+import warnings
+
+warnings.warn("the imp module is deprecated in favour of importlib; "
+ "see the module's documentation for alternative uses",
+ DeprecationWarning, stacklevel=2)
+
+# DEPRECATED
+SEARCH_ERROR = 0
+PY_SOURCE = 1
+PY_COMPILED = 2
+C_EXTENSION = 3
+PY_RESOURCE = 4
+PKG_DIRECTORY = 5
+C_BUILTIN = 6
+PY_FROZEN = 7
+PY_CODERESOURCE = 8
+IMP_HOOK = 9
+
+
+def new_module(name):
+ """**DEPRECATED**
+
+ Create a new module.
+
+ The module is not entered into sys.modules.
+
+ """
+ return types.ModuleType(name)
+
+
+def get_magic():
+ """**DEPRECATED**
+
+ Return the magic number for .pyc files.
+ """
+ return util.MAGIC_NUMBER
+
+
+def get_tag():
+ """Return the magic tag for .pyc files."""
+ return sys.implementation.cache_tag
+
+
+def cache_from_source(path, debug_override=None):
+ """**DEPRECATED**
+
+ Given the path to a .py file, return the path to its .pyc file.
+
+ The .py file does not need to exist; this simply returns the path to the
+ .pyc file calculated as if the .py file were imported.
+
+ If debug_override is not None, then it must be a boolean and is used in
+ place of sys.flags.optimize.
+
+ If sys.implementation.cache_tag is None then NotImplementedError is raised.
+
+ """
+ with warnings.catch_warnings():
+ warnings.simplefilter('ignore')
+ return util.cache_from_source(path, debug_override)
+
+
+def source_from_cache(path):
+ """**DEPRECATED**
+
+ Given the path to a .pyc. file, return the path to its .py file.
+
+ The .pyc file does not need to exist; this simply returns the path to
+ the .py file calculated to correspond to the .pyc file. If path does
+ not conform to PEP 3147 format, ValueError will be raised. If
+ sys.implementation.cache_tag is None then NotImplementedError is raised.
+
+ """
+ return util.source_from_cache(path)
+
+
+def get_suffixes():
+ """**DEPRECATED**"""
+ extensions = [(s, 'rb', C_EXTENSION) for s in machinery.EXTENSION_SUFFIXES]
+ source = [(s, 'r', PY_SOURCE) for s in machinery.SOURCE_SUFFIXES]
+ bytecode = [(s, 'rb', PY_COMPILED) for s in machinery.BYTECODE_SUFFIXES]
+
+ return extensions + source + bytecode
+
+
+class NullImporter:
+
+ """**DEPRECATED**
+
+ Null import object.
+
+ """
+
+ def __init__(self, path):
+ if path == '':
+ raise ImportError('empty pathname', path='')
+ elif os.path.isdir(path):
+ raise ImportError('existing directory', path=path)
+
+ def find_module(self, fullname):
+ """Always returns None."""
+ return None
+
+
+class _HackedGetData:
+
+ """Compatibility support for 'file' arguments of various load_*()
+ functions."""
+
+ def __init__(self, fullname, path, file=None):
+ super().__init__(fullname, path)
+ self.file = file
+
+ def get_data(self, path):
+ """Gross hack to contort loader to deal w/ load_*()'s bad API."""
+ if self.file and path == self.path:
+ # The contract of get_data() requires us to return bytes. Reopen the
+ # file in binary mode if needed.
+ if not self.file.closed:
+ file = self.file
+ if 'b' not in file.mode:
+ file.close()
+ if self.file.closed:
+ self.file = file = open(self.path, 'rb')
+
+ with file:
+ return file.read()
+ else:
+ return super().get_data(path)
+
+
+class _LoadSourceCompatibility(_HackedGetData, machinery.SourceFileLoader):
+
+ """Compatibility support for implementing load_source()."""
+
+
+def load_source(name, pathname, file=None):
+ loader = _LoadSourceCompatibility(name, pathname, file)
+ spec = util.spec_from_file_location(name, pathname, loader=loader)
+ if name in sys.modules:
+ module = _exec(spec, sys.modules[name])
+ else:
+ module = _load(spec)
+ # To allow reloading to potentially work, use a non-hacked loader which
+ # won't rely on a now-closed file object.
+ module.__loader__ = machinery.SourceFileLoader(name, pathname)
+ module.__spec__.loader = module.__loader__
+ return module
+
+
+class _LoadCompiledCompatibility(_HackedGetData, SourcelessFileLoader):
+
+ """Compatibility support for implementing load_compiled()."""
+
+
+def load_compiled(name, pathname, file=None):
+ """**DEPRECATED**"""
+ loader = _LoadCompiledCompatibility(name, pathname, file)
+ spec = util.spec_from_file_location(name, pathname, loader=loader)
+ if name in sys.modules:
+ module = _exec(spec, sys.modules[name])
+ else:
+ module = _load(spec)
+ # To allow reloading to potentially work, use a non-hacked loader which
+ # won't rely on a now-closed file object.
+ module.__loader__ = SourcelessFileLoader(name, pathname)
+ module.__spec__.loader = module.__loader__
+ return module
+
+
+def load_package(name, path):
+ """**DEPRECATED**"""
+ if os.path.isdir(path):
+ extensions = (machinery.SOURCE_SUFFIXES[:] +
+ machinery.BYTECODE_SUFFIXES[:])
+ for extension in extensions:
+ init_path = os.path.join(path, '__init__' + extension)
+ if os.path.exists(init_path):
+ path = init_path
+ break
+ else:
+ raise ValueError('{!r} is not a package'.format(path))
+ spec = util.spec_from_file_location(name, path,
+ submodule_search_locations=[])
+ if name in sys.modules:
+ return _exec(spec, sys.modules[name])
+ else:
+ return _load(spec)
+
+
+def load_module(name, file, filename, details):
+ """**DEPRECATED**
+
+ Load a module, given information returned by find_module().
+
+ The module name must include the full package name, if any.
+
+ """
+ suffix, mode, type_ = details
+ if mode and (not mode.startswith(('r', 'U')) or '+' in mode):
+ raise ValueError('invalid file open mode {!r}'.format(mode))
+ elif file is None and type_ in {PY_SOURCE, PY_COMPILED}:
+ msg = 'file object required for import (type code {})'.format(type_)
+ raise ValueError(msg)
+ elif type_ == PY_SOURCE:
+ return load_source(name, filename, file)
+ elif type_ == PY_COMPILED:
+ return load_compiled(name, filename, file)
+ elif type_ == C_EXTENSION and load_dynamic is not None:
+ if file is None:
+ with open(filename, 'rb') as opened_file:
+ return load_dynamic(name, filename, opened_file)
+ else:
+ return load_dynamic(name, filename, file)
+ elif type_ == PKG_DIRECTORY:
+ return load_package(name, filename)
+ elif type_ == C_BUILTIN:
+ return init_builtin(name)
+ elif type_ == PY_FROZEN:
+ return init_frozen(name)
+ else:
+ msg = "Don't know how to import {} (type code {})".format(name, type_)
+ raise ImportError(msg, name=name)
+
+
+def find_module(name, path=None):
+ """**DEPRECATED**
+
+ Search for a module.
+
+ If path is omitted or None, search for a built-in, frozen or special
+ module and continue search in sys.path. The module name cannot
+ contain '.'; to search for a submodule of a package, pass the
+ submodule name and the package's __path__.
+
+ """
+ if not isinstance(name, str):
+ raise TypeError("'name' must be a str, not {}".format(type(name)))
+ elif not isinstance(path, (type(None), list)):
+ # Backwards-compatibility
+ raise RuntimeError("'path' must be None or a list, "
+ "not {}".format(type(path)))
+
+ if path is None:
+ if is_builtin(name):
+ return None, None, ('', '', C_BUILTIN)
+ elif is_frozen(name):
+ return None, None, ('', '', PY_FROZEN)
+ else:
+ path = sys.path
+
+ for entry in path:
+ package_directory = os.path.join(entry, name)
+ for suffix in ['.py', machinery.BYTECODE_SUFFIXES[0]]:
+ package_file_name = '__init__' + suffix
+ file_path = os.path.join(package_directory, package_file_name)
+ if os.path.isfile(file_path):
+ return None, package_directory, ('', '', PKG_DIRECTORY)
+ for suffix, mode, type_ in get_suffixes():
+ file_name = name + suffix
+ file_path = os.path.join(entry, file_name)
+ if os.path.isfile(file_path):
+ break
+ else:
+ continue
+ break # Break out of outer loop when breaking out of inner loop.
+ else:
+ raise ImportError(_ERR_MSG.format(name), name=name)
+
+ encoding = None
+ if 'b' not in mode:
+ with open(file_path, 'rb') as file:
+ encoding = tokenize.detect_encoding(file.readline)[0]
+ file = open(file_path, mode, encoding=encoding)
+ return file, file_path, (suffix, mode, type_)
+
+
+def reload(module):
+ """**DEPRECATED**
+
+ Reload the module and return it.
+
+ The module must have been successfully imported before.
+
+ """
+ return importlib.reload(module)
+
+
+def init_builtin(name):
+ """**DEPRECATED**
+
+ Load and return a built-in module by name, or None is such module doesn't
+ exist
+ """
+ try:
+ return _builtin_from_name(name)
+ except ImportError:
+ return None
+
+
+if create_dynamic:
+ def load_dynamic(name, path, file=None):
+ """**DEPRECATED**
+
+ Load an extension module.
+ """
+ import importlib.machinery
+ loader = importlib.machinery.ExtensionFileLoader(name, path)
+
+ # Issue #24748: Skip the sys.modules check in _load_module_shim;
+ # always load new extension
+ spec = importlib.machinery.ModuleSpec(
+ name=name, loader=loader, origin=path)
+ return _load(spec)
+
+else:
+ load_dynamic = None
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/inspect.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/inspect.py
new file mode 100644
index 0000000000000000000000000000000000000000..7ffc7d31bd8a6a9b64c24f6057092f82a1fada29
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/inspect.py
@@ -0,0 +1,3167 @@
+"""Get useful information from live Python objects.
+
+This module encapsulates the interface provided by the internal special
+attributes (co_*, im_*, tb_*, etc.) in a friendlier fashion.
+It also provides some help for examining source code and class layout.
+
+Here are some of the useful functions provided by this module:
+
+ ismodule(), isclass(), ismethod(), isfunction(), isgeneratorfunction(),
+ isgenerator(), istraceback(), isframe(), iscode(), isbuiltin(),
+ isroutine() - check object types
+ getmembers() - get members of an object that satisfy a given condition
+
+ getfile(), getsourcefile(), getsource() - find an object's source code
+ getdoc(), getcomments() - get documentation on an object
+ getmodule() - determine the module that an object came from
+ getclasstree() - arrange classes so as to represent their hierarchy
+
+ getargvalues(), getcallargs() - get info about function arguments
+ getfullargspec() - same, with support for Python 3 features
+ formatargvalues() - format an argument spec
+ getouterframes(), getinnerframes() - get info about frames
+ currentframe() - get the current stack frame
+ stack(), trace() - get info about frames on the stack or in a traceback
+
+ signature() - get a Signature object for the callable
+"""
+
+# This module is in the public domain. No warranties.
+
+__author__ = ('Ka-Ping Yee ',
+ 'Yury Selivanov ')
+
+import abc
+import dis
+import collections.abc
+import enum
+import importlib.machinery
+import itertools
+import linecache
+import os
+import re
+import sys
+import tokenize
+import token
+import types
+import warnings
+import functools
+import builtins
+from operator import attrgetter
+from collections import namedtuple, OrderedDict
+
+# Create constants for the compiler flags in Include/code.h
+# We try to get them from dis to avoid duplication
+mod_dict = globals()
+for k, v in dis.COMPILER_FLAG_NAMES.items():
+ mod_dict["CO_" + v] = k
+
+# See Include/object.h
+TPFLAGS_IS_ABSTRACT = 1 << 20
+
+# ----------------------------------------------------------- type-checking
+def ismodule(object):
+ """Return true if the object is a module.
+
+ Module objects provide these attributes:
+ __cached__ pathname to byte compiled file
+ __doc__ documentation string
+ __file__ filename (missing for built-in modules)"""
+ return isinstance(object, types.ModuleType)
+
+def isclass(object):
+ """Return true if the object is a class.
+
+ Class objects provide these attributes:
+ __doc__ documentation string
+ __module__ name of module in which this class was defined"""
+ return isinstance(object, type)
+
+def ismethod(object):
+ """Return true if the object is an instance method.
+
+ Instance method objects provide these attributes:
+ __doc__ documentation string
+ __name__ name with which this method was defined
+ __func__ function object containing implementation of method
+ __self__ instance to which this method is bound"""
+ return isinstance(object, types.MethodType)
+
+def ismethoddescriptor(object):
+ """Return true if the object is a method descriptor.
+
+ But not if ismethod() or isclass() or isfunction() are true.
+
+ This is new in Python 2.2, and, for example, is true of int.__add__.
+ An object passing this test has a __get__ attribute but not a __set__
+ attribute, but beyond that the set of attributes varies. __name__ is
+ usually sensible, and __doc__ often is.
+
+ Methods implemented via descriptors that also pass one of the other
+ tests return false from the ismethoddescriptor() test, simply because
+ the other tests promise more -- you can, e.g., count on having the
+ __func__ attribute (etc) when an object passes ismethod()."""
+ if isclass(object) or ismethod(object) or isfunction(object):
+ # mutual exclusion
+ return False
+ tp = type(object)
+ return hasattr(tp, "__get__") and not hasattr(tp, "__set__")
+
+def isdatadescriptor(object):
+ """Return true if the object is a data descriptor.
+
+ Data descriptors have a __set__ or a __delete__ attribute. Examples are
+ properties (defined in Python) and getsets and members (defined in C).
+ Typically, data descriptors will also have __name__ and __doc__ attributes
+ (properties, getsets, and members have both of these attributes), but this
+ is not guaranteed."""
+ if isclass(object) or ismethod(object) or isfunction(object):
+ # mutual exclusion
+ return False
+ tp = type(object)
+ return hasattr(tp, "__set__") or hasattr(tp, "__delete__")
+
+if hasattr(types, 'MemberDescriptorType'):
+ # CPython and equivalent
+ def ismemberdescriptor(object):
+ """Return true if the object is a member descriptor.
+
+ Member descriptors are specialized descriptors defined in extension
+ modules."""
+ return isinstance(object, types.MemberDescriptorType)
+else:
+ # Other implementations
+ def ismemberdescriptor(object):
+ """Return true if the object is a member descriptor.
+
+ Member descriptors are specialized descriptors defined in extension
+ modules."""
+ return False
+
+if hasattr(types, 'GetSetDescriptorType'):
+ # CPython and equivalent
+ def isgetsetdescriptor(object):
+ """Return true if the object is a getset descriptor.
+
+ getset descriptors are specialized descriptors defined in extension
+ modules."""
+ return isinstance(object, types.GetSetDescriptorType)
+else:
+ # Other implementations
+ def isgetsetdescriptor(object):
+ """Return true if the object is a getset descriptor.
+
+ getset descriptors are specialized descriptors defined in extension
+ modules."""
+ return False
+
+def isfunction(object):
+ """Return true if the object is a user-defined function.
+
+ Function objects provide these attributes:
+ __doc__ documentation string
+ __name__ name with which this function was defined
+ __code__ code object containing compiled function bytecode
+ __defaults__ tuple of any default values for arguments
+ __globals__ global namespace in which this function was defined
+ __annotations__ dict of parameter annotations
+ __kwdefaults__ dict of keyword only parameters with defaults"""
+ return isinstance(object, types.FunctionType)
+
+def _has_code_flag(f, flag):
+ """Return true if ``f`` is a function (or a method or functools.partial
+ wrapper wrapping a function) whose code object has the given ``flag``
+ set in its flags."""
+ while ismethod(f):
+ f = f.__func__
+ f = functools._unwrap_partial(f)
+ if not isfunction(f):
+ return False
+ return bool(f.__code__.co_flags & flag)
+
+def isgeneratorfunction(obj):
+ """Return true if the object is a user-defined generator function.
+
+ Generator function objects provide the same attributes as functions.
+ See help(isfunction) for a list of attributes."""
+ return _has_code_flag(obj, CO_GENERATOR)
+
+def iscoroutinefunction(obj):
+ """Return true if the object is a coroutine function.
+
+ Coroutine functions are defined with "async def" syntax.
+ """
+ return _has_code_flag(obj, CO_COROUTINE)
+
+def isasyncgenfunction(obj):
+ """Return true if the object is an asynchronous generator function.
+
+ Asynchronous generator functions are defined with "async def"
+ syntax and have "yield" expressions in their body.
+ """
+ return _has_code_flag(obj, CO_ASYNC_GENERATOR)
+
+def isasyncgen(object):
+ """Return true if the object is an asynchronous generator."""
+ return isinstance(object, types.AsyncGeneratorType)
+
+def isgenerator(object):
+ """Return true if the object is a generator.
+
+ Generator objects provide these attributes:
+ __iter__ defined to support iteration over container
+ close raises a new GeneratorExit exception inside the
+ generator to terminate the iteration
+ gi_code code object
+ gi_frame frame object or possibly None once the generator has
+ been exhausted
+ gi_running set to 1 when generator is executing, 0 otherwise
+ next return the next item from the container
+ send resumes the generator and "sends" a value that becomes
+ the result of the current yield-expression
+ throw used to raise an exception inside the generator"""
+ return isinstance(object, types.GeneratorType)
+
+def iscoroutine(object):
+ """Return true if the object is a coroutine."""
+ return isinstance(object, types.CoroutineType)
+
+def isawaitable(object):
+ """Return true if object can be passed to an ``await`` expression."""
+ return (isinstance(object, types.CoroutineType) or
+ isinstance(object, types.GeneratorType) and
+ bool(object.gi_code.co_flags & CO_ITERABLE_COROUTINE) or
+ isinstance(object, collections.abc.Awaitable))
+
+def istraceback(object):
+ """Return true if the object is a traceback.
+
+ Traceback objects provide these attributes:
+ tb_frame frame object at this level
+ tb_lasti index of last attempted instruction in bytecode
+ tb_lineno current line number in Python source code
+ tb_next next inner traceback object (called by this level)"""
+ return isinstance(object, types.TracebackType)
+
+def isframe(object):
+ """Return true if the object is a frame object.
+
+ Frame objects provide these attributes:
+ f_back next outer frame object (this frame's caller)
+ f_builtins built-in namespace seen by this frame
+ f_code code object being executed in this frame
+ f_globals global namespace seen by this frame
+ f_lasti index of last attempted instruction in bytecode
+ f_lineno current line number in Python source code
+ f_locals local namespace seen by this frame
+ f_trace tracing function for this frame, or None"""
+ return isinstance(object, types.FrameType)
+
+def iscode(object):
+ """Return true if the object is a code object.
+
+ Code objects provide these attributes:
+ co_argcount number of arguments (not including *, ** args
+ or keyword only arguments)
+ co_code string of raw compiled bytecode
+ co_cellvars tuple of names of cell variables
+ co_consts tuple of constants used in the bytecode
+ co_filename name of file in which this code object was created
+ co_firstlineno number of first line in Python source code
+ co_flags bitmap: 1=optimized | 2=newlocals | 4=*arg | 8=**arg
+ | 16=nested | 32=generator | 64=nofree | 128=coroutine
+ | 256=iterable_coroutine | 512=async_generator
+ co_freevars tuple of names of free variables
+ co_posonlyargcount number of positional only arguments
+ co_kwonlyargcount number of keyword only arguments (not including ** arg)
+ co_lnotab encoded mapping of line numbers to bytecode indices
+ co_name name with which this code object was defined
+ co_names tuple of names of local variables
+ co_nlocals number of local variables
+ co_stacksize virtual machine stack space required
+ co_varnames tuple of names of arguments and local variables"""
+ return isinstance(object, types.CodeType)
+
+def isbuiltin(object):
+ """Return true if the object is a built-in function or method.
+
+ Built-in functions and methods provide these attributes:
+ __doc__ documentation string
+ __name__ original name of this function or method
+ __self__ instance to which a method is bound, or None"""
+ return isinstance(object, types.BuiltinFunctionType)
+
+def isroutine(object):
+ """Return true if the object is any kind of function or method."""
+ return (isbuiltin(object)
+ or isfunction(object)
+ or ismethod(object)
+ or ismethoddescriptor(object))
+
+def isabstract(object):
+ """Return true if the object is an abstract base class (ABC)."""
+ if not isinstance(object, type):
+ return False
+ if object.__flags__ & TPFLAGS_IS_ABSTRACT:
+ return True
+ if not issubclass(type(object), abc.ABCMeta):
+ return False
+ if hasattr(object, '__abstractmethods__'):
+ # It looks like ABCMeta.__new__ has finished running;
+ # TPFLAGS_IS_ABSTRACT should have been accurate.
+ return False
+ # It looks like ABCMeta.__new__ has not finished running yet; we're
+ # probably in __init_subclass__. We'll look for abstractmethods manually.
+ for name, value in object.__dict__.items():
+ if getattr(value, "__isabstractmethod__", False):
+ return True
+ for base in object.__bases__:
+ for name in getattr(base, "__abstractmethods__", ()):
+ value = getattr(object, name, None)
+ if getattr(value, "__isabstractmethod__", False):
+ return True
+ return False
+
+def getmembers(object, predicate=None):
+ """Return all members of an object as (name, value) pairs sorted by name.
+ Optionally, only return members that satisfy a given predicate."""
+ if isclass(object):
+ mro = (object,) + getmro(object)
+ else:
+ mro = ()
+ results = []
+ processed = set()
+ names = dir(object)
+ # :dd any DynamicClassAttributes to the list of names if object is a class;
+ # this may result in duplicate entries if, for example, a virtual
+ # attribute with the same name as a DynamicClassAttribute exists
+ try:
+ for base in object.__bases__:
+ for k, v in base.__dict__.items():
+ if isinstance(v, types.DynamicClassAttribute):
+ names.append(k)
+ except AttributeError:
+ pass
+ for key in names:
+ # First try to get the value via getattr. Some descriptors don't
+ # like calling their __get__ (see bug #1785), so fall back to
+ # looking in the __dict__.
+ try:
+ value = getattr(object, key)
+ # handle the duplicate key
+ if key in processed:
+ raise AttributeError
+ except AttributeError:
+ for base in mro:
+ if key in base.__dict__:
+ value = base.__dict__[key]
+ break
+ else:
+ # could be a (currently) missing slot member, or a buggy
+ # __dir__; discard and move on
+ continue
+ if not predicate or predicate(value):
+ results.append((key, value))
+ processed.add(key)
+ results.sort(key=lambda pair: pair[0])
+ return results
+
+Attribute = namedtuple('Attribute', 'name kind defining_class object')
+
+def classify_class_attrs(cls):
+ """Return list of attribute-descriptor tuples.
+
+ For each name in dir(cls), the return list contains a 4-tuple
+ with these elements:
+
+ 0. The name (a string).
+
+ 1. The kind of attribute this is, one of these strings:
+ 'class method' created via classmethod()
+ 'static method' created via staticmethod()
+ 'property' created via property()
+ 'method' any other flavor of method or descriptor
+ 'data' not a method
+
+ 2. The class which defined this attribute (a class).
+
+ 3. The object as obtained by calling getattr; if this fails, or if the
+ resulting object does not live anywhere in the class' mro (including
+ metaclasses) then the object is looked up in the defining class's
+ dict (found by walking the mro).
+
+ If one of the items in dir(cls) is stored in the metaclass it will now
+ be discovered and not have None be listed as the class in which it was
+ defined. Any items whose home class cannot be discovered are skipped.
+ """
+
+ mro = getmro(cls)
+ metamro = getmro(type(cls)) # for attributes stored in the metaclass
+ metamro = tuple(cls for cls in metamro if cls not in (type, object))
+ class_bases = (cls,) + mro
+ all_bases = class_bases + metamro
+ names = dir(cls)
+ # :dd any DynamicClassAttributes to the list of names;
+ # this may result in duplicate entries if, for example, a virtual
+ # attribute with the same name as a DynamicClassAttribute exists.
+ for base in mro:
+ for k, v in base.__dict__.items():
+ if isinstance(v, types.DynamicClassAttribute):
+ names.append(k)
+ result = []
+ processed = set()
+
+ for name in names:
+ # Get the object associated with the name, and where it was defined.
+ # Normal objects will be looked up with both getattr and directly in
+ # its class' dict (in case getattr fails [bug #1785], and also to look
+ # for a docstring).
+ # For DynamicClassAttributes on the second pass we only look in the
+ # class's dict.
+ #
+ # Getting an obj from the __dict__ sometimes reveals more than
+ # using getattr. Static and class methods are dramatic examples.
+ homecls = None
+ get_obj = None
+ dict_obj = None
+ if name not in processed:
+ try:
+ if name == '__dict__':
+ raise Exception("__dict__ is special, don't want the proxy")
+ get_obj = getattr(cls, name)
+ except Exception as exc:
+ pass
+ else:
+ homecls = getattr(get_obj, "__objclass__", homecls)
+ if homecls not in class_bases:
+ # if the resulting object does not live somewhere in the
+ # mro, drop it and search the mro manually
+ homecls = None
+ last_cls = None
+ # first look in the classes
+ for srch_cls in class_bases:
+ srch_obj = getattr(srch_cls, name, None)
+ if srch_obj is get_obj:
+ last_cls = srch_cls
+ # then check the metaclasses
+ for srch_cls in metamro:
+ try:
+ srch_obj = srch_cls.__getattr__(cls, name)
+ except AttributeError:
+ continue
+ if srch_obj is get_obj:
+ last_cls = srch_cls
+ if last_cls is not None:
+ homecls = last_cls
+ for base in all_bases:
+ if name in base.__dict__:
+ dict_obj = base.__dict__[name]
+ if homecls not in metamro:
+ homecls = base
+ break
+ if homecls is None:
+ # unable to locate the attribute anywhere, most likely due to
+ # buggy custom __dir__; discard and move on
+ continue
+ obj = get_obj if get_obj is not None else dict_obj
+ # Classify the object or its descriptor.
+ if isinstance(dict_obj, (staticmethod, types.BuiltinMethodType)):
+ kind = "static method"
+ obj = dict_obj
+ elif isinstance(dict_obj, (classmethod, types.ClassMethodDescriptorType)):
+ kind = "class method"
+ obj = dict_obj
+ elif isinstance(dict_obj, property):
+ kind = "property"
+ obj = dict_obj
+ elif isroutine(obj):
+ kind = "method"
+ else:
+ kind = "data"
+ result.append(Attribute(name, kind, homecls, obj))
+ processed.add(name)
+ return result
+
+# ----------------------------------------------------------- class helpers
+
+def getmro(cls):
+ "Return tuple of base classes (including cls) in method resolution order."
+ return cls.__mro__
+
+# -------------------------------------------------------- function helpers
+
+def unwrap(func, *, stop=None):
+ """Get the object wrapped by *func*.
+
+ Follows the chain of :attr:`__wrapped__` attributes returning the last
+ object in the chain.
+
+ *stop* is an optional callback accepting an object in the wrapper chain
+ as its sole argument that allows the unwrapping to be terminated early if
+ the callback returns a true value. If the callback never returns a true
+ value, the last object in the chain is returned as usual. For example,
+ :func:`signature` uses this to stop unwrapping if any object in the
+ chain has a ``__signature__`` attribute defined.
+
+ :exc:`ValueError` is raised if a cycle is encountered.
+
+ """
+ if stop is None:
+ def _is_wrapper(f):
+ return hasattr(f, '__wrapped__')
+ else:
+ def _is_wrapper(f):
+ return hasattr(f, '__wrapped__') and not stop(f)
+ f = func # remember the original func for error reporting
+ # Memoise by id to tolerate non-hashable objects, but store objects to
+ # ensure they aren't destroyed, which would allow their IDs to be reused.
+ memo = {id(f): f}
+ recursion_limit = sys.getrecursionlimit()
+ while _is_wrapper(func):
+ func = func.__wrapped__
+ id_func = id(func)
+ if (id_func in memo) or (len(memo) >= recursion_limit):
+ raise ValueError('wrapper loop when unwrapping {!r}'.format(f))
+ memo[id_func] = func
+ return func
+
+# -------------------------------------------------- source code extraction
+def indentsize(line):
+ """Return the indent size, in spaces, at the start of a line of text."""
+ expline = line.expandtabs()
+ return len(expline) - len(expline.lstrip())
+
+def _findclass(func):
+ cls = sys.modules.get(func.__module__)
+ if cls is None:
+ return None
+ for name in func.__qualname__.split('.')[:-1]:
+ cls = getattr(cls, name)
+ if not isclass(cls):
+ return None
+ return cls
+
+def _finddoc(obj):
+ if isclass(obj):
+ for base in obj.__mro__:
+ if base is not object:
+ try:
+ doc = base.__doc__
+ except AttributeError:
+ continue
+ if doc is not None:
+ return doc
+ return None
+
+ if ismethod(obj):
+ name = obj.__func__.__name__
+ self = obj.__self__
+ if (isclass(self) and
+ getattr(getattr(self, name, None), '__func__') is obj.__func__):
+ # classmethod
+ cls = self
+ else:
+ cls = self.__class__
+ elif isfunction(obj):
+ name = obj.__name__
+ cls = _findclass(obj)
+ if cls is None or getattr(cls, name) is not obj:
+ return None
+ elif isbuiltin(obj):
+ name = obj.__name__
+ self = obj.__self__
+ if (isclass(self) and
+ self.__qualname__ + '.' + name == obj.__qualname__):
+ # classmethod
+ cls = self
+ else:
+ cls = self.__class__
+ # Should be tested before isdatadescriptor().
+ elif isinstance(obj, property):
+ func = obj.fget
+ name = func.__name__
+ cls = _findclass(func)
+ if cls is None or getattr(cls, name) is not obj:
+ return None
+ elif ismethoddescriptor(obj) or isdatadescriptor(obj):
+ name = obj.__name__
+ cls = obj.__objclass__
+ if getattr(cls, name) is not obj:
+ return None
+ if ismemberdescriptor(obj):
+ slots = getattr(cls, '__slots__', None)
+ if isinstance(slots, dict) and name in slots:
+ return slots[name]
+ else:
+ return None
+ for base in cls.__mro__:
+ try:
+ doc = getattr(base, name).__doc__
+ except AttributeError:
+ continue
+ if doc is not None:
+ return doc
+ return None
+
+def getdoc(object):
+ """Get the documentation string for an object.
+
+ All tabs are expanded to spaces. To clean up docstrings that are
+ indented to line up with blocks of code, any whitespace than can be
+ uniformly removed from the second line onwards is removed."""
+ try:
+ doc = object.__doc__
+ except AttributeError:
+ return None
+ if doc is None:
+ try:
+ doc = _finddoc(object)
+ except (AttributeError, TypeError):
+ return None
+ if not isinstance(doc, str):
+ return None
+ return cleandoc(doc)
+
+def cleandoc(doc):
+ """Clean up indentation from docstrings.
+
+ Any whitespace that can be uniformly removed from the second line
+ onwards is removed."""
+ try:
+ lines = doc.expandtabs().split('\n')
+ except UnicodeError:
+ return None
+ else:
+ # Find minimum indentation of any non-blank lines after first line.
+ margin = sys.maxsize
+ for line in lines[1:]:
+ content = len(line.lstrip())
+ if content:
+ indent = len(line) - content
+ margin = min(margin, indent)
+ # Remove indentation.
+ if lines:
+ lines[0] = lines[0].lstrip()
+ if margin < sys.maxsize:
+ for i in range(1, len(lines)): lines[i] = lines[i][margin:]
+ # Remove any trailing or leading blank lines.
+ while lines and not lines[-1]:
+ lines.pop()
+ while lines and not lines[0]:
+ lines.pop(0)
+ return '\n'.join(lines)
+
+def getfile(object):
+ """Work out which source or compiled file an object was defined in."""
+ if ismodule(object):
+ if getattr(object, '__file__', None):
+ return object.__file__
+ raise TypeError('{!r} is a built-in module'.format(object))
+ if isclass(object):
+ if hasattr(object, '__module__'):
+ module = sys.modules.get(object.__module__)
+ if getattr(module, '__file__', None):
+ return module.__file__
+ raise TypeError('{!r} is a built-in class'.format(object))
+ if ismethod(object):
+ object = object.__func__
+ if isfunction(object):
+ object = object.__code__
+ if istraceback(object):
+ object = object.tb_frame
+ if isframe(object):
+ object = object.f_code
+ if iscode(object):
+ return object.co_filename
+ raise TypeError('module, class, method, function, traceback, frame, or '
+ 'code object was expected, got {}'.format(
+ type(object).__name__))
+
+def getmodulename(path):
+ """Return the module name for a given file, or None."""
+ fname = os.path.basename(path)
+ # Check for paths that look like an actual module file
+ suffixes = [(-len(suffix), suffix)
+ for suffix in importlib.machinery.all_suffixes()]
+ suffixes.sort() # try longest suffixes first, in case they overlap
+ for neglen, suffix in suffixes:
+ if fname.endswith(suffix):
+ return fname[:neglen]
+ return None
+
+def getsourcefile(object):
+ """Return the filename that can be used to locate an object's source.
+ Return None if no way can be identified to get the source.
+ """
+ filename = getfile(object)
+ all_bytecode_suffixes = importlib.machinery.DEBUG_BYTECODE_SUFFIXES[:]
+ all_bytecode_suffixes += importlib.machinery.OPTIMIZED_BYTECODE_SUFFIXES[:]
+ if any(filename.endswith(s) for s in all_bytecode_suffixes):
+ filename = (os.path.splitext(filename)[0] +
+ importlib.machinery.SOURCE_SUFFIXES[0])
+ elif any(filename.endswith(s) for s in
+ importlib.machinery.EXTENSION_SUFFIXES):
+ return None
+ if os.path.exists(filename):
+ return filename
+ # only return a non-existent filename if the module has a PEP 302 loader
+ if getattr(getmodule(object, filename), '__loader__', None) is not None:
+ return filename
+ # or it is in the linecache
+ if filename in linecache.cache:
+ return filename
+
+def getabsfile(object, _filename=None):
+ """Return an absolute path to the source or compiled file for an object.
+
+ The idea is for each object to have a unique origin, so this routine
+ normalizes the result as much as possible."""
+ if _filename is None:
+ _filename = getsourcefile(object) or getfile(object)
+ return os.path.normcase(os.path.abspath(_filename))
+
+modulesbyfile = {}
+_filesbymodname = {}
+
+def getmodule(object, _filename=None):
+ """Return the module an object was defined in, or None if not found."""
+ if ismodule(object):
+ return object
+ if hasattr(object, '__module__'):
+ return sys.modules.get(object.__module__)
+ # Try the filename to modulename cache
+ if _filename is not None and _filename in modulesbyfile:
+ return sys.modules.get(modulesbyfile[_filename])
+ # Try the cache again with the absolute file name
+ try:
+ file = getabsfile(object, _filename)
+ except TypeError:
+ return None
+ if file in modulesbyfile:
+ return sys.modules.get(modulesbyfile[file])
+ # Update the filename to module name cache and check yet again
+ # Copy sys.modules in order to cope with changes while iterating
+ for modname, module in sys.modules.copy().items():
+ if ismodule(module) and hasattr(module, '__file__'):
+ f = module.__file__
+ if f == _filesbymodname.get(modname, None):
+ # Have already mapped this module, so skip it
+ continue
+ _filesbymodname[modname] = f
+ f = getabsfile(module)
+ # Always map to the name the module knows itself by
+ modulesbyfile[f] = modulesbyfile[
+ os.path.realpath(f)] = module.__name__
+ if file in modulesbyfile:
+ return sys.modules.get(modulesbyfile[file])
+ # Check the main module
+ main = sys.modules['__main__']
+ if not hasattr(object, '__name__'):
+ return None
+ if hasattr(main, object.__name__):
+ mainobject = getattr(main, object.__name__)
+ if mainobject is object:
+ return main
+ # Check builtins
+ builtin = sys.modules['builtins']
+ if hasattr(builtin, object.__name__):
+ builtinobject = getattr(builtin, object.__name__)
+ if builtinobject is object:
+ return builtin
+
+def findsource(object):
+ """Return the entire source file and starting line number for an object.
+
+ The argument may be a module, class, method, function, traceback, frame,
+ or code object. The source code is returned as a list of all the lines
+ in the file and the line number indexes a line in that list. An OSError
+ is raised if the source code cannot be retrieved."""
+
+ file = getsourcefile(object)
+ if file:
+ # Invalidate cache if needed.
+ linecache.checkcache(file)
+ else:
+ file = getfile(object)
+ # Allow filenames in form of "" to pass through.
+ # `doctest` monkeypatches `linecache` module to enable
+ # inspection, so let `linecache.getlines` to be called.
+ if not (file.startswith('<') and file.endswith('>')):
+ raise OSError('source code not available')
+
+ module = getmodule(object, file)
+ if module:
+ lines = linecache.getlines(file, module.__dict__)
+ else:
+ lines = linecache.getlines(file)
+ if not lines:
+ raise OSError('could not get source code')
+
+ if ismodule(object):
+ return lines, 0
+
+ if isclass(object):
+ name = object.__name__
+ pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
+ # make some effort to find the best matching class definition:
+ # use the one with the least indentation, which is the one
+ # that's most probably not inside a function definition.
+ candidates = []
+ for i in range(len(lines)):
+ match = pat.match(lines[i])
+ if match:
+ # if it's at toplevel, it's already the best one
+ if lines[i][0] == 'c':
+ return lines, i
+ # else add whitespace to candidate list
+ candidates.append((match.group(1), i))
+ if candidates:
+ # this will sort by whitespace, and by line number,
+ # less whitespace first
+ candidates.sort()
+ return lines, candidates[0][1]
+ else:
+ raise OSError('could not find class definition')
+
+ if ismethod(object):
+ object = object.__func__
+ if isfunction(object):
+ object = object.__code__
+ if istraceback(object):
+ object = object.tb_frame
+ if isframe(object):
+ object = object.f_code
+ if iscode(object):
+ if not hasattr(object, 'co_firstlineno'):
+ raise OSError('could not find function definition')
+ lnum = object.co_firstlineno - 1
+ pat = re.compile(r'^(\s*def\s)|(\s*async\s+def\s)|(.*(? 0:
+ try:
+ line = lines[lnum]
+ except IndexError:
+ raise OSError('lineno is out of bounds')
+ if pat.match(line):
+ break
+ lnum = lnum - 1
+ return lines, lnum
+ raise OSError('could not find code object')
+
+def getcomments(object):
+ """Get lines of comments immediately preceding an object's source code.
+
+ Returns None when source can't be found.
+ """
+ try:
+ lines, lnum = findsource(object)
+ except (OSError, TypeError):
+ return None
+
+ if ismodule(object):
+ # Look for a comment block at the top of the file.
+ start = 0
+ if lines and lines[0][:2] == '#!': start = 1
+ while start < len(lines) and lines[start].strip() in ('', '#'):
+ start = start + 1
+ if start < len(lines) and lines[start][:1] == '#':
+ comments = []
+ end = start
+ while end < len(lines) and lines[end][:1] == '#':
+ comments.append(lines[end].expandtabs())
+ end = end + 1
+ return ''.join(comments)
+
+ # Look for a preceding block of comments at the same indentation.
+ elif lnum > 0:
+ indent = indentsize(lines[lnum])
+ end = lnum - 1
+ if end >= 0 and lines[end].lstrip()[:1] == '#' and \
+ indentsize(lines[end]) == indent:
+ comments = [lines[end].expandtabs().lstrip()]
+ if end > 0:
+ end = end - 1
+ comment = lines[end].expandtabs().lstrip()
+ while comment[:1] == '#' and indentsize(lines[end]) == indent:
+ comments[:0] = [comment]
+ end = end - 1
+ if end < 0: break
+ comment = lines[end].expandtabs().lstrip()
+ while comments and comments[0].strip() == '#':
+ comments[:1] = []
+ while comments and comments[-1].strip() == '#':
+ comments[-1:] = []
+ return ''.join(comments)
+
+class EndOfBlock(Exception): pass
+
+class BlockFinder:
+ """Provide a tokeneater() method to detect the end of a code block."""
+ def __init__(self):
+ self.indent = 0
+ self.islambda = False
+ self.started = False
+ self.passline = False
+ self.indecorator = False
+ self.decoratorhasargs = False
+ self.last = 1
+ self.body_col0 = None
+
+ def tokeneater(self, type, token, srowcol, erowcol, line):
+ if not self.started and not self.indecorator:
+ # skip any decorators
+ if token == "@":
+ self.indecorator = True
+ # look for the first "def", "class" or "lambda"
+ elif token in ("def", "class", "lambda"):
+ if token == "lambda":
+ self.islambda = True
+ self.started = True
+ self.passline = True # skip to the end of the line
+ elif token == "(":
+ if self.indecorator:
+ self.decoratorhasargs = True
+ elif token == ")":
+ if self.indecorator:
+ self.indecorator = False
+ self.decoratorhasargs = False
+ elif type == tokenize.NEWLINE:
+ self.passline = False # stop skipping when a NEWLINE is seen
+ self.last = srowcol[0]
+ if self.islambda: # lambdas always end at the first NEWLINE
+ raise EndOfBlock
+ # hitting a NEWLINE when in a decorator without args
+ # ends the decorator
+ if self.indecorator and not self.decoratorhasargs:
+ self.indecorator = False
+ elif self.passline:
+ pass
+ elif type == tokenize.INDENT:
+ if self.body_col0 is None and self.started:
+ self.body_col0 = erowcol[1]
+ self.indent = self.indent + 1
+ self.passline = True
+ elif type == tokenize.DEDENT:
+ self.indent = self.indent - 1
+ # the end of matching indent/dedent pairs end a block
+ # (note that this only works for "def"/"class" blocks,
+ # not e.g. for "if: else:" or "try: finally:" blocks)
+ if self.indent <= 0:
+ raise EndOfBlock
+ elif type == tokenize.COMMENT:
+ if self.body_col0 is not None and srowcol[1] >= self.body_col0:
+ # Include comments if indented at least as much as the block
+ self.last = srowcol[0]
+ elif self.indent == 0 and type not in (tokenize.COMMENT, tokenize.NL):
+ # any other token on the same indentation level end the previous
+ # block as well, except the pseudo-tokens COMMENT and NL.
+ raise EndOfBlock
+
+def getblock(lines):
+ """Extract the block of code at the top of the given list of lines."""
+ blockfinder = BlockFinder()
+ try:
+ tokens = tokenize.generate_tokens(iter(lines).__next__)
+ for _token in tokens:
+ blockfinder.tokeneater(*_token)
+ except (EndOfBlock, IndentationError):
+ pass
+ return lines[:blockfinder.last]
+
+def getsourcelines(object):
+ """Return a list of source lines and starting line number for an object.
+
+ The argument may be a module, class, method, function, traceback, frame,
+ or code object. The source code is returned as a list of the lines
+ corresponding to the object and the line number indicates where in the
+ original source file the first line of code was found. An OSError is
+ raised if the source code cannot be retrieved."""
+ object = unwrap(object)
+ lines, lnum = findsource(object)
+
+ if istraceback(object):
+ object = object.tb_frame
+
+ # for module or frame that corresponds to module, return all source lines
+ if (ismodule(object) or
+ (isframe(object) and object.f_code.co_name == "")):
+ return lines, 0
+ else:
+ return getblock(lines[lnum:]), lnum + 1
+
+def getsource(object):
+ """Return the text of the source code for an object.
+
+ The argument may be a module, class, method, function, traceback, frame,
+ or code object. The source code is returned as a single string. An
+ OSError is raised if the source code cannot be retrieved."""
+ lines, lnum = getsourcelines(object)
+ return ''.join(lines)
+
+# --------------------------------------------------- class tree extraction
+def walktree(classes, children, parent):
+ """Recursive helper function for getclasstree()."""
+ results = []
+ classes.sort(key=attrgetter('__module__', '__name__'))
+ for c in classes:
+ results.append((c, c.__bases__))
+ if c in children:
+ results.append(walktree(children[c], children, c))
+ return results
+
+def getclasstree(classes, unique=False):
+ """Arrange the given list of classes into a hierarchy of nested lists.
+
+ Where a nested list appears, it contains classes derived from the class
+ whose entry immediately precedes the list. Each entry is a 2-tuple
+ containing a class and a tuple of its base classes. If the 'unique'
+ argument is true, exactly one entry appears in the returned structure
+ for each class in the given list. Otherwise, classes using multiple
+ inheritance and their descendants will appear multiple times."""
+ children = {}
+ roots = []
+ for c in classes:
+ if c.__bases__:
+ for parent in c.__bases__:
+ if parent not in children:
+ children[parent] = []
+ if c not in children[parent]:
+ children[parent].append(c)
+ if unique and parent in classes: break
+ elif c not in roots:
+ roots.append(c)
+ for parent in children:
+ if parent not in classes:
+ roots.append(parent)
+ return walktree(roots, children, None)
+
+# ------------------------------------------------ argument list extraction
+Arguments = namedtuple('Arguments', 'args, varargs, varkw')
+
+def getargs(co):
+ """Get information about the arguments accepted by a code object.
+
+ Three things are returned: (args, varargs, varkw), where
+ 'args' is the list of argument names. Keyword-only arguments are
+ appended. 'varargs' and 'varkw' are the names of the * and **
+ arguments or None."""
+ if not iscode(co):
+ raise TypeError('{!r} is not a code object'.format(co))
+
+ names = co.co_varnames
+ nargs = co.co_argcount
+ nkwargs = co.co_kwonlyargcount
+ args = list(names[:nargs])
+ kwonlyargs = list(names[nargs:nargs+nkwargs])
+ step = 0
+
+ nargs += nkwargs
+ varargs = None
+ if co.co_flags & CO_VARARGS:
+ varargs = co.co_varnames[nargs]
+ nargs = nargs + 1
+ varkw = None
+ if co.co_flags & CO_VARKEYWORDS:
+ varkw = co.co_varnames[nargs]
+ return Arguments(args + kwonlyargs, varargs, varkw)
+
+ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults')
+
+def getargspec(func):
+ """Get the names and default values of a function's parameters.
+
+ A tuple of four things is returned: (args, varargs, keywords, defaults).
+ 'args' is a list of the argument names, including keyword-only argument names.
+ 'varargs' and 'keywords' are the names of the * and ** parameters or None.
+ 'defaults' is an n-tuple of the default values of the last n parameters.
+
+ This function is deprecated, as it does not support annotations or
+ keyword-only parameters and will raise ValueError if either is present
+ on the supplied callable.
+
+ For a more structured introspection API, use inspect.signature() instead.
+
+ Alternatively, use getfullargspec() for an API with a similar namedtuple
+ based interface, but full support for annotations and keyword-only
+ parameters.
+
+ Deprecated since Python 3.5, use `inspect.getfullargspec()`.
+ """
+ warnings.warn("inspect.getargspec() is deprecated since Python 3.0, "
+ "use inspect.signature() or inspect.getfullargspec()",
+ DeprecationWarning, stacklevel=2)
+ args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = \
+ getfullargspec(func)
+ if kwonlyargs or ann:
+ raise ValueError("Function has keyword-only parameters or annotations"
+ ", use inspect.signature() API which can support them")
+ return ArgSpec(args, varargs, varkw, defaults)
+
+FullArgSpec = namedtuple('FullArgSpec',
+ 'args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations')
+
+def getfullargspec(func):
+ """Get the names and default values of a callable object's parameters.
+
+ A tuple of seven things is returned:
+ (args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations).
+ 'args' is a list of the parameter names.
+ 'varargs' and 'varkw' are the names of the * and ** parameters or None.
+ 'defaults' is an n-tuple of the default values of the last n parameters.
+ 'kwonlyargs' is a list of keyword-only parameter names.
+ 'kwonlydefaults' is a dictionary mapping names from kwonlyargs to defaults.
+ 'annotations' is a dictionary mapping parameter names to annotations.
+
+ Notable differences from inspect.signature():
+ - the "self" parameter is always reported, even for bound methods
+ - wrapper chains defined by __wrapped__ *not* unwrapped automatically
+ """
+ try:
+ # Re: `skip_bound_arg=False`
+ #
+ # There is a notable difference in behaviour between getfullargspec
+ # and Signature: the former always returns 'self' parameter for bound
+ # methods, whereas the Signature always shows the actual calling
+ # signature of the passed object.
+ #
+ # To simulate this behaviour, we "unbind" bound methods, to trick
+ # inspect.signature to always return their first parameter ("self",
+ # usually)
+
+ # Re: `follow_wrapper_chains=False`
+ #
+ # getfullargspec() historically ignored __wrapped__ attributes,
+ # so we ensure that remains the case in 3.3+
+
+ sig = _signature_from_callable(func,
+ follow_wrapper_chains=False,
+ skip_bound_arg=False,
+ sigcls=Signature)
+ except Exception as ex:
+ # Most of the times 'signature' will raise ValueError.
+ # But, it can also raise AttributeError, and, maybe something
+ # else. So to be fully backwards compatible, we catch all
+ # possible exceptions here, and reraise a TypeError.
+ raise TypeError('unsupported callable') from ex
+
+ args = []
+ varargs = None
+ varkw = None
+ posonlyargs = []
+ kwonlyargs = []
+ defaults = ()
+ annotations = {}
+ defaults = ()
+ kwdefaults = {}
+
+ if sig.return_annotation is not sig.empty:
+ annotations['return'] = sig.return_annotation
+
+ for param in sig.parameters.values():
+ kind = param.kind
+ name = param.name
+
+ if kind is _POSITIONAL_ONLY:
+ posonlyargs.append(name)
+ if param.default is not param.empty:
+ defaults += (param.default,)
+ elif kind is _POSITIONAL_OR_KEYWORD:
+ args.append(name)
+ if param.default is not param.empty:
+ defaults += (param.default,)
+ elif kind is _VAR_POSITIONAL:
+ varargs = name
+ elif kind is _KEYWORD_ONLY:
+ kwonlyargs.append(name)
+ if param.default is not param.empty:
+ kwdefaults[name] = param.default
+ elif kind is _VAR_KEYWORD:
+ varkw = name
+
+ if param.annotation is not param.empty:
+ annotations[name] = param.annotation
+
+ if not kwdefaults:
+ # compatibility with 'func.__kwdefaults__'
+ kwdefaults = None
+
+ if not defaults:
+ # compatibility with 'func.__defaults__'
+ defaults = None
+
+ return FullArgSpec(posonlyargs + args, varargs, varkw, defaults,
+ kwonlyargs, kwdefaults, annotations)
+
+
+ArgInfo = namedtuple('ArgInfo', 'args varargs keywords locals')
+
+def getargvalues(frame):
+ """Get information about arguments passed into a particular frame.
+
+ A tuple of four things is returned: (args, varargs, varkw, locals).
+ 'args' is a list of the argument names.
+ 'varargs' and 'varkw' are the names of the * and ** arguments or None.
+ 'locals' is the locals dictionary of the given frame."""
+ args, varargs, varkw = getargs(frame.f_code)
+ return ArgInfo(args, varargs, varkw, frame.f_locals)
+
+def formatannotation(annotation, base_module=None):
+ if getattr(annotation, '__module__', None) == 'typing':
+ return repr(annotation).replace('typing.', '')
+ if isinstance(annotation, type):
+ if annotation.__module__ in ('builtins', base_module):
+ return annotation.__qualname__
+ return annotation.__module__+'.'+annotation.__qualname__
+ return repr(annotation)
+
+def formatannotationrelativeto(object):
+ module = getattr(object, '__module__', None)
+ def _formatannotation(annotation):
+ return formatannotation(annotation, module)
+ return _formatannotation
+
+def formatargspec(args, varargs=None, varkw=None, defaults=None,
+ kwonlyargs=(), kwonlydefaults={}, annotations={},
+ formatarg=str,
+ formatvarargs=lambda name: '*' + name,
+ formatvarkw=lambda name: '**' + name,
+ formatvalue=lambda value: '=' + repr(value),
+ formatreturns=lambda text: ' -> ' + text,
+ formatannotation=formatannotation):
+ """Format an argument spec from the values returned by getfullargspec.
+
+ The first seven arguments are (args, varargs, varkw, defaults,
+ kwonlyargs, kwonlydefaults, annotations). The other five arguments
+ are the corresponding optional formatting functions that are called to
+ turn names and values into strings. The last argument is an optional
+ function to format the sequence of arguments.
+
+ Deprecated since Python 3.5: use the `signature` function and `Signature`
+ objects.
+ """
+
+ from warnings import warn
+
+ warn("`formatargspec` is deprecated since Python 3.5. Use `signature` and "
+ "the `Signature` object directly",
+ DeprecationWarning,
+ stacklevel=2)
+
+ def formatargandannotation(arg):
+ result = formatarg(arg)
+ if arg in annotations:
+ result += ': ' + formatannotation(annotations[arg])
+ return result
+ specs = []
+ if defaults:
+ firstdefault = len(args) - len(defaults)
+ for i, arg in enumerate(args):
+ spec = formatargandannotation(arg)
+ if defaults and i >= firstdefault:
+ spec = spec + formatvalue(defaults[i - firstdefault])
+ specs.append(spec)
+ if varargs is not None:
+ specs.append(formatvarargs(formatargandannotation(varargs)))
+ else:
+ if kwonlyargs:
+ specs.append('*')
+ if kwonlyargs:
+ for kwonlyarg in kwonlyargs:
+ spec = formatargandannotation(kwonlyarg)
+ if kwonlydefaults and kwonlyarg in kwonlydefaults:
+ spec += formatvalue(kwonlydefaults[kwonlyarg])
+ specs.append(spec)
+ if varkw is not None:
+ specs.append(formatvarkw(formatargandannotation(varkw)))
+ result = '(' + ', '.join(specs) + ')'
+ if 'return' in annotations:
+ result += formatreturns(formatannotation(annotations['return']))
+ return result
+
+def formatargvalues(args, varargs, varkw, locals,
+ formatarg=str,
+ formatvarargs=lambda name: '*' + name,
+ formatvarkw=lambda name: '**' + name,
+ formatvalue=lambda value: '=' + repr(value)):
+ """Format an argument spec from the 4 values returned by getargvalues.
+
+ The first four arguments are (args, varargs, varkw, locals). The
+ next four arguments are the corresponding optional formatting functions
+ that are called to turn names and values into strings. The ninth
+ argument is an optional function to format the sequence of arguments."""
+ def convert(name, locals=locals,
+ formatarg=formatarg, formatvalue=formatvalue):
+ return formatarg(name) + formatvalue(locals[name])
+ specs = []
+ for i in range(len(args)):
+ specs.append(convert(args[i]))
+ if varargs:
+ specs.append(formatvarargs(varargs) + formatvalue(locals[varargs]))
+ if varkw:
+ specs.append(formatvarkw(varkw) + formatvalue(locals[varkw]))
+ return '(' + ', '.join(specs) + ')'
+
+def _missing_arguments(f_name, argnames, pos, values):
+ names = [repr(name) for name in argnames if name not in values]
+ missing = len(names)
+ if missing == 1:
+ s = names[0]
+ elif missing == 2:
+ s = "{} and {}".format(*names)
+ else:
+ tail = ", {} and {}".format(*names[-2:])
+ del names[-2:]
+ s = ", ".join(names) + tail
+ raise TypeError("%s() missing %i required %s argument%s: %s" %
+ (f_name, missing,
+ "positional" if pos else "keyword-only",
+ "" if missing == 1 else "s", s))
+
+def _too_many(f_name, args, kwonly, varargs, defcount, given, values):
+ atleast = len(args) - defcount
+ kwonly_given = len([arg for arg in kwonly if arg in values])
+ if varargs:
+ plural = atleast != 1
+ sig = "at least %d" % (atleast,)
+ elif defcount:
+ plural = True
+ sig = "from %d to %d" % (atleast, len(args))
+ else:
+ plural = len(args) != 1
+ sig = str(len(args))
+ kwonly_sig = ""
+ if kwonly_given:
+ msg = " positional argument%s (and %d keyword-only argument%s)"
+ kwonly_sig = (msg % ("s" if given != 1 else "", kwonly_given,
+ "s" if kwonly_given != 1 else ""))
+ raise TypeError("%s() takes %s positional argument%s but %d%s %s given" %
+ (f_name, sig, "s" if plural else "", given, kwonly_sig,
+ "was" if given == 1 and not kwonly_given else "were"))
+
+def getcallargs(func, /, *positional, **named):
+ """Get the mapping of arguments to values.
+
+ A dict is returned, with keys the function argument names (including the
+ names of the * and ** arguments, if any), and values the respective bound
+ values from 'positional' and 'named'."""
+ spec = getfullargspec(func)
+ args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = spec
+ f_name = func.__name__
+ arg2value = {}
+
+
+ if ismethod(func) and func.__self__ is not None:
+ # implicit 'self' (or 'cls' for classmethods) argument
+ positional = (func.__self__,) + positional
+ num_pos = len(positional)
+ num_args = len(args)
+ num_defaults = len(defaults) if defaults else 0
+
+ n = min(num_pos, num_args)
+ for i in range(n):
+ arg2value[args[i]] = positional[i]
+ if varargs:
+ arg2value[varargs] = tuple(positional[n:])
+ possible_kwargs = set(args + kwonlyargs)
+ if varkw:
+ arg2value[varkw] = {}
+ for kw, value in named.items():
+ if kw not in possible_kwargs:
+ if not varkw:
+ raise TypeError("%s() got an unexpected keyword argument %r" %
+ (f_name, kw))
+ arg2value[varkw][kw] = value
+ continue
+ if kw in arg2value:
+ raise TypeError("%s() got multiple values for argument %r" %
+ (f_name, kw))
+ arg2value[kw] = value
+ if num_pos > num_args and not varargs:
+ _too_many(f_name, args, kwonlyargs, varargs, num_defaults,
+ num_pos, arg2value)
+ if num_pos < num_args:
+ req = args[:num_args - num_defaults]
+ for arg in req:
+ if arg not in arg2value:
+ _missing_arguments(f_name, req, True, arg2value)
+ for i, arg in enumerate(args[num_args - num_defaults:]):
+ if arg not in arg2value:
+ arg2value[arg] = defaults[i]
+ missing = 0
+ for kwarg in kwonlyargs:
+ if kwarg not in arg2value:
+ if kwonlydefaults and kwarg in kwonlydefaults:
+ arg2value[kwarg] = kwonlydefaults[kwarg]
+ else:
+ missing += 1
+ if missing:
+ _missing_arguments(f_name, kwonlyargs, False, arg2value)
+ return arg2value
+
+ClosureVars = namedtuple('ClosureVars', 'nonlocals globals builtins unbound')
+
+def getclosurevars(func):
+ """
+ Get the mapping of free variables to their current values.
+
+ Returns a named tuple of dicts mapping the current nonlocal, global
+ and builtin references as seen by the body of the function. A final
+ set of unbound names that could not be resolved is also provided.
+ """
+
+ if ismethod(func):
+ func = func.__func__
+
+ if not isfunction(func):
+ raise TypeError("{!r} is not a Python function".format(func))
+
+ code = func.__code__
+ # Nonlocal references are named in co_freevars and resolved
+ # by looking them up in __closure__ by positional index
+ if func.__closure__ is None:
+ nonlocal_vars = {}
+ else:
+ nonlocal_vars = {
+ var : cell.cell_contents
+ for var, cell in zip(code.co_freevars, func.__closure__)
+ }
+
+ # Global and builtin references are named in co_names and resolved
+ # by looking them up in __globals__ or __builtins__
+ global_ns = func.__globals__
+ builtin_ns = global_ns.get("__builtins__", builtins.__dict__)
+ if ismodule(builtin_ns):
+ builtin_ns = builtin_ns.__dict__
+ global_vars = {}
+ builtin_vars = {}
+ unbound_names = set()
+ for name in code.co_names:
+ if name in ("None", "True", "False"):
+ # Because these used to be builtins instead of keywords, they
+ # may still show up as name references. We ignore them.
+ continue
+ try:
+ global_vars[name] = global_ns[name]
+ except KeyError:
+ try:
+ builtin_vars[name] = builtin_ns[name]
+ except KeyError:
+ unbound_names.add(name)
+
+ return ClosureVars(nonlocal_vars, global_vars,
+ builtin_vars, unbound_names)
+
+# -------------------------------------------------- stack frame extraction
+
+Traceback = namedtuple('Traceback', 'filename lineno function code_context index')
+
+def getframeinfo(frame, context=1):
+ """Get information about a frame or traceback object.
+
+ A tuple of five things is returned: the filename, the line number of
+ the current line, the function name, a list of lines of context from
+ the source code, and the index of the current line within that list.
+ The optional second argument specifies the number of lines of context
+ to return, which are centered around the current line."""
+ if istraceback(frame):
+ lineno = frame.tb_lineno
+ frame = frame.tb_frame
+ else:
+ lineno = frame.f_lineno
+ if not isframe(frame):
+ raise TypeError('{!r} is not a frame or traceback object'.format(frame))
+
+ filename = getsourcefile(frame) or getfile(frame)
+ if context > 0:
+ start = lineno - 1 - context//2
+ try:
+ lines, lnum = findsource(frame)
+ except OSError:
+ lines = index = None
+ else:
+ start = max(0, min(start, len(lines) - context))
+ lines = lines[start:start+context]
+ index = lineno - 1 - start
+ else:
+ lines = index = None
+
+ return Traceback(filename, lineno, frame.f_code.co_name, lines, index)
+
+def getlineno(frame):
+ """Get the line number from a frame object, allowing for optimization."""
+ # FrameType.f_lineno is now a descriptor that grovels co_lnotab
+ return frame.f_lineno
+
+FrameInfo = namedtuple('FrameInfo', ('frame',) + Traceback._fields)
+
+def getouterframes(frame, context=1):
+ """Get a list of records for a frame and all higher (calling) frames.
+
+ Each record contains a frame object, filename, line number, function
+ name, a list of lines of context, and index within the context."""
+ framelist = []
+ while frame:
+ frameinfo = (frame,) + getframeinfo(frame, context)
+ framelist.append(FrameInfo(*frameinfo))
+ frame = frame.f_back
+ return framelist
+
+def getinnerframes(tb, context=1):
+ """Get a list of records for a traceback's frame and all lower frames.
+
+ Each record contains a frame object, filename, line number, function
+ name, a list of lines of context, and index within the context."""
+ framelist = []
+ while tb:
+ frameinfo = (tb.tb_frame,) + getframeinfo(tb, context)
+ framelist.append(FrameInfo(*frameinfo))
+ tb = tb.tb_next
+ return framelist
+
+def currentframe():
+ """Return the frame of the caller or None if this is not possible."""
+ return sys._getframe(1) if hasattr(sys, "_getframe") else None
+
+def stack(context=1):
+ """Return a list of records for the stack above the caller's frame."""
+ return getouterframes(sys._getframe(1), context)
+
+def trace(context=1):
+ """Return a list of records for the stack below the current exception."""
+ return getinnerframes(sys.exc_info()[2], context)
+
+
+# ------------------------------------------------ static version of getattr
+
+_sentinel = object()
+
+def _static_getmro(klass):
+ return type.__dict__['__mro__'].__get__(klass)
+
+def _check_instance(obj, attr):
+ instance_dict = {}
+ try:
+ instance_dict = object.__getattribute__(obj, "__dict__")
+ except AttributeError:
+ pass
+ return dict.get(instance_dict, attr, _sentinel)
+
+
+def _check_class(klass, attr):
+ for entry in _static_getmro(klass):
+ if _shadowed_dict(type(entry)) is _sentinel:
+ try:
+ return entry.__dict__[attr]
+ except KeyError:
+ pass
+ return _sentinel
+
+def _is_type(obj):
+ try:
+ _static_getmro(obj)
+ except TypeError:
+ return False
+ return True
+
+def _shadowed_dict(klass):
+ dict_attr = type.__dict__["__dict__"]
+ for entry in _static_getmro(klass):
+ try:
+ class_dict = dict_attr.__get__(entry)["__dict__"]
+ except KeyError:
+ pass
+ else:
+ if not (type(class_dict) is types.GetSetDescriptorType and
+ class_dict.__name__ == "__dict__" and
+ class_dict.__objclass__ is entry):
+ return class_dict
+ return _sentinel
+
+def getattr_static(obj, attr, default=_sentinel):
+ """Retrieve attributes without triggering dynamic lookup via the
+ descriptor protocol, __getattr__ or __getattribute__.
+
+ Note: this function may not be able to retrieve all attributes
+ that getattr can fetch (like dynamically created attributes)
+ and may find attributes that getattr can't (like descriptors
+ that raise AttributeError). It can also return descriptor objects
+ instead of instance members in some cases. See the
+ documentation for details.
+ """
+ instance_result = _sentinel
+ if not _is_type(obj):
+ klass = type(obj)
+ dict_attr = _shadowed_dict(klass)
+ if (dict_attr is _sentinel or
+ type(dict_attr) is types.MemberDescriptorType):
+ instance_result = _check_instance(obj, attr)
+ else:
+ klass = obj
+
+ klass_result = _check_class(klass, attr)
+
+ if instance_result is not _sentinel and klass_result is not _sentinel:
+ if (_check_class(type(klass_result), '__get__') is not _sentinel and
+ _check_class(type(klass_result), '__set__') is not _sentinel):
+ return klass_result
+
+ if instance_result is not _sentinel:
+ return instance_result
+ if klass_result is not _sentinel:
+ return klass_result
+
+ if obj is klass:
+ # for types we check the metaclass too
+ for entry in _static_getmro(type(klass)):
+ if _shadowed_dict(type(entry)) is _sentinel:
+ try:
+ return entry.__dict__[attr]
+ except KeyError:
+ pass
+ if default is not _sentinel:
+ return default
+ raise AttributeError(attr)
+
+
+# ------------------------------------------------ generator introspection
+
+GEN_CREATED = 'GEN_CREATED'
+GEN_RUNNING = 'GEN_RUNNING'
+GEN_SUSPENDED = 'GEN_SUSPENDED'
+GEN_CLOSED = 'GEN_CLOSED'
+
+def getgeneratorstate(generator):
+ """Get current state of a generator-iterator.
+
+ Possible states are:
+ GEN_CREATED: Waiting to start execution.
+ GEN_RUNNING: Currently being executed by the interpreter.
+ GEN_SUSPENDED: Currently suspended at a yield expression.
+ GEN_CLOSED: Execution has completed.
+ """
+ if generator.gi_running:
+ return GEN_RUNNING
+ if generator.gi_frame is None:
+ return GEN_CLOSED
+ if generator.gi_frame.f_lasti == -1:
+ return GEN_CREATED
+ return GEN_SUSPENDED
+
+
+def getgeneratorlocals(generator):
+ """
+ Get the mapping of generator local variables to their current values.
+
+ A dict is returned, with the keys the local variable names and values the
+ bound values."""
+
+ if not isgenerator(generator):
+ raise TypeError("{!r} is not a Python generator".format(generator))
+
+ frame = getattr(generator, "gi_frame", None)
+ if frame is not None:
+ return generator.gi_frame.f_locals
+ else:
+ return {}
+
+
+# ------------------------------------------------ coroutine introspection
+
+CORO_CREATED = 'CORO_CREATED'
+CORO_RUNNING = 'CORO_RUNNING'
+CORO_SUSPENDED = 'CORO_SUSPENDED'
+CORO_CLOSED = 'CORO_CLOSED'
+
+def getcoroutinestate(coroutine):
+ """Get current state of a coroutine object.
+
+ Possible states are:
+ CORO_CREATED: Waiting to start execution.
+ CORO_RUNNING: Currently being executed by the interpreter.
+ CORO_SUSPENDED: Currently suspended at an await expression.
+ CORO_CLOSED: Execution has completed.
+ """
+ if coroutine.cr_running:
+ return CORO_RUNNING
+ if coroutine.cr_frame is None:
+ return CORO_CLOSED
+ if coroutine.cr_frame.f_lasti == -1:
+ return CORO_CREATED
+ return CORO_SUSPENDED
+
+
+def getcoroutinelocals(coroutine):
+ """
+ Get the mapping of coroutine local variables to their current values.
+
+ A dict is returned, with the keys the local variable names and values the
+ bound values."""
+ frame = getattr(coroutine, "cr_frame", None)
+ if frame is not None:
+ return frame.f_locals
+ else:
+ return {}
+
+
+###############################################################################
+### Function Signature Object (PEP 362)
+###############################################################################
+
+
+_WrapperDescriptor = type(type.__call__)
+_MethodWrapper = type(all.__call__)
+_ClassMethodWrapper = type(int.__dict__['from_bytes'])
+
+_NonUserDefinedCallables = (_WrapperDescriptor,
+ _MethodWrapper,
+ _ClassMethodWrapper,
+ types.BuiltinFunctionType)
+
+
+def _signature_get_user_defined_method(cls, method_name):
+ """Private helper. Checks if ``cls`` has an attribute
+ named ``method_name`` and returns it only if it is a
+ pure python function.
+ """
+ try:
+ meth = getattr(cls, method_name)
+ except AttributeError:
+ return
+ else:
+ if not isinstance(meth, _NonUserDefinedCallables):
+ # Once '__signature__' will be added to 'C'-level
+ # callables, this check won't be necessary
+ return meth
+
+
+def _signature_get_partial(wrapped_sig, partial, extra_args=()):
+ """Private helper to calculate how 'wrapped_sig' signature will
+ look like after applying a 'functools.partial' object (or alike)
+ on it.
+ """
+
+ old_params = wrapped_sig.parameters
+ new_params = OrderedDict(old_params.items())
+
+ partial_args = partial.args or ()
+ partial_keywords = partial.keywords or {}
+
+ if extra_args:
+ partial_args = extra_args + partial_args
+
+ try:
+ ba = wrapped_sig.bind_partial(*partial_args, **partial_keywords)
+ except TypeError as ex:
+ msg = 'partial object {!r} has incorrect arguments'.format(partial)
+ raise ValueError(msg) from ex
+
+
+ transform_to_kwonly = False
+ for param_name, param in old_params.items():
+ try:
+ arg_value = ba.arguments[param_name]
+ except KeyError:
+ pass
+ else:
+ if param.kind is _POSITIONAL_ONLY:
+ # If positional-only parameter is bound by partial,
+ # it effectively disappears from the signature
+ new_params.pop(param_name)
+ continue
+
+ if param.kind is _POSITIONAL_OR_KEYWORD:
+ if param_name in partial_keywords:
+ # This means that this parameter, and all parameters
+ # after it should be keyword-only (and var-positional
+ # should be removed). Here's why. Consider the following
+ # function:
+ # foo(a, b, *args, c):
+ # pass
+ #
+ # "partial(foo, a='spam')" will have the following
+ # signature: "(*, a='spam', b, c)". Because attempting
+ # to call that partial with "(10, 20)" arguments will
+ # raise a TypeError, saying that "a" argument received
+ # multiple values.
+ transform_to_kwonly = True
+ # Set the new default value
+ new_params[param_name] = param.replace(default=arg_value)
+ else:
+ # was passed as a positional argument
+ new_params.pop(param.name)
+ continue
+
+ if param.kind is _KEYWORD_ONLY:
+ # Set the new default value
+ new_params[param_name] = param.replace(default=arg_value)
+
+ if transform_to_kwonly:
+ assert param.kind is not _POSITIONAL_ONLY
+
+ if param.kind is _POSITIONAL_OR_KEYWORD:
+ new_param = new_params[param_name].replace(kind=_KEYWORD_ONLY)
+ new_params[param_name] = new_param
+ new_params.move_to_end(param_name)
+ elif param.kind in (_KEYWORD_ONLY, _VAR_KEYWORD):
+ new_params.move_to_end(param_name)
+ elif param.kind is _VAR_POSITIONAL:
+ new_params.pop(param.name)
+
+ return wrapped_sig.replace(parameters=new_params.values())
+
+
+def _signature_bound_method(sig):
+ """Private helper to transform signatures for unbound
+ functions to bound methods.
+ """
+
+ params = tuple(sig.parameters.values())
+
+ if not params or params[0].kind in (_VAR_KEYWORD, _KEYWORD_ONLY):
+ raise ValueError('invalid method signature')
+
+ kind = params[0].kind
+ if kind in (_POSITIONAL_OR_KEYWORD, _POSITIONAL_ONLY):
+ # Drop first parameter:
+ # '(p1, p2[, ...])' -> '(p2[, ...])'
+ params = params[1:]
+ else:
+ if kind is not _VAR_POSITIONAL:
+ # Unless we add a new parameter type we never
+ # get here
+ raise ValueError('invalid argument type')
+ # It's a var-positional parameter.
+ # Do nothing. '(*args[, ...])' -> '(*args[, ...])'
+
+ return sig.replace(parameters=params)
+
+
+def _signature_is_builtin(obj):
+ """Private helper to test if `obj` is a callable that might
+ support Argument Clinic's __text_signature__ protocol.
+ """
+ return (isbuiltin(obj) or
+ ismethoddescriptor(obj) or
+ isinstance(obj, _NonUserDefinedCallables) or
+ # Can't test 'isinstance(type)' here, as it would
+ # also be True for regular python classes
+ obj in (type, object))
+
+
+def _signature_is_functionlike(obj):
+ """Private helper to test if `obj` is a duck type of FunctionType.
+ A good example of such objects are functions compiled with
+ Cython, which have all attributes that a pure Python function
+ would have, but have their code statically compiled.
+ """
+
+ if not callable(obj) or isclass(obj):
+ # All function-like objects are obviously callables,
+ # and not classes.
+ return False
+
+ name = getattr(obj, '__name__', None)
+ code = getattr(obj, '__code__', None)
+ defaults = getattr(obj, '__defaults__', _void) # Important to use _void ...
+ kwdefaults = getattr(obj, '__kwdefaults__', _void) # ... and not None here
+ annotations = getattr(obj, '__annotations__', None)
+
+ return (isinstance(code, types.CodeType) and
+ isinstance(name, str) and
+ (defaults is None or isinstance(defaults, tuple)) and
+ (kwdefaults is None or isinstance(kwdefaults, dict)) and
+ isinstance(annotations, dict))
+
+
+def _signature_get_bound_param(spec):
+ """ Private helper to get first parameter name from a
+ __text_signature__ of a builtin method, which should
+ be in the following format: '($param1, ...)'.
+ Assumptions are that the first argument won't have
+ a default value or an annotation.
+ """
+
+ assert spec.startswith('($')
+
+ pos = spec.find(',')
+ if pos == -1:
+ pos = spec.find(')')
+
+ cpos = spec.find(':')
+ assert cpos == -1 or cpos > pos
+
+ cpos = spec.find('=')
+ assert cpos == -1 or cpos > pos
+
+ return spec[2:pos]
+
+
+def _signature_strip_non_python_syntax(signature):
+ """
+ Private helper function. Takes a signature in Argument Clinic's
+ extended signature format.
+
+ Returns a tuple of three things:
+ * that signature re-rendered in standard Python syntax,
+ * the index of the "self" parameter (generally 0), or None if
+ the function does not have a "self" parameter, and
+ * the index of the last "positional only" parameter,
+ or None if the signature has no positional-only parameters.
+ """
+
+ if not signature:
+ return signature, None, None
+
+ self_parameter = None
+ last_positional_only = None
+
+ lines = [l.encode('ascii') for l in signature.split('\n')]
+ generator = iter(lines).__next__
+ token_stream = tokenize.tokenize(generator)
+
+ delayed_comma = False
+ skip_next_comma = False
+ text = []
+ add = text.append
+
+ current_parameter = 0
+ OP = token.OP
+ ERRORTOKEN = token.ERRORTOKEN
+
+ # token stream always starts with ENCODING token, skip it
+ t = next(token_stream)
+ assert t.type == tokenize.ENCODING
+
+ for t in token_stream:
+ type, string = t.type, t.string
+
+ if type == OP:
+ if string == ',':
+ if skip_next_comma:
+ skip_next_comma = False
+ else:
+ assert not delayed_comma
+ delayed_comma = True
+ current_parameter += 1
+ continue
+
+ if string == '/':
+ assert not skip_next_comma
+ assert last_positional_only is None
+ skip_next_comma = True
+ last_positional_only = current_parameter - 1
+ continue
+
+ if (type == ERRORTOKEN) and (string == '$'):
+ assert self_parameter is None
+ self_parameter = current_parameter
+ continue
+
+ if delayed_comma:
+ delayed_comma = False
+ if not ((type == OP) and (string == ')')):
+ add(', ')
+ add(string)
+ if (string == ','):
+ add(' ')
+ clean_signature = ''.join(text)
+ return clean_signature, self_parameter, last_positional_only
+
+
+def _signature_fromstr(cls, obj, s, skip_bound_arg=True):
+ """Private helper to parse content of '__text_signature__'
+ and return a Signature based on it.
+ """
+ # Lazy import ast because it's relatively heavy and
+ # it's not used for other than this function.
+ import ast
+
+ Parameter = cls._parameter_cls
+
+ clean_signature, self_parameter, last_positional_only = \
+ _signature_strip_non_python_syntax(s)
+
+ program = "def foo" + clean_signature + ": pass"
+
+ try:
+ module = ast.parse(program)
+ except SyntaxError:
+ module = None
+
+ if not isinstance(module, ast.Module):
+ raise ValueError("{!r} builtin has invalid signature".format(obj))
+
+ f = module.body[0]
+
+ parameters = []
+ empty = Parameter.empty
+ invalid = object()
+
+ module = None
+ module_dict = {}
+ module_name = getattr(obj, '__module__', None)
+ if module_name:
+ module = sys.modules.get(module_name, None)
+ if module:
+ module_dict = module.__dict__
+ sys_module_dict = sys.modules.copy()
+
+ def parse_name(node):
+ assert isinstance(node, ast.arg)
+ if node.annotation is not None:
+ raise ValueError("Annotations are not currently supported")
+ return node.arg
+
+ def wrap_value(s):
+ try:
+ value = eval(s, module_dict)
+ except NameError:
+ try:
+ value = eval(s, sys_module_dict)
+ except NameError:
+ raise RuntimeError()
+
+ if isinstance(value, (str, int, float, bytes, bool, type(None))):
+ return ast.Constant(value)
+ raise RuntimeError()
+
+ class RewriteSymbolics(ast.NodeTransformer):
+ def visit_Attribute(self, node):
+ a = []
+ n = node
+ while isinstance(n, ast.Attribute):
+ a.append(n.attr)
+ n = n.value
+ if not isinstance(n, ast.Name):
+ raise RuntimeError()
+ a.append(n.id)
+ value = ".".join(reversed(a))
+ return wrap_value(value)
+
+ def visit_Name(self, node):
+ if not isinstance(node.ctx, ast.Load):
+ raise ValueError()
+ return wrap_value(node.id)
+
+ def p(name_node, default_node, default=empty):
+ name = parse_name(name_node)
+ if name is invalid:
+ return None
+ if default_node and default_node is not _empty:
+ try:
+ default_node = RewriteSymbolics().visit(default_node)
+ o = ast.literal_eval(default_node)
+ except ValueError:
+ o = invalid
+ if o is invalid:
+ return None
+ default = o if o is not invalid else default
+ parameters.append(Parameter(name, kind, default=default, annotation=empty))
+
+ # non-keyword-only parameters
+ args = reversed(f.args.args)
+ defaults = reversed(f.args.defaults)
+ iter = itertools.zip_longest(args, defaults, fillvalue=None)
+ if last_positional_only is not None:
+ kind = Parameter.POSITIONAL_ONLY
+ else:
+ kind = Parameter.POSITIONAL_OR_KEYWORD
+ for i, (name, default) in enumerate(reversed(list(iter))):
+ p(name, default)
+ if i == last_positional_only:
+ kind = Parameter.POSITIONAL_OR_KEYWORD
+
+ # *args
+ if f.args.vararg:
+ kind = Parameter.VAR_POSITIONAL
+ p(f.args.vararg, empty)
+
+ # keyword-only arguments
+ kind = Parameter.KEYWORD_ONLY
+ for name, default in zip(f.args.kwonlyargs, f.args.kw_defaults):
+ p(name, default)
+
+ # **kwargs
+ if f.args.kwarg:
+ kind = Parameter.VAR_KEYWORD
+ p(f.args.kwarg, empty)
+
+ if self_parameter is not None:
+ # Possibly strip the bound argument:
+ # - We *always* strip first bound argument if
+ # it is a module.
+ # - We don't strip first bound argument if
+ # skip_bound_arg is False.
+ assert parameters
+ _self = getattr(obj, '__self__', None)
+ self_isbound = _self is not None
+ self_ismodule = ismodule(_self)
+ if self_isbound and (self_ismodule or skip_bound_arg):
+ parameters.pop(0)
+ else:
+ # for builtins, self parameter is always positional-only!
+ p = parameters[0].replace(kind=Parameter.POSITIONAL_ONLY)
+ parameters[0] = p
+
+ return cls(parameters, return_annotation=cls.empty)
+
+
+def _signature_from_builtin(cls, func, skip_bound_arg=True):
+ """Private helper function to get signature for
+ builtin callables.
+ """
+
+ if not _signature_is_builtin(func):
+ raise TypeError("{!r} is not a Python builtin "
+ "function".format(func))
+
+ s = getattr(func, "__text_signature__", None)
+ if not s:
+ raise ValueError("no signature found for builtin {!r}".format(func))
+
+ return _signature_fromstr(cls, func, s, skip_bound_arg)
+
+
+def _signature_from_function(cls, func, skip_bound_arg=True):
+ """Private helper: constructs Signature for the given python function."""
+
+ is_duck_function = False
+ if not isfunction(func):
+ if _signature_is_functionlike(func):
+ is_duck_function = True
+ else:
+ # If it's not a pure Python function, and not a duck type
+ # of pure function:
+ raise TypeError('{!r} is not a Python function'.format(func))
+
+ s = getattr(func, "__text_signature__", None)
+ if s:
+ return _signature_fromstr(cls, func, s, skip_bound_arg)
+
+ Parameter = cls._parameter_cls
+
+ # Parameter information.
+ func_code = func.__code__
+ pos_count = func_code.co_argcount
+ arg_names = func_code.co_varnames
+ posonly_count = func_code.co_posonlyargcount
+ positional = arg_names[:pos_count]
+ keyword_only_count = func_code.co_kwonlyargcount
+ keyword_only = arg_names[pos_count:pos_count + keyword_only_count]
+ annotations = func.__annotations__
+ defaults = func.__defaults__
+ kwdefaults = func.__kwdefaults__
+
+ if defaults:
+ pos_default_count = len(defaults)
+ else:
+ pos_default_count = 0
+
+ parameters = []
+
+ non_default_count = pos_count - pos_default_count
+ posonly_left = posonly_count
+
+ # Non-keyword-only parameters w/o defaults.
+ for name in positional[:non_default_count]:
+ kind = _POSITIONAL_ONLY if posonly_left else _POSITIONAL_OR_KEYWORD
+ annotation = annotations.get(name, _empty)
+ parameters.append(Parameter(name, annotation=annotation,
+ kind=kind))
+ if posonly_left:
+ posonly_left -= 1
+
+ # ... w/ defaults.
+ for offset, name in enumerate(positional[non_default_count:]):
+ kind = _POSITIONAL_ONLY if posonly_left else _POSITIONAL_OR_KEYWORD
+ annotation = annotations.get(name, _empty)
+ parameters.append(Parameter(name, annotation=annotation,
+ kind=kind,
+ default=defaults[offset]))
+ if posonly_left:
+ posonly_left -= 1
+
+ # *args
+ if func_code.co_flags & CO_VARARGS:
+ name = arg_names[pos_count + keyword_only_count]
+ annotation = annotations.get(name, _empty)
+ parameters.append(Parameter(name, annotation=annotation,
+ kind=_VAR_POSITIONAL))
+
+ # Keyword-only parameters.
+ for name in keyword_only:
+ default = _empty
+ if kwdefaults is not None:
+ default = kwdefaults.get(name, _empty)
+
+ annotation = annotations.get(name, _empty)
+ parameters.append(Parameter(name, annotation=annotation,
+ kind=_KEYWORD_ONLY,
+ default=default))
+ # **kwargs
+ if func_code.co_flags & CO_VARKEYWORDS:
+ index = pos_count + keyword_only_count
+ if func_code.co_flags & CO_VARARGS:
+ index += 1
+
+ name = arg_names[index]
+ annotation = annotations.get(name, _empty)
+ parameters.append(Parameter(name, annotation=annotation,
+ kind=_VAR_KEYWORD))
+
+ # Is 'func' is a pure Python function - don't validate the
+ # parameters list (for correct order and defaults), it should be OK.
+ return cls(parameters,
+ return_annotation=annotations.get('return', _empty),
+ __validate_parameters__=is_duck_function)
+
+
+def _signature_from_callable(obj, *,
+ follow_wrapper_chains=True,
+ skip_bound_arg=True,
+ sigcls):
+
+ """Private helper function to get signature for arbitrary
+ callable objects.
+ """
+
+ if not callable(obj):
+ raise TypeError('{!r} is not a callable object'.format(obj))
+
+ if isinstance(obj, types.MethodType):
+ # In this case we skip the first parameter of the underlying
+ # function (usually `self` or `cls`).
+ sig = _signature_from_callable(
+ obj.__func__,
+ follow_wrapper_chains=follow_wrapper_chains,
+ skip_bound_arg=skip_bound_arg,
+ sigcls=sigcls)
+
+ if skip_bound_arg:
+ return _signature_bound_method(sig)
+ else:
+ return sig
+
+ # Was this function wrapped by a decorator?
+ if follow_wrapper_chains:
+ obj = unwrap(obj, stop=(lambda f: hasattr(f, "__signature__")))
+ if isinstance(obj, types.MethodType):
+ # If the unwrapped object is a *method*, we might want to
+ # skip its first parameter (self).
+ # See test_signature_wrapped_bound_method for details.
+ return _signature_from_callable(
+ obj,
+ follow_wrapper_chains=follow_wrapper_chains,
+ skip_bound_arg=skip_bound_arg,
+ sigcls=sigcls)
+
+ try:
+ sig = obj.__signature__
+ except AttributeError:
+ pass
+ else:
+ if sig is not None:
+ if not isinstance(sig, Signature):
+ raise TypeError(
+ 'unexpected object {!r} in __signature__ '
+ 'attribute'.format(sig))
+ return sig
+
+ try:
+ partialmethod = obj._partialmethod
+ except AttributeError:
+ pass
+ else:
+ if isinstance(partialmethod, functools.partialmethod):
+ # Unbound partialmethod (see functools.partialmethod)
+ # This means, that we need to calculate the signature
+ # as if it's a regular partial object, but taking into
+ # account that the first positional argument
+ # (usually `self`, or `cls`) will not be passed
+ # automatically (as for boundmethods)
+
+ wrapped_sig = _signature_from_callable(
+ partialmethod.func,
+ follow_wrapper_chains=follow_wrapper_chains,
+ skip_bound_arg=skip_bound_arg,
+ sigcls=sigcls)
+
+ sig = _signature_get_partial(wrapped_sig, partialmethod, (None,))
+ first_wrapped_param = tuple(wrapped_sig.parameters.values())[0]
+ if first_wrapped_param.kind is Parameter.VAR_POSITIONAL:
+ # First argument of the wrapped callable is `*args`, as in
+ # `partialmethod(lambda *args)`.
+ return sig
+ else:
+ sig_params = tuple(sig.parameters.values())
+ assert (not sig_params or
+ first_wrapped_param is not sig_params[0])
+ new_params = (first_wrapped_param,) + sig_params
+ return sig.replace(parameters=new_params)
+
+ if isfunction(obj) or _signature_is_functionlike(obj):
+ # If it's a pure Python function, or an object that is duck type
+ # of a Python function (Cython functions, for instance), then:
+ return _signature_from_function(sigcls, obj,
+ skip_bound_arg=skip_bound_arg)
+
+ if _signature_is_builtin(obj):
+ return _signature_from_builtin(sigcls, obj,
+ skip_bound_arg=skip_bound_arg)
+
+ if isinstance(obj, functools.partial):
+ wrapped_sig = _signature_from_callable(
+ obj.func,
+ follow_wrapper_chains=follow_wrapper_chains,
+ skip_bound_arg=skip_bound_arg,
+ sigcls=sigcls)
+ return _signature_get_partial(wrapped_sig, obj)
+
+ sig = None
+ if isinstance(obj, type):
+ # obj is a class or a metaclass
+
+ # First, let's see if it has an overloaded __call__ defined
+ # in its metaclass
+ call = _signature_get_user_defined_method(type(obj), '__call__')
+ if call is not None:
+ sig = _signature_from_callable(
+ call,
+ follow_wrapper_chains=follow_wrapper_chains,
+ skip_bound_arg=skip_bound_arg,
+ sigcls=sigcls)
+ else:
+ # Now we check if the 'obj' class has a '__new__' method
+ new = _signature_get_user_defined_method(obj, '__new__')
+ if new is not None:
+ sig = _signature_from_callable(
+ new,
+ follow_wrapper_chains=follow_wrapper_chains,
+ skip_bound_arg=skip_bound_arg,
+ sigcls=sigcls)
+ else:
+ # Finally, we should have at least __init__ implemented
+ init = _signature_get_user_defined_method(obj, '__init__')
+ if init is not None:
+ sig = _signature_from_callable(
+ init,
+ follow_wrapper_chains=follow_wrapper_chains,
+ skip_bound_arg=skip_bound_arg,
+ sigcls=sigcls)
+
+ if sig is None:
+ # At this point we know, that `obj` is a class, with no user-
+ # defined '__init__', '__new__', or class-level '__call__'
+
+ for base in obj.__mro__[:-1]:
+ # Since '__text_signature__' is implemented as a
+ # descriptor that extracts text signature from the
+ # class docstring, if 'obj' is derived from a builtin
+ # class, its own '__text_signature__' may be 'None'.
+ # Therefore, we go through the MRO (except the last
+ # class in there, which is 'object') to find the first
+ # class with non-empty text signature.
+ try:
+ text_sig = base.__text_signature__
+ except AttributeError:
+ pass
+ else:
+ if text_sig:
+ # If 'obj' class has a __text_signature__ attribute:
+ # return a signature based on it
+ return _signature_fromstr(sigcls, obj, text_sig)
+
+ # No '__text_signature__' was found for the 'obj' class.
+ # Last option is to check if its '__init__' is
+ # object.__init__ or type.__init__.
+ if type not in obj.__mro__:
+ # We have a class (not metaclass), but no user-defined
+ # __init__ or __new__ for it
+ if (obj.__init__ is object.__init__ and
+ obj.__new__ is object.__new__):
+ # Return a signature of 'object' builtin.
+ return sigcls.from_callable(object)
+ else:
+ raise ValueError(
+ 'no signature found for builtin type {!r}'.format(obj))
+
+ elif not isinstance(obj, _NonUserDefinedCallables):
+ # An object with __call__
+ # We also check that the 'obj' is not an instance of
+ # _WrapperDescriptor or _MethodWrapper to avoid
+ # infinite recursion (and even potential segfault)
+ call = _signature_get_user_defined_method(type(obj), '__call__')
+ if call is not None:
+ try:
+ sig = _signature_from_callable(
+ call,
+ follow_wrapper_chains=follow_wrapper_chains,
+ skip_bound_arg=skip_bound_arg,
+ sigcls=sigcls)
+ except ValueError as ex:
+ msg = 'no signature found for {!r}'.format(obj)
+ raise ValueError(msg) from ex
+
+ if sig is not None:
+ # For classes and objects we skip the first parameter of their
+ # __call__, __new__, or __init__ methods
+ if skip_bound_arg:
+ return _signature_bound_method(sig)
+ else:
+ return sig
+
+ if isinstance(obj, types.BuiltinFunctionType):
+ # Raise a nicer error message for builtins
+ msg = 'no signature found for builtin function {!r}'.format(obj)
+ raise ValueError(msg)
+
+ raise ValueError('callable {!r} is not supported by signature'.format(obj))
+
+
+class _void:
+ """A private marker - used in Parameter & Signature."""
+
+
+class _empty:
+ """Marker object for Signature.empty and Parameter.empty."""
+
+
+class _ParameterKind(enum.IntEnum):
+ POSITIONAL_ONLY = 0
+ POSITIONAL_OR_KEYWORD = 1
+ VAR_POSITIONAL = 2
+ KEYWORD_ONLY = 3
+ VAR_KEYWORD = 4
+
+ def __str__(self):
+ return self._name_
+
+ @property
+ def description(self):
+ return _PARAM_NAME_MAPPING[self]
+
+_POSITIONAL_ONLY = _ParameterKind.POSITIONAL_ONLY
+_POSITIONAL_OR_KEYWORD = _ParameterKind.POSITIONAL_OR_KEYWORD
+_VAR_POSITIONAL = _ParameterKind.VAR_POSITIONAL
+_KEYWORD_ONLY = _ParameterKind.KEYWORD_ONLY
+_VAR_KEYWORD = _ParameterKind.VAR_KEYWORD
+
+_PARAM_NAME_MAPPING = {
+ _POSITIONAL_ONLY: 'positional-only',
+ _POSITIONAL_OR_KEYWORD: 'positional or keyword',
+ _VAR_POSITIONAL: 'variadic positional',
+ _KEYWORD_ONLY: 'keyword-only',
+ _VAR_KEYWORD: 'variadic keyword'
+}
+
+
+class Parameter:
+ """Represents a parameter in a function signature.
+
+ Has the following public attributes:
+
+ * name : str
+ The name of the parameter as a string.
+ * default : object
+ The default value for the parameter if specified. If the
+ parameter has no default value, this attribute is set to
+ `Parameter.empty`.
+ * annotation
+ The annotation for the parameter if specified. If the
+ parameter has no annotation, this attribute is set to
+ `Parameter.empty`.
+ * kind : str
+ Describes how argument values are bound to the parameter.
+ Possible values: `Parameter.POSITIONAL_ONLY`,
+ `Parameter.POSITIONAL_OR_KEYWORD`, `Parameter.VAR_POSITIONAL`,
+ `Parameter.KEYWORD_ONLY`, `Parameter.VAR_KEYWORD`.
+ """
+
+ __slots__ = ('_name', '_kind', '_default', '_annotation')
+
+ POSITIONAL_ONLY = _POSITIONAL_ONLY
+ POSITIONAL_OR_KEYWORD = _POSITIONAL_OR_KEYWORD
+ VAR_POSITIONAL = _VAR_POSITIONAL
+ KEYWORD_ONLY = _KEYWORD_ONLY
+ VAR_KEYWORD = _VAR_KEYWORD
+
+ empty = _empty
+
+ def __init__(self, name, kind, *, default=_empty, annotation=_empty):
+ try:
+ self._kind = _ParameterKind(kind)
+ except ValueError:
+ raise ValueError(f'value {kind!r} is not a valid Parameter.kind')
+ if default is not _empty:
+ if self._kind in (_VAR_POSITIONAL, _VAR_KEYWORD):
+ msg = '{} parameters cannot have default values'
+ msg = msg.format(self._kind.description)
+ raise ValueError(msg)
+ self._default = default
+ self._annotation = annotation
+
+ if name is _empty:
+ raise ValueError('name is a required attribute for Parameter')
+
+ if not isinstance(name, str):
+ msg = 'name must be a str, not a {}'.format(type(name).__name__)
+ raise TypeError(msg)
+
+ if name[0] == '.' and name[1:].isdigit():
+ # These are implicit arguments generated by comprehensions. In
+ # order to provide a friendlier interface to users, we recast
+ # their name as "implicitN" and treat them as positional-only.
+ # See issue 19611.
+ if self._kind != _POSITIONAL_OR_KEYWORD:
+ msg = (
+ 'implicit arguments must be passed as '
+ 'positional or keyword arguments, not {}'
+ )
+ msg = msg.format(self._kind.description)
+ raise ValueError(msg)
+ self._kind = _POSITIONAL_ONLY
+ name = 'implicit{}'.format(name[1:])
+
+ if not name.isidentifier():
+ raise ValueError('{!r} is not a valid parameter name'.format(name))
+
+ self._name = name
+
+ def __reduce__(self):
+ return (type(self),
+ (self._name, self._kind),
+ {'_default': self._default,
+ '_annotation': self._annotation})
+
+ def __setstate__(self, state):
+ self._default = state['_default']
+ self._annotation = state['_annotation']
+
+ @property
+ def name(self):
+ return self._name
+
+ @property
+ def default(self):
+ return self._default
+
+ @property
+ def annotation(self):
+ return self._annotation
+
+ @property
+ def kind(self):
+ return self._kind
+
+ def replace(self, *, name=_void, kind=_void,
+ annotation=_void, default=_void):
+ """Creates a customized copy of the Parameter."""
+
+ if name is _void:
+ name = self._name
+
+ if kind is _void:
+ kind = self._kind
+
+ if annotation is _void:
+ annotation = self._annotation
+
+ if default is _void:
+ default = self._default
+
+ return type(self)(name, kind, default=default, annotation=annotation)
+
+ def __str__(self):
+ kind = self.kind
+ formatted = self._name
+
+ # Add annotation and default value
+ if self._annotation is not _empty:
+ formatted = '{}: {}'.format(formatted,
+ formatannotation(self._annotation))
+
+ if self._default is not _empty:
+ if self._annotation is not _empty:
+ formatted = '{} = {}'.format(formatted, repr(self._default))
+ else:
+ formatted = '{}={}'.format(formatted, repr(self._default))
+
+ if kind == _VAR_POSITIONAL:
+ formatted = '*' + formatted
+ elif kind == _VAR_KEYWORD:
+ formatted = '**' + formatted
+
+ return formatted
+
+ def __repr__(self):
+ return '<{} "{}">'.format(self.__class__.__name__, self)
+
+ def __hash__(self):
+ return hash((self.name, self.kind, self.annotation, self.default))
+
+ def __eq__(self, other):
+ if self is other:
+ return True
+ if not isinstance(other, Parameter):
+ return NotImplemented
+ return (self._name == other._name and
+ self._kind == other._kind and
+ self._default == other._default and
+ self._annotation == other._annotation)
+
+
+class BoundArguments:
+ """Result of `Signature.bind` call. Holds the mapping of arguments
+ to the function's parameters.
+
+ Has the following public attributes:
+
+ * arguments : OrderedDict
+ An ordered mutable mapping of parameters' names to arguments' values.
+ Does not contain arguments' default values.
+ * signature : Signature
+ The Signature object that created this instance.
+ * args : tuple
+ Tuple of positional arguments values.
+ * kwargs : dict
+ Dict of keyword arguments values.
+ """
+
+ __slots__ = ('arguments', '_signature', '__weakref__')
+
+ def __init__(self, signature, arguments):
+ self.arguments = arguments
+ self._signature = signature
+
+ @property
+ def signature(self):
+ return self._signature
+
+ @property
+ def args(self):
+ args = []
+ for param_name, param in self._signature.parameters.items():
+ if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY):
+ break
+
+ try:
+ arg = self.arguments[param_name]
+ except KeyError:
+ # We're done here. Other arguments
+ # will be mapped in 'BoundArguments.kwargs'
+ break
+ else:
+ if param.kind == _VAR_POSITIONAL:
+ # *args
+ args.extend(arg)
+ else:
+ # plain argument
+ args.append(arg)
+
+ return tuple(args)
+
+ @property
+ def kwargs(self):
+ kwargs = {}
+ kwargs_started = False
+ for param_name, param in self._signature.parameters.items():
+ if not kwargs_started:
+ if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY):
+ kwargs_started = True
+ else:
+ if param_name not in self.arguments:
+ kwargs_started = True
+ continue
+
+ if not kwargs_started:
+ continue
+
+ try:
+ arg = self.arguments[param_name]
+ except KeyError:
+ pass
+ else:
+ if param.kind == _VAR_KEYWORD:
+ # **kwargs
+ kwargs.update(arg)
+ else:
+ # plain keyword argument
+ kwargs[param_name] = arg
+
+ return kwargs
+
+ def apply_defaults(self):
+ """Set default values for missing arguments.
+
+ For variable-positional arguments (*args) the default is an
+ empty tuple.
+
+ For variable-keyword arguments (**kwargs) the default is an
+ empty dict.
+ """
+ arguments = self.arguments
+ new_arguments = []
+ for name, param in self._signature.parameters.items():
+ try:
+ new_arguments.append((name, arguments[name]))
+ except KeyError:
+ if param.default is not _empty:
+ val = param.default
+ elif param.kind is _VAR_POSITIONAL:
+ val = ()
+ elif param.kind is _VAR_KEYWORD:
+ val = {}
+ else:
+ # This BoundArguments was likely produced by
+ # Signature.bind_partial().
+ continue
+ new_arguments.append((name, val))
+ self.arguments = OrderedDict(new_arguments)
+
+ def __eq__(self, other):
+ if self is other:
+ return True
+ if not isinstance(other, BoundArguments):
+ return NotImplemented
+ return (self.signature == other.signature and
+ self.arguments == other.arguments)
+
+ def __setstate__(self, state):
+ self._signature = state['_signature']
+ self.arguments = state['arguments']
+
+ def __getstate__(self):
+ return {'_signature': self._signature, 'arguments': self.arguments}
+
+ def __repr__(self):
+ args = []
+ for arg, value in self.arguments.items():
+ args.append('{}={!r}'.format(arg, value))
+ return '<{} ({})>'.format(self.__class__.__name__, ', '.join(args))
+
+
+class Signature:
+ """A Signature object represents the overall signature of a function.
+ It stores a Parameter object for each parameter accepted by the
+ function, as well as information specific to the function itself.
+
+ A Signature object has the following public attributes and methods:
+
+ * parameters : OrderedDict
+ An ordered mapping of parameters' names to the corresponding
+ Parameter objects (keyword-only arguments are in the same order
+ as listed in `code.co_varnames`).
+ * return_annotation : object
+ The annotation for the return type of the function if specified.
+ If the function has no annotation for its return type, this
+ attribute is set to `Signature.empty`.
+ * bind(*args, **kwargs) -> BoundArguments
+ Creates a mapping from positional and keyword arguments to
+ parameters.
+ * bind_partial(*args, **kwargs) -> BoundArguments
+ Creates a partial mapping from positional and keyword arguments
+ to parameters (simulating 'functools.partial' behavior.)
+ """
+
+ __slots__ = ('_return_annotation', '_parameters')
+
+ _parameter_cls = Parameter
+ _bound_arguments_cls = BoundArguments
+
+ empty = _empty
+
+ def __init__(self, parameters=None, *, return_annotation=_empty,
+ __validate_parameters__=True):
+ """Constructs Signature from the given list of Parameter
+ objects and 'return_annotation'. All arguments are optional.
+ """
+
+ if parameters is None:
+ params = OrderedDict()
+ else:
+ if __validate_parameters__:
+ params = OrderedDict()
+ top_kind = _POSITIONAL_ONLY
+ kind_defaults = False
+
+ for idx, param in enumerate(parameters):
+ kind = param.kind
+ name = param.name
+
+ if kind < top_kind:
+ msg = (
+ 'wrong parameter order: {} parameter before {} '
+ 'parameter'
+ )
+ msg = msg.format(top_kind.description,
+ kind.description)
+ raise ValueError(msg)
+ elif kind > top_kind:
+ kind_defaults = False
+ top_kind = kind
+
+ if kind in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD):
+ if param.default is _empty:
+ if kind_defaults:
+ # No default for this parameter, but the
+ # previous parameter of the same kind had
+ # a default
+ msg = 'non-default argument follows default ' \
+ 'argument'
+ raise ValueError(msg)
+ else:
+ # There is a default for this parameter.
+ kind_defaults = True
+
+ if name in params:
+ msg = 'duplicate parameter name: {!r}'.format(name)
+ raise ValueError(msg)
+
+ params[name] = param
+ else:
+ params = OrderedDict(((param.name, param)
+ for param in parameters))
+
+ self._parameters = types.MappingProxyType(params)
+ self._return_annotation = return_annotation
+
+ @classmethod
+ def from_function(cls, func):
+ """Constructs Signature for the given python function.
+
+ Deprecated since Python 3.5, use `Signature.from_callable()`.
+ """
+
+ warnings.warn("inspect.Signature.from_function() is deprecated since "
+ "Python 3.5, use Signature.from_callable()",
+ DeprecationWarning, stacklevel=2)
+ return _signature_from_function(cls, func)
+
+ @classmethod
+ def from_builtin(cls, func):
+ """Constructs Signature for the given builtin function.
+
+ Deprecated since Python 3.5, use `Signature.from_callable()`.
+ """
+
+ warnings.warn("inspect.Signature.from_builtin() is deprecated since "
+ "Python 3.5, use Signature.from_callable()",
+ DeprecationWarning, stacklevel=2)
+ return _signature_from_builtin(cls, func)
+
+ @classmethod
+ def from_callable(cls, obj, *, follow_wrapped=True):
+ """Constructs Signature for the given callable object."""
+ return _signature_from_callable(obj, sigcls=cls,
+ follow_wrapper_chains=follow_wrapped)
+
+ @property
+ def parameters(self):
+ return self._parameters
+
+ @property
+ def return_annotation(self):
+ return self._return_annotation
+
+ def replace(self, *, parameters=_void, return_annotation=_void):
+ """Creates a customized copy of the Signature.
+ Pass 'parameters' and/or 'return_annotation' arguments
+ to override them in the new copy.
+ """
+
+ if parameters is _void:
+ parameters = self.parameters.values()
+
+ if return_annotation is _void:
+ return_annotation = self._return_annotation
+
+ return type(self)(parameters,
+ return_annotation=return_annotation)
+
+ def _hash_basis(self):
+ params = tuple(param for param in self.parameters.values()
+ if param.kind != _KEYWORD_ONLY)
+
+ kwo_params = {param.name: param for param in self.parameters.values()
+ if param.kind == _KEYWORD_ONLY}
+
+ return params, kwo_params, self.return_annotation
+
+ def __hash__(self):
+ params, kwo_params, return_annotation = self._hash_basis()
+ kwo_params = frozenset(kwo_params.values())
+ return hash((params, kwo_params, return_annotation))
+
+ def __eq__(self, other):
+ if self is other:
+ return True
+ if not isinstance(other, Signature):
+ return NotImplemented
+ return self._hash_basis() == other._hash_basis()
+
+ def _bind(self, args, kwargs, *, partial=False):
+ """Private method. Don't use directly."""
+
+ arguments = OrderedDict()
+
+ parameters = iter(self.parameters.values())
+ parameters_ex = ()
+ arg_vals = iter(args)
+
+ while True:
+ # Let's iterate through the positional arguments and corresponding
+ # parameters
+ try:
+ arg_val = next(arg_vals)
+ except StopIteration:
+ # No more positional arguments
+ try:
+ param = next(parameters)
+ except StopIteration:
+ # No more parameters. That's it. Just need to check that
+ # we have no `kwargs` after this while loop
+ break
+ else:
+ if param.kind == _VAR_POSITIONAL:
+ # That's OK, just empty *args. Let's start parsing
+ # kwargs
+ break
+ elif param.name in kwargs:
+ if param.kind == _POSITIONAL_ONLY:
+ msg = '{arg!r} parameter is positional only, ' \
+ 'but was passed as a keyword'
+ msg = msg.format(arg=param.name)
+ raise TypeError(msg) from None
+ parameters_ex = (param,)
+ break
+ elif (param.kind == _VAR_KEYWORD or
+ param.default is not _empty):
+ # That's fine too - we have a default value for this
+ # parameter. So, lets start parsing `kwargs`, starting
+ # with the current parameter
+ parameters_ex = (param,)
+ break
+ else:
+ # No default, not VAR_KEYWORD, not VAR_POSITIONAL,
+ # not in `kwargs`
+ if partial:
+ parameters_ex = (param,)
+ break
+ else:
+ msg = 'missing a required argument: {arg!r}'
+ msg = msg.format(arg=param.name)
+ raise TypeError(msg) from None
+ else:
+ # We have a positional argument to process
+ try:
+ param = next(parameters)
+ except StopIteration:
+ raise TypeError('too many positional arguments') from None
+ else:
+ if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY):
+ # Looks like we have no parameter for this positional
+ # argument
+ raise TypeError(
+ 'too many positional arguments') from None
+
+ if param.kind == _VAR_POSITIONAL:
+ # We have an '*args'-like argument, let's fill it with
+ # all positional arguments we have left and move on to
+ # the next phase
+ values = [arg_val]
+ values.extend(arg_vals)
+ arguments[param.name] = tuple(values)
+ break
+
+ if param.name in kwargs and param.kind != _POSITIONAL_ONLY:
+ raise TypeError(
+ 'multiple values for argument {arg!r}'.format(
+ arg=param.name)) from None
+
+ arguments[param.name] = arg_val
+
+ # Now, we iterate through the remaining parameters to process
+ # keyword arguments
+ kwargs_param = None
+ for param in itertools.chain(parameters_ex, parameters):
+ if param.kind == _VAR_KEYWORD:
+ # Memorize that we have a '**kwargs'-like parameter
+ kwargs_param = param
+ continue
+
+ if param.kind == _VAR_POSITIONAL:
+ # Named arguments don't refer to '*args'-like parameters.
+ # We only arrive here if the positional arguments ended
+ # before reaching the last parameter before *args.
+ continue
+
+ param_name = param.name
+ try:
+ arg_val = kwargs.pop(param_name)
+ except KeyError:
+ # We have no value for this parameter. It's fine though,
+ # if it has a default value, or it is an '*args'-like
+ # parameter, left alone by the processing of positional
+ # arguments.
+ if (not partial and param.kind != _VAR_POSITIONAL and
+ param.default is _empty):
+ raise TypeError('missing a required argument: {arg!r}'. \
+ format(arg=param_name)) from None
+
+ else:
+ if param.kind == _POSITIONAL_ONLY:
+ # This should never happen in case of a properly built
+ # Signature object (but let's have this check here
+ # to ensure correct behaviour just in case)
+ raise TypeError('{arg!r} parameter is positional only, '
+ 'but was passed as a keyword'. \
+ format(arg=param.name))
+
+ arguments[param_name] = arg_val
+
+ if kwargs:
+ if kwargs_param is not None:
+ # Process our '**kwargs'-like parameter
+ arguments[kwargs_param.name] = kwargs
+ else:
+ raise TypeError(
+ 'got an unexpected keyword argument {arg!r}'.format(
+ arg=next(iter(kwargs))))
+
+ return self._bound_arguments_cls(self, arguments)
+
+ def bind(self, /, *args, **kwargs):
+ """Get a BoundArguments object, that maps the passed `args`
+ and `kwargs` to the function's signature. Raises `TypeError`
+ if the passed arguments can not be bound.
+ """
+ return self._bind(args, kwargs)
+
+ def bind_partial(self, /, *args, **kwargs):
+ """Get a BoundArguments object, that partially maps the
+ passed `args` and `kwargs` to the function's signature.
+ Raises `TypeError` if the passed arguments can not be bound.
+ """
+ return self._bind(args, kwargs, partial=True)
+
+ def __reduce__(self):
+ return (type(self),
+ (tuple(self._parameters.values()),),
+ {'_return_annotation': self._return_annotation})
+
+ def __setstate__(self, state):
+ self._return_annotation = state['_return_annotation']
+
+ def __repr__(self):
+ return '<{} {}>'.format(self.__class__.__name__, self)
+
+ def __str__(self):
+ result = []
+ render_pos_only_separator = False
+ render_kw_only_separator = True
+ for param in self.parameters.values():
+ formatted = str(param)
+
+ kind = param.kind
+
+ if kind == _POSITIONAL_ONLY:
+ render_pos_only_separator = True
+ elif render_pos_only_separator:
+ # It's not a positional-only parameter, and the flag
+ # is set to 'True' (there were pos-only params before.)
+ result.append('/')
+ render_pos_only_separator = False
+
+ if kind == _VAR_POSITIONAL:
+ # OK, we have an '*args'-like parameter, so we won't need
+ # a '*' to separate keyword-only arguments
+ render_kw_only_separator = False
+ elif kind == _KEYWORD_ONLY and render_kw_only_separator:
+ # We have a keyword-only parameter to render and we haven't
+ # rendered an '*args'-like parameter before, so add a '*'
+ # separator to the parameters list ("foo(arg1, *, arg2)" case)
+ result.append('*')
+ # This condition should be only triggered once, so
+ # reset the flag
+ render_kw_only_separator = False
+
+ result.append(formatted)
+
+ if render_pos_only_separator:
+ # There were only positional-only parameters, hence the
+ # flag was not reset to 'False'
+ result.append('/')
+
+ rendered = '({})'.format(', '.join(result))
+
+ if self.return_annotation is not _empty:
+ anno = formatannotation(self.return_annotation)
+ rendered += ' -> {}'.format(anno)
+
+ return rendered
+
+
+def signature(obj, *, follow_wrapped=True):
+ """Get a signature object for the passed callable."""
+ return Signature.from_callable(obj, follow_wrapped=follow_wrapped)
+
+
+def _main():
+ """ Logic for inspecting an object given at command line """
+ import argparse
+ import importlib
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ 'object',
+ help="The object to be analysed. "
+ "It supports the 'module:qualname' syntax")
+ parser.add_argument(
+ '-d', '--details', action='store_true',
+ help='Display info about the module rather than its source code')
+
+ args = parser.parse_args()
+
+ target = args.object
+ mod_name, has_attrs, attrs = target.partition(":")
+ try:
+ obj = module = importlib.import_module(mod_name)
+ except Exception as exc:
+ msg = "Failed to import {} ({}: {})".format(mod_name,
+ type(exc).__name__,
+ exc)
+ print(msg, file=sys.stderr)
+ sys.exit(2)
+
+ if has_attrs:
+ parts = attrs.split(".")
+ obj = module
+ for part in parts:
+ obj = getattr(obj, part)
+
+ if module.__name__ in sys.builtin_module_names:
+ print("Can't get info for builtin modules.", file=sys.stderr)
+ sys.exit(1)
+
+ if args.details:
+ print('Target: {}'.format(target))
+ print('Origin: {}'.format(getsourcefile(module)))
+ print('Cached: {}'.format(module.__cached__))
+ if obj is module:
+ print('Loader: {}'.format(repr(module.__loader__)))
+ if hasattr(module, '__path__'):
+ print('Submodule search path: {}'.format(module.__path__))
+ else:
+ try:
+ __, lineno = findsource(obj)
+ except Exception:
+ pass
+ else:
+ print('Line: {}'.format(lineno))
+
+ print('\n')
+ else:
+ print(getsource(obj))
+
+
+if __name__ == "__main__":
+ _main()
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/io.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/io.py
new file mode 100644
index 0000000000000000000000000000000000000000..fbce6efc010c07c78bcf7b4458d5f7f22cd6f0ba
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/io.py
@@ -0,0 +1,99 @@
+"""The io module provides the Python interfaces to stream handling. The
+builtin open function is defined in this module.
+
+At the top of the I/O hierarchy is the abstract base class IOBase. It
+defines the basic interface to a stream. Note, however, that there is no
+separation between reading and writing to streams; implementations are
+allowed to raise an OSError if they do not support a given operation.
+
+Extending IOBase is RawIOBase which deals simply with the reading and
+writing of raw bytes to a stream. FileIO subclasses RawIOBase to provide
+an interface to OS files.
+
+BufferedIOBase deals with buffering on a raw byte stream (RawIOBase). Its
+subclasses, BufferedWriter, BufferedReader, and BufferedRWPair buffer
+streams that are readable, writable, and both respectively.
+BufferedRandom provides a buffered interface to random access
+streams. BytesIO is a simple stream of in-memory bytes.
+
+Another IOBase subclass, TextIOBase, deals with the encoding and decoding
+of streams into text. TextIOWrapper, which extends it, is a buffered text
+interface to a buffered raw stream (`BufferedIOBase`). Finally, StringIO
+is an in-memory stream for text.
+
+Argument names are not part of the specification, and only the arguments
+of open() are intended to be used as keyword arguments.
+
+data:
+
+DEFAULT_BUFFER_SIZE
+
+ An int containing the default buffer size used by the module's buffered
+ I/O classes. open() uses the file's blksize (as obtained by os.stat) if
+ possible.
+"""
+# New I/O library conforming to PEP 3116.
+
+__author__ = ("Guido van Rossum , "
+ "Mike Verdone , "
+ "Mark Russell , "
+ "Antoine Pitrou , "
+ "Amaury Forgeot d'Arc , "
+ "Benjamin Peterson ")
+
+__all__ = ["BlockingIOError", "open", "open_code", "IOBase", "RawIOBase",
+ "FileIO", "BytesIO", "StringIO", "BufferedIOBase",
+ "BufferedReader", "BufferedWriter", "BufferedRWPair",
+ "BufferedRandom", "TextIOBase", "TextIOWrapper",
+ "UnsupportedOperation", "SEEK_SET", "SEEK_CUR", "SEEK_END"]
+
+
+import _io
+import abc
+
+from _io import (DEFAULT_BUFFER_SIZE, BlockingIOError, UnsupportedOperation,
+ open, open_code, FileIO, BytesIO, StringIO, BufferedReader,
+ BufferedWriter, BufferedRWPair, BufferedRandom,
+ IncrementalNewlineDecoder, TextIOWrapper)
+
+OpenWrapper = _io.open # for compatibility with _pyio
+
+# Pretend this exception was created here.
+UnsupportedOperation.__module__ = "io"
+
+# for seek()
+SEEK_SET = 0
+SEEK_CUR = 1
+SEEK_END = 2
+
+# Declaring ABCs in C is tricky so we do it here.
+# Method descriptions and default implementations are inherited from the C
+# version however.
+class IOBase(_io._IOBase, metaclass=abc.ABCMeta):
+ __doc__ = _io._IOBase.__doc__
+
+class RawIOBase(_io._RawIOBase, IOBase):
+ __doc__ = _io._RawIOBase.__doc__
+
+class BufferedIOBase(_io._BufferedIOBase, IOBase):
+ __doc__ = _io._BufferedIOBase.__doc__
+
+class TextIOBase(_io._TextIOBase, IOBase):
+ __doc__ = _io._TextIOBase.__doc__
+
+RawIOBase.register(FileIO)
+
+for klass in (BytesIO, BufferedReader, BufferedWriter, BufferedRandom,
+ BufferedRWPair):
+ BufferedIOBase.register(klass)
+
+for klass in (StringIO, TextIOWrapper):
+ TextIOBase.register(klass)
+del klass
+
+try:
+ from _io import _WindowsConsoleIO
+except ImportError:
+ pass
+else:
+ RawIOBase.register(_WindowsConsoleIO)
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/lzma.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/lzma.py
new file mode 100644
index 0000000000000000000000000000000000000000..0817b872d2019f2198b17e382cdc9beb3899ac80
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/lzma.py
@@ -0,0 +1,347 @@
+"""Interface to the liblzma compression library.
+
+This module provides a class for reading and writing compressed files,
+classes for incremental (de)compression, and convenience functions for
+one-shot (de)compression.
+
+These classes and functions support both the XZ and legacy LZMA
+container formats, as well as raw compressed data streams.
+"""
+
+__all__ = [
+ "CHECK_NONE", "CHECK_CRC32", "CHECK_CRC64", "CHECK_SHA256",
+ "CHECK_ID_MAX", "CHECK_UNKNOWN",
+ "FILTER_LZMA1", "FILTER_LZMA2", "FILTER_DELTA", "FILTER_X86", "FILTER_IA64",
+ "FILTER_ARM", "FILTER_ARMTHUMB", "FILTER_POWERPC", "FILTER_SPARC",
+ "FORMAT_AUTO", "FORMAT_XZ", "FORMAT_ALONE", "FORMAT_RAW",
+ "MF_HC3", "MF_HC4", "MF_BT2", "MF_BT3", "MF_BT4",
+ "MODE_FAST", "MODE_NORMAL", "PRESET_DEFAULT", "PRESET_EXTREME",
+
+ "LZMACompressor", "LZMADecompressor", "LZMAFile", "LZMAError",
+ "open", "compress", "decompress", "is_check_supported",
+]
+
+import builtins
+import io
+import os
+from _lzma import *
+from _lzma import _encode_filter_properties, _decode_filter_properties
+import _compression
+
+
+_MODE_CLOSED = 0
+_MODE_READ = 1
+# Value 2 no longer used
+_MODE_WRITE = 3
+
+
+class LZMAFile(_compression.BaseStream):
+
+ """A file object providing transparent LZMA (de)compression.
+
+ An LZMAFile can act as a wrapper for an existing file object, or
+ refer directly to a named file on disk.
+
+ Note that LZMAFile provides a *binary* file interface - data read
+ is returned as bytes, and data to be written must be given as bytes.
+ """
+
+ def __init__(self, filename=None, mode="r", *,
+ format=None, check=-1, preset=None, filters=None):
+ """Open an LZMA-compressed file in binary mode.
+
+ filename can be either an actual file name (given as a str,
+ bytes, or PathLike object), in which case the named file is
+ opened, or it can be an existing file object to read from or
+ write to.
+
+ mode can be "r" for reading (default), "w" for (over)writing,
+ "x" for creating exclusively, or "a" for appending. These can
+ equivalently be given as "rb", "wb", "xb" and "ab" respectively.
+
+ format specifies the container format to use for the file.
+ If mode is "r", this defaults to FORMAT_AUTO. Otherwise, the
+ default is FORMAT_XZ.
+
+ check specifies the integrity check to use. This argument can
+ only be used when opening a file for writing. For FORMAT_XZ,
+ the default is CHECK_CRC64. FORMAT_ALONE and FORMAT_RAW do not
+ support integrity checks - for these formats, check must be
+ omitted, or be CHECK_NONE.
+
+ When opening a file for reading, the *preset* argument is not
+ meaningful, and should be omitted. The *filters* argument should
+ also be omitted, except when format is FORMAT_RAW (in which case
+ it is required).
+
+ When opening a file for writing, the settings used by the
+ compressor can be specified either as a preset compression
+ level (with the *preset* argument), or in detail as a custom
+ filter chain (with the *filters* argument). For FORMAT_XZ and
+ FORMAT_ALONE, the default is to use the PRESET_DEFAULT preset
+ level. For FORMAT_RAW, the caller must always specify a filter
+ chain; the raw compressor does not support preset compression
+ levels.
+
+ preset (if provided) should be an integer in the range 0-9,
+ optionally OR-ed with the constant PRESET_EXTREME.
+
+ filters (if provided) should be a sequence of dicts. Each dict
+ should have an entry for "id" indicating ID of the filter, plus
+ additional entries for options to the filter.
+ """
+ self._fp = None
+ self._closefp = False
+ self._mode = _MODE_CLOSED
+
+ if mode in ("r", "rb"):
+ if check != -1:
+ raise ValueError("Cannot specify an integrity check "
+ "when opening a file for reading")
+ if preset is not None:
+ raise ValueError("Cannot specify a preset compression "
+ "level when opening a file for reading")
+ if format is None:
+ format = FORMAT_AUTO
+ mode_code = _MODE_READ
+ elif mode in ("w", "wb", "a", "ab", "x", "xb"):
+ if format is None:
+ format = FORMAT_XZ
+ mode_code = _MODE_WRITE
+ self._compressor = LZMACompressor(format=format, check=check,
+ preset=preset, filters=filters)
+ self._pos = 0
+ else:
+ raise ValueError("Invalid mode: {!r}".format(mode))
+
+ if isinstance(filename, (str, bytes, os.PathLike)):
+ if "b" not in mode:
+ mode += "b"
+ self._fp = builtins.open(filename, mode)
+ self._closefp = True
+ self._mode = mode_code
+ elif hasattr(filename, "read") or hasattr(filename, "write"):
+ self._fp = filename
+ self._mode = mode_code
+ else:
+ raise TypeError("filename must be a str, bytes, file or PathLike object")
+
+ if self._mode == _MODE_READ:
+ raw = _compression.DecompressReader(self._fp, LZMADecompressor,
+ trailing_error=LZMAError, format=format, filters=filters)
+ self._buffer = io.BufferedReader(raw)
+
+ def close(self):
+ """Flush and close the file.
+
+ May be called more than once without error. Once the file is
+ closed, any other operation on it will raise a ValueError.
+ """
+ if self._mode == _MODE_CLOSED:
+ return
+ try:
+ if self._mode == _MODE_READ:
+ self._buffer.close()
+ self._buffer = None
+ elif self._mode == _MODE_WRITE:
+ self._fp.write(self._compressor.flush())
+ self._compressor = None
+ finally:
+ try:
+ if self._closefp:
+ self._fp.close()
+ finally:
+ self._fp = None
+ self._closefp = False
+ self._mode = _MODE_CLOSED
+
+ @property
+ def closed(self):
+ """True if this file is closed."""
+ return self._mode == _MODE_CLOSED
+
+ def fileno(self):
+ """Return the file descriptor for the underlying file."""
+ self._check_not_closed()
+ return self._fp.fileno()
+
+ def seekable(self):
+ """Return whether the file supports seeking."""
+ return self.readable() and self._buffer.seekable()
+
+ def readable(self):
+ """Return whether the file was opened for reading."""
+ self._check_not_closed()
+ return self._mode == _MODE_READ
+
+ def writable(self):
+ """Return whether the file was opened for writing."""
+ self._check_not_closed()
+ return self._mode == _MODE_WRITE
+
+ def peek(self, size=-1):
+ """Return buffered data without advancing the file position.
+
+ Always returns at least one byte of data, unless at EOF.
+ The exact number of bytes returned is unspecified.
+ """
+ self._check_can_read()
+ # Relies on the undocumented fact that BufferedReader.peek() always
+ # returns at least one byte (except at EOF)
+ return self._buffer.peek(size)
+
+ def read(self, size=-1):
+ """Read up to size uncompressed bytes from the file.
+
+ If size is negative or omitted, read until EOF is reached.
+ Returns b"" if the file is already at EOF.
+ """
+ self._check_can_read()
+ return self._buffer.read(size)
+
+ def read1(self, size=-1):
+ """Read up to size uncompressed bytes, while trying to avoid
+ making multiple reads from the underlying stream. Reads up to a
+ buffer's worth of data if size is negative.
+
+ Returns b"" if the file is at EOF.
+ """
+ self._check_can_read()
+ if size < 0:
+ size = io.DEFAULT_BUFFER_SIZE
+ return self._buffer.read1(size)
+
+ def readline(self, size=-1):
+ """Read a line of uncompressed bytes from the file.
+
+ The terminating newline (if present) is retained. If size is
+ non-negative, no more than size bytes will be read (in which
+ case the line may be incomplete). Returns b'' if already at EOF.
+ """
+ self._check_can_read()
+ return self._buffer.readline(size)
+
+ def write(self, data):
+ """Write a bytes object to the file.
+
+ Returns the number of uncompressed bytes written, which is
+ always len(data). Note that due to buffering, the file on disk
+ may not reflect the data written until close() is called.
+ """
+ self._check_can_write()
+ compressed = self._compressor.compress(data)
+ self._fp.write(compressed)
+ self._pos += len(data)
+ return len(data)
+
+ def seek(self, offset, whence=io.SEEK_SET):
+ """Change the file position.
+
+ The new position is specified by offset, relative to the
+ position indicated by whence. Possible values for whence are:
+
+ 0: start of stream (default): offset must not be negative
+ 1: current stream position
+ 2: end of stream; offset must not be positive
+
+ Returns the new file position.
+
+ Note that seeking is emulated, so depending on the parameters,
+ this operation may be extremely slow.
+ """
+ self._check_can_seek()
+ return self._buffer.seek(offset, whence)
+
+ def tell(self):
+ """Return the current file position."""
+ self._check_not_closed()
+ if self._mode == _MODE_READ:
+ return self._buffer.tell()
+ return self._pos
+
+
+def open(filename, mode="rb", *,
+ format=None, check=-1, preset=None, filters=None,
+ encoding=None, errors=None, newline=None):
+ """Open an LZMA-compressed file in binary or text mode.
+
+ filename can be either an actual file name (given as a str, bytes,
+ or PathLike object), in which case the named file is opened, or it
+ can be an existing file object to read from or write to.
+
+ The mode argument can be "r", "rb" (default), "w", "wb", "x", "xb",
+ "a", or "ab" for binary mode, or "rt", "wt", "xt", or "at" for text
+ mode.
+
+ The format, check, preset and filters arguments specify the
+ compression settings, as for LZMACompressor, LZMADecompressor and
+ LZMAFile.
+
+ For binary mode, this function is equivalent to the LZMAFile
+ constructor: LZMAFile(filename, mode, ...). In this case, the
+ encoding, errors and newline arguments must not be provided.
+
+ For text mode, an LZMAFile object is created, and wrapped in an
+ io.TextIOWrapper instance with the specified encoding, error
+ handling behavior, and line ending(s).
+
+ """
+ if "t" in mode:
+ if "b" in mode:
+ raise ValueError("Invalid mode: %r" % (mode,))
+ else:
+ if encoding is not None:
+ raise ValueError("Argument 'encoding' not supported in binary mode")
+ if errors is not None:
+ raise ValueError("Argument 'errors' not supported in binary mode")
+ if newline is not None:
+ raise ValueError("Argument 'newline' not supported in binary mode")
+
+ lz_mode = mode.replace("t", "")
+ binary_file = LZMAFile(filename, lz_mode, format=format, check=check,
+ preset=preset, filters=filters)
+
+ if "t" in mode:
+ return io.TextIOWrapper(binary_file, encoding, errors, newline)
+ else:
+ return binary_file
+
+
+def compress(data, format=FORMAT_XZ, check=-1, preset=None, filters=None):
+ """Compress a block of data.
+
+ Refer to LZMACompressor's docstring for a description of the
+ optional arguments *format*, *check*, *preset* and *filters*.
+
+ For incremental compression, use an LZMACompressor instead.
+ """
+ comp = LZMACompressor(format, check, preset, filters)
+ return comp.compress(data) + comp.flush()
+
+
+def decompress(data, format=FORMAT_AUTO, memlimit=None, filters=None):
+ """Decompress a block of data.
+
+ Refer to LZMADecompressor's docstring for a description of the
+ optional arguments *format*, *check* and *filters*.
+
+ For incremental decompression, use an LZMADecompressor instead.
+ """
+ results = []
+ while True:
+ decomp = LZMADecompressor(format, memlimit, filters)
+ try:
+ res = decomp.decompress(data)
+ except LZMAError:
+ if results:
+ break # Leftover data is not a valid LZMA/XZ stream; ignore it.
+ else:
+ raise # Error on the first iteration; bail out.
+ results.append(res)
+ if not decomp.eof:
+ raise LZMAError("Compressed data ended before the "
+ "end-of-stream marker was reached")
+ data = decomp.unused_data
+ if not data:
+ break
+ return b"".join(results)
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/mailbox.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/mailbox.py
new file mode 100644
index 0000000000000000000000000000000000000000..5b4e86419f1173147ab4957af415ebcaef655b20
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/mailbox.py
@@ -0,0 +1,2146 @@
+"""Read/write support for Maildir, mbox, MH, Babyl, and MMDF mailboxes."""
+
+# Notes for authors of new mailbox subclasses:
+#
+# Remember to fsync() changes to disk before closing a modified file
+# or returning from a flush() method. See functions _sync_flush() and
+# _sync_close().
+
+import os
+import time
+import calendar
+import socket
+import errno
+import copy
+import warnings
+import email
+import email.message
+import email.generator
+import io
+import contextlib
+try:
+ import fcntl
+except ImportError:
+ fcntl = None
+
+__all__ = ['Mailbox', 'Maildir', 'mbox', 'MH', 'Babyl', 'MMDF',
+ 'Message', 'MaildirMessage', 'mboxMessage', 'MHMessage',
+ 'BabylMessage', 'MMDFMessage', 'Error', 'NoSuchMailboxError',
+ 'NotEmptyError', 'ExternalClashError', 'FormatError']
+
+linesep = os.linesep.encode('ascii')
+
+class Mailbox:
+ """A group of messages in a particular place."""
+
+ def __init__(self, path, factory=None, create=True):
+ """Initialize a Mailbox instance."""
+ self._path = os.path.abspath(os.path.expanduser(path))
+ self._factory = factory
+
+ def add(self, message):
+ """Add message and return assigned key."""
+ raise NotImplementedError('Method must be implemented by subclass')
+
+ def remove(self, key):
+ """Remove the keyed message; raise KeyError if it doesn't exist."""
+ raise NotImplementedError('Method must be implemented by subclass')
+
+ def __delitem__(self, key):
+ self.remove(key)
+
+ def discard(self, key):
+ """If the keyed message exists, remove it."""
+ try:
+ self.remove(key)
+ except KeyError:
+ pass
+
+ def __setitem__(self, key, message):
+ """Replace the keyed message; raise KeyError if it doesn't exist."""
+ raise NotImplementedError('Method must be implemented by subclass')
+
+ def get(self, key, default=None):
+ """Return the keyed message, or default if it doesn't exist."""
+ try:
+ return self.__getitem__(key)
+ except KeyError:
+ return default
+
+ def __getitem__(self, key):
+ """Return the keyed message; raise KeyError if it doesn't exist."""
+ if not self._factory:
+ return self.get_message(key)
+ else:
+ with contextlib.closing(self.get_file(key)) as file:
+ return self._factory(file)
+
+ def get_message(self, key):
+ """Return a Message representation or raise a KeyError."""
+ raise NotImplementedError('Method must be implemented by subclass')
+
+ def get_string(self, key):
+ """Return a string representation or raise a KeyError.
+
+ Uses email.message.Message to create a 7bit clean string
+ representation of the message."""
+ return email.message_from_bytes(self.get_bytes(key)).as_string()
+
+ def get_bytes(self, key):
+ """Return a byte string representation or raise a KeyError."""
+ raise NotImplementedError('Method must be implemented by subclass')
+
+ def get_file(self, key):
+ """Return a file-like representation or raise a KeyError."""
+ raise NotImplementedError('Method must be implemented by subclass')
+
+ def iterkeys(self):
+ """Return an iterator over keys."""
+ raise NotImplementedError('Method must be implemented by subclass')
+
+ def keys(self):
+ """Return a list of keys."""
+ return list(self.iterkeys())
+
+ def itervalues(self):
+ """Return an iterator over all messages."""
+ for key in self.iterkeys():
+ try:
+ value = self[key]
+ except KeyError:
+ continue
+ yield value
+
+ def __iter__(self):
+ return self.itervalues()
+
+ def values(self):
+ """Return a list of messages. Memory intensive."""
+ return list(self.itervalues())
+
+ def iteritems(self):
+ """Return an iterator over (key, message) tuples."""
+ for key in self.iterkeys():
+ try:
+ value = self[key]
+ except KeyError:
+ continue
+ yield (key, value)
+
+ def items(self):
+ """Return a list of (key, message) tuples. Memory intensive."""
+ return list(self.iteritems())
+
+ def __contains__(self, key):
+ """Return True if the keyed message exists, False otherwise."""
+ raise NotImplementedError('Method must be implemented by subclass')
+
+ def __len__(self):
+ """Return a count of messages in the mailbox."""
+ raise NotImplementedError('Method must be implemented by subclass')
+
+ def clear(self):
+ """Delete all messages."""
+ for key in self.keys():
+ self.discard(key)
+
+ def pop(self, key, default=None):
+ """Delete the keyed message and return it, or default."""
+ try:
+ result = self[key]
+ except KeyError:
+ return default
+ self.discard(key)
+ return result
+
+ def popitem(self):
+ """Delete an arbitrary (key, message) pair and return it."""
+ for key in self.iterkeys():
+ return (key, self.pop(key)) # This is only run once.
+ else:
+ raise KeyError('No messages in mailbox')
+
+ def update(self, arg=None):
+ """Change the messages that correspond to certain keys."""
+ if hasattr(arg, 'iteritems'):
+ source = arg.iteritems()
+ elif hasattr(arg, 'items'):
+ source = arg.items()
+ else:
+ source = arg
+ bad_key = False
+ for key, message in source:
+ try:
+ self[key] = message
+ except KeyError:
+ bad_key = True
+ if bad_key:
+ raise KeyError('No message with key(s)')
+
+ def flush(self):
+ """Write any pending changes to the disk."""
+ raise NotImplementedError('Method must be implemented by subclass')
+
+ def lock(self):
+ """Lock the mailbox."""
+ raise NotImplementedError('Method must be implemented by subclass')
+
+ def unlock(self):
+ """Unlock the mailbox if it is locked."""
+ raise NotImplementedError('Method must be implemented by subclass')
+
+ def close(self):
+ """Flush and close the mailbox."""
+ raise NotImplementedError('Method must be implemented by subclass')
+
+ def _string_to_bytes(self, message):
+ # If a message is not 7bit clean, we refuse to handle it since it
+ # likely came from reading invalid messages in text mode, and that way
+ # lies mojibake.
+ try:
+ return message.encode('ascii')
+ except UnicodeError:
+ raise ValueError("String input must be ASCII-only; "
+ "use bytes or a Message instead")
+
+ # Whether each message must end in a newline
+ _append_newline = False
+
+ def _dump_message(self, message, target, mangle_from_=False):
+ # This assumes the target file is open in binary mode.
+ """Dump message contents to target file."""
+ if isinstance(message, email.message.Message):
+ buffer = io.BytesIO()
+ gen = email.generator.BytesGenerator(buffer, mangle_from_, 0)
+ gen.flatten(message)
+ buffer.seek(0)
+ data = buffer.read()
+ data = data.replace(b'\n', linesep)
+ target.write(data)
+ if self._append_newline and not data.endswith(linesep):
+ # Make sure the message ends with a newline
+ target.write(linesep)
+ elif isinstance(message, (str, bytes, io.StringIO)):
+ if isinstance(message, io.StringIO):
+ warnings.warn("Use of StringIO input is deprecated, "
+ "use BytesIO instead", DeprecationWarning, 3)
+ message = message.getvalue()
+ if isinstance(message, str):
+ message = self._string_to_bytes(message)
+ if mangle_from_:
+ message = message.replace(b'\nFrom ', b'\n>From ')
+ message = message.replace(b'\n', linesep)
+ target.write(message)
+ if self._append_newline and not message.endswith(linesep):
+ # Make sure the message ends with a newline
+ target.write(linesep)
+ elif hasattr(message, 'read'):
+ if hasattr(message, 'buffer'):
+ warnings.warn("Use of text mode files is deprecated, "
+ "use a binary mode file instead", DeprecationWarning, 3)
+ message = message.buffer
+ lastline = None
+ while True:
+ line = message.readline()
+ # Universal newline support.
+ if line.endswith(b'\r\n'):
+ line = line[:-2] + b'\n'
+ elif line.endswith(b'\r'):
+ line = line[:-1] + b'\n'
+ if not line:
+ break
+ if mangle_from_ and line.startswith(b'From '):
+ line = b'>From ' + line[5:]
+ line = line.replace(b'\n', linesep)
+ target.write(line)
+ lastline = line
+ if self._append_newline and lastline and not lastline.endswith(linesep):
+ # Make sure the message ends with a newline
+ target.write(linesep)
+ else:
+ raise TypeError('Invalid message type: %s' % type(message))
+
+
+class Maildir(Mailbox):
+ """A qmail-style Maildir mailbox."""
+
+ colon = ':'
+
+ def __init__(self, dirname, factory=None, create=True):
+ """Initialize a Maildir instance."""
+ Mailbox.__init__(self, dirname, factory, create)
+ self._paths = {
+ 'tmp': os.path.join(self._path, 'tmp'),
+ 'new': os.path.join(self._path, 'new'),
+ 'cur': os.path.join(self._path, 'cur'),
+ }
+ if not os.path.exists(self._path):
+ if create:
+ os.mkdir(self._path, 0o700)
+ for path in self._paths.values():
+ os.mkdir(path, 0o700)
+ else:
+ raise NoSuchMailboxError(self._path)
+ self._toc = {}
+ self._toc_mtimes = {'cur': 0, 'new': 0}
+ self._last_read = 0 # Records last time we read cur/new
+ self._skewfactor = 0.1 # Adjust if os/fs clocks are skewing
+
+ def add(self, message):
+ """Add message and return assigned key."""
+ tmp_file = self._create_tmp()
+ try:
+ self._dump_message(message, tmp_file)
+ except BaseException:
+ tmp_file.close()
+ os.remove(tmp_file.name)
+ raise
+ _sync_close(tmp_file)
+ if isinstance(message, MaildirMessage):
+ subdir = message.get_subdir()
+ suffix = self.colon + message.get_info()
+ if suffix == self.colon:
+ suffix = ''
+ else:
+ subdir = 'new'
+ suffix = ''
+ uniq = os.path.basename(tmp_file.name).split(self.colon)[0]
+ dest = os.path.join(self._path, subdir, uniq + suffix)
+ if isinstance(message, MaildirMessage):
+ os.utime(tmp_file.name,
+ (os.path.getatime(tmp_file.name), message.get_date()))
+ # No file modification should be done after the file is moved to its
+ # final position in order to prevent race conditions with changes
+ # from other programs
+ try:
+ try:
+ os.link(tmp_file.name, dest)
+ except (AttributeError, PermissionError):
+ os.rename(tmp_file.name, dest)
+ else:
+ os.remove(tmp_file.name)
+ except OSError as e:
+ os.remove(tmp_file.name)
+ if e.errno == errno.EEXIST:
+ raise ExternalClashError('Name clash with existing message: %s'
+ % dest)
+ else:
+ raise
+ return uniq
+
+ def remove(self, key):
+ """Remove the keyed message; raise KeyError if it doesn't exist."""
+ os.remove(os.path.join(self._path, self._lookup(key)))
+
+ def discard(self, key):
+ """If the keyed message exists, remove it."""
+ # This overrides an inapplicable implementation in the superclass.
+ try:
+ self.remove(key)
+ except (KeyError, FileNotFoundError):
+ pass
+
+ def __setitem__(self, key, message):
+ """Replace the keyed message; raise KeyError if it doesn't exist."""
+ old_subpath = self._lookup(key)
+ temp_key = self.add(message)
+ temp_subpath = self._lookup(temp_key)
+ if isinstance(message, MaildirMessage):
+ # temp's subdir and suffix were specified by message.
+ dominant_subpath = temp_subpath
+ else:
+ # temp's subdir and suffix were defaults from add().
+ dominant_subpath = old_subpath
+ subdir = os.path.dirname(dominant_subpath)
+ if self.colon in dominant_subpath:
+ suffix = self.colon + dominant_subpath.split(self.colon)[-1]
+ else:
+ suffix = ''
+ self.discard(key)
+ tmp_path = os.path.join(self._path, temp_subpath)
+ new_path = os.path.join(self._path, subdir, key + suffix)
+ if isinstance(message, MaildirMessage):
+ os.utime(tmp_path,
+ (os.path.getatime(tmp_path), message.get_date()))
+ # No file modification should be done after the file is moved to its
+ # final position in order to prevent race conditions with changes
+ # from other programs
+ os.rename(tmp_path, new_path)
+
+ def get_message(self, key):
+ """Return a Message representation or raise a KeyError."""
+ subpath = self._lookup(key)
+ with open(os.path.join(self._path, subpath), 'rb') as f:
+ if self._factory:
+ msg = self._factory(f)
+ else:
+ msg = MaildirMessage(f)
+ subdir, name = os.path.split(subpath)
+ msg.set_subdir(subdir)
+ if self.colon in name:
+ msg.set_info(name.split(self.colon)[-1])
+ msg.set_date(os.path.getmtime(os.path.join(self._path, subpath)))
+ return msg
+
+ def get_bytes(self, key):
+ """Return a bytes representation or raise a KeyError."""
+ with open(os.path.join(self._path, self._lookup(key)), 'rb') as f:
+ return f.read().replace(linesep, b'\n')
+
+ def get_file(self, key):
+ """Return a file-like representation or raise a KeyError."""
+ f = open(os.path.join(self._path, self._lookup(key)), 'rb')
+ return _ProxyFile(f)
+
+ def iterkeys(self):
+ """Return an iterator over keys."""
+ self._refresh()
+ for key in self._toc:
+ try:
+ self._lookup(key)
+ except KeyError:
+ continue
+ yield key
+
+ def __contains__(self, key):
+ """Return True if the keyed message exists, False otherwise."""
+ self._refresh()
+ return key in self._toc
+
+ def __len__(self):
+ """Return a count of messages in the mailbox."""
+ self._refresh()
+ return len(self._toc)
+
+ def flush(self):
+ """Write any pending changes to disk."""
+ # Maildir changes are always written immediately, so there's nothing
+ # to do.
+ pass
+
+ def lock(self):
+ """Lock the mailbox."""
+ return
+
+ def unlock(self):
+ """Unlock the mailbox if it is locked."""
+ return
+
+ def close(self):
+ """Flush and close the mailbox."""
+ return
+
+ def list_folders(self):
+ """Return a list of folder names."""
+ result = []
+ for entry in os.listdir(self._path):
+ if len(entry) > 1 and entry[0] == '.' and \
+ os.path.isdir(os.path.join(self._path, entry)):
+ result.append(entry[1:])
+ return result
+
+ def get_folder(self, folder):
+ """Return a Maildir instance for the named folder."""
+ return Maildir(os.path.join(self._path, '.' + folder),
+ factory=self._factory,
+ create=False)
+
+ def add_folder(self, folder):
+ """Create a folder and return a Maildir instance representing it."""
+ path = os.path.join(self._path, '.' + folder)
+ result = Maildir(path, factory=self._factory)
+ maildirfolder_path = os.path.join(path, 'maildirfolder')
+ if not os.path.exists(maildirfolder_path):
+ os.close(os.open(maildirfolder_path, os.O_CREAT | os.O_WRONLY,
+ 0o666))
+ return result
+
+ def remove_folder(self, folder):
+ """Delete the named folder, which must be empty."""
+ path = os.path.join(self._path, '.' + folder)
+ for entry in os.listdir(os.path.join(path, 'new')) + \
+ os.listdir(os.path.join(path, 'cur')):
+ if len(entry) < 1 or entry[0] != '.':
+ raise NotEmptyError('Folder contains message(s): %s' % folder)
+ for entry in os.listdir(path):
+ if entry != 'new' and entry != 'cur' and entry != 'tmp' and \
+ os.path.isdir(os.path.join(path, entry)):
+ raise NotEmptyError("Folder contains subdirectory '%s': %s" %
+ (folder, entry))
+ for root, dirs, files in os.walk(path, topdown=False):
+ for entry in files:
+ os.remove(os.path.join(root, entry))
+ for entry in dirs:
+ os.rmdir(os.path.join(root, entry))
+ os.rmdir(path)
+
+ def clean(self):
+ """Delete old files in "tmp"."""
+ now = time.time()
+ for entry in os.listdir(os.path.join(self._path, 'tmp')):
+ path = os.path.join(self._path, 'tmp', entry)
+ if now - os.path.getatime(path) > 129600: # 60 * 60 * 36
+ os.remove(path)
+
+ _count = 1 # This is used to generate unique file names.
+
+ def _create_tmp(self):
+ """Create a file in the tmp subdirectory and open and return it."""
+ now = time.time()
+ hostname = socket.gethostname()
+ if '/' in hostname:
+ hostname = hostname.replace('/', r'\057')
+ if ':' in hostname:
+ hostname = hostname.replace(':', r'\072')
+ uniq = "%s.M%sP%sQ%s.%s" % (int(now), int(now % 1 * 1e6), os.getpid(),
+ Maildir._count, hostname)
+ path = os.path.join(self._path, 'tmp', uniq)
+ try:
+ os.stat(path)
+ except FileNotFoundError:
+ Maildir._count += 1
+ try:
+ return _create_carefully(path)
+ except FileExistsError:
+ pass
+
+ # Fall through to here if stat succeeded or open raised EEXIST.
+ raise ExternalClashError('Name clash prevented file creation: %s' %
+ path)
+
+ def _refresh(self):
+ """Update table of contents mapping."""
+ # If it has been less than two seconds since the last _refresh() call,
+ # we have to unconditionally re-read the mailbox just in case it has
+ # been modified, because os.path.mtime() has a 2 sec resolution in the
+ # most common worst case (FAT) and a 1 sec resolution typically. This
+ # results in a few unnecessary re-reads when _refresh() is called
+ # multiple times in that interval, but once the clock ticks over, we
+ # will only re-read as needed. Because the filesystem might be being
+ # served by an independent system with its own clock, we record and
+ # compare with the mtimes from the filesystem. Because the other
+ # system's clock might be skewing relative to our clock, we add an
+ # extra delta to our wait. The default is one tenth second, but is an
+ # instance variable and so can be adjusted if dealing with a
+ # particularly skewed or irregular system.
+ if time.time() - self._last_read > 2 + self._skewfactor:
+ refresh = False
+ for subdir in self._toc_mtimes:
+ mtime = os.path.getmtime(self._paths[subdir])
+ if mtime > self._toc_mtimes[subdir]:
+ refresh = True
+ self._toc_mtimes[subdir] = mtime
+ if not refresh:
+ return
+ # Refresh toc
+ self._toc = {}
+ for subdir in self._toc_mtimes:
+ path = self._paths[subdir]
+ for entry in os.listdir(path):
+ p = os.path.join(path, entry)
+ if os.path.isdir(p):
+ continue
+ uniq = entry.split(self.colon)[0]
+ self._toc[uniq] = os.path.join(subdir, entry)
+ self._last_read = time.time()
+
+ def _lookup(self, key):
+ """Use TOC to return subpath for given key, or raise a KeyError."""
+ try:
+ if os.path.exists(os.path.join(self._path, self._toc[key])):
+ return self._toc[key]
+ except KeyError:
+ pass
+ self._refresh()
+ try:
+ return self._toc[key]
+ except KeyError:
+ raise KeyError('No message with key: %s' % key) from None
+
+ # This method is for backward compatibility only.
+ def next(self):
+ """Return the next message in a one-time iteration."""
+ if not hasattr(self, '_onetime_keys'):
+ self._onetime_keys = self.iterkeys()
+ while True:
+ try:
+ return self[next(self._onetime_keys)]
+ except StopIteration:
+ return None
+ except KeyError:
+ continue
+
+
+class _singlefileMailbox(Mailbox):
+ """A single-file mailbox."""
+
+ def __init__(self, path, factory=None, create=True):
+ """Initialize a single-file mailbox."""
+ Mailbox.__init__(self, path, factory, create)
+ try:
+ f = open(self._path, 'rb+')
+ except OSError as e:
+ if e.errno == errno.ENOENT:
+ if create:
+ f = open(self._path, 'wb+')
+ else:
+ raise NoSuchMailboxError(self._path)
+ elif e.errno in (errno.EACCES, errno.EROFS):
+ f = open(self._path, 'rb')
+ else:
+ raise
+ self._file = f
+ self._toc = None
+ self._next_key = 0
+ self._pending = False # No changes require rewriting the file.
+ self._pending_sync = False # No need to sync the file
+ self._locked = False
+ self._file_length = None # Used to record mailbox size
+
+ def add(self, message):
+ """Add message and return assigned key."""
+ self._lookup()
+ self._toc[self._next_key] = self._append_message(message)
+ self._next_key += 1
+ # _append_message appends the message to the mailbox file. We
+ # don't need a full rewrite + rename, sync is enough.
+ self._pending_sync = True
+ return self._next_key - 1
+
+ def remove(self, key):
+ """Remove the keyed message; raise KeyError if it doesn't exist."""
+ self._lookup(key)
+ del self._toc[key]
+ self._pending = True
+
+ def __setitem__(self, key, message):
+ """Replace the keyed message; raise KeyError if it doesn't exist."""
+ self._lookup(key)
+ self._toc[key] = self._append_message(message)
+ self._pending = True
+
+ def iterkeys(self):
+ """Return an iterator over keys."""
+ self._lookup()
+ yield from self._toc.keys()
+
+ def __contains__(self, key):
+ """Return True if the keyed message exists, False otherwise."""
+ self._lookup()
+ return key in self._toc
+
+ def __len__(self):
+ """Return a count of messages in the mailbox."""
+ self._lookup()
+ return len(self._toc)
+
+ def lock(self):
+ """Lock the mailbox."""
+ if not self._locked:
+ _lock_file(self._file)
+ self._locked = True
+
+ def unlock(self):
+ """Unlock the mailbox if it is locked."""
+ if self._locked:
+ _unlock_file(self._file)
+ self._locked = False
+
+ def flush(self):
+ """Write any pending changes to disk."""
+ if not self._pending:
+ if self._pending_sync:
+ # Messages have only been added, so syncing the file
+ # is enough.
+ _sync_flush(self._file)
+ self._pending_sync = False
+ return
+
+ # In order to be writing anything out at all, self._toc must
+ # already have been generated (and presumably has been modified
+ # by adding or deleting an item).
+ assert self._toc is not None
+
+ # Check length of self._file; if it's changed, some other process
+ # has modified the mailbox since we scanned it.
+ self._file.seek(0, 2)
+ cur_len = self._file.tell()
+ if cur_len != self._file_length:
+ raise ExternalClashError('Size of mailbox file changed '
+ '(expected %i, found %i)' %
+ (self._file_length, cur_len))
+
+ new_file = _create_temporary(self._path)
+ try:
+ new_toc = {}
+ self._pre_mailbox_hook(new_file)
+ for key in sorted(self._toc.keys()):
+ start, stop = self._toc[key]
+ self._file.seek(start)
+ self._pre_message_hook(new_file)
+ new_start = new_file.tell()
+ while True:
+ buffer = self._file.read(min(4096,
+ stop - self._file.tell()))
+ if not buffer:
+ break
+ new_file.write(buffer)
+ new_toc[key] = (new_start, new_file.tell())
+ self._post_message_hook(new_file)
+ self._file_length = new_file.tell()
+ except:
+ new_file.close()
+ os.remove(new_file.name)
+ raise
+ _sync_close(new_file)
+ # self._file is about to get replaced, so no need to sync.
+ self._file.close()
+ # Make sure the new file's mode is the same as the old file's
+ mode = os.stat(self._path).st_mode
+ os.chmod(new_file.name, mode)
+ try:
+ os.rename(new_file.name, self._path)
+ except FileExistsError:
+ os.remove(self._path)
+ os.rename(new_file.name, self._path)
+ self._file = open(self._path, 'rb+')
+ self._toc = new_toc
+ self._pending = False
+ self._pending_sync = False
+ if self._locked:
+ _lock_file(self._file, dotlock=False)
+
+ def _pre_mailbox_hook(self, f):
+ """Called before writing the mailbox to file f."""
+ return
+
+ def _pre_message_hook(self, f):
+ """Called before writing each message to file f."""
+ return
+
+ def _post_message_hook(self, f):
+ """Called after writing each message to file f."""
+ return
+
+ def close(self):
+ """Flush and close the mailbox."""
+ try:
+ self.flush()
+ finally:
+ try:
+ if self._locked:
+ self.unlock()
+ finally:
+ self._file.close() # Sync has been done by self.flush() above.
+
+ def _lookup(self, key=None):
+ """Return (start, stop) or raise KeyError."""
+ if self._toc is None:
+ self._generate_toc()
+ if key is not None:
+ try:
+ return self._toc[key]
+ except KeyError:
+ raise KeyError('No message with key: %s' % key) from None
+
+ def _append_message(self, message):
+ """Append message to mailbox and return (start, stop) offsets."""
+ self._file.seek(0, 2)
+ before = self._file.tell()
+ if len(self._toc) == 0 and not self._pending:
+ # This is the first message, and the _pre_mailbox_hook
+ # hasn't yet been called. If self._pending is True,
+ # messages have been removed, so _pre_mailbox_hook must
+ # have been called already.
+ self._pre_mailbox_hook(self._file)
+ try:
+ self._pre_message_hook(self._file)
+ offsets = self._install_message(message)
+ self._post_message_hook(self._file)
+ except BaseException:
+ self._file.truncate(before)
+ raise
+ self._file.flush()
+ self._file_length = self._file.tell() # Record current length of mailbox
+ return offsets
+
+
+
+class _mboxMMDF(_singlefileMailbox):
+ """An mbox or MMDF mailbox."""
+
+ _mangle_from_ = True
+
+ def get_message(self, key):
+ """Return a Message representation or raise a KeyError."""
+ start, stop = self._lookup(key)
+ self._file.seek(start)
+ from_line = self._file.readline().replace(linesep, b'')
+ string = self._file.read(stop - self._file.tell())
+ msg = self._message_factory(string.replace(linesep, b'\n'))
+ msg.set_from(from_line[5:].decode('ascii'))
+ return msg
+
+ def get_string(self, key, from_=False):
+ """Return a string representation or raise a KeyError."""
+ return email.message_from_bytes(
+ self.get_bytes(key, from_)).as_string(unixfrom=from_)
+
+ def get_bytes(self, key, from_=False):
+ """Return a string representation or raise a KeyError."""
+ start, stop = self._lookup(key)
+ self._file.seek(start)
+ if not from_:
+ self._file.readline()
+ string = self._file.read(stop - self._file.tell())
+ return string.replace(linesep, b'\n')
+
+ def get_file(self, key, from_=False):
+ """Return a file-like representation or raise a KeyError."""
+ start, stop = self._lookup(key)
+ self._file.seek(start)
+ if not from_:
+ self._file.readline()
+ return _PartialFile(self._file, self._file.tell(), stop)
+
+ def _install_message(self, message):
+ """Format a message and blindly write to self._file."""
+ from_line = None
+ if isinstance(message, str):
+ message = self._string_to_bytes(message)
+ if isinstance(message, bytes) and message.startswith(b'From '):
+ newline = message.find(b'\n')
+ if newline != -1:
+ from_line = message[:newline]
+ message = message[newline + 1:]
+ else:
+ from_line = message
+ message = b''
+ elif isinstance(message, _mboxMMDFMessage):
+ author = message.get_from().encode('ascii')
+ from_line = b'From ' + author
+ elif isinstance(message, email.message.Message):
+ from_line = message.get_unixfrom() # May be None.
+ if from_line is not None:
+ from_line = from_line.encode('ascii')
+ if from_line is None:
+ from_line = b'From MAILER-DAEMON ' + time.asctime(time.gmtime()).encode()
+ start = self._file.tell()
+ self._file.write(from_line + linesep)
+ self._dump_message(message, self._file, self._mangle_from_)
+ stop = self._file.tell()
+ return (start, stop)
+
+
+class mbox(_mboxMMDF):
+ """A classic mbox mailbox."""
+
+ _mangle_from_ = True
+
+ # All messages must end in a newline character, and
+ # _post_message_hooks outputs an empty line between messages.
+ _append_newline = True
+
+ def __init__(self, path, factory=None, create=True):
+ """Initialize an mbox mailbox."""
+ self._message_factory = mboxMessage
+ _mboxMMDF.__init__(self, path, factory, create)
+
+ def _post_message_hook(self, f):
+ """Called after writing each message to file f."""
+ f.write(linesep)
+
+ def _generate_toc(self):
+ """Generate key-to-(start, stop) table of contents."""
+ starts, stops = [], []
+ last_was_empty = False
+ self._file.seek(0)
+ while True:
+ line_pos = self._file.tell()
+ line = self._file.readline()
+ if line.startswith(b'From '):
+ if len(stops) < len(starts):
+ if last_was_empty:
+ stops.append(line_pos - len(linesep))
+ else:
+ # The last line before the "From " line wasn't
+ # blank, but we consider it a start of a
+ # message anyway.
+ stops.append(line_pos)
+ starts.append(line_pos)
+ last_was_empty = False
+ elif not line:
+ if last_was_empty:
+ stops.append(line_pos - len(linesep))
+ else:
+ stops.append(line_pos)
+ break
+ elif line == linesep:
+ last_was_empty = True
+ else:
+ last_was_empty = False
+ self._toc = dict(enumerate(zip(starts, stops)))
+ self._next_key = len(self._toc)
+ self._file_length = self._file.tell()
+
+
+class MMDF(_mboxMMDF):
+ """An MMDF mailbox."""
+
+ def __init__(self, path, factory=None, create=True):
+ """Initialize an MMDF mailbox."""
+ self._message_factory = MMDFMessage
+ _mboxMMDF.__init__(self, path, factory, create)
+
+ def _pre_message_hook(self, f):
+ """Called before writing each message to file f."""
+ f.write(b'\001\001\001\001' + linesep)
+
+ def _post_message_hook(self, f):
+ """Called after writing each message to file f."""
+ f.write(linesep + b'\001\001\001\001' + linesep)
+
+ def _generate_toc(self):
+ """Generate key-to-(start, stop) table of contents."""
+ starts, stops = [], []
+ self._file.seek(0)
+ next_pos = 0
+ while True:
+ line_pos = next_pos
+ line = self._file.readline()
+ next_pos = self._file.tell()
+ if line.startswith(b'\001\001\001\001' + linesep):
+ starts.append(next_pos)
+ while True:
+ line_pos = next_pos
+ line = self._file.readline()
+ next_pos = self._file.tell()
+ if line == b'\001\001\001\001' + linesep:
+ stops.append(line_pos - len(linesep))
+ break
+ elif not line:
+ stops.append(line_pos)
+ break
+ elif not line:
+ break
+ self._toc = dict(enumerate(zip(starts, stops)))
+ self._next_key = len(self._toc)
+ self._file.seek(0, 2)
+ self._file_length = self._file.tell()
+
+
+class MH(Mailbox):
+ """An MH mailbox."""
+
+ def __init__(self, path, factory=None, create=True):
+ """Initialize an MH instance."""
+ Mailbox.__init__(self, path, factory, create)
+ if not os.path.exists(self._path):
+ if create:
+ os.mkdir(self._path, 0o700)
+ os.close(os.open(os.path.join(self._path, '.mh_sequences'),
+ os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0o600))
+ else:
+ raise NoSuchMailboxError(self._path)
+ self._locked = False
+
+ def add(self, message):
+ """Add message and return assigned key."""
+ keys = self.keys()
+ if len(keys) == 0:
+ new_key = 1
+ else:
+ new_key = max(keys) + 1
+ new_path = os.path.join(self._path, str(new_key))
+ f = _create_carefully(new_path)
+ closed = False
+ try:
+ if self._locked:
+ _lock_file(f)
+ try:
+ try:
+ self._dump_message(message, f)
+ except BaseException:
+ # Unlock and close so it can be deleted on Windows
+ if self._locked:
+ _unlock_file(f)
+ _sync_close(f)
+ closed = True
+ os.remove(new_path)
+ raise
+ if isinstance(message, MHMessage):
+ self._dump_sequences(message, new_key)
+ finally:
+ if self._locked:
+ _unlock_file(f)
+ finally:
+ if not closed:
+ _sync_close(f)
+ return new_key
+
+ def remove(self, key):
+ """Remove the keyed message; raise KeyError if it doesn't exist."""
+ path = os.path.join(self._path, str(key))
+ try:
+ f = open(path, 'rb+')
+ except OSError as e:
+ if e.errno == errno.ENOENT:
+ raise KeyError('No message with key: %s' % key)
+ else:
+ raise
+ else:
+ f.close()
+ os.remove(path)
+
+ def __setitem__(self, key, message):
+ """Replace the keyed message; raise KeyError if it doesn't exist."""
+ path = os.path.join(self._path, str(key))
+ try:
+ f = open(path, 'rb+')
+ except OSError as e:
+ if e.errno == errno.ENOENT:
+ raise KeyError('No message with key: %s' % key)
+ else:
+ raise
+ try:
+ if self._locked:
+ _lock_file(f)
+ try:
+ os.close(os.open(path, os.O_WRONLY | os.O_TRUNC))
+ self._dump_message(message, f)
+ if isinstance(message, MHMessage):
+ self._dump_sequences(message, key)
+ finally:
+ if self._locked:
+ _unlock_file(f)
+ finally:
+ _sync_close(f)
+
+ def get_message(self, key):
+ """Return a Message representation or raise a KeyError."""
+ try:
+ if self._locked:
+ f = open(os.path.join(self._path, str(key)), 'rb+')
+ else:
+ f = open(os.path.join(self._path, str(key)), 'rb')
+ except OSError as e:
+ if e.errno == errno.ENOENT:
+ raise KeyError('No message with key: %s' % key)
+ else:
+ raise
+ with f:
+ if self._locked:
+ _lock_file(f)
+ try:
+ msg = MHMessage(f)
+ finally:
+ if self._locked:
+ _unlock_file(f)
+ for name, key_list in self.get_sequences().items():
+ if key in key_list:
+ msg.add_sequence(name)
+ return msg
+
+ def get_bytes(self, key):
+ """Return a bytes representation or raise a KeyError."""
+ try:
+ if self._locked:
+ f = open(os.path.join(self._path, str(key)), 'rb+')
+ else:
+ f = open(os.path.join(self._path, str(key)), 'rb')
+ except OSError as e:
+ if e.errno == errno.ENOENT:
+ raise KeyError('No message with key: %s' % key)
+ else:
+ raise
+ with f:
+ if self._locked:
+ _lock_file(f)
+ try:
+ return f.read().replace(linesep, b'\n')
+ finally:
+ if self._locked:
+ _unlock_file(f)
+
+ def get_file(self, key):
+ """Return a file-like representation or raise a KeyError."""
+ try:
+ f = open(os.path.join(self._path, str(key)), 'rb')
+ except OSError as e:
+ if e.errno == errno.ENOENT:
+ raise KeyError('No message with key: %s' % key)
+ else:
+ raise
+ return _ProxyFile(f)
+
+ def iterkeys(self):
+ """Return an iterator over keys."""
+ return iter(sorted(int(entry) for entry in os.listdir(self._path)
+ if entry.isdigit()))
+
+ def __contains__(self, key):
+ """Return True if the keyed message exists, False otherwise."""
+ return os.path.exists(os.path.join(self._path, str(key)))
+
+ def __len__(self):
+ """Return a count of messages in the mailbox."""
+ return len(list(self.iterkeys()))
+
+ def lock(self):
+ """Lock the mailbox."""
+ if not self._locked:
+ self._file = open(os.path.join(self._path, '.mh_sequences'), 'rb+')
+ _lock_file(self._file)
+ self._locked = True
+
+ def unlock(self):
+ """Unlock the mailbox if it is locked."""
+ if self._locked:
+ _unlock_file(self._file)
+ _sync_close(self._file)
+ del self._file
+ self._locked = False
+
+ def flush(self):
+ """Write any pending changes to the disk."""
+ return
+
+ def close(self):
+ """Flush and close the mailbox."""
+ if self._locked:
+ self.unlock()
+
+ def list_folders(self):
+ """Return a list of folder names."""
+ result = []
+ for entry in os.listdir(self._path):
+ if os.path.isdir(os.path.join(self._path, entry)):
+ result.append(entry)
+ return result
+
+ def get_folder(self, folder):
+ """Return an MH instance for the named folder."""
+ return MH(os.path.join(self._path, folder),
+ factory=self._factory, create=False)
+
+ def add_folder(self, folder):
+ """Create a folder and return an MH instance representing it."""
+ return MH(os.path.join(self._path, folder),
+ factory=self._factory)
+
+ def remove_folder(self, folder):
+ """Delete the named folder, which must be empty."""
+ path = os.path.join(self._path, folder)
+ entries = os.listdir(path)
+ if entries == ['.mh_sequences']:
+ os.remove(os.path.join(path, '.mh_sequences'))
+ elif entries == []:
+ pass
+ else:
+ raise NotEmptyError('Folder not empty: %s' % self._path)
+ os.rmdir(path)
+
+ def get_sequences(self):
+ """Return a name-to-key-list dictionary to define each sequence."""
+ results = {}
+ with open(os.path.join(self._path, '.mh_sequences'), 'r', encoding='ASCII') as f:
+ all_keys = set(self.keys())
+ for line in f:
+ try:
+ name, contents = line.split(':')
+ keys = set()
+ for spec in contents.split():
+ if spec.isdigit():
+ keys.add(int(spec))
+ else:
+ start, stop = (int(x) for x in spec.split('-'))
+ keys.update(range(start, stop + 1))
+ results[name] = [key for key in sorted(keys) \
+ if key in all_keys]
+ if len(results[name]) == 0:
+ del results[name]
+ except ValueError:
+ raise FormatError('Invalid sequence specification: %s' %
+ line.rstrip())
+ return results
+
+ def set_sequences(self, sequences):
+ """Set sequences using the given name-to-key-list dictionary."""
+ f = open(os.path.join(self._path, '.mh_sequences'), 'r+', encoding='ASCII')
+ try:
+ os.close(os.open(f.name, os.O_WRONLY | os.O_TRUNC))
+ for name, keys in sequences.items():
+ if len(keys) == 0:
+ continue
+ f.write(name + ':')
+ prev = None
+ completing = False
+ for key in sorted(set(keys)):
+ if key - 1 == prev:
+ if not completing:
+ completing = True
+ f.write('-')
+ elif completing:
+ completing = False
+ f.write('%s %s' % (prev, key))
+ else:
+ f.write(' %s' % key)
+ prev = key
+ if completing:
+ f.write(str(prev) + '\n')
+ else:
+ f.write('\n')
+ finally:
+ _sync_close(f)
+
+ def pack(self):
+ """Re-name messages to eliminate numbering gaps. Invalidates keys."""
+ sequences = self.get_sequences()
+ prev = 0
+ changes = []
+ for key in self.iterkeys():
+ if key - 1 != prev:
+ changes.append((key, prev + 1))
+ try:
+ os.link(os.path.join(self._path, str(key)),
+ os.path.join(self._path, str(prev + 1)))
+ except (AttributeError, PermissionError):
+ os.rename(os.path.join(self._path, str(key)),
+ os.path.join(self._path, str(prev + 1)))
+ else:
+ os.unlink(os.path.join(self._path, str(key)))
+ prev += 1
+ self._next_key = prev + 1
+ if len(changes) == 0:
+ return
+ for name, key_list in sequences.items():
+ for old, new in changes:
+ if old in key_list:
+ key_list[key_list.index(old)] = new
+ self.set_sequences(sequences)
+
+ def _dump_sequences(self, message, key):
+ """Inspect a new MHMessage and update sequences appropriately."""
+ pending_sequences = message.get_sequences()
+ all_sequences = self.get_sequences()
+ for name, key_list in all_sequences.items():
+ if name in pending_sequences:
+ key_list.append(key)
+ elif key in key_list:
+ del key_list[key_list.index(key)]
+ for sequence in pending_sequences:
+ if sequence not in all_sequences:
+ all_sequences[sequence] = [key]
+ self.set_sequences(all_sequences)
+
+
+class Babyl(_singlefileMailbox):
+ """An Rmail-style Babyl mailbox."""
+
+ _special_labels = frozenset({'unseen', 'deleted', 'filed', 'answered',
+ 'forwarded', 'edited', 'resent'})
+
+ def __init__(self, path, factory=None, create=True):
+ """Initialize a Babyl mailbox."""
+ _singlefileMailbox.__init__(self, path, factory, create)
+ self._labels = {}
+
+ def add(self, message):
+ """Add message and return assigned key."""
+ key = _singlefileMailbox.add(self, message)
+ if isinstance(message, BabylMessage):
+ self._labels[key] = message.get_labels()
+ return key
+
+ def remove(self, key):
+ """Remove the keyed message; raise KeyError if it doesn't exist."""
+ _singlefileMailbox.remove(self, key)
+ if key in self._labels:
+ del self._labels[key]
+
+ def __setitem__(self, key, message):
+ """Replace the keyed message; raise KeyError if it doesn't exist."""
+ _singlefileMailbox.__setitem__(self, key, message)
+ if isinstance(message, BabylMessage):
+ self._labels[key] = message.get_labels()
+
+ def get_message(self, key):
+ """Return a Message representation or raise a KeyError."""
+ start, stop = self._lookup(key)
+ self._file.seek(start)
+ self._file.readline() # Skip b'1,' line specifying labels.
+ original_headers = io.BytesIO()
+ while True:
+ line = self._file.readline()
+ if line == b'*** EOOH ***' + linesep or not line:
+ break
+ original_headers.write(line.replace(linesep, b'\n'))
+ visible_headers = io.BytesIO()
+ while True:
+ line = self._file.readline()
+ if line == linesep or not line:
+ break
+ visible_headers.write(line.replace(linesep, b'\n'))
+ # Read up to the stop, or to the end
+ n = stop - self._file.tell()
+ assert n >= 0
+ body = self._file.read(n)
+ body = body.replace(linesep, b'\n')
+ msg = BabylMessage(original_headers.getvalue() + body)
+ msg.set_visible(visible_headers.getvalue())
+ if key in self._labels:
+ msg.set_labels(self._labels[key])
+ return msg
+
+ def get_bytes(self, key):
+ """Return a string representation or raise a KeyError."""
+ start, stop = self._lookup(key)
+ self._file.seek(start)
+ self._file.readline() # Skip b'1,' line specifying labels.
+ original_headers = io.BytesIO()
+ while True:
+ line = self._file.readline()
+ if line == b'*** EOOH ***' + linesep or not line:
+ break
+ original_headers.write(line.replace(linesep, b'\n'))
+ while True:
+ line = self._file.readline()
+ if line == linesep or not line:
+ break
+ headers = original_headers.getvalue()
+ n = stop - self._file.tell()
+ assert n >= 0
+ data = self._file.read(n)
+ data = data.replace(linesep, b'\n')
+ return headers + data
+
+ def get_file(self, key):
+ """Return a file-like representation or raise a KeyError."""
+ return io.BytesIO(self.get_bytes(key).replace(b'\n', linesep))
+
+ def get_labels(self):
+ """Return a list of user-defined labels in the mailbox."""
+ self._lookup()
+ labels = set()
+ for label_list in self._labels.values():
+ labels.update(label_list)
+ labels.difference_update(self._special_labels)
+ return list(labels)
+
+ def _generate_toc(self):
+ """Generate key-to-(start, stop) table of contents."""
+ starts, stops = [], []
+ self._file.seek(0)
+ next_pos = 0
+ label_lists = []
+ while True:
+ line_pos = next_pos
+ line = self._file.readline()
+ next_pos = self._file.tell()
+ if line == b'\037\014' + linesep:
+ if len(stops) < len(starts):
+ stops.append(line_pos - len(linesep))
+ starts.append(next_pos)
+ labels = [label.strip() for label
+ in self._file.readline()[1:].split(b',')
+ if label.strip()]
+ label_lists.append(labels)
+ elif line == b'\037' or line == b'\037' + linesep:
+ if len(stops) < len(starts):
+ stops.append(line_pos - len(linesep))
+ elif not line:
+ stops.append(line_pos - len(linesep))
+ break
+ self._toc = dict(enumerate(zip(starts, stops)))
+ self._labels = dict(enumerate(label_lists))
+ self._next_key = len(self._toc)
+ self._file.seek(0, 2)
+ self._file_length = self._file.tell()
+
+ def _pre_mailbox_hook(self, f):
+ """Called before writing the mailbox to file f."""
+ babyl = b'BABYL OPTIONS:' + linesep
+ babyl += b'Version: 5' + linesep
+ labels = self.get_labels()
+ labels = (label.encode() for label in labels)
+ babyl += b'Labels:' + b','.join(labels) + linesep
+ babyl += b'\037'
+ f.write(babyl)
+
+ def _pre_message_hook(self, f):
+ """Called before writing each message to file f."""
+ f.write(b'\014' + linesep)
+
+ def _post_message_hook(self, f):
+ """Called after writing each message to file f."""
+ f.write(linesep + b'\037')
+
+ def _install_message(self, message):
+ """Write message contents and return (start, stop)."""
+ start = self._file.tell()
+ if isinstance(message, BabylMessage):
+ special_labels = []
+ labels = []
+ for label in message.get_labels():
+ if label in self._special_labels:
+ special_labels.append(label)
+ else:
+ labels.append(label)
+ self._file.write(b'1')
+ for label in special_labels:
+ self._file.write(b', ' + label.encode())
+ self._file.write(b',,')
+ for label in labels:
+ self._file.write(b' ' + label.encode() + b',')
+ self._file.write(linesep)
+ else:
+ self._file.write(b'1,,' + linesep)
+ if isinstance(message, email.message.Message):
+ orig_buffer = io.BytesIO()
+ orig_generator = email.generator.BytesGenerator(orig_buffer, False, 0)
+ orig_generator.flatten(message)
+ orig_buffer.seek(0)
+ while True:
+ line = orig_buffer.readline()
+ self._file.write(line.replace(b'\n', linesep))
+ if line == b'\n' or not line:
+ break
+ self._file.write(b'*** EOOH ***' + linesep)
+ if isinstance(message, BabylMessage):
+ vis_buffer = io.BytesIO()
+ vis_generator = email.generator.BytesGenerator(vis_buffer, False, 0)
+ vis_generator.flatten(message.get_visible())
+ while True:
+ line = vis_buffer.readline()
+ self._file.write(line.replace(b'\n', linesep))
+ if line == b'\n' or not line:
+ break
+ else:
+ orig_buffer.seek(0)
+ while True:
+ line = orig_buffer.readline()
+ self._file.write(line.replace(b'\n', linesep))
+ if line == b'\n' or not line:
+ break
+ while True:
+ buffer = orig_buffer.read(4096) # Buffer size is arbitrary.
+ if not buffer:
+ break
+ self._file.write(buffer.replace(b'\n', linesep))
+ elif isinstance(message, (bytes, str, io.StringIO)):
+ if isinstance(message, io.StringIO):
+ warnings.warn("Use of StringIO input is deprecated, "
+ "use BytesIO instead", DeprecationWarning, 3)
+ message = message.getvalue()
+ if isinstance(message, str):
+ message = self._string_to_bytes(message)
+ body_start = message.find(b'\n\n') + 2
+ if body_start - 2 != -1:
+ self._file.write(message[:body_start].replace(b'\n', linesep))
+ self._file.write(b'*** EOOH ***' + linesep)
+ self._file.write(message[:body_start].replace(b'\n', linesep))
+ self._file.write(message[body_start:].replace(b'\n', linesep))
+ else:
+ self._file.write(b'*** EOOH ***' + linesep + linesep)
+ self._file.write(message.replace(b'\n', linesep))
+ elif hasattr(message, 'readline'):
+ if hasattr(message, 'buffer'):
+ warnings.warn("Use of text mode files is deprecated, "
+ "use a binary mode file instead", DeprecationWarning, 3)
+ message = message.buffer
+ original_pos = message.tell()
+ first_pass = True
+ while True:
+ line = message.readline()
+ # Universal newline support.
+ if line.endswith(b'\r\n'):
+ line = line[:-2] + b'\n'
+ elif line.endswith(b'\r'):
+ line = line[:-1] + b'\n'
+ self._file.write(line.replace(b'\n', linesep))
+ if line == b'\n' or not line:
+ if first_pass:
+ first_pass = False
+ self._file.write(b'*** EOOH ***' + linesep)
+ message.seek(original_pos)
+ else:
+ break
+ while True:
+ line = message.readline()
+ if not line:
+ break
+ # Universal newline support.
+ if line.endswith(b'\r\n'):
+ line = line[:-2] + linesep
+ elif line.endswith(b'\r'):
+ line = line[:-1] + linesep
+ elif line.endswith(b'\n'):
+ line = line[:-1] + linesep
+ self._file.write(line)
+ else:
+ raise TypeError('Invalid message type: %s' % type(message))
+ stop = self._file.tell()
+ return (start, stop)
+
+
+class Message(email.message.Message):
+ """Message with mailbox-format-specific properties."""
+
+ def __init__(self, message=None):
+ """Initialize a Message instance."""
+ if isinstance(message, email.message.Message):
+ self._become_message(copy.deepcopy(message))
+ if isinstance(message, Message):
+ message._explain_to(self)
+ elif isinstance(message, bytes):
+ self._become_message(email.message_from_bytes(message))
+ elif isinstance(message, str):
+ self._become_message(email.message_from_string(message))
+ elif isinstance(message, io.TextIOWrapper):
+ self._become_message(email.message_from_file(message))
+ elif hasattr(message, "read"):
+ self._become_message(email.message_from_binary_file(message))
+ elif message is None:
+ email.message.Message.__init__(self)
+ else:
+ raise TypeError('Invalid message type: %s' % type(message))
+
+ def _become_message(self, message):
+ """Assume the non-format-specific state of message."""
+ type_specific = getattr(message, '_type_specific_attributes', [])
+ for name in message.__dict__:
+ if name not in type_specific:
+ self.__dict__[name] = message.__dict__[name]
+
+ def _explain_to(self, message):
+ """Copy format-specific state to message insofar as possible."""
+ if isinstance(message, Message):
+ return # There's nothing format-specific to explain.
+ else:
+ raise TypeError('Cannot convert to specified type')
+
+
+class MaildirMessage(Message):
+ """Message with Maildir-specific properties."""
+
+ _type_specific_attributes = ['_subdir', '_info', '_date']
+
+ def __init__(self, message=None):
+ """Initialize a MaildirMessage instance."""
+ self._subdir = 'new'
+ self._info = ''
+ self._date = time.time()
+ Message.__init__(self, message)
+
+ def get_subdir(self):
+ """Return 'new' or 'cur'."""
+ return self._subdir
+
+ def set_subdir(self, subdir):
+ """Set subdir to 'new' or 'cur'."""
+ if subdir == 'new' or subdir == 'cur':
+ self._subdir = subdir
+ else:
+ raise ValueError("subdir must be 'new' or 'cur': %s" % subdir)
+
+ def get_flags(self):
+ """Return as a string the flags that are set."""
+ if self._info.startswith('2,'):
+ return self._info[2:]
+ else:
+ return ''
+
+ def set_flags(self, flags):
+ """Set the given flags and unset all others."""
+ self._info = '2,' + ''.join(sorted(flags))
+
+ def add_flag(self, flag):
+ """Set the given flag(s) without changing others."""
+ self.set_flags(''.join(set(self.get_flags()) | set(flag)))
+
+ def remove_flag(self, flag):
+ """Unset the given string flag(s) without changing others."""
+ if self.get_flags():
+ self.set_flags(''.join(set(self.get_flags()) - set(flag)))
+
+ def get_date(self):
+ """Return delivery date of message, in seconds since the epoch."""
+ return self._date
+
+ def set_date(self, date):
+ """Set delivery date of message, in seconds since the epoch."""
+ try:
+ self._date = float(date)
+ except ValueError:
+ raise TypeError("can't convert to float: %s" % date) from None
+
+ def get_info(self):
+ """Get the message's "info" as a string."""
+ return self._info
+
+ def set_info(self, info):
+ """Set the message's "info" string."""
+ if isinstance(info, str):
+ self._info = info
+ else:
+ raise TypeError('info must be a string: %s' % type(info))
+
+ def _explain_to(self, message):
+ """Copy Maildir-specific state to message insofar as possible."""
+ if isinstance(message, MaildirMessage):
+ message.set_flags(self.get_flags())
+ message.set_subdir(self.get_subdir())
+ message.set_date(self.get_date())
+ elif isinstance(message, _mboxMMDFMessage):
+ flags = set(self.get_flags())
+ if 'S' in flags:
+ message.add_flag('R')
+ if self.get_subdir() == 'cur':
+ message.add_flag('O')
+ if 'T' in flags:
+ message.add_flag('D')
+ if 'F' in flags:
+ message.add_flag('F')
+ if 'R' in flags:
+ message.add_flag('A')
+ message.set_from('MAILER-DAEMON', time.gmtime(self.get_date()))
+ elif isinstance(message, MHMessage):
+ flags = set(self.get_flags())
+ if 'S' not in flags:
+ message.add_sequence('unseen')
+ if 'R' in flags:
+ message.add_sequence('replied')
+ if 'F' in flags:
+ message.add_sequence('flagged')
+ elif isinstance(message, BabylMessage):
+ flags = set(self.get_flags())
+ if 'S' not in flags:
+ message.add_label('unseen')
+ if 'T' in flags:
+ message.add_label('deleted')
+ if 'R' in flags:
+ message.add_label('answered')
+ if 'P' in flags:
+ message.add_label('forwarded')
+ elif isinstance(message, Message):
+ pass
+ else:
+ raise TypeError('Cannot convert to specified type: %s' %
+ type(message))
+
+
+class _mboxMMDFMessage(Message):
+ """Message with mbox- or MMDF-specific properties."""
+
+ _type_specific_attributes = ['_from']
+
+ def __init__(self, message=None):
+ """Initialize an mboxMMDFMessage instance."""
+ self.set_from('MAILER-DAEMON', True)
+ if isinstance(message, email.message.Message):
+ unixfrom = message.get_unixfrom()
+ if unixfrom is not None and unixfrom.startswith('From '):
+ self.set_from(unixfrom[5:])
+ Message.__init__(self, message)
+
+ def get_from(self):
+ """Return contents of "From " line."""
+ return self._from
+
+ def set_from(self, from_, time_=None):
+ """Set "From " line, formatting and appending time_ if specified."""
+ if time_ is not None:
+ if time_ is True:
+ time_ = time.gmtime()
+ from_ += ' ' + time.asctime(time_)
+ self._from = from_
+
+ def get_flags(self):
+ """Return as a string the flags that are set."""
+ return self.get('Status', '') + self.get('X-Status', '')
+
+ def set_flags(self, flags):
+ """Set the given flags and unset all others."""
+ flags = set(flags)
+ status_flags, xstatus_flags = '', ''
+ for flag in ('R', 'O'):
+ if flag in flags:
+ status_flags += flag
+ flags.remove(flag)
+ for flag in ('D', 'F', 'A'):
+ if flag in flags:
+ xstatus_flags += flag
+ flags.remove(flag)
+ xstatus_flags += ''.join(sorted(flags))
+ try:
+ self.replace_header('Status', status_flags)
+ except KeyError:
+ self.add_header('Status', status_flags)
+ try:
+ self.replace_header('X-Status', xstatus_flags)
+ except KeyError:
+ self.add_header('X-Status', xstatus_flags)
+
+ def add_flag(self, flag):
+ """Set the given flag(s) without changing others."""
+ self.set_flags(''.join(set(self.get_flags()) | set(flag)))
+
+ def remove_flag(self, flag):
+ """Unset the given string flag(s) without changing others."""
+ if 'Status' in self or 'X-Status' in self:
+ self.set_flags(''.join(set(self.get_flags()) - set(flag)))
+
+ def _explain_to(self, message):
+ """Copy mbox- or MMDF-specific state to message insofar as possible."""
+ if isinstance(message, MaildirMessage):
+ flags = set(self.get_flags())
+ if 'O' in flags:
+ message.set_subdir('cur')
+ if 'F' in flags:
+ message.add_flag('F')
+ if 'A' in flags:
+ message.add_flag('R')
+ if 'R' in flags:
+ message.add_flag('S')
+ if 'D' in flags:
+ message.add_flag('T')
+ del message['status']
+ del message['x-status']
+ maybe_date = ' '.join(self.get_from().split()[-5:])
+ try:
+ message.set_date(calendar.timegm(time.strptime(maybe_date,
+ '%a %b %d %H:%M:%S %Y')))
+ except (ValueError, OverflowError):
+ pass
+ elif isinstance(message, _mboxMMDFMessage):
+ message.set_flags(self.get_flags())
+ message.set_from(self.get_from())
+ elif isinstance(message, MHMessage):
+ flags = set(self.get_flags())
+ if 'R' not in flags:
+ message.add_sequence('unseen')
+ if 'A' in flags:
+ message.add_sequence('replied')
+ if 'F' in flags:
+ message.add_sequence('flagged')
+ del message['status']
+ del message['x-status']
+ elif isinstance(message, BabylMessage):
+ flags = set(self.get_flags())
+ if 'R' not in flags:
+ message.add_label('unseen')
+ if 'D' in flags:
+ message.add_label('deleted')
+ if 'A' in flags:
+ message.add_label('answered')
+ del message['status']
+ del message['x-status']
+ elif isinstance(message, Message):
+ pass
+ else:
+ raise TypeError('Cannot convert to specified type: %s' %
+ type(message))
+
+
+class mboxMessage(_mboxMMDFMessage):
+ """Message with mbox-specific properties."""
+
+
+class MHMessage(Message):
+ """Message with MH-specific properties."""
+
+ _type_specific_attributes = ['_sequences']
+
+ def __init__(self, message=None):
+ """Initialize an MHMessage instance."""
+ self._sequences = []
+ Message.__init__(self, message)
+
+ def get_sequences(self):
+ """Return a list of sequences that include the message."""
+ return self._sequences[:]
+
+ def set_sequences(self, sequences):
+ """Set the list of sequences that include the message."""
+ self._sequences = list(sequences)
+
+ def add_sequence(self, sequence):
+ """Add sequence to list of sequences including the message."""
+ if isinstance(sequence, str):
+ if not sequence in self._sequences:
+ self._sequences.append(sequence)
+ else:
+ raise TypeError('sequence type must be str: %s' % type(sequence))
+
+ def remove_sequence(self, sequence):
+ """Remove sequence from the list of sequences including the message."""
+ try:
+ self._sequences.remove(sequence)
+ except ValueError:
+ pass
+
+ def _explain_to(self, message):
+ """Copy MH-specific state to message insofar as possible."""
+ if isinstance(message, MaildirMessage):
+ sequences = set(self.get_sequences())
+ if 'unseen' in sequences:
+ message.set_subdir('cur')
+ else:
+ message.set_subdir('cur')
+ message.add_flag('S')
+ if 'flagged' in sequences:
+ message.add_flag('F')
+ if 'replied' in sequences:
+ message.add_flag('R')
+ elif isinstance(message, _mboxMMDFMessage):
+ sequences = set(self.get_sequences())
+ if 'unseen' not in sequences:
+ message.add_flag('RO')
+ else:
+ message.add_flag('O')
+ if 'flagged' in sequences:
+ message.add_flag('F')
+ if 'replied' in sequences:
+ message.add_flag('A')
+ elif isinstance(message, MHMessage):
+ for sequence in self.get_sequences():
+ message.add_sequence(sequence)
+ elif isinstance(message, BabylMessage):
+ sequences = set(self.get_sequences())
+ if 'unseen' in sequences:
+ message.add_label('unseen')
+ if 'replied' in sequences:
+ message.add_label('answered')
+ elif isinstance(message, Message):
+ pass
+ else:
+ raise TypeError('Cannot convert to specified type: %s' %
+ type(message))
+
+
+class BabylMessage(Message):
+ """Message with Babyl-specific properties."""
+
+ _type_specific_attributes = ['_labels', '_visible']
+
+ def __init__(self, message=None):
+ """Initialize a BabylMessage instance."""
+ self._labels = []
+ self._visible = Message()
+ Message.__init__(self, message)
+
+ def get_labels(self):
+ """Return a list of labels on the message."""
+ return self._labels[:]
+
+ def set_labels(self, labels):
+ """Set the list of labels on the message."""
+ self._labels = list(labels)
+
+ def add_label(self, label):
+ """Add label to list of labels on the message."""
+ if isinstance(label, str):
+ if label not in self._labels:
+ self._labels.append(label)
+ else:
+ raise TypeError('label must be a string: %s' % type(label))
+
+ def remove_label(self, label):
+ """Remove label from the list of labels on the message."""
+ try:
+ self._labels.remove(label)
+ except ValueError:
+ pass
+
+ def get_visible(self):
+ """Return a Message representation of visible headers."""
+ return Message(self._visible)
+
+ def set_visible(self, visible):
+ """Set the Message representation of visible headers."""
+ self._visible = Message(visible)
+
+ def update_visible(self):
+ """Update and/or sensibly generate a set of visible headers."""
+ for header in self._visible.keys():
+ if header in self:
+ self._visible.replace_header(header, self[header])
+ else:
+ del self._visible[header]
+ for header in ('Date', 'From', 'Reply-To', 'To', 'CC', 'Subject'):
+ if header in self and header not in self._visible:
+ self._visible[header] = self[header]
+
+ def _explain_to(self, message):
+ """Copy Babyl-specific state to message insofar as possible."""
+ if isinstance(message, MaildirMessage):
+ labels = set(self.get_labels())
+ if 'unseen' in labels:
+ message.set_subdir('cur')
+ else:
+ message.set_subdir('cur')
+ message.add_flag('S')
+ if 'forwarded' in labels or 'resent' in labels:
+ message.add_flag('P')
+ if 'answered' in labels:
+ message.add_flag('R')
+ if 'deleted' in labels:
+ message.add_flag('T')
+ elif isinstance(message, _mboxMMDFMessage):
+ labels = set(self.get_labels())
+ if 'unseen' not in labels:
+ message.add_flag('RO')
+ else:
+ message.add_flag('O')
+ if 'deleted' in labels:
+ message.add_flag('D')
+ if 'answered' in labels:
+ message.add_flag('A')
+ elif isinstance(message, MHMessage):
+ labels = set(self.get_labels())
+ if 'unseen' in labels:
+ message.add_sequence('unseen')
+ if 'answered' in labels:
+ message.add_sequence('replied')
+ elif isinstance(message, BabylMessage):
+ message.set_visible(self.get_visible())
+ for label in self.get_labels():
+ message.add_label(label)
+ elif isinstance(message, Message):
+ pass
+ else:
+ raise TypeError('Cannot convert to specified type: %s' %
+ type(message))
+
+
+class MMDFMessage(_mboxMMDFMessage):
+ """Message with MMDF-specific properties."""
+
+
+class _ProxyFile:
+ """A read-only wrapper of a file."""
+
+ def __init__(self, f, pos=None):
+ """Initialize a _ProxyFile."""
+ self._file = f
+ if pos is None:
+ self._pos = f.tell()
+ else:
+ self._pos = pos
+
+ def read(self, size=None):
+ """Read bytes."""
+ return self._read(size, self._file.read)
+
+ def read1(self, size=None):
+ """Read bytes."""
+ return self._read(size, self._file.read1)
+
+ def readline(self, size=None):
+ """Read a line."""
+ return self._read(size, self._file.readline)
+
+ def readlines(self, sizehint=None):
+ """Read multiple lines."""
+ result = []
+ for line in self:
+ result.append(line)
+ if sizehint is not None:
+ sizehint -= len(line)
+ if sizehint <= 0:
+ break
+ return result
+
+ def __iter__(self):
+ """Iterate over lines."""
+ while True:
+ line = self.readline()
+ if not line:
+ return
+ yield line
+
+ def tell(self):
+ """Return the position."""
+ return self._pos
+
+ def seek(self, offset, whence=0):
+ """Change position."""
+ if whence == 1:
+ self._file.seek(self._pos)
+ self._file.seek(offset, whence)
+ self._pos = self._file.tell()
+
+ def close(self):
+ """Close the file."""
+ if hasattr(self, '_file'):
+ try:
+ if hasattr(self._file, 'close'):
+ self._file.close()
+ finally:
+ del self._file
+
+ def _read(self, size, read_method):
+ """Read size bytes using read_method."""
+ if size is None:
+ size = -1
+ self._file.seek(self._pos)
+ result = read_method(size)
+ self._pos = self._file.tell()
+ return result
+
+ def __enter__(self):
+ """Context management protocol support."""
+ return self
+
+ def __exit__(self, *exc):
+ self.close()
+
+ def readable(self):
+ return self._file.readable()
+
+ def writable(self):
+ return self._file.writable()
+
+ def seekable(self):
+ return self._file.seekable()
+
+ def flush(self):
+ return self._file.flush()
+
+ @property
+ def closed(self):
+ if not hasattr(self, '_file'):
+ return True
+ if not hasattr(self._file, 'closed'):
+ return False
+ return self._file.closed
+
+
+class _PartialFile(_ProxyFile):
+ """A read-only wrapper of part of a file."""
+
+ def __init__(self, f, start=None, stop=None):
+ """Initialize a _PartialFile."""
+ _ProxyFile.__init__(self, f, start)
+ self._start = start
+ self._stop = stop
+
+ def tell(self):
+ """Return the position with respect to start."""
+ return _ProxyFile.tell(self) - self._start
+
+ def seek(self, offset, whence=0):
+ """Change position, possibly with respect to start or stop."""
+ if whence == 0:
+ self._pos = self._start
+ whence = 1
+ elif whence == 2:
+ self._pos = self._stop
+ whence = 1
+ _ProxyFile.seek(self, offset, whence)
+
+ def _read(self, size, read_method):
+ """Read size bytes using read_method, honoring start and stop."""
+ remaining = self._stop - self._pos
+ if remaining <= 0:
+ return b''
+ if size is None or size < 0 or size > remaining:
+ size = remaining
+ return _ProxyFile._read(self, size, read_method)
+
+ def close(self):
+ # do *not* close the underlying file object for partial files,
+ # since it's global to the mailbox object
+ if hasattr(self, '_file'):
+ del self._file
+
+
+def _lock_file(f, dotlock=True):
+ """Lock file f using lockf and dot locking."""
+ dotlock_done = False
+ try:
+ if fcntl:
+ try:
+ fcntl.lockf(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
+ except OSError as e:
+ if e.errno in (errno.EAGAIN, errno.EACCES, errno.EROFS):
+ raise ExternalClashError('lockf: lock unavailable: %s' %
+ f.name)
+ else:
+ raise
+ if dotlock:
+ try:
+ pre_lock = _create_temporary(f.name + '.lock')
+ pre_lock.close()
+ except OSError as e:
+ if e.errno in (errno.EACCES, errno.EROFS):
+ return # Without write access, just skip dotlocking.
+ else:
+ raise
+ try:
+ try:
+ os.link(pre_lock.name, f.name + '.lock')
+ dotlock_done = True
+ except (AttributeError, PermissionError):
+ os.rename(pre_lock.name, f.name + '.lock')
+ dotlock_done = True
+ else:
+ os.unlink(pre_lock.name)
+ except FileExistsError:
+ os.remove(pre_lock.name)
+ raise ExternalClashError('dot lock unavailable: %s' %
+ f.name)
+ except:
+ if fcntl:
+ fcntl.lockf(f, fcntl.LOCK_UN)
+ if dotlock_done:
+ os.remove(f.name + '.lock')
+ raise
+
+def _unlock_file(f):
+ """Unlock file f using lockf and dot locking."""
+ if fcntl:
+ fcntl.lockf(f, fcntl.LOCK_UN)
+ if os.path.exists(f.name + '.lock'):
+ os.remove(f.name + '.lock')
+
+def _create_carefully(path):
+ """Create a file if it doesn't exist and open for reading and writing."""
+ fd = os.open(path, os.O_CREAT | os.O_EXCL | os.O_RDWR, 0o666)
+ try:
+ return open(path, 'rb+')
+ finally:
+ os.close(fd)
+
+def _create_temporary(path):
+ """Create a temp file based on path and open for reading and writing."""
+ return _create_carefully('%s.%s.%s.%s' % (path, int(time.time()),
+ socket.gethostname(),
+ os.getpid()))
+
+def _sync_flush(f):
+ """Ensure changes to file f are physically on disk."""
+ f.flush()
+ if hasattr(os, 'fsync'):
+ os.fsync(f.fileno())
+
+def _sync_close(f):
+ """Close file f, ensuring all changes are physically on disk."""
+ _sync_flush(f)
+ f.close()
+
+
+class Error(Exception):
+ """Raised for module-specific errors."""
+
+class NoSuchMailboxError(Error):
+ """The specified mailbox does not exist and won't be created."""
+
+class NotEmptyError(Error):
+ """The specified mailbox is not empty and deletion was requested."""
+
+class ExternalClashError(Error):
+ """Another process caused an action to fail."""
+
+class FormatError(Error):
+ """A file appears to have an invalid format."""
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/mimetypes.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/mimetypes.py
new file mode 100644
index 0000000000000000000000000000000000000000..954bb0a7453477fc5aa0ff44adad6a9a4da89dcb
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/mimetypes.py
@@ -0,0 +1,614 @@
+"""Guess the MIME type of a file.
+
+This module defines two useful functions:
+
+guess_type(url, strict=True) -- guess the MIME type and encoding of a URL.
+
+guess_extension(type, strict=True) -- guess the extension for a given MIME type.
+
+It also contains the following, for tuning the behavior:
+
+Data:
+
+knownfiles -- list of files to parse
+inited -- flag set when init() has been called
+suffix_map -- dictionary mapping suffixes to suffixes
+encodings_map -- dictionary mapping suffixes to encodings
+types_map -- dictionary mapping suffixes to types
+
+Functions:
+
+init([files]) -- parse a list of files, default knownfiles (on Windows, the
+ default values are taken from the registry)
+read_mime_types(file) -- parse one file, return a dictionary or None
+"""
+
+import os
+import sys
+import posixpath
+import urllib.parse
+try:
+ import winreg as _winreg
+except ImportError:
+ _winreg = None
+
+__all__ = [
+ "knownfiles", "inited", "MimeTypes",
+ "guess_type", "guess_all_extensions", "guess_extension",
+ "add_type", "init", "read_mime_types",
+ "suffix_map", "encodings_map", "types_map", "common_types"
+]
+
+knownfiles = [
+ "/etc/mime.types",
+ "/etc/httpd/mime.types", # Mac OS X
+ "/etc/httpd/conf/mime.types", # Apache
+ "/etc/apache/mime.types", # Apache 1
+ "/etc/apache2/mime.types", # Apache 2
+ "/usr/local/etc/httpd/conf/mime.types",
+ "/usr/local/lib/netscape/mime.types",
+ "/usr/local/etc/httpd/conf/mime.types", # Apache 1.2
+ "/usr/local/etc/mime.types", # Apache 1.3
+ ]
+
+inited = False
+_db = None
+
+
+class MimeTypes:
+ """MIME-types datastore.
+
+ This datastore can handle information from mime.types-style files
+ and supports basic determination of MIME type from a filename or
+ URL, and can guess a reasonable extension given a MIME type.
+ """
+
+ def __init__(self, filenames=(), strict=True):
+ if not inited:
+ init()
+ self.encodings_map = _encodings_map_default.copy()
+ self.suffix_map = _suffix_map_default.copy()
+ self.types_map = ({}, {}) # dict for (non-strict, strict)
+ self.types_map_inv = ({}, {})
+ for (ext, type) in _types_map_default.items():
+ self.add_type(type, ext, True)
+ for (ext, type) in _common_types_default.items():
+ self.add_type(type, ext, False)
+ for name in filenames:
+ self.read(name, strict)
+
+ def add_type(self, type, ext, strict=True):
+ """Add a mapping between a type and an extension.
+
+ When the extension is already known, the new
+ type will replace the old one. When the type
+ is already known the extension will be added
+ to the list of known extensions.
+
+ If strict is true, information will be added to
+ list of standard types, else to the list of non-standard
+ types.
+ """
+ self.types_map[strict][ext] = type
+ exts = self.types_map_inv[strict].setdefault(type, [])
+ if ext not in exts:
+ exts.append(ext)
+
+ def guess_type(self, url, strict=True):
+ """Guess the type of a file which is either a URL or a path-like object.
+
+ Return value is a tuple (type, encoding) where type is None if
+ the type can't be guessed (no or unknown suffix) or a string
+ of the form type/subtype, usable for a MIME Content-type
+ header; and encoding is None for no encoding or the name of
+ the program used to encode (e.g. compress or gzip). The
+ mappings are table driven. Encoding suffixes are case
+ sensitive; type suffixes are first tried case sensitive, then
+ case insensitive.
+
+ The suffixes .tgz, .taz and .tz (case sensitive!) are all
+ mapped to '.tar.gz'. (This is table-driven too, using the
+ dictionary suffix_map.)
+
+ Optional `strict' argument when False adds a bunch of commonly found,
+ but non-standard types.
+ """
+ url = os.fspath(url)
+ scheme, url = urllib.parse._splittype(url)
+ if scheme == 'data':
+ # syntax of data URLs:
+ # dataurl := "data:" [ mediatype ] [ ";base64" ] "," data
+ # mediatype := [ type "/" subtype ] *( ";" parameter )
+ # data := *urlchar
+ # parameter := attribute "=" value
+ # type/subtype defaults to "text/plain"
+ comma = url.find(',')
+ if comma < 0:
+ # bad data URL
+ return None, None
+ semi = url.find(';', 0, comma)
+ if semi >= 0:
+ type = url[:semi]
+ else:
+ type = url[:comma]
+ if '=' in type or '/' not in type:
+ type = 'text/plain'
+ return type, None # never compressed, so encoding is None
+ base, ext = posixpath.splitext(url)
+ while ext in self.suffix_map:
+ base, ext = posixpath.splitext(base + self.suffix_map[ext])
+ if ext in self.encodings_map:
+ encoding = self.encodings_map[ext]
+ base, ext = posixpath.splitext(base)
+ else:
+ encoding = None
+ types_map = self.types_map[True]
+ if ext in types_map:
+ return types_map[ext], encoding
+ elif ext.lower() in types_map:
+ return types_map[ext.lower()], encoding
+ elif strict:
+ return None, encoding
+ types_map = self.types_map[False]
+ if ext in types_map:
+ return types_map[ext], encoding
+ elif ext.lower() in types_map:
+ return types_map[ext.lower()], encoding
+ else:
+ return None, encoding
+
+ def guess_all_extensions(self, type, strict=True):
+ """Guess the extensions for a file based on its MIME type.
+
+ Return value is a list of strings giving the possible filename
+ extensions, including the leading dot ('.'). The extension is not
+ guaranteed to have been associated with any particular data stream,
+ but would be mapped to the MIME type `type' by guess_type().
+
+ Optional `strict' argument when false adds a bunch of commonly found,
+ but non-standard types.
+ """
+ type = type.lower()
+ extensions = self.types_map_inv[True].get(type, [])
+ if not strict:
+ for ext in self.types_map_inv[False].get(type, []):
+ if ext not in extensions:
+ extensions.append(ext)
+ return extensions
+
+ def guess_extension(self, type, strict=True):
+ """Guess the extension for a file based on its MIME type.
+
+ Return value is a string giving a filename extension,
+ including the leading dot ('.'). The extension is not
+ guaranteed to have been associated with any particular data
+ stream, but would be mapped to the MIME type `type' by
+ guess_type(). If no extension can be guessed for `type', None
+ is returned.
+
+ Optional `strict' argument when false adds a bunch of commonly found,
+ but non-standard types.
+ """
+ extensions = self.guess_all_extensions(type, strict)
+ if not extensions:
+ return None
+ return extensions[0]
+
+ def read(self, filename, strict=True):
+ """
+ Read a single mime.types-format file, specified by pathname.
+
+ If strict is true, information will be added to
+ list of standard types, else to the list of non-standard
+ types.
+ """
+ with open(filename, encoding='utf-8') as fp:
+ self.readfp(fp, strict)
+
+ def readfp(self, fp, strict=True):
+ """
+ Read a single mime.types-format file.
+
+ If strict is true, information will be added to
+ list of standard types, else to the list of non-standard
+ types.
+ """
+ while 1:
+ line = fp.readline()
+ if not line:
+ break
+ words = line.split()
+ for i in range(len(words)):
+ if words[i][0] == '#':
+ del words[i:]
+ break
+ if not words:
+ continue
+ type, suffixes = words[0], words[1:]
+ for suff in suffixes:
+ self.add_type(type, '.' + suff, strict)
+
+ def read_windows_registry(self, strict=True):
+ """
+ Load the MIME types database from Windows registry.
+
+ If strict is true, information will be added to
+ list of standard types, else to the list of non-standard
+ types.
+ """
+
+ # Windows only
+ if not _winreg:
+ return
+
+ def enum_types(mimedb):
+ i = 0
+ while True:
+ try:
+ ctype = _winreg.EnumKey(mimedb, i)
+ except OSError:
+ break
+ else:
+ if '\0' not in ctype:
+ yield ctype
+ i += 1
+
+ with _winreg.OpenKey(_winreg.HKEY_CLASSES_ROOT, '') as hkcr:
+ for subkeyname in enum_types(hkcr):
+ try:
+ with _winreg.OpenKey(hkcr, subkeyname) as subkey:
+ # Only check file extensions
+ if not subkeyname.startswith("."):
+ continue
+ # raises OSError if no 'Content Type' value
+ mimetype, datatype = _winreg.QueryValueEx(
+ subkey, 'Content Type')
+ if datatype != _winreg.REG_SZ:
+ continue
+ self.add_type(mimetype, subkeyname, strict)
+ except OSError:
+ continue
+
+def guess_type(url, strict=True):
+ """Guess the type of a file based on its URL.
+
+ Return value is a tuple (type, encoding) where type is None if the
+ type can't be guessed (no or unknown suffix) or a string of the
+ form type/subtype, usable for a MIME Content-type header; and
+ encoding is None for no encoding or the name of the program used
+ to encode (e.g. compress or gzip). The mappings are table
+ driven. Encoding suffixes are case sensitive; type suffixes are
+ first tried case sensitive, then case insensitive.
+
+ The suffixes .tgz, .taz and .tz (case sensitive!) are all mapped
+ to ".tar.gz". (This is table-driven too, using the dictionary
+ suffix_map).
+
+ Optional `strict' argument when false adds a bunch of commonly found, but
+ non-standard types.
+ """
+ if _db is None:
+ init()
+ return _db.guess_type(url, strict)
+
+
+def guess_all_extensions(type, strict=True):
+ """Guess the extensions for a file based on its MIME type.
+
+ Return value is a list of strings giving the possible filename
+ extensions, including the leading dot ('.'). The extension is not
+ guaranteed to have been associated with any particular data
+ stream, but would be mapped to the MIME type `type' by
+ guess_type(). If no extension can be guessed for `type', None
+ is returned.
+
+ Optional `strict' argument when false adds a bunch of commonly found,
+ but non-standard types.
+ """
+ if _db is None:
+ init()
+ return _db.guess_all_extensions(type, strict)
+
+def guess_extension(type, strict=True):
+ """Guess the extension for a file based on its MIME type.
+
+ Return value is a string giving a filename extension, including the
+ leading dot ('.'). The extension is not guaranteed to have been
+ associated with any particular data stream, but would be mapped to the
+ MIME type `type' by guess_type(). If no extension can be guessed for
+ `type', None is returned.
+
+ Optional `strict' argument when false adds a bunch of commonly found,
+ but non-standard types.
+ """
+ if _db is None:
+ init()
+ return _db.guess_extension(type, strict)
+
+def add_type(type, ext, strict=True):
+ """Add a mapping between a type and an extension.
+
+ When the extension is already known, the new
+ type will replace the old one. When the type
+ is already known the extension will be added
+ to the list of known extensions.
+
+ If strict is true, information will be added to
+ list of standard types, else to the list of non-standard
+ types.
+ """
+ if _db is None:
+ init()
+ return _db.add_type(type, ext, strict)
+
+
+def init(files=None):
+ global suffix_map, types_map, encodings_map, common_types
+ global inited, _db
+ inited = True # so that MimeTypes.__init__() doesn't call us again
+
+ if files is None or _db is None:
+ db = MimeTypes()
+ if _winreg:
+ db.read_windows_registry()
+
+ if files is None:
+ files = knownfiles
+ else:
+ files = knownfiles + list(files)
+ else:
+ db = _db
+
+ for file in files:
+ if os.path.isfile(file):
+ db.read(file)
+ encodings_map = db.encodings_map
+ suffix_map = db.suffix_map
+ types_map = db.types_map[True]
+ common_types = db.types_map[False]
+ # Make the DB a global variable now that it is fully initialized
+ _db = db
+
+
+def read_mime_types(file):
+ try:
+ f = open(file, encoding='utf-8')
+ except OSError:
+ return None
+ with f:
+ db = MimeTypes()
+ db.readfp(f, True)
+ return db.types_map[True]
+
+
+def _default_mime_types():
+ global suffix_map, _suffix_map_default
+ global encodings_map, _encodings_map_default
+ global types_map, _types_map_default
+ global common_types, _common_types_default
+
+ suffix_map = _suffix_map_default = {
+ '.svgz': '.svg.gz',
+ '.tgz': '.tar.gz',
+ '.taz': '.tar.gz',
+ '.tz': '.tar.gz',
+ '.tbz2': '.tar.bz2',
+ '.txz': '.tar.xz',
+ }
+
+ encodings_map = _encodings_map_default = {
+ '.gz': 'gzip',
+ '.Z': 'compress',
+ '.bz2': 'bzip2',
+ '.xz': 'xz',
+ }
+
+ # Before adding new types, make sure they are either registered with IANA,
+ # at http://www.iana.org/assignments/media-types
+ # or extensions, i.e. using the x- prefix
+
+ # If you add to these, please keep them sorted by mime type.
+ # Make sure the entry with the preferred file extension for a particular mime type
+ # appears before any others of the same mimetype.
+ types_map = _types_map_default = {
+ '.js' : 'application/javascript',
+ '.mjs' : 'application/javascript',
+ '.json' : 'application/json',
+ '.webmanifest': 'application/manifest+json',
+ '.doc' : 'application/msword',
+ '.dot' : 'application/msword',
+ '.wiz' : 'application/msword',
+ '.bin' : 'application/octet-stream',
+ '.a' : 'application/octet-stream',
+ '.dll' : 'application/octet-stream',
+ '.exe' : 'application/octet-stream',
+ '.o' : 'application/octet-stream',
+ '.obj' : 'application/octet-stream',
+ '.so' : 'application/octet-stream',
+ '.oda' : 'application/oda',
+ '.pdf' : 'application/pdf',
+ '.p7c' : 'application/pkcs7-mime',
+ '.ps' : 'application/postscript',
+ '.ai' : 'application/postscript',
+ '.eps' : 'application/postscript',
+ '.m3u' : 'application/vnd.apple.mpegurl',
+ '.m3u8' : 'application/vnd.apple.mpegurl',
+ '.xls' : 'application/vnd.ms-excel',
+ '.xlb' : 'application/vnd.ms-excel',
+ '.ppt' : 'application/vnd.ms-powerpoint',
+ '.pot' : 'application/vnd.ms-powerpoint',
+ '.ppa' : 'application/vnd.ms-powerpoint',
+ '.pps' : 'application/vnd.ms-powerpoint',
+ '.pwz' : 'application/vnd.ms-powerpoint',
+ '.wasm' : 'application/wasm',
+ '.bcpio' : 'application/x-bcpio',
+ '.cpio' : 'application/x-cpio',
+ '.csh' : 'application/x-csh',
+ '.dvi' : 'application/x-dvi',
+ '.gtar' : 'application/x-gtar',
+ '.hdf' : 'application/x-hdf',
+ '.h5' : 'application/x-hdf5',
+ '.latex' : 'application/x-latex',
+ '.mif' : 'application/x-mif',
+ '.cdf' : 'application/x-netcdf',
+ '.nc' : 'application/x-netcdf',
+ '.p12' : 'application/x-pkcs12',
+ '.pfx' : 'application/x-pkcs12',
+ '.ram' : 'application/x-pn-realaudio',
+ '.pyc' : 'application/x-python-code',
+ '.pyo' : 'application/x-python-code',
+ '.sh' : 'application/x-sh',
+ '.shar' : 'application/x-shar',
+ '.swf' : 'application/x-shockwave-flash',
+ '.sv4cpio': 'application/x-sv4cpio',
+ '.sv4crc' : 'application/x-sv4crc',
+ '.tar' : 'application/x-tar',
+ '.tcl' : 'application/x-tcl',
+ '.tex' : 'application/x-tex',
+ '.texi' : 'application/x-texinfo',
+ '.texinfo': 'application/x-texinfo',
+ '.roff' : 'application/x-troff',
+ '.t' : 'application/x-troff',
+ '.tr' : 'application/x-troff',
+ '.man' : 'application/x-troff-man',
+ '.me' : 'application/x-troff-me',
+ '.ms' : 'application/x-troff-ms',
+ '.ustar' : 'application/x-ustar',
+ '.src' : 'application/x-wais-source',
+ '.xsl' : 'application/xml',
+ '.rdf' : 'application/xml',
+ '.wsdl' : 'application/xml',
+ '.xpdl' : 'application/xml',
+ '.zip' : 'application/zip',
+ '.au' : 'audio/basic',
+ '.snd' : 'audio/basic',
+ '.mp3' : 'audio/mpeg',
+ '.mp2' : 'audio/mpeg',
+ '.aif' : 'audio/x-aiff',
+ '.aifc' : 'audio/x-aiff',
+ '.aiff' : 'audio/x-aiff',
+ '.ra' : 'audio/x-pn-realaudio',
+ '.wav' : 'audio/x-wav',
+ '.bmp' : 'image/bmp',
+ '.gif' : 'image/gif',
+ '.ief' : 'image/ief',
+ '.jpg' : 'image/jpeg',
+ '.jpe' : 'image/jpeg',
+ '.jpeg' : 'image/jpeg',
+ '.png' : 'image/png',
+ '.svg' : 'image/svg+xml',
+ '.tiff' : 'image/tiff',
+ '.tif' : 'image/tiff',
+ '.ico' : 'image/vnd.microsoft.icon',
+ '.ras' : 'image/x-cmu-raster',
+ '.bmp' : 'image/x-ms-bmp',
+ '.pnm' : 'image/x-portable-anymap',
+ '.pbm' : 'image/x-portable-bitmap',
+ '.pgm' : 'image/x-portable-graymap',
+ '.ppm' : 'image/x-portable-pixmap',
+ '.rgb' : 'image/x-rgb',
+ '.xbm' : 'image/x-xbitmap',
+ '.xpm' : 'image/x-xpixmap',
+ '.xwd' : 'image/x-xwindowdump',
+ '.eml' : 'message/rfc822',
+ '.mht' : 'message/rfc822',
+ '.mhtml' : 'message/rfc822',
+ '.nws' : 'message/rfc822',
+ '.css' : 'text/css',
+ '.csv' : 'text/csv',
+ '.html' : 'text/html',
+ '.htm' : 'text/html',
+ '.txt' : 'text/plain',
+ '.bat' : 'text/plain',
+ '.c' : 'text/plain',
+ '.h' : 'text/plain',
+ '.ksh' : 'text/plain',
+ '.pl' : 'text/plain',
+ '.rtx' : 'text/richtext',
+ '.tsv' : 'text/tab-separated-values',
+ '.py' : 'text/x-python',
+ '.etx' : 'text/x-setext',
+ '.sgm' : 'text/x-sgml',
+ '.sgml' : 'text/x-sgml',
+ '.vcf' : 'text/x-vcard',
+ '.xml' : 'text/xml',
+ '.mp4' : 'video/mp4',
+ '.mpeg' : 'video/mpeg',
+ '.m1v' : 'video/mpeg',
+ '.mpa' : 'video/mpeg',
+ '.mpe' : 'video/mpeg',
+ '.mpg' : 'video/mpeg',
+ '.mov' : 'video/quicktime',
+ '.qt' : 'video/quicktime',
+ '.webm' : 'video/webm',
+ '.avi' : 'video/x-msvideo',
+ '.movie' : 'video/x-sgi-movie',
+ }
+
+ # These are non-standard types, commonly found in the wild. They will
+ # only match if strict=0 flag is given to the API methods.
+
+ # Please sort these too
+ common_types = _common_types_default = {
+ '.rtf' : 'application/rtf',
+ '.midi': 'audio/midi',
+ '.mid' : 'audio/midi',
+ '.jpg' : 'image/jpg',
+ '.pict': 'image/pict',
+ '.pct' : 'image/pict',
+ '.pic' : 'image/pict',
+ '.xul' : 'text/xul',
+ }
+
+
+_default_mime_types()
+
+
+def _main():
+ import getopt
+
+ USAGE = """\
+Usage: mimetypes.py [options] type
+
+Options:
+ --help / -h -- print this message and exit
+ --lenient / -l -- additionally search of some common, but non-standard
+ types.
+ --extension / -e -- guess extension instead of type
+
+More than one type argument may be given.
+"""
+
+ def usage(code, msg=''):
+ print(USAGE)
+ if msg: print(msg)
+ sys.exit(code)
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], 'hle',
+ ['help', 'lenient', 'extension'])
+ except getopt.error as msg:
+ usage(1, msg)
+
+ strict = 1
+ extension = 0
+ for opt, arg in opts:
+ if opt in ('-h', '--help'):
+ usage(0)
+ elif opt in ('-l', '--lenient'):
+ strict = 0
+ elif opt in ('-e', '--extension'):
+ extension = 1
+ for gtype in args:
+ if extension:
+ guess = guess_extension(gtype, strict)
+ if not guess: print("I don't know anything about type", gtype)
+ else: print(guess)
+ else:
+ guess, encoding = guess_type(gtype, strict)
+ if not guess: print("I don't know anything about type", gtype)
+ else: print('type:', guess, 'encoding:', encoding)
+
+
+if __name__ == '__main__':
+ _main()
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/modulefinder.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/modulefinder.py
new file mode 100644
index 0000000000000000000000000000000000000000..aadcd23edbaaa7c91eb28ffe56b4cd75ab4d418f
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/modulefinder.py
@@ -0,0 +1,687 @@
+"""Find modules used by a script, using introspection."""
+
+import dis
+import importlib._bootstrap_external
+import importlib.machinery
+import marshal
+import os
+import io
+import sys
+import types
+import warnings
+
+
+LOAD_CONST = dis.opmap['LOAD_CONST']
+IMPORT_NAME = dis.opmap['IMPORT_NAME']
+STORE_NAME = dis.opmap['STORE_NAME']
+STORE_GLOBAL = dis.opmap['STORE_GLOBAL']
+STORE_OPS = STORE_NAME, STORE_GLOBAL
+EXTENDED_ARG = dis.EXTENDED_ARG
+
+# Old imp constants:
+
+_SEARCH_ERROR = 0
+_PY_SOURCE = 1
+_PY_COMPILED = 2
+_C_EXTENSION = 3
+_PKG_DIRECTORY = 5
+_C_BUILTIN = 6
+_PY_FROZEN = 7
+
+# Modulefinder does a good job at simulating Python's, but it can not
+# handle __path__ modifications packages make at runtime. Therefore there
+# is a mechanism whereby you can register extra paths in this map for a
+# package, and it will be honored.
+
+# Note this is a mapping is lists of paths.
+packagePathMap = {}
+
+# A Public interface
+def AddPackagePath(packagename, path):
+ packagePathMap.setdefault(packagename, []).append(path)
+
+replacePackageMap = {}
+
+# This ReplacePackage mechanism allows modulefinder to work around
+# situations in which a package injects itself under the name
+# of another package into sys.modules at runtime by calling
+# ReplacePackage("real_package_name", "faked_package_name")
+# before running ModuleFinder.
+
+def ReplacePackage(oldname, newname):
+ replacePackageMap[oldname] = newname
+
+
+def _find_module(name, path=None):
+ """An importlib reimplementation of imp.find_module (for our purposes)."""
+
+ # It's necessary to clear the caches for our Finder first, in case any
+ # modules are being added/deleted/modified at runtime. In particular,
+ # test_modulefinder.py changes file tree contents in a cache-breaking way:
+
+ importlib.machinery.PathFinder.invalidate_caches()
+
+ spec = importlib.machinery.PathFinder.find_spec(name, path)
+
+ if spec is None:
+ raise ImportError("No module named {name!r}".format(name=name), name=name)
+
+ # Some special cases:
+
+ if spec.loader is importlib.machinery.BuiltinImporter:
+ return None, None, ("", "", _C_BUILTIN)
+
+ if spec.loader is importlib.machinery.FrozenImporter:
+ return None, None, ("", "", _PY_FROZEN)
+
+ file_path = spec.origin
+
+ if spec.loader.is_package(name):
+ return None, os.path.dirname(file_path), ("", "", _PKG_DIRECTORY)
+
+ if isinstance(spec.loader, importlib.machinery.SourceFileLoader):
+ kind = _PY_SOURCE
+
+ elif isinstance(spec.loader, importlib.machinery.ExtensionFileLoader):
+ kind = _C_EXTENSION
+
+ elif isinstance(spec.loader, importlib.machinery.SourcelessFileLoader):
+ kind = _PY_COMPILED
+
+ else: # Should never happen.
+ return None, None, ("", "", _SEARCH_ERROR)
+
+ file = io.open_code(file_path)
+ suffix = os.path.splitext(file_path)[-1]
+
+ return file, file_path, (suffix, "rb", kind)
+
+
+class Module:
+
+ def __init__(self, name, file=None, path=None):
+ self.__name__ = name
+ self.__file__ = file
+ self.__path__ = path
+ self.__code__ = None
+ # The set of global names that are assigned to in the module.
+ # This includes those names imported through starimports of
+ # Python modules.
+ self.globalnames = {}
+ # The set of starimports this module did that could not be
+ # resolved, ie. a starimport from a non-Python module.
+ self.starimports = {}
+
+ def __repr__(self):
+ s = "Module(%r" % (self.__name__,)
+ if self.__file__ is not None:
+ s = s + ", %r" % (self.__file__,)
+ if self.__path__ is not None:
+ s = s + ", %r" % (self.__path__,)
+ s = s + ")"
+ return s
+
+class ModuleFinder:
+
+ def __init__(self, path=None, debug=0, excludes=None, replace_paths=None):
+ if path is None:
+ path = sys.path
+ self.path = path
+ self.modules = {}
+ self.badmodules = {}
+ self.debug = debug
+ self.indent = 0
+ self.excludes = excludes if excludes is not None else []
+ self.replace_paths = replace_paths if replace_paths is not None else []
+ self.processed_paths = [] # Used in debugging only
+
+ def msg(self, level, str, *args):
+ if level <= self.debug:
+ for i in range(self.indent):
+ print(" ", end=' ')
+ print(str, end=' ')
+ for arg in args:
+ print(repr(arg), end=' ')
+ print()
+
+ def msgin(self, *args):
+ level = args[0]
+ if level <= self.debug:
+ self.indent = self.indent + 1
+ self.msg(*args)
+
+ def msgout(self, *args):
+ level = args[0]
+ if level <= self.debug:
+ self.indent = self.indent - 1
+ self.msg(*args)
+
+ def run_script(self, pathname):
+ self.msg(2, "run_script", pathname)
+ with io.open_code(pathname) as fp:
+ stuff = ("", "rb", _PY_SOURCE)
+ self.load_module('__main__', fp, pathname, stuff)
+
+ def load_file(self, pathname):
+ dir, name = os.path.split(pathname)
+ name, ext = os.path.splitext(name)
+ with io.open_code(pathname) as fp:
+ stuff = (ext, "rb", _PY_SOURCE)
+ self.load_module(name, fp, pathname, stuff)
+
+ def import_hook(self, name, caller=None, fromlist=None, level=-1):
+ self.msg(3, "import_hook", name, caller, fromlist, level)
+ parent = self.determine_parent(caller, level=level)
+ q, tail = self.find_head_package(parent, name)
+ m = self.load_tail(q, tail)
+ if not fromlist:
+ return q
+ if m.__path__:
+ self.ensure_fromlist(m, fromlist)
+ return None
+
+ def determine_parent(self, caller, level=-1):
+ self.msgin(4, "determine_parent", caller, level)
+ if not caller or level == 0:
+ self.msgout(4, "determine_parent -> None")
+ return None
+ pname = caller.__name__
+ if level >= 1: # relative import
+ if caller.__path__:
+ level -= 1
+ if level == 0:
+ parent = self.modules[pname]
+ assert parent is caller
+ self.msgout(4, "determine_parent ->", parent)
+ return parent
+ if pname.count(".") < level:
+ raise ImportError("relative importpath too deep")
+ pname = ".".join(pname.split(".")[:-level])
+ parent = self.modules[pname]
+ self.msgout(4, "determine_parent ->", parent)
+ return parent
+ if caller.__path__:
+ parent = self.modules[pname]
+ assert caller is parent
+ self.msgout(4, "determine_parent ->", parent)
+ return parent
+ if '.' in pname:
+ i = pname.rfind('.')
+ pname = pname[:i]
+ parent = self.modules[pname]
+ assert parent.__name__ == pname
+ self.msgout(4, "determine_parent ->", parent)
+ return parent
+ self.msgout(4, "determine_parent -> None")
+ return None
+
+ def find_head_package(self, parent, name):
+ self.msgin(4, "find_head_package", parent, name)
+ if '.' in name:
+ i = name.find('.')
+ head = name[:i]
+ tail = name[i+1:]
+ else:
+ head = name
+ tail = ""
+ if parent:
+ qname = "%s.%s" % (parent.__name__, head)
+ else:
+ qname = head
+ q = self.import_module(head, qname, parent)
+ if q:
+ self.msgout(4, "find_head_package ->", (q, tail))
+ return q, tail
+ if parent:
+ qname = head
+ parent = None
+ q = self.import_module(head, qname, parent)
+ if q:
+ self.msgout(4, "find_head_package ->", (q, tail))
+ return q, tail
+ self.msgout(4, "raise ImportError: No module named", qname)
+ raise ImportError("No module named " + qname)
+
+ def load_tail(self, q, tail):
+ self.msgin(4, "load_tail", q, tail)
+ m = q
+ while tail:
+ i = tail.find('.')
+ if i < 0: i = len(tail)
+ head, tail = tail[:i], tail[i+1:]
+ mname = "%s.%s" % (m.__name__, head)
+ m = self.import_module(head, mname, m)
+ if not m:
+ self.msgout(4, "raise ImportError: No module named", mname)
+ raise ImportError("No module named " + mname)
+ self.msgout(4, "load_tail ->", m)
+ return m
+
+ def ensure_fromlist(self, m, fromlist, recursive=0):
+ self.msg(4, "ensure_fromlist", m, fromlist, recursive)
+ for sub in fromlist:
+ if sub == "*":
+ if not recursive:
+ all = self.find_all_submodules(m)
+ if all:
+ self.ensure_fromlist(m, all, 1)
+ elif not hasattr(m, sub):
+ subname = "%s.%s" % (m.__name__, sub)
+ submod = self.import_module(sub, subname, m)
+ if not submod:
+ raise ImportError("No module named " + subname)
+
+ def find_all_submodules(self, m):
+ if not m.__path__:
+ return
+ modules = {}
+ # 'suffixes' used to be a list hardcoded to [".py", ".pyc"].
+ # But we must also collect Python extension modules - although
+ # we cannot separate normal dlls from Python extensions.
+ suffixes = []
+ suffixes += importlib.machinery.EXTENSION_SUFFIXES[:]
+ suffixes += importlib.machinery.SOURCE_SUFFIXES[:]
+ suffixes += importlib.machinery.BYTECODE_SUFFIXES[:]
+ for dir in m.__path__:
+ try:
+ names = os.listdir(dir)
+ except OSError:
+ self.msg(2, "can't list directory", dir)
+ continue
+ for name in names:
+ mod = None
+ for suff in suffixes:
+ n = len(suff)
+ if name[-n:] == suff:
+ mod = name[:-n]
+ break
+ if mod and mod != "__init__":
+ modules[mod] = mod
+ return modules.keys()
+
+ def import_module(self, partname, fqname, parent):
+ self.msgin(3, "import_module", partname, fqname, parent)
+ try:
+ m = self.modules[fqname]
+ except KeyError:
+ pass
+ else:
+ self.msgout(3, "import_module ->", m)
+ return m
+ if fqname in self.badmodules:
+ self.msgout(3, "import_module -> None")
+ return None
+ if parent and parent.__path__ is None:
+ self.msgout(3, "import_module -> None")
+ return None
+ try:
+ fp, pathname, stuff = self.find_module(partname,
+ parent and parent.__path__, parent)
+ except ImportError:
+ self.msgout(3, "import_module ->", None)
+ return None
+
+ try:
+ m = self.load_module(fqname, fp, pathname, stuff)
+ finally:
+ if fp:
+ fp.close()
+ if parent:
+ setattr(parent, partname, m)
+ self.msgout(3, "import_module ->", m)
+ return m
+
+ def load_module(self, fqname, fp, pathname, file_info):
+ suffix, mode, type = file_info
+ self.msgin(2, "load_module", fqname, fp and "fp", pathname)
+ if type == _PKG_DIRECTORY:
+ m = self.load_package(fqname, pathname)
+ self.msgout(2, "load_module ->", m)
+ return m
+ if type == _PY_SOURCE:
+ co = compile(fp.read(), pathname, 'exec')
+ elif type == _PY_COMPILED:
+ try:
+ data = fp.read()
+ importlib._bootstrap_external._classify_pyc(data, fqname, {})
+ except ImportError as exc:
+ self.msgout(2, "raise ImportError: " + str(exc), pathname)
+ raise
+ co = marshal.loads(memoryview(data)[16:])
+ else:
+ co = None
+ m = self.add_module(fqname)
+ m.__file__ = pathname
+ if co:
+ if self.replace_paths:
+ co = self.replace_paths_in_code(co)
+ m.__code__ = co
+ self.scan_code(co, m)
+ self.msgout(2, "load_module ->", m)
+ return m
+
+ def _add_badmodule(self, name, caller):
+ if name not in self.badmodules:
+ self.badmodules[name] = {}
+ if caller:
+ self.badmodules[name][caller.__name__] = 1
+ else:
+ self.badmodules[name]["-"] = 1
+
+ def _safe_import_hook(self, name, caller, fromlist, level=-1):
+ # wrapper for self.import_hook() that won't raise ImportError
+ if name in self.badmodules:
+ self._add_badmodule(name, caller)
+ return
+ try:
+ self.import_hook(name, caller, level=level)
+ except ImportError as msg:
+ self.msg(2, "ImportError:", str(msg))
+ self._add_badmodule(name, caller)
+ except SyntaxError as msg:
+ self.msg(2, "SyntaxError:", str(msg))
+ self._add_badmodule(name, caller)
+ else:
+ if fromlist:
+ for sub in fromlist:
+ fullname = name + "." + sub
+ if fullname in self.badmodules:
+ self._add_badmodule(fullname, caller)
+ continue
+ try:
+ self.import_hook(name, caller, [sub], level=level)
+ except ImportError as msg:
+ self.msg(2, "ImportError:", str(msg))
+ self._add_badmodule(fullname, caller)
+
+ def scan_opcodes(self, co):
+ # Scan the code, and yield 'interesting' opcode combinations
+ code = co.co_code
+ names = co.co_names
+ consts = co.co_consts
+ opargs = [(op, arg) for _, op, arg in dis._unpack_opargs(code)
+ if op != EXTENDED_ARG]
+ for i, (op, oparg) in enumerate(opargs):
+ if op in STORE_OPS:
+ yield "store", (names[oparg],)
+ continue
+ if (op == IMPORT_NAME and i >= 2
+ and opargs[i-1][0] == opargs[i-2][0] == LOAD_CONST):
+ level = consts[opargs[i-2][1]]
+ fromlist = consts[opargs[i-1][1]]
+ if level == 0: # absolute import
+ yield "absolute_import", (fromlist, names[oparg])
+ else: # relative import
+ yield "relative_import", (level, fromlist, names[oparg])
+ continue
+
+ def scan_code(self, co, m):
+ code = co.co_code
+ scanner = self.scan_opcodes
+ for what, args in scanner(co):
+ if what == "store":
+ name, = args
+ m.globalnames[name] = 1
+ elif what == "absolute_import":
+ fromlist, name = args
+ have_star = 0
+ if fromlist is not None:
+ if "*" in fromlist:
+ have_star = 1
+ fromlist = [f for f in fromlist if f != "*"]
+ self._safe_import_hook(name, m, fromlist, level=0)
+ if have_star:
+ # We've encountered an "import *". If it is a Python module,
+ # the code has already been parsed and we can suck out the
+ # global names.
+ mm = None
+ if m.__path__:
+ # At this point we don't know whether 'name' is a
+ # submodule of 'm' or a global module. Let's just try
+ # the full name first.
+ mm = self.modules.get(m.__name__ + "." + name)
+ if mm is None:
+ mm = self.modules.get(name)
+ if mm is not None:
+ m.globalnames.update(mm.globalnames)
+ m.starimports.update(mm.starimports)
+ if mm.__code__ is None:
+ m.starimports[name] = 1
+ else:
+ m.starimports[name] = 1
+ elif what == "relative_import":
+ level, fromlist, name = args
+ if name:
+ self._safe_import_hook(name, m, fromlist, level=level)
+ else:
+ parent = self.determine_parent(m, level=level)
+ self._safe_import_hook(parent.__name__, None, fromlist, level=0)
+ else:
+ # We don't expect anything else from the generator.
+ raise RuntimeError(what)
+
+ for c in co.co_consts:
+ if isinstance(c, type(co)):
+ self.scan_code(c, m)
+
+ def load_package(self, fqname, pathname):
+ self.msgin(2, "load_package", fqname, pathname)
+ newname = replacePackageMap.get(fqname)
+ if newname:
+ fqname = newname
+ m = self.add_module(fqname)
+ m.__file__ = pathname
+ m.__path__ = [pathname]
+
+ # As per comment at top of file, simulate runtime __path__ additions.
+ m.__path__ = m.__path__ + packagePathMap.get(fqname, [])
+
+ fp, buf, stuff = self.find_module("__init__", m.__path__)
+ try:
+ self.load_module(fqname, fp, buf, stuff)
+ self.msgout(2, "load_package ->", m)
+ return m
+ finally:
+ if fp:
+ fp.close()
+
+ def add_module(self, fqname):
+ if fqname in self.modules:
+ return self.modules[fqname]
+ self.modules[fqname] = m = Module(fqname)
+ return m
+
+ def find_module(self, name, path, parent=None):
+ if parent is not None:
+ # assert path is not None
+ fullname = parent.__name__+'.'+name
+ else:
+ fullname = name
+ if fullname in self.excludes:
+ self.msgout(3, "find_module -> Excluded", fullname)
+ raise ImportError(name)
+
+ if path is None:
+ if name in sys.builtin_module_names:
+ return (None, None, ("", "", _C_BUILTIN))
+
+ path = self.path
+
+ return _find_module(name, path)
+
+ def report(self):
+ """Print a report to stdout, listing the found modules with their
+ paths, as well as modules that are missing, or seem to be missing.
+ """
+ print()
+ print(" %-25s %s" % ("Name", "File"))
+ print(" %-25s %s" % ("----", "----"))
+ # Print modules found
+ keys = sorted(self.modules.keys())
+ for key in keys:
+ m = self.modules[key]
+ if m.__path__:
+ print("P", end=' ')
+ else:
+ print("m", end=' ')
+ print("%-25s" % key, m.__file__ or "")
+
+ # Print missing modules
+ missing, maybe = self.any_missing_maybe()
+ if missing:
+ print()
+ print("Missing modules:")
+ for name in missing:
+ mods = sorted(self.badmodules[name].keys())
+ print("?", name, "imported from", ', '.join(mods))
+ # Print modules that may be missing, but then again, maybe not...
+ if maybe:
+ print()
+ print("Submodules that appear to be missing, but could also be", end=' ')
+ print("global names in the parent package:")
+ for name in maybe:
+ mods = sorted(self.badmodules[name].keys())
+ print("?", name, "imported from", ', '.join(mods))
+
+ def any_missing(self):
+ """Return a list of modules that appear to be missing. Use
+ any_missing_maybe() if you want to know which modules are
+ certain to be missing, and which *may* be missing.
+ """
+ missing, maybe = self.any_missing_maybe()
+ return missing + maybe
+
+ def any_missing_maybe(self):
+ """Return two lists, one with modules that are certainly missing
+ and one with modules that *may* be missing. The latter names could
+ either be submodules *or* just global names in the package.
+
+ The reason it can't always be determined is that it's impossible to
+ tell which names are imported when "from module import *" is done
+ with an extension module, short of actually importing it.
+ """
+ missing = []
+ maybe = []
+ for name in self.badmodules:
+ if name in self.excludes:
+ continue
+ i = name.rfind(".")
+ if i < 0:
+ missing.append(name)
+ continue
+ subname = name[i+1:]
+ pkgname = name[:i]
+ pkg = self.modules.get(pkgname)
+ if pkg is not None:
+ if pkgname in self.badmodules[name]:
+ # The package tried to import this module itself and
+ # failed. It's definitely missing.
+ missing.append(name)
+ elif subname in pkg.globalnames:
+ # It's a global in the package: definitely not missing.
+ pass
+ elif pkg.starimports:
+ # It could be missing, but the package did an "import *"
+ # from a non-Python module, so we simply can't be sure.
+ maybe.append(name)
+ else:
+ # It's not a global in the package, the package didn't
+ # do funny star imports, it's very likely to be missing.
+ # The symbol could be inserted into the package from the
+ # outside, but since that's not good style we simply list
+ # it missing.
+ missing.append(name)
+ else:
+ missing.append(name)
+ missing.sort()
+ maybe.sort()
+ return missing, maybe
+
+ def replace_paths_in_code(self, co):
+ new_filename = original_filename = os.path.normpath(co.co_filename)
+ for f, r in self.replace_paths:
+ if original_filename.startswith(f):
+ new_filename = r + original_filename[len(f):]
+ break
+
+ if self.debug and original_filename not in self.processed_paths:
+ if new_filename != original_filename:
+ self.msgout(2, "co_filename %r changed to %r" \
+ % (original_filename,new_filename,))
+ else:
+ self.msgout(2, "co_filename %r remains unchanged" \
+ % (original_filename,))
+ self.processed_paths.append(original_filename)
+
+ consts = list(co.co_consts)
+ for i in range(len(consts)):
+ if isinstance(consts[i], type(co)):
+ consts[i] = self.replace_paths_in_code(consts[i])
+
+ return co.replace(co_consts=tuple(consts), co_filename=new_filename)
+
+
+def test():
+ # Parse command line
+ import getopt
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "dmp:qx:")
+ except getopt.error as msg:
+ print(msg)
+ return
+
+ # Process options
+ debug = 1
+ domods = 0
+ addpath = []
+ exclude = []
+ for o, a in opts:
+ if o == '-d':
+ debug = debug + 1
+ if o == '-m':
+ domods = 1
+ if o == '-p':
+ addpath = addpath + a.split(os.pathsep)
+ if o == '-q':
+ debug = 0
+ if o == '-x':
+ exclude.append(a)
+
+ # Provide default arguments
+ if not args:
+ script = "hello.py"
+ else:
+ script = args[0]
+
+ # Set the path based on sys.path and the script directory
+ path = sys.path[:]
+ path[0] = os.path.dirname(script)
+ path = addpath + path
+ if debug > 1:
+ print("path:")
+ for item in path:
+ print(" ", repr(item))
+
+ # Create the module finder and turn its crank
+ mf = ModuleFinder(path, debug, exclude)
+ for arg in args[1:]:
+ if arg == '-m':
+ domods = 1
+ continue
+ if domods:
+ if arg[-2:] == '.*':
+ mf.import_hook(arg[:-2], None, ["*"])
+ else:
+ mf.import_hook(arg)
+ else:
+ mf.load_file(arg)
+ mf.run_script(script)
+ mf.report()
+ return mf # for -i debugging
+
+
+if __name__ == '__main__':
+ try:
+ mf = test()
+ except KeyboardInterrupt:
+ print("\n[interrupted]")
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/netrc.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/netrc.py
new file mode 100644
index 0000000000000000000000000000000000000000..f0ae48cfed9e67e8192b82fc66c0755a8cfdb270
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/netrc.py
@@ -0,0 +1,139 @@
+"""An object-oriented interface to .netrc files."""
+
+# Module and documentation by Eric S. Raymond, 21 Dec 1998
+
+import os, shlex, stat
+
+__all__ = ["netrc", "NetrcParseError"]
+
+
+class NetrcParseError(Exception):
+ """Exception raised on syntax errors in the .netrc file."""
+ def __init__(self, msg, filename=None, lineno=None):
+ self.filename = filename
+ self.lineno = lineno
+ self.msg = msg
+ Exception.__init__(self, msg)
+
+ def __str__(self):
+ return "%s (%s, line %s)" % (self.msg, self.filename, self.lineno)
+
+
+class netrc:
+ def __init__(self, file=None):
+ default_netrc = file is None
+ if file is None:
+ file = os.path.join(os.path.expanduser("~"), ".netrc")
+ self.hosts = {}
+ self.macros = {}
+ with open(file) as fp:
+ self._parse(file, fp, default_netrc)
+
+ def _parse(self, file, fp, default_netrc):
+ lexer = shlex.shlex(fp)
+ lexer.wordchars += r"""!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~"""
+ lexer.commenters = lexer.commenters.replace('#', '')
+ while 1:
+ # Look for a machine, default, or macdef top-level keyword
+ saved_lineno = lexer.lineno
+ toplevel = tt = lexer.get_token()
+ if not tt:
+ break
+ elif tt[0] == '#':
+ if lexer.lineno == saved_lineno and len(tt) == 1:
+ lexer.instream.readline()
+ continue
+ elif tt == 'machine':
+ entryname = lexer.get_token()
+ elif tt == 'default':
+ entryname = 'default'
+ elif tt == 'macdef': # Just skip to end of macdefs
+ entryname = lexer.get_token()
+ self.macros[entryname] = []
+ lexer.whitespace = ' \t'
+ while 1:
+ line = lexer.instream.readline()
+ if not line or line == '\012':
+ lexer.whitespace = ' \t\r\n'
+ break
+ self.macros[entryname].append(line)
+ continue
+ else:
+ raise NetrcParseError(
+ "bad toplevel token %r" % tt, file, lexer.lineno)
+
+ # We're looking at start of an entry for a named machine or default.
+ login = ''
+ account = password = None
+ self.hosts[entryname] = {}
+ while 1:
+ tt = lexer.get_token()
+ if (tt.startswith('#') or
+ tt in {'', 'machine', 'default', 'macdef'}):
+ if password:
+ self.hosts[entryname] = (login, account, password)
+ lexer.push_token(tt)
+ break
+ else:
+ raise NetrcParseError(
+ "malformed %s entry %s terminated by %s"
+ % (toplevel, entryname, repr(tt)),
+ file, lexer.lineno)
+ elif tt == 'login' or tt == 'user':
+ login = lexer.get_token()
+ elif tt == 'account':
+ account = lexer.get_token()
+ elif tt == 'password':
+ if os.name == 'posix' and default_netrc:
+ prop = os.fstat(fp.fileno())
+ if prop.st_uid != os.getuid():
+ import pwd
+ try:
+ fowner = pwd.getpwuid(prop.st_uid)[0]
+ except KeyError:
+ fowner = 'uid %s' % prop.st_uid
+ try:
+ user = pwd.getpwuid(os.getuid())[0]
+ except KeyError:
+ user = 'uid %s' % os.getuid()
+ raise NetrcParseError(
+ ("~/.netrc file owner (%s) does not match"
+ " current user (%s)") % (fowner, user),
+ file, lexer.lineno)
+ if (prop.st_mode & (stat.S_IRWXG | stat.S_IRWXO)):
+ raise NetrcParseError(
+ "~/.netrc access too permissive: access"
+ " permissions must restrict access to only"
+ " the owner", file, lexer.lineno)
+ password = lexer.get_token()
+ else:
+ raise NetrcParseError("bad follower token %r" % tt,
+ file, lexer.lineno)
+
+ def authenticators(self, host):
+ """Return a (user, account, password) tuple for given host."""
+ if host in self.hosts:
+ return self.hosts[host]
+ elif 'default' in self.hosts:
+ return self.hosts['default']
+ else:
+ return None
+
+ def __repr__(self):
+ """Dump the class data in the format of a .netrc file."""
+ rep = ""
+ for host in self.hosts.keys():
+ attrs = self.hosts[host]
+ rep += f"machine {host}\n\tlogin {attrs[0]}\n"
+ if attrs[1]:
+ rep += f"\taccount {attrs[1]}\n"
+ rep += f"\tpassword {attrs[2]}\n"
+ for macro in self.macros.keys():
+ rep += f"macdef {macro}\n"
+ for line in self.macros[macro]:
+ rep += line
+ rep += "\n"
+ return rep
+
+if __name__ == '__main__':
+ print(netrc())
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/nntplib.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/nntplib.py
new file mode 100644
index 0000000000000000000000000000000000000000..9036f361b5fb6b9e631b713016f1d341baed8a7b
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/nntplib.py
@@ -0,0 +1,1151 @@
+"""An NNTP client class based on:
+- RFC 977: Network News Transfer Protocol
+- RFC 2980: Common NNTP Extensions
+- RFC 3977: Network News Transfer Protocol (version 2)
+
+Example:
+
+>>> from nntplib import NNTP
+>>> s = NNTP('news')
+>>> resp, count, first, last, name = s.group('comp.lang.python')
+>>> print('Group', name, 'has', count, 'articles, range', first, 'to', last)
+Group comp.lang.python has 51 articles, range 5770 to 5821
+>>> resp, subs = s.xhdr('subject', '{0}-{1}'.format(first, last))
+>>> resp = s.quit()
+>>>
+
+Here 'resp' is the server response line.
+Error responses are turned into exceptions.
+
+To post an article from a file:
+>>> f = open(filename, 'rb') # file containing article, including header
+>>> resp = s.post(f)
+>>>
+
+For descriptions of all methods, read the comments in the code below.
+Note that all arguments and return values representing article numbers
+are strings, not numbers, since they are rarely used for calculations.
+"""
+
+# RFC 977 by Brian Kantor and Phil Lapsley.
+# xover, xgtitle, xpath, date methods by Kevan Heydon
+
+# Incompatible changes from the 2.x nntplib:
+# - all commands are encoded as UTF-8 data (using the "surrogateescape"
+# error handler), except for raw message data (POST, IHAVE)
+# - all responses are decoded as UTF-8 data (using the "surrogateescape"
+# error handler), except for raw message data (ARTICLE, HEAD, BODY)
+# - the `file` argument to various methods is keyword-only
+#
+# - NNTP.date() returns a datetime object
+# - NNTP.newgroups() and NNTP.newnews() take a datetime (or date) object,
+# rather than a pair of (date, time) strings.
+# - NNTP.newgroups() and NNTP.list() return a list of GroupInfo named tuples
+# - NNTP.descriptions() returns a dict mapping group names to descriptions
+# - NNTP.xover() returns a list of dicts mapping field names (header or metadata)
+# to field values; each dict representing a message overview.
+# - NNTP.article(), NNTP.head() and NNTP.body() return a (response, ArticleInfo)
+# tuple.
+# - the "internal" methods have been marked private (they now start with
+# an underscore)
+
+# Other changes from the 2.x/3.1 nntplib:
+# - automatic querying of capabilities at connect
+# - New method NNTP.getcapabilities()
+# - New method NNTP.over()
+# - New helper function decode_header()
+# - NNTP.post() and NNTP.ihave() accept file objects, bytes-like objects and
+# arbitrary iterables yielding lines.
+# - An extensive test suite :-)
+
+# TODO:
+# - return structured data (GroupInfo etc.) everywhere
+# - support HDR
+
+# Imports
+import re
+import socket
+import collections
+import datetime
+import warnings
+import sys
+
+try:
+ import ssl
+except ImportError:
+ _have_ssl = False
+else:
+ _have_ssl = True
+
+from email.header import decode_header as _email_decode_header
+from socket import _GLOBAL_DEFAULT_TIMEOUT
+
+__all__ = ["NNTP",
+ "NNTPError", "NNTPReplyError", "NNTPTemporaryError",
+ "NNTPPermanentError", "NNTPProtocolError", "NNTPDataError",
+ "decode_header",
+ ]
+
+# maximal line length when calling readline(). This is to prevent
+# reading arbitrary length lines. RFC 3977 limits NNTP line length to
+# 512 characters, including CRLF. We have selected 2048 just to be on
+# the safe side.
+_MAXLINE = 2048
+
+
+# Exceptions raised when an error or invalid response is received
+class NNTPError(Exception):
+ """Base class for all nntplib exceptions"""
+ def __init__(self, *args):
+ Exception.__init__(self, *args)
+ try:
+ self.response = args[0]
+ except IndexError:
+ self.response = 'No response given'
+
+class NNTPReplyError(NNTPError):
+ """Unexpected [123]xx reply"""
+ pass
+
+class NNTPTemporaryError(NNTPError):
+ """4xx errors"""
+ pass
+
+class NNTPPermanentError(NNTPError):
+ """5xx errors"""
+ pass
+
+class NNTPProtocolError(NNTPError):
+ """Response does not begin with [1-5]"""
+ pass
+
+class NNTPDataError(NNTPError):
+ """Error in response data"""
+ pass
+
+
+# Standard port used by NNTP servers
+NNTP_PORT = 119
+NNTP_SSL_PORT = 563
+
+# Response numbers that are followed by additional text (e.g. article)
+_LONGRESP = {
+ '100', # HELP
+ '101', # CAPABILITIES
+ '211', # LISTGROUP (also not multi-line with GROUP)
+ '215', # LIST
+ '220', # ARTICLE
+ '221', # HEAD, XHDR
+ '222', # BODY
+ '224', # OVER, XOVER
+ '225', # HDR
+ '230', # NEWNEWS
+ '231', # NEWGROUPS
+ '282', # XGTITLE
+}
+
+# Default decoded value for LIST OVERVIEW.FMT if not supported
+_DEFAULT_OVERVIEW_FMT = [
+ "subject", "from", "date", "message-id", "references", ":bytes", ":lines"]
+
+# Alternative names allowed in LIST OVERVIEW.FMT response
+_OVERVIEW_FMT_ALTERNATIVES = {
+ 'bytes': ':bytes',
+ 'lines': ':lines',
+}
+
+# Line terminators (we always output CRLF, but accept any of CRLF, CR, LF)
+_CRLF = b'\r\n'
+
+GroupInfo = collections.namedtuple('GroupInfo',
+ ['group', 'last', 'first', 'flag'])
+
+ArticleInfo = collections.namedtuple('ArticleInfo',
+ ['number', 'message_id', 'lines'])
+
+
+# Helper function(s)
+def decode_header(header_str):
+ """Takes a unicode string representing a munged header value
+ and decodes it as a (possibly non-ASCII) readable value."""
+ parts = []
+ for v, enc in _email_decode_header(header_str):
+ if isinstance(v, bytes):
+ parts.append(v.decode(enc or 'ascii'))
+ else:
+ parts.append(v)
+ return ''.join(parts)
+
+def _parse_overview_fmt(lines):
+ """Parse a list of string representing the response to LIST OVERVIEW.FMT
+ and return a list of header/metadata names.
+ Raises NNTPDataError if the response is not compliant
+ (cf. RFC 3977, section 8.4)."""
+ fmt = []
+ for line in lines:
+ if line[0] == ':':
+ # Metadata name (e.g. ":bytes")
+ name, _, suffix = line[1:].partition(':')
+ name = ':' + name
+ else:
+ # Header name (e.g. "Subject:" or "Xref:full")
+ name, _, suffix = line.partition(':')
+ name = name.lower()
+ name = _OVERVIEW_FMT_ALTERNATIVES.get(name, name)
+ # Should we do something with the suffix?
+ fmt.append(name)
+ defaults = _DEFAULT_OVERVIEW_FMT
+ if len(fmt) < len(defaults):
+ raise NNTPDataError("LIST OVERVIEW.FMT response too short")
+ if fmt[:len(defaults)] != defaults:
+ raise NNTPDataError("LIST OVERVIEW.FMT redefines default fields")
+ return fmt
+
+def _parse_overview(lines, fmt, data_process_func=None):
+ """Parse the response to an OVER or XOVER command according to the
+ overview format `fmt`."""
+ n_defaults = len(_DEFAULT_OVERVIEW_FMT)
+ overview = []
+ for line in lines:
+ fields = {}
+ article_number, *tokens = line.split('\t')
+ article_number = int(article_number)
+ for i, token in enumerate(tokens):
+ if i >= len(fmt):
+ # XXX should we raise an error? Some servers might not
+ # support LIST OVERVIEW.FMT and still return additional
+ # headers.
+ continue
+ field_name = fmt[i]
+ is_metadata = field_name.startswith(':')
+ if i >= n_defaults and not is_metadata:
+ # Non-default header names are included in full in the response
+ # (unless the field is totally empty)
+ h = field_name + ": "
+ if token and token[:len(h)].lower() != h:
+ raise NNTPDataError("OVER/XOVER response doesn't include "
+ "names of additional headers")
+ token = token[len(h):] if token else None
+ fields[fmt[i]] = token
+ overview.append((article_number, fields))
+ return overview
+
+def _parse_datetime(date_str, time_str=None):
+ """Parse a pair of (date, time) strings, and return a datetime object.
+ If only the date is given, it is assumed to be date and time
+ concatenated together (e.g. response to the DATE command).
+ """
+ if time_str is None:
+ time_str = date_str[-6:]
+ date_str = date_str[:-6]
+ hours = int(time_str[:2])
+ minutes = int(time_str[2:4])
+ seconds = int(time_str[4:])
+ year = int(date_str[:-4])
+ month = int(date_str[-4:-2])
+ day = int(date_str[-2:])
+ # RFC 3977 doesn't say how to interpret 2-char years. Assume that
+ # there are no dates before 1970 on Usenet.
+ if year < 70:
+ year += 2000
+ elif year < 100:
+ year += 1900
+ return datetime.datetime(year, month, day, hours, minutes, seconds)
+
+def _unparse_datetime(dt, legacy=False):
+ """Format a date or datetime object as a pair of (date, time) strings
+ in the format required by the NEWNEWS and NEWGROUPS commands. If a
+ date object is passed, the time is assumed to be midnight (00h00).
+
+ The returned representation depends on the legacy flag:
+ * if legacy is False (the default):
+ date has the YYYYMMDD format and time the HHMMSS format
+ * if legacy is True:
+ date has the YYMMDD format and time the HHMMSS format.
+ RFC 3977 compliant servers should understand both formats; therefore,
+ legacy is only needed when talking to old servers.
+ """
+ if not isinstance(dt, datetime.datetime):
+ time_str = "000000"
+ else:
+ time_str = "{0.hour:02d}{0.minute:02d}{0.second:02d}".format(dt)
+ y = dt.year
+ if legacy:
+ y = y % 100
+ date_str = "{0:02d}{1.month:02d}{1.day:02d}".format(y, dt)
+ else:
+ date_str = "{0:04d}{1.month:02d}{1.day:02d}".format(y, dt)
+ return date_str, time_str
+
+
+if _have_ssl:
+
+ def _encrypt_on(sock, context, hostname):
+ """Wrap a socket in SSL/TLS. Arguments:
+ - sock: Socket to wrap
+ - context: SSL context to use for the encrypted connection
+ Returns:
+ - sock: New, encrypted socket.
+ """
+ # Generate a default SSL context if none was passed.
+ if context is None:
+ context = ssl._create_stdlib_context()
+ return context.wrap_socket(sock, server_hostname=hostname)
+
+
+# The classes themselves
+class _NNTPBase:
+ # UTF-8 is the character set for all NNTP commands and responses: they
+ # are automatically encoded (when sending) and decoded (and receiving)
+ # by this class.
+ # However, some multi-line data blocks can contain arbitrary bytes (for
+ # example, latin-1 or utf-16 data in the body of a message). Commands
+ # taking (POST, IHAVE) or returning (HEAD, BODY, ARTICLE) raw message
+ # data will therefore only accept and produce bytes objects.
+ # Furthermore, since there could be non-compliant servers out there,
+ # we use 'surrogateescape' as the error handler for fault tolerance
+ # and easy round-tripping. This could be useful for some applications
+ # (e.g. NNTP gateways).
+
+ encoding = 'utf-8'
+ errors = 'surrogateescape'
+
+ def __init__(self, file, host,
+ readermode=None, timeout=_GLOBAL_DEFAULT_TIMEOUT):
+ """Initialize an instance. Arguments:
+ - file: file-like object (open for read/write in binary mode)
+ - host: hostname of the server
+ - readermode: if true, send 'mode reader' command after
+ connecting.
+ - timeout: timeout (in seconds) used for socket connections
+
+ readermode is sometimes necessary if you are connecting to an
+ NNTP server on the local machine and intend to call
+ reader-specific commands, such as `group'. If you get
+ unexpected NNTPPermanentErrors, you might need to set
+ readermode.
+ """
+ self.host = host
+ self.file = file
+ self.debugging = 0
+ self.welcome = self._getresp()
+
+ # Inquire about capabilities (RFC 3977).
+ self._caps = None
+ self.getcapabilities()
+
+ # 'MODE READER' is sometimes necessary to enable 'reader' mode.
+ # However, the order in which 'MODE READER' and 'AUTHINFO' need to
+ # arrive differs between some NNTP servers. If _setreadermode() fails
+ # with an authorization failed error, it will set this to True;
+ # the login() routine will interpret that as a request to try again
+ # after performing its normal function.
+ # Enable only if we're not already in READER mode anyway.
+ self.readermode_afterauth = False
+ if readermode and 'READER' not in self._caps:
+ self._setreadermode()
+ if not self.readermode_afterauth:
+ # Capabilities might have changed after MODE READER
+ self._caps = None
+ self.getcapabilities()
+
+ # RFC 4642 2.2.2: Both the client and the server MUST know if there is
+ # a TLS session active. A client MUST NOT attempt to start a TLS
+ # session if a TLS session is already active.
+ self.tls_on = False
+
+ # Log in and encryption setup order is left to subclasses.
+ self.authenticated = False
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args):
+ is_connected = lambda: hasattr(self, "file")
+ if is_connected():
+ try:
+ self.quit()
+ except (OSError, EOFError):
+ pass
+ finally:
+ if is_connected():
+ self._close()
+
+ def getwelcome(self):
+ """Get the welcome message from the server
+ (this is read and squirreled away by __init__()).
+ If the response code is 200, posting is allowed;
+ if it 201, posting is not allowed."""
+
+ if self.debugging: print('*welcome*', repr(self.welcome))
+ return self.welcome
+
+ def getcapabilities(self):
+ """Get the server capabilities, as read by __init__().
+ If the CAPABILITIES command is not supported, an empty dict is
+ returned."""
+ if self._caps is None:
+ self.nntp_version = 1
+ self.nntp_implementation = None
+ try:
+ resp, caps = self.capabilities()
+ except (NNTPPermanentError, NNTPTemporaryError):
+ # Server doesn't support capabilities
+ self._caps = {}
+ else:
+ self._caps = caps
+ if 'VERSION' in caps:
+ # The server can advertise several supported versions,
+ # choose the highest.
+ self.nntp_version = max(map(int, caps['VERSION']))
+ if 'IMPLEMENTATION' in caps:
+ self.nntp_implementation = ' '.join(caps['IMPLEMENTATION'])
+ return self._caps
+
+ def set_debuglevel(self, level):
+ """Set the debugging level. Argument 'level' means:
+ 0: no debugging output (default)
+ 1: print commands and responses but not body text etc.
+ 2: also print raw lines read and sent before stripping CR/LF"""
+
+ self.debugging = level
+ debug = set_debuglevel
+
+ def _putline(self, line):
+ """Internal: send one line to the server, appending CRLF.
+ The `line` must be a bytes-like object."""
+ sys.audit("nntplib.putline", self, line)
+ line = line + _CRLF
+ if self.debugging > 1: print('*put*', repr(line))
+ self.file.write(line)
+ self.file.flush()
+
+ def _putcmd(self, line):
+ """Internal: send one command to the server (through _putline()).
+ The `line` must be a unicode string."""
+ if self.debugging: print('*cmd*', repr(line))
+ line = line.encode(self.encoding, self.errors)
+ self._putline(line)
+
+ def _getline(self, strip_crlf=True):
+ """Internal: return one line from the server, stripping _CRLF.
+ Raise EOFError if the connection is closed.
+ Returns a bytes object."""
+ line = self.file.readline(_MAXLINE +1)
+ if len(line) > _MAXLINE:
+ raise NNTPDataError('line too long')
+ if self.debugging > 1:
+ print('*get*', repr(line))
+ if not line: raise EOFError
+ if strip_crlf:
+ if line[-2:] == _CRLF:
+ line = line[:-2]
+ elif line[-1:] in _CRLF:
+ line = line[:-1]
+ return line
+
+ def _getresp(self):
+ """Internal: get a response from the server.
+ Raise various errors if the response indicates an error.
+ Returns a unicode string."""
+ resp = self._getline()
+ if self.debugging: print('*resp*', repr(resp))
+ resp = resp.decode(self.encoding, self.errors)
+ c = resp[:1]
+ if c == '4':
+ raise NNTPTemporaryError(resp)
+ if c == '5':
+ raise NNTPPermanentError(resp)
+ if c not in '123':
+ raise NNTPProtocolError(resp)
+ return resp
+
+ def _getlongresp(self, file=None):
+ """Internal: get a response plus following text from the server.
+ Raise various errors if the response indicates an error.
+
+ Returns a (response, lines) tuple where `response` is a unicode
+ string and `lines` is a list of bytes objects.
+ If `file` is a file-like object, it must be open in binary mode.
+ """
+
+ openedFile = None
+ try:
+ # If a string was passed then open a file with that name
+ if isinstance(file, (str, bytes)):
+ openedFile = file = open(file, "wb")
+
+ resp = self._getresp()
+ if resp[:3] not in _LONGRESP:
+ raise NNTPReplyError(resp)
+
+ lines = []
+ if file is not None:
+ # XXX lines = None instead?
+ terminators = (b'.' + _CRLF, b'.\n')
+ while 1:
+ line = self._getline(False)
+ if line in terminators:
+ break
+ if line.startswith(b'..'):
+ line = line[1:]
+ file.write(line)
+ else:
+ terminator = b'.'
+ while 1:
+ line = self._getline()
+ if line == terminator:
+ break
+ if line.startswith(b'..'):
+ line = line[1:]
+ lines.append(line)
+ finally:
+ # If this method created the file, then it must close it
+ if openedFile:
+ openedFile.close()
+
+ return resp, lines
+
+ def _shortcmd(self, line):
+ """Internal: send a command and get the response.
+ Same return value as _getresp()."""
+ self._putcmd(line)
+ return self._getresp()
+
+ def _longcmd(self, line, file=None):
+ """Internal: send a command and get the response plus following text.
+ Same return value as _getlongresp()."""
+ self._putcmd(line)
+ return self._getlongresp(file)
+
+ def _longcmdstring(self, line, file=None):
+ """Internal: send a command and get the response plus following text.
+ Same as _longcmd() and _getlongresp(), except that the returned `lines`
+ are unicode strings rather than bytes objects.
+ """
+ self._putcmd(line)
+ resp, list = self._getlongresp(file)
+ return resp, [line.decode(self.encoding, self.errors)
+ for line in list]
+
+ def _getoverviewfmt(self):
+ """Internal: get the overview format. Queries the server if not
+ already done, else returns the cached value."""
+ try:
+ return self._cachedoverviewfmt
+ except AttributeError:
+ pass
+ try:
+ resp, lines = self._longcmdstring("LIST OVERVIEW.FMT")
+ except NNTPPermanentError:
+ # Not supported by server?
+ fmt = _DEFAULT_OVERVIEW_FMT[:]
+ else:
+ fmt = _parse_overview_fmt(lines)
+ self._cachedoverviewfmt = fmt
+ return fmt
+
+ def _grouplist(self, lines):
+ # Parse lines into "group last first flag"
+ return [GroupInfo(*line.split()) for line in lines]
+
+ def capabilities(self):
+ """Process a CAPABILITIES command. Not supported by all servers.
+ Return:
+ - resp: server response if successful
+ - caps: a dictionary mapping capability names to lists of tokens
+ (for example {'VERSION': ['2'], 'OVER': [], LIST: ['ACTIVE', 'HEADERS'] })
+ """
+ caps = {}
+ resp, lines = self._longcmdstring("CAPABILITIES")
+ for line in lines:
+ name, *tokens = line.split()
+ caps[name] = tokens
+ return resp, caps
+
+ def newgroups(self, date, *, file=None):
+ """Process a NEWGROUPS command. Arguments:
+ - date: a date or datetime object
+ Return:
+ - resp: server response if successful
+ - list: list of newsgroup names
+ """
+ if not isinstance(date, (datetime.date, datetime.date)):
+ raise TypeError(
+ "the date parameter must be a date or datetime object, "
+ "not '{:40}'".format(date.__class__.__name__))
+ date_str, time_str = _unparse_datetime(date, self.nntp_version < 2)
+ cmd = 'NEWGROUPS {0} {1}'.format(date_str, time_str)
+ resp, lines = self._longcmdstring(cmd, file)
+ return resp, self._grouplist(lines)
+
+ def newnews(self, group, date, *, file=None):
+ """Process a NEWNEWS command. Arguments:
+ - group: group name or '*'
+ - date: a date or datetime object
+ Return:
+ - resp: server response if successful
+ - list: list of message ids
+ """
+ if not isinstance(date, (datetime.date, datetime.date)):
+ raise TypeError(
+ "the date parameter must be a date or datetime object, "
+ "not '{:40}'".format(date.__class__.__name__))
+ date_str, time_str = _unparse_datetime(date, self.nntp_version < 2)
+ cmd = 'NEWNEWS {0} {1} {2}'.format(group, date_str, time_str)
+ return self._longcmdstring(cmd, file)
+
+ def list(self, group_pattern=None, *, file=None):
+ """Process a LIST or LIST ACTIVE command. Arguments:
+ - group_pattern: a pattern indicating which groups to query
+ - file: Filename string or file object to store the result in
+ Returns:
+ - resp: server response if successful
+ - list: list of (group, last, first, flag) (strings)
+ """
+ if group_pattern is not None:
+ command = 'LIST ACTIVE ' + group_pattern
+ else:
+ command = 'LIST'
+ resp, lines = self._longcmdstring(command, file)
+ return resp, self._grouplist(lines)
+
+ def _getdescriptions(self, group_pattern, return_all):
+ line_pat = re.compile('^(?P[^ \t]+)[ \t]+(.*)$')
+ # Try the more std (acc. to RFC2980) LIST NEWSGROUPS first
+ resp, lines = self._longcmdstring('LIST NEWSGROUPS ' + group_pattern)
+ if not resp.startswith('215'):
+ # Now the deprecated XGTITLE. This either raises an error
+ # or succeeds with the same output structure as LIST
+ # NEWSGROUPS.
+ resp, lines = self._longcmdstring('XGTITLE ' + group_pattern)
+ groups = {}
+ for raw_line in lines:
+ match = line_pat.search(raw_line.strip())
+ if match:
+ name, desc = match.group(1, 2)
+ if not return_all:
+ return desc
+ groups[name] = desc
+ if return_all:
+ return resp, groups
+ else:
+ # Nothing found
+ return ''
+
+ def description(self, group):
+ """Get a description for a single group. If more than one
+ group matches ('group' is a pattern), return the first. If no
+ group matches, return an empty string.
+
+ This elides the response code from the server, since it can
+ only be '215' or '285' (for xgtitle) anyway. If the response
+ code is needed, use the 'descriptions' method.
+
+ NOTE: This neither checks for a wildcard in 'group' nor does
+ it check whether the group actually exists."""
+ return self._getdescriptions(group, False)
+
+ def descriptions(self, group_pattern):
+ """Get descriptions for a range of groups."""
+ return self._getdescriptions(group_pattern, True)
+
+ def group(self, name):
+ """Process a GROUP command. Argument:
+ - group: the group name
+ Returns:
+ - resp: server response if successful
+ - count: number of articles
+ - first: first article number
+ - last: last article number
+ - name: the group name
+ """
+ resp = self._shortcmd('GROUP ' + name)
+ if not resp.startswith('211'):
+ raise NNTPReplyError(resp)
+ words = resp.split()
+ count = first = last = 0
+ n = len(words)
+ if n > 1:
+ count = words[1]
+ if n > 2:
+ first = words[2]
+ if n > 3:
+ last = words[3]
+ if n > 4:
+ name = words[4].lower()
+ return resp, int(count), int(first), int(last), name
+
+ def help(self, *, file=None):
+ """Process a HELP command. Argument:
+ - file: Filename string or file object to store the result in
+ Returns:
+ - resp: server response if successful
+ - list: list of strings returned by the server in response to the
+ HELP command
+ """
+ return self._longcmdstring('HELP', file)
+
+ def _statparse(self, resp):
+ """Internal: parse the response line of a STAT, NEXT, LAST,
+ ARTICLE, HEAD or BODY command."""
+ if not resp.startswith('22'):
+ raise NNTPReplyError(resp)
+ words = resp.split()
+ art_num = int(words[1])
+ message_id = words[2]
+ return resp, art_num, message_id
+
+ def _statcmd(self, line):
+ """Internal: process a STAT, NEXT or LAST command."""
+ resp = self._shortcmd(line)
+ return self._statparse(resp)
+
+ def stat(self, message_spec=None):
+ """Process a STAT command. Argument:
+ - message_spec: article number or message id (if not specified,
+ the current article is selected)
+ Returns:
+ - resp: server response if successful
+ - art_num: the article number
+ - message_id: the message id
+ """
+ if message_spec:
+ return self._statcmd('STAT {0}'.format(message_spec))
+ else:
+ return self._statcmd('STAT')
+
+ def next(self):
+ """Process a NEXT command. No arguments. Return as for STAT."""
+ return self._statcmd('NEXT')
+
+ def last(self):
+ """Process a LAST command. No arguments. Return as for STAT."""
+ return self._statcmd('LAST')
+
+ def _artcmd(self, line, file=None):
+ """Internal: process a HEAD, BODY or ARTICLE command."""
+ resp, lines = self._longcmd(line, file)
+ resp, art_num, message_id = self._statparse(resp)
+ return resp, ArticleInfo(art_num, message_id, lines)
+
+ def head(self, message_spec=None, *, file=None):
+ """Process a HEAD command. Argument:
+ - message_spec: article number or message id
+ - file: filename string or file object to store the headers in
+ Returns:
+ - resp: server response if successful
+ - ArticleInfo: (article number, message id, list of header lines)
+ """
+ if message_spec is not None:
+ cmd = 'HEAD {0}'.format(message_spec)
+ else:
+ cmd = 'HEAD'
+ return self._artcmd(cmd, file)
+
+ def body(self, message_spec=None, *, file=None):
+ """Process a BODY command. Argument:
+ - message_spec: article number or message id
+ - file: filename string or file object to store the body in
+ Returns:
+ - resp: server response if successful
+ - ArticleInfo: (article number, message id, list of body lines)
+ """
+ if message_spec is not None:
+ cmd = 'BODY {0}'.format(message_spec)
+ else:
+ cmd = 'BODY'
+ return self._artcmd(cmd, file)
+
+ def article(self, message_spec=None, *, file=None):
+ """Process an ARTICLE command. Argument:
+ - message_spec: article number or message id
+ - file: filename string or file object to store the article in
+ Returns:
+ - resp: server response if successful
+ - ArticleInfo: (article number, message id, list of article lines)
+ """
+ if message_spec is not None:
+ cmd = 'ARTICLE {0}'.format(message_spec)
+ else:
+ cmd = 'ARTICLE'
+ return self._artcmd(cmd, file)
+
+ def slave(self):
+ """Process a SLAVE command. Returns:
+ - resp: server response if successful
+ """
+ return self._shortcmd('SLAVE')
+
+ def xhdr(self, hdr, str, *, file=None):
+ """Process an XHDR command (optional server extension). Arguments:
+ - hdr: the header type (e.g. 'subject')
+ - str: an article nr, a message id, or a range nr1-nr2
+ - file: Filename string or file object to store the result in
+ Returns:
+ - resp: server response if successful
+ - list: list of (nr, value) strings
+ """
+ pat = re.compile('^([0-9]+) ?(.*)\n?')
+ resp, lines = self._longcmdstring('XHDR {0} {1}'.format(hdr, str), file)
+ def remove_number(line):
+ m = pat.match(line)
+ return m.group(1, 2) if m else line
+ return resp, [remove_number(line) for line in lines]
+
+ def xover(self, start, end, *, file=None):
+ """Process an XOVER command (optional server extension) Arguments:
+ - start: start of range
+ - end: end of range
+ - file: Filename string or file object to store the result in
+ Returns:
+ - resp: server response if successful
+ - list: list of dicts containing the response fields
+ """
+ resp, lines = self._longcmdstring('XOVER {0}-{1}'.format(start, end),
+ file)
+ fmt = self._getoverviewfmt()
+ return resp, _parse_overview(lines, fmt)
+
+ def over(self, message_spec, *, file=None):
+ """Process an OVER command. If the command isn't supported, fall
+ back to XOVER. Arguments:
+ - message_spec:
+ - either a message id, indicating the article to fetch
+ information about
+ - or a (start, end) tuple, indicating a range of article numbers;
+ if end is None, information up to the newest message will be
+ retrieved
+ - or None, indicating the current article number must be used
+ - file: Filename string or file object to store the result in
+ Returns:
+ - resp: server response if successful
+ - list: list of dicts containing the response fields
+
+ NOTE: the "message id" form isn't supported by XOVER
+ """
+ cmd = 'OVER' if 'OVER' in self._caps else 'XOVER'
+ if isinstance(message_spec, (tuple, list)):
+ start, end = message_spec
+ cmd += ' {0}-{1}'.format(start, end or '')
+ elif message_spec is not None:
+ cmd = cmd + ' ' + message_spec
+ resp, lines = self._longcmdstring(cmd, file)
+ fmt = self._getoverviewfmt()
+ return resp, _parse_overview(lines, fmt)
+
+ def xgtitle(self, group, *, file=None):
+ """Process an XGTITLE command (optional server extension) Arguments:
+ - group: group name wildcard (i.e. news.*)
+ Returns:
+ - resp: server response if successful
+ - list: list of (name,title) strings"""
+ warnings.warn("The XGTITLE extension is not actively used, "
+ "use descriptions() instead",
+ DeprecationWarning, 2)
+ line_pat = re.compile('^([^ \t]+)[ \t]+(.*)$')
+ resp, raw_lines = self._longcmdstring('XGTITLE ' + group, file)
+ lines = []
+ for raw_line in raw_lines:
+ match = line_pat.search(raw_line.strip())
+ if match:
+ lines.append(match.group(1, 2))
+ return resp, lines
+
+ def xpath(self, id):
+ """Process an XPATH command (optional server extension) Arguments:
+ - id: Message id of article
+ Returns:
+ resp: server response if successful
+ path: directory path to article
+ """
+ warnings.warn("The XPATH extension is not actively used",
+ DeprecationWarning, 2)
+
+ resp = self._shortcmd('XPATH {0}'.format(id))
+ if not resp.startswith('223'):
+ raise NNTPReplyError(resp)
+ try:
+ [resp_num, path] = resp.split()
+ except ValueError:
+ raise NNTPReplyError(resp) from None
+ else:
+ return resp, path
+
+ def date(self):
+ """Process the DATE command.
+ Returns:
+ - resp: server response if successful
+ - date: datetime object
+ """
+ resp = self._shortcmd("DATE")
+ if not resp.startswith('111'):
+ raise NNTPReplyError(resp)
+ elem = resp.split()
+ if len(elem) != 2:
+ raise NNTPDataError(resp)
+ date = elem[1]
+ if len(date) != 14:
+ raise NNTPDataError(resp)
+ return resp, _parse_datetime(date, None)
+
+ def _post(self, command, f):
+ resp = self._shortcmd(command)
+ # Raises a specific exception if posting is not allowed
+ if not resp.startswith('3'):
+ raise NNTPReplyError(resp)
+ if isinstance(f, (bytes, bytearray)):
+ f = f.splitlines()
+ # We don't use _putline() because:
+ # - we don't want additional CRLF if the file or iterable is already
+ # in the right format
+ # - we don't want a spurious flush() after each line is written
+ for line in f:
+ if not line.endswith(_CRLF):
+ line = line.rstrip(b"\r\n") + _CRLF
+ if line.startswith(b'.'):
+ line = b'.' + line
+ self.file.write(line)
+ self.file.write(b".\r\n")
+ self.file.flush()
+ return self._getresp()
+
+ def post(self, data):
+ """Process a POST command. Arguments:
+ - data: bytes object, iterable or file containing the article
+ Returns:
+ - resp: server response if successful"""
+ return self._post('POST', data)
+
+ def ihave(self, message_id, data):
+ """Process an IHAVE command. Arguments:
+ - message_id: message-id of the article
+ - data: file containing the article
+ Returns:
+ - resp: server response if successful
+ Note that if the server refuses the article an exception is raised."""
+ return self._post('IHAVE {0}'.format(message_id), data)
+
+ def _close(self):
+ self.file.close()
+ del self.file
+
+ def quit(self):
+ """Process a QUIT command and close the socket. Returns:
+ - resp: server response if successful"""
+ try:
+ resp = self._shortcmd('QUIT')
+ finally:
+ self._close()
+ return resp
+
+ def login(self, user=None, password=None, usenetrc=True):
+ if self.authenticated:
+ raise ValueError("Already logged in.")
+ if not user and not usenetrc:
+ raise ValueError(
+ "At least one of `user` and `usenetrc` must be specified")
+ # If no login/password was specified but netrc was requested,
+ # try to get them from ~/.netrc
+ # Presume that if .netrc has an entry, NNRP authentication is required.
+ try:
+ if usenetrc and not user:
+ import netrc
+ credentials = netrc.netrc()
+ auth = credentials.authenticators(self.host)
+ if auth:
+ user = auth[0]
+ password = auth[2]
+ except OSError:
+ pass
+ # Perform NNTP authentication if needed.
+ if not user:
+ return
+ resp = self._shortcmd('authinfo user ' + user)
+ if resp.startswith('381'):
+ if not password:
+ raise NNTPReplyError(resp)
+ else:
+ resp = self._shortcmd('authinfo pass ' + password)
+ if not resp.startswith('281'):
+ raise NNTPPermanentError(resp)
+ # Capabilities might have changed after login
+ self._caps = None
+ self.getcapabilities()
+ # Attempt to send mode reader if it was requested after login.
+ # Only do so if we're not in reader mode already.
+ if self.readermode_afterauth and 'READER' not in self._caps:
+ self._setreadermode()
+ # Capabilities might have changed after MODE READER
+ self._caps = None
+ self.getcapabilities()
+
+ def _setreadermode(self):
+ try:
+ self.welcome = self._shortcmd('mode reader')
+ except NNTPPermanentError:
+ # Error 5xx, probably 'not implemented'
+ pass
+ except NNTPTemporaryError as e:
+ if e.response.startswith('480'):
+ # Need authorization before 'mode reader'
+ self.readermode_afterauth = True
+ else:
+ raise
+
+ if _have_ssl:
+ def starttls(self, context=None):
+ """Process a STARTTLS command. Arguments:
+ - context: SSL context to use for the encrypted connection
+ """
+ # Per RFC 4642, STARTTLS MUST NOT be sent after authentication or if
+ # a TLS session already exists.
+ if self.tls_on:
+ raise ValueError("TLS is already enabled.")
+ if self.authenticated:
+ raise ValueError("TLS cannot be started after authentication.")
+ resp = self._shortcmd('STARTTLS')
+ if resp.startswith('382'):
+ self.file.close()
+ self.sock = _encrypt_on(self.sock, context, self.host)
+ self.file = self.sock.makefile("rwb")
+ self.tls_on = True
+ # Capabilities may change after TLS starts up, so ask for them
+ # again.
+ self._caps = None
+ self.getcapabilities()
+ else:
+ raise NNTPError("TLS failed to start.")
+
+
+class NNTP(_NNTPBase):
+
+ def __init__(self, host, port=NNTP_PORT, user=None, password=None,
+ readermode=None, usenetrc=False,
+ timeout=_GLOBAL_DEFAULT_TIMEOUT):
+ """Initialize an instance. Arguments:
+ - host: hostname to connect to
+ - port: port to connect to (default the standard NNTP port)
+ - user: username to authenticate with
+ - password: password to use with username
+ - readermode: if true, send 'mode reader' command after
+ connecting.
+ - usenetrc: allow loading username and password from ~/.netrc file
+ if not specified explicitly
+ - timeout: timeout (in seconds) used for socket connections
+
+ readermode is sometimes necessary if you are connecting to an
+ NNTP server on the local machine and intend to call
+ reader-specific commands, such as `group'. If you get
+ unexpected NNTPPermanentErrors, you might need to set
+ readermode.
+ """
+ self.host = host
+ self.port = port
+ sys.audit("nntplib.connect", self, host, port)
+ self.sock = socket.create_connection((host, port), timeout)
+ file = None
+ try:
+ file = self.sock.makefile("rwb")
+ _NNTPBase.__init__(self, file, host,
+ readermode, timeout)
+ if user or usenetrc:
+ self.login(user, password, usenetrc)
+ except:
+ if file:
+ file.close()
+ self.sock.close()
+ raise
+
+ def _close(self):
+ try:
+ _NNTPBase._close(self)
+ finally:
+ self.sock.close()
+
+
+if _have_ssl:
+ class NNTP_SSL(_NNTPBase):
+
+ def __init__(self, host, port=NNTP_SSL_PORT,
+ user=None, password=None, ssl_context=None,
+ readermode=None, usenetrc=False,
+ timeout=_GLOBAL_DEFAULT_TIMEOUT):
+ """This works identically to NNTP.__init__, except for the change
+ in default port and the `ssl_context` argument for SSL connections.
+ """
+ sys.audit("nntplib.connect", self, host, port)
+ self.sock = socket.create_connection((host, port), timeout)
+ file = None
+ try:
+ self.sock = _encrypt_on(self.sock, ssl_context, host)
+ file = self.sock.makefile("rwb")
+ _NNTPBase.__init__(self, file, host,
+ readermode=readermode, timeout=timeout)
+ if user or usenetrc:
+ self.login(user, password, usenetrc)
+ except:
+ if file:
+ file.close()
+ self.sock.close()
+ raise
+
+ def _close(self):
+ try:
+ _NNTPBase._close(self)
+ finally:
+ self.sock.close()
+
+ __all__.append("NNTP_SSL")
+
+
+# Test retrieval when run as a script.
+if __name__ == '__main__':
+ import argparse
+
+ parser = argparse.ArgumentParser(description="""\
+ nntplib built-in demo - display the latest articles in a newsgroup""")
+ parser.add_argument('-g', '--group', default='gmane.comp.python.general',
+ help='group to fetch messages from (default: %(default)s)')
+ parser.add_argument('-s', '--server', default='news.gmane.io',
+ help='NNTP server hostname (default: %(default)s)')
+ parser.add_argument('-p', '--port', default=-1, type=int,
+ help='NNTP port number (default: %s / %s)' % (NNTP_PORT, NNTP_SSL_PORT))
+ parser.add_argument('-n', '--nb-articles', default=10, type=int,
+ help='number of articles to fetch (default: %(default)s)')
+ parser.add_argument('-S', '--ssl', action='store_true', default=False,
+ help='use NNTP over SSL')
+ args = parser.parse_args()
+
+ port = args.port
+ if not args.ssl:
+ if port == -1:
+ port = NNTP_PORT
+ s = NNTP(host=args.server, port=port)
+ else:
+ if port == -1:
+ port = NNTP_SSL_PORT
+ s = NNTP_SSL(host=args.server, port=port)
+
+ caps = s.getcapabilities()
+ if 'STARTTLS' in caps:
+ s.starttls()
+ resp, count, first, last, name = s.group(args.group)
+ print('Group', name, 'has', count, 'articles, range', first, 'to', last)
+
+ def cut(s, lim):
+ if len(s) > lim:
+ s = s[:lim - 4] + "..."
+ return s
+
+ first = str(int(last) - args.nb_articles + 1)
+ resp, overviews = s.xover(first, last)
+ for artnum, over in overviews:
+ author = decode_header(over['from']).split('<', 1)[0]
+ subject = decode_header(over['subject'])
+ lines = int(over[':lines'])
+ print("{:7} {:20} {:42} ({})".format(
+ artnum, cut(author, 20), cut(subject, 42), lines)
+ )
+
+ s.quit()
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/numbers.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/numbers.py
new file mode 100644
index 0000000000000000000000000000000000000000..ed815ef41ebe121da873fd9bedb90e6c298c1269
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/numbers.py
@@ -0,0 +1,389 @@
+# Copyright 2007 Google, Inc. All Rights Reserved.
+# Licensed to PSF under a Contributor Agreement.
+
+"""Abstract Base Classes (ABCs) for numbers, according to PEP 3141.
+
+TODO: Fill out more detailed documentation on the operators."""
+
+from abc import ABCMeta, abstractmethod
+
+__all__ = ["Number", "Complex", "Real", "Rational", "Integral"]
+
+class Number(metaclass=ABCMeta):
+ """All numbers inherit from this class.
+
+ If you just want to check if an argument x is a number, without
+ caring what kind, use isinstance(x, Number).
+ """
+ __slots__ = ()
+
+ # Concrete numeric types must provide their own hash implementation
+ __hash__ = None
+
+
+## Notes on Decimal
+## ----------------
+## Decimal has all of the methods specified by the Real abc, but it should
+## not be registered as a Real because decimals do not interoperate with
+## binary floats (i.e. Decimal('3.14') + 2.71828 is undefined). But,
+## abstract reals are expected to interoperate (i.e. R1 + R2 should be
+## expected to work if R1 and R2 are both Reals).
+
+class Complex(Number):
+ """Complex defines the operations that work on the builtin complex type.
+
+ In short, those are: a conversion to complex, .real, .imag, +, -,
+ *, /, abs(), .conjugate, ==, and !=.
+
+ If it is given heterogeneous arguments, and doesn't have special
+ knowledge about them, it should fall back to the builtin complex
+ type as described below.
+ """
+
+ __slots__ = ()
+
+ @abstractmethod
+ def __complex__(self):
+ """Return a builtin complex instance. Called for complex(self)."""
+
+ def __bool__(self):
+ """True if self != 0. Called for bool(self)."""
+ return self != 0
+
+ @property
+ @abstractmethod
+ def real(self):
+ """Retrieve the real component of this number.
+
+ This should subclass Real.
+ """
+ raise NotImplementedError
+
+ @property
+ @abstractmethod
+ def imag(self):
+ """Retrieve the imaginary component of this number.
+
+ This should subclass Real.
+ """
+ raise NotImplementedError
+
+ @abstractmethod
+ def __add__(self, other):
+ """self + other"""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __radd__(self, other):
+ """other + self"""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __neg__(self):
+ """-self"""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __pos__(self):
+ """+self"""
+ raise NotImplementedError
+
+ def __sub__(self, other):
+ """self - other"""
+ return self + -other
+
+ def __rsub__(self, other):
+ """other - self"""
+ return -self + other
+
+ @abstractmethod
+ def __mul__(self, other):
+ """self * other"""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __rmul__(self, other):
+ """other * self"""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __truediv__(self, other):
+ """self / other: Should promote to float when necessary."""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __rtruediv__(self, other):
+ """other / self"""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __pow__(self, exponent):
+ """self**exponent; should promote to float or complex when necessary."""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __rpow__(self, base):
+ """base ** self"""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __abs__(self):
+ """Returns the Real distance from 0. Called for abs(self)."""
+ raise NotImplementedError
+
+ @abstractmethod
+ def conjugate(self):
+ """(x+y*i).conjugate() returns (x-y*i)."""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __eq__(self, other):
+ """self == other"""
+ raise NotImplementedError
+
+Complex.register(complex)
+
+
+class Real(Complex):
+ """To Complex, Real adds the operations that work on real numbers.
+
+ In short, those are: a conversion to float, trunc(), divmod,
+ %, <, <=, >, and >=.
+
+ Real also provides defaults for the derived operations.
+ """
+
+ __slots__ = ()
+
+ @abstractmethod
+ def __float__(self):
+ """Any Real can be converted to a native float object.
+
+ Called for float(self)."""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __trunc__(self):
+ """trunc(self): Truncates self to an Integral.
+
+ Returns an Integral i such that:
+ * i>0 iff self>0;
+ * abs(i) <= abs(self);
+ * for any Integral j satisfying the first two conditions,
+ abs(i) >= abs(j) [i.e. i has "maximal" abs among those].
+ i.e. "truncate towards 0".
+ """
+ raise NotImplementedError
+
+ @abstractmethod
+ def __floor__(self):
+ """Finds the greatest Integral <= self."""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __ceil__(self):
+ """Finds the least Integral >= self."""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __round__(self, ndigits=None):
+ """Rounds self to ndigits decimal places, defaulting to 0.
+
+ If ndigits is omitted or None, returns an Integral, otherwise
+ returns a Real. Rounds half toward even.
+ """
+ raise NotImplementedError
+
+ def __divmod__(self, other):
+ """divmod(self, other): The pair (self // other, self % other).
+
+ Sometimes this can be computed faster than the pair of
+ operations.
+ """
+ return (self // other, self % other)
+
+ def __rdivmod__(self, other):
+ """divmod(other, self): The pair (self // other, self % other).
+
+ Sometimes this can be computed faster than the pair of
+ operations.
+ """
+ return (other // self, other % self)
+
+ @abstractmethod
+ def __floordiv__(self, other):
+ """self // other: The floor() of self/other."""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __rfloordiv__(self, other):
+ """other // self: The floor() of other/self."""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __mod__(self, other):
+ """self % other"""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __rmod__(self, other):
+ """other % self"""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __lt__(self, other):
+ """self < other
+
+ < on Reals defines a total ordering, except perhaps for NaN."""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __le__(self, other):
+ """self <= other"""
+ raise NotImplementedError
+
+ # Concrete implementations of Complex abstract methods.
+ def __complex__(self):
+ """complex(self) == complex(float(self), 0)"""
+ return complex(float(self))
+
+ @property
+ def real(self):
+ """Real numbers are their real component."""
+ return +self
+
+ @property
+ def imag(self):
+ """Real numbers have no imaginary component."""
+ return 0
+
+ def conjugate(self):
+ """Conjugate is a no-op for Reals."""
+ return +self
+
+Real.register(float)
+
+
+class Rational(Real):
+ """.numerator and .denominator should be in lowest terms."""
+
+ __slots__ = ()
+
+ @property
+ @abstractmethod
+ def numerator(self):
+ raise NotImplementedError
+
+ @property
+ @abstractmethod
+ def denominator(self):
+ raise NotImplementedError
+
+ # Concrete implementation of Real's conversion to float.
+ def __float__(self):
+ """float(self) = self.numerator / self.denominator
+
+ It's important that this conversion use the integer's "true"
+ division rather than casting one side to float before dividing
+ so that ratios of huge integers convert without overflowing.
+
+ """
+ return self.numerator / self.denominator
+
+
+class Integral(Rational):
+ """Integral adds a conversion to int and the bit-string operations."""
+
+ __slots__ = ()
+
+ @abstractmethod
+ def __int__(self):
+ """int(self)"""
+ raise NotImplementedError
+
+ def __index__(self):
+ """Called whenever an index is needed, such as in slicing"""
+ return int(self)
+
+ @abstractmethod
+ def __pow__(self, exponent, modulus=None):
+ """self ** exponent % modulus, but maybe faster.
+
+ Accept the modulus argument if you want to support the
+ 3-argument version of pow(). Raise a TypeError if exponent < 0
+ or any argument isn't Integral. Otherwise, just implement the
+ 2-argument version described in Complex.
+ """
+ raise NotImplementedError
+
+ @abstractmethod
+ def __lshift__(self, other):
+ """self << other"""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __rlshift__(self, other):
+ """other << self"""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __rshift__(self, other):
+ """self >> other"""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __rrshift__(self, other):
+ """other >> self"""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __and__(self, other):
+ """self & other"""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __rand__(self, other):
+ """other & self"""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __xor__(self, other):
+ """self ^ other"""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __rxor__(self, other):
+ """other ^ self"""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __or__(self, other):
+ """self | other"""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __ror__(self, other):
+ """other | self"""
+ raise NotImplementedError
+
+ @abstractmethod
+ def __invert__(self):
+ """~self"""
+ raise NotImplementedError
+
+ # Concrete implementations of Rational and Real abstract methods.
+ def __float__(self):
+ """float(self) == float(int(self))"""
+ return float(int(self))
+
+ @property
+ def numerator(self):
+ """Integers are their own numerators."""
+ return +self
+
+ @property
+ def denominator(self):
+ """Integers have a denominator of 1."""
+ return 1
+
+Integral.register(int)
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/opcode.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/opcode.py
new file mode 100644
index 0000000000000000000000000000000000000000..3fb716b5d96a2909556eb25621ec0b354a5a3a03
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/opcode.py
@@ -0,0 +1,216 @@
+
+"""
+opcode module - potentially shared between dis and other modules which
+operate on bytecodes (e.g. peephole optimizers).
+"""
+
+__all__ = ["cmp_op", "hasconst", "hasname", "hasjrel", "hasjabs",
+ "haslocal", "hascompare", "hasfree", "opname", "opmap",
+ "HAVE_ARGUMENT", "EXTENDED_ARG", "hasnargs"]
+
+# It's a chicken-and-egg I'm afraid:
+# We're imported before _opcode's made.
+# With exception unheeded
+# (stack_effect is not needed)
+# Both our chickens and eggs are allayed.
+# --Larry Hastings, 2013/11/23
+
+try:
+ from _opcode import stack_effect
+ __all__.append('stack_effect')
+except ImportError:
+ pass
+
+cmp_op = ('<', '<=', '==', '!=', '>', '>=', 'in', 'not in', 'is',
+ 'is not', 'exception match', 'BAD')
+
+hasconst = []
+hasname = []
+hasjrel = []
+hasjabs = []
+haslocal = []
+hascompare = []
+hasfree = []
+hasnargs = [] # unused
+
+opmap = {}
+opname = ['<%r>' % (op,) for op in range(256)]
+
+def def_op(name, op):
+ opname[op] = name
+ opmap[name] = op
+
+def name_op(name, op):
+ def_op(name, op)
+ hasname.append(op)
+
+def jrel_op(name, op):
+ def_op(name, op)
+ hasjrel.append(op)
+
+def jabs_op(name, op):
+ def_op(name, op)
+ hasjabs.append(op)
+
+# Instruction opcodes for compiled code
+# Blank lines correspond to available opcodes
+
+def_op('POP_TOP', 1)
+def_op('ROT_TWO', 2)
+def_op('ROT_THREE', 3)
+def_op('DUP_TOP', 4)
+def_op('DUP_TOP_TWO', 5)
+def_op('ROT_FOUR', 6)
+
+def_op('NOP', 9)
+def_op('UNARY_POSITIVE', 10)
+def_op('UNARY_NEGATIVE', 11)
+def_op('UNARY_NOT', 12)
+
+def_op('UNARY_INVERT', 15)
+
+def_op('BINARY_MATRIX_MULTIPLY', 16)
+def_op('INPLACE_MATRIX_MULTIPLY', 17)
+
+def_op('BINARY_POWER', 19)
+def_op('BINARY_MULTIPLY', 20)
+
+def_op('BINARY_MODULO', 22)
+def_op('BINARY_ADD', 23)
+def_op('BINARY_SUBTRACT', 24)
+def_op('BINARY_SUBSCR', 25)
+def_op('BINARY_FLOOR_DIVIDE', 26)
+def_op('BINARY_TRUE_DIVIDE', 27)
+def_op('INPLACE_FLOOR_DIVIDE', 28)
+def_op('INPLACE_TRUE_DIVIDE', 29)
+
+def_op('GET_AITER', 50)
+def_op('GET_ANEXT', 51)
+def_op('BEFORE_ASYNC_WITH', 52)
+def_op('BEGIN_FINALLY', 53)
+def_op('END_ASYNC_FOR', 54)
+def_op('INPLACE_ADD', 55)
+def_op('INPLACE_SUBTRACT', 56)
+def_op('INPLACE_MULTIPLY', 57)
+
+def_op('INPLACE_MODULO', 59)
+def_op('STORE_SUBSCR', 60)
+def_op('DELETE_SUBSCR', 61)
+def_op('BINARY_LSHIFT', 62)
+def_op('BINARY_RSHIFT', 63)
+def_op('BINARY_AND', 64)
+def_op('BINARY_XOR', 65)
+def_op('BINARY_OR', 66)
+def_op('INPLACE_POWER', 67)
+def_op('GET_ITER', 68)
+def_op('GET_YIELD_FROM_ITER', 69)
+
+def_op('PRINT_EXPR', 70)
+def_op('LOAD_BUILD_CLASS', 71)
+def_op('YIELD_FROM', 72)
+def_op('GET_AWAITABLE', 73)
+
+def_op('INPLACE_LSHIFT', 75)
+def_op('INPLACE_RSHIFT', 76)
+def_op('INPLACE_AND', 77)
+def_op('INPLACE_XOR', 78)
+def_op('INPLACE_OR', 79)
+def_op('WITH_CLEANUP_START', 81)
+def_op('WITH_CLEANUP_FINISH', 82)
+def_op('RETURN_VALUE', 83)
+def_op('IMPORT_STAR', 84)
+def_op('SETUP_ANNOTATIONS', 85)
+def_op('YIELD_VALUE', 86)
+def_op('POP_BLOCK', 87)
+def_op('END_FINALLY', 88)
+def_op('POP_EXCEPT', 89)
+
+HAVE_ARGUMENT = 90 # Opcodes from here have an argument:
+
+name_op('STORE_NAME', 90) # Index in name list
+name_op('DELETE_NAME', 91) # ""
+def_op('UNPACK_SEQUENCE', 92) # Number of tuple items
+jrel_op('FOR_ITER', 93)
+def_op('UNPACK_EX', 94)
+name_op('STORE_ATTR', 95) # Index in name list
+name_op('DELETE_ATTR', 96) # ""
+name_op('STORE_GLOBAL', 97) # ""
+name_op('DELETE_GLOBAL', 98) # ""
+def_op('LOAD_CONST', 100) # Index in const list
+hasconst.append(100)
+name_op('LOAD_NAME', 101) # Index in name list
+def_op('BUILD_TUPLE', 102) # Number of tuple items
+def_op('BUILD_LIST', 103) # Number of list items
+def_op('BUILD_SET', 104) # Number of set items
+def_op('BUILD_MAP', 105) # Number of dict entries
+name_op('LOAD_ATTR', 106) # Index in name list
+def_op('COMPARE_OP', 107) # Comparison operator
+hascompare.append(107)
+name_op('IMPORT_NAME', 108) # Index in name list
+name_op('IMPORT_FROM', 109) # Index in name list
+
+jrel_op('JUMP_FORWARD', 110) # Number of bytes to skip
+jabs_op('JUMP_IF_FALSE_OR_POP', 111) # Target byte offset from beginning of code
+jabs_op('JUMP_IF_TRUE_OR_POP', 112) # ""
+jabs_op('JUMP_ABSOLUTE', 113) # ""
+jabs_op('POP_JUMP_IF_FALSE', 114) # ""
+jabs_op('POP_JUMP_IF_TRUE', 115) # ""
+
+name_op('LOAD_GLOBAL', 116) # Index in name list
+
+jrel_op('SETUP_FINALLY', 122) # Distance to target address
+
+def_op('LOAD_FAST', 124) # Local variable number
+haslocal.append(124)
+def_op('STORE_FAST', 125) # Local variable number
+haslocal.append(125)
+def_op('DELETE_FAST', 126) # Local variable number
+haslocal.append(126)
+
+def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3)
+def_op('CALL_FUNCTION', 131) # #args
+def_op('MAKE_FUNCTION', 132) # Flags
+def_op('BUILD_SLICE', 133) # Number of items
+def_op('LOAD_CLOSURE', 135)
+hasfree.append(135)
+def_op('LOAD_DEREF', 136)
+hasfree.append(136)
+def_op('STORE_DEREF', 137)
+hasfree.append(137)
+def_op('DELETE_DEREF', 138)
+hasfree.append(138)
+
+def_op('CALL_FUNCTION_KW', 141) # #args + #kwargs
+def_op('CALL_FUNCTION_EX', 142) # Flags
+
+jrel_op('SETUP_WITH', 143)
+
+def_op('LIST_APPEND', 145)
+def_op('SET_ADD', 146)
+def_op('MAP_ADD', 147)
+
+def_op('LOAD_CLASSDEREF', 148)
+hasfree.append(148)
+
+def_op('EXTENDED_ARG', 144)
+EXTENDED_ARG = 144
+
+def_op('BUILD_LIST_UNPACK', 149)
+def_op('BUILD_MAP_UNPACK', 150)
+def_op('BUILD_MAP_UNPACK_WITH_CALL', 151)
+def_op('BUILD_TUPLE_UNPACK', 152)
+def_op('BUILD_SET_UNPACK', 153)
+
+jrel_op('SETUP_ASYNC_WITH', 154)
+
+def_op('FORMAT_VALUE', 155)
+def_op('BUILD_CONST_KEY_MAP', 156)
+def_op('BUILD_STRING', 157)
+def_op('BUILD_TUPLE_UNPACK_WITH_CALL', 158)
+
+name_op('LOAD_METHOD', 160)
+def_op('CALL_METHOD', 161)
+jrel_op('CALL_FINALLY', 162)
+def_op('POP_FINALLY', 163)
+
+del def_op, name_op, jrel_op, jabs_op
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/pathlib.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/pathlib.py
new file mode 100644
index 0000000000000000000000000000000000000000..350f27e4a06de1a7b4ab75e1c13632ea723f7ea1
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/pathlib.py
@@ -0,0 +1,1583 @@
+import fnmatch
+import functools
+import io
+import ntpath
+import os
+import posixpath
+import re
+import sys
+from _collections_abc import Sequence
+from errno import EINVAL, ENOENT, ENOTDIR, EBADF, ELOOP
+from operator import attrgetter
+from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO
+from urllib.parse import quote_from_bytes as urlquote_from_bytes
+
+
+supports_symlinks = True
+if os.name == 'nt':
+ import nt
+ if sys.getwindowsversion()[:2] >= (6, 0):
+ from nt import _getfinalpathname
+ else:
+ supports_symlinks = False
+ _getfinalpathname = None
+else:
+ nt = None
+
+
+__all__ = [
+ "PurePath", "PurePosixPath", "PureWindowsPath",
+ "Path", "PosixPath", "WindowsPath",
+ ]
+
+#
+# Internals
+#
+
+# EBADF - guard against macOS `stat` throwing EBADF
+_IGNORED_ERROS = (ENOENT, ENOTDIR, EBADF, ELOOP)
+
+_IGNORED_WINERRORS = (
+ 21, # ERROR_NOT_READY - drive exists but is not accessible
+ 123, # ERROR_INVALID_NAME - fix for bpo-35306
+ 1921, # ERROR_CANT_RESOLVE_FILENAME - fix for broken symlink pointing to itself
+)
+
+def _ignore_error(exception):
+ return (getattr(exception, 'errno', None) in _IGNORED_ERROS or
+ getattr(exception, 'winerror', None) in _IGNORED_WINERRORS)
+
+
+def _is_wildcard_pattern(pat):
+ # Whether this pattern needs actual matching using fnmatch, or can
+ # be looked up directly as a file.
+ return "*" in pat or "?" in pat or "[" in pat
+
+
+class _Flavour(object):
+ """A flavour implements a particular (platform-specific) set of path
+ semantics."""
+
+ def __init__(self):
+ self.join = self.sep.join
+
+ def parse_parts(self, parts):
+ parsed = []
+ sep = self.sep
+ altsep = self.altsep
+ drv = root = ''
+ it = reversed(parts)
+ for part in it:
+ if not part:
+ continue
+ if altsep:
+ part = part.replace(altsep, sep)
+ drv, root, rel = self.splitroot(part)
+ if sep in rel:
+ for x in reversed(rel.split(sep)):
+ if x and x != '.':
+ parsed.append(sys.intern(x))
+ else:
+ if rel and rel != '.':
+ parsed.append(sys.intern(rel))
+ if drv or root:
+ if not drv:
+ # If no drive is present, try to find one in the previous
+ # parts. This makes the result of parsing e.g.
+ # ("C:", "/", "a") reasonably intuitive.
+ for part in it:
+ if not part:
+ continue
+ if altsep:
+ part = part.replace(altsep, sep)
+ drv = self.splitroot(part)[0]
+ if drv:
+ break
+ break
+ if drv or root:
+ parsed.append(drv + root)
+ parsed.reverse()
+ return drv, root, parsed
+
+ def join_parsed_parts(self, drv, root, parts, drv2, root2, parts2):
+ """
+ Join the two paths represented by the respective
+ (drive, root, parts) tuples. Return a new (drive, root, parts) tuple.
+ """
+ if root2:
+ if not drv2 and drv:
+ return drv, root2, [drv + root2] + parts2[1:]
+ elif drv2:
+ if drv2 == drv or self.casefold(drv2) == self.casefold(drv):
+ # Same drive => second path is relative to the first
+ return drv, root, parts + parts2[1:]
+ else:
+ # Second path is non-anchored (common case)
+ return drv, root, parts + parts2
+ return drv2, root2, parts2
+
+
+class _WindowsFlavour(_Flavour):
+ # Reference for Windows paths can be found at
+ # http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx
+
+ sep = '\\'
+ altsep = '/'
+ has_drv = True
+ pathmod = ntpath
+
+ is_supported = (os.name == 'nt')
+
+ drive_letters = set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
+ ext_namespace_prefix = '\\\\?\\'
+
+ reserved_names = (
+ {'CON', 'PRN', 'AUX', 'NUL'} |
+ {'COM%d' % i for i in range(1, 10)} |
+ {'LPT%d' % i for i in range(1, 10)}
+ )
+
+ # Interesting findings about extended paths:
+ # - '\\?\c:\a', '//?/c:\a' and '//?/c:/a' are all supported
+ # but '\\?\c:/a' is not
+ # - extended paths are always absolute; "relative" extended paths will
+ # fail.
+
+ def splitroot(self, part, sep=sep):
+ first = part[0:1]
+ second = part[1:2]
+ if (second == sep and first == sep):
+ # XXX extended paths should also disable the collapsing of "."
+ # components (according to MSDN docs).
+ prefix, part = self._split_extended_path(part)
+ first = part[0:1]
+ second = part[1:2]
+ else:
+ prefix = ''
+ third = part[2:3]
+ if (second == sep and first == sep and third != sep):
+ # is a UNC path:
+ # vvvvvvvvvvvvvvvvvvvvv root
+ # \\machine\mountpoint\directory\etc\...
+ # directory ^^^^^^^^^^^^^^
+ index = part.find(sep, 2)
+ if index != -1:
+ index2 = part.find(sep, index + 1)
+ # a UNC path can't have two slashes in a row
+ # (after the initial two)
+ if index2 != index + 1:
+ if index2 == -1:
+ index2 = len(part)
+ if prefix:
+ return prefix + part[1:index2], sep, part[index2+1:]
+ else:
+ return part[:index2], sep, part[index2+1:]
+ drv = root = ''
+ if second == ':' and first in self.drive_letters:
+ drv = part[:2]
+ part = part[2:]
+ first = third
+ if first == sep:
+ root = first
+ part = part.lstrip(sep)
+ return prefix + drv, root, part
+
+ def casefold(self, s):
+ return s.lower()
+
+ def casefold_parts(self, parts):
+ return [p.lower() for p in parts]
+
+ def compile_pattern(self, pattern):
+ return re.compile(fnmatch.translate(pattern), re.IGNORECASE).fullmatch
+
+ def resolve(self, path, strict=False):
+ s = str(path)
+ if not s:
+ return os.getcwd()
+ previous_s = None
+ if _getfinalpathname is not None:
+ if strict:
+ return self._ext_to_normal(_getfinalpathname(s))
+ else:
+ tail_parts = [] # End of the path after the first one not found
+ while True:
+ try:
+ s = self._ext_to_normal(_getfinalpathname(s))
+ except FileNotFoundError:
+ previous_s = s
+ s, tail = os.path.split(s)
+ tail_parts.append(tail)
+ if previous_s == s:
+ return path
+ else:
+ return os.path.join(s, *reversed(tail_parts))
+ # Means fallback on absolute
+ return None
+
+ def _split_extended_path(self, s, ext_prefix=ext_namespace_prefix):
+ prefix = ''
+ if s.startswith(ext_prefix):
+ prefix = s[:4]
+ s = s[4:]
+ if s.startswith('UNC\\'):
+ prefix += s[:3]
+ s = '\\' + s[3:]
+ return prefix, s
+
+ def _ext_to_normal(self, s):
+ # Turn back an extended path into a normal DOS-like path
+ return self._split_extended_path(s)[1]
+
+ def is_reserved(self, parts):
+ # NOTE: the rules for reserved names seem somewhat complicated
+ # (e.g. r"..\NUL" is reserved but not r"foo\NUL").
+ # We err on the side of caution and return True for paths which are
+ # not considered reserved by Windows.
+ if not parts:
+ return False
+ if parts[0].startswith('\\\\'):
+ # UNC paths are never reserved
+ return False
+ return parts[-1].partition('.')[0].upper() in self.reserved_names
+
+ def make_uri(self, path):
+ # Under Windows, file URIs use the UTF-8 encoding.
+ drive = path.drive
+ if len(drive) == 2 and drive[1] == ':':
+ # It's a path on a local drive => 'file:///c:/a/b'
+ rest = path.as_posix()[2:].lstrip('/')
+ return 'file:///%s/%s' % (
+ drive, urlquote_from_bytes(rest.encode('utf-8')))
+ else:
+ # It's a path on a network drive => 'file://host/share/a/b'
+ return 'file:' + urlquote_from_bytes(path.as_posix().encode('utf-8'))
+
+ def gethomedir(self, username):
+ if 'USERPROFILE' in os.environ:
+ userhome = os.environ['USERPROFILE']
+ elif 'HOMEPATH' in os.environ:
+ try:
+ drv = os.environ['HOMEDRIVE']
+ except KeyError:
+ drv = ''
+ userhome = drv + os.environ['HOMEPATH']
+ else:
+ raise RuntimeError("Can't determine home directory")
+
+ if username:
+ # Try to guess user home directory. By default all users
+ # directories are located in the same place and are named by
+ # corresponding usernames. If current user home directory points
+ # to nonstandard place, this guess is likely wrong.
+ if os.environ['USERNAME'] != username:
+ drv, root, parts = self.parse_parts((userhome,))
+ if parts[-1] != os.environ['USERNAME']:
+ raise RuntimeError("Can't determine home directory "
+ "for %r" % username)
+ parts[-1] = username
+ if drv or root:
+ userhome = drv + root + self.join(parts[1:])
+ else:
+ userhome = self.join(parts)
+ return userhome
+
+class _PosixFlavour(_Flavour):
+ sep = '/'
+ altsep = ''
+ has_drv = False
+ pathmod = posixpath
+
+ is_supported = (os.name != 'nt')
+
+ def splitroot(self, part, sep=sep):
+ if part and part[0] == sep:
+ stripped_part = part.lstrip(sep)
+ # According to POSIX path resolution:
+ # http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap04.html#tag_04_11
+ # "A pathname that begins with two successive slashes may be
+ # interpreted in an implementation-defined manner, although more
+ # than two leading slashes shall be treated as a single slash".
+ if len(part) - len(stripped_part) == 2:
+ return '', sep * 2, stripped_part
+ else:
+ return '', sep, stripped_part
+ else:
+ return '', '', part
+
+ def casefold(self, s):
+ return s
+
+ def casefold_parts(self, parts):
+ return parts
+
+ def compile_pattern(self, pattern):
+ return re.compile(fnmatch.translate(pattern)).fullmatch
+
+ def resolve(self, path, strict=False):
+ sep = self.sep
+ accessor = path._accessor
+ seen = {}
+ def _resolve(path, rest):
+ if rest.startswith(sep):
+ path = ''
+
+ for name in rest.split(sep):
+ if not name or name == '.':
+ # current dir
+ continue
+ if name == '..':
+ # parent dir
+ path, _, _ = path.rpartition(sep)
+ continue
+ if path.endswith(sep):
+ newpath = path + name
+ else:
+ newpath = path + sep + name
+ if newpath in seen:
+ # Already seen this path
+ path = seen[newpath]
+ if path is not None:
+ # use cached value
+ continue
+ # The symlink is not resolved, so we must have a symlink loop.
+ raise RuntimeError("Symlink loop from %r" % newpath)
+ # Resolve the symbolic link
+ try:
+ target = accessor.readlink(newpath)
+ except OSError as e:
+ if e.errno != EINVAL and strict:
+ raise
+ # Not a symlink, or non-strict mode. We just leave the path
+ # untouched.
+ path = newpath
+ else:
+ seen[newpath] = None # not resolved symlink
+ path = _resolve(path, target)
+ seen[newpath] = path # resolved symlink
+
+ return path
+ # NOTE: according to POSIX, getcwd() cannot contain path components
+ # which are symlinks.
+ base = '' if path.is_absolute() else os.getcwd()
+ return _resolve(base, str(path)) or sep
+
+ def is_reserved(self, parts):
+ return False
+
+ def make_uri(self, path):
+ # We represent the path using the local filesystem encoding,
+ # for portability to other applications.
+ bpath = bytes(path)
+ return 'file://' + urlquote_from_bytes(bpath)
+
+ def gethomedir(self, username):
+ if not username:
+ try:
+ return os.environ['HOME']
+ except KeyError:
+ import pwd
+ return pwd.getpwuid(os.getuid()).pw_dir
+ else:
+ import pwd
+ try:
+ return pwd.getpwnam(username).pw_dir
+ except KeyError:
+ raise RuntimeError("Can't determine home directory "
+ "for %r" % username)
+
+
+_windows_flavour = _WindowsFlavour()
+_posix_flavour = _PosixFlavour()
+
+
+class _Accessor:
+ """An accessor implements a particular (system-specific or not) way of
+ accessing paths on the filesystem."""
+
+
+class _NormalAccessor(_Accessor):
+
+ stat = os.stat
+
+ lstat = os.lstat
+
+ open = os.open
+
+ listdir = os.listdir
+
+ scandir = os.scandir
+
+ chmod = os.chmod
+
+ if hasattr(os, "lchmod"):
+ lchmod = os.lchmod
+ else:
+ def lchmod(self, pathobj, mode):
+ raise NotImplementedError("lchmod() not available on this system")
+
+ mkdir = os.mkdir
+
+ unlink = os.unlink
+
+ if hasattr(os, "link"):
+ link_to = os.link
+ else:
+ @staticmethod
+ def link_to(self, target):
+ raise NotImplementedError("os.link() not available on this system")
+
+ rmdir = os.rmdir
+
+ rename = os.rename
+
+ replace = os.replace
+
+ if nt:
+ if supports_symlinks:
+ symlink = os.symlink
+ else:
+ def symlink(a, b, target_is_directory):
+ raise NotImplementedError("symlink() not available on this system")
+ else:
+ # Under POSIX, os.symlink() takes two args
+ @staticmethod
+ def symlink(a, b, target_is_directory):
+ return os.symlink(a, b)
+
+ utime = os.utime
+
+ # Helper for resolve()
+ def readlink(self, path):
+ return os.readlink(path)
+
+
+_normal_accessor = _NormalAccessor()
+
+
+#
+# Globbing helpers
+#
+
+def _make_selector(pattern_parts, flavour):
+ pat = pattern_parts[0]
+ child_parts = pattern_parts[1:]
+ if pat == '**':
+ cls = _RecursiveWildcardSelector
+ elif '**' in pat:
+ raise ValueError("Invalid pattern: '**' can only be an entire path component")
+ elif _is_wildcard_pattern(pat):
+ cls = _WildcardSelector
+ else:
+ cls = _PreciseSelector
+ return cls(pat, child_parts, flavour)
+
+if hasattr(functools, "lru_cache"):
+ _make_selector = functools.lru_cache()(_make_selector)
+
+
+class _Selector:
+ """A selector matches a specific glob pattern part against the children
+ of a given path."""
+
+ def __init__(self, child_parts, flavour):
+ self.child_parts = child_parts
+ if child_parts:
+ self.successor = _make_selector(child_parts, flavour)
+ self.dironly = True
+ else:
+ self.successor = _TerminatingSelector()
+ self.dironly = False
+
+ def select_from(self, parent_path):
+ """Iterate over all child paths of `parent_path` matched by this
+ selector. This can contain parent_path itself."""
+ path_cls = type(parent_path)
+ is_dir = path_cls.is_dir
+ exists = path_cls.exists
+ scandir = parent_path._accessor.scandir
+ if not is_dir(parent_path):
+ return iter([])
+ return self._select_from(parent_path, is_dir, exists, scandir)
+
+
+class _TerminatingSelector:
+
+ def _select_from(self, parent_path, is_dir, exists, scandir):
+ yield parent_path
+
+
+class _PreciseSelector(_Selector):
+
+ def __init__(self, name, child_parts, flavour):
+ self.name = name
+ _Selector.__init__(self, child_parts, flavour)
+
+ def _select_from(self, parent_path, is_dir, exists, scandir):
+ try:
+ path = parent_path._make_child_relpath(self.name)
+ if (is_dir if self.dironly else exists)(path):
+ for p in self.successor._select_from(path, is_dir, exists, scandir):
+ yield p
+ except PermissionError:
+ return
+
+
+class _WildcardSelector(_Selector):
+
+ def __init__(self, pat, child_parts, flavour):
+ self.match = flavour.compile_pattern(pat)
+ _Selector.__init__(self, child_parts, flavour)
+
+ def _select_from(self, parent_path, is_dir, exists, scandir):
+ try:
+ with scandir(parent_path) as scandir_it:
+ entries = list(scandir_it)
+ for entry in entries:
+ if self.dironly:
+ try:
+ # "entry.is_dir()" can raise PermissionError
+ # in some cases (see bpo-38894), which is not
+ # among the errors ignored by _ignore_error()
+ if not entry.is_dir():
+ continue
+ except OSError as e:
+ if not _ignore_error(e):
+ raise
+ continue
+ name = entry.name
+ if self.match(name):
+ path = parent_path._make_child_relpath(name)
+ for p in self.successor._select_from(path, is_dir, exists, scandir):
+ yield p
+ except PermissionError:
+ return
+
+
+class _RecursiveWildcardSelector(_Selector):
+
+ def __init__(self, pat, child_parts, flavour):
+ _Selector.__init__(self, child_parts, flavour)
+
+ def _iterate_directories(self, parent_path, is_dir, scandir):
+ yield parent_path
+ try:
+ with scandir(parent_path) as scandir_it:
+ entries = list(scandir_it)
+ for entry in entries:
+ entry_is_dir = False
+ try:
+ entry_is_dir = entry.is_dir()
+ except OSError as e:
+ if not _ignore_error(e):
+ raise
+ if entry_is_dir and not entry.is_symlink():
+ path = parent_path._make_child_relpath(entry.name)
+ for p in self._iterate_directories(path, is_dir, scandir):
+ yield p
+ except PermissionError:
+ return
+
+ def _select_from(self, parent_path, is_dir, exists, scandir):
+ try:
+ yielded = set()
+ try:
+ successor_select = self.successor._select_from
+ for starting_point in self._iterate_directories(parent_path, is_dir, scandir):
+ for p in successor_select(starting_point, is_dir, exists, scandir):
+ if p not in yielded:
+ yield p
+ yielded.add(p)
+ finally:
+ yielded.clear()
+ except PermissionError:
+ return
+
+
+#
+# Public API
+#
+
+class _PathParents(Sequence):
+ """This object provides sequence-like access to the logical ancestors
+ of a path. Don't try to construct it yourself."""
+ __slots__ = ('_pathcls', '_drv', '_root', '_parts')
+
+ def __init__(self, path):
+ # We don't store the instance to avoid reference cycles
+ self._pathcls = type(path)
+ self._drv = path._drv
+ self._root = path._root
+ self._parts = path._parts
+
+ def __len__(self):
+ if self._drv or self._root:
+ return len(self._parts) - 1
+ else:
+ return len(self._parts)
+
+ def __getitem__(self, idx):
+ if idx < 0 or idx >= len(self):
+ raise IndexError(idx)
+ return self._pathcls._from_parsed_parts(self._drv, self._root,
+ self._parts[:-idx - 1])
+
+ def __repr__(self):
+ return "<{}.parents>".format(self._pathcls.__name__)
+
+
+class PurePath(object):
+ """Base class for manipulating paths without I/O.
+
+ PurePath represents a filesystem path and offers operations which
+ don't imply any actual filesystem I/O. Depending on your system,
+ instantiating a PurePath will return either a PurePosixPath or a
+ PureWindowsPath object. You can also instantiate either of these classes
+ directly, regardless of your system.
+ """
+ __slots__ = (
+ '_drv', '_root', '_parts',
+ '_str', '_hash', '_pparts', '_cached_cparts',
+ )
+
+ def __new__(cls, *args):
+ """Construct a PurePath from one or several strings and or existing
+ PurePath objects. The strings and path objects are combined so as
+ to yield a canonicalized path, which is incorporated into the
+ new PurePath object.
+ """
+ if cls is PurePath:
+ cls = PureWindowsPath if os.name == 'nt' else PurePosixPath
+ return cls._from_parts(args)
+
+ def __reduce__(self):
+ # Using the parts tuple helps share interned path parts
+ # when pickling related paths.
+ return (self.__class__, tuple(self._parts))
+
+ @classmethod
+ def _parse_args(cls, args):
+ # This is useful when you don't want to create an instance, just
+ # canonicalize some constructor arguments.
+ parts = []
+ for a in args:
+ if isinstance(a, PurePath):
+ parts += a._parts
+ else:
+ a = os.fspath(a)
+ if isinstance(a, str):
+ # Force-cast str subclasses to str (issue #21127)
+ parts.append(str(a))
+ else:
+ raise TypeError(
+ "argument should be a str object or an os.PathLike "
+ "object returning str, not %r"
+ % type(a))
+ return cls._flavour.parse_parts(parts)
+
+ @classmethod
+ def _from_parts(cls, args, init=True):
+ # We need to call _parse_args on the instance, so as to get the
+ # right flavour.
+ self = object.__new__(cls)
+ drv, root, parts = self._parse_args(args)
+ self._drv = drv
+ self._root = root
+ self._parts = parts
+ if init:
+ self._init()
+ return self
+
+ @classmethod
+ def _from_parsed_parts(cls, drv, root, parts, init=True):
+ self = object.__new__(cls)
+ self._drv = drv
+ self._root = root
+ self._parts = parts
+ if init:
+ self._init()
+ return self
+
+ @classmethod
+ def _format_parsed_parts(cls, drv, root, parts):
+ if drv or root:
+ return drv + root + cls._flavour.join(parts[1:])
+ else:
+ return cls._flavour.join(parts)
+
+ def _init(self):
+ # Overridden in concrete Path
+ pass
+
+ def _make_child(self, args):
+ drv, root, parts = self._parse_args(args)
+ drv, root, parts = self._flavour.join_parsed_parts(
+ self._drv, self._root, self._parts, drv, root, parts)
+ return self._from_parsed_parts(drv, root, parts)
+
+ def __str__(self):
+ """Return the string representation of the path, suitable for
+ passing to system calls."""
+ try:
+ return self._str
+ except AttributeError:
+ self._str = self._format_parsed_parts(self._drv, self._root,
+ self._parts) or '.'
+ return self._str
+
+ def __fspath__(self):
+ return str(self)
+
+ def as_posix(self):
+ """Return the string representation of the path with forward (/)
+ slashes."""
+ f = self._flavour
+ return str(self).replace(f.sep, '/')
+
+ def __bytes__(self):
+ """Return the bytes representation of the path. This is only
+ recommended to use under Unix."""
+ return os.fsencode(self)
+
+ def __repr__(self):
+ return "{}({!r})".format(self.__class__.__name__, self.as_posix())
+
+ def as_uri(self):
+ """Return the path as a 'file' URI."""
+ if not self.is_absolute():
+ raise ValueError("relative path can't be expressed as a file URI")
+ return self._flavour.make_uri(self)
+
+ @property
+ def _cparts(self):
+ # Cached casefolded parts, for hashing and comparison
+ try:
+ return self._cached_cparts
+ except AttributeError:
+ self._cached_cparts = self._flavour.casefold_parts(self._parts)
+ return self._cached_cparts
+
+ def __eq__(self, other):
+ if not isinstance(other, PurePath):
+ return NotImplemented
+ return self._cparts == other._cparts and self._flavour is other._flavour
+
+ def __hash__(self):
+ try:
+ return self._hash
+ except AttributeError:
+ self._hash = hash(tuple(self._cparts))
+ return self._hash
+
+ def __lt__(self, other):
+ if not isinstance(other, PurePath) or self._flavour is not other._flavour:
+ return NotImplemented
+ return self._cparts < other._cparts
+
+ def __le__(self, other):
+ if not isinstance(other, PurePath) or self._flavour is not other._flavour:
+ return NotImplemented
+ return self._cparts <= other._cparts
+
+ def __gt__(self, other):
+ if not isinstance(other, PurePath) or self._flavour is not other._flavour:
+ return NotImplemented
+ return self._cparts > other._cparts
+
+ def __ge__(self, other):
+ if not isinstance(other, PurePath) or self._flavour is not other._flavour:
+ return NotImplemented
+ return self._cparts >= other._cparts
+
+ drive = property(attrgetter('_drv'),
+ doc="""The drive prefix (letter or UNC path), if any.""")
+
+ root = property(attrgetter('_root'),
+ doc="""The root of the path, if any.""")
+
+ @property
+ def anchor(self):
+ """The concatenation of the drive and root, or ''."""
+ anchor = self._drv + self._root
+ return anchor
+
+ @property
+ def name(self):
+ """The final path component, if any."""
+ parts = self._parts
+ if len(parts) == (1 if (self._drv or self._root) else 0):
+ return ''
+ return parts[-1]
+
+ @property
+ def suffix(self):
+ """
+ The final component's last suffix, if any.
+
+ This includes the leading period. For example: '.txt'
+ """
+ name = self.name
+ i = name.rfind('.')
+ if 0 < i < len(name) - 1:
+ return name[i:]
+ else:
+ return ''
+
+ @property
+ def suffixes(self):
+ """
+ A list of the final component's suffixes, if any.
+
+ These include the leading periods. For example: ['.tar', '.gz']
+ """
+ name = self.name
+ if name.endswith('.'):
+ return []
+ name = name.lstrip('.')
+ return ['.' + suffix for suffix in name.split('.')[1:]]
+
+ @property
+ def stem(self):
+ """The final path component, minus its last suffix."""
+ name = self.name
+ i = name.rfind('.')
+ if 0 < i < len(name) - 1:
+ return name[:i]
+ else:
+ return name
+
+ def with_name(self, name):
+ """Return a new path with the file name changed."""
+ if not self.name:
+ raise ValueError("%r has an empty name" % (self,))
+ drv, root, parts = self._flavour.parse_parts((name,))
+ if (not name or name[-1] in [self._flavour.sep, self._flavour.altsep]
+ or drv or root or len(parts) != 1):
+ raise ValueError("Invalid name %r" % (name))
+ return self._from_parsed_parts(self._drv, self._root,
+ self._parts[:-1] + [name])
+
+ def with_suffix(self, suffix):
+ """Return a new path with the file suffix changed. If the path
+ has no suffix, add given suffix. If the given suffix is an empty
+ string, remove the suffix from the path.
+ """
+ f = self._flavour
+ if f.sep in suffix or f.altsep and f.altsep in suffix:
+ raise ValueError("Invalid suffix %r" % (suffix,))
+ if suffix and not suffix.startswith('.') or suffix == '.':
+ raise ValueError("Invalid suffix %r" % (suffix))
+ name = self.name
+ if not name:
+ raise ValueError("%r has an empty name" % (self,))
+ old_suffix = self.suffix
+ if not old_suffix:
+ name = name + suffix
+ else:
+ name = name[:-len(old_suffix)] + suffix
+ return self._from_parsed_parts(self._drv, self._root,
+ self._parts[:-1] + [name])
+
+ def relative_to(self, *other):
+ """Return the relative path to another path identified by the passed
+ arguments. If the operation is not possible (because this is not
+ a subpath of the other path), raise ValueError.
+ """
+ # For the purpose of this method, drive and root are considered
+ # separate parts, i.e.:
+ # Path('c:/').relative_to('c:') gives Path('/')
+ # Path('c:/').relative_to('/') raise ValueError
+ if not other:
+ raise TypeError("need at least one argument")
+ parts = self._parts
+ drv = self._drv
+ root = self._root
+ if root:
+ abs_parts = [drv, root] + parts[1:]
+ else:
+ abs_parts = parts
+ to_drv, to_root, to_parts = self._parse_args(other)
+ if to_root:
+ to_abs_parts = [to_drv, to_root] + to_parts[1:]
+ else:
+ to_abs_parts = to_parts
+ n = len(to_abs_parts)
+ cf = self._flavour.casefold_parts
+ if (root or drv) if n == 0 else cf(abs_parts[:n]) != cf(to_abs_parts):
+ formatted = self._format_parsed_parts(to_drv, to_root, to_parts)
+ raise ValueError("{!r} does not start with {!r}"
+ .format(str(self), str(formatted)))
+ return self._from_parsed_parts('', root if n == 1 else '',
+ abs_parts[n:])
+
+ @property
+ def parts(self):
+ """An object providing sequence-like access to the
+ components in the filesystem path."""
+ # We cache the tuple to avoid building a new one each time .parts
+ # is accessed. XXX is this necessary?
+ try:
+ return self._pparts
+ except AttributeError:
+ self._pparts = tuple(self._parts)
+ return self._pparts
+
+ def joinpath(self, *args):
+ """Combine this path with one or several arguments, and return a
+ new path representing either a subpath (if all arguments are relative
+ paths) or a totally different path (if one of the arguments is
+ anchored).
+ """
+ return self._make_child(args)
+
+ def __truediv__(self, key):
+ try:
+ return self._make_child((key,))
+ except TypeError:
+ return NotImplemented
+
+ def __rtruediv__(self, key):
+ try:
+ return self._from_parts([key] + self._parts)
+ except TypeError:
+ return NotImplemented
+
+ @property
+ def parent(self):
+ """The logical parent of the path."""
+ drv = self._drv
+ root = self._root
+ parts = self._parts
+ if len(parts) == 1 and (drv or root):
+ return self
+ return self._from_parsed_parts(drv, root, parts[:-1])
+
+ @property
+ def parents(self):
+ """A sequence of this path's logical parents."""
+ return _PathParents(self)
+
+ def is_absolute(self):
+ """True if the path is absolute (has both a root and, if applicable,
+ a drive)."""
+ if not self._root:
+ return False
+ return not self._flavour.has_drv or bool(self._drv)
+
+ def is_reserved(self):
+ """Return True if the path contains one of the special names reserved
+ by the system, if any."""
+ return self._flavour.is_reserved(self._parts)
+
+ def match(self, path_pattern):
+ """
+ Return True if this path matches the given pattern.
+ """
+ cf = self._flavour.casefold
+ path_pattern = cf(path_pattern)
+ drv, root, pat_parts = self._flavour.parse_parts((path_pattern,))
+ if not pat_parts:
+ raise ValueError("empty pattern")
+ if drv and drv != cf(self._drv):
+ return False
+ if root and root != cf(self._root):
+ return False
+ parts = self._cparts
+ if drv or root:
+ if len(pat_parts) != len(parts):
+ return False
+ pat_parts = pat_parts[1:]
+ elif len(pat_parts) > len(parts):
+ return False
+ for part, pat in zip(reversed(parts), reversed(pat_parts)):
+ if not fnmatch.fnmatchcase(part, pat):
+ return False
+ return True
+
+# Can't subclass os.PathLike from PurePath and keep the constructor
+# optimizations in PurePath._parse_args().
+os.PathLike.register(PurePath)
+
+
+class PurePosixPath(PurePath):
+ """PurePath subclass for non-Windows systems.
+
+ On a POSIX system, instantiating a PurePath should return this object.
+ However, you can also instantiate it directly on any system.
+ """
+ _flavour = _posix_flavour
+ __slots__ = ()
+
+
+class PureWindowsPath(PurePath):
+ """PurePath subclass for Windows systems.
+
+ On a Windows system, instantiating a PurePath should return this object.
+ However, you can also instantiate it directly on any system.
+ """
+ _flavour = _windows_flavour
+ __slots__ = ()
+
+
+# Filesystem-accessing classes
+
+
+class Path(PurePath):
+ """PurePath subclass that can make system calls.
+
+ Path represents a filesystem path but unlike PurePath, also offers
+ methods to do system calls on path objects. Depending on your system,
+ instantiating a Path will return either a PosixPath or a WindowsPath
+ object. You can also instantiate a PosixPath or WindowsPath directly,
+ but cannot instantiate a WindowsPath on a POSIX system or vice versa.
+ """
+ __slots__ = (
+ '_accessor',
+ '_closed',
+ )
+
+ def __new__(cls, *args, **kwargs):
+ if cls is Path:
+ cls = WindowsPath if os.name == 'nt' else PosixPath
+ self = cls._from_parts(args, init=False)
+ if not self._flavour.is_supported:
+ raise NotImplementedError("cannot instantiate %r on your system"
+ % (cls.__name__,))
+ self._init()
+ return self
+
+ def _init(self,
+ # Private non-constructor arguments
+ template=None,
+ ):
+ self._closed = False
+ if template is not None:
+ self._accessor = template._accessor
+ else:
+ self._accessor = _normal_accessor
+
+ def _make_child_relpath(self, part):
+ # This is an optimization used for dir walking. `part` must be
+ # a single part relative to this path.
+ parts = self._parts + [part]
+ return self._from_parsed_parts(self._drv, self._root, parts)
+
+ def __enter__(self):
+ if self._closed:
+ self._raise_closed()
+ return self
+
+ def __exit__(self, t, v, tb):
+ self._closed = True
+
+ def _raise_closed(self):
+ raise ValueError("I/O operation on closed path")
+
+ def _opener(self, name, flags, mode=0o666):
+ # A stub for the opener argument to built-in open()
+ return self._accessor.open(self, flags, mode)
+
+ def _raw_open(self, flags, mode=0o777):
+ """
+ Open the file pointed by this path and return a file descriptor,
+ as os.open() does.
+ """
+ if self._closed:
+ self._raise_closed()
+ return self._accessor.open(self, flags, mode)
+
+ # Public API
+
+ @classmethod
+ def cwd(cls):
+ """Return a new path pointing to the current working directory
+ (as returned by os.getcwd()).
+ """
+ return cls(os.getcwd())
+
+ @classmethod
+ def home(cls):
+ """Return a new path pointing to the user's home directory (as
+ returned by os.path.expanduser('~')).
+ """
+ return cls(cls()._flavour.gethomedir(None))
+
+ def samefile(self, other_path):
+ """Return whether other_path is the same or not as this file
+ (as returned by os.path.samefile()).
+ """
+ st = self.stat()
+ try:
+ other_st = other_path.stat()
+ except AttributeError:
+ other_st = os.stat(other_path)
+ return os.path.samestat(st, other_st)
+
+ def iterdir(self):
+ """Iterate over the files in this directory. Does not yield any
+ result for the special paths '.' and '..'.
+ """
+ if self._closed:
+ self._raise_closed()
+ for name in self._accessor.listdir(self):
+ if name in {'.', '..'}:
+ # Yielding a path object for these makes little sense
+ continue
+ yield self._make_child_relpath(name)
+ if self._closed:
+ self._raise_closed()
+
+ def glob(self, pattern):
+ """Iterate over this subtree and yield all existing files (of any
+ kind, including directories) matching the given relative pattern.
+ """
+ if not pattern:
+ raise ValueError("Unacceptable pattern: {!r}".format(pattern))
+ drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
+ if drv or root:
+ raise NotImplementedError("Non-relative patterns are unsupported")
+ selector = _make_selector(tuple(pattern_parts), self._flavour)
+ for p in selector.select_from(self):
+ yield p
+
+ def rglob(self, pattern):
+ """Recursively yield all existing files (of any kind, including
+ directories) matching the given relative pattern, anywhere in
+ this subtree.
+ """
+ drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
+ if drv or root:
+ raise NotImplementedError("Non-relative patterns are unsupported")
+ selector = _make_selector(("**",) + tuple(pattern_parts), self._flavour)
+ for p in selector.select_from(self):
+ yield p
+
+ def absolute(self):
+ """Return an absolute version of this path. This function works
+ even if the path doesn't point to anything.
+
+ No normalization is done, i.e. all '.' and '..' will be kept along.
+ Use resolve() to get the canonical path to a file.
+ """
+ # XXX untested yet!
+ if self._closed:
+ self._raise_closed()
+ if self.is_absolute():
+ return self
+ # FIXME this must defer to the specific flavour (and, under Windows,
+ # use nt._getfullpathname())
+ obj = self._from_parts([os.getcwd()] + self._parts, init=False)
+ obj._init(template=self)
+ return obj
+
+ def resolve(self, strict=False):
+ """
+ Make the path absolute, resolving all symlinks on the way and also
+ normalizing it (for example turning slashes into backslashes under
+ Windows).
+ """
+ if self._closed:
+ self._raise_closed()
+ s = self._flavour.resolve(self, strict=strict)
+ if s is None:
+ # No symlink resolution => for consistency, raise an error if
+ # the path doesn't exist or is forbidden
+ self.stat()
+ s = str(self.absolute())
+ # Now we have no symlinks in the path, it's safe to normalize it.
+ normed = self._flavour.pathmod.normpath(s)
+ obj = self._from_parts((normed,), init=False)
+ obj._init(template=self)
+ return obj
+
+ def stat(self):
+ """
+ Return the result of the stat() system call on this path, like
+ os.stat() does.
+ """
+ return self._accessor.stat(self)
+
+ def owner(self):
+ """
+ Return the login name of the file owner.
+ """
+ import pwd
+ return pwd.getpwuid(self.stat().st_uid).pw_name
+
+ def group(self):
+ """
+ Return the group name of the file gid.
+ """
+ import grp
+ return grp.getgrgid(self.stat().st_gid).gr_name
+
+ def open(self, mode='r', buffering=-1, encoding=None,
+ errors=None, newline=None):
+ """
+ Open the file pointed by this path and return a file object, as
+ the built-in open() function does.
+ """
+ if self._closed:
+ self._raise_closed()
+ return io.open(self, mode, buffering, encoding, errors, newline,
+ opener=self._opener)
+
+ def read_bytes(self):
+ """
+ Open the file in bytes mode, read it, and close the file.
+ """
+ with self.open(mode='rb') as f:
+ return f.read()
+
+ def read_text(self, encoding=None, errors=None):
+ """
+ Open the file in text mode, read it, and close the file.
+ """
+ with self.open(mode='r', encoding=encoding, errors=errors) as f:
+ return f.read()
+
+ def write_bytes(self, data):
+ """
+ Open the file in bytes mode, write to it, and close the file.
+ """
+ # type-check for the buffer interface before truncating the file
+ view = memoryview(data)
+ with self.open(mode='wb') as f:
+ return f.write(view)
+
+ def write_text(self, data, encoding=None, errors=None):
+ """
+ Open the file in text mode, write to it, and close the file.
+ """
+ if not isinstance(data, str):
+ raise TypeError('data must be str, not %s' %
+ data.__class__.__name__)
+ with self.open(mode='w', encoding=encoding, errors=errors) as f:
+ return f.write(data)
+
+ def touch(self, mode=0o666, exist_ok=True):
+ """
+ Create this file with the given access mode, if it doesn't exist.
+ """
+ if self._closed:
+ self._raise_closed()
+ if exist_ok:
+ # First try to bump modification time
+ # Implementation note: GNU touch uses the UTIME_NOW option of
+ # the utimensat() / futimens() functions.
+ try:
+ self._accessor.utime(self, None)
+ except OSError:
+ # Avoid exception chaining
+ pass
+ else:
+ return
+ flags = os.O_CREAT | os.O_WRONLY
+ if not exist_ok:
+ flags |= os.O_EXCL
+ fd = self._raw_open(flags, mode)
+ os.close(fd)
+
+ def mkdir(self, mode=0o777, parents=False, exist_ok=False):
+ """
+ Create a new directory at this given path.
+ """
+ if self._closed:
+ self._raise_closed()
+ try:
+ self._accessor.mkdir(self, mode)
+ except FileNotFoundError:
+ if not parents or self.parent == self:
+ raise
+ self.parent.mkdir(parents=True, exist_ok=True)
+ self.mkdir(mode, parents=False, exist_ok=exist_ok)
+ except OSError:
+ # Cannot rely on checking for EEXIST, since the operating system
+ # could give priority to other errors like EACCES or EROFS
+ if not exist_ok or not self.is_dir():
+ raise
+
+ def chmod(self, mode):
+ """
+ Change the permissions of the path, like os.chmod().
+ """
+ if self._closed:
+ self._raise_closed()
+ self._accessor.chmod(self, mode)
+
+ def lchmod(self, mode):
+ """
+ Like chmod(), except if the path points to a symlink, the symlink's
+ permissions are changed, rather than its target's.
+ """
+ if self._closed:
+ self._raise_closed()
+ self._accessor.lchmod(self, mode)
+
+ def unlink(self, missing_ok=False):
+ """
+ Remove this file or link.
+ If the path is a directory, use rmdir() instead.
+ """
+ if self._closed:
+ self._raise_closed()
+ try:
+ self._accessor.unlink(self)
+ except FileNotFoundError:
+ if not missing_ok:
+ raise
+
+ def rmdir(self):
+ """
+ Remove this directory. The directory must be empty.
+ """
+ if self._closed:
+ self._raise_closed()
+ self._accessor.rmdir(self)
+
+ def lstat(self):
+ """
+ Like stat(), except if the path points to a symlink, the symlink's
+ status information is returned, rather than its target's.
+ """
+ if self._closed:
+ self._raise_closed()
+ return self._accessor.lstat(self)
+
+ def rename(self, target):
+ """
+ Rename this path to the target path.
+
+ The target path may be absolute or relative. Relative paths are
+ interpreted relative to the current working directory, *not* the
+ directory of the Path object.
+
+ Returns the new Path instance pointing to the target path.
+ """
+ if self._closed:
+ self._raise_closed()
+ self._accessor.rename(self, target)
+ return self.__class__(target)
+
+ def replace(self, target):
+ """
+ Rename this path to the target path, overwriting if that path exists.
+
+ The target path may be absolute or relative. Relative paths are
+ interpreted relative to the current working directory, *not* the
+ directory of the Path object.
+
+ Returns the new Path instance pointing to the target path.
+ """
+ if self._closed:
+ self._raise_closed()
+ self._accessor.replace(self, target)
+ return self.__class__(target)
+
+ def symlink_to(self, target, target_is_directory=False):
+ """
+ Make this path a symlink pointing to the target path.
+ Note the order of arguments (link, target) is the reverse of os.symlink.
+ """
+ if self._closed:
+ self._raise_closed()
+ self._accessor.symlink(target, self, target_is_directory)
+
+ def link_to(self, target):
+ """
+ Make the target path a hard link pointing to this path.
+
+ Note this function does not make this path a hard link to *target*,
+ despite the implication of the function and argument names. The order
+ of arguments (target, link) is the reverse of Path.symlink_to, but
+ matches that of os.link.
+
+ """
+ if self._closed:
+ self._raise_closed()
+ self._accessor.link_to(self, target)
+
+ # Convenience functions for querying the stat results
+
+ def exists(self):
+ """
+ Whether this path exists.
+ """
+ try:
+ self.stat()
+ except OSError as e:
+ if not _ignore_error(e):
+ raise
+ return False
+ except ValueError:
+ # Non-encodable path
+ return False
+ return True
+
+ def is_dir(self):
+ """
+ Whether this path is a directory.
+ """
+ try:
+ return S_ISDIR(self.stat().st_mode)
+ except OSError as e:
+ if not _ignore_error(e):
+ raise
+ # Path doesn't exist or is a broken symlink
+ # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
+ return False
+ except ValueError:
+ # Non-encodable path
+ return False
+
+ def is_file(self):
+ """
+ Whether this path is a regular file (also True for symlinks pointing
+ to regular files).
+ """
+ try:
+ return S_ISREG(self.stat().st_mode)
+ except OSError as e:
+ if not _ignore_error(e):
+ raise
+ # Path doesn't exist or is a broken symlink
+ # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
+ return False
+ except ValueError:
+ # Non-encodable path
+ return False
+
+ def is_mount(self):
+ """
+ Check if this path is a POSIX mount point
+ """
+ # Need to exist and be a dir
+ if not self.exists() or not self.is_dir():
+ return False
+
+ parent = Path(self.parent)
+ try:
+ parent_dev = parent.stat().st_dev
+ except OSError:
+ return False
+
+ dev = self.stat().st_dev
+ if dev != parent_dev:
+ return True
+ ino = self.stat().st_ino
+ parent_ino = parent.stat().st_ino
+ return ino == parent_ino
+
+ def is_symlink(self):
+ """
+ Whether this path is a symbolic link.
+ """
+ try:
+ return S_ISLNK(self.lstat().st_mode)
+ except OSError as e:
+ if not _ignore_error(e):
+ raise
+ # Path doesn't exist
+ return False
+ except ValueError:
+ # Non-encodable path
+ return False
+
+ def is_block_device(self):
+ """
+ Whether this path is a block device.
+ """
+ try:
+ return S_ISBLK(self.stat().st_mode)
+ except OSError as e:
+ if not _ignore_error(e):
+ raise
+ # Path doesn't exist or is a broken symlink
+ # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
+ return False
+ except ValueError:
+ # Non-encodable path
+ return False
+
+ def is_char_device(self):
+ """
+ Whether this path is a character device.
+ """
+ try:
+ return S_ISCHR(self.stat().st_mode)
+ except OSError as e:
+ if not _ignore_error(e):
+ raise
+ # Path doesn't exist or is a broken symlink
+ # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
+ return False
+ except ValueError:
+ # Non-encodable path
+ return False
+
+ def is_fifo(self):
+ """
+ Whether this path is a FIFO.
+ """
+ try:
+ return S_ISFIFO(self.stat().st_mode)
+ except OSError as e:
+ if not _ignore_error(e):
+ raise
+ # Path doesn't exist or is a broken symlink
+ # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
+ return False
+ except ValueError:
+ # Non-encodable path
+ return False
+
+ def is_socket(self):
+ """
+ Whether this path is a socket.
+ """
+ try:
+ return S_ISSOCK(self.stat().st_mode)
+ except OSError as e:
+ if not _ignore_error(e):
+ raise
+ # Path doesn't exist or is a broken symlink
+ # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
+ return False
+ except ValueError:
+ # Non-encodable path
+ return False
+
+ def expanduser(self):
+ """ Return a new path with expanded ~ and ~user constructs
+ (as returned by os.path.expanduser)
+ """
+ if (not (self._drv or self._root) and
+ self._parts and self._parts[0][:1] == '~'):
+ homedir = self._flavour.gethomedir(self._parts[0][1:])
+ return self._from_parts([homedir] + self._parts[1:])
+
+ return self
+
+
+class PosixPath(Path, PurePosixPath):
+ """Path subclass for non-Windows systems.
+
+ On a POSIX system, instantiating a Path should return this object.
+ """
+ __slots__ = ()
+
+class WindowsPath(Path, PureWindowsPath):
+ """Path subclass for Windows systems.
+
+ On a Windows system, instantiating a Path should return this object.
+ """
+ __slots__ = ()
+
+ def owner(self):
+ raise NotImplementedError("Path.owner() is unsupported on this system")
+
+ def group(self):
+ raise NotImplementedError("Path.group() is unsupported on this system")
+
+ def is_mount(self):
+ raise NotImplementedError("Path.is_mount() is unsupported on this system")
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/pickle.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/pickle.py
new file mode 100644
index 0000000000000000000000000000000000000000..05f30b6b168b5cb8961a2a1e55d3a0341b8b3816
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/pickle.py
@@ -0,0 +1,1807 @@
+"""Create portable serialized representations of Python objects.
+
+See module copyreg for a mechanism for registering custom picklers.
+See module pickletools source for extensive comments.
+
+Classes:
+
+ Pickler
+ Unpickler
+
+Functions:
+
+ dump(object, file)
+ dumps(object) -> string
+ load(file) -> object
+ loads(string) -> object
+
+Misc variables:
+
+ __version__
+ format_version
+ compatible_formats
+
+"""
+
+from types import FunctionType
+from copyreg import dispatch_table
+from copyreg import _extension_registry, _inverted_registry, _extension_cache
+from itertools import islice
+from functools import partial
+import sys
+from sys import maxsize
+from struct import pack, unpack
+import re
+import io
+import codecs
+import _compat_pickle
+
+__all__ = ["PickleError", "PicklingError", "UnpicklingError", "Pickler",
+ "Unpickler", "dump", "dumps", "load", "loads"]
+
+try:
+ from _pickle import PickleBuffer
+ __all__.append("PickleBuffer")
+ _HAVE_PICKLE_BUFFER = True
+except ImportError:
+ _HAVE_PICKLE_BUFFER = False
+
+
+# Shortcut for use in isinstance testing
+bytes_types = (bytes, bytearray)
+
+# These are purely informational; no code uses these.
+format_version = "4.0" # File format version we write
+compatible_formats = ["1.0", # Original protocol 0
+ "1.1", # Protocol 0 with INST added
+ "1.2", # Original protocol 1
+ "1.3", # Protocol 1 with BINFLOAT added
+ "2.0", # Protocol 2
+ "3.0", # Protocol 3
+ "4.0", # Protocol 4
+ "5.0", # Protocol 5
+ ] # Old format versions we can read
+
+# This is the highest protocol number we know how to read.
+HIGHEST_PROTOCOL = 5
+
+# The protocol we write by default. May be less than HIGHEST_PROTOCOL.
+# Only bump this if the oldest still supported version of Python already
+# includes it.
+DEFAULT_PROTOCOL = 4
+
+class PickleError(Exception):
+ """A common base class for the other pickling exceptions."""
+ pass
+
+class PicklingError(PickleError):
+ """This exception is raised when an unpicklable object is passed to the
+ dump() method.
+
+ """
+ pass
+
+class UnpicklingError(PickleError):
+ """This exception is raised when there is a problem unpickling an object,
+ such as a security violation.
+
+ Note that other exceptions may also be raised during unpickling, including
+ (but not necessarily limited to) AttributeError, EOFError, ImportError,
+ and IndexError.
+
+ """
+ pass
+
+# An instance of _Stop is raised by Unpickler.load_stop() in response to
+# the STOP opcode, passing the object that is the result of unpickling.
+class _Stop(Exception):
+ def __init__(self, value):
+ self.value = value
+
+# Jython has PyStringMap; it's a dict subclass with string keys
+try:
+ from org.python.core import PyStringMap
+except ImportError:
+ PyStringMap = None
+
+# Pickle opcodes. See pickletools.py for extensive docs. The listing
+# here is in kind-of alphabetical order of 1-character pickle code.
+# pickletools groups them by purpose.
+
+MARK = b'(' # push special markobject on stack
+STOP = b'.' # every pickle ends with STOP
+POP = b'0' # discard topmost stack item
+POP_MARK = b'1' # discard stack top through topmost markobject
+DUP = b'2' # duplicate top stack item
+FLOAT = b'F' # push float object; decimal string argument
+INT = b'I' # push integer or bool; decimal string argument
+BININT = b'J' # push four-byte signed int
+BININT1 = b'K' # push 1-byte unsigned int
+LONG = b'L' # push long; decimal string argument
+BININT2 = b'M' # push 2-byte unsigned int
+NONE = b'N' # push None
+PERSID = b'P' # push persistent object; id is taken from string arg
+BINPERSID = b'Q' # " " " ; " " " " stack
+REDUCE = b'R' # apply callable to argtuple, both on stack
+STRING = b'S' # push string; NL-terminated string argument
+BINSTRING = b'T' # push string; counted binary string argument
+SHORT_BINSTRING= b'U' # " " ; " " " " < 256 bytes
+UNICODE = b'V' # push Unicode string; raw-unicode-escaped'd argument
+BINUNICODE = b'X' # " " " ; counted UTF-8 string argument
+APPEND = b'a' # append stack top to list below it
+BUILD = b'b' # call __setstate__ or __dict__.update()
+GLOBAL = b'c' # push self.find_class(modname, name); 2 string args
+DICT = b'd' # build a dict from stack items
+EMPTY_DICT = b'}' # push empty dict
+APPENDS = b'e' # extend list on stack by topmost stack slice
+GET = b'g' # push item from memo on stack; index is string arg
+BINGET = b'h' # " " " " " " ; " " 1-byte arg
+INST = b'i' # build & push class instance
+LONG_BINGET = b'j' # push item from memo on stack; index is 4-byte arg
+LIST = b'l' # build list from topmost stack items
+EMPTY_LIST = b']' # push empty list
+OBJ = b'o' # build & push class instance
+PUT = b'p' # store stack top in memo; index is string arg
+BINPUT = b'q' # " " " " " ; " " 1-byte arg
+LONG_BINPUT = b'r' # " " " " " ; " " 4-byte arg
+SETITEM = b's' # add key+value pair to dict
+TUPLE = b't' # build tuple from topmost stack items
+EMPTY_TUPLE = b')' # push empty tuple
+SETITEMS = b'u' # modify dict by adding topmost key+value pairs
+BINFLOAT = b'G' # push float; arg is 8-byte float encoding
+
+TRUE = b'I01\n' # not an opcode; see INT docs in pickletools.py
+FALSE = b'I00\n' # not an opcode; see INT docs in pickletools.py
+
+# Protocol 2
+
+PROTO = b'\x80' # identify pickle protocol
+NEWOBJ = b'\x81' # build object by applying cls.__new__ to argtuple
+EXT1 = b'\x82' # push object from extension registry; 1-byte index
+EXT2 = b'\x83' # ditto, but 2-byte index
+EXT4 = b'\x84' # ditto, but 4-byte index
+TUPLE1 = b'\x85' # build 1-tuple from stack top
+TUPLE2 = b'\x86' # build 2-tuple from two topmost stack items
+TUPLE3 = b'\x87' # build 3-tuple from three topmost stack items
+NEWTRUE = b'\x88' # push True
+NEWFALSE = b'\x89' # push False
+LONG1 = b'\x8a' # push long from < 256 bytes
+LONG4 = b'\x8b' # push really big long
+
+_tuplesize2code = [EMPTY_TUPLE, TUPLE1, TUPLE2, TUPLE3]
+
+# Protocol 3 (Python 3.x)
+
+BINBYTES = b'B' # push bytes; counted binary string argument
+SHORT_BINBYTES = b'C' # " " ; " " " " < 256 bytes
+
+# Protocol 4
+
+SHORT_BINUNICODE = b'\x8c' # push short string; UTF-8 length < 256 bytes
+BINUNICODE8 = b'\x8d' # push very long string
+BINBYTES8 = b'\x8e' # push very long bytes string
+EMPTY_SET = b'\x8f' # push empty set on the stack
+ADDITEMS = b'\x90' # modify set by adding topmost stack items
+FROZENSET = b'\x91' # build frozenset from topmost stack items
+NEWOBJ_EX = b'\x92' # like NEWOBJ but work with keyword only arguments
+STACK_GLOBAL = b'\x93' # same as GLOBAL but using names on the stacks
+MEMOIZE = b'\x94' # store top of the stack in memo
+FRAME = b'\x95' # indicate the beginning of a new frame
+
+# Protocol 5
+
+BYTEARRAY8 = b'\x96' # push bytearray
+NEXT_BUFFER = b'\x97' # push next out-of-band buffer
+READONLY_BUFFER = b'\x98' # make top of stack readonly
+
+__all__.extend([x for x in dir() if re.match("[A-Z][A-Z0-9_]+$", x)])
+
+
+class _Framer:
+
+ _FRAME_SIZE_MIN = 4
+ _FRAME_SIZE_TARGET = 64 * 1024
+
+ def __init__(self, file_write):
+ self.file_write = file_write
+ self.current_frame = None
+
+ def start_framing(self):
+ self.current_frame = io.BytesIO()
+
+ def end_framing(self):
+ if self.current_frame and self.current_frame.tell() > 0:
+ self.commit_frame(force=True)
+ self.current_frame = None
+
+ def commit_frame(self, force=False):
+ if self.current_frame:
+ f = self.current_frame
+ if f.tell() >= self._FRAME_SIZE_TARGET or force:
+ data = f.getbuffer()
+ write = self.file_write
+ if len(data) >= self._FRAME_SIZE_MIN:
+ # Issue a single call to the write method of the underlying
+ # file object for the frame opcode with the size of the
+ # frame. The concatenation is expected to be less expensive
+ # than issuing an additional call to write.
+ write(FRAME + pack("':
+ raise AttributeError("Can't get local attribute {!r} on {!r}"
+ .format(name, obj))
+ try:
+ parent = obj
+ obj = getattr(obj, subpath)
+ except AttributeError:
+ raise AttributeError("Can't get attribute {!r} on {!r}"
+ .format(name, obj)) from None
+ return obj, parent
+
+def whichmodule(obj, name):
+ """Find the module an object belong to."""
+ module_name = getattr(obj, '__module__', None)
+ if module_name is not None:
+ return module_name
+ # Protect the iteration by using a list copy of sys.modules against dynamic
+ # modules that trigger imports of other modules upon calls to getattr.
+ for module_name, module in sys.modules.copy().items():
+ if (module_name == '__main__'
+ or module_name == '__mp_main__' # bpo-42406
+ or module is None):
+ continue
+ try:
+ if _getattribute(module, name)[0] is obj:
+ return module_name
+ except AttributeError:
+ pass
+ return '__main__'
+
+def encode_long(x):
+ r"""Encode a long to a two's complement little-endian binary string.
+ Note that 0 is a special case, returning an empty string, to save a
+ byte in the LONG1 pickling context.
+
+ >>> encode_long(0)
+ b''
+ >>> encode_long(255)
+ b'\xff\x00'
+ >>> encode_long(32767)
+ b'\xff\x7f'
+ >>> encode_long(-256)
+ b'\x00\xff'
+ >>> encode_long(-32768)
+ b'\x00\x80'
+ >>> encode_long(-128)
+ b'\x80'
+ >>> encode_long(127)
+ b'\x7f'
+ >>>
+ """
+ if x == 0:
+ return b''
+ nbytes = (x.bit_length() >> 3) + 1
+ result = x.to_bytes(nbytes, byteorder='little', signed=True)
+ if x < 0 and nbytes > 1:
+ if result[-1] == 0xff and (result[-2] & 0x80) != 0:
+ result = result[:-1]
+ return result
+
+def decode_long(data):
+ r"""Decode a long from a two's complement little-endian binary string.
+
+ >>> decode_long(b'')
+ 0
+ >>> decode_long(b"\xff\x00")
+ 255
+ >>> decode_long(b"\xff\x7f")
+ 32767
+ >>> decode_long(b"\x00\xff")
+ -256
+ >>> decode_long(b"\x00\x80")
+ -32768
+ >>> decode_long(b"\x80")
+ -128
+ >>> decode_long(b"\x7f")
+ 127
+ """
+ return int.from_bytes(data, byteorder='little', signed=True)
+
+
+# Pickling machinery
+
+class _Pickler:
+
+ def __init__(self, file, protocol=None, *, fix_imports=True,
+ buffer_callback=None):
+ """This takes a binary file for writing a pickle data stream.
+
+ The optional *protocol* argument tells the pickler to use the
+ given protocol; supported protocols are 0, 1, 2, 3, 4 and 5.
+ The default protocol is 4. It was introduced in Python 3.4, and
+ is incompatible with previous versions.
+
+ Specifying a negative protocol version selects the highest
+ protocol version supported. The higher the protocol used, the
+ more recent the version of Python needed to read the pickle
+ produced.
+
+ The *file* argument must have a write() method that accepts a
+ single bytes argument. It can thus be a file object opened for
+ binary writing, an io.BytesIO instance, or any other custom
+ object that meets this interface.
+
+ If *fix_imports* is True and *protocol* is less than 3, pickle
+ will try to map the new Python 3 names to the old module names
+ used in Python 2, so that the pickle data stream is readable
+ with Python 2.
+
+ If *buffer_callback* is None (the default), buffer views are
+ serialized into *file* as part of the pickle stream.
+
+ If *buffer_callback* is not None, then it can be called any number
+ of times with a buffer view. If the callback returns a false value
+ (such as None), the given buffer is out-of-band; otherwise the
+ buffer is serialized in-band, i.e. inside the pickle stream.
+
+ It is an error if *buffer_callback* is not None and *protocol*
+ is None or smaller than 5.
+ """
+ if protocol is None:
+ protocol = DEFAULT_PROTOCOL
+ if protocol < 0:
+ protocol = HIGHEST_PROTOCOL
+ elif not 0 <= protocol <= HIGHEST_PROTOCOL:
+ raise ValueError("pickle protocol must be <= %d" % HIGHEST_PROTOCOL)
+ if buffer_callback is not None and protocol < 5:
+ raise ValueError("buffer_callback needs protocol >= 5")
+ self._buffer_callback = buffer_callback
+ try:
+ self._file_write = file.write
+ except AttributeError:
+ raise TypeError("file must have a 'write' attribute")
+ self.framer = _Framer(self._file_write)
+ self.write = self.framer.write
+ self._write_large_bytes = self.framer.write_large_bytes
+ self.memo = {}
+ self.proto = int(protocol)
+ self.bin = protocol >= 1
+ self.fast = 0
+ self.fix_imports = fix_imports and protocol < 3
+
+ def clear_memo(self):
+ """Clears the pickler's "memo".
+
+ The memo is the data structure that remembers which objects the
+ pickler has already seen, so that shared or recursive objects
+ are pickled by reference and not by value. This method is
+ useful when re-using picklers.
+ """
+ self.memo.clear()
+
+ def dump(self, obj):
+ """Write a pickled representation of obj to the open file."""
+ # Check whether Pickler was initialized correctly. This is
+ # only needed to mimic the behavior of _pickle.Pickler.dump().
+ if not hasattr(self, "_file_write"):
+ raise PicklingError("Pickler.__init__() was not called by "
+ "%s.__init__()" % (self.__class__.__name__,))
+ if self.proto >= 2:
+ self.write(PROTO + pack("= 4:
+ self.framer.start_framing()
+ self.save(obj)
+ self.write(STOP)
+ self.framer.end_framing()
+
+ def memoize(self, obj):
+ """Store an object in the memo."""
+
+ # The Pickler memo is a dictionary mapping object ids to 2-tuples
+ # that contain the Unpickler memo key and the object being memoized.
+ # The memo key is written to the pickle and will become
+ # the key in the Unpickler's memo. The object is stored in the
+ # Pickler memo so that transient objects are kept alive during
+ # pickling.
+
+ # The use of the Unpickler memo length as the memo key is just a
+ # convention. The only requirement is that the memo values be unique.
+ # But there appears no advantage to any other scheme, and this
+ # scheme allows the Unpickler memo to be implemented as a plain (but
+ # growable) array, indexed by memo key.
+ if self.fast:
+ return
+ assert id(obj) not in self.memo
+ idx = len(self.memo)
+ self.write(self.put(idx))
+ self.memo[id(obj)] = idx, obj
+
+ # Return a PUT (BINPUT, LONG_BINPUT) opcode string, with argument i.
+ def put(self, idx):
+ if self.proto >= 4:
+ return MEMOIZE
+ elif self.bin:
+ if idx < 256:
+ return BINPUT + pack("= 2 and func_name == "__newobj_ex__":
+ cls, args, kwargs = args
+ if not hasattr(cls, "__new__"):
+ raise PicklingError("args[0] from {} args has no __new__"
+ .format(func_name))
+ if obj is not None and cls is not obj.__class__:
+ raise PicklingError("args[0] from {} args has the wrong class"
+ .format(func_name))
+ if self.proto >= 4:
+ save(cls)
+ save(args)
+ save(kwargs)
+ write(NEWOBJ_EX)
+ else:
+ func = partial(cls.__new__, cls, *args, **kwargs)
+ save(func)
+ save(())
+ write(REDUCE)
+ elif self.proto >= 2 and func_name == "__newobj__":
+ # A __reduce__ implementation can direct protocol 2 or newer to
+ # use the more efficient NEWOBJ opcode, while still
+ # allowing protocol 0 and 1 to work normally. For this to
+ # work, the function returned by __reduce__ should be
+ # called __newobj__, and its first argument should be a
+ # class. The implementation for __newobj__
+ # should be as follows, although pickle has no way to
+ # verify this:
+ #
+ # def __newobj__(cls, *args):
+ # return cls.__new__(cls, *args)
+ #
+ # Protocols 0 and 1 will pickle a reference to __newobj__,
+ # while protocol 2 (and above) will pickle a reference to
+ # cls, the remaining args tuple, and the NEWOBJ code,
+ # which calls cls.__new__(cls, *args) at unpickling time
+ # (see load_newobj below). If __reduce__ returns a
+ # three-tuple, the state from the third tuple item will be
+ # pickled regardless of the protocol, calling __setstate__
+ # at unpickling time (see load_build below).
+ #
+ # Note that no standard __newobj__ implementation exists;
+ # you have to provide your own. This is to enforce
+ # compatibility with Python 2.2 (pickles written using
+ # protocol 0 or 1 in Python 2.3 should be unpicklable by
+ # Python 2.2).
+ cls = args[0]
+ if not hasattr(cls, "__new__"):
+ raise PicklingError(
+ "args[0] from __newobj__ args has no __new__")
+ if obj is not None and cls is not obj.__class__:
+ raise PicklingError(
+ "args[0] from __newobj__ args has the wrong class")
+ args = args[1:]
+ save(cls)
+ save(args)
+ write(NEWOBJ)
+ else:
+ save(func)
+ save(args)
+ write(REDUCE)
+
+ if obj is not None:
+ # If the object is already in the memo, this means it is
+ # recursive. In this case, throw away everything we put on the
+ # stack, and fetch the object back from the memo.
+ if id(obj) in self.memo:
+ write(POP + self.get(self.memo[id(obj)][0]))
+ else:
+ self.memoize(obj)
+
+ # More new special cases (that work with older protocols as
+ # well): when __reduce__ returns a tuple with 4 or 5 items,
+ # the 4th and 5th item should be iterators that provide list
+ # items and dict items (as (key, value) tuples), or None.
+
+ if listitems is not None:
+ self._batch_appends(listitems)
+
+ if dictitems is not None:
+ self._batch_setitems(dictitems)
+
+ if state is not None:
+ if state_setter is None:
+ save(state)
+ write(BUILD)
+ else:
+ # If a state_setter is specified, call it instead of load_build
+ # to update obj's with its previous state.
+ # First, push state_setter and its tuple of expected arguments
+ # (obj, state) onto the stack.
+ save(state_setter)
+ save(obj) # simple BINGET opcode as obj is already memoized.
+ save(state)
+ write(TUPLE2)
+ # Trigger a state_setter(obj, state) function call.
+ write(REDUCE)
+ # The purpose of state_setter is to carry-out an
+ # inplace modification of obj. We do not care about what the
+ # method might return, so its output is eventually removed from
+ # the stack.
+ write(POP)
+
+ # Methods below this point are dispatched through the dispatch table
+
+ dispatch = {}
+
+ def save_none(self, obj):
+ self.write(NONE)
+ dispatch[type(None)] = save_none
+
+ def save_bool(self, obj):
+ if self.proto >= 2:
+ self.write(NEWTRUE if obj else NEWFALSE)
+ else:
+ self.write(TRUE if obj else FALSE)
+ dispatch[bool] = save_bool
+
+ def save_long(self, obj):
+ if self.bin:
+ # If the int is small enough to fit in a signed 4-byte 2's-comp
+ # format, we can store it more efficiently than the general
+ # case.
+ # First one- and two-byte unsigned ints:
+ if obj >= 0:
+ if obj <= 0xff:
+ self.write(BININT1 + pack("= 2:
+ encoded = encode_long(obj)
+ n = len(encoded)
+ if n < 256:
+ self.write(LONG1 + pack("d', obj))
+ else:
+ self.write(FLOAT + repr(obj).encode("ascii") + b'\n')
+ dispatch[float] = save_float
+
+ def save_bytes(self, obj):
+ if self.proto < 3:
+ if not obj: # bytes object is empty
+ self.save_reduce(bytes, (), obj=obj)
+ else:
+ self.save_reduce(codecs.encode,
+ (str(obj, 'latin1'), 'latin1'), obj=obj)
+ return
+ n = len(obj)
+ if n <= 0xff:
+ self.write(SHORT_BINBYTES + pack(" 0xffffffff and self.proto >= 4:
+ self._write_large_bytes(BINBYTES8 + pack("= self.framer._FRAME_SIZE_TARGET:
+ self._write_large_bytes(BINBYTES + pack("= self.framer._FRAME_SIZE_TARGET:
+ self._write_large_bytes(BYTEARRAY8 + pack("= 5")
+ with obj.raw() as m:
+ if not m.contiguous:
+ raise PicklingError("PickleBuffer can not be pickled when "
+ "pointing to a non-contiguous buffer")
+ in_band = True
+ if self._buffer_callback is not None:
+ in_band = bool(self._buffer_callback(obj))
+ if in_band:
+ # Write data in-band
+ # XXX The C implementation avoids a copy here
+ if m.readonly:
+ self.save_bytes(m.tobytes())
+ else:
+ self.save_bytearray(m.tobytes())
+ else:
+ # Write data out-of-band
+ self.write(NEXT_BUFFER)
+ if m.readonly:
+ self.write(READONLY_BUFFER)
+
+ dispatch[PickleBuffer] = save_picklebuffer
+
+ def save_str(self, obj):
+ if self.bin:
+ encoded = obj.encode('utf-8', 'surrogatepass')
+ n = len(encoded)
+ if n <= 0xff and self.proto >= 4:
+ self.write(SHORT_BINUNICODE + pack(" 0xffffffff and self.proto >= 4:
+ self._write_large_bytes(BINUNICODE8 + pack("= self.framer._FRAME_SIZE_TARGET:
+ self._write_large_bytes(BINUNICODE + pack("= 2:
+ for element in obj:
+ save(element)
+ # Subtle. Same as in the big comment below.
+ if id(obj) in memo:
+ get = self.get(memo[id(obj)][0])
+ self.write(POP * n + get)
+ else:
+ self.write(_tuplesize2code[n])
+ self.memoize(obj)
+ return
+
+ # proto 0 or proto 1 and tuple isn't empty, or proto > 1 and tuple
+ # has more than 3 elements.
+ write = self.write
+ write(MARK)
+ for element in obj:
+ save(element)
+
+ if id(obj) in memo:
+ # Subtle. d was not in memo when we entered save_tuple(), so
+ # the process of saving the tuple's elements must have saved
+ # the tuple itself: the tuple is recursive. The proper action
+ # now is to throw away everything we put on the stack, and
+ # simply GET the tuple (it's already constructed). This check
+ # could have been done in the "for element" loop instead, but
+ # recursive tuples are a rare thing.
+ get = self.get(memo[id(obj)][0])
+ if self.bin:
+ write(POP_MARK + get)
+ else: # proto 0 -- POP_MARK not available
+ write(POP * (n+1) + get)
+ return
+
+ # No recursion.
+ write(TUPLE)
+ self.memoize(obj)
+
+ dispatch[tuple] = save_tuple
+
+ def save_list(self, obj):
+ if self.bin:
+ self.write(EMPTY_LIST)
+ else: # proto 0 -- can't use EMPTY_LIST
+ self.write(MARK + LIST)
+
+ self.memoize(obj)
+ self._batch_appends(obj)
+
+ dispatch[list] = save_list
+
+ _BATCHSIZE = 1000
+
+ def _batch_appends(self, items):
+ # Helper to batch up APPENDS sequences
+ save = self.save
+ write = self.write
+
+ if not self.bin:
+ for x in items:
+ save(x)
+ write(APPEND)
+ return
+
+ it = iter(items)
+ while True:
+ tmp = list(islice(it, self._BATCHSIZE))
+ n = len(tmp)
+ if n > 1:
+ write(MARK)
+ for x in tmp:
+ save(x)
+ write(APPENDS)
+ elif n:
+ save(tmp[0])
+ write(APPEND)
+ # else tmp is empty, and we're done
+ if n < self._BATCHSIZE:
+ return
+
+ def save_dict(self, obj):
+ if self.bin:
+ self.write(EMPTY_DICT)
+ else: # proto 0 -- can't use EMPTY_DICT
+ self.write(MARK + DICT)
+
+ self.memoize(obj)
+ self._batch_setitems(obj.items())
+
+ dispatch[dict] = save_dict
+ if PyStringMap is not None:
+ dispatch[PyStringMap] = save_dict
+
+ def _batch_setitems(self, items):
+ # Helper to batch up SETITEMS sequences; proto >= 1 only
+ save = self.save
+ write = self.write
+
+ if not self.bin:
+ for k, v in items:
+ save(k)
+ save(v)
+ write(SETITEM)
+ return
+
+ it = iter(items)
+ while True:
+ tmp = list(islice(it, self._BATCHSIZE))
+ n = len(tmp)
+ if n > 1:
+ write(MARK)
+ for k, v in tmp:
+ save(k)
+ save(v)
+ write(SETITEMS)
+ elif n:
+ k, v = tmp[0]
+ save(k)
+ save(v)
+ write(SETITEM)
+ # else tmp is empty, and we're done
+ if n < self._BATCHSIZE:
+ return
+
+ def save_set(self, obj):
+ save = self.save
+ write = self.write
+
+ if self.proto < 4:
+ self.save_reduce(set, (list(obj),), obj=obj)
+ return
+
+ write(EMPTY_SET)
+ self.memoize(obj)
+
+ it = iter(obj)
+ while True:
+ batch = list(islice(it, self._BATCHSIZE))
+ n = len(batch)
+ if n > 0:
+ write(MARK)
+ for item in batch:
+ save(item)
+ write(ADDITEMS)
+ if n < self._BATCHSIZE:
+ return
+ dispatch[set] = save_set
+
+ def save_frozenset(self, obj):
+ save = self.save
+ write = self.write
+
+ if self.proto < 4:
+ self.save_reduce(frozenset, (list(obj),), obj=obj)
+ return
+
+ write(MARK)
+ for item in obj:
+ save(item)
+
+ if id(obj) in self.memo:
+ # If the object is already in the memo, this means it is
+ # recursive. In this case, throw away everything we put on the
+ # stack, and fetch the object back from the memo.
+ write(POP_MARK + self.get(self.memo[id(obj)][0]))
+ return
+
+ write(FROZENSET)
+ self.memoize(obj)
+ dispatch[frozenset] = save_frozenset
+
+ def save_global(self, obj, name=None):
+ write = self.write
+ memo = self.memo
+
+ if name is None:
+ name = getattr(obj, '__qualname__', None)
+ if name is None:
+ name = obj.__name__
+
+ module_name = whichmodule(obj, name)
+ try:
+ __import__(module_name, level=0)
+ module = sys.modules[module_name]
+ obj2, parent = _getattribute(module, name)
+ except (ImportError, KeyError, AttributeError):
+ raise PicklingError(
+ "Can't pickle %r: it's not found as %s.%s" %
+ (obj, module_name, name)) from None
+ else:
+ if obj2 is not obj:
+ raise PicklingError(
+ "Can't pickle %r: it's not the same object as %s.%s" %
+ (obj, module_name, name))
+
+ if self.proto >= 2:
+ code = _extension_registry.get((module_name, name))
+ if code:
+ assert code > 0
+ if code <= 0xff:
+ write(EXT1 + pack("= 3.
+ if self.proto >= 4:
+ self.save(module_name)
+ self.save(name)
+ write(STACK_GLOBAL)
+ elif parent is not module:
+ self.save_reduce(getattr, (parent, lastname))
+ elif self.proto >= 3:
+ write(GLOBAL + bytes(module_name, "utf-8") + b'\n' +
+ bytes(name, "utf-8") + b'\n')
+ else:
+ if self.fix_imports:
+ r_name_mapping = _compat_pickle.REVERSE_NAME_MAPPING
+ r_import_mapping = _compat_pickle.REVERSE_IMPORT_MAPPING
+ if (module_name, name) in r_name_mapping:
+ module_name, name = r_name_mapping[(module_name, name)]
+ elif module_name in r_import_mapping:
+ module_name = r_import_mapping[module_name]
+ try:
+ write(GLOBAL + bytes(module_name, "ascii") + b'\n' +
+ bytes(name, "ascii") + b'\n')
+ except UnicodeEncodeError:
+ raise PicklingError(
+ "can't pickle global identifier '%s.%s' using "
+ "pickle protocol %i" % (module, name, self.proto)) from None
+
+ self.memoize(obj)
+
+ def save_type(self, obj):
+ if obj is type(None):
+ return self.save_reduce(type, (None,), obj=obj)
+ elif obj is type(NotImplemented):
+ return self.save_reduce(type, (NotImplemented,), obj=obj)
+ elif obj is type(...):
+ return self.save_reduce(type, (...,), obj=obj)
+ return self.save_global(obj)
+
+ dispatch[FunctionType] = save_global
+ dispatch[type] = save_type
+
+
+# Unpickling machinery
+
+class _Unpickler:
+
+ def __init__(self, file, *, fix_imports=True,
+ encoding="ASCII", errors="strict", buffers=None):
+ """This takes a binary file for reading a pickle data stream.
+
+ The protocol version of the pickle is detected automatically, so
+ no proto argument is needed.
+
+ The argument *file* must have two methods, a read() method that
+ takes an integer argument, and a readline() method that requires
+ no arguments. Both methods should return bytes. Thus *file*
+ can be a binary file object opened for reading, an io.BytesIO
+ object, or any other custom object that meets this interface.
+
+ The file-like object must have two methods, a read() method
+ that takes an integer argument, and a readline() method that
+ requires no arguments. Both methods should return bytes.
+ Thus file-like object can be a binary file object opened for
+ reading, a BytesIO object, or any other custom object that
+ meets this interface.
+
+ If *buffers* is not None, it should be an iterable of buffer-enabled
+ objects that is consumed each time the pickle stream references
+ an out-of-band buffer view. Such buffers have been given in order
+ to the *buffer_callback* of a Pickler object.
+
+ If *buffers* is None (the default), then the buffers are taken
+ from the pickle stream, assuming they are serialized there.
+ It is an error for *buffers* to be None if the pickle stream
+ was produced with a non-None *buffer_callback*.
+
+ Other optional arguments are *fix_imports*, *encoding* and
+ *errors*, which are used to control compatibility support for
+ pickle stream generated by Python 2. If *fix_imports* is True,
+ pickle will try to map the old Python 2 names to the new names
+ used in Python 3. The *encoding* and *errors* tell pickle how
+ to decode 8-bit string instances pickled by Python 2; these
+ default to 'ASCII' and 'strict', respectively. *encoding* can be
+ 'bytes' to read theses 8-bit string instances as bytes objects.
+ """
+ self._buffers = iter(buffers) if buffers is not None else None
+ self._file_readline = file.readline
+ self._file_read = file.read
+ self.memo = {}
+ self.encoding = encoding
+ self.errors = errors
+ self.proto = 0
+ self.fix_imports = fix_imports
+
+ def load(self):
+ """Read a pickled object representation from the open file.
+
+ Return the reconstituted object hierarchy specified in the file.
+ """
+ # Check whether Unpickler was initialized correctly. This is
+ # only needed to mimic the behavior of _pickle.Unpickler.dump().
+ if not hasattr(self, "_file_read"):
+ raise UnpicklingError("Unpickler.__init__() was not called by "
+ "%s.__init__()" % (self.__class__.__name__,))
+ self._unframer = _Unframer(self._file_read, self._file_readline)
+ self.read = self._unframer.read
+ self.readinto = self._unframer.readinto
+ self.readline = self._unframer.readline
+ self.metastack = []
+ self.stack = []
+ self.append = self.stack.append
+ self.proto = 0
+ read = self.read
+ dispatch = self.dispatch
+ try:
+ while True:
+ key = read(1)
+ if not key:
+ raise EOFError
+ assert isinstance(key, bytes_types)
+ dispatch[key[0]](self)
+ except _Stop as stopinst:
+ return stopinst.value
+
+ # Return a list of items pushed in the stack after last MARK instruction.
+ def pop_mark(self):
+ items = self.stack
+ self.stack = self.metastack.pop()
+ self.append = self.stack.append
+ return items
+
+ def persistent_load(self, pid):
+ raise UnpicklingError("unsupported persistent id encountered")
+
+ dispatch = {}
+
+ def load_proto(self):
+ proto = self.read(1)[0]
+ if not 0 <= proto <= HIGHEST_PROTOCOL:
+ raise ValueError("unsupported pickle protocol: %d" % proto)
+ self.proto = proto
+ dispatch[PROTO[0]] = load_proto
+
+ def load_frame(self):
+ frame_size, = unpack(' sys.maxsize:
+ raise ValueError("frame size > sys.maxsize: %d" % frame_size)
+ self._unframer.load_frame(frame_size)
+ dispatch[FRAME[0]] = load_frame
+
+ def load_persid(self):
+ try:
+ pid = self.readline()[:-1].decode("ascii")
+ except UnicodeDecodeError:
+ raise UnpicklingError(
+ "persistent IDs in protocol 0 must be ASCII strings")
+ self.append(self.persistent_load(pid))
+ dispatch[PERSID[0]] = load_persid
+
+ def load_binpersid(self):
+ pid = self.stack.pop()
+ self.append(self.persistent_load(pid))
+ dispatch[BINPERSID[0]] = load_binpersid
+
+ def load_none(self):
+ self.append(None)
+ dispatch[NONE[0]] = load_none
+
+ def load_false(self):
+ self.append(False)
+ dispatch[NEWFALSE[0]] = load_false
+
+ def load_true(self):
+ self.append(True)
+ dispatch[NEWTRUE[0]] = load_true
+
+ def load_int(self):
+ data = self.readline()
+ if data == FALSE[1:]:
+ val = False
+ elif data == TRUE[1:]:
+ val = True
+ else:
+ val = int(data, 0)
+ self.append(val)
+ dispatch[INT[0]] = load_int
+
+ def load_binint(self):
+ self.append(unpack('d', self.read(8))[0])
+ dispatch[BINFLOAT[0]] = load_binfloat
+
+ def _decode_string(self, value):
+ # Used to allow strings from Python 2 to be decoded either as
+ # bytes or Unicode strings. This should be used only with the
+ # STRING, BINSTRING and SHORT_BINSTRING opcodes.
+ if self.encoding == "bytes":
+ return value
+ else:
+ return value.decode(self.encoding, self.errors)
+
+ def load_string(self):
+ data = self.readline()[:-1]
+ # Strip outermost quotes
+ if len(data) >= 2 and data[0] == data[-1] and data[0] in b'"\'':
+ data = data[1:-1]
+ else:
+ raise UnpicklingError("the STRING opcode argument must be quoted")
+ self.append(self._decode_string(codecs.escape_decode(data)[0]))
+ dispatch[STRING[0]] = load_string
+
+ def load_binstring(self):
+ # Deprecated BINSTRING uses signed 32-bit length
+ len, = unpack(' maxsize:
+ raise UnpicklingError("BINBYTES exceeds system's maximum size "
+ "of %d bytes" % maxsize)
+ self.append(self.read(len))
+ dispatch[BINBYTES[0]] = load_binbytes
+
+ def load_unicode(self):
+ self.append(str(self.readline()[:-1], 'raw-unicode-escape'))
+ dispatch[UNICODE[0]] = load_unicode
+
+ def load_binunicode(self):
+ len, = unpack(' maxsize:
+ raise UnpicklingError("BINUNICODE exceeds system's maximum size "
+ "of %d bytes" % maxsize)
+ self.append(str(self.read(len), 'utf-8', 'surrogatepass'))
+ dispatch[BINUNICODE[0]] = load_binunicode
+
+ def load_binunicode8(self):
+ len, = unpack(' maxsize:
+ raise UnpicklingError("BINUNICODE8 exceeds system's maximum size "
+ "of %d bytes" % maxsize)
+ self.append(str(self.read(len), 'utf-8', 'surrogatepass'))
+ dispatch[BINUNICODE8[0]] = load_binunicode8
+
+ def load_binbytes8(self):
+ len, = unpack(' maxsize:
+ raise UnpicklingError("BINBYTES8 exceeds system's maximum size "
+ "of %d bytes" % maxsize)
+ self.append(self.read(len))
+ dispatch[BINBYTES8[0]] = load_binbytes8
+
+ def load_bytearray8(self):
+ len, = unpack(' maxsize:
+ raise UnpicklingError("BYTEARRAY8 exceeds system's maximum size "
+ "of %d bytes" % maxsize)
+ b = bytearray(len)
+ self.readinto(b)
+ self.append(b)
+ dispatch[BYTEARRAY8[0]] = load_bytearray8
+
+ def load_next_buffer(self):
+ if self._buffers is None:
+ raise UnpicklingError("pickle stream refers to out-of-band data "
+ "but no *buffers* argument was given")
+ try:
+ buf = next(self._buffers)
+ except StopIteration:
+ raise UnpicklingError("not enough out-of-band buffers")
+ self.append(buf)
+ dispatch[NEXT_BUFFER[0]] = load_next_buffer
+
+ def load_readonly_buffer(self):
+ buf = self.stack[-1]
+ with memoryview(buf) as m:
+ if not m.readonly:
+ self.stack[-1] = m.toreadonly()
+ dispatch[READONLY_BUFFER[0]] = load_readonly_buffer
+
+ def load_short_binstring(self):
+ len = self.read(1)[0]
+ data = self.read(len)
+ self.append(self._decode_string(data))
+ dispatch[SHORT_BINSTRING[0]] = load_short_binstring
+
+ def load_short_binbytes(self):
+ len = self.read(1)[0]
+ self.append(self.read(len))
+ dispatch[SHORT_BINBYTES[0]] = load_short_binbytes
+
+ def load_short_binunicode(self):
+ len = self.read(1)[0]
+ self.append(str(self.read(len), 'utf-8', 'surrogatepass'))
+ dispatch[SHORT_BINUNICODE[0]] = load_short_binunicode
+
+ def load_tuple(self):
+ items = self.pop_mark()
+ self.append(tuple(items))
+ dispatch[TUPLE[0]] = load_tuple
+
+ def load_empty_tuple(self):
+ self.append(())
+ dispatch[EMPTY_TUPLE[0]] = load_empty_tuple
+
+ def load_tuple1(self):
+ self.stack[-1] = (self.stack[-1],)
+ dispatch[TUPLE1[0]] = load_tuple1
+
+ def load_tuple2(self):
+ self.stack[-2:] = [(self.stack[-2], self.stack[-1])]
+ dispatch[TUPLE2[0]] = load_tuple2
+
+ def load_tuple3(self):
+ self.stack[-3:] = [(self.stack[-3], self.stack[-2], self.stack[-1])]
+ dispatch[TUPLE3[0]] = load_tuple3
+
+ def load_empty_list(self):
+ self.append([])
+ dispatch[EMPTY_LIST[0]] = load_empty_list
+
+ def load_empty_dictionary(self):
+ self.append({})
+ dispatch[EMPTY_DICT[0]] = load_empty_dictionary
+
+ def load_empty_set(self):
+ self.append(set())
+ dispatch[EMPTY_SET[0]] = load_empty_set
+
+ def load_frozenset(self):
+ items = self.pop_mark()
+ self.append(frozenset(items))
+ dispatch[FROZENSET[0]] = load_frozenset
+
+ def load_list(self):
+ items = self.pop_mark()
+ self.append(items)
+ dispatch[LIST[0]] = load_list
+
+ def load_dict(self):
+ items = self.pop_mark()
+ d = {items[i]: items[i+1]
+ for i in range(0, len(items), 2)}
+ self.append(d)
+ dispatch[DICT[0]] = load_dict
+
+ # INST and OBJ differ only in how they get a class object. It's not
+ # only sensible to do the rest in a common routine, the two routines
+ # previously diverged and grew different bugs.
+ # klass is the class to instantiate, and k points to the topmost mark
+ # object, following which are the arguments for klass.__init__.
+ def _instantiate(self, klass, args):
+ if (args or not isinstance(klass, type) or
+ hasattr(klass, "__getinitargs__")):
+ try:
+ value = klass(*args)
+ except TypeError as err:
+ raise TypeError("in constructor for %s: %s" %
+ (klass.__name__, str(err)), sys.exc_info()[2])
+ else:
+ value = klass.__new__(klass)
+ self.append(value)
+
+ def load_inst(self):
+ module = self.readline()[:-1].decode("ascii")
+ name = self.readline()[:-1].decode("ascii")
+ klass = self.find_class(module, name)
+ self._instantiate(klass, self.pop_mark())
+ dispatch[INST[0]] = load_inst
+
+ def load_obj(self):
+ # Stack is ... markobject classobject arg1 arg2 ...
+ args = self.pop_mark()
+ cls = args.pop(0)
+ self._instantiate(cls, args)
+ dispatch[OBJ[0]] = load_obj
+
+ def load_newobj(self):
+ args = self.stack.pop()
+ cls = self.stack.pop()
+ obj = cls.__new__(cls, *args)
+ self.append(obj)
+ dispatch[NEWOBJ[0]] = load_newobj
+
+ def load_newobj_ex(self):
+ kwargs = self.stack.pop()
+ args = self.stack.pop()
+ cls = self.stack.pop()
+ obj = cls.__new__(cls, *args, **kwargs)
+ self.append(obj)
+ dispatch[NEWOBJ_EX[0]] = load_newobj_ex
+
+ def load_global(self):
+ module = self.readline()[:-1].decode("utf-8")
+ name = self.readline()[:-1].decode("utf-8")
+ klass = self.find_class(module, name)
+ self.append(klass)
+ dispatch[GLOBAL[0]] = load_global
+
+ def load_stack_global(self):
+ name = self.stack.pop()
+ module = self.stack.pop()
+ if type(name) is not str or type(module) is not str:
+ raise UnpicklingError("STACK_GLOBAL requires str")
+ self.append(self.find_class(module, name))
+ dispatch[STACK_GLOBAL[0]] = load_stack_global
+
+ def load_ext1(self):
+ code = self.read(1)[0]
+ self.get_extension(code)
+ dispatch[EXT1[0]] = load_ext1
+
+ def load_ext2(self):
+ code, = unpack('= 4:
+ return _getattribute(sys.modules[module], name)[0]
+ else:
+ return getattr(sys.modules[module], name)
+
+ def load_reduce(self):
+ stack = self.stack
+ args = stack.pop()
+ func = stack[-1]
+ stack[-1] = func(*args)
+ dispatch[REDUCE[0]] = load_reduce
+
+ def load_pop(self):
+ if self.stack:
+ del self.stack[-1]
+ else:
+ self.pop_mark()
+ dispatch[POP[0]] = load_pop
+
+ def load_pop_mark(self):
+ self.pop_mark()
+ dispatch[POP_MARK[0]] = load_pop_mark
+
+ def load_dup(self):
+ self.append(self.stack[-1])
+ dispatch[DUP[0]] = load_dup
+
+ def load_get(self):
+ i = int(self.readline()[:-1])
+ self.append(self.memo[i])
+ dispatch[GET[0]] = load_get
+
+ def load_binget(self):
+ i = self.read(1)[0]
+ self.append(self.memo[i])
+ dispatch[BINGET[0]] = load_binget
+
+ def load_long_binget(self):
+ i, = unpack(' maxsize:
+ raise ValueError("negative LONG_BINPUT argument")
+ self.memo[i] = self.stack[-1]
+ dispatch[LONG_BINPUT[0]] = load_long_binput
+
+ def load_memoize(self):
+ memo = self.memo
+ memo[len(memo)] = self.stack[-1]
+ dispatch[MEMOIZE[0]] = load_memoize
+
+ def load_append(self):
+ stack = self.stack
+ value = stack.pop()
+ list = stack[-1]
+ list.append(value)
+ dispatch[APPEND[0]] = load_append
+
+ def load_appends(self):
+ items = self.pop_mark()
+ list_obj = self.stack[-1]
+ try:
+ extend = list_obj.extend
+ except AttributeError:
+ pass
+ else:
+ extend(items)
+ return
+ # Even if the PEP 307 requires extend() and append() methods,
+ # fall back on append() if the object has no extend() method
+ # for backward compatibility.
+ append = list_obj.append
+ for item in items:
+ append(item)
+ dispatch[APPENDS[0]] = load_appends
+
+ def load_setitem(self):
+ stack = self.stack
+ value = stack.pop()
+ key = stack.pop()
+ dict = stack[-1]
+ dict[key] = value
+ dispatch[SETITEM[0]] = load_setitem
+
+ def load_setitems(self):
+ items = self.pop_mark()
+ dict = self.stack[-1]
+ for i in range(0, len(items), 2):
+ dict[items[i]] = items[i + 1]
+ dispatch[SETITEMS[0]] = load_setitems
+
+ def load_additems(self):
+ items = self.pop_mark()
+ set_obj = self.stack[-1]
+ if isinstance(set_obj, set):
+ set_obj.update(items)
+ else:
+ add = set_obj.add
+ for item in items:
+ add(item)
+ dispatch[ADDITEMS[0]] = load_additems
+
+ def load_build(self):
+ stack = self.stack
+ state = stack.pop()
+ inst = stack[-1]
+ setstate = getattr(inst, "__setstate__", None)
+ if setstate is not None:
+ setstate(state)
+ return
+ slotstate = None
+ if isinstance(state, tuple) and len(state) == 2:
+ state, slotstate = state
+ if state:
+ inst_dict = inst.__dict__
+ intern = sys.intern
+ for k, v in state.items():
+ if type(k) is str:
+ inst_dict[intern(k)] = v
+ else:
+ inst_dict[k] = v
+ if slotstate:
+ for k, v in slotstate.items():
+ setattr(inst, k, v)
+ dispatch[BUILD[0]] = load_build
+
+ def load_mark(self):
+ self.metastack.append(self.stack)
+ self.stack = []
+ self.append = self.stack.append
+ dispatch[MARK[0]] = load_mark
+
+ def load_stop(self):
+ value = self.stack.pop()
+ raise _Stop(value)
+ dispatch[STOP[0]] = load_stop
+
+
+# Shorthands
+
+def _dump(obj, file, protocol=None, *, fix_imports=True, buffer_callback=None):
+ _Pickler(file, protocol, fix_imports=fix_imports,
+ buffer_callback=buffer_callback).dump(obj)
+
+def _dumps(obj, protocol=None, *, fix_imports=True, buffer_callback=None):
+ f = io.BytesIO()
+ _Pickler(f, protocol, fix_imports=fix_imports,
+ buffer_callback=buffer_callback).dump(obj)
+ res = f.getvalue()
+ assert isinstance(res, bytes_types)
+ return res
+
+def _load(file, *, fix_imports=True, encoding="ASCII", errors="strict",
+ buffers=None):
+ return _Unpickler(file, fix_imports=fix_imports, buffers=buffers,
+ encoding=encoding, errors=errors).load()
+
+def _loads(s, *, fix_imports=True, encoding="ASCII", errors="strict",
+ buffers=None):
+ if isinstance(s, str):
+ raise TypeError("Can't load pickle from unicode string")
+ file = io.BytesIO(s)
+ return _Unpickler(file, fix_imports=fix_imports, buffers=buffers,
+ encoding=encoding, errors=errors).load()
+
+# Use the faster _pickle if possible
+try:
+ from _pickle import (
+ PickleError,
+ PicklingError,
+ UnpicklingError,
+ Pickler,
+ Unpickler,
+ dump,
+ dumps,
+ load,
+ loads
+ )
+except ImportError:
+ Pickler, Unpickler = _Pickler, _Unpickler
+ dump, dumps, load, loads = _dump, _dumps, _load, _loads
+
+# Doctest
+def _test():
+ import doctest
+ return doctest.testmod()
+
+if __name__ == "__main__":
+ import argparse
+ parser = argparse.ArgumentParser(
+ description='display contents of the pickle files')
+ parser.add_argument(
+ 'pickle_file', type=argparse.FileType('br'),
+ nargs='*', help='the pickle file')
+ parser.add_argument(
+ '-t', '--test', action='store_true',
+ help='run self-test suite')
+ parser.add_argument(
+ '-v', action='store_true',
+ help='run verbosely; only affects self-test run')
+ args = parser.parse_args()
+ if args.test:
+ _test()
+ else:
+ if not args.pickle_file:
+ parser.print_help()
+ else:
+ import pprint
+ for f in args.pickle_file:
+ obj = load(f)
+ pprint.pprint(obj)
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/pickletools.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/pickletools.py
new file mode 100644
index 0000000000000000000000000000000000000000..95706e746c9870c92996a622ef56a25c41aa88cd
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/pickletools.py
@@ -0,0 +1,2890 @@
+'''"Executable documentation" for the pickle module.
+
+Extensive comments about the pickle protocols and pickle-machine opcodes
+can be found here. Some functions meant for external use:
+
+genops(pickle)
+ Generate all the opcodes in a pickle, as (opcode, arg, position) triples.
+
+dis(pickle, out=None, memo=None, indentlevel=4)
+ Print a symbolic disassembly of a pickle.
+'''
+
+import codecs
+import io
+import pickle
+import re
+import sys
+
+__all__ = ['dis', 'genops', 'optimize']
+
+bytes_types = pickle.bytes_types
+
+# Other ideas:
+#
+# - A pickle verifier: read a pickle and check it exhaustively for
+# well-formedness. dis() does a lot of this already.
+#
+# - A protocol identifier: examine a pickle and return its protocol number
+# (== the highest .proto attr value among all the opcodes in the pickle).
+# dis() already prints this info at the end.
+#
+# - A pickle optimizer: for example, tuple-building code is sometimes more
+# elaborate than necessary, catering for the possibility that the tuple
+# is recursive. Or lots of times a PUT is generated that's never accessed
+# by a later GET.
+
+
+# "A pickle" is a program for a virtual pickle machine (PM, but more accurately
+# called an unpickling machine). It's a sequence of opcodes, interpreted by the
+# PM, building an arbitrarily complex Python object.
+#
+# For the most part, the PM is very simple: there are no looping, testing, or
+# conditional instructions, no arithmetic and no function calls. Opcodes are
+# executed once each, from first to last, until a STOP opcode is reached.
+#
+# The PM has two data areas, "the stack" and "the memo".
+#
+# Many opcodes push Python objects onto the stack; e.g., INT pushes a Python
+# integer object on the stack, whose value is gotten from a decimal string
+# literal immediately following the INT opcode in the pickle bytestream. Other
+# opcodes take Python objects off the stack. The result of unpickling is
+# whatever object is left on the stack when the final STOP opcode is executed.
+#
+# The memo is simply an array of objects, or it can be implemented as a dict
+# mapping little integers to objects. The memo serves as the PM's "long term
+# memory", and the little integers indexing the memo are akin to variable
+# names. Some opcodes pop a stack object into the memo at a given index,
+# and others push a memo object at a given index onto the stack again.
+#
+# At heart, that's all the PM has. Subtleties arise for these reasons:
+#
+# + Object identity. Objects can be arbitrarily complex, and subobjects
+# may be shared (for example, the list [a, a] refers to the same object a
+# twice). It can be vital that unpickling recreate an isomorphic object
+# graph, faithfully reproducing sharing.
+#
+# + Recursive objects. For example, after "L = []; L.append(L)", L is a
+# list, and L[0] is the same list. This is related to the object identity
+# point, and some sequences of pickle opcodes are subtle in order to
+# get the right result in all cases.
+#
+# + Things pickle doesn't know everything about. Examples of things pickle
+# does know everything about are Python's builtin scalar and container
+# types, like ints and tuples. They generally have opcodes dedicated to
+# them. For things like module references and instances of user-defined
+# classes, pickle's knowledge is limited. Historically, many enhancements
+# have been made to the pickle protocol in order to do a better (faster,
+# and/or more compact) job on those.
+#
+# + Backward compatibility and micro-optimization. As explained below,
+# pickle opcodes never go away, not even when better ways to do a thing
+# get invented. The repertoire of the PM just keeps growing over time.
+# For example, protocol 0 had two opcodes for building Python integers (INT
+# and LONG), protocol 1 added three more for more-efficient pickling of short
+# integers, and protocol 2 added two more for more-efficient pickling of
+# long integers (before protocol 2, the only ways to pickle a Python long
+# took time quadratic in the number of digits, for both pickling and
+# unpickling). "Opcode bloat" isn't so much a subtlety as a source of
+# wearying complication.
+#
+#
+# Pickle protocols:
+#
+# For compatibility, the meaning of a pickle opcode never changes. Instead new
+# pickle opcodes get added, and each version's unpickler can handle all the
+# pickle opcodes in all protocol versions to date. So old pickles continue to
+# be readable forever. The pickler can generally be told to restrict itself to
+# the subset of opcodes available under previous protocol versions too, so that
+# users can create pickles under the current version readable by older
+# versions. However, a pickle does not contain its version number embedded
+# within it. If an older unpickler tries to read a pickle using a later
+# protocol, the result is most likely an exception due to seeing an unknown (in
+# the older unpickler) opcode.
+#
+# The original pickle used what's now called "protocol 0", and what was called
+# "text mode" before Python 2.3. The entire pickle bytestream is made up of
+# printable 7-bit ASCII characters, plus the newline character, in protocol 0.
+# That's why it was called text mode. Protocol 0 is small and elegant, but
+# sometimes painfully inefficient.
+#
+# The second major set of additions is now called "protocol 1", and was called
+# "binary mode" before Python 2.3. This added many opcodes with arguments
+# consisting of arbitrary bytes, including NUL bytes and unprintable "high bit"
+# bytes. Binary mode pickles can be substantially smaller than equivalent
+# text mode pickles, and sometimes faster too; e.g., BININT represents a 4-byte
+# int as 4 bytes following the opcode, which is cheaper to unpickle than the
+# (perhaps) 11-character decimal string attached to INT. Protocol 1 also added
+# a number of opcodes that operate on many stack elements at once (like APPENDS
+# and SETITEMS), and "shortcut" opcodes (like EMPTY_DICT and EMPTY_TUPLE).
+#
+# The third major set of additions came in Python 2.3, and is called "protocol
+# 2". This added:
+#
+# - A better way to pickle instances of new-style classes (NEWOBJ).
+#
+# - A way for a pickle to identify its protocol (PROTO).
+#
+# - Time- and space- efficient pickling of long ints (LONG{1,4}).
+#
+# - Shortcuts for small tuples (TUPLE{1,2,3}}.
+#
+# - Dedicated opcodes for bools (NEWTRUE, NEWFALSE).
+#
+# - The "extension registry", a vector of popular objects that can be pushed
+# efficiently by index (EXT{1,2,4}). This is akin to the memo and GET, but
+# the registry contents are predefined (there's nothing akin to the memo's
+# PUT).
+#
+# Another independent change with Python 2.3 is the abandonment of any
+# pretense that it might be safe to load pickles received from untrusted
+# parties -- no sufficient security analysis has been done to guarantee
+# this and there isn't a use case that warrants the expense of such an
+# analysis.
+#
+# To this end, all tests for __safe_for_unpickling__ or for
+# copyreg.safe_constructors are removed from the unpickling code.
+# References to these variables in the descriptions below are to be seen
+# as describing unpickling in Python 2.2 and before.
+
+
+# Meta-rule: Descriptions are stored in instances of descriptor objects,
+# with plain constructors. No meta-language is defined from which
+# descriptors could be constructed. If you want, e.g., XML, write a little
+# program to generate XML from the objects.
+
+##############################################################################
+# Some pickle opcodes have an argument, following the opcode in the
+# bytestream. An argument is of a specific type, described by an instance
+# of ArgumentDescriptor. These are not to be confused with arguments taken
+# off the stack -- ArgumentDescriptor applies only to arguments embedded in
+# the opcode stream, immediately following an opcode.
+
+# Represents the number of bytes consumed by an argument delimited by the
+# next newline character.
+UP_TO_NEWLINE = -1
+
+# Represents the number of bytes consumed by a two-argument opcode where
+# the first argument gives the number of bytes in the second argument.
+TAKEN_FROM_ARGUMENT1 = -2 # num bytes is 1-byte unsigned int
+TAKEN_FROM_ARGUMENT4 = -3 # num bytes is 4-byte signed little-endian int
+TAKEN_FROM_ARGUMENT4U = -4 # num bytes is 4-byte unsigned little-endian int
+TAKEN_FROM_ARGUMENT8U = -5 # num bytes is 8-byte unsigned little-endian int
+
+class ArgumentDescriptor(object):
+ __slots__ = (
+ # name of descriptor record, also a module global name; a string
+ 'name',
+
+ # length of argument, in bytes; an int; UP_TO_NEWLINE and
+ # TAKEN_FROM_ARGUMENT{1,4,8} are negative values for variable-length
+ # cases
+ 'n',
+
+ # a function taking a file-like object, reading this kind of argument
+ # from the object at the current position, advancing the current
+ # position by n bytes, and returning the value of the argument
+ 'reader',
+
+ # human-readable docs for this arg descriptor; a string
+ 'doc',
+ )
+
+ def __init__(self, name, n, reader, doc):
+ assert isinstance(name, str)
+ self.name = name
+
+ assert isinstance(n, int) and (n >= 0 or
+ n in (UP_TO_NEWLINE,
+ TAKEN_FROM_ARGUMENT1,
+ TAKEN_FROM_ARGUMENT4,
+ TAKEN_FROM_ARGUMENT4U,
+ TAKEN_FROM_ARGUMENT8U))
+ self.n = n
+
+ self.reader = reader
+
+ assert isinstance(doc, str)
+ self.doc = doc
+
+from struct import unpack as _unpack
+
+def read_uint1(f):
+ r"""
+ >>> import io
+ >>> read_uint1(io.BytesIO(b'\xff'))
+ 255
+ """
+
+ data = f.read(1)
+ if data:
+ return data[0]
+ raise ValueError("not enough data in stream to read uint1")
+
+uint1 = ArgumentDescriptor(
+ name='uint1',
+ n=1,
+ reader=read_uint1,
+ doc="One-byte unsigned integer.")
+
+
+def read_uint2(f):
+ r"""
+ >>> import io
+ >>> read_uint2(io.BytesIO(b'\xff\x00'))
+ 255
+ >>> read_uint2(io.BytesIO(b'\xff\xff'))
+ 65535
+ """
+
+ data = f.read(2)
+ if len(data) == 2:
+ return _unpack(">> import io
+ >>> read_int4(io.BytesIO(b'\xff\x00\x00\x00'))
+ 255
+ >>> read_int4(io.BytesIO(b'\x00\x00\x00\x80')) == -(2**31)
+ True
+ """
+
+ data = f.read(4)
+ if len(data) == 4:
+ return _unpack(">> import io
+ >>> read_uint4(io.BytesIO(b'\xff\x00\x00\x00'))
+ 255
+ >>> read_uint4(io.BytesIO(b'\x00\x00\x00\x80')) == 2**31
+ True
+ """
+
+ data = f.read(4)
+ if len(data) == 4:
+ return _unpack(">> import io
+ >>> read_uint8(io.BytesIO(b'\xff\x00\x00\x00\x00\x00\x00\x00'))
+ 255
+ >>> read_uint8(io.BytesIO(b'\xff' * 8)) == 2**64-1
+ True
+ """
+
+ data = f.read(8)
+ if len(data) == 8:
+ return _unpack(">> import io
+ >>> read_stringnl(io.BytesIO(b"'abcd'\nefg\n"))
+ 'abcd'
+
+ >>> read_stringnl(io.BytesIO(b"\n"))
+ Traceback (most recent call last):
+ ...
+ ValueError: no string quotes around b''
+
+ >>> read_stringnl(io.BytesIO(b"\n"), stripquotes=False)
+ ''
+
+ >>> read_stringnl(io.BytesIO(b"''\n"))
+ ''
+
+ >>> read_stringnl(io.BytesIO(b'"abcd"'))
+ Traceback (most recent call last):
+ ...
+ ValueError: no newline found when trying to read stringnl
+
+ Embedded escapes are undone in the result.
+ >>> read_stringnl(io.BytesIO(br"'a\n\\b\x00c\td'" + b"\n'e'"))
+ 'a\n\\b\x00c\td'
+ """
+
+ data = f.readline()
+ if not data.endswith(b'\n'):
+ raise ValueError("no newline found when trying to read stringnl")
+ data = data[:-1] # lose the newline
+
+ if stripquotes:
+ for q in (b'"', b"'"):
+ if data.startswith(q):
+ if not data.endswith(q):
+ raise ValueError("strinq quote %r not found at both "
+ "ends of %r" % (q, data))
+ data = data[1:-1]
+ break
+ else:
+ raise ValueError("no string quotes around %r" % data)
+
+ if decode:
+ data = codecs.escape_decode(data)[0].decode("ascii")
+ return data
+
+stringnl = ArgumentDescriptor(
+ name='stringnl',
+ n=UP_TO_NEWLINE,
+ reader=read_stringnl,
+ doc="""A newline-terminated string.
+
+ This is a repr-style string, with embedded escapes, and
+ bracketing quotes.
+ """)
+
+def read_stringnl_noescape(f):
+ return read_stringnl(f, stripquotes=False)
+
+stringnl_noescape = ArgumentDescriptor(
+ name='stringnl_noescape',
+ n=UP_TO_NEWLINE,
+ reader=read_stringnl_noescape,
+ doc="""A newline-terminated string.
+
+ This is a str-style string, without embedded escapes,
+ or bracketing quotes. It should consist solely of
+ printable ASCII characters.
+ """)
+
+def read_stringnl_noescape_pair(f):
+ r"""
+ >>> import io
+ >>> read_stringnl_noescape_pair(io.BytesIO(b"Queue\nEmpty\njunk"))
+ 'Queue Empty'
+ """
+
+ return "%s %s" % (read_stringnl_noescape(f), read_stringnl_noescape(f))
+
+stringnl_noescape_pair = ArgumentDescriptor(
+ name='stringnl_noescape_pair',
+ n=UP_TO_NEWLINE,
+ reader=read_stringnl_noescape_pair,
+ doc="""A pair of newline-terminated strings.
+
+ These are str-style strings, without embedded
+ escapes, or bracketing quotes. They should
+ consist solely of printable ASCII characters.
+ The pair is returned as a single string, with
+ a single blank separating the two strings.
+ """)
+
+
+def read_string1(f):
+ r"""
+ >>> import io
+ >>> read_string1(io.BytesIO(b"\x00"))
+ ''
+ >>> read_string1(io.BytesIO(b"\x03abcdef"))
+ 'abc'
+ """
+
+ n = read_uint1(f)
+ assert n >= 0
+ data = f.read(n)
+ if len(data) == n:
+ return data.decode("latin-1")
+ raise ValueError("expected %d bytes in a string1, but only %d remain" %
+ (n, len(data)))
+
+string1 = ArgumentDescriptor(
+ name="string1",
+ n=TAKEN_FROM_ARGUMENT1,
+ reader=read_string1,
+ doc="""A counted string.
+
+ The first argument is a 1-byte unsigned int giving the number
+ of bytes in the string, and the second argument is that many
+ bytes.
+ """)
+
+
+def read_string4(f):
+ r"""
+ >>> import io
+ >>> read_string4(io.BytesIO(b"\x00\x00\x00\x00abc"))
+ ''
+ >>> read_string4(io.BytesIO(b"\x03\x00\x00\x00abcdef"))
+ 'abc'
+ >>> read_string4(io.BytesIO(b"\x00\x00\x00\x03abcdef"))
+ Traceback (most recent call last):
+ ...
+ ValueError: expected 50331648 bytes in a string4, but only 6 remain
+ """
+
+ n = read_int4(f)
+ if n < 0:
+ raise ValueError("string4 byte count < 0: %d" % n)
+ data = f.read(n)
+ if len(data) == n:
+ return data.decode("latin-1")
+ raise ValueError("expected %d bytes in a string4, but only %d remain" %
+ (n, len(data)))
+
+string4 = ArgumentDescriptor(
+ name="string4",
+ n=TAKEN_FROM_ARGUMENT4,
+ reader=read_string4,
+ doc="""A counted string.
+
+ The first argument is a 4-byte little-endian signed int giving
+ the number of bytes in the string, and the second argument is
+ that many bytes.
+ """)
+
+
+def read_bytes1(f):
+ r"""
+ >>> import io
+ >>> read_bytes1(io.BytesIO(b"\x00"))
+ b''
+ >>> read_bytes1(io.BytesIO(b"\x03abcdef"))
+ b'abc'
+ """
+
+ n = read_uint1(f)
+ assert n >= 0
+ data = f.read(n)
+ if len(data) == n:
+ return data
+ raise ValueError("expected %d bytes in a bytes1, but only %d remain" %
+ (n, len(data)))
+
+bytes1 = ArgumentDescriptor(
+ name="bytes1",
+ n=TAKEN_FROM_ARGUMENT1,
+ reader=read_bytes1,
+ doc="""A counted bytes string.
+
+ The first argument is a 1-byte unsigned int giving the number
+ of bytes, and the second argument is that many bytes.
+ """)
+
+
+def read_bytes4(f):
+ r"""
+ >>> import io
+ >>> read_bytes4(io.BytesIO(b"\x00\x00\x00\x00abc"))
+ b''
+ >>> read_bytes4(io.BytesIO(b"\x03\x00\x00\x00abcdef"))
+ b'abc'
+ >>> read_bytes4(io.BytesIO(b"\x00\x00\x00\x03abcdef"))
+ Traceback (most recent call last):
+ ...
+ ValueError: expected 50331648 bytes in a bytes4, but only 6 remain
+ """
+
+ n = read_uint4(f)
+ assert n >= 0
+ if n > sys.maxsize:
+ raise ValueError("bytes4 byte count > sys.maxsize: %d" % n)
+ data = f.read(n)
+ if len(data) == n:
+ return data
+ raise ValueError("expected %d bytes in a bytes4, but only %d remain" %
+ (n, len(data)))
+
+bytes4 = ArgumentDescriptor(
+ name="bytes4",
+ n=TAKEN_FROM_ARGUMENT4U,
+ reader=read_bytes4,
+ doc="""A counted bytes string.
+
+ The first argument is a 4-byte little-endian unsigned int giving
+ the number of bytes, and the second argument is that many bytes.
+ """)
+
+
+def read_bytes8(f):
+ r"""
+ >>> import io, struct, sys
+ >>> read_bytes8(io.BytesIO(b"\x00\x00\x00\x00\x00\x00\x00\x00abc"))
+ b''
+ >>> read_bytes8(io.BytesIO(b"\x03\x00\x00\x00\x00\x00\x00\x00abcdef"))
+ b'abc'
+ >>> bigsize8 = struct.pack(">> read_bytes8(io.BytesIO(bigsize8 + b"abcdef")) #doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ ValueError: expected ... bytes in a bytes8, but only 6 remain
+ """
+
+ n = read_uint8(f)
+ assert n >= 0
+ if n > sys.maxsize:
+ raise ValueError("bytes8 byte count > sys.maxsize: %d" % n)
+ data = f.read(n)
+ if len(data) == n:
+ return data
+ raise ValueError("expected %d bytes in a bytes8, but only %d remain" %
+ (n, len(data)))
+
+bytes8 = ArgumentDescriptor(
+ name="bytes8",
+ n=TAKEN_FROM_ARGUMENT8U,
+ reader=read_bytes8,
+ doc="""A counted bytes string.
+
+ The first argument is an 8-byte little-endian unsigned int giving
+ the number of bytes, and the second argument is that many bytes.
+ """)
+
+
+def read_bytearray8(f):
+ r"""
+ >>> import io, struct, sys
+ >>> read_bytearray8(io.BytesIO(b"\x00\x00\x00\x00\x00\x00\x00\x00abc"))
+ bytearray(b'')
+ >>> read_bytearray8(io.BytesIO(b"\x03\x00\x00\x00\x00\x00\x00\x00abcdef"))
+ bytearray(b'abc')
+ >>> bigsize8 = struct.pack(">> read_bytearray8(io.BytesIO(bigsize8 + b"abcdef")) #doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ ValueError: expected ... bytes in a bytearray8, but only 6 remain
+ """
+
+ n = read_uint8(f)
+ assert n >= 0
+ if n > sys.maxsize:
+ raise ValueError("bytearray8 byte count > sys.maxsize: %d" % n)
+ data = f.read(n)
+ if len(data) == n:
+ return bytearray(data)
+ raise ValueError("expected %d bytes in a bytearray8, but only %d remain" %
+ (n, len(data)))
+
+bytearray8 = ArgumentDescriptor(
+ name="bytearray8",
+ n=TAKEN_FROM_ARGUMENT8U,
+ reader=read_bytearray8,
+ doc="""A counted bytearray.
+
+ The first argument is an 8-byte little-endian unsigned int giving
+ the number of bytes, and the second argument is that many bytes.
+ """)
+
+def read_unicodestringnl(f):
+ r"""
+ >>> import io
+ >>> read_unicodestringnl(io.BytesIO(b"abc\\uabcd\njunk")) == 'abc\uabcd'
+ True
+ """
+
+ data = f.readline()
+ if not data.endswith(b'\n'):
+ raise ValueError("no newline found when trying to read "
+ "unicodestringnl")
+ data = data[:-1] # lose the newline
+ return str(data, 'raw-unicode-escape')
+
+unicodestringnl = ArgumentDescriptor(
+ name='unicodestringnl',
+ n=UP_TO_NEWLINE,
+ reader=read_unicodestringnl,
+ doc="""A newline-terminated Unicode string.
+
+ This is raw-unicode-escape encoded, so consists of
+ printable ASCII characters, and may contain embedded
+ escape sequences.
+ """)
+
+
+def read_unicodestring1(f):
+ r"""
+ >>> import io
+ >>> s = 'abcd\uabcd'
+ >>> enc = s.encode('utf-8')
+ >>> enc
+ b'abcd\xea\xaf\x8d'
+ >>> n = bytes([len(enc)]) # little-endian 1-byte length
+ >>> t = read_unicodestring1(io.BytesIO(n + enc + b'junk'))
+ >>> s == t
+ True
+
+ >>> read_unicodestring1(io.BytesIO(n + enc[:-1]))
+ Traceback (most recent call last):
+ ...
+ ValueError: expected 7 bytes in a unicodestring1, but only 6 remain
+ """
+
+ n = read_uint1(f)
+ assert n >= 0
+ data = f.read(n)
+ if len(data) == n:
+ return str(data, 'utf-8', 'surrogatepass')
+ raise ValueError("expected %d bytes in a unicodestring1, but only %d "
+ "remain" % (n, len(data)))
+
+unicodestring1 = ArgumentDescriptor(
+ name="unicodestring1",
+ n=TAKEN_FROM_ARGUMENT1,
+ reader=read_unicodestring1,
+ doc="""A counted Unicode string.
+
+ The first argument is a 1-byte little-endian signed int
+ giving the number of bytes in the string, and the second
+ argument-- the UTF-8 encoding of the Unicode string --
+ contains that many bytes.
+ """)
+
+
+def read_unicodestring4(f):
+ r"""
+ >>> import io
+ >>> s = 'abcd\uabcd'
+ >>> enc = s.encode('utf-8')
+ >>> enc
+ b'abcd\xea\xaf\x8d'
+ >>> n = bytes([len(enc), 0, 0, 0]) # little-endian 4-byte length
+ >>> t = read_unicodestring4(io.BytesIO(n + enc + b'junk'))
+ >>> s == t
+ True
+
+ >>> read_unicodestring4(io.BytesIO(n + enc[:-1]))
+ Traceback (most recent call last):
+ ...
+ ValueError: expected 7 bytes in a unicodestring4, but only 6 remain
+ """
+
+ n = read_uint4(f)
+ assert n >= 0
+ if n > sys.maxsize:
+ raise ValueError("unicodestring4 byte count > sys.maxsize: %d" % n)
+ data = f.read(n)
+ if len(data) == n:
+ return str(data, 'utf-8', 'surrogatepass')
+ raise ValueError("expected %d bytes in a unicodestring4, but only %d "
+ "remain" % (n, len(data)))
+
+unicodestring4 = ArgumentDescriptor(
+ name="unicodestring4",
+ n=TAKEN_FROM_ARGUMENT4U,
+ reader=read_unicodestring4,
+ doc="""A counted Unicode string.
+
+ The first argument is a 4-byte little-endian signed int
+ giving the number of bytes in the string, and the second
+ argument-- the UTF-8 encoding of the Unicode string --
+ contains that many bytes.
+ """)
+
+
+def read_unicodestring8(f):
+ r"""
+ >>> import io
+ >>> s = 'abcd\uabcd'
+ >>> enc = s.encode('utf-8')
+ >>> enc
+ b'abcd\xea\xaf\x8d'
+ >>> n = bytes([len(enc)]) + b'\0' * 7 # little-endian 8-byte length
+ >>> t = read_unicodestring8(io.BytesIO(n + enc + b'junk'))
+ >>> s == t
+ True
+
+ >>> read_unicodestring8(io.BytesIO(n + enc[:-1]))
+ Traceback (most recent call last):
+ ...
+ ValueError: expected 7 bytes in a unicodestring8, but only 6 remain
+ """
+
+ n = read_uint8(f)
+ assert n >= 0
+ if n > sys.maxsize:
+ raise ValueError("unicodestring8 byte count > sys.maxsize: %d" % n)
+ data = f.read(n)
+ if len(data) == n:
+ return str(data, 'utf-8', 'surrogatepass')
+ raise ValueError("expected %d bytes in a unicodestring8, but only %d "
+ "remain" % (n, len(data)))
+
+unicodestring8 = ArgumentDescriptor(
+ name="unicodestring8",
+ n=TAKEN_FROM_ARGUMENT8U,
+ reader=read_unicodestring8,
+ doc="""A counted Unicode string.
+
+ The first argument is an 8-byte little-endian signed int
+ giving the number of bytes in the string, and the second
+ argument-- the UTF-8 encoding of the Unicode string --
+ contains that many bytes.
+ """)
+
+
+def read_decimalnl_short(f):
+ r"""
+ >>> import io
+ >>> read_decimalnl_short(io.BytesIO(b"1234\n56"))
+ 1234
+
+ >>> read_decimalnl_short(io.BytesIO(b"1234L\n56"))
+ Traceback (most recent call last):
+ ...
+ ValueError: invalid literal for int() with base 10: b'1234L'
+ """
+
+ s = read_stringnl(f, decode=False, stripquotes=False)
+
+ # There's a hack for True and False here.
+ if s == b"00":
+ return False
+ elif s == b"01":
+ return True
+
+ return int(s)
+
+def read_decimalnl_long(f):
+ r"""
+ >>> import io
+
+ >>> read_decimalnl_long(io.BytesIO(b"1234L\n56"))
+ 1234
+
+ >>> read_decimalnl_long(io.BytesIO(b"123456789012345678901234L\n6"))
+ 123456789012345678901234
+ """
+
+ s = read_stringnl(f, decode=False, stripquotes=False)
+ if s[-1:] == b'L':
+ s = s[:-1]
+ return int(s)
+
+
+decimalnl_short = ArgumentDescriptor(
+ name='decimalnl_short',
+ n=UP_TO_NEWLINE,
+ reader=read_decimalnl_short,
+ doc="""A newline-terminated decimal integer literal.
+
+ This never has a trailing 'L', and the integer fit
+ in a short Python int on the box where the pickle
+ was written -- but there's no guarantee it will fit
+ in a short Python int on the box where the pickle
+ is read.
+ """)
+
+decimalnl_long = ArgumentDescriptor(
+ name='decimalnl_long',
+ n=UP_TO_NEWLINE,
+ reader=read_decimalnl_long,
+ doc="""A newline-terminated decimal integer literal.
+
+ This has a trailing 'L', and can represent integers
+ of any size.
+ """)
+
+
+def read_floatnl(f):
+ r"""
+ >>> import io
+ >>> read_floatnl(io.BytesIO(b"-1.25\n6"))
+ -1.25
+ """
+ s = read_stringnl(f, decode=False, stripquotes=False)
+ return float(s)
+
+floatnl = ArgumentDescriptor(
+ name='floatnl',
+ n=UP_TO_NEWLINE,
+ reader=read_floatnl,
+ doc="""A newline-terminated decimal floating literal.
+
+ In general this requires 17 significant digits for roundtrip
+ identity, and pickling then unpickling infinities, NaNs, and
+ minus zero doesn't work across boxes, or on some boxes even
+ on itself (e.g., Windows can't read the strings it produces
+ for infinities or NaNs).
+ """)
+
+def read_float8(f):
+ r"""
+ >>> import io, struct
+ >>> raw = struct.pack(">d", -1.25)
+ >>> raw
+ b'\xbf\xf4\x00\x00\x00\x00\x00\x00'
+ >>> read_float8(io.BytesIO(raw + b"\n"))
+ -1.25
+ """
+
+ data = f.read(8)
+ if len(data) == 8:
+ return _unpack(">d", data)[0]
+ raise ValueError("not enough data in stream to read float8")
+
+
+float8 = ArgumentDescriptor(
+ name='float8',
+ n=8,
+ reader=read_float8,
+ doc="""An 8-byte binary representation of a float, big-endian.
+
+ The format is unique to Python, and shared with the struct
+ module (format string '>d') "in theory" (the struct and pickle
+ implementations don't share the code -- they should). It's
+ strongly related to the IEEE-754 double format, and, in normal
+ cases, is in fact identical to the big-endian 754 double format.
+ On other boxes the dynamic range is limited to that of a 754
+ double, and "add a half and chop" rounding is used to reduce
+ the precision to 53 bits. However, even on a 754 box,
+ infinities, NaNs, and minus zero may not be handled correctly
+ (may not survive roundtrip pickling intact).
+ """)
+
+# Protocol 2 formats
+
+from pickle import decode_long
+
+def read_long1(f):
+ r"""
+ >>> import io
+ >>> read_long1(io.BytesIO(b"\x00"))
+ 0
+ >>> read_long1(io.BytesIO(b"\x02\xff\x00"))
+ 255
+ >>> read_long1(io.BytesIO(b"\x02\xff\x7f"))
+ 32767
+ >>> read_long1(io.BytesIO(b"\x02\x00\xff"))
+ -256
+ >>> read_long1(io.BytesIO(b"\x02\x00\x80"))
+ -32768
+ """
+
+ n = read_uint1(f)
+ data = f.read(n)
+ if len(data) != n:
+ raise ValueError("not enough data in stream to read long1")
+ return decode_long(data)
+
+long1 = ArgumentDescriptor(
+ name="long1",
+ n=TAKEN_FROM_ARGUMENT1,
+ reader=read_long1,
+ doc="""A binary long, little-endian, using 1-byte size.
+
+ This first reads one byte as an unsigned size, then reads that
+ many bytes and interprets them as a little-endian 2's-complement long.
+ If the size is 0, that's taken as a shortcut for the long 0L.
+ """)
+
+def read_long4(f):
+ r"""
+ >>> import io
+ >>> read_long4(io.BytesIO(b"\x02\x00\x00\x00\xff\x00"))
+ 255
+ >>> read_long4(io.BytesIO(b"\x02\x00\x00\x00\xff\x7f"))
+ 32767
+ >>> read_long4(io.BytesIO(b"\x02\x00\x00\x00\x00\xff"))
+ -256
+ >>> read_long4(io.BytesIO(b"\x02\x00\x00\x00\x00\x80"))
+ -32768
+ >>> read_long1(io.BytesIO(b"\x00\x00\x00\x00"))
+ 0
+ """
+
+ n = read_int4(f)
+ if n < 0:
+ raise ValueError("long4 byte count < 0: %d" % n)
+ data = f.read(n)
+ if len(data) != n:
+ raise ValueError("not enough data in stream to read long4")
+ return decode_long(data)
+
+long4 = ArgumentDescriptor(
+ name="long4",
+ n=TAKEN_FROM_ARGUMENT4,
+ reader=read_long4,
+ doc="""A binary representation of a long, little-endian.
+
+ This first reads four bytes as a signed size (but requires the
+ size to be >= 0), then reads that many bytes and interprets them
+ as a little-endian 2's-complement long. If the size is 0, that's taken
+ as a shortcut for the int 0, although LONG1 should really be used
+ then instead (and in any case where # of bytes < 256).
+ """)
+
+
+##############################################################################
+# Object descriptors. The stack used by the pickle machine holds objects,
+# and in the stack_before and stack_after attributes of OpcodeInfo
+# descriptors we need names to describe the various types of objects that can
+# appear on the stack.
+
+class StackObject(object):
+ __slots__ = (
+ # name of descriptor record, for info only
+ 'name',
+
+ # type of object, or tuple of type objects (meaning the object can
+ # be of any type in the tuple)
+ 'obtype',
+
+ # human-readable docs for this kind of stack object; a string
+ 'doc',
+ )
+
+ def __init__(self, name, obtype, doc):
+ assert isinstance(name, str)
+ self.name = name
+
+ assert isinstance(obtype, type) or isinstance(obtype, tuple)
+ if isinstance(obtype, tuple):
+ for contained in obtype:
+ assert isinstance(contained, type)
+ self.obtype = obtype
+
+ assert isinstance(doc, str)
+ self.doc = doc
+
+ def __repr__(self):
+ return self.name
+
+
+pyint = pylong = StackObject(
+ name='int',
+ obtype=int,
+ doc="A Python integer object.")
+
+pyinteger_or_bool = StackObject(
+ name='int_or_bool',
+ obtype=(int, bool),
+ doc="A Python integer or boolean object.")
+
+pybool = StackObject(
+ name='bool',
+ obtype=bool,
+ doc="A Python boolean object.")
+
+pyfloat = StackObject(
+ name='float',
+ obtype=float,
+ doc="A Python float object.")
+
+pybytes_or_str = pystring = StackObject(
+ name='bytes_or_str',
+ obtype=(bytes, str),
+ doc="A Python bytes or (Unicode) string object.")
+
+pybytes = StackObject(
+ name='bytes',
+ obtype=bytes,
+ doc="A Python bytes object.")
+
+pybytearray = StackObject(
+ name='bytearray',
+ obtype=bytearray,
+ doc="A Python bytearray object.")
+
+pyunicode = StackObject(
+ name='str',
+ obtype=str,
+ doc="A Python (Unicode) string object.")
+
+pynone = StackObject(
+ name="None",
+ obtype=type(None),
+ doc="The Python None object.")
+
+pytuple = StackObject(
+ name="tuple",
+ obtype=tuple,
+ doc="A Python tuple object.")
+
+pylist = StackObject(
+ name="list",
+ obtype=list,
+ doc="A Python list object.")
+
+pydict = StackObject(
+ name="dict",
+ obtype=dict,
+ doc="A Python dict object.")
+
+pyset = StackObject(
+ name="set",
+ obtype=set,
+ doc="A Python set object.")
+
+pyfrozenset = StackObject(
+ name="frozenset",
+ obtype=set,
+ doc="A Python frozenset object.")
+
+pybuffer = StackObject(
+ name='buffer',
+ obtype=object,
+ doc="A Python buffer-like object.")
+
+anyobject = StackObject(
+ name='any',
+ obtype=object,
+ doc="Any kind of object whatsoever.")
+
+markobject = StackObject(
+ name="mark",
+ obtype=StackObject,
+ doc="""'The mark' is a unique object.
+
+Opcodes that operate on a variable number of objects
+generally don't embed the count of objects in the opcode,
+or pull it off the stack. Instead the MARK opcode is used
+to push a special marker object on the stack, and then
+some other opcodes grab all the objects from the top of
+the stack down to (but not including) the topmost marker
+object.
+""")
+
+stackslice = StackObject(
+ name="stackslice",
+ obtype=StackObject,
+ doc="""An object representing a contiguous slice of the stack.
+
+This is used in conjunction with markobject, to represent all
+of the stack following the topmost markobject. For example,
+the POP_MARK opcode changes the stack from
+
+ [..., markobject, stackslice]
+to
+ [...]
+
+No matter how many object are on the stack after the topmost
+markobject, POP_MARK gets rid of all of them (including the
+topmost markobject too).
+""")
+
+##############################################################################
+# Descriptors for pickle opcodes.
+
+class OpcodeInfo(object):
+
+ __slots__ = (
+ # symbolic name of opcode; a string
+ 'name',
+
+ # the code used in a bytestream to represent the opcode; a
+ # one-character string
+ 'code',
+
+ # If the opcode has an argument embedded in the byte string, an
+ # instance of ArgumentDescriptor specifying its type. Note that
+ # arg.reader(s) can be used to read and decode the argument from
+ # the bytestream s, and arg.doc documents the format of the raw
+ # argument bytes. If the opcode doesn't have an argument embedded
+ # in the bytestream, arg should be None.
+ 'arg',
+
+ # what the stack looks like before this opcode runs; a list
+ 'stack_before',
+
+ # what the stack looks like after this opcode runs; a list
+ 'stack_after',
+
+ # the protocol number in which this opcode was introduced; an int
+ 'proto',
+
+ # human-readable docs for this opcode; a string
+ 'doc',
+ )
+
+ def __init__(self, name, code, arg,
+ stack_before, stack_after, proto, doc):
+ assert isinstance(name, str)
+ self.name = name
+
+ assert isinstance(code, str)
+ assert len(code) == 1
+ self.code = code
+
+ assert arg is None or isinstance(arg, ArgumentDescriptor)
+ self.arg = arg
+
+ assert isinstance(stack_before, list)
+ for x in stack_before:
+ assert isinstance(x, StackObject)
+ self.stack_before = stack_before
+
+ assert isinstance(stack_after, list)
+ for x in stack_after:
+ assert isinstance(x, StackObject)
+ self.stack_after = stack_after
+
+ assert isinstance(proto, int) and 0 <= proto <= pickle.HIGHEST_PROTOCOL
+ self.proto = proto
+
+ assert isinstance(doc, str)
+ self.doc = doc
+
+I = OpcodeInfo
+opcodes = [
+
+ # Ways to spell integers.
+
+ I(name='INT',
+ code='I',
+ arg=decimalnl_short,
+ stack_before=[],
+ stack_after=[pyinteger_or_bool],
+ proto=0,
+ doc="""Push an integer or bool.
+
+ The argument is a newline-terminated decimal literal string.
+
+ The intent may have been that this always fit in a short Python int,
+ but INT can be generated in pickles written on a 64-bit box that
+ require a Python long on a 32-bit box. The difference between this
+ and LONG then is that INT skips a trailing 'L', and produces a short
+ int whenever possible.
+
+ Another difference is due to that, when bool was introduced as a
+ distinct type in 2.3, builtin names True and False were also added to
+ 2.2.2, mapping to ints 1 and 0. For compatibility in both directions,
+ True gets pickled as INT + "I01\\n", and False as INT + "I00\\n".
+ Leading zeroes are never produced for a genuine integer. The 2.3
+ (and later) unpicklers special-case these and return bool instead;
+ earlier unpicklers ignore the leading "0" and return the int.
+ """),
+
+ I(name='BININT',
+ code='J',
+ arg=int4,
+ stack_before=[],
+ stack_after=[pyint],
+ proto=1,
+ doc="""Push a four-byte signed integer.
+
+ This handles the full range of Python (short) integers on a 32-bit
+ box, directly as binary bytes (1 for the opcode and 4 for the integer).
+ If the integer is non-negative and fits in 1 or 2 bytes, pickling via
+ BININT1 or BININT2 saves space.
+ """),
+
+ I(name='BININT1',
+ code='K',
+ arg=uint1,
+ stack_before=[],
+ stack_after=[pyint],
+ proto=1,
+ doc="""Push a one-byte unsigned integer.
+
+ This is a space optimization for pickling very small non-negative ints,
+ in range(256).
+ """),
+
+ I(name='BININT2',
+ code='M',
+ arg=uint2,
+ stack_before=[],
+ stack_after=[pyint],
+ proto=1,
+ doc="""Push a two-byte unsigned integer.
+
+ This is a space optimization for pickling small positive ints, in
+ range(256, 2**16). Integers in range(256) can also be pickled via
+ BININT2, but BININT1 instead saves a byte.
+ """),
+
+ I(name='LONG',
+ code='L',
+ arg=decimalnl_long,
+ stack_before=[],
+ stack_after=[pyint],
+ proto=0,
+ doc="""Push a long integer.
+
+ The same as INT, except that the literal ends with 'L', and always
+ unpickles to a Python long. There doesn't seem a real purpose to the
+ trailing 'L'.
+
+ Note that LONG takes time quadratic in the number of digits when
+ unpickling (this is simply due to the nature of decimal->binary
+ conversion). Proto 2 added linear-time (in C; still quadratic-time
+ in Python) LONG1 and LONG4 opcodes.
+ """),
+
+ I(name="LONG1",
+ code='\x8a',
+ arg=long1,
+ stack_before=[],
+ stack_after=[pyint],
+ proto=2,
+ doc="""Long integer using one-byte length.
+
+ A more efficient encoding of a Python long; the long1 encoding
+ says it all."""),
+
+ I(name="LONG4",
+ code='\x8b',
+ arg=long4,
+ stack_before=[],
+ stack_after=[pyint],
+ proto=2,
+ doc="""Long integer using found-byte length.
+
+ A more efficient encoding of a Python long; the long4 encoding
+ says it all."""),
+
+ # Ways to spell strings (8-bit, not Unicode).
+
+ I(name='STRING',
+ code='S',
+ arg=stringnl,
+ stack_before=[],
+ stack_after=[pybytes_or_str],
+ proto=0,
+ doc="""Push a Python string object.
+
+ The argument is a repr-style string, with bracketing quote characters,
+ and perhaps embedded escapes. The argument extends until the next
+ newline character. These are usually decoded into a str instance
+ using the encoding given to the Unpickler constructor. or the default,
+ 'ASCII'. If the encoding given was 'bytes' however, they will be
+ decoded as bytes object instead.
+ """),
+
+ I(name='BINSTRING',
+ code='T',
+ arg=string4,
+ stack_before=[],
+ stack_after=[pybytes_or_str],
+ proto=1,
+ doc="""Push a Python string object.
+
+ There are two arguments: the first is a 4-byte little-endian
+ signed int giving the number of bytes in the string, and the
+ second is that many bytes, which are taken literally as the string
+ content. These are usually decoded into a str instance using the
+ encoding given to the Unpickler constructor. or the default,
+ 'ASCII'. If the encoding given was 'bytes' however, they will be
+ decoded as bytes object instead.
+ """),
+
+ I(name='SHORT_BINSTRING',
+ code='U',
+ arg=string1,
+ stack_before=[],
+ stack_after=[pybytes_or_str],
+ proto=1,
+ doc="""Push a Python string object.
+
+ There are two arguments: the first is a 1-byte unsigned int giving
+ the number of bytes in the string, and the second is that many
+ bytes, which are taken literally as the string content. These are
+ usually decoded into a str instance using the encoding given to
+ the Unpickler constructor. or the default, 'ASCII'. If the
+ encoding given was 'bytes' however, they will be decoded as bytes
+ object instead.
+ """),
+
+ # Bytes (protocol 3 and higher)
+
+ I(name='BINBYTES',
+ code='B',
+ arg=bytes4,
+ stack_before=[],
+ stack_after=[pybytes],
+ proto=3,
+ doc="""Push a Python bytes object.
+
+ There are two arguments: the first is a 4-byte little-endian unsigned int
+ giving the number of bytes, and the second is that many bytes, which are
+ taken literally as the bytes content.
+ """),
+
+ I(name='SHORT_BINBYTES',
+ code='C',
+ arg=bytes1,
+ stack_before=[],
+ stack_after=[pybytes],
+ proto=3,
+ doc="""Push a Python bytes object.
+
+ There are two arguments: the first is a 1-byte unsigned int giving
+ the number of bytes, and the second is that many bytes, which are taken
+ literally as the string content.
+ """),
+
+ I(name='BINBYTES8',
+ code='\x8e',
+ arg=bytes8,
+ stack_before=[],
+ stack_after=[pybytes],
+ proto=4,
+ doc="""Push a Python bytes object.
+
+ There are two arguments: the first is an 8-byte unsigned int giving
+ the number of bytes in the string, and the second is that many bytes,
+ which are taken literally as the string content.
+ """),
+
+ # Bytearray (protocol 5 and higher)
+
+ I(name='BYTEARRAY8',
+ code='\x96',
+ arg=bytearray8,
+ stack_before=[],
+ stack_after=[pybytearray],
+ proto=5,
+ doc="""Push a Python bytearray object.
+
+ There are two arguments: the first is an 8-byte unsigned int giving
+ the number of bytes in the bytearray, and the second is that many bytes,
+ which are taken literally as the bytearray content.
+ """),
+
+ # Out-of-band buffer (protocol 5 and higher)
+
+ I(name='NEXT_BUFFER',
+ code='\x97',
+ arg=None,
+ stack_before=[],
+ stack_after=[pybuffer],
+ proto=5,
+ doc="Push an out-of-band buffer object."),
+
+ I(name='READONLY_BUFFER',
+ code='\x98',
+ arg=None,
+ stack_before=[pybuffer],
+ stack_after=[pybuffer],
+ proto=5,
+ doc="Make an out-of-band buffer object read-only."),
+
+ # Ways to spell None.
+
+ I(name='NONE',
+ code='N',
+ arg=None,
+ stack_before=[],
+ stack_after=[pynone],
+ proto=0,
+ doc="Push None on the stack."),
+
+ # Ways to spell bools, starting with proto 2. See INT for how this was
+ # done before proto 2.
+
+ I(name='NEWTRUE',
+ code='\x88',
+ arg=None,
+ stack_before=[],
+ stack_after=[pybool],
+ proto=2,
+ doc="Push True onto the stack."),
+
+ I(name='NEWFALSE',
+ code='\x89',
+ arg=None,
+ stack_before=[],
+ stack_after=[pybool],
+ proto=2,
+ doc="Push False onto the stack."),
+
+ # Ways to spell Unicode strings.
+
+ I(name='UNICODE',
+ code='V',
+ arg=unicodestringnl,
+ stack_before=[],
+ stack_after=[pyunicode],
+ proto=0, # this may be pure-text, but it's a later addition
+ doc="""Push a Python Unicode string object.
+
+ The argument is a raw-unicode-escape encoding of a Unicode string,
+ and so may contain embedded escape sequences. The argument extends
+ until the next newline character.
+ """),
+
+ I(name='SHORT_BINUNICODE',
+ code='\x8c',
+ arg=unicodestring1,
+ stack_before=[],
+ stack_after=[pyunicode],
+ proto=4,
+ doc="""Push a Python Unicode string object.
+
+ There are two arguments: the first is a 1-byte little-endian signed int
+ giving the number of bytes in the string. The second is that many
+ bytes, and is the UTF-8 encoding of the Unicode string.
+ """),
+
+ I(name='BINUNICODE',
+ code='X',
+ arg=unicodestring4,
+ stack_before=[],
+ stack_after=[pyunicode],
+ proto=1,
+ doc="""Push a Python Unicode string object.
+
+ There are two arguments: the first is a 4-byte little-endian unsigned int
+ giving the number of bytes in the string. The second is that many
+ bytes, and is the UTF-8 encoding of the Unicode string.
+ """),
+
+ I(name='BINUNICODE8',
+ code='\x8d',
+ arg=unicodestring8,
+ stack_before=[],
+ stack_after=[pyunicode],
+ proto=4,
+ doc="""Push a Python Unicode string object.
+
+ There are two arguments: the first is an 8-byte little-endian signed int
+ giving the number of bytes in the string. The second is that many
+ bytes, and is the UTF-8 encoding of the Unicode string.
+ """),
+
+ # Ways to spell floats.
+
+ I(name='FLOAT',
+ code='F',
+ arg=floatnl,
+ stack_before=[],
+ stack_after=[pyfloat],
+ proto=0,
+ doc="""Newline-terminated decimal float literal.
+
+ The argument is repr(a_float), and in general requires 17 significant
+ digits for roundtrip conversion to be an identity (this is so for
+ IEEE-754 double precision values, which is what Python float maps to
+ on most boxes).
+
+ In general, FLOAT cannot be used to transport infinities, NaNs, or
+ minus zero across boxes (or even on a single box, if the platform C
+ library can't read the strings it produces for such things -- Windows
+ is like that), but may do less damage than BINFLOAT on boxes with
+ greater precision or dynamic range than IEEE-754 double.
+ """),
+
+ I(name='BINFLOAT',
+ code='G',
+ arg=float8,
+ stack_before=[],
+ stack_after=[pyfloat],
+ proto=1,
+ doc="""Float stored in binary form, with 8 bytes of data.
+
+ This generally requires less than half the space of FLOAT encoding.
+ In general, BINFLOAT cannot be used to transport infinities, NaNs, or
+ minus zero, raises an exception if the exponent exceeds the range of
+ an IEEE-754 double, and retains no more than 53 bits of precision (if
+ there are more than that, "add a half and chop" rounding is used to
+ cut it back to 53 significant bits).
+ """),
+
+ # Ways to build lists.
+
+ I(name='EMPTY_LIST',
+ code=']',
+ arg=None,
+ stack_before=[],
+ stack_after=[pylist],
+ proto=1,
+ doc="Push an empty list."),
+
+ I(name='APPEND',
+ code='a',
+ arg=None,
+ stack_before=[pylist, anyobject],
+ stack_after=[pylist],
+ proto=0,
+ doc="""Append an object to a list.
+
+ Stack before: ... pylist anyobject
+ Stack after: ... pylist+[anyobject]
+
+ although pylist is really extended in-place.
+ """),
+
+ I(name='APPENDS',
+ code='e',
+ arg=None,
+ stack_before=[pylist, markobject, stackslice],
+ stack_after=[pylist],
+ proto=1,
+ doc="""Extend a list by a slice of stack objects.
+
+ Stack before: ... pylist markobject stackslice
+ Stack after: ... pylist+stackslice
+
+ although pylist is really extended in-place.
+ """),
+
+ I(name='LIST',
+ code='l',
+ arg=None,
+ stack_before=[markobject, stackslice],
+ stack_after=[pylist],
+ proto=0,
+ doc="""Build a list out of the topmost stack slice, after markobject.
+
+ All the stack entries following the topmost markobject are placed into
+ a single Python list, which single list object replaces all of the
+ stack from the topmost markobject onward. For example,
+
+ Stack before: ... markobject 1 2 3 'abc'
+ Stack after: ... [1, 2, 3, 'abc']
+ """),
+
+ # Ways to build tuples.
+
+ I(name='EMPTY_TUPLE',
+ code=')',
+ arg=None,
+ stack_before=[],
+ stack_after=[pytuple],
+ proto=1,
+ doc="Push an empty tuple."),
+
+ I(name='TUPLE',
+ code='t',
+ arg=None,
+ stack_before=[markobject, stackslice],
+ stack_after=[pytuple],
+ proto=0,
+ doc="""Build a tuple out of the topmost stack slice, after markobject.
+
+ All the stack entries following the topmost markobject are placed into
+ a single Python tuple, which single tuple object replaces all of the
+ stack from the topmost markobject onward. For example,
+
+ Stack before: ... markobject 1 2 3 'abc'
+ Stack after: ... (1, 2, 3, 'abc')
+ """),
+
+ I(name='TUPLE1',
+ code='\x85',
+ arg=None,
+ stack_before=[anyobject],
+ stack_after=[pytuple],
+ proto=2,
+ doc="""Build a one-tuple out of the topmost item on the stack.
+
+ This code pops one value off the stack and pushes a tuple of
+ length 1 whose one item is that value back onto it. In other
+ words:
+
+ stack[-1] = tuple(stack[-1:])
+ """),
+
+ I(name='TUPLE2',
+ code='\x86',
+ arg=None,
+ stack_before=[anyobject, anyobject],
+ stack_after=[pytuple],
+ proto=2,
+ doc="""Build a two-tuple out of the top two items on the stack.
+
+ This code pops two values off the stack and pushes a tuple of
+ length 2 whose items are those values back onto it. In other
+ words:
+
+ stack[-2:] = [tuple(stack[-2:])]
+ """),
+
+ I(name='TUPLE3',
+ code='\x87',
+ arg=None,
+ stack_before=[anyobject, anyobject, anyobject],
+ stack_after=[pytuple],
+ proto=2,
+ doc="""Build a three-tuple out of the top three items on the stack.
+
+ This code pops three values off the stack and pushes a tuple of
+ length 3 whose items are those values back onto it. In other
+ words:
+
+ stack[-3:] = [tuple(stack[-3:])]
+ """),
+
+ # Ways to build dicts.
+
+ I(name='EMPTY_DICT',
+ code='}',
+ arg=None,
+ stack_before=[],
+ stack_after=[pydict],
+ proto=1,
+ doc="Push an empty dict."),
+
+ I(name='DICT',
+ code='d',
+ arg=None,
+ stack_before=[markobject, stackslice],
+ stack_after=[pydict],
+ proto=0,
+ doc="""Build a dict out of the topmost stack slice, after markobject.
+
+ All the stack entries following the topmost markobject are placed into
+ a single Python dict, which single dict object replaces all of the
+ stack from the topmost markobject onward. The stack slice alternates
+ key, value, key, value, .... For example,
+
+ Stack before: ... markobject 1 2 3 'abc'
+ Stack after: ... {1: 2, 3: 'abc'}
+ """),
+
+ I(name='SETITEM',
+ code='s',
+ arg=None,
+ stack_before=[pydict, anyobject, anyobject],
+ stack_after=[pydict],
+ proto=0,
+ doc="""Add a key+value pair to an existing dict.
+
+ Stack before: ... pydict key value
+ Stack after: ... pydict
+
+ where pydict has been modified via pydict[key] = value.
+ """),
+
+ I(name='SETITEMS',
+ code='u',
+ arg=None,
+ stack_before=[pydict, markobject, stackslice],
+ stack_after=[pydict],
+ proto=1,
+ doc="""Add an arbitrary number of key+value pairs to an existing dict.
+
+ The slice of the stack following the topmost markobject is taken as
+ an alternating sequence of keys and values, added to the dict
+ immediately under the topmost markobject. Everything at and after the
+ topmost markobject is popped, leaving the mutated dict at the top
+ of the stack.
+
+ Stack before: ... pydict markobject key_1 value_1 ... key_n value_n
+ Stack after: ... pydict
+
+ where pydict has been modified via pydict[key_i] = value_i for i in
+ 1, 2, ..., n, and in that order.
+ """),
+
+ # Ways to build sets
+
+ I(name='EMPTY_SET',
+ code='\x8f',
+ arg=None,
+ stack_before=[],
+ stack_after=[pyset],
+ proto=4,
+ doc="Push an empty set."),
+
+ I(name='ADDITEMS',
+ code='\x90',
+ arg=None,
+ stack_before=[pyset, markobject, stackslice],
+ stack_after=[pyset],
+ proto=4,
+ doc="""Add an arbitrary number of items to an existing set.
+
+ The slice of the stack following the topmost markobject is taken as
+ a sequence of items, added to the set immediately under the topmost
+ markobject. Everything at and after the topmost markobject is popped,
+ leaving the mutated set at the top of the stack.
+
+ Stack before: ... pyset markobject item_1 ... item_n
+ Stack after: ... pyset
+
+ where pyset has been modified via pyset.add(item_i) = item_i for i in
+ 1, 2, ..., n, and in that order.
+ """),
+
+ # Way to build frozensets
+
+ I(name='FROZENSET',
+ code='\x91',
+ arg=None,
+ stack_before=[markobject, stackslice],
+ stack_after=[pyfrozenset],
+ proto=4,
+ doc="""Build a frozenset out of the topmost slice, after markobject.
+
+ All the stack entries following the topmost markobject are placed into
+ a single Python frozenset, which single frozenset object replaces all
+ of the stack from the topmost markobject onward. For example,
+
+ Stack before: ... markobject 1 2 3
+ Stack after: ... frozenset({1, 2, 3})
+ """),
+
+ # Stack manipulation.
+
+ I(name='POP',
+ code='0',
+ arg=None,
+ stack_before=[anyobject],
+ stack_after=[],
+ proto=0,
+ doc="Discard the top stack item, shrinking the stack by one item."),
+
+ I(name='DUP',
+ code='2',
+ arg=None,
+ stack_before=[anyobject],
+ stack_after=[anyobject, anyobject],
+ proto=0,
+ doc="Push the top stack item onto the stack again, duplicating it."),
+
+ I(name='MARK',
+ code='(',
+ arg=None,
+ stack_before=[],
+ stack_after=[markobject],
+ proto=0,
+ doc="""Push markobject onto the stack.
+
+ markobject is a unique object, used by other opcodes to identify a
+ region of the stack containing a variable number of objects for them
+ to work on. See markobject.doc for more detail.
+ """),
+
+ I(name='POP_MARK',
+ code='1',
+ arg=None,
+ stack_before=[markobject, stackslice],
+ stack_after=[],
+ proto=1,
+ doc="""Pop all the stack objects at and above the topmost markobject.
+
+ When an opcode using a variable number of stack objects is done,
+ POP_MARK is used to remove those objects, and to remove the markobject
+ that delimited their starting position on the stack.
+ """),
+
+ # Memo manipulation. There are really only two operations (get and put),
+ # each in all-text, "short binary", and "long binary" flavors.
+
+ I(name='GET',
+ code='g',
+ arg=decimalnl_short,
+ stack_before=[],
+ stack_after=[anyobject],
+ proto=0,
+ doc="""Read an object from the memo and push it on the stack.
+
+ The index of the memo object to push is given by the newline-terminated
+ decimal string following. BINGET and LONG_BINGET are space-optimized
+ versions.
+ """),
+
+ I(name='BINGET',
+ code='h',
+ arg=uint1,
+ stack_before=[],
+ stack_after=[anyobject],
+ proto=1,
+ doc="""Read an object from the memo and push it on the stack.
+
+ The index of the memo object to push is given by the 1-byte unsigned
+ integer following.
+ """),
+
+ I(name='LONG_BINGET',
+ code='j',
+ arg=uint4,
+ stack_before=[],
+ stack_after=[anyobject],
+ proto=1,
+ doc="""Read an object from the memo and push it on the stack.
+
+ The index of the memo object to push is given by the 4-byte unsigned
+ little-endian integer following.
+ """),
+
+ I(name='PUT',
+ code='p',
+ arg=decimalnl_short,
+ stack_before=[],
+ stack_after=[],
+ proto=0,
+ doc="""Store the stack top into the memo. The stack is not popped.
+
+ The index of the memo location to write into is given by the newline-
+ terminated decimal string following. BINPUT and LONG_BINPUT are
+ space-optimized versions.
+ """),
+
+ I(name='BINPUT',
+ code='q',
+ arg=uint1,
+ stack_before=[],
+ stack_after=[],
+ proto=1,
+ doc="""Store the stack top into the memo. The stack is not popped.
+
+ The index of the memo location to write into is given by the 1-byte
+ unsigned integer following.
+ """),
+
+ I(name='LONG_BINPUT',
+ code='r',
+ arg=uint4,
+ stack_before=[],
+ stack_after=[],
+ proto=1,
+ doc="""Store the stack top into the memo. The stack is not popped.
+
+ The index of the memo location to write into is given by the 4-byte
+ unsigned little-endian integer following.
+ """),
+
+ I(name='MEMOIZE',
+ code='\x94',
+ arg=None,
+ stack_before=[anyobject],
+ stack_after=[anyobject],
+ proto=4,
+ doc="""Store the stack top into the memo. The stack is not popped.
+
+ The index of the memo location to write is the number of
+ elements currently present in the memo.
+ """),
+
+ # Access the extension registry (predefined objects). Akin to the GET
+ # family.
+
+ I(name='EXT1',
+ code='\x82',
+ arg=uint1,
+ stack_before=[],
+ stack_after=[anyobject],
+ proto=2,
+ doc="""Extension code.
+
+ This code and the similar EXT2 and EXT4 allow using a registry
+ of popular objects that are pickled by name, typically classes.
+ It is envisioned that through a global negotiation and
+ registration process, third parties can set up a mapping between
+ ints and object names.
+
+ In order to guarantee pickle interchangeability, the extension
+ code registry ought to be global, although a range of codes may
+ be reserved for private use.
+
+ EXT1 has a 1-byte integer argument. This is used to index into the
+ extension registry, and the object at that index is pushed on the stack.
+ """),
+
+ I(name='EXT2',
+ code='\x83',
+ arg=uint2,
+ stack_before=[],
+ stack_after=[anyobject],
+ proto=2,
+ doc="""Extension code.
+
+ See EXT1. EXT2 has a two-byte integer argument.
+ """),
+
+ I(name='EXT4',
+ code='\x84',
+ arg=int4,
+ stack_before=[],
+ stack_after=[anyobject],
+ proto=2,
+ doc="""Extension code.
+
+ See EXT1. EXT4 has a four-byte integer argument.
+ """),
+
+ # Push a class object, or module function, on the stack, via its module
+ # and name.
+
+ I(name='GLOBAL',
+ code='c',
+ arg=stringnl_noescape_pair,
+ stack_before=[],
+ stack_after=[anyobject],
+ proto=0,
+ doc="""Push a global object (module.attr) on the stack.
+
+ Two newline-terminated strings follow the GLOBAL opcode. The first is
+ taken as a module name, and the second as a class name. The class
+ object module.class is pushed on the stack. More accurately, the
+ object returned by self.find_class(module, class) is pushed on the
+ stack, so unpickling subclasses can override this form of lookup.
+ """),
+
+ I(name='STACK_GLOBAL',
+ code='\x93',
+ arg=None,
+ stack_before=[pyunicode, pyunicode],
+ stack_after=[anyobject],
+ proto=4,
+ doc="""Push a global object (module.attr) on the stack.
+ """),
+
+ # Ways to build objects of classes pickle doesn't know about directly
+ # (user-defined classes). I despair of documenting this accurately
+ # and comprehensibly -- you really have to read the pickle code to
+ # find all the special cases.
+
+ I(name='REDUCE',
+ code='R',
+ arg=None,
+ stack_before=[anyobject, anyobject],
+ stack_after=[anyobject],
+ proto=0,
+ doc="""Push an object built from a callable and an argument tuple.
+
+ The opcode is named to remind of the __reduce__() method.
+
+ Stack before: ... callable pytuple
+ Stack after: ... callable(*pytuple)
+
+ The callable and the argument tuple are the first two items returned
+ by a __reduce__ method. Applying the callable to the argtuple is
+ supposed to reproduce the original object, or at least get it started.
+ If the __reduce__ method returns a 3-tuple, the last component is an
+ argument to be passed to the object's __setstate__, and then the REDUCE
+ opcode is followed by code to create setstate's argument, and then a
+ BUILD opcode to apply __setstate__ to that argument.
+
+ If not isinstance(callable, type), REDUCE complains unless the
+ callable has been registered with the copyreg module's
+ safe_constructors dict, or the callable has a magic
+ '__safe_for_unpickling__' attribute with a true value. I'm not sure
+ why it does this, but I've sure seen this complaint often enough when
+ I didn't want to .
+ """),
+
+ I(name='BUILD',
+ code='b',
+ arg=None,
+ stack_before=[anyobject, anyobject],
+ stack_after=[anyobject],
+ proto=0,
+ doc="""Finish building an object, via __setstate__ or dict update.
+
+ Stack before: ... anyobject argument
+ Stack after: ... anyobject
+
+ where anyobject may have been mutated, as follows:
+
+ If the object has a __setstate__ method,
+
+ anyobject.__setstate__(argument)
+
+ is called.
+
+ Else the argument must be a dict, the object must have a __dict__, and
+ the object is updated via
+
+ anyobject.__dict__.update(argument)
+ """),
+
+ I(name='INST',
+ code='i',
+ arg=stringnl_noescape_pair,
+ stack_before=[markobject, stackslice],
+ stack_after=[anyobject],
+ proto=0,
+ doc="""Build a class instance.
+
+ This is the protocol 0 version of protocol 1's OBJ opcode.
+ INST is followed by two newline-terminated strings, giving a
+ module and class name, just as for the GLOBAL opcode (and see
+ GLOBAL for more details about that). self.find_class(module, name)
+ is used to get a class object.
+
+ In addition, all the objects on the stack following the topmost
+ markobject are gathered into a tuple and popped (along with the
+ topmost markobject), just as for the TUPLE opcode.
+
+ Now it gets complicated. If all of these are true:
+
+ + The argtuple is empty (markobject was at the top of the stack
+ at the start).
+
+ + The class object does not have a __getinitargs__ attribute.
+
+ then we want to create an old-style class instance without invoking
+ its __init__() method (pickle has waffled on this over the years; not
+ calling __init__() is current wisdom). In this case, an instance of
+ an old-style dummy class is created, and then we try to rebind its
+ __class__ attribute to the desired class object. If this succeeds,
+ the new instance object is pushed on the stack, and we're done.
+
+ Else (the argtuple is not empty, it's not an old-style class object,
+ or the class object does have a __getinitargs__ attribute), the code
+ first insists that the class object have a __safe_for_unpickling__
+ attribute. Unlike as for the __safe_for_unpickling__ check in REDUCE,
+ it doesn't matter whether this attribute has a true or false value, it
+ only matters whether it exists (XXX this is a bug). If
+ __safe_for_unpickling__ doesn't exist, UnpicklingError is raised.
+
+ Else (the class object does have a __safe_for_unpickling__ attr),
+ the class object obtained from INST's arguments is applied to the
+ argtuple obtained from the stack, and the resulting instance object
+ is pushed on the stack.
+
+ NOTE: checks for __safe_for_unpickling__ went away in Python 2.3.
+ NOTE: the distinction between old-style and new-style classes does
+ not make sense in Python 3.
+ """),
+
+ I(name='OBJ',
+ code='o',
+ arg=None,
+ stack_before=[markobject, anyobject, stackslice],
+ stack_after=[anyobject],
+ proto=1,
+ doc="""Build a class instance.
+
+ This is the protocol 1 version of protocol 0's INST opcode, and is
+ very much like it. The major difference is that the class object
+ is taken off the stack, allowing it to be retrieved from the memo
+ repeatedly if several instances of the same class are created. This
+ can be much more efficient (in both time and space) than repeatedly
+ embedding the module and class names in INST opcodes.
+
+ Unlike INST, OBJ takes no arguments from the opcode stream. Instead
+ the class object is taken off the stack, immediately above the
+ topmost markobject:
+
+ Stack before: ... markobject classobject stackslice
+ Stack after: ... new_instance_object
+
+ As for INST, the remainder of the stack above the markobject is
+ gathered into an argument tuple, and then the logic seems identical,
+ except that no __safe_for_unpickling__ check is done (XXX this is
+ a bug). See INST for the gory details.
+
+ NOTE: In Python 2.3, INST and OBJ are identical except for how they
+ get the class object. That was always the intent; the implementations
+ had diverged for accidental reasons.
+ """),
+
+ I(name='NEWOBJ',
+ code='\x81',
+ arg=None,
+ stack_before=[anyobject, anyobject],
+ stack_after=[anyobject],
+ proto=2,
+ doc="""Build an object instance.
+
+ The stack before should be thought of as containing a class
+ object followed by an argument tuple (the tuple being the stack
+ top). Call these cls and args. They are popped off the stack,
+ and the value returned by cls.__new__(cls, *args) is pushed back
+ onto the stack.
+ """),
+
+ I(name='NEWOBJ_EX',
+ code='\x92',
+ arg=None,
+ stack_before=[anyobject, anyobject, anyobject],
+ stack_after=[anyobject],
+ proto=4,
+ doc="""Build an object instance.
+
+ The stack before should be thought of as containing a class
+ object followed by an argument tuple and by a keyword argument dict
+ (the dict being the stack top). Call these cls and args. They are
+ popped off the stack, and the value returned by
+ cls.__new__(cls, *args, *kwargs) is pushed back onto the stack.
+ """),
+
+ # Machine control.
+
+ I(name='PROTO',
+ code='\x80',
+ arg=uint1,
+ stack_before=[],
+ stack_after=[],
+ proto=2,
+ doc="""Protocol version indicator.
+
+ For protocol 2 and above, a pickle must start with this opcode.
+ The argument is the protocol version, an int in range(2, 256).
+ """),
+
+ I(name='STOP',
+ code='.',
+ arg=None,
+ stack_before=[anyobject],
+ stack_after=[],
+ proto=0,
+ doc="""Stop the unpickling machine.
+
+ Every pickle ends with this opcode. The object at the top of the stack
+ is popped, and that's the result of unpickling. The stack should be
+ empty then.
+ """),
+
+ # Framing support.
+
+ I(name='FRAME',
+ code='\x95',
+ arg=uint8,
+ stack_before=[],
+ stack_after=[],
+ proto=4,
+ doc="""Indicate the beginning of a new frame.
+
+ The unpickler may use this opcode to safely prefetch data from its
+ underlying stream.
+ """),
+
+ # Ways to deal with persistent IDs.
+
+ I(name='PERSID',
+ code='P',
+ arg=stringnl_noescape,
+ stack_before=[],
+ stack_after=[anyobject],
+ proto=0,
+ doc="""Push an object identified by a persistent ID.
+
+ The pickle module doesn't define what a persistent ID means. PERSID's
+ argument is a newline-terminated str-style (no embedded escapes, no
+ bracketing quote characters) string, which *is* "the persistent ID".
+ The unpickler passes this string to self.persistent_load(). Whatever
+ object that returns is pushed on the stack. There is no implementation
+ of persistent_load() in Python's unpickler: it must be supplied by an
+ unpickler subclass.
+ """),
+
+ I(name='BINPERSID',
+ code='Q',
+ arg=None,
+ stack_before=[anyobject],
+ stack_after=[anyobject],
+ proto=1,
+ doc="""Push an object identified by a persistent ID.
+
+ Like PERSID, except the persistent ID is popped off the stack (instead
+ of being a string embedded in the opcode bytestream). The persistent
+ ID is passed to self.persistent_load(), and whatever object that
+ returns is pushed on the stack. See PERSID for more detail.
+ """),
+]
+del I
+
+# Verify uniqueness of .name and .code members.
+name2i = {}
+code2i = {}
+
+for i, d in enumerate(opcodes):
+ if d.name in name2i:
+ raise ValueError("repeated name %r at indices %d and %d" %
+ (d.name, name2i[d.name], i))
+ if d.code in code2i:
+ raise ValueError("repeated code %r at indices %d and %d" %
+ (d.code, code2i[d.code], i))
+
+ name2i[d.name] = i
+ code2i[d.code] = i
+
+del name2i, code2i, i, d
+
+##############################################################################
+# Build a code2op dict, mapping opcode characters to OpcodeInfo records.
+# Also ensure we've got the same stuff as pickle.py, although the
+# introspection here is dicey.
+
+code2op = {}
+for d in opcodes:
+ code2op[d.code] = d
+del d
+
+def assure_pickle_consistency(verbose=False):
+
+ copy = code2op.copy()
+ for name in pickle.__all__:
+ if not re.match("[A-Z][A-Z0-9_]+$", name):
+ if verbose:
+ print("skipping %r: it doesn't look like an opcode name" % name)
+ continue
+ picklecode = getattr(pickle, name)
+ if not isinstance(picklecode, bytes) or len(picklecode) != 1:
+ if verbose:
+ print(("skipping %r: value %r doesn't look like a pickle "
+ "code" % (name, picklecode)))
+ continue
+ picklecode = picklecode.decode("latin-1")
+ if picklecode in copy:
+ if verbose:
+ print("checking name %r w/ code %r for consistency" % (
+ name, picklecode))
+ d = copy[picklecode]
+ if d.name != name:
+ raise ValueError("for pickle code %r, pickle.py uses name %r "
+ "but we're using name %r" % (picklecode,
+ name,
+ d.name))
+ # Forget this one. Any left over in copy at the end are a problem
+ # of a different kind.
+ del copy[picklecode]
+ else:
+ raise ValueError("pickle.py appears to have a pickle opcode with "
+ "name %r and code %r, but we don't" %
+ (name, picklecode))
+ if copy:
+ msg = ["we appear to have pickle opcodes that pickle.py doesn't have:"]
+ for code, d in copy.items():
+ msg.append(" name %r with code %r" % (d.name, code))
+ raise ValueError("\n".join(msg))
+
+assure_pickle_consistency()
+del assure_pickle_consistency
+
+##############################################################################
+# A pickle opcode generator.
+
+def _genops(data, yield_end_pos=False):
+ if isinstance(data, bytes_types):
+ data = io.BytesIO(data)
+
+ if hasattr(data, "tell"):
+ getpos = data.tell
+ else:
+ getpos = lambda: None
+
+ while True:
+ pos = getpos()
+ code = data.read(1)
+ opcode = code2op.get(code.decode("latin-1"))
+ if opcode is None:
+ if code == b"":
+ raise ValueError("pickle exhausted before seeing STOP")
+ else:
+ raise ValueError("at position %s, opcode %r unknown" % (
+ "" if pos is None else pos,
+ code))
+ if opcode.arg is None:
+ arg = None
+ else:
+ arg = opcode.arg.reader(data)
+ if yield_end_pos:
+ yield opcode, arg, pos, getpos()
+ else:
+ yield opcode, arg, pos
+ if code == b'.':
+ assert opcode.name == 'STOP'
+ break
+
+def genops(pickle):
+ """Generate all the opcodes in a pickle.
+
+ 'pickle' is a file-like object, or string, containing the pickle.
+
+ Each opcode in the pickle is generated, from the current pickle position,
+ stopping after a STOP opcode is delivered. A triple is generated for
+ each opcode:
+
+ opcode, arg, pos
+
+ opcode is an OpcodeInfo record, describing the current opcode.
+
+ If the opcode has an argument embedded in the pickle, arg is its decoded
+ value, as a Python object. If the opcode doesn't have an argument, arg
+ is None.
+
+ If the pickle has a tell() method, pos was the value of pickle.tell()
+ before reading the current opcode. If the pickle is a bytes object,
+ it's wrapped in a BytesIO object, and the latter's tell() result is
+ used. Else (the pickle doesn't have a tell(), and it's not obvious how
+ to query its current position) pos is None.
+ """
+ return _genops(pickle)
+
+##############################################################################
+# A pickle optimizer.
+
+def optimize(p):
+ 'Optimize a pickle string by removing unused PUT opcodes'
+ put = 'PUT'
+ get = 'GET'
+ oldids = set() # set of all PUT ids
+ newids = {} # set of ids used by a GET opcode
+ opcodes = [] # (op, idx) or (pos, end_pos)
+ proto = 0
+ protoheader = b''
+ for opcode, arg, pos, end_pos in _genops(p, yield_end_pos=True):
+ if 'PUT' in opcode.name:
+ oldids.add(arg)
+ opcodes.append((put, arg))
+ elif opcode.name == 'MEMOIZE':
+ idx = len(oldids)
+ oldids.add(idx)
+ opcodes.append((put, idx))
+ elif 'FRAME' in opcode.name:
+ pass
+ elif 'GET' in opcode.name:
+ if opcode.proto > proto:
+ proto = opcode.proto
+ newids[arg] = None
+ opcodes.append((get, arg))
+ elif opcode.name == 'PROTO':
+ if arg > proto:
+ proto = arg
+ if pos == 0:
+ protoheader = p[pos:end_pos]
+ else:
+ opcodes.append((pos, end_pos))
+ else:
+ opcodes.append((pos, end_pos))
+ del oldids
+
+ # Copy the opcodes except for PUTS without a corresponding GET
+ out = io.BytesIO()
+ # Write the PROTO header before any framing
+ out.write(protoheader)
+ pickler = pickle._Pickler(out, proto)
+ if proto >= 4:
+ pickler.framer.start_framing()
+ idx = 0
+ for op, arg in opcodes:
+ frameless = False
+ if op is put:
+ if arg not in newids:
+ continue
+ data = pickler.put(idx)
+ newids[arg] = idx
+ idx += 1
+ elif op is get:
+ data = pickler.get(newids[arg])
+ else:
+ data = p[op:arg]
+ frameless = len(data) > pickler.framer._FRAME_SIZE_TARGET
+ pickler.framer.commit_frame(force=frameless)
+ if frameless:
+ pickler.framer.file_write(data)
+ else:
+ pickler.write(data)
+ pickler.framer.end_framing()
+ return out.getvalue()
+
+##############################################################################
+# A symbolic pickle disassembler.
+
+def dis(pickle, out=None, memo=None, indentlevel=4, annotate=0):
+ """Produce a symbolic disassembly of a pickle.
+
+ 'pickle' is a file-like object, or string, containing a (at least one)
+ pickle. The pickle is disassembled from the current position, through
+ the first STOP opcode encountered.
+
+ Optional arg 'out' is a file-like object to which the disassembly is
+ printed. It defaults to sys.stdout.
+
+ Optional arg 'memo' is a Python dict, used as the pickle's memo. It
+ may be mutated by dis(), if the pickle contains PUT or BINPUT opcodes.
+ Passing the same memo object to another dis() call then allows disassembly
+ to proceed across multiple pickles that were all created by the same
+ pickler with the same memo. Ordinarily you don't need to worry about this.
+
+ Optional arg 'indentlevel' is the number of blanks by which to indent
+ a new MARK level. It defaults to 4.
+
+ Optional arg 'annotate' if nonzero instructs dis() to add short
+ description of the opcode on each line of disassembled output.
+ The value given to 'annotate' must be an integer and is used as a
+ hint for the column where annotation should start. The default
+ value is 0, meaning no annotations.
+
+ In addition to printing the disassembly, some sanity checks are made:
+
+ + All embedded opcode arguments "make sense".
+
+ + Explicit and implicit pop operations have enough items on the stack.
+
+ + When an opcode implicitly refers to a markobject, a markobject is
+ actually on the stack.
+
+ + A memo entry isn't referenced before it's defined.
+
+ + The markobject isn't stored in the memo.
+
+ + A memo entry isn't redefined.
+ """
+
+ # Most of the hair here is for sanity checks, but most of it is needed
+ # anyway to detect when a protocol 0 POP takes a MARK off the stack
+ # (which in turn is needed to indent MARK blocks correctly).
+
+ stack = [] # crude emulation of unpickler stack
+ if memo is None:
+ memo = {} # crude emulation of unpickler memo
+ maxproto = -1 # max protocol number seen
+ markstack = [] # bytecode positions of MARK opcodes
+ indentchunk = ' ' * indentlevel
+ errormsg = None
+ annocol = annotate # column hint for annotations
+ for opcode, arg, pos in genops(pickle):
+ if pos is not None:
+ print("%5d:" % pos, end=' ', file=out)
+
+ line = "%-4s %s%s" % (repr(opcode.code)[1:-1],
+ indentchunk * len(markstack),
+ opcode.name)
+
+ maxproto = max(maxproto, opcode.proto)
+ before = opcode.stack_before # don't mutate
+ after = opcode.stack_after # don't mutate
+ numtopop = len(before)
+
+ # See whether a MARK should be popped.
+ markmsg = None
+ if markobject in before or (opcode.name == "POP" and
+ stack and
+ stack[-1] is markobject):
+ assert markobject not in after
+ if __debug__:
+ if markobject in before:
+ assert before[-1] is stackslice
+ if markstack:
+ markpos = markstack.pop()
+ if markpos is None:
+ markmsg = "(MARK at unknown opcode offset)"
+ else:
+ markmsg = "(MARK at %d)" % markpos
+ # Pop everything at and after the topmost markobject.
+ while stack[-1] is not markobject:
+ stack.pop()
+ stack.pop()
+ # Stop later code from popping too much.
+ try:
+ numtopop = before.index(markobject)
+ except ValueError:
+ assert opcode.name == "POP"
+ numtopop = 0
+ else:
+ errormsg = markmsg = "no MARK exists on stack"
+
+ # Check for correct memo usage.
+ if opcode.name in ("PUT", "BINPUT", "LONG_BINPUT", "MEMOIZE"):
+ if opcode.name == "MEMOIZE":
+ memo_idx = len(memo)
+ markmsg = "(as %d)" % memo_idx
+ else:
+ assert arg is not None
+ memo_idx = arg
+ if memo_idx in memo:
+ errormsg = "memo key %r already defined" % arg
+ elif not stack:
+ errormsg = "stack is empty -- can't store into memo"
+ elif stack[-1] is markobject:
+ errormsg = "can't store markobject in the memo"
+ else:
+ memo[memo_idx] = stack[-1]
+ elif opcode.name in ("GET", "BINGET", "LONG_BINGET"):
+ if arg in memo:
+ assert len(after) == 1
+ after = [memo[arg]] # for better stack emulation
+ else:
+ errormsg = "memo key %r has never been stored into" % arg
+
+ if arg is not None or markmsg:
+ # make a mild effort to align arguments
+ line += ' ' * (10 - len(opcode.name))
+ if arg is not None:
+ line += ' ' + repr(arg)
+ if markmsg:
+ line += ' ' + markmsg
+ if annotate:
+ line += ' ' * (annocol - len(line))
+ # make a mild effort to align annotations
+ annocol = len(line)
+ if annocol > 50:
+ annocol = annotate
+ line += ' ' + opcode.doc.split('\n', 1)[0]
+ print(line, file=out)
+
+ if errormsg:
+ # Note that we delayed complaining until the offending opcode
+ # was printed.
+ raise ValueError(errormsg)
+
+ # Emulate the stack effects.
+ if len(stack) < numtopop:
+ raise ValueError("tries to pop %d items from stack with "
+ "only %d items" % (numtopop, len(stack)))
+ if numtopop:
+ del stack[-numtopop:]
+ if markobject in after:
+ assert markobject not in before
+ markstack.append(pos)
+
+ stack.extend(after)
+
+ print("highest protocol among opcodes =", maxproto, file=out)
+ if stack:
+ raise ValueError("stack not empty after STOP: %r" % stack)
+
+# For use in the doctest, simply as an example of a class to pickle.
+class _Example:
+ def __init__(self, value):
+ self.value = value
+
+_dis_test = r"""
+>>> import pickle
+>>> x = [1, 2, (3, 4), {b'abc': "def"}]
+>>> pkl0 = pickle.dumps(x, 0)
+>>> dis(pkl0)
+ 0: ( MARK
+ 1: l LIST (MARK at 0)
+ 2: p PUT 0
+ 5: I INT 1
+ 8: a APPEND
+ 9: I INT 2
+ 12: a APPEND
+ 13: ( MARK
+ 14: I INT 3
+ 17: I INT 4
+ 20: t TUPLE (MARK at 13)
+ 21: p PUT 1
+ 24: a APPEND
+ 25: ( MARK
+ 26: d DICT (MARK at 25)
+ 27: p PUT 2
+ 30: c GLOBAL '_codecs encode'
+ 46: p PUT 3
+ 49: ( MARK
+ 50: V UNICODE 'abc'
+ 55: p PUT 4
+ 58: V UNICODE 'latin1'
+ 66: p PUT 5
+ 69: t TUPLE (MARK at 49)
+ 70: p PUT 6
+ 73: R REDUCE
+ 74: p PUT 7
+ 77: V UNICODE 'def'
+ 82: p PUT 8
+ 85: s SETITEM
+ 86: a APPEND
+ 87: . STOP
+highest protocol among opcodes = 0
+
+Try again with a "binary" pickle.
+
+>>> pkl1 = pickle.dumps(x, 1)
+>>> dis(pkl1)
+ 0: ] EMPTY_LIST
+ 1: q BINPUT 0
+ 3: ( MARK
+ 4: K BININT1 1
+ 6: K BININT1 2
+ 8: ( MARK
+ 9: K BININT1 3
+ 11: K BININT1 4
+ 13: t TUPLE (MARK at 8)
+ 14: q BINPUT 1
+ 16: } EMPTY_DICT
+ 17: q BINPUT 2
+ 19: c GLOBAL '_codecs encode'
+ 35: q BINPUT 3
+ 37: ( MARK
+ 38: X BINUNICODE 'abc'
+ 46: q BINPUT 4
+ 48: X BINUNICODE 'latin1'
+ 59: q BINPUT 5
+ 61: t TUPLE (MARK at 37)
+ 62: q BINPUT 6
+ 64: R REDUCE
+ 65: q BINPUT 7
+ 67: X BINUNICODE 'def'
+ 75: q BINPUT 8
+ 77: s SETITEM
+ 78: e APPENDS (MARK at 3)
+ 79: . STOP
+highest protocol among opcodes = 1
+
+Exercise the INST/OBJ/BUILD family.
+
+>>> import pickletools
+>>> dis(pickle.dumps(pickletools.dis, 0))
+ 0: c GLOBAL 'pickletools dis'
+ 17: p PUT 0
+ 20: . STOP
+highest protocol among opcodes = 0
+
+>>> from pickletools import _Example
+>>> x = [_Example(42)] * 2
+>>> dis(pickle.dumps(x, 0))
+ 0: ( MARK
+ 1: l LIST (MARK at 0)
+ 2: p PUT 0
+ 5: c GLOBAL 'copy_reg _reconstructor'
+ 30: p PUT 1
+ 33: ( MARK
+ 34: c GLOBAL 'pickletools _Example'
+ 56: p PUT 2
+ 59: c GLOBAL '__builtin__ object'
+ 79: p PUT 3
+ 82: N NONE
+ 83: t TUPLE (MARK at 33)
+ 84: p PUT 4
+ 87: R REDUCE
+ 88: p PUT 5
+ 91: ( MARK
+ 92: d DICT (MARK at 91)
+ 93: p PUT 6
+ 96: V UNICODE 'value'
+ 103: p PUT 7
+ 106: I INT 42
+ 110: s SETITEM
+ 111: b BUILD
+ 112: a APPEND
+ 113: g GET 5
+ 116: a APPEND
+ 117: . STOP
+highest protocol among opcodes = 0
+
+>>> dis(pickle.dumps(x, 1))
+ 0: ] EMPTY_LIST
+ 1: q BINPUT 0
+ 3: ( MARK
+ 4: c GLOBAL 'copy_reg _reconstructor'
+ 29: q BINPUT 1
+ 31: ( MARK
+ 32: c GLOBAL 'pickletools _Example'
+ 54: q BINPUT 2
+ 56: c GLOBAL '__builtin__ object'
+ 76: q BINPUT 3
+ 78: N NONE
+ 79: t TUPLE (MARK at 31)
+ 80: q BINPUT 4
+ 82: R REDUCE
+ 83: q BINPUT 5
+ 85: } EMPTY_DICT
+ 86: q BINPUT 6
+ 88: X BINUNICODE 'value'
+ 98: q BINPUT 7
+ 100: K BININT1 42
+ 102: s SETITEM
+ 103: b BUILD
+ 104: h BINGET 5
+ 106: e APPENDS (MARK at 3)
+ 107: . STOP
+highest protocol among opcodes = 1
+
+Try "the canonical" recursive-object test.
+
+>>> L = []
+>>> T = L,
+>>> L.append(T)
+>>> L[0] is T
+True
+>>> T[0] is L
+True
+>>> L[0][0] is L
+True
+>>> T[0][0] is T
+True
+>>> dis(pickle.dumps(L, 0))
+ 0: ( MARK
+ 1: l LIST (MARK at 0)
+ 2: p PUT 0
+ 5: ( MARK
+ 6: g GET 0
+ 9: t TUPLE (MARK at 5)
+ 10: p PUT 1
+ 13: a APPEND
+ 14: . STOP
+highest protocol among opcodes = 0
+
+>>> dis(pickle.dumps(L, 1))
+ 0: ] EMPTY_LIST
+ 1: q BINPUT 0
+ 3: ( MARK
+ 4: h BINGET 0
+ 6: t TUPLE (MARK at 3)
+ 7: q BINPUT 1
+ 9: a APPEND
+ 10: . STOP
+highest protocol among opcodes = 1
+
+Note that, in the protocol 0 pickle of the recursive tuple, the disassembler
+has to emulate the stack in order to realize that the POP opcode at 16 gets
+rid of the MARK at 0.
+
+>>> dis(pickle.dumps(T, 0))
+ 0: ( MARK
+ 1: ( MARK
+ 2: l LIST (MARK at 1)
+ 3: p PUT 0
+ 6: ( MARK
+ 7: g GET 0
+ 10: t TUPLE (MARK at 6)
+ 11: p PUT 1
+ 14: a APPEND
+ 15: 0 POP
+ 16: 0 POP (MARK at 0)
+ 17: g GET 1
+ 20: . STOP
+highest protocol among opcodes = 0
+
+>>> dis(pickle.dumps(T, 1))
+ 0: ( MARK
+ 1: ] EMPTY_LIST
+ 2: q BINPUT 0
+ 4: ( MARK
+ 5: h BINGET 0
+ 7: t TUPLE (MARK at 4)
+ 8: q BINPUT 1
+ 10: a APPEND
+ 11: 1 POP_MARK (MARK at 0)
+ 12: h BINGET 1
+ 14: . STOP
+highest protocol among opcodes = 1
+
+Try protocol 2.
+
+>>> dis(pickle.dumps(L, 2))
+ 0: \x80 PROTO 2
+ 2: ] EMPTY_LIST
+ 3: q BINPUT 0
+ 5: h BINGET 0
+ 7: \x85 TUPLE1
+ 8: q BINPUT 1
+ 10: a APPEND
+ 11: . STOP
+highest protocol among opcodes = 2
+
+>>> dis(pickle.dumps(T, 2))
+ 0: \x80 PROTO 2
+ 2: ] EMPTY_LIST
+ 3: q BINPUT 0
+ 5: h BINGET 0
+ 7: \x85 TUPLE1
+ 8: q BINPUT 1
+ 10: a APPEND
+ 11: 0 POP
+ 12: h BINGET 1
+ 14: . STOP
+highest protocol among opcodes = 2
+
+Try protocol 3 with annotations:
+
+>>> dis(pickle.dumps(T, 3), annotate=1)
+ 0: \x80 PROTO 3 Protocol version indicator.
+ 2: ] EMPTY_LIST Push an empty list.
+ 3: q BINPUT 0 Store the stack top into the memo. The stack is not popped.
+ 5: h BINGET 0 Read an object from the memo and push it on the stack.
+ 7: \x85 TUPLE1 Build a one-tuple out of the topmost item on the stack.
+ 8: q BINPUT 1 Store the stack top into the memo. The stack is not popped.
+ 10: a APPEND Append an object to a list.
+ 11: 0 POP Discard the top stack item, shrinking the stack by one item.
+ 12: h BINGET 1 Read an object from the memo and push it on the stack.
+ 14: . STOP Stop the unpickling machine.
+highest protocol among opcodes = 2
+
+"""
+
+_memo_test = r"""
+>>> import pickle
+>>> import io
+>>> f = io.BytesIO()
+>>> p = pickle.Pickler(f, 2)
+>>> x = [1, 2, 3]
+>>> p.dump(x)
+>>> p.dump(x)
+>>> f.seek(0)
+0
+>>> memo = {}
+>>> dis(f, memo=memo)
+ 0: \x80 PROTO 2
+ 2: ] EMPTY_LIST
+ 3: q BINPUT 0
+ 5: ( MARK
+ 6: K BININT1 1
+ 8: K BININT1 2
+ 10: K BININT1 3
+ 12: e APPENDS (MARK at 5)
+ 13: . STOP
+highest protocol among opcodes = 2
+>>> dis(f, memo=memo)
+ 14: \x80 PROTO 2
+ 16: h BINGET 0
+ 18: . STOP
+highest protocol among opcodes = 2
+"""
+
+__test__ = {'disassembler_test': _dis_test,
+ 'disassembler_memo_test': _memo_test,
+ }
+
+def _test():
+ import doctest
+ return doctest.testmod()
+
+if __name__ == "__main__":
+ import argparse
+ parser = argparse.ArgumentParser(
+ description='disassemble one or more pickle files')
+ parser.add_argument(
+ 'pickle_file', type=argparse.FileType('br'),
+ nargs='*', help='the pickle file')
+ parser.add_argument(
+ '-o', '--output', default=sys.stdout, type=argparse.FileType('w'),
+ help='the file where the output should be written')
+ parser.add_argument(
+ '-m', '--memo', action='store_true',
+ help='preserve memo between disassemblies')
+ parser.add_argument(
+ '-l', '--indentlevel', default=4, type=int,
+ help='the number of blanks by which to indent a new MARK level')
+ parser.add_argument(
+ '-a', '--annotate', action='store_true',
+ help='annotate each line with a short opcode description')
+ parser.add_argument(
+ '-p', '--preamble', default="==> {name} <==",
+ help='if more than one pickle file is specified, print this before'
+ ' each disassembly')
+ parser.add_argument(
+ '-t', '--test', action='store_true',
+ help='run self-test suite')
+ parser.add_argument(
+ '-v', action='store_true',
+ help='run verbosely; only affects self-test run')
+ args = parser.parse_args()
+ if args.test:
+ _test()
+ else:
+ annotate = 30 if args.annotate else 0
+ if not args.pickle_file:
+ parser.print_help()
+ elif len(args.pickle_file) == 1:
+ dis(args.pickle_file[0], args.output, None,
+ args.indentlevel, annotate)
+ else:
+ memo = {} if args.memo else None
+ for f in args.pickle_file:
+ preamble = args.preamble.format(name=f.name)
+ args.output.write(preamble + '\n')
+ dis(f, args.output, memo, args.indentlevel, annotate)
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/platform.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/platform.py
new file mode 100644
index 0000000000000000000000000000000000000000..8e32b2a45e8a575d1c64fd553803fe05847885eb
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/platform.py
@@ -0,0 +1,1245 @@
+#!/usr/bin/env python3
+
+""" This module tries to retrieve as much platform-identifying data as
+ possible. It makes this information available via function APIs.
+
+ If called from the command line, it prints the platform
+ information concatenated as single string to stdout. The output
+ format is useable as part of a filename.
+
+"""
+# This module is maintained by Marc-Andre Lemburg .
+# If you find problems, please submit bug reports/patches via the
+# Python bug tracker (http://bugs.python.org) and assign them to "lemburg".
+#
+# Still needed:
+# * support for MS-DOS (PythonDX ?)
+# * support for Amiga and other still unsupported platforms running Python
+# * support for additional Linux distributions
+#
+# Many thanks to all those who helped adding platform-specific
+# checks (in no particular order):
+#
+# Charles G Waldman, David Arnold, Gordon McMillan, Ben Darnell,
+# Jeff Bauer, Cliff Crawford, Ivan Van Laningham, Josef
+# Betancourt, Randall Hopper, Karl Putland, John Farrell, Greg
+# Andruk, Just van Rossum, Thomas Heller, Mark R. Levinson, Mark
+# Hammond, Bill Tutt, Hans Nowak, Uwe Zessin (OpenVMS support),
+# Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter, Steve
+# Dower
+#
+# History:
+#
+#
+#
+# 1.0.8 - changed Windows support to read version from kernel32.dll
+# 1.0.7 - added DEV_NULL
+# 1.0.6 - added linux_distribution()
+# 1.0.5 - fixed Java support to allow running the module on Jython
+# 1.0.4 - added IronPython support
+# 1.0.3 - added normalization of Windows system name
+# 1.0.2 - added more Windows support
+# 1.0.1 - reformatted to make doc.py happy
+# 1.0.0 - reformatted a bit and checked into Python CVS
+# 0.8.0 - added sys.version parser and various new access
+# APIs (python_version(), python_compiler(), etc.)
+# 0.7.2 - fixed architecture() to use sizeof(pointer) where available
+# 0.7.1 - added support for Caldera OpenLinux
+# 0.7.0 - some fixes for WinCE; untabified the source file
+# 0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and
+# vms_lib.getsyi() configured
+# 0.6.1 - added code to prevent 'uname -p' on platforms which are
+# known not to support it
+# 0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k;
+# did some cleanup of the interfaces - some APIs have changed
+# 0.5.5 - fixed another type in the MacOS code... should have
+# used more coffee today ;-)
+# 0.5.4 - fixed a few typos in the MacOS code
+# 0.5.3 - added experimental MacOS support; added better popen()
+# workarounds in _syscmd_ver() -- still not 100% elegant
+# though
+# 0.5.2 - fixed uname() to return '' instead of 'unknown' in all
+# return values (the system uname command tends to return
+# 'unknown' instead of just leaving the field empty)
+# 0.5.1 - included code for slackware dist; added exception handlers
+# to cover up situations where platforms don't have os.popen
+# (e.g. Mac) or fail on socket.gethostname(); fixed libc
+# detection RE
+# 0.5.0 - changed the API names referring to system commands to *syscmd*;
+# added java_ver(); made syscmd_ver() a private
+# API (was system_ver() in previous versions) -- use uname()
+# instead; extended the win32_ver() to also return processor
+# type information
+# 0.4.0 - added win32_ver() and modified the platform() output for WinXX
+# 0.3.4 - fixed a bug in _follow_symlinks()
+# 0.3.3 - fixed popen() and "file" command invocation bugs
+# 0.3.2 - added architecture() API and support for it in platform()
+# 0.3.1 - fixed syscmd_ver() RE to support Windows NT
+# 0.3.0 - added system alias support
+# 0.2.3 - removed 'wince' again... oh well.
+# 0.2.2 - added 'wince' to syscmd_ver() supported platforms
+# 0.2.1 - added cache logic and changed the platform string format
+# 0.2.0 - changed the API to use functions instead of module globals
+# since some action take too long to be run on module import
+# 0.1.0 - first release
+#
+# You can always get the latest version of this module at:
+#
+# http://www.egenix.com/files/python/platform.py
+#
+# If that URL should fail, try contacting the author.
+
+__copyright__ = """
+ Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
+ Copyright (c) 2000-2010, eGenix.com Software GmbH; mailto:info@egenix.com
+
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee or royalty is hereby granted,
+ provided that the above copyright notice appear in all copies and that
+ both that copyright notice and this permission notice appear in
+ supporting documentation or portions thereof, including modifications,
+ that you make.
+
+ EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
+ INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
+
+"""
+
+__version__ = '1.0.8'
+
+import collections
+import os
+import re
+import sys
+
+### Globals & Constants
+
+# Helper for comparing two version number strings.
+# Based on the description of the PHP's version_compare():
+# http://php.net/manual/en/function.version-compare.php
+
+_ver_stages = {
+ # any string not found in this dict, will get 0 assigned
+ 'dev': 10,
+ 'alpha': 20, 'a': 20,
+ 'beta': 30, 'b': 30,
+ 'c': 40,
+ 'RC': 50, 'rc': 50,
+ # number, will get 100 assigned
+ 'pl': 200, 'p': 200,
+}
+
+_component_re = re.compile(r'([0-9]+|[._+-])')
+
+def _comparable_version(version):
+ result = []
+ for v in _component_re.split(version):
+ if v not in '._+-':
+ try:
+ v = int(v, 10)
+ t = 100
+ except ValueError:
+ t = _ver_stages.get(v, 0)
+ result.extend((t, v))
+ return result
+
+### Platform specific APIs
+
+_libc_search = re.compile(b'(__libc_init)'
+ b'|'
+ b'(GLIBC_([0-9.]+))'
+ b'|'
+ br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
+
+def libc_ver(executable=None, lib='', version='', chunksize=16384):
+
+ """ Tries to determine the libc version that the file executable
+ (which defaults to the Python interpreter) is linked against.
+
+ Returns a tuple of strings (lib,version) which default to the
+ given parameters in case the lookup fails.
+
+ Note that the function has intimate knowledge of how different
+ libc versions add symbols to the executable and thus is probably
+ only useable for executables compiled using gcc.
+
+ The file is read and scanned in chunks of chunksize bytes.
+
+ """
+ if executable is None:
+ try:
+ ver = os.confstr('CS_GNU_LIBC_VERSION')
+ # parse 'glibc 2.28' as ('glibc', '2.28')
+ parts = ver.split(maxsplit=1)
+ if len(parts) == 2:
+ return tuple(parts)
+ except (AttributeError, ValueError, OSError):
+ # os.confstr() or CS_GNU_LIBC_VERSION value not available
+ pass
+
+ executable = sys.executable
+
+ V = _comparable_version
+ if hasattr(os.path, 'realpath'):
+ # Python 2.2 introduced os.path.realpath(); it is used
+ # here to work around problems with Cygwin not being
+ # able to open symlinks for reading
+ executable = os.path.realpath(executable)
+ with open(executable, 'rb') as f:
+ binary = f.read(chunksize)
+ pos = 0
+ while pos < len(binary):
+ if b'libc' in binary or b'GLIBC' in binary:
+ m = _libc_search.search(binary, pos)
+ else:
+ m = None
+ if not m or m.end() == len(binary):
+ chunk = f.read(chunksize)
+ if chunk:
+ binary = binary[max(pos, len(binary) - 1000):] + chunk
+ pos = 0
+ continue
+ if not m:
+ break
+ libcinit, glibc, glibcversion, so, threads, soversion = [
+ s.decode('latin1') if s is not None else s
+ for s in m.groups()]
+ if libcinit and not lib:
+ lib = 'libc'
+ elif glibc:
+ if lib != 'glibc':
+ lib = 'glibc'
+ version = glibcversion
+ elif V(glibcversion) > V(version):
+ version = glibcversion
+ elif so:
+ if lib != 'glibc':
+ lib = 'libc'
+ if soversion and (not version or V(soversion) > V(version)):
+ version = soversion
+ if threads and version[-len(threads):] != threads:
+ version = version + threads
+ pos = m.end()
+ return lib, version
+
+def _norm_version(version, build=''):
+
+ """ Normalize the version and build strings and return a single
+ version string using the format major.minor.build (or patchlevel).
+ """
+ l = version.split('.')
+ if build:
+ l.append(build)
+ try:
+ strings = list(map(str, map(int, l)))
+ except ValueError:
+ strings = l
+ version = '.'.join(strings[:3])
+ return version
+
+_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
+ r'.*'
+ r'\[.* ([\d.]+)\])')
+
+# Examples of VER command output:
+#
+# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
+# Windows XP: Microsoft Windows XP [Version 5.1.2600]
+# Windows Vista: Microsoft Windows [Version 6.0.6002]
+#
+# Note that the "Version" string gets localized on different
+# Windows versions.
+
+def _syscmd_ver(system='', release='', version='',
+
+ supported_platforms=('win32', 'win16', 'dos')):
+
+ """ Tries to figure out the OS version used and returns
+ a tuple (system, release, version).
+
+ It uses the "ver" shell command for this which is known
+ to exists on Windows, DOS. XXX Others too ?
+
+ In case this fails, the given parameters are used as
+ defaults.
+
+ """
+ if sys.platform not in supported_platforms:
+ return system, release, version
+
+ # Try some common cmd strings
+ import subprocess
+ for cmd in ('ver', 'command /c ver', 'cmd /c ver'):
+ try:
+ info = subprocess.check_output(cmd,
+ stderr=subprocess.DEVNULL,
+ text=True,
+ shell=True)
+ except (OSError, subprocess.CalledProcessError) as why:
+ #print('Command %s failed: %s' % (cmd, why))
+ continue
+ else:
+ break
+ else:
+ return system, release, version
+
+ # Parse the output
+ info = info.strip()
+ m = _ver_output.match(info)
+ if m is not None:
+ system, release, version = m.groups()
+ # Strip trailing dots from version and release
+ if release[-1] == '.':
+ release = release[:-1]
+ if version[-1] == '.':
+ version = version[:-1]
+ # Normalize the version and build strings (eliminating additional
+ # zeros)
+ version = _norm_version(version)
+ return system, release, version
+
+_WIN32_CLIENT_RELEASES = {
+ (5, 0): "2000",
+ (5, 1): "XP",
+ # Strictly, 5.2 client is XP 64-bit, but platform.py historically
+ # has always called it 2003 Server
+ (5, 2): "2003Server",
+ (5, None): "post2003",
+
+ (6, 0): "Vista",
+ (6, 1): "7",
+ (6, 2): "8",
+ (6, 3): "8.1",
+ (6, None): "post8.1",
+
+ (10, 0): "10",
+ (10, None): "post10",
+}
+
+# Server release name lookup will default to client names if necessary
+_WIN32_SERVER_RELEASES = {
+ (5, 2): "2003Server",
+
+ (6, 0): "2008Server",
+ (6, 1): "2008ServerR2",
+ (6, 2): "2012Server",
+ (6, 3): "2012ServerR2",
+ (6, None): "post2012ServerR2",
+}
+
+def win32_is_iot():
+ return win32_edition() in ('IoTUAP', 'NanoServer', 'WindowsCoreHeadless', 'IoTEdgeOS')
+
+def win32_edition():
+ try:
+ try:
+ import winreg
+ except ImportError:
+ import _winreg as winreg
+ except ImportError:
+ pass
+ else:
+ try:
+ cvkey = r'SOFTWARE\Microsoft\Windows NT\CurrentVersion'
+ with winreg.OpenKeyEx(winreg.HKEY_LOCAL_MACHINE, cvkey) as key:
+ return winreg.QueryValueEx(key, 'EditionId')[0]
+ except OSError:
+ pass
+
+ return None
+
+def win32_ver(release='', version='', csd='', ptype=''):
+ try:
+ from sys import getwindowsversion
+ except ImportError:
+ return release, version, csd, ptype
+
+ winver = getwindowsversion()
+ try:
+ major, minor, build = map(int, _syscmd_ver()[2].split('.'))
+ except ValueError:
+ major, minor, build = winver.platform_version or winver[:3]
+ version = '{0}.{1}.{2}'.format(major, minor, build)
+
+ release = (_WIN32_CLIENT_RELEASES.get((major, minor)) or
+ _WIN32_CLIENT_RELEASES.get((major, None)) or
+ release)
+
+ # getwindowsversion() reflect the compatibility mode Python is
+ # running under, and so the service pack value is only going to be
+ # valid if the versions match.
+ if winver[:2] == (major, minor):
+ try:
+ csd = 'SP{}'.format(winver.service_pack_major)
+ except AttributeError:
+ if csd[:13] == 'Service Pack ':
+ csd = 'SP' + csd[13:]
+
+ # VER_NT_SERVER = 3
+ if getattr(winver, 'product_type', None) == 3:
+ release = (_WIN32_SERVER_RELEASES.get((major, minor)) or
+ _WIN32_SERVER_RELEASES.get((major, None)) or
+ release)
+
+ try:
+ try:
+ import winreg
+ except ImportError:
+ import _winreg as winreg
+ except ImportError:
+ pass
+ else:
+ try:
+ cvkey = r'SOFTWARE\Microsoft\Windows NT\CurrentVersion'
+ with winreg.OpenKeyEx(winreg.HKEY_LOCAL_MACHINE, cvkey) as key:
+ ptype = winreg.QueryValueEx(key, 'CurrentType')[0]
+ except OSError:
+ pass
+
+ return release, version, csd, ptype
+
+
+def _mac_ver_xml():
+ fn = '/System/Library/CoreServices/SystemVersion.plist'
+ if not os.path.exists(fn):
+ if 'SDKROOT' in os.environ:
+ fn = os.environ['SDKROOT'] + fn
+ if not os.path.exists(fn):
+ return None
+ else:
+ return None
+
+ try:
+ import plistlib
+ except ImportError:
+ return None
+
+ with open(fn, 'rb') as f:
+ pl = plistlib.load(f)
+ release = pl['ProductVersion']
+ versioninfo = ('', '', '')
+ machine = os.uname().machine
+ if machine in ('ppc', 'Power Macintosh'):
+ # Canonical name
+ machine = 'PowerPC'
+
+ return release, versioninfo, machine
+
+
+def mac_ver(release='', versioninfo=('', '', ''), machine=''):
+
+ """ Get macOS version information and return it as tuple (release,
+ versioninfo, machine) with versioninfo being a tuple (version,
+ dev_stage, non_release_version).
+
+ Entries which cannot be determined are set to the parameter values
+ which default to ''. All tuple entries are strings.
+ """
+
+ # First try reading the information from an XML file which should
+ # always be present
+ info = _mac_ver_xml()
+ if info is not None:
+ return info
+
+ # If that also doesn't work return the default values
+ return release, versioninfo, machine
+
+def _java_getprop(name, default):
+
+ from java.lang import System
+ try:
+ value = System.getProperty(name)
+ if value is None:
+ return default
+ return value
+ except AttributeError:
+ return default
+
+def java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')):
+
+ """ Version interface for Jython.
+
+ Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
+ a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
+ tuple (os_name, os_version, os_arch).
+
+ Values which cannot be determined are set to the defaults
+ given as parameters (which all default to '').
+
+ """
+ # Import the needed APIs
+ try:
+ import java.lang
+ except ImportError:
+ return release, vendor, vminfo, osinfo
+
+ vendor = _java_getprop('java.vendor', vendor)
+ release = _java_getprop('java.version', release)
+ vm_name, vm_release, vm_vendor = vminfo
+ vm_name = _java_getprop('java.vm.name', vm_name)
+ vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
+ vm_release = _java_getprop('java.vm.version', vm_release)
+ vminfo = vm_name, vm_release, vm_vendor
+ os_name, os_version, os_arch = osinfo
+ os_arch = _java_getprop('java.os.arch', os_arch)
+ os_name = _java_getprop('java.os.name', os_name)
+ os_version = _java_getprop('java.os.version', os_version)
+ osinfo = os_name, os_version, os_arch
+
+ return release, vendor, vminfo, osinfo
+
+### System name aliasing
+
+def system_alias(system, release, version):
+
+ """ Returns (system, release, version) aliased to common
+ marketing names used for some systems.
+
+ It also does some reordering of the information in some cases
+ where it would otherwise cause confusion.
+
+ """
+ if system == 'SunOS':
+ # Sun's OS
+ if release < '5':
+ # These releases use the old name SunOS
+ return system, release, version
+ # Modify release (marketing release = SunOS release - 3)
+ l = release.split('.')
+ if l:
+ try:
+ major = int(l[0])
+ except ValueError:
+ pass
+ else:
+ major = major - 3
+ l[0] = str(major)
+ release = '.'.join(l)
+ if release < '6':
+ system = 'Solaris'
+ else:
+ # XXX Whatever the new SunOS marketing name is...
+ system = 'Solaris'
+
+ elif system == 'IRIX64':
+ # IRIX reports IRIX64 on platforms with 64-bit support; yet it
+ # is really a version and not a different platform, since 32-bit
+ # apps are also supported..
+ system = 'IRIX'
+ if version:
+ version = version + ' (64bit)'
+ else:
+ version = '64bit'
+
+ elif system in ('win32', 'win16'):
+ # In case one of the other tricks
+ system = 'Windows'
+
+ # bpo-35516: Don't replace Darwin with macOS since input release and
+ # version arguments can be different than the currently running version.
+
+ return system, release, version
+
+### Various internal helpers
+
+def _platform(*args):
+
+ """ Helper to format the platform string in a filename
+ compatible format e.g. "system-version-machine".
+ """
+ # Format the platform string
+ platform = '-'.join(x.strip() for x in filter(len, args))
+
+ # Cleanup some possible filename obstacles...
+ platform = platform.replace(' ', '_')
+ platform = platform.replace('/', '-')
+ platform = platform.replace('\\', '-')
+ platform = platform.replace(':', '-')
+ platform = platform.replace(';', '-')
+ platform = platform.replace('"', '-')
+ platform = platform.replace('(', '-')
+ platform = platform.replace(')', '-')
+
+ # No need to report 'unknown' information...
+ platform = platform.replace('unknown', '')
+
+ # Fold '--'s and remove trailing '-'
+ while 1:
+ cleaned = platform.replace('--', '-')
+ if cleaned == platform:
+ break
+ platform = cleaned
+ while platform[-1] == '-':
+ platform = platform[:-1]
+
+ return platform
+
+def _node(default=''):
+
+ """ Helper to determine the node name of this machine.
+ """
+ try:
+ import socket
+ except ImportError:
+ # No sockets...
+ return default
+ try:
+ return socket.gethostname()
+ except OSError:
+ # Still not working...
+ return default
+
+def _follow_symlinks(filepath):
+
+ """ In case filepath is a symlink, follow it until a
+ real file is reached.
+ """
+ filepath = os.path.abspath(filepath)
+ while os.path.islink(filepath):
+ filepath = os.path.normpath(
+ os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
+ return filepath
+
+def _syscmd_uname(option, default=''):
+
+ """ Interface to the system's uname command.
+ """
+ if sys.platform in ('dos', 'win32', 'win16'):
+ # XXX Others too ?
+ return default
+
+ import subprocess
+ try:
+ output = subprocess.check_output(('uname', option),
+ stderr=subprocess.DEVNULL,
+ text=True)
+ except (OSError, subprocess.CalledProcessError):
+ return default
+ return (output.strip() or default)
+
+def _syscmd_file(target, default=''):
+
+ """ Interface to the system's file command.
+
+ The function uses the -b option of the file command to have it
+ omit the filename in its output. Follow the symlinks. It returns
+ default in case the command should fail.
+
+ """
+ if sys.platform in ('dos', 'win32', 'win16'):
+ # XXX Others too ?
+ return default
+
+ import subprocess
+ target = _follow_symlinks(target)
+ # "file" output is locale dependent: force the usage of the C locale
+ # to get deterministic behavior.
+ env = dict(os.environ, LC_ALL='C')
+ try:
+ # -b: do not prepend filenames to output lines (brief mode)
+ output = subprocess.check_output(['file', '-b', target],
+ stderr=subprocess.DEVNULL,
+ env=env)
+ except (OSError, subprocess.CalledProcessError):
+ return default
+ if not output:
+ return default
+ # With the C locale, the output should be mostly ASCII-compatible.
+ # Decode from Latin-1 to prevent Unicode decode error.
+ return output.decode('latin-1')
+
+### Information about the used architecture
+
+# Default values for architecture; non-empty strings override the
+# defaults given as parameters
+_default_architecture = {
+ 'win32': ('', 'WindowsPE'),
+ 'win16': ('', 'Windows'),
+ 'dos': ('', 'MSDOS'),
+}
+
+def architecture(executable=sys.executable, bits='', linkage=''):
+
+ """ Queries the given executable (defaults to the Python interpreter
+ binary) for various architecture information.
+
+ Returns a tuple (bits, linkage) which contains information about
+ the bit architecture and the linkage format used for the
+ executable. Both values are returned as strings.
+
+ Values that cannot be determined are returned as given by the
+ parameter presets. If bits is given as '', the sizeof(pointer)
+ (or sizeof(long) on Python version < 1.5.2) is used as
+ indicator for the supported pointer size.
+
+ The function relies on the system's "file" command to do the
+ actual work. This is available on most if not all Unix
+ platforms. On some non-Unix platforms where the "file" command
+ does not exist and the executable is set to the Python interpreter
+ binary defaults from _default_architecture are used.
+
+ """
+ # Use the sizeof(pointer) as default number of bits if nothing
+ # else is given as default.
+ if not bits:
+ import struct
+ size = struct.calcsize('P')
+ bits = str(size * 8) + 'bit'
+
+ # Get data from the 'file' system command
+ if executable:
+ fileout = _syscmd_file(executable, '')
+ else:
+ fileout = ''
+
+ if not fileout and \
+ executable == sys.executable:
+ # "file" command did not return anything; we'll try to provide
+ # some sensible defaults then...
+ if sys.platform in _default_architecture:
+ b, l = _default_architecture[sys.platform]
+ if b:
+ bits = b
+ if l:
+ linkage = l
+ return bits, linkage
+
+ if 'executable' not in fileout and 'shared object' not in fileout:
+ # Format not supported
+ return bits, linkage
+
+ # Bits
+ if '32-bit' in fileout:
+ bits = '32bit'
+ elif 'N32' in fileout:
+ # On Irix only
+ bits = 'n32bit'
+ elif '64-bit' in fileout:
+ bits = '64bit'
+
+ # Linkage
+ if 'ELF' in fileout:
+ linkage = 'ELF'
+ elif 'PE' in fileout:
+ # E.g. Windows uses this format
+ if 'Windows' in fileout:
+ linkage = 'WindowsPE'
+ else:
+ linkage = 'PE'
+ elif 'COFF' in fileout:
+ linkage = 'COFF'
+ elif 'MS-DOS' in fileout:
+ linkage = 'MSDOS'
+ else:
+ # XXX the A.OUT format also falls under this class...
+ pass
+
+ return bits, linkage
+
+### Portable uname() interface
+
+uname_result = collections.namedtuple("uname_result",
+ "system node release version machine processor")
+
+_uname_cache = None
+
+def uname():
+
+ """ Fairly portable uname interface. Returns a tuple
+ of strings (system, node, release, version, machine, processor)
+ identifying the underlying platform.
+
+ Note that unlike the os.uname function this also returns
+ possible processor information as an additional tuple entry.
+
+ Entries which cannot be determined are set to ''.
+
+ """
+ global _uname_cache
+ no_os_uname = 0
+
+ if _uname_cache is not None:
+ return _uname_cache
+
+ processor = ''
+
+ # Get some infos from the builtin os.uname API...
+ try:
+ system, node, release, version, machine = os.uname()
+ except AttributeError:
+ no_os_uname = 1
+
+ if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
+ # Hmm, no there is either no uname or uname has returned
+ #'unknowns'... we'll have to poke around the system then.
+ if no_os_uname:
+ system = sys.platform
+ release = ''
+ version = ''
+ node = _node()
+ machine = ''
+
+ use_syscmd_ver = 1
+
+ # Try win32_ver() on win32 platforms
+ if system == 'win32':
+ release, version, csd, ptype = win32_ver()
+ if release and version:
+ use_syscmd_ver = 0
+ # Try to use the PROCESSOR_* environment variables
+ # available on Win XP and later; see
+ # http://support.microsoft.com/kb/888731 and
+ # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
+ if not machine:
+ # WOW64 processes mask the native architecture
+ if "PROCESSOR_ARCHITEW6432" in os.environ:
+ machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
+ else:
+ machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
+ if not processor:
+ processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
+
+ # Try the 'ver' system command available on some
+ # platforms
+ if use_syscmd_ver:
+ system, release, version = _syscmd_ver(system)
+ # Normalize system to what win32_ver() normally returns
+ # (_syscmd_ver() tends to return the vendor name as well)
+ if system == 'Microsoft Windows':
+ system = 'Windows'
+ elif system == 'Microsoft' and release == 'Windows':
+ # Under Windows Vista and Windows Server 2008,
+ # Microsoft changed the output of the ver command. The
+ # release is no longer printed. This causes the
+ # system and release to be misidentified.
+ system = 'Windows'
+ if '6.0' == version[:3]:
+ release = 'Vista'
+ else:
+ release = ''
+
+ # In case we still don't know anything useful, we'll try to
+ # help ourselves
+ if system in ('win32', 'win16'):
+ if not version:
+ if system == 'win32':
+ version = '32bit'
+ else:
+ version = '16bit'
+ system = 'Windows'
+
+ elif system[:4] == 'java':
+ release, vendor, vminfo, osinfo = java_ver()
+ system = 'Java'
+ version = ', '.join(vminfo)
+ if not version:
+ version = vendor
+
+ # System specific extensions
+ if system == 'OpenVMS':
+ # OpenVMS seems to have release and version mixed up
+ if not release or release == '0':
+ release = version
+ version = ''
+ # Get processor information
+ try:
+ import vms_lib
+ except ImportError:
+ pass
+ else:
+ csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
+ if (cpu_number >= 128):
+ processor = 'Alpha'
+ else:
+ processor = 'VAX'
+ if not processor:
+ # Get processor information from the uname system command
+ processor = _syscmd_uname('-p', '')
+
+ #If any unknowns still exist, replace them with ''s, which are more portable
+ if system == 'unknown':
+ system = ''
+ if node == 'unknown':
+ node = ''
+ if release == 'unknown':
+ release = ''
+ if version == 'unknown':
+ version = ''
+ if machine == 'unknown':
+ machine = ''
+ if processor == 'unknown':
+ processor = ''
+
+ # normalize name
+ if system == 'Microsoft' and release == 'Windows':
+ system = 'Windows'
+ release = 'Vista'
+
+ _uname_cache = uname_result(system, node, release, version,
+ machine, processor)
+ return _uname_cache
+
+### Direct interfaces to some of the uname() return values
+
+def system():
+
+ """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
+
+ An empty string is returned if the value cannot be determined.
+
+ """
+ return uname().system
+
+def node():
+
+ """ Returns the computer's network name (which may not be fully
+ qualified)
+
+ An empty string is returned if the value cannot be determined.
+
+ """
+ return uname().node
+
+def release():
+
+ """ Returns the system's release, e.g. '2.2.0' or 'NT'
+
+ An empty string is returned if the value cannot be determined.
+
+ """
+ return uname().release
+
+def version():
+
+ """ Returns the system's release version, e.g. '#3 on degas'
+
+ An empty string is returned if the value cannot be determined.
+
+ """
+ return uname().version
+
+def machine():
+
+ """ Returns the machine type, e.g. 'i386'
+
+ An empty string is returned if the value cannot be determined.
+
+ """
+ return uname().machine
+
+def processor():
+
+ """ Returns the (true) processor name, e.g. 'amdk6'
+
+ An empty string is returned if the value cannot be
+ determined. Note that many platforms do not provide this
+ information or simply return the same value as for machine(),
+ e.g. NetBSD does this.
+
+ """
+ return uname().processor
+
+### Various APIs for extracting information from sys.version
+
+_sys_version_parser = re.compile(
+ r'([\w.+]+)\s*' # "version"
+ r'(?:\|[^|]*\|)?\s*' # version extra
+ r'\(#?([^,]+)' # "(#buildno"
+ r'(?:,\s*([\w ]*)' # ", builddate"
+ r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)"
+ r'\[([^\]]+)\]?', re.ASCII) # "[compiler]"
+
+_ironpython_sys_version_parser = re.compile(
+ r'IronPython\s*'
+ r'([\d\.]+)'
+ r'(?: \(([\d\.]+)\))?'
+ r' on (.NET [\d\.]+)', re.ASCII)
+
+# IronPython covering 2.6 and 2.7
+_ironpython26_sys_version_parser = re.compile(
+ r'([\d.]+)\s*'
+ r'\(IronPython\s*'
+ r'[\d.]+\s*'
+ r'\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
+)
+
+_pypy_sys_version_parser = re.compile(
+ r'([\w.+]+)\s*'
+ r'\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
+ r'\[PyPy [^\]]+\]?')
+
+_sys_version_cache = {}
+
+def _sys_version(sys_version=None):
+
+ """ Returns a parsed version of Python's sys.version as tuple
+ (name, version, branch, revision, buildno, builddate, compiler)
+ referring to the Python implementation name, version, branch,
+ revision, build number, build date/time as string and the compiler
+ identification string.
+
+ Note that unlike the Python sys.version, the returned value
+ for the Python version will always include the patchlevel (it
+ defaults to '.0').
+
+ The function returns empty strings for tuple entries that
+ cannot be determined.
+
+ sys_version may be given to parse an alternative version
+ string, e.g. if the version was read from a different Python
+ interpreter.
+
+ """
+ # Get the Python version
+ if sys_version is None:
+ sys_version = sys.version
+
+ # Try the cache first
+ result = _sys_version_cache.get(sys_version, None)
+ if result is not None:
+ return result
+
+ # Parse it
+ if 'IronPython' in sys_version:
+ # IronPython
+ name = 'IronPython'
+ if sys_version.startswith('IronPython'):
+ match = _ironpython_sys_version_parser.match(sys_version)
+ else:
+ match = _ironpython26_sys_version_parser.match(sys_version)
+
+ if match is None:
+ raise ValueError(
+ 'failed to parse IronPython sys.version: %s' %
+ repr(sys_version))
+
+ version, alt_version, compiler = match.groups()
+ buildno = ''
+ builddate = ''
+
+ elif sys.platform.startswith('java'):
+ # Jython
+ name = 'Jython'
+ match = _sys_version_parser.match(sys_version)
+ if match is None:
+ raise ValueError(
+ 'failed to parse Jython sys.version: %s' %
+ repr(sys_version))
+ version, buildno, builddate, buildtime, _ = match.groups()
+ if builddate is None:
+ builddate = ''
+ compiler = sys.platform
+
+ elif "PyPy" in sys_version:
+ # PyPy
+ name = "PyPy"
+ match = _pypy_sys_version_parser.match(sys_version)
+ if match is None:
+ raise ValueError("failed to parse PyPy sys.version: %s" %
+ repr(sys_version))
+ version, buildno, builddate, buildtime = match.groups()
+ compiler = ""
+
+ else:
+ # CPython
+ match = _sys_version_parser.match(sys_version)
+ if match is None:
+ raise ValueError(
+ 'failed to parse CPython sys.version: %s' %
+ repr(sys_version))
+ version, buildno, builddate, buildtime, compiler = \
+ match.groups()
+ name = 'CPython'
+ if builddate is None:
+ builddate = ''
+ elif buildtime:
+ builddate = builddate + ' ' + buildtime
+
+ if hasattr(sys, '_git'):
+ _, branch, revision = sys._git
+ elif hasattr(sys, '_mercurial'):
+ _, branch, revision = sys._mercurial
+ else:
+ branch = ''
+ revision = ''
+
+ # Add the patchlevel version if missing
+ l = version.split('.')
+ if len(l) == 2:
+ l.append('0')
+ version = '.'.join(l)
+
+ # Build and cache the result
+ result = (name, version, branch, revision, buildno, builddate, compiler)
+ _sys_version_cache[sys_version] = result
+ return result
+
+def python_implementation():
+
+ """ Returns a string identifying the Python implementation.
+
+ Currently, the following implementations are identified:
+ 'CPython' (C implementation of Python),
+ 'IronPython' (.NET implementation of Python),
+ 'Jython' (Java implementation of Python),
+ 'PyPy' (Python implementation of Python).
+
+ """
+ return _sys_version()[0]
+
+def python_version():
+
+ """ Returns the Python version as string 'major.minor.patchlevel'
+
+ Note that unlike the Python sys.version, the returned value
+ will always include the patchlevel (it defaults to 0).
+
+ """
+ return _sys_version()[1]
+
+def python_version_tuple():
+
+ """ Returns the Python version as tuple (major, minor, patchlevel)
+ of strings.
+
+ Note that unlike the Python sys.version, the returned value
+ will always include the patchlevel (it defaults to 0).
+
+ """
+ return tuple(_sys_version()[1].split('.'))
+
+def python_branch():
+
+ """ Returns a string identifying the Python implementation
+ branch.
+
+ For CPython this is the SCM branch from which the
+ Python binary was built.
+
+ If not available, an empty string is returned.
+
+ """
+
+ return _sys_version()[2]
+
+def python_revision():
+
+ """ Returns a string identifying the Python implementation
+ revision.
+
+ For CPython this is the SCM revision from which the
+ Python binary was built.
+
+ If not available, an empty string is returned.
+
+ """
+ return _sys_version()[3]
+
+def python_build():
+
+ """ Returns a tuple (buildno, builddate) stating the Python
+ build number and date as strings.
+
+ """
+ return _sys_version()[4:6]
+
+def python_compiler():
+
+ """ Returns a string identifying the compiler used for compiling
+ Python.
+
+ """
+ return _sys_version()[6]
+
+### The Opus Magnum of platform strings :-)
+
+_platform_cache = {}
+
+def platform(aliased=0, terse=0):
+
+ """ Returns a single string identifying the underlying platform
+ with as much useful information as possible (but no more :).
+
+ The output is intended to be human readable rather than
+ machine parseable. It may look different on different
+ platforms and this is intended.
+
+ If "aliased" is true, the function will use aliases for
+ various platforms that report system names which differ from
+ their common names, e.g. SunOS will be reported as
+ Solaris. The system_alias() function is used to implement
+ this.
+
+ Setting terse to true causes the function to return only the
+ absolute minimum information needed to identify the platform.
+
+ """
+ result = _platform_cache.get((aliased, terse), None)
+ if result is not None:
+ return result
+
+ # Get uname information and then apply platform specific cosmetics
+ # to it...
+ system, node, release, version, machine, processor = uname()
+ if machine == processor:
+ processor = ''
+ if aliased:
+ system, release, version = system_alias(system, release, version)
+
+ if system == 'Darwin':
+ # macOS (darwin kernel)
+ macos_release = mac_ver()[0]
+ if macos_release:
+ system = 'macOS'
+ release = macos_release
+
+ if system == 'Windows':
+ # MS platforms
+ rel, vers, csd, ptype = win32_ver(version)
+ if terse:
+ platform = _platform(system, release)
+ else:
+ platform = _platform(system, release, version, csd)
+
+ elif system in ('Linux',):
+ # check for libc vs. glibc
+ libcname, libcversion = libc_ver(sys.executable)
+ platform = _platform(system, release, machine, processor,
+ 'with',
+ libcname+libcversion)
+ elif system == 'Java':
+ # Java platforms
+ r, v, vminfo, (os_name, os_version, os_arch) = java_ver()
+ if terse or not os_name:
+ platform = _platform(system, release, version)
+ else:
+ platform = _platform(system, release, version,
+ 'on',
+ os_name, os_version, os_arch)
+
+ else:
+ # Generic handler
+ if terse:
+ platform = _platform(system, release)
+ else:
+ bits, linkage = architecture(sys.executable)
+ platform = _platform(system, release, machine,
+ processor, bits, linkage)
+
+ _platform_cache[(aliased, terse)] = platform
+ return platform
+
+### Command line interface
+
+if __name__ == '__main__':
+ # Default is to print the aliased verbose platform string
+ terse = ('terse' in sys.argv or '--terse' in sys.argv)
+ aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
+ print(platform(aliased, terse))
+ sys.exit(0)
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/poplib.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/poplib.py
new file mode 100644
index 0000000000000000000000000000000000000000..e3bd2ab1ebc8bd2b08da1631993d344d3e8b5cc1
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/poplib.py
@@ -0,0 +1,481 @@
+"""A POP3 client class.
+
+Based on the J. Myers POP3 draft, Jan. 96
+"""
+
+# Author: David Ascher
+# [heavily stealing from nntplib.py]
+# Updated: Piers Lauder [Jul '97]
+# String method conversion and test jig improvements by ESR, February 2001.
+# Added the POP3_SSL class. Methods loosely based on IMAP_SSL. Hector Urtubia Aug 2003
+
+# Example (see the test function at the end of this file)
+
+# Imports
+
+import errno
+import re
+import socket
+import sys
+
+try:
+ import ssl
+ HAVE_SSL = True
+except ImportError:
+ HAVE_SSL = False
+
+__all__ = ["POP3","error_proto"]
+
+# Exception raised when an error or invalid response is received:
+
+class error_proto(Exception): pass
+
+# Standard Port
+POP3_PORT = 110
+
+# POP SSL PORT
+POP3_SSL_PORT = 995
+
+# Line terminators (we always output CRLF, but accept any of CRLF, LFCR, LF)
+CR = b'\r'
+LF = b'\n'
+CRLF = CR+LF
+
+# maximal line length when calling readline(). This is to prevent
+# reading arbitrary length lines. RFC 1939 limits POP3 line length to
+# 512 characters, including CRLF. We have selected 2048 just to be on
+# the safe side.
+_MAXLINE = 2048
+
+
+class POP3:
+
+ """This class supports both the minimal and optional command sets.
+ Arguments can be strings or integers (where appropriate)
+ (e.g.: retr(1) and retr('1') both work equally well.
+
+ Minimal Command Set:
+ USER name user(name)
+ PASS string pass_(string)
+ STAT stat()
+ LIST [msg] list(msg = None)
+ RETR msg retr(msg)
+ DELE msg dele(msg)
+ NOOP noop()
+ RSET rset()
+ QUIT quit()
+
+ Optional Commands (some servers support these):
+ RPOP name rpop(name)
+ APOP name digest apop(name, digest)
+ TOP msg n top(msg, n)
+ UIDL [msg] uidl(msg = None)
+ CAPA capa()
+ STLS stls()
+ UTF8 utf8()
+
+ Raises one exception: 'error_proto'.
+
+ Instantiate with:
+ POP3(hostname, port=110)
+
+ NB: the POP protocol locks the mailbox from user
+ authorization until QUIT, so be sure to get in, suck
+ the messages, and quit, each time you access the
+ mailbox.
+
+ POP is a line-based protocol, which means large mail
+ messages consume lots of python cycles reading them
+ line-by-line.
+
+ If it's available on your mail server, use IMAP4
+ instead, it doesn't suffer from the two problems
+ above.
+ """
+
+ encoding = 'UTF-8'
+
+ def __init__(self, host, port=POP3_PORT,
+ timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
+ self.host = host
+ self.port = port
+ self._tls_established = False
+ sys.audit("poplib.connect", self, host, port)
+ self.sock = self._create_socket(timeout)
+ self.file = self.sock.makefile('rb')
+ self._debugging = 0
+ self.welcome = self._getresp()
+
+ def _create_socket(self, timeout):
+ return socket.create_connection((self.host, self.port), timeout)
+
+ def _putline(self, line):
+ if self._debugging > 1: print('*put*', repr(line))
+ sys.audit("poplib.putline", self, line)
+ self.sock.sendall(line + CRLF)
+
+
+ # Internal: send one command to the server (through _putline())
+
+ def _putcmd(self, line):
+ if self._debugging: print('*cmd*', repr(line))
+ line = bytes(line, self.encoding)
+ self._putline(line)
+
+
+ # Internal: return one line from the server, stripping CRLF.
+ # This is where all the CPU time of this module is consumed.
+ # Raise error_proto('-ERR EOF') if the connection is closed.
+
+ def _getline(self):
+ line = self.file.readline(_MAXLINE + 1)
+ if len(line) > _MAXLINE:
+ raise error_proto('line too long')
+
+ if self._debugging > 1: print('*get*', repr(line))
+ if not line: raise error_proto('-ERR EOF')
+ octets = len(line)
+ # server can send any combination of CR & LF
+ # however, 'readline()' returns lines ending in LF
+ # so only possibilities are ...LF, ...CRLF, CR...LF
+ if line[-2:] == CRLF:
+ return line[:-2], octets
+ if line[:1] == CR:
+ return line[1:-1], octets
+ return line[:-1], octets
+
+
+ # Internal: get a response from the server.
+ # Raise 'error_proto' if the response doesn't start with '+'.
+
+ def _getresp(self):
+ resp, o = self._getline()
+ if self._debugging > 1: print('*resp*', repr(resp))
+ if not resp.startswith(b'+'):
+ raise error_proto(resp)
+ return resp
+
+
+ # Internal: get a response plus following text from the server.
+
+ def _getlongresp(self):
+ resp = self._getresp()
+ list = []; octets = 0
+ line, o = self._getline()
+ while line != b'.':
+ if line.startswith(b'..'):
+ o = o-1
+ line = line[1:]
+ octets = octets + o
+ list.append(line)
+ line, o = self._getline()
+ return resp, list, octets
+
+
+ # Internal: send a command and get the response
+
+ def _shortcmd(self, line):
+ self._putcmd(line)
+ return self._getresp()
+
+
+ # Internal: send a command and get the response plus following text
+
+ def _longcmd(self, line):
+ self._putcmd(line)
+ return self._getlongresp()
+
+
+ # These can be useful:
+
+ def getwelcome(self):
+ return self.welcome
+
+
+ def set_debuglevel(self, level):
+ self._debugging = level
+
+
+ # Here are all the POP commands:
+
+ def user(self, user):
+ """Send user name, return response
+
+ (should indicate password required).
+ """
+ return self._shortcmd('USER %s' % user)
+
+
+ def pass_(self, pswd):
+ """Send password, return response
+
+ (response includes message count, mailbox size).
+
+ NB: mailbox is locked by server from here to 'quit()'
+ """
+ return self._shortcmd('PASS %s' % pswd)
+
+
+ def stat(self):
+ """Get mailbox status.
+
+ Result is tuple of 2 ints (message count, mailbox size)
+ """
+ retval = self._shortcmd('STAT')
+ rets = retval.split()
+ if self._debugging: print('*stat*', repr(rets))
+ numMessages = int(rets[1])
+ sizeMessages = int(rets[2])
+ return (numMessages, sizeMessages)
+
+
+ def list(self, which=None):
+ """Request listing, return result.
+
+ Result without a message number argument is in form
+ ['response', ['mesg_num octets', ...], octets].
+
+ Result when a message number argument is given is a
+ single response: the "scan listing" for that message.
+ """
+ if which is not None:
+ return self._shortcmd('LIST %s' % which)
+ return self._longcmd('LIST')
+
+
+ def retr(self, which):
+ """Retrieve whole message number 'which'.
+
+ Result is in form ['response', ['line', ...], octets].
+ """
+ return self._longcmd('RETR %s' % which)
+
+
+ def dele(self, which):
+ """Delete message number 'which'.
+
+ Result is 'response'.
+ """
+ return self._shortcmd('DELE %s' % which)
+
+
+ def noop(self):
+ """Does nothing.
+
+ One supposes the response indicates the server is alive.
+ """
+ return self._shortcmd('NOOP')
+
+
+ def rset(self):
+ """Unmark all messages marked for deletion."""
+ return self._shortcmd('RSET')
+
+
+ def quit(self):
+ """Signoff: commit changes on server, unlock mailbox, close connection."""
+ resp = self._shortcmd('QUIT')
+ self.close()
+ return resp
+
+ def close(self):
+ """Close the connection without assuming anything about it."""
+ try:
+ file = self.file
+ self.file = None
+ if file is not None:
+ file.close()
+ finally:
+ sock = self.sock
+ self.sock = None
+ if sock is not None:
+ try:
+ sock.shutdown(socket.SHUT_RDWR)
+ except OSError as exc:
+ # The server might already have closed the connection.
+ # On Windows, this may result in WSAEINVAL (error 10022):
+ # An invalid operation was attempted.
+ if (exc.errno != errno.ENOTCONN
+ and getattr(exc, 'winerror', 0) != 10022):
+ raise
+ finally:
+ sock.close()
+
+ #__del__ = quit
+
+
+ # optional commands:
+
+ def rpop(self, user):
+ """Not sure what this does."""
+ return self._shortcmd('RPOP %s' % user)
+
+
+ timestamp = re.compile(br'\+OK.[^<]*(<.*>)')
+
+ def apop(self, user, password):
+ """Authorisation
+
+ - only possible if server has supplied a timestamp in initial greeting.
+
+ Args:
+ user - mailbox user;
+ password - mailbox password.
+
+ NB: mailbox is locked by server from here to 'quit()'
+ """
+ secret = bytes(password, self.encoding)
+ m = self.timestamp.match(self.welcome)
+ if not m:
+ raise error_proto('-ERR APOP not supported by server')
+ import hashlib
+ digest = m.group(1)+secret
+ digest = hashlib.md5(digest).hexdigest()
+ return self._shortcmd('APOP %s %s' % (user, digest))
+
+
+ def top(self, which, howmuch):
+ """Retrieve message header of message number 'which'
+ and first 'howmuch' lines of message body.
+
+ Result is in form ['response', ['line', ...], octets].
+ """
+ return self._longcmd('TOP %s %s' % (which, howmuch))
+
+
+ def uidl(self, which=None):
+ """Return message digest (unique id) list.
+
+ If 'which', result contains unique id for that message
+ in the form 'response mesgnum uid', otherwise result is
+ the list ['response', ['mesgnum uid', ...], octets]
+ """
+ if which is not None:
+ return self._shortcmd('UIDL %s' % which)
+ return self._longcmd('UIDL')
+
+
+ def utf8(self):
+ """Try to enter UTF-8 mode (see RFC 6856). Returns server response.
+ """
+ return self._shortcmd('UTF8')
+
+
+ def capa(self):
+ """Return server capabilities (RFC 2449) as a dictionary
+ >>> c=poplib.POP3('localhost')
+ >>> c.capa()
+ {'IMPLEMENTATION': ['Cyrus', 'POP3', 'server', 'v2.2.12'],
+ 'TOP': [], 'LOGIN-DELAY': ['0'], 'AUTH-RESP-CODE': [],
+ 'EXPIRE': ['NEVER'], 'USER': [], 'STLS': [], 'PIPELINING': [],
+ 'UIDL': [], 'RESP-CODES': []}
+ >>>
+
+ Really, according to RFC 2449, the cyrus folks should avoid
+ having the implementation split into multiple arguments...
+ """
+ def _parsecap(line):
+ lst = line.decode('ascii').split()
+ return lst[0], lst[1:]
+
+ caps = {}
+ try:
+ resp = self._longcmd('CAPA')
+ rawcaps = resp[1]
+ for capline in rawcaps:
+ capnm, capargs = _parsecap(capline)
+ caps[capnm] = capargs
+ except error_proto as _err:
+ raise error_proto('-ERR CAPA not supported by server')
+ return caps
+
+
+ def stls(self, context=None):
+ """Start a TLS session on the active connection as specified in RFC 2595.
+
+ context - a ssl.SSLContext
+ """
+ if not HAVE_SSL:
+ raise error_proto('-ERR TLS support missing')
+ if self._tls_established:
+ raise error_proto('-ERR TLS session already established')
+ caps = self.capa()
+ if not 'STLS' in caps:
+ raise error_proto('-ERR STLS not supported by server')
+ if context is None:
+ context = ssl._create_stdlib_context()
+ resp = self._shortcmd('STLS')
+ self.sock = context.wrap_socket(self.sock,
+ server_hostname=self.host)
+ self.file = self.sock.makefile('rb')
+ self._tls_established = True
+ return resp
+
+
+if HAVE_SSL:
+
+ class POP3_SSL(POP3):
+ """POP3 client class over SSL connection
+
+ Instantiate with: POP3_SSL(hostname, port=995, keyfile=None, certfile=None,
+ context=None)
+
+ hostname - the hostname of the pop3 over ssl server
+ port - port number
+ keyfile - PEM formatted file that contains your private key
+ certfile - PEM formatted certificate chain file
+ context - a ssl.SSLContext
+
+ See the methods of the parent class POP3 for more documentation.
+ """
+
+ def __init__(self, host, port=POP3_SSL_PORT, keyfile=None, certfile=None,
+ timeout=socket._GLOBAL_DEFAULT_TIMEOUT, context=None):
+ if context is not None and keyfile is not None:
+ raise ValueError("context and keyfile arguments are mutually "
+ "exclusive")
+ if context is not None and certfile is not None:
+ raise ValueError("context and certfile arguments are mutually "
+ "exclusive")
+ if keyfile is not None or certfile is not None:
+ import warnings
+ warnings.warn("keyfile and certfile are deprecated, use a "
+ "custom context instead", DeprecationWarning, 2)
+ self.keyfile = keyfile
+ self.certfile = certfile
+ if context is None:
+ context = ssl._create_stdlib_context(certfile=certfile,
+ keyfile=keyfile)
+ self.context = context
+ POP3.__init__(self, host, port, timeout)
+
+ def _create_socket(self, timeout):
+ sock = POP3._create_socket(self, timeout)
+ sock = self.context.wrap_socket(sock,
+ server_hostname=self.host)
+ return sock
+
+ def stls(self, keyfile=None, certfile=None, context=None):
+ """The method unconditionally raises an exception since the
+ STLS command doesn't make any sense on an already established
+ SSL/TLS session.
+ """
+ raise error_proto('-ERR TLS session already established')
+
+ __all__.append("POP3_SSL")
+
+if __name__ == "__main__":
+ import sys
+ a = POP3(sys.argv[1])
+ print(a.getwelcome())
+ a.user(sys.argv[2])
+ a.pass_(sys.argv[3])
+ a.list()
+ (numMsgs, totalSize) = a.stat()
+ for i in range(1, numMsgs + 1):
+ (header, msg, octets) = a.retr(i)
+ print("Message %d:" % i)
+ for line in msg:
+ print(' ' + line)
+ print('-----------------------')
+ a.quit()
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/posixpath.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/posixpath.py
new file mode 100644
index 0000000000000000000000000000000000000000..ecb4e5a8f7072c52effe4606b7406190a2dd7787
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/posixpath.py
@@ -0,0 +1,525 @@
+"""Common operations on Posix pathnames.
+
+Instead of importing this module directly, import os and refer to
+this module as os.path. The "os.path" name is an alias for this
+module on Posix systems; on other systems (e.g. Windows),
+os.path provides the same operations in a manner specific to that
+platform, and is an alias to another module (e.g. ntpath).
+
+Some of this can actually be useful on non-Posix systems too, e.g.
+for manipulation of the pathname component of URLs.
+"""
+
+# Strings representing various path-related bits and pieces.
+# These are primarily for export; internally, they are hardcoded.
+# Should be set before imports for resolving cyclic dependency.
+curdir = '.'
+pardir = '..'
+extsep = '.'
+sep = '/'
+pathsep = ':'
+defpath = '/bin:/usr/bin'
+altsep = None
+devnull = '/dev/null'
+
+import os
+import sys
+import stat
+import genericpath
+from genericpath import *
+
+__all__ = ["normcase","isabs","join","splitdrive","split","splitext",
+ "basename","dirname","commonprefix","getsize","getmtime",
+ "getatime","getctime","islink","exists","lexists","isdir","isfile",
+ "ismount", "expanduser","expandvars","normpath","abspath",
+ "samefile","sameopenfile","samestat",
+ "curdir","pardir","sep","pathsep","defpath","altsep","extsep",
+ "devnull","realpath","supports_unicode_filenames","relpath",
+ "commonpath"]
+
+
+def _get_sep(path):
+ if isinstance(path, bytes):
+ return b'/'
+ else:
+ return '/'
+
+# Normalize the case of a pathname. Trivial in Posix, string.lower on Mac.
+# On MS-DOS this may also turn slashes into backslashes; however, other
+# normalizations (such as optimizing '../' away) are not allowed
+# (another function should be defined to do that).
+
+def normcase(s):
+ """Normalize case of pathname. Has no effect under Posix"""
+ return os.fspath(s)
+
+
+# Return whether a path is absolute.
+# Trivial in Posix, harder on the Mac or MS-DOS.
+
+def isabs(s):
+ """Test whether a path is absolute"""
+ s = os.fspath(s)
+ sep = _get_sep(s)
+ return s.startswith(sep)
+
+
+# Join pathnames.
+# Ignore the previous parts if a part is absolute.
+# Insert a '/' unless the first part is empty or already ends in '/'.
+
+def join(a, *p):
+ """Join two or more pathname components, inserting '/' as needed.
+ If any component is an absolute path, all previous path components
+ will be discarded. An empty last part will result in a path that
+ ends with a separator."""
+ a = os.fspath(a)
+ sep = _get_sep(a)
+ path = a
+ try:
+ if not p:
+ path[:0] + sep #23780: Ensure compatible data type even if p is null.
+ for b in map(os.fspath, p):
+ if b.startswith(sep):
+ path = b
+ elif not path or path.endswith(sep):
+ path += b
+ else:
+ path += sep + b
+ except (TypeError, AttributeError, BytesWarning):
+ genericpath._check_arg_types('join', a, *p)
+ raise
+ return path
+
+
+# Split a path in head (everything up to the last '/') and tail (the
+# rest). If the path ends in '/', tail will be empty. If there is no
+# '/' in the path, head will be empty.
+# Trailing '/'es are stripped from head unless it is the root.
+
+def split(p):
+ """Split a pathname. Returns tuple "(head, tail)" where "tail" is
+ everything after the final slash. Either part may be empty."""
+ p = os.fspath(p)
+ sep = _get_sep(p)
+ i = p.rfind(sep) + 1
+ head, tail = p[:i], p[i:]
+ if head and head != sep*len(head):
+ head = head.rstrip(sep)
+ return head, tail
+
+
+# Split a path in root and extension.
+# The extension is everything starting at the last dot in the last
+# pathname component; the root is everything before that.
+# It is always true that root + ext == p.
+
+def splitext(p):
+ p = os.fspath(p)
+ if isinstance(p, bytes):
+ sep = b'/'
+ extsep = b'.'
+ else:
+ sep = '/'
+ extsep = '.'
+ return genericpath._splitext(p, sep, None, extsep)
+splitext.__doc__ = genericpath._splitext.__doc__
+
+# Split a pathname into a drive specification and the rest of the
+# path. Useful on DOS/Windows/NT; on Unix, the drive is always empty.
+
+def splitdrive(p):
+ """Split a pathname into drive and path. On Posix, drive is always
+ empty."""
+ p = os.fspath(p)
+ return p[:0], p
+
+
+# Return the tail (basename) part of a path, same as split(path)[1].
+
+def basename(p):
+ """Returns the final component of a pathname"""
+ p = os.fspath(p)
+ sep = _get_sep(p)
+ i = p.rfind(sep) + 1
+ return p[i:]
+
+
+# Return the head (dirname) part of a path, same as split(path)[0].
+
+def dirname(p):
+ """Returns the directory component of a pathname"""
+ p = os.fspath(p)
+ sep = _get_sep(p)
+ i = p.rfind(sep) + 1
+ head = p[:i]
+ if head and head != sep*len(head):
+ head = head.rstrip(sep)
+ return head
+
+
+# Is a path a symbolic link?
+# This will always return false on systems where os.lstat doesn't exist.
+
+def islink(path):
+ """Test whether a path is a symbolic link"""
+ try:
+ st = os.lstat(path)
+ except (OSError, ValueError, AttributeError):
+ return False
+ return stat.S_ISLNK(st.st_mode)
+
+# Being true for dangling symbolic links is also useful.
+
+def lexists(path):
+ """Test whether a path exists. Returns True for broken symbolic links"""
+ try:
+ os.lstat(path)
+ except (OSError, ValueError):
+ return False
+ return True
+
+
+# Is a path a mount point?
+# (Does this work for all UNIXes? Is it even guaranteed to work by Posix?)
+
+def ismount(path):
+ """Test whether a path is a mount point"""
+ try:
+ s1 = os.lstat(path)
+ except (OSError, ValueError):
+ # It doesn't exist -- so not a mount point. :-)
+ return False
+ else:
+ # A symlink can never be a mount point
+ if stat.S_ISLNK(s1.st_mode):
+ return False
+
+ if isinstance(path, bytes):
+ parent = join(path, b'..')
+ else:
+ parent = join(path, '..')
+ parent = realpath(parent)
+ try:
+ s2 = os.lstat(parent)
+ except (OSError, ValueError):
+ return False
+
+ dev1 = s1.st_dev
+ dev2 = s2.st_dev
+ if dev1 != dev2:
+ return True # path/.. on a different device as path
+ ino1 = s1.st_ino
+ ino2 = s2.st_ino
+ if ino1 == ino2:
+ return True # path/.. is the same i-node as path
+ return False
+
+
+# Expand paths beginning with '~' or '~user'.
+# '~' means $HOME; '~user' means that user's home directory.
+# If the path doesn't begin with '~', or if the user or $HOME is unknown,
+# the path is returned unchanged (leaving error reporting to whatever
+# function is called with the expanded path as argument).
+# See also module 'glob' for expansion of *, ? and [...] in pathnames.
+# (A function should also be defined to do full *sh-style environment
+# variable expansion.)
+
+def expanduser(path):
+ """Expand ~ and ~user constructions. If user or $HOME is unknown,
+ do nothing."""
+ path = os.fspath(path)
+ if isinstance(path, bytes):
+ tilde = b'~'
+ else:
+ tilde = '~'
+ if not path.startswith(tilde):
+ return path
+ sep = _get_sep(path)
+ i = path.find(sep, 1)
+ if i < 0:
+ i = len(path)
+ if i == 1:
+ if 'HOME' not in os.environ:
+ import pwd
+ try:
+ userhome = pwd.getpwuid(os.getuid()).pw_dir
+ except KeyError:
+ # bpo-10496: if the current user identifier doesn't exist in the
+ # password database, return the path unchanged
+ return path
+ else:
+ userhome = os.environ['HOME']
+ else:
+ import pwd
+ name = path[1:i]
+ if isinstance(name, bytes):
+ name = str(name, 'ASCII')
+ try:
+ pwent = pwd.getpwnam(name)
+ except KeyError:
+ # bpo-10496: if the user name from the path doesn't exist in the
+ # password database, return the path unchanged
+ return path
+ userhome = pwent.pw_dir
+ if isinstance(path, bytes):
+ userhome = os.fsencode(userhome)
+ root = b'/'
+ else:
+ root = '/'
+ userhome = userhome.rstrip(root)
+ return (userhome + path[i:]) or root
+
+
+# Expand paths containing shell variable substitutions.
+# This expands the forms $variable and ${variable} only.
+# Non-existent variables are left unchanged.
+
+_varprog = None
+_varprogb = None
+
+def expandvars(path):
+ """Expand shell variables of form $var and ${var}. Unknown variables
+ are left unchanged."""
+ path = os.fspath(path)
+ global _varprog, _varprogb
+ if isinstance(path, bytes):
+ if b'$' not in path:
+ return path
+ if not _varprogb:
+ import re
+ _varprogb = re.compile(br'\$(\w+|\{[^}]*\})', re.ASCII)
+ search = _varprogb.search
+ start = b'{'
+ end = b'}'
+ environ = getattr(os, 'environb', None)
+ else:
+ if '$' not in path:
+ return path
+ if not _varprog:
+ import re
+ _varprog = re.compile(r'\$(\w+|\{[^}]*\})', re.ASCII)
+ search = _varprog.search
+ start = '{'
+ end = '}'
+ environ = os.environ
+ i = 0
+ while True:
+ m = search(path, i)
+ if not m:
+ break
+ i, j = m.span(0)
+ name = m.group(1)
+ if name.startswith(start) and name.endswith(end):
+ name = name[1:-1]
+ try:
+ if environ is None:
+ value = os.fsencode(os.environ[os.fsdecode(name)])
+ else:
+ value = environ[name]
+ except KeyError:
+ i = j
+ else:
+ tail = path[j:]
+ path = path[:i] + value
+ i = len(path)
+ path += tail
+ return path
+
+
+# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
+# It should be understood that this may change the meaning of the path
+# if it contains symbolic links!
+
+def normpath(path):
+ """Normalize path, eliminating double slashes, etc."""
+ path = os.fspath(path)
+ if isinstance(path, bytes):
+ sep = b'/'
+ empty = b''
+ dot = b'.'
+ dotdot = b'..'
+ else:
+ sep = '/'
+ empty = ''
+ dot = '.'
+ dotdot = '..'
+ if path == empty:
+ return dot
+ initial_slashes = path.startswith(sep)
+ # POSIX allows one or two initial slashes, but treats three or more
+ # as single slash.
+ if (initial_slashes and
+ path.startswith(sep*2) and not path.startswith(sep*3)):
+ initial_slashes = 2
+ comps = path.split(sep)
+ new_comps = []
+ for comp in comps:
+ if comp in (empty, dot):
+ continue
+ if (comp != dotdot or (not initial_slashes and not new_comps) or
+ (new_comps and new_comps[-1] == dotdot)):
+ new_comps.append(comp)
+ elif new_comps:
+ new_comps.pop()
+ comps = new_comps
+ path = sep.join(comps)
+ if initial_slashes:
+ path = sep*initial_slashes + path
+ return path or dot
+
+
+def abspath(path):
+ """Return an absolute path."""
+ path = os.fspath(path)
+ if not isabs(path):
+ if isinstance(path, bytes):
+ cwd = os.getcwdb()
+ else:
+ cwd = os.getcwd()
+ path = join(cwd, path)
+ return normpath(path)
+
+
+# Return a canonical path (i.e. the absolute location of a file on the
+# filesystem).
+
+def realpath(filename):
+ """Return the canonical path of the specified filename, eliminating any
+symbolic links encountered in the path."""
+ filename = os.fspath(filename)
+ path, ok = _joinrealpath(filename[:0], filename, {})
+ return abspath(path)
+
+# Join two paths, normalizing and eliminating any symbolic links
+# encountered in the second path.
+def _joinrealpath(path, rest, seen):
+ if isinstance(path, bytes):
+ sep = b'/'
+ curdir = b'.'
+ pardir = b'..'
+ else:
+ sep = '/'
+ curdir = '.'
+ pardir = '..'
+
+ if isabs(rest):
+ rest = rest[1:]
+ path = sep
+
+ while rest:
+ name, _, rest = rest.partition(sep)
+ if not name or name == curdir:
+ # current dir
+ continue
+ if name == pardir:
+ # parent dir
+ if path:
+ path, name = split(path)
+ if name == pardir:
+ path = join(path, pardir, pardir)
+ else:
+ path = pardir
+ continue
+ newpath = join(path, name)
+ if not islink(newpath):
+ path = newpath
+ continue
+ # Resolve the symbolic link
+ if newpath in seen:
+ # Already seen this path
+ path = seen[newpath]
+ if path is not None:
+ # use cached value
+ continue
+ # The symlink is not resolved, so we must have a symlink loop.
+ # Return already resolved part + rest of the path unchanged.
+ return join(newpath, rest), False
+ seen[newpath] = None # not resolved symlink
+ path, ok = _joinrealpath(path, os.readlink(newpath), seen)
+ if not ok:
+ return join(path, rest), False
+ seen[newpath] = path # resolved symlink
+
+ return path, True
+
+
+supports_unicode_filenames = (sys.platform == 'darwin')
+
+def relpath(path, start=None):
+ """Return a relative version of a path"""
+
+ if not path:
+ raise ValueError("no path specified")
+
+ path = os.fspath(path)
+ if isinstance(path, bytes):
+ curdir = b'.'
+ sep = b'/'
+ pardir = b'..'
+ else:
+ curdir = '.'
+ sep = '/'
+ pardir = '..'
+
+ if start is None:
+ start = curdir
+ else:
+ start = os.fspath(start)
+
+ try:
+ start_list = [x for x in abspath(start).split(sep) if x]
+ path_list = [x for x in abspath(path).split(sep) if x]
+ # Work out how much of the filepath is shared by start and path.
+ i = len(commonprefix([start_list, path_list]))
+
+ rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
+ if not rel_list:
+ return curdir
+ return join(*rel_list)
+ except (TypeError, AttributeError, BytesWarning, DeprecationWarning):
+ genericpath._check_arg_types('relpath', path, start)
+ raise
+
+
+# Return the longest common sub-path of the sequence of paths given as input.
+# The paths are not normalized before comparing them (this is the
+# responsibility of the caller). Any trailing separator is stripped from the
+# returned path.
+
+def commonpath(paths):
+ """Given a sequence of path names, returns the longest common sub-path."""
+
+ if not paths:
+ raise ValueError('commonpath() arg is an empty sequence')
+
+ paths = tuple(map(os.fspath, paths))
+ if isinstance(paths[0], bytes):
+ sep = b'/'
+ curdir = b'.'
+ else:
+ sep = '/'
+ curdir = '.'
+
+ try:
+ split_paths = [path.split(sep) for path in paths]
+
+ try:
+ isabs, = set(p[:1] == sep for p in paths)
+ except ValueError:
+ raise ValueError("Can't mix absolute and relative paths") from None
+
+ split_paths = [[c for c in s if c and c != curdir] for s in split_paths]
+ s1 = min(split_paths)
+ s2 = max(split_paths)
+ common = s1
+ for i, c in enumerate(s1):
+ if c != s2[i]:
+ common = s1[:i]
+ break
+
+ prefix = sep if isabs else sep[:0]
+ return prefix + sep.join(common)
+ except (TypeError, AttributeError):
+ genericpath._check_arg_types('commonpath', *paths)
+ raise
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/pyclbr.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/pyclbr.py
new file mode 100644
index 0000000000000000000000000000000000000000..99a17343fb61fdaa0f13422fa0325b95aeb88a4b
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/pyclbr.py
@@ -0,0 +1,404 @@
+"""Parse a Python module and describe its classes and functions.
+
+Parse enough of a Python file to recognize imports and class and
+function definitions, and to find out the superclasses of a class.
+
+The interface consists of a single function:
+ readmodule_ex(module, path=None)
+where module is the name of a Python module, and path is an optional
+list of directories where the module is to be searched. If present,
+path is prepended to the system search path sys.path. The return value
+is a dictionary. The keys of the dictionary are the names of the
+classes and functions defined in the module (including classes that are
+defined via the from XXX import YYY construct). The values are
+instances of classes Class and Function. One special key/value pair is
+present for packages: the key '__path__' has a list as its value which
+contains the package search path.
+
+Classes and Functions have a common superclass: _Object. Every instance
+has the following attributes:
+ module -- name of the module;
+ name -- name of the object;
+ file -- file in which the object is defined;
+ lineno -- line in the file where the object's definition starts;
+ parent -- parent of this object, if any;
+ children -- nested objects contained in this object.
+The 'children' attribute is a dictionary mapping names to objects.
+
+Instances of Function describe functions with the attributes from _Object.
+
+Instances of Class describe classes with the attributes from _Object,
+plus the following:
+ super -- list of super classes (Class instances if possible);
+ methods -- mapping of method names to beginning line numbers.
+If the name of a super class is not recognized, the corresponding
+entry in the list of super classes is not a class instance but a
+string giving the name of the super class. Since import statements
+are recognized and imported modules are scanned as well, this
+shouldn't happen often.
+"""
+
+import io
+import sys
+import importlib.util
+import tokenize
+from token import NAME, DEDENT, OP
+
+__all__ = ["readmodule", "readmodule_ex", "Class", "Function"]
+
+_modules = {} # Initialize cache of modules we've seen.
+
+
+class _Object:
+ "Information about Python class or function."
+ def __init__(self, module, name, file, lineno, parent):
+ self.module = module
+ self.name = name
+ self.file = file
+ self.lineno = lineno
+ self.parent = parent
+ self.children = {}
+
+ def _addchild(self, name, obj):
+ self.children[name] = obj
+
+
+class Function(_Object):
+ "Information about a Python function, including methods."
+ def __init__(self, module, name, file, lineno, parent=None):
+ _Object.__init__(self, module, name, file, lineno, parent)
+
+
+class Class(_Object):
+ "Information about a Python class."
+ def __init__(self, module, name, super, file, lineno, parent=None):
+ _Object.__init__(self, module, name, file, lineno, parent)
+ self.super = [] if super is None else super
+ self.methods = {}
+
+ def _addmethod(self, name, lineno):
+ self.methods[name] = lineno
+
+
+def _nest_function(ob, func_name, lineno):
+ "Return a Function after nesting within ob."
+ newfunc = Function(ob.module, func_name, ob.file, lineno, ob)
+ ob._addchild(func_name, newfunc)
+ if isinstance(ob, Class):
+ ob._addmethod(func_name, lineno)
+ return newfunc
+
+def _nest_class(ob, class_name, lineno, super=None):
+ "Return a Class after nesting within ob."
+ newclass = Class(ob.module, class_name, super, ob.file, lineno, ob)
+ ob._addchild(class_name, newclass)
+ return newclass
+
+def readmodule(module, path=None):
+ """Return Class objects for the top-level classes in module.
+
+ This is the original interface, before Functions were added.
+ """
+
+ res = {}
+ for key, value in _readmodule(module, path or []).items():
+ if isinstance(value, Class):
+ res[key] = value
+ return res
+
+def readmodule_ex(module, path=None):
+ """Return a dictionary with all functions and classes in module.
+
+ Search for module in PATH + sys.path.
+ If possible, include imported superclasses.
+ Do this by reading source, without importing (and executing) it.
+ """
+ return _readmodule(module, path or [])
+
+def _readmodule(module, path, inpackage=None):
+ """Do the hard work for readmodule[_ex].
+
+ If inpackage is given, it must be the dotted name of the package in
+ which we are searching for a submodule, and then PATH must be the
+ package search path; otherwise, we are searching for a top-level
+ module, and path is combined with sys.path.
+ """
+ # Compute the full module name (prepending inpackage if set).
+ if inpackage is not None:
+ fullmodule = "%s.%s" % (inpackage, module)
+ else:
+ fullmodule = module
+
+ # Check in the cache.
+ if fullmodule in _modules:
+ return _modules[fullmodule]
+
+ # Initialize the dict for this module's contents.
+ tree = {}
+
+ # Check if it is a built-in module; we don't do much for these.
+ if module in sys.builtin_module_names and inpackage is None:
+ _modules[module] = tree
+ return tree
+
+ # Check for a dotted module name.
+ i = module.rfind('.')
+ if i >= 0:
+ package = module[:i]
+ submodule = module[i+1:]
+ parent = _readmodule(package, path, inpackage)
+ if inpackage is not None:
+ package = "%s.%s" % (inpackage, package)
+ if not '__path__' in parent:
+ raise ImportError('No package named {}'.format(package))
+ return _readmodule(submodule, parent['__path__'], package)
+
+ # Search the path for the module.
+ f = None
+ if inpackage is not None:
+ search_path = path
+ else:
+ search_path = path + sys.path
+ spec = importlib.util._find_spec_from_path(fullmodule, search_path)
+ if spec is None:
+ raise ModuleNotFoundError(f"no module named {fullmodule!r}", name=fullmodule)
+ _modules[fullmodule] = tree
+ # Is module a package?
+ if spec.submodule_search_locations is not None:
+ tree['__path__'] = spec.submodule_search_locations
+ try:
+ source = spec.loader.get_source(fullmodule)
+ except (AttributeError, ImportError):
+ # If module is not Python source, we cannot do anything.
+ return tree
+ else:
+ if source is None:
+ return tree
+
+ fname = spec.loader.get_filename(fullmodule)
+ return _create_tree(fullmodule, path, fname, source, tree, inpackage)
+
+
+def _create_tree(fullmodule, path, fname, source, tree, inpackage):
+ """Return the tree for a particular module.
+
+ fullmodule (full module name), inpackage+module, becomes o.module.
+ path is passed to recursive calls of _readmodule.
+ fname becomes o.file.
+ source is tokenized. Imports cause recursive calls to _readmodule.
+ tree is {} or {'__path__': }.
+ inpackage, None or string, is passed to recursive calls of _readmodule.
+
+ The effect of recursive calls is mutation of global _modules.
+ """
+ f = io.StringIO(source)
+
+ stack = [] # Initialize stack of (class, indent) pairs.
+
+ g = tokenize.generate_tokens(f.readline)
+ try:
+ for tokentype, token, start, _end, _line in g:
+ if tokentype == DEDENT:
+ lineno, thisindent = start
+ # Close previous nested classes and defs.
+ while stack and stack[-1][1] >= thisindent:
+ del stack[-1]
+ elif token == 'def':
+ lineno, thisindent = start
+ # Close previous nested classes and defs.
+ while stack and stack[-1][1] >= thisindent:
+ del stack[-1]
+ tokentype, func_name, start = next(g)[0:3]
+ if tokentype != NAME:
+ continue # Skip def with syntax error.
+ cur_func = None
+ if stack:
+ cur_obj = stack[-1][0]
+ cur_func = _nest_function(cur_obj, func_name, lineno)
+ else:
+ # It is just a function.
+ cur_func = Function(fullmodule, func_name, fname, lineno)
+ tree[func_name] = cur_func
+ stack.append((cur_func, thisindent))
+ elif token == 'class':
+ lineno, thisindent = start
+ # Close previous nested classes and defs.
+ while stack and stack[-1][1] >= thisindent:
+ del stack[-1]
+ tokentype, class_name, start = next(g)[0:3]
+ if tokentype != NAME:
+ continue # Skip class with syntax error.
+ # Parse what follows the class name.
+ tokentype, token, start = next(g)[0:3]
+ inherit = None
+ if token == '(':
+ names = [] # Initialize list of superclasses.
+ level = 1
+ super = [] # Tokens making up current superclass.
+ while True:
+ tokentype, token, start = next(g)[0:3]
+ if token in (')', ',') and level == 1:
+ n = "".join(super)
+ if n in tree:
+ # We know this super class.
+ n = tree[n]
+ else:
+ c = n.split('.')
+ if len(c) > 1:
+ # Super class form is module.class:
+ # look in module for class.
+ m = c[-2]
+ c = c[-1]
+ if m in _modules:
+ d = _modules[m]
+ if c in d:
+ n = d[c]
+ names.append(n)
+ super = []
+ if token == '(':
+ level += 1
+ elif token == ')':
+ level -= 1
+ if level == 0:
+ break
+ elif token == ',' and level == 1:
+ pass
+ # Only use NAME and OP (== dot) tokens for type name.
+ elif tokentype in (NAME, OP) and level == 1:
+ super.append(token)
+ # Expressions in the base list are not supported.
+ inherit = names
+ if stack:
+ cur_obj = stack[-1][0]
+ cur_class = _nest_class(
+ cur_obj, class_name, lineno, inherit)
+ else:
+ cur_class = Class(fullmodule, class_name, inherit,
+ fname, lineno)
+ tree[class_name] = cur_class
+ stack.append((cur_class, thisindent))
+ elif token == 'import' and start[1] == 0:
+ modules = _getnamelist(g)
+ for mod, _mod2 in modules:
+ try:
+ # Recursively read the imported module.
+ if inpackage is None:
+ _readmodule(mod, path)
+ else:
+ try:
+ _readmodule(mod, path, inpackage)
+ except ImportError:
+ _readmodule(mod, [])
+ except:
+ # If we can't find or parse the imported module,
+ # too bad -- don't die here.
+ pass
+ elif token == 'from' and start[1] == 0:
+ mod, token = _getname(g)
+ if not mod or token != "import":
+ continue
+ names = _getnamelist(g)
+ try:
+ # Recursively read the imported module.
+ d = _readmodule(mod, path, inpackage)
+ except:
+ # If we can't find or parse the imported module,
+ # too bad -- don't die here.
+ continue
+ # Add any classes that were defined in the imported module
+ # to our name space if they were mentioned in the list.
+ for n, n2 in names:
+ if n in d:
+ tree[n2 or n] = d[n]
+ elif n == '*':
+ # Don't add names that start with _.
+ for n in d:
+ if n[0] != '_':
+ tree[n] = d[n]
+ except StopIteration:
+ pass
+
+ f.close()
+ return tree
+
+
+def _getnamelist(g):
+ """Return list of (dotted-name, as-name or None) tuples for token source g.
+
+ An as-name is the name that follows 'as' in an as clause.
+ """
+ names = []
+ while True:
+ name, token = _getname(g)
+ if not name:
+ break
+ if token == 'as':
+ name2, token = _getname(g)
+ else:
+ name2 = None
+ names.append((name, name2))
+ while token != "," and "\n" not in token:
+ token = next(g)[1]
+ if token != ",":
+ break
+ return names
+
+
+def _getname(g):
+ "Return (dotted-name or None, next-token) tuple for token source g."
+ parts = []
+ tokentype, token = next(g)[0:2]
+ if tokentype != NAME and token != '*':
+ return (None, token)
+ parts.append(token)
+ while True:
+ tokentype, token = next(g)[0:2]
+ if token != '.':
+ break
+ tokentype, token = next(g)[0:2]
+ if tokentype != NAME:
+ break
+ parts.append(token)
+ return (".".join(parts), token)
+
+
+def _main():
+ "Print module output (default this file) for quick visual check."
+ import os
+ try:
+ mod = sys.argv[1]
+ except:
+ mod = __file__
+ if os.path.exists(mod):
+ path = [os.path.dirname(mod)]
+ mod = os.path.basename(mod)
+ if mod.lower().endswith(".py"):
+ mod = mod[:-3]
+ else:
+ path = []
+ tree = readmodule_ex(mod, path)
+ lineno_key = lambda a: getattr(a, 'lineno', 0)
+ objs = sorted(tree.values(), key=lineno_key, reverse=True)
+ indent_level = 2
+ while objs:
+ obj = objs.pop()
+ if isinstance(obj, list):
+ # Value is a __path__ key.
+ continue
+ if not hasattr(obj, 'indent'):
+ obj.indent = 0
+
+ if isinstance(obj, _Object):
+ new_objs = sorted(obj.children.values(),
+ key=lineno_key, reverse=True)
+ for ob in new_objs:
+ ob.indent = obj.indent + indent_level
+ objs.extend(new_objs)
+ if isinstance(obj, Class):
+ print("{}class {} {} {}"
+ .format(' ' * obj.indent, obj.name, obj.super, obj.lineno))
+ elif isinstance(obj, Function):
+ print("{}def {} {}".format(' ' * obj.indent, obj.name, obj.lineno))
+
+if __name__ == "__main__":
+ _main()
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/rlcompleter.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/rlcompleter.py
new file mode 100644
index 0000000000000000000000000000000000000000..bca4a7bc5218a90d7ad145ae1d57e9eb489daeda
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/rlcompleter.py
@@ -0,0 +1,205 @@
+"""Word completion for GNU readline.
+
+The completer completes keywords, built-ins and globals in a selectable
+namespace (which defaults to __main__); when completing NAME.NAME..., it
+evaluates (!) the expression up to the last dot and completes its attributes.
+
+It's very cool to do "import sys" type "sys.", hit the completion key (twice),
+and see the list of names defined by the sys module!
+
+Tip: to use the tab key as the completion key, call
+
+ readline.parse_and_bind("tab: complete")
+
+Notes:
+
+- Exceptions raised by the completer function are *ignored* (and generally cause
+ the completion to fail). This is a feature -- since readline sets the tty
+ device in raw (or cbreak) mode, printing a traceback wouldn't work well
+ without some complicated hoopla to save, reset and restore the tty state.
+
+- The evaluation of the NAME.NAME... form may cause arbitrary application
+ defined code to be executed if an object with a __getattr__ hook is found.
+ Since it is the responsibility of the application (or the user) to enable this
+ feature, I consider this an acceptable risk. More complicated expressions
+ (e.g. function calls or indexing operations) are *not* evaluated.
+
+- When the original stdin is not a tty device, GNU readline is never
+ used, and this module (and the readline module) are silently inactive.
+
+"""
+
+import atexit
+import builtins
+import __main__
+
+__all__ = ["Completer"]
+
+class Completer:
+ def __init__(self, namespace = None):
+ """Create a new completer for the command line.
+
+ Completer([namespace]) -> completer instance.
+
+ If unspecified, the default namespace where completions are performed
+ is __main__ (technically, __main__.__dict__). Namespaces should be
+ given as dictionaries.
+
+ Completer instances should be used as the completion mechanism of
+ readline via the set_completer() call:
+
+ readline.set_completer(Completer(my_namespace).complete)
+ """
+
+ if namespace and not isinstance(namespace, dict):
+ raise TypeError('namespace must be a dictionary')
+
+ # Don't bind to namespace quite yet, but flag whether the user wants a
+ # specific namespace or to use __main__.__dict__. This will allow us
+ # to bind to __main__.__dict__ at completion time, not now.
+ if namespace is None:
+ self.use_main_ns = 1
+ else:
+ self.use_main_ns = 0
+ self.namespace = namespace
+
+ def complete(self, text, state):
+ """Return the next possible completion for 'text'.
+
+ This is called successively with state == 0, 1, 2, ... until it
+ returns None. The completion should begin with 'text'.
+
+ """
+ if self.use_main_ns:
+ self.namespace = __main__.__dict__
+
+ if not text.strip():
+ if state == 0:
+ if _readline_available:
+ readline.insert_text('\t')
+ readline.redisplay()
+ return ''
+ else:
+ return '\t'
+ else:
+ return None
+
+ if state == 0:
+ if "." in text:
+ self.matches = self.attr_matches(text)
+ else:
+ self.matches = self.global_matches(text)
+ try:
+ return self.matches[state]
+ except IndexError:
+ return None
+
+ def _callable_postfix(self, val, word):
+ if callable(val):
+ word = word + "("
+ return word
+
+ def global_matches(self, text):
+ """Compute matches when text is a simple name.
+
+ Return a list of all keywords, built-in functions and names currently
+ defined in self.namespace that match.
+
+ """
+ import keyword
+ matches = []
+ seen = {"__builtins__"}
+ n = len(text)
+ for word in keyword.kwlist:
+ if word[:n] == text:
+ seen.add(word)
+ if word in {'finally', 'try'}:
+ word = word + ':'
+ elif word not in {'False', 'None', 'True',
+ 'break', 'continue', 'pass',
+ 'else'}:
+ word = word + ' '
+ matches.append(word)
+ for nspace in [self.namespace, builtins.__dict__]:
+ for word, val in nspace.items():
+ if word[:n] == text and word not in seen:
+ seen.add(word)
+ matches.append(self._callable_postfix(val, word))
+ return matches
+
+ def attr_matches(self, text):
+ """Compute matches when text contains a dot.
+
+ Assuming the text is of the form NAME.NAME....[NAME], and is
+ evaluable in self.namespace, it will be evaluated and its attributes
+ (as revealed by dir()) are used as possible completions. (For class
+ instances, class members are also considered.)
+
+ WARNING: this can still invoke arbitrary C code, if an object
+ with a __getattr__ hook is evaluated.
+
+ """
+ import re
+ m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text)
+ if not m:
+ return []
+ expr, attr = m.group(1, 3)
+ try:
+ thisobject = eval(expr, self.namespace)
+ except Exception:
+ return []
+
+ # get the content of the object, except __builtins__
+ words = set(dir(thisobject))
+ words.discard("__builtins__")
+
+ if hasattr(thisobject, '__class__'):
+ words.add('__class__')
+ words.update(get_class_members(thisobject.__class__))
+ matches = []
+ n = len(attr)
+ if attr == '':
+ noprefix = '_'
+ elif attr == '_':
+ noprefix = '__'
+ else:
+ noprefix = None
+ while True:
+ for word in words:
+ if (word[:n] == attr and
+ not (noprefix and word[:n+1] == noprefix)):
+ match = "%s.%s" % (expr, word)
+ try:
+ val = getattr(thisobject, word)
+ except Exception:
+ pass # Include even if attribute not set
+ else:
+ match = self._callable_postfix(val, match)
+ matches.append(match)
+ if matches or not noprefix:
+ break
+ if noprefix == '_':
+ noprefix = '__'
+ else:
+ noprefix = None
+ matches.sort()
+ return matches
+
+def get_class_members(klass):
+ ret = dir(klass)
+ if hasattr(klass,'__bases__'):
+ for base in klass.__bases__:
+ ret = ret + get_class_members(base)
+ return ret
+
+try:
+ import readline
+except ImportError:
+ _readline_available = False
+else:
+ readline.set_completer(Completer().complete)
+ # Release references early at shutdown (the readline module's
+ # contents are quasi-immortal, and the completer function holds a
+ # reference to globals).
+ atexit.register(lambda: readline.set_completer(None))
+ _readline_available = True
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/secrets.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/secrets.py
new file mode 100644
index 0000000000000000000000000000000000000000..130434229e96a96dfacf1fc8b90dc98ef80d9bec
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/secrets.py
@@ -0,0 +1,73 @@
+"""Generate cryptographically strong pseudo-random numbers suitable for
+managing secrets such as account authentication, tokens, and similar.
+
+See PEP 506 for more information.
+https://www.python.org/dev/peps/pep-0506/
+
+"""
+
+__all__ = ['choice', 'randbelow', 'randbits', 'SystemRandom',
+ 'token_bytes', 'token_hex', 'token_urlsafe',
+ 'compare_digest',
+ ]
+
+
+import base64
+import binascii
+import os
+
+from hmac import compare_digest
+from random import SystemRandom
+
+_sysrand = SystemRandom()
+
+randbits = _sysrand.getrandbits
+choice = _sysrand.choice
+
+def randbelow(exclusive_upper_bound):
+ """Return a random int in the range [0, n)."""
+ if exclusive_upper_bound <= 0:
+ raise ValueError("Upper bound must be positive.")
+ return _sysrand._randbelow(exclusive_upper_bound)
+
+DEFAULT_ENTROPY = 32 # number of bytes to return by default
+
+def token_bytes(nbytes=None):
+ """Return a random byte string containing *nbytes* bytes.
+
+ If *nbytes* is ``None`` or not supplied, a reasonable
+ default is used.
+
+ >>> token_bytes(16) #doctest:+SKIP
+ b'\\xebr\\x17D*t\\xae\\xd4\\xe3S\\xb6\\xe2\\xebP1\\x8b'
+
+ """
+ if nbytes is None:
+ nbytes = DEFAULT_ENTROPY
+ return os.urandom(nbytes)
+
+def token_hex(nbytes=None):
+ """Return a random text string, in hexadecimal.
+
+ The string has *nbytes* random bytes, each byte converted to two
+ hex digits. If *nbytes* is ``None`` or not supplied, a reasonable
+ default is used.
+
+ >>> token_hex(16) #doctest:+SKIP
+ 'f9bf78b9a18ce6d46a0cd2b0b86df9da'
+
+ """
+ return binascii.hexlify(token_bytes(nbytes)).decode('ascii')
+
+def token_urlsafe(nbytes=None):
+ """Return a random URL-safe text string, in Base64 encoding.
+
+ The string has *nbytes* random bytes. If *nbytes* is ``None``
+ or not supplied, a reasonable default is used.
+
+ >>> token_urlsafe(16) #doctest:+SKIP
+ 'Drmhze6EPcv0fN_81Bj-nA'
+
+ """
+ tok = token_bytes(nbytes)
+ return base64.urlsafe_b64encode(tok).rstrip(b'=').decode('ascii')
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/shelve.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/shelve.py
new file mode 100644
index 0000000000000000000000000000000000000000..5d443a0fa8d4f14c56b1ca2497a621f0d02683d7
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/shelve.py
@@ -0,0 +1,243 @@
+"""Manage shelves of pickled objects.
+
+A "shelf" is a persistent, dictionary-like object. The difference
+with dbm databases is that the values (not the keys!) in a shelf can
+be essentially arbitrary Python objects -- anything that the "pickle"
+module can handle. This includes most class instances, recursive data
+types, and objects containing lots of shared sub-objects. The keys
+are ordinary strings.
+
+To summarize the interface (key is a string, data is an arbitrary
+object):
+
+ import shelve
+ d = shelve.open(filename) # open, with (g)dbm filename -- no suffix
+
+ d[key] = data # store data at key (overwrites old data if
+ # using an existing key)
+ data = d[key] # retrieve a COPY of the data at key (raise
+ # KeyError if no such key) -- NOTE that this
+ # access returns a *copy* of the entry!
+ del d[key] # delete data stored at key (raises KeyError
+ # if no such key)
+ flag = key in d # true if the key exists
+ list = d.keys() # a list of all existing keys (slow!)
+
+ d.close() # close it
+
+Dependent on the implementation, closing a persistent dictionary may
+or may not be necessary to flush changes to disk.
+
+Normally, d[key] returns a COPY of the entry. This needs care when
+mutable entries are mutated: for example, if d[key] is a list,
+ d[key].append(anitem)
+does NOT modify the entry d[key] itself, as stored in the persistent
+mapping -- it only modifies the copy, which is then immediately
+discarded, so that the append has NO effect whatsoever. To append an
+item to d[key] in a way that will affect the persistent mapping, use:
+ data = d[key]
+ data.append(anitem)
+ d[key] = data
+
+To avoid the problem with mutable entries, you may pass the keyword
+argument writeback=True in the call to shelve.open. When you use:
+ d = shelve.open(filename, writeback=True)
+then d keeps a cache of all entries you access, and writes them all back
+to the persistent mapping when you call d.close(). This ensures that
+such usage as d[key].append(anitem) works as intended.
+
+However, using keyword argument writeback=True may consume vast amount
+of memory for the cache, and it may make d.close() very slow, if you
+access many of d's entries after opening it in this way: d has no way to
+check which of the entries you access are mutable and/or which ones you
+actually mutate, so it must cache, and write back at close, all of the
+entries that you access. You can call d.sync() to write back all the
+entries in the cache, and empty the cache (d.sync() also synchronizes
+the persistent dictionary on disk, if feasible).
+"""
+
+from pickle import Pickler, Unpickler
+from io import BytesIO
+
+import collections.abc
+
+__all__ = ["Shelf", "BsdDbShelf", "DbfilenameShelf", "open"]
+
+class _ClosedDict(collections.abc.MutableMapping):
+ 'Marker for a closed dict. Access attempts raise a ValueError.'
+
+ def closed(self, *args):
+ raise ValueError('invalid operation on closed shelf')
+ __iter__ = __len__ = __getitem__ = __setitem__ = __delitem__ = keys = closed
+
+ def __repr__(self):
+ return ''
+
+
+class Shelf(collections.abc.MutableMapping):
+ """Base class for shelf implementations.
+
+ This is initialized with a dictionary-like object.
+ See the module's __doc__ string for an overview of the interface.
+ """
+
+ def __init__(self, dict, protocol=None, writeback=False,
+ keyencoding="utf-8"):
+ self.dict = dict
+ if protocol is None:
+ protocol = 3
+ self._protocol = protocol
+ self.writeback = writeback
+ self.cache = {}
+ self.keyencoding = keyencoding
+
+ def __iter__(self):
+ for k in self.dict.keys():
+ yield k.decode(self.keyencoding)
+
+ def __len__(self):
+ return len(self.dict)
+
+ def __contains__(self, key):
+ return key.encode(self.keyencoding) in self.dict
+
+ def get(self, key, default=None):
+ if key.encode(self.keyencoding) in self.dict:
+ return self[key]
+ return default
+
+ def __getitem__(self, key):
+ try:
+ value = self.cache[key]
+ except KeyError:
+ f = BytesIO(self.dict[key.encode(self.keyencoding)])
+ value = Unpickler(f).load()
+ if self.writeback:
+ self.cache[key] = value
+ return value
+
+ def __setitem__(self, key, value):
+ if self.writeback:
+ self.cache[key] = value
+ f = BytesIO()
+ p = Pickler(f, self._protocol)
+ p.dump(value)
+ self.dict[key.encode(self.keyencoding)] = f.getvalue()
+
+ def __delitem__(self, key):
+ del self.dict[key.encode(self.keyencoding)]
+ try:
+ del self.cache[key]
+ except KeyError:
+ pass
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, type, value, traceback):
+ self.close()
+
+ def close(self):
+ if self.dict is None:
+ return
+ try:
+ self.sync()
+ try:
+ self.dict.close()
+ except AttributeError:
+ pass
+ finally:
+ # Catch errors that may happen when close is called from __del__
+ # because CPython is in interpreter shutdown.
+ try:
+ self.dict = _ClosedDict()
+ except:
+ self.dict = None
+
+ def __del__(self):
+ if not hasattr(self, 'writeback'):
+ # __init__ didn't succeed, so don't bother closing
+ # see http://bugs.python.org/issue1339007 for details
+ return
+ self.close()
+
+ def sync(self):
+ if self.writeback and self.cache:
+ self.writeback = False
+ for key, entry in self.cache.items():
+ self[key] = entry
+ self.writeback = True
+ self.cache = {}
+ if hasattr(self.dict, 'sync'):
+ self.dict.sync()
+
+
+class BsdDbShelf(Shelf):
+ """Shelf implementation using the "BSD" db interface.
+
+ This adds methods first(), next(), previous(), last() and
+ set_location() that have no counterpart in [g]dbm databases.
+
+ The actual database must be opened using one of the "bsddb"
+ modules "open" routines (i.e. bsddb.hashopen, bsddb.btopen or
+ bsddb.rnopen) and passed to the constructor.
+
+ See the module's __doc__ string for an overview of the interface.
+ """
+
+ def __init__(self, dict, protocol=None, writeback=False,
+ keyencoding="utf-8"):
+ Shelf.__init__(self, dict, protocol, writeback, keyencoding)
+
+ def set_location(self, key):
+ (key, value) = self.dict.set_location(key)
+ f = BytesIO(value)
+ return (key.decode(self.keyencoding), Unpickler(f).load())
+
+ def next(self):
+ (key, value) = next(self.dict)
+ f = BytesIO(value)
+ return (key.decode(self.keyencoding), Unpickler(f).load())
+
+ def previous(self):
+ (key, value) = self.dict.previous()
+ f = BytesIO(value)
+ return (key.decode(self.keyencoding), Unpickler(f).load())
+
+ def first(self):
+ (key, value) = self.dict.first()
+ f = BytesIO(value)
+ return (key.decode(self.keyencoding), Unpickler(f).load())
+
+ def last(self):
+ (key, value) = self.dict.last()
+ f = BytesIO(value)
+ return (key.decode(self.keyencoding), Unpickler(f).load())
+
+
+class DbfilenameShelf(Shelf):
+ """Shelf implementation using the "dbm" generic dbm interface.
+
+ This is initialized with the filename for the dbm database.
+ See the module's __doc__ string for an overview of the interface.
+ """
+
+ def __init__(self, filename, flag='c', protocol=None, writeback=False):
+ import dbm
+ Shelf.__init__(self, dbm.open(filename, flag), protocol, writeback)
+
+
+def open(filename, flag='c', protocol=None, writeback=False):
+ """Open a persistent dictionary for reading and writing.
+
+ The filename parameter is the base filename for the underlying
+ database. As a side-effect, an extension may be added to the
+ filename and more than one file may be created. The optional flag
+ parameter has the same interpretation as the flag parameter of
+ dbm.open(). The optional protocol parameter specifies the
+ version of the pickle protocol.
+
+ See the module's __doc__ string for an overview of the interface.
+ """
+
+ return DbfilenameShelf(filename, flag, protocol, writeback)
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/site.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/site.py
new file mode 100644
index 0000000000000000000000000000000000000000..9fa21cca3866747ab3e074777e90e497c35a348d
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/site.py
@@ -0,0 +1,634 @@
+"""Append module search paths for third-party packages to sys.path.
+
+****************************************************************
+* This module is automatically imported during initialization. *
+****************************************************************
+
+This will append site-specific paths to the module search path. On
+Unix (including Mac OSX), it starts with sys.prefix and
+sys.exec_prefix (if different) and appends
+lib/python/site-packages.
+On other platforms (such as Windows), it tries each of the
+prefixes directly, as well as with lib/site-packages appended. The
+resulting directories, if they exist, are appended to sys.path, and
+also inspected for path configuration files.
+
+If a file named "pyvenv.cfg" exists one directory above sys.executable,
+sys.prefix and sys.exec_prefix are set to that directory and
+it is also checked for site-packages (sys.base_prefix and
+sys.base_exec_prefix will always be the "real" prefixes of the Python
+installation). If "pyvenv.cfg" (a bootstrap configuration file) contains
+the key "include-system-site-packages" set to anything other than "false"
+(case-insensitive), the system-level prefixes will still also be
+searched for site-packages; otherwise they won't.
+
+All of the resulting site-specific directories, if they exist, are
+appended to sys.path, and also inspected for path configuration
+files.
+
+A path configuration file is a file whose name has the form
+.pth; its contents are additional directories (one per line)
+to be added to sys.path. Non-existing directories (or
+non-directories) are never added to sys.path; no directory is added to
+sys.path more than once. Blank lines and lines beginning with
+'#' are skipped. Lines starting with 'import' are executed.
+
+For example, suppose sys.prefix and sys.exec_prefix are set to
+/usr/local and there is a directory /usr/local/lib/python2.5/site-packages
+with three subdirectories, foo, bar and spam, and two path
+configuration files, foo.pth and bar.pth. Assume foo.pth contains the
+following:
+
+ # foo package configuration
+ foo
+ bar
+ bletch
+
+and bar.pth contains:
+
+ # bar package configuration
+ bar
+
+Then the following directories are added to sys.path, in this order:
+
+ /usr/local/lib/python2.5/site-packages/bar
+ /usr/local/lib/python2.5/site-packages/foo
+
+Note that bletch is omitted because it doesn't exist; bar precedes foo
+because bar.pth comes alphabetically before foo.pth; and spam is
+omitted because it is not mentioned in either path configuration file.
+
+The readline module is also automatically configured to enable
+completion for systems that support it. This can be overridden in
+sitecustomize, usercustomize or PYTHONSTARTUP. Starting Python in
+isolated mode (-I) disables automatic readline configuration.
+
+After these operations, an attempt is made to import a module
+named sitecustomize, which can perform arbitrary additional
+site-specific customizations. If this import fails with an
+ImportError exception, it is silently ignored.
+"""
+
+import sys
+import os
+import builtins
+import _sitebuiltins
+import io
+
+# Prefixes for site-packages; add additional prefixes like /usr/local here
+PREFIXES = [sys.prefix, sys.exec_prefix]
+# Enable per user site-packages directory
+# set it to False to disable the feature or True to force the feature
+ENABLE_USER_SITE = None
+
+# for distutils.commands.install
+# These values are initialized by the getuserbase() and getusersitepackages()
+# functions, through the main() function when Python starts.
+USER_SITE = None
+USER_BASE = None
+
+
+def makepath(*paths):
+ dir = os.path.join(*paths)
+ try:
+ dir = os.path.abspath(dir)
+ except OSError:
+ pass
+ return dir, os.path.normcase(dir)
+
+
+def abs_paths():
+ """Set all module __file__ and __cached__ attributes to an absolute path"""
+ for m in set(sys.modules.values()):
+ if (getattr(getattr(m, '__loader__', None), '__module__', None) not in
+ ('_frozen_importlib', '_frozen_importlib_external')):
+ continue # don't mess with a PEP 302-supplied __file__
+ try:
+ m.__file__ = os.path.abspath(m.__file__)
+ except (AttributeError, OSError, TypeError):
+ pass
+ try:
+ m.__cached__ = os.path.abspath(m.__cached__)
+ except (AttributeError, OSError, TypeError):
+ pass
+
+
+def removeduppaths():
+ """ Remove duplicate entries from sys.path along with making them
+ absolute"""
+ # This ensures that the initial path provided by the interpreter contains
+ # only absolute pathnames, even if we're running from the build directory.
+ L = []
+ known_paths = set()
+ for dir in sys.path:
+ # Filter out duplicate paths (on case-insensitive file systems also
+ # if they only differ in case); turn relative paths into absolute
+ # paths.
+ dir, dircase = makepath(dir)
+ if dircase not in known_paths:
+ L.append(dir)
+ known_paths.add(dircase)
+ sys.path[:] = L
+ return known_paths
+
+
+def _init_pathinfo():
+ """Return a set containing all existing file system items from sys.path."""
+ d = set()
+ for item in sys.path:
+ try:
+ if os.path.exists(item):
+ _, itemcase = makepath(item)
+ d.add(itemcase)
+ except TypeError:
+ continue
+ return d
+
+
+def addpackage(sitedir, name, known_paths):
+ """Process a .pth file within the site-packages directory:
+ For each line in the file, either combine it with sitedir to a path
+ and add that to known_paths, or execute it if it starts with 'import '.
+ """
+ if known_paths is None:
+ known_paths = _init_pathinfo()
+ reset = True
+ else:
+ reset = False
+ fullname = os.path.join(sitedir, name)
+ try:
+ f = io.TextIOWrapper(io.open_code(fullname))
+ except OSError:
+ return
+ with f:
+ for n, line in enumerate(f):
+ if line.startswith("#"):
+ continue
+ try:
+ if line.startswith(("import ", "import\t")):
+ exec(line)
+ continue
+ line = line.rstrip()
+ dir, dircase = makepath(sitedir, line)
+ if not dircase in known_paths and os.path.exists(dir):
+ sys.path.append(dir)
+ known_paths.add(dircase)
+ except Exception:
+ print("Error processing line {:d} of {}:\n".format(n+1, fullname),
+ file=sys.stderr)
+ import traceback
+ for record in traceback.format_exception(*sys.exc_info()):
+ for line in record.splitlines():
+ print(' '+line, file=sys.stderr)
+ print("\nRemainder of file ignored", file=sys.stderr)
+ break
+ if reset:
+ known_paths = None
+ return known_paths
+
+
+def addsitedir(sitedir, known_paths=None):
+ """Add 'sitedir' argument to sys.path if missing and handle .pth files in
+ 'sitedir'"""
+ if known_paths is None:
+ known_paths = _init_pathinfo()
+ reset = True
+ else:
+ reset = False
+ sitedir, sitedircase = makepath(sitedir)
+ if not sitedircase in known_paths:
+ sys.path.append(sitedir) # Add path component
+ known_paths.add(sitedircase)
+ try:
+ names = os.listdir(sitedir)
+ except OSError:
+ return
+ names = [name for name in names if name.endswith(".pth")]
+ for name in sorted(names):
+ addpackage(sitedir, name, known_paths)
+ if reset:
+ known_paths = None
+ return known_paths
+
+
+def check_enableusersite():
+ """Check if user site directory is safe for inclusion
+
+ The function tests for the command line flag (including environment var),
+ process uid/gid equal to effective uid/gid.
+
+ None: Disabled for security reasons
+ False: Disabled by user (command line option)
+ True: Safe and enabled
+ """
+ if sys.flags.no_user_site:
+ return False
+
+ if hasattr(os, "getuid") and hasattr(os, "geteuid"):
+ # check process uid == effective uid
+ if os.geteuid() != os.getuid():
+ return None
+ if hasattr(os, "getgid") and hasattr(os, "getegid"):
+ # check process gid == effective gid
+ if os.getegid() != os.getgid():
+ return None
+
+ return True
+
+
+# NOTE: sysconfig and it's dependencies are relatively large but site module
+# needs very limited part of them.
+# To speedup startup time, we have copy of them.
+#
+# See https://bugs.python.org/issue29585
+
+# Copy of sysconfig._getuserbase()
+def _getuserbase():
+ env_base = os.environ.get("PYTHONUSERBASE", None)
+ if env_base:
+ return env_base
+
+ def joinuser(*args):
+ return os.path.expanduser(os.path.join(*args))
+
+ if os.name == "nt":
+ base = os.environ.get("APPDATA") or "~"
+ return joinuser(base, "Python")
+
+ if sys.platform == "darwin" and sys._framework:
+ return joinuser("~", "Library", sys._framework,
+ "%d.%d" % sys.version_info[:2])
+
+ return joinuser("~", ".local")
+
+
+# Same to sysconfig.get_path('purelib', os.name+'_user')
+def _get_path(userbase):
+ version = sys.version_info
+
+ if os.name == 'nt':
+ return f'{userbase}\\Python{version[0]}{version[1]}\\site-packages'
+
+ if sys.platform == 'darwin' and sys._framework:
+ return f'{userbase}/lib/python/site-packages'
+
+ return f'{userbase}/lib/python{version[0]}.{version[1]}/site-packages'
+
+
+def getuserbase():
+ """Returns the `user base` directory path.
+
+ The `user base` directory can be used to store data. If the global
+ variable ``USER_BASE`` is not initialized yet, this function will also set
+ it.
+ """
+ global USER_BASE
+ if USER_BASE is None:
+ USER_BASE = _getuserbase()
+ return USER_BASE
+
+
+def getusersitepackages():
+ """Returns the user-specific site-packages directory path.
+
+ If the global variable ``USER_SITE`` is not initialized yet, this
+ function will also set it.
+ """
+ global USER_SITE
+ userbase = getuserbase() # this will also set USER_BASE
+
+ if USER_SITE is None:
+ USER_SITE = _get_path(userbase)
+
+ return USER_SITE
+
+def addusersitepackages(known_paths):
+ """Add a per user site-package to sys.path
+
+ Each user has its own python directory with site-packages in the
+ home directory.
+ """
+ # get the per user site-package path
+ # this call will also make sure USER_BASE and USER_SITE are set
+ user_site = getusersitepackages()
+
+ if ENABLE_USER_SITE and os.path.isdir(user_site):
+ addsitedir(user_site, known_paths)
+ return known_paths
+
+def getsitepackages(prefixes=None):
+ """Returns a list containing all global site-packages directories.
+
+ For each directory present in ``prefixes`` (or the global ``PREFIXES``),
+ this function will find its `site-packages` subdirectory depending on the
+ system environment, and will return a list of full paths.
+ """
+ sitepackages = []
+ seen = set()
+
+ if prefixes is None:
+ prefixes = PREFIXES
+
+ for prefix in prefixes:
+ if not prefix or prefix in seen:
+ continue
+ seen.add(prefix)
+
+ if os.sep == '/':
+ sitepackages.append(os.path.join(prefix, "lib",
+ "python%d.%d" % sys.version_info[:2],
+ "site-packages"))
+ else:
+ sitepackages.append(prefix)
+ sitepackages.append(os.path.join(prefix, "lib", "site-packages"))
+ return sitepackages
+
+def addsitepackages(known_paths, prefixes=None):
+ """Add site-packages to sys.path"""
+ for sitedir in getsitepackages(prefixes):
+ if os.path.isdir(sitedir):
+ addsitedir(sitedir, known_paths)
+
+ return known_paths
+
+def setquit():
+ """Define new builtins 'quit' and 'exit'.
+
+ These are objects which make the interpreter exit when called.
+ The repr of each object contains a hint at how it works.
+
+ """
+ if os.sep == '\\':
+ eof = 'Ctrl-Z plus Return'
+ else:
+ eof = 'Ctrl-D (i.e. EOF)'
+
+ builtins.quit = _sitebuiltins.Quitter('quit', eof)
+ builtins.exit = _sitebuiltins.Quitter('exit', eof)
+
+
+def setcopyright():
+ """Set 'copyright' and 'credits' in builtins"""
+ builtins.copyright = _sitebuiltins._Printer("copyright", sys.copyright)
+ if sys.platform[:4] == 'java':
+ builtins.credits = _sitebuiltins._Printer(
+ "credits",
+ "Jython is maintained by the Jython developers (www.jython.org).")
+ else:
+ builtins.credits = _sitebuiltins._Printer("credits", """\
+ Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
+ for supporting Python development. See www.python.org for more information.""")
+ files, dirs = [], []
+ # Not all modules are required to have a __file__ attribute. See
+ # PEP 420 for more details.
+ if hasattr(os, '__file__'):
+ here = os.path.dirname(os.__file__)
+ files.extend(["LICENSE.txt", "LICENSE"])
+ dirs.extend([os.path.join(here, os.pardir), here, os.curdir])
+ builtins.license = _sitebuiltins._Printer(
+ "license",
+ "See https://www.python.org/psf/license/",
+ files, dirs)
+
+
+def sethelper():
+ builtins.help = _sitebuiltins._Helper()
+
+def enablerlcompleter():
+ """Enable default readline configuration on interactive prompts, by
+ registering a sys.__interactivehook__.
+
+ If the readline module can be imported, the hook will set the Tab key
+ as completion key and register ~/.python_history as history file.
+ This can be overridden in the sitecustomize or usercustomize module,
+ or in a PYTHONSTARTUP file.
+ """
+ def register_readline():
+ import atexit
+ try:
+ import readline
+ import rlcompleter
+ except ImportError:
+ return
+
+ # Reading the initialization (config) file may not be enough to set a
+ # completion key, so we set one first and then read the file.
+ readline_doc = getattr(readline, '__doc__', '')
+ if readline_doc is not None and 'libedit' in readline_doc:
+ readline.parse_and_bind('bind ^I rl_complete')
+ else:
+ readline.parse_and_bind('tab: complete')
+
+ try:
+ readline.read_init_file()
+ except OSError:
+ # An OSError here could have many causes, but the most likely one
+ # is that there's no .inputrc file (or .editrc file in the case of
+ # Mac OS X + libedit) in the expected location. In that case, we
+ # want to ignore the exception.
+ pass
+
+ if readline.get_current_history_length() == 0:
+ # If no history was loaded, default to .python_history.
+ # The guard is necessary to avoid doubling history size at
+ # each interpreter exit when readline was already configured
+ # through a PYTHONSTARTUP hook, see:
+ # http://bugs.python.org/issue5845#msg198636
+ history = os.path.join(os.path.expanduser('~'),
+ '.python_history')
+ try:
+ readline.read_history_file(history)
+ except OSError:
+ pass
+
+ def write_history():
+ try:
+ readline.write_history_file(history)
+ except OSError:
+ # bpo-19891, bpo-41193: Home directory does not exist
+ # or is not writable, or the filesystem is read-only.
+ pass
+
+ atexit.register(write_history)
+
+ sys.__interactivehook__ = register_readline
+
+def venv(known_paths):
+ global PREFIXES, ENABLE_USER_SITE
+
+ env = os.environ
+ if sys.platform == 'darwin' and '__PYVENV_LAUNCHER__' in env:
+ executable = sys._base_executable = os.environ['__PYVENV_LAUNCHER__']
+ else:
+ executable = sys.executable
+ exe_dir, _ = os.path.split(os.path.abspath(executable))
+ site_prefix = os.path.dirname(exe_dir)
+ sys._home = None
+ conf_basename = 'pyvenv.cfg'
+ candidate_confs = [
+ conffile for conffile in (
+ os.path.join(exe_dir, conf_basename),
+ os.path.join(site_prefix, conf_basename)
+ )
+ if os.path.isfile(conffile)
+ ]
+
+ if candidate_confs:
+ virtual_conf = candidate_confs[0]
+ system_site = "true"
+ # Issue 25185: Use UTF-8, as that's what the venv module uses when
+ # writing the file.
+ with open(virtual_conf, encoding='utf-8') as f:
+ for line in f:
+ if '=' in line:
+ key, _, value = line.partition('=')
+ key = key.strip().lower()
+ value = value.strip()
+ if key == 'include-system-site-packages':
+ system_site = value.lower()
+ elif key == 'home':
+ sys._home = value
+
+ sys.prefix = sys.exec_prefix = site_prefix
+
+ # Doing this here ensures venv takes precedence over user-site
+ addsitepackages(known_paths, [sys.prefix])
+
+ # addsitepackages will process site_prefix again if its in PREFIXES,
+ # but that's ok; known_paths will prevent anything being added twice
+ if system_site == "true":
+ PREFIXES.insert(0, sys.prefix)
+ else:
+ PREFIXES = [sys.prefix]
+ ENABLE_USER_SITE = False
+
+ return known_paths
+
+
+def execsitecustomize():
+ """Run custom site specific code, if available."""
+ try:
+ try:
+ import sitecustomize
+ except ImportError as exc:
+ if exc.name == 'sitecustomize':
+ pass
+ else:
+ raise
+ except Exception as err:
+ if sys.flags.verbose:
+ sys.excepthook(*sys.exc_info())
+ else:
+ sys.stderr.write(
+ "Error in sitecustomize; set PYTHONVERBOSE for traceback:\n"
+ "%s: %s\n" %
+ (err.__class__.__name__, err))
+
+
+def execusercustomize():
+ """Run custom user specific code, if available."""
+ try:
+ try:
+ import usercustomize
+ except ImportError as exc:
+ if exc.name == 'usercustomize':
+ pass
+ else:
+ raise
+ except Exception as err:
+ if sys.flags.verbose:
+ sys.excepthook(*sys.exc_info())
+ else:
+ sys.stderr.write(
+ "Error in usercustomize; set PYTHONVERBOSE for traceback:\n"
+ "%s: %s\n" %
+ (err.__class__.__name__, err))
+
+
+def main():
+ """Add standard site-specific directories to the module search path.
+
+ This function is called automatically when this module is imported,
+ unless the python interpreter was started with the -S flag.
+ """
+ global ENABLE_USER_SITE
+
+ orig_path = sys.path[:]
+ known_paths = removeduppaths()
+ if orig_path != sys.path:
+ # removeduppaths() might make sys.path absolute.
+ # fix __file__ and __cached__ of already imported modules too.
+ abs_paths()
+
+ known_paths = venv(known_paths)
+ if ENABLE_USER_SITE is None:
+ ENABLE_USER_SITE = check_enableusersite()
+ known_paths = addusersitepackages(known_paths)
+ known_paths = addsitepackages(known_paths)
+ setquit()
+ setcopyright()
+ sethelper()
+ if not sys.flags.isolated:
+ enablerlcompleter()
+ execsitecustomize()
+ if ENABLE_USER_SITE:
+ execusercustomize()
+
+# Prevent extending of sys.path when python was started with -S and
+# site is imported later.
+if not sys.flags.no_site:
+ main()
+
+def _script():
+ help = """\
+ %s [--user-base] [--user-site]
+
+ Without arguments print some useful information
+ With arguments print the value of USER_BASE and/or USER_SITE separated
+ by '%s'.
+
+ Exit codes with --user-base or --user-site:
+ 0 - user site directory is enabled
+ 1 - user site directory is disabled by user
+ 2 - uses site directory is disabled by super user
+ or for security reasons
+ >2 - unknown error
+ """
+ args = sys.argv[1:]
+ if not args:
+ user_base = getuserbase()
+ user_site = getusersitepackages()
+ print("sys.path = [")
+ for dir in sys.path:
+ print(" %r," % (dir,))
+ print("]")
+ print("USER_BASE: %r (%s)" % (user_base,
+ "exists" if os.path.isdir(user_base) else "doesn't exist"))
+ print("USER_SITE: %r (%s)" % (user_site,
+ "exists" if os.path.isdir(user_site) else "doesn't exist"))
+ print("ENABLE_USER_SITE: %r" % ENABLE_USER_SITE)
+ sys.exit(0)
+
+ buffer = []
+ if '--user-base' in args:
+ buffer.append(USER_BASE)
+ if '--user-site' in args:
+ buffer.append(USER_SITE)
+
+ if buffer:
+ print(os.pathsep.join(buffer))
+ if ENABLE_USER_SITE:
+ sys.exit(0)
+ elif ENABLE_USER_SITE is False:
+ sys.exit(1)
+ elif ENABLE_USER_SITE is None:
+ sys.exit(2)
+ else:
+ sys.exit(3)
+ else:
+ import textwrap
+ print(textwrap.dedent(help % (sys.argv[0], os.pathsep)))
+ sys.exit(10)
+
+if __name__ == '__main__':
+ _script()
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/smtplib.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/smtplib.py
new file mode 100644
index 0000000000000000000000000000000000000000..9c390db0bfa7d1d67fc0dd99e4ff9a1515b308e6
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/smtplib.py
@@ -0,0 +1,1134 @@
+#! /usr/bin/env python3
+
+'''SMTP/ESMTP client class.
+
+This should follow RFC 821 (SMTP), RFC 1869 (ESMTP), RFC 2554 (SMTP
+Authentication) and RFC 2487 (Secure SMTP over TLS).
+
+Notes:
+
+Please remember, when doing ESMTP, that the names of the SMTP service
+extensions are NOT the same thing as the option keywords for the RCPT
+and MAIL commands!
+
+Example:
+
+ >>> import smtplib
+ >>> s=smtplib.SMTP("localhost")
+ >>> print(s.help())
+ This is Sendmail version 8.8.4
+ Topics:
+ HELO EHLO MAIL RCPT DATA
+ RSET NOOP QUIT HELP VRFY
+ EXPN VERB ETRN DSN
+ For more info use "HELP ".
+ To report bugs in the implementation send email to
+ sendmail-bugs@sendmail.org.
+ For local information send email to Postmaster at your site.
+ End of HELP info
+ >>> s.putcmd("vrfy","someone@here")
+ >>> s.getreply()
+ (250, "Somebody OverHere ")
+ >>> s.quit()
+'''
+
+# Author: The Dragon De Monsyne
+# ESMTP support, test code and doc fixes added by
+# Eric S. Raymond
+# Better RFC 821 compliance (MAIL and RCPT, and CRLF in data)
+# by Carey Evans , for picky mail servers.
+# RFC 2554 (authentication) support by Gerhard Haering .
+#
+# This was modified from the Python 1.5 library HTTP lib.
+
+import socket
+import io
+import re
+import email.utils
+import email.message
+import email.generator
+import base64
+import hmac
+import copy
+import datetime
+import sys
+from email.base64mime import body_encode as encode_base64
+
+__all__ = ["SMTPException", "SMTPNotSupportedError", "SMTPServerDisconnected", "SMTPResponseException",
+ "SMTPSenderRefused", "SMTPRecipientsRefused", "SMTPDataError",
+ "SMTPConnectError", "SMTPHeloError", "SMTPAuthenticationError",
+ "quoteaddr", "quotedata", "SMTP"]
+
+SMTP_PORT = 25
+SMTP_SSL_PORT = 465
+CRLF = "\r\n"
+bCRLF = b"\r\n"
+_MAXLINE = 8192 # more than 8 times larger than RFC 821, 4.5.3
+_MAXCHALLENGE = 5 # Maximum number of AUTH challenges sent
+
+OLDSTYLE_AUTH = re.compile(r"auth=(.*)", re.I)
+
+# Exception classes used by this module.
+class SMTPException(OSError):
+ """Base class for all exceptions raised by this module."""
+
+class SMTPNotSupportedError(SMTPException):
+ """The command or option is not supported by the SMTP server.
+
+ This exception is raised when an attempt is made to run a command or a
+ command with an option which is not supported by the server.
+ """
+
+class SMTPServerDisconnected(SMTPException):
+ """Not connected to any SMTP server.
+
+ This exception is raised when the server unexpectedly disconnects,
+ or when an attempt is made to use the SMTP instance before
+ connecting it to a server.
+ """
+
+class SMTPResponseException(SMTPException):
+ """Base class for all exceptions that include an SMTP error code.
+
+ These exceptions are generated in some instances when the SMTP
+ server returns an error code. The error code is stored in the
+ `smtp_code' attribute of the error, and the `smtp_error' attribute
+ is set to the error message.
+ """
+
+ def __init__(self, code, msg):
+ self.smtp_code = code
+ self.smtp_error = msg
+ self.args = (code, msg)
+
+class SMTPSenderRefused(SMTPResponseException):
+ """Sender address refused.
+
+ In addition to the attributes set by on all SMTPResponseException
+ exceptions, this sets `sender' to the string that the SMTP refused.
+ """
+
+ def __init__(self, code, msg, sender):
+ self.smtp_code = code
+ self.smtp_error = msg
+ self.sender = sender
+ self.args = (code, msg, sender)
+
+class SMTPRecipientsRefused(SMTPException):
+ """All recipient addresses refused.
+
+ The errors for each recipient are accessible through the attribute
+ 'recipients', which is a dictionary of exactly the same sort as
+ SMTP.sendmail() returns.
+ """
+
+ def __init__(self, recipients):
+ self.recipients = recipients
+ self.args = (recipients,)
+
+
+class SMTPDataError(SMTPResponseException):
+ """The SMTP server didn't accept the data."""
+
+class SMTPConnectError(SMTPResponseException):
+ """Error during connection establishment."""
+
+class SMTPHeloError(SMTPResponseException):
+ """The server refused our HELO reply."""
+
+class SMTPAuthenticationError(SMTPResponseException):
+ """Authentication error.
+
+ Most probably the server didn't accept the username/password
+ combination provided.
+ """
+
+def quoteaddr(addrstring):
+ """Quote a subset of the email addresses defined by RFC 821.
+
+ Should be able to handle anything email.utils.parseaddr can handle.
+ """
+ displayname, addr = email.utils.parseaddr(addrstring)
+ if (displayname, addr) == ('', ''):
+ # parseaddr couldn't parse it, use it as is and hope for the best.
+ if addrstring.strip().startswith('<'):
+ return addrstring
+ return "<%s>" % addrstring
+ return "<%s>" % addr
+
+def _addr_only(addrstring):
+ displayname, addr = email.utils.parseaddr(addrstring)
+ if (displayname, addr) == ('', ''):
+ # parseaddr couldn't parse it, so use it as is.
+ return addrstring
+ return addr
+
+# Legacy method kept for backward compatibility.
+def quotedata(data):
+ """Quote data for email.
+
+ Double leading '.', and change Unix newline '\\n', or Mac '\\r' into
+ Internet CRLF end-of-line.
+ """
+ return re.sub(r'(?m)^\.', '..',
+ re.sub(r'(?:\r\n|\n|\r(?!\n))', CRLF, data))
+
+def _quote_periods(bindata):
+ return re.sub(br'(?m)^\.', b'..', bindata)
+
+def _fix_eols(data):
+ return re.sub(r'(?:\r\n|\n|\r(?!\n))', CRLF, data)
+
+try:
+ import ssl
+except ImportError:
+ _have_ssl = False
+else:
+ _have_ssl = True
+
+
+class SMTP:
+ """This class manages a connection to an SMTP or ESMTP server.
+ SMTP Objects:
+ SMTP objects have the following attributes:
+ helo_resp
+ This is the message given by the server in response to the
+ most recent HELO command.
+
+ ehlo_resp
+ This is the message given by the server in response to the
+ most recent EHLO command. This is usually multiline.
+
+ does_esmtp
+ This is a True value _after you do an EHLO command_, if the
+ server supports ESMTP.
+
+ esmtp_features
+ This is a dictionary, which, if the server supports ESMTP,
+ will _after you do an EHLO command_, contain the names of the
+ SMTP service extensions this server supports, and their
+ parameters (if any).
+
+ Note, all extension names are mapped to lower case in the
+ dictionary.
+
+ See each method's docstrings for details. In general, there is a
+ method of the same name to perform each SMTP command. There is also a
+ method called 'sendmail' that will do an entire mail transaction.
+ """
+ debuglevel = 0
+
+ sock = None
+ file = None
+ helo_resp = None
+ ehlo_msg = "ehlo"
+ ehlo_resp = None
+ does_esmtp = 0
+ default_port = SMTP_PORT
+
+ def __init__(self, host='', port=0, local_hostname=None,
+ timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
+ source_address=None):
+ """Initialize a new instance.
+
+ If specified, `host` is the name of the remote host to which to
+ connect. If specified, `port` specifies the port to which to connect.
+ By default, smtplib.SMTP_PORT is used. If a host is specified the
+ connect method is called, and if it returns anything other than a
+ success code an SMTPConnectError is raised. If specified,
+ `local_hostname` is used as the FQDN of the local host in the HELO/EHLO
+ command. Otherwise, the local hostname is found using
+ socket.getfqdn(). The `source_address` parameter takes a 2-tuple (host,
+ port) for the socket to bind to as its source address before
+ connecting. If the host is '' and port is 0, the OS default behavior
+ will be used.
+
+ """
+ self._host = host
+ self.timeout = timeout
+ self.esmtp_features = {}
+ self.command_encoding = 'ascii'
+ self.source_address = source_address
+ self._auth_challenge_count = 0
+
+ if host:
+ (code, msg) = self.connect(host, port)
+ if code != 220:
+ self.close()
+ raise SMTPConnectError(code, msg)
+ if local_hostname is not None:
+ self.local_hostname = local_hostname
+ else:
+ # RFC 2821 says we should use the fqdn in the EHLO/HELO verb, and
+ # if that can't be calculated, that we should use a domain literal
+ # instead (essentially an encoded IP address like [A.B.C.D]).
+ fqdn = socket.getfqdn()
+ if '.' in fqdn:
+ self.local_hostname = fqdn
+ else:
+ # We can't find an fqdn hostname, so use a domain literal
+ addr = '127.0.0.1'
+ try:
+ addr = socket.gethostbyname(socket.gethostname())
+ except socket.gaierror:
+ pass
+ self.local_hostname = '[%s]' % addr
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args):
+ try:
+ code, message = self.docmd("QUIT")
+ if code != 221:
+ raise SMTPResponseException(code, message)
+ except SMTPServerDisconnected:
+ pass
+ finally:
+ self.close()
+
+ def set_debuglevel(self, debuglevel):
+ """Set the debug output level.
+
+ A non-false value results in debug messages for connection and for all
+ messages sent to and received from the server.
+
+ """
+ self.debuglevel = debuglevel
+
+ def _print_debug(self, *args):
+ if self.debuglevel > 1:
+ print(datetime.datetime.now().time(), *args, file=sys.stderr)
+ else:
+ print(*args, file=sys.stderr)
+
+ def _get_socket(self, host, port, timeout):
+ # This makes it simpler for SMTP_SSL to use the SMTP connect code
+ # and just alter the socket connection bit.
+ if self.debuglevel > 0:
+ self._print_debug('connect: to', (host, port), self.source_address)
+ return socket.create_connection((host, port), timeout,
+ self.source_address)
+
+ def connect(self, host='localhost', port=0, source_address=None):
+ """Connect to a host on a given port.
+
+ If the hostname ends with a colon (`:') followed by a number, and
+ there is no port specified, that suffix will be stripped off and the
+ number interpreted as the port number to use.
+
+ Note: This method is automatically invoked by __init__, if a host is
+ specified during instantiation.
+
+ """
+
+ if source_address:
+ self.source_address = source_address
+
+ if not port and (host.find(':') == host.rfind(':')):
+ i = host.rfind(':')
+ if i >= 0:
+ host, port = host[:i], host[i + 1:]
+ try:
+ port = int(port)
+ except ValueError:
+ raise OSError("nonnumeric port")
+ if not port:
+ port = self.default_port
+ sys.audit("smtplib.connect", self, host, port)
+ self.sock = self._get_socket(host, port, self.timeout)
+ self.file = None
+ (code, msg) = self.getreply()
+ if self.debuglevel > 0:
+ self._print_debug('connect:', repr(msg))
+ return (code, msg)
+
+ def send(self, s):
+ """Send `s' to the server."""
+ if self.debuglevel > 0:
+ self._print_debug('send:', repr(s))
+ if self.sock:
+ if isinstance(s, str):
+ # send is used by the 'data' command, where command_encoding
+ # 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.send", self, s)
+ try:
+ self.sock.sendall(s)
+ except OSError:
+ self.close()
+ raise SMTPServerDisconnected('Server not connected')
+ else:
+ raise SMTPServerDisconnected('please run connect() first')
+
+ def putcmd(self, cmd, args=""):
+ """Send a command to the server."""
+ if args == "":
+ s = cmd
+ else:
+ s = f'{cmd} {args}'
+ if '\r' in s or '\n' in s:
+ s = s.replace('\n', '\\n').replace('\r', '\\r')
+ raise ValueError(
+ f'command and arguments contain prohibited newline characters: {s}'
+ )
+ self.send(f'{s}{CRLF}')
+
+ def getreply(self):
+ """Get a reply from the server.
+
+ Returns a tuple consisting of:
+
+ - server response code (e.g. '250', or such, if all goes well)
+ Note: returns -1 if it can't read response code.
+
+ - server response string corresponding to response code (multiline
+ responses are converted to a single, multiline string).
+
+ Raises SMTPServerDisconnected if end-of-file is reached.
+ """
+ resp = []
+ if self.file is None:
+ self.file = self.sock.makefile('rb')
+ while 1:
+ try:
+ line = self.file.readline(_MAXLINE + 1)
+ except OSError as e:
+ self.close()
+ raise SMTPServerDisconnected("Connection unexpectedly closed: "
+ + str(e))
+ if not line:
+ self.close()
+ raise SMTPServerDisconnected("Connection unexpectedly closed")
+ if self.debuglevel > 0:
+ self._print_debug('reply:', repr(line))
+ if len(line) > _MAXLINE:
+ self.close()
+ raise SMTPResponseException(500, "Line too long.")
+ resp.append(line[4:].strip(b' \t\r\n'))
+ code = line[:3]
+ # Check that the error code is syntactically correct.
+ # Don't attempt to read a continuation line if it is broken.
+ try:
+ errcode = int(code)
+ except ValueError:
+ errcode = -1
+ break
+ # Check if multiline response.
+ if line[3:4] != b"-":
+ break
+
+ errmsg = b"\n".join(resp)
+ if self.debuglevel > 0:
+ self._print_debug('reply: retcode (%s); Msg: %a' % (errcode, errmsg))
+ return errcode, errmsg
+
+ def docmd(self, cmd, args=""):
+ """Send a command, and return its response code."""
+ self.putcmd(cmd, args)
+ return self.getreply()
+
+ # std smtp commands
+ def helo(self, name=''):
+ """SMTP 'helo' command.
+ Hostname to send for this command defaults to the FQDN of the local
+ host.
+ """
+ self.putcmd("helo", name or self.local_hostname)
+ (code, msg) = self.getreply()
+ self.helo_resp = msg
+ return (code, msg)
+
+ def ehlo(self, name=''):
+ """ SMTP 'ehlo' command.
+ Hostname to send for this command defaults to the FQDN of the local
+ host.
+ """
+ self.esmtp_features = {}
+ self.putcmd(self.ehlo_msg, name or self.local_hostname)
+ (code, msg) = self.getreply()
+ # According to RFC1869 some (badly written)
+ # MTA's will disconnect on an ehlo. Toss an exception if
+ # that happens -ddm
+ if code == -1 and len(msg) == 0:
+ self.close()
+ raise SMTPServerDisconnected("Server not connected")
+ self.ehlo_resp = msg
+ if code != 250:
+ return (code, msg)
+ self.does_esmtp = 1
+ #parse the ehlo response -ddm
+ assert isinstance(self.ehlo_resp, bytes), repr(self.ehlo_resp)
+ resp = self.ehlo_resp.decode("latin-1").split('\n')
+ del resp[0]
+ for each in resp:
+ # To be able to communicate with as many SMTP servers as possible,
+ # we have to take the old-style auth advertisement into account,
+ # because:
+ # 1) Else our SMTP feature parser gets confused.
+ # 2) There are some servers that only advertise the auth methods we
+ # support using the old style.
+ auth_match = OLDSTYLE_AUTH.match(each)
+ if auth_match:
+ # This doesn't remove duplicates, but that's no problem
+ self.esmtp_features["auth"] = self.esmtp_features.get("auth", "") \
+ + " " + auth_match.groups(0)[0]
+ continue
+
+ # RFC 1869 requires a space between ehlo keyword and parameters.
+ # It's actually stricter, in that only spaces are allowed between
+ # parameters, but were not going to check for that here. Note
+ # that the space isn't present if there are no parameters.
+ m = re.match(r'(?P[A-Za-z0-9][A-Za-z0-9\-]*) ?', each)
+ if m:
+ feature = m.group("feature").lower()
+ params = m.string[m.end("feature"):].strip()
+ if feature == "auth":
+ self.esmtp_features[feature] = self.esmtp_features.get(feature, "") \
+ + " " + params
+ else:
+ self.esmtp_features[feature] = params
+ return (code, msg)
+
+ def has_extn(self, opt):
+ """Does the server support a given SMTP service extension?"""
+ return opt.lower() in self.esmtp_features
+
+ def help(self, args=''):
+ """SMTP 'help' command.
+ Returns help text from server."""
+ self.putcmd("help", args)
+ return self.getreply()[1]
+
+ def rset(self):
+ """SMTP 'rset' command -- resets session."""
+ self.command_encoding = 'ascii'
+ return self.docmd("rset")
+
+ def _rset(self):
+ """Internal 'rset' command which ignores any SMTPServerDisconnected error.
+
+ Used internally in the library, since the server disconnected error
+ should appear to the application when the *next* command is issued, if
+ we are doing an internal "safety" reset.
+ """
+ try:
+ self.rset()
+ except SMTPServerDisconnected:
+ pass
+
+ def noop(self):
+ """SMTP 'noop' command -- doesn't do anything :>"""
+ return self.docmd("noop")
+
+ def mail(self, sender, options=()):
+ """SMTP 'mail' command -- begins mail xfer session.
+
+ This method may raise the following exceptions:
+
+ SMTPNotSupportedError The options parameter includes 'SMTPUTF8'
+ but the SMTPUTF8 extension is not supported by
+ the server.
+ """
+ optionlist = ''
+ if options and self.does_esmtp:
+ if any(x.lower()=='smtputf8' for x in options):
+ if self.has_extn('smtputf8'):
+ self.command_encoding = 'utf-8'
+ else:
+ raise SMTPNotSupportedError(
+ 'SMTPUTF8 not supported by server')
+ optionlist = ' ' + ' '.join(options)
+ self.putcmd("mail", "FROM:%s%s" % (quoteaddr(sender), optionlist))
+ return self.getreply()
+
+ def rcpt(self, recip, options=()):
+ """SMTP 'rcpt' command -- indicates 1 recipient for this mail."""
+ optionlist = ''
+ if options and self.does_esmtp:
+ optionlist = ' ' + ' '.join(options)
+ self.putcmd("rcpt", "TO:%s%s" % (quoteaddr(recip), optionlist))
+ return self.getreply()
+
+ def data(self, msg):
+ """SMTP 'DATA' command -- sends message data to server.
+
+ Automatically quotes lines beginning with a period per rfc821.
+ Raises SMTPDataError if there is an unexpected reply to the
+ DATA command; the return value from this method is the final
+ response code received when the all data is sent. If msg
+ is a string, lone '\\r' and '\\n' characters are converted to
+ '\\r\\n' characters. If msg is bytes, it is transmitted as is.
+ """
+ self.putcmd("data")
+ (code, repl) = self.getreply()
+ if self.debuglevel > 0:
+ self._print_debug('data:', (code, repl))
+ if code != 354:
+ raise SMTPDataError(code, repl)
+ else:
+ if isinstance(msg, str):
+ msg = _fix_eols(msg).encode('ascii')
+ q = _quote_periods(msg)
+ if q[-2:] != bCRLF:
+ q = q + bCRLF
+ q = q + b"." + bCRLF
+ self.send(q)
+ (code, msg) = self.getreply()
+ if self.debuglevel > 0:
+ self._print_debug('data:', (code, msg))
+ return (code, msg)
+
+ def verify(self, address):
+ """SMTP 'verify' command -- checks for address validity."""
+ self.putcmd("vrfy", _addr_only(address))
+ return self.getreply()
+ # a.k.a.
+ vrfy = verify
+
+ def expn(self, address):
+ """SMTP 'expn' command -- expands a mailing list."""
+ self.putcmd("expn", _addr_only(address))
+ return self.getreply()
+
+ # some useful methods
+
+ def ehlo_or_helo_if_needed(self):
+ """Call self.ehlo() and/or self.helo() if needed.
+
+ If there has been no previous EHLO or HELO command this session, this
+ method tries ESMTP EHLO first.
+
+ This method may raise the following exceptions:
+
+ SMTPHeloError The server didn't reply properly to
+ the helo greeting.
+ """
+ if self.helo_resp is None and self.ehlo_resp is None:
+ if not (200 <= self.ehlo()[0] <= 299):
+ (code, resp) = self.helo()
+ if not (200 <= code <= 299):
+ raise SMTPHeloError(code, resp)
+
+ def auth(self, mechanism, authobject, *, initial_response_ok=True):
+ """Authentication command - requires response processing.
+
+ 'mechanism' specifies which authentication mechanism is to
+ be used - the valid values are those listed in the 'auth'
+ element of 'esmtp_features'.
+
+ 'authobject' must be a callable object taking a single argument:
+
+ data = authobject(challenge)
+
+ It will be called to process the server's challenge response; the
+ challenge argument it is passed will be a bytes. It should return
+ an ASCII string that will be base64 encoded and sent to the server.
+
+ Keyword arguments:
+ - initial_response_ok: Allow sending the RFC 4954 initial-response
+ to the AUTH command, if the authentication methods supports it.
+ """
+ # RFC 4954 allows auth methods to provide an initial response. Not all
+ # methods support it. By definition, if they return something other
+ # than None when challenge is None, then they do. See issue #15014.
+ mechanism = mechanism.upper()
+ initial_response = (authobject() if initial_response_ok else None)
+ if initial_response is not None:
+ response = encode_base64(initial_response.encode('ascii'), eol='')
+ (code, resp) = self.docmd("AUTH", mechanism + " " + response)
+ self._auth_challenge_count = 1
+ else:
+ (code, resp) = self.docmd("AUTH", mechanism)
+ self._auth_challenge_count = 0
+ # If server responds with a challenge, send the response.
+ while code == 334:
+ self._auth_challenge_count += 1
+ challenge = base64.decodebytes(resp)
+ response = encode_base64(
+ authobject(challenge).encode('ascii'), eol='')
+ (code, resp) = self.docmd(response)
+ # If server keeps sending challenges, something is wrong.
+ if self._auth_challenge_count > _MAXCHALLENGE:
+ raise SMTPException(
+ "Server AUTH mechanism infinite loop. Last response: "
+ + repr((code, resp))
+ )
+ if code in (235, 503):
+ return (code, resp)
+ raise SMTPAuthenticationError(code, resp)
+
+ def auth_cram_md5(self, challenge=None):
+ """ Authobject to use with CRAM-MD5 authentication. Requires self.user
+ and self.password to be set."""
+ # CRAM-MD5 does not support initial-response.
+ if challenge is None:
+ return None
+ return self.user + " " + hmac.HMAC(
+ self.password.encode('ascii'), challenge, 'md5').hexdigest()
+
+ def auth_plain(self, challenge=None):
+ """ Authobject to use with PLAIN authentication. Requires self.user and
+ self.password to be set."""
+ return "\0%s\0%s" % (self.user, self.password)
+
+ def auth_login(self, challenge=None):
+ """ Authobject to use with LOGIN authentication. Requires self.user and
+ self.password to be set."""
+ if challenge is None or self._auth_challenge_count < 2:
+ return self.user
+ else:
+ return self.password
+
+ def login(self, user, password, *, initial_response_ok=True):
+ """Log in on an SMTP server that requires authentication.
+
+ The arguments are:
+ - user: The user name to authenticate with.
+ - password: The password for the authentication.
+
+ Keyword arguments:
+ - initial_response_ok: Allow sending the RFC 4954 initial-response
+ to the AUTH command, if the authentication methods supports it.
+
+ If there has been no previous EHLO or HELO command this session, this
+ method tries ESMTP EHLO first.
+
+ This method will return normally if the authentication was successful.
+
+ This method may raise the following exceptions:
+
+ SMTPHeloError The server didn't reply properly to
+ the helo greeting.
+ SMTPAuthenticationError The server didn't accept the username/
+ password combination.
+ SMTPNotSupportedError The AUTH command is not supported by the
+ server.
+ SMTPException No suitable authentication method was
+ found.
+ """
+
+ self.ehlo_or_helo_if_needed()
+ if not self.has_extn("auth"):
+ raise SMTPNotSupportedError(
+ "SMTP AUTH extension not supported by server.")
+
+ # Authentication methods the server claims to support
+ advertised_authlist = self.esmtp_features["auth"].split()
+
+ # Authentication methods we can handle in our preferred order:
+ preferred_auths = ['CRAM-MD5', 'PLAIN', 'LOGIN']
+
+ # We try the supported authentications in our preferred order, if
+ # the server supports them.
+ authlist = [auth for auth in preferred_auths
+ if auth in advertised_authlist]
+ if not authlist:
+ raise SMTPException("No suitable authentication method found.")
+
+ # Some servers advertise authentication methods they don't really
+ # support, so if authentication fails, we continue until we've tried
+ # all methods.
+ self.user, self.password = user, password
+ for authmethod in authlist:
+ method_name = 'auth_' + authmethod.lower().replace('-', '_')
+ try:
+ (code, resp) = self.auth(
+ authmethod, getattr(self, method_name),
+ initial_response_ok=initial_response_ok)
+ # 235 == 'Authentication successful'
+ # 503 == 'Error: already authenticated'
+ if code in (235, 503):
+ return (code, resp)
+ except SMTPAuthenticationError as e:
+ last_exception = e
+
+ # We could not login successfully. Return result of last attempt.
+ raise last_exception
+
+ def starttls(self, keyfile=None, certfile=None, context=None):
+ """Puts the connection to the SMTP server into TLS mode.
+
+ If there has been no previous EHLO or HELO command this session, this
+ method tries ESMTP EHLO first.
+
+ If the server supports TLS, this will encrypt the rest of the SMTP
+ session. If you provide the keyfile and certfile parameters,
+ the identity of the SMTP server and client can be checked. This,
+ however, depends on whether the socket module really checks the
+ certificates.
+
+ This method may raise the following exceptions:
+
+ SMTPHeloError The server didn't reply properly to
+ the helo greeting.
+ """
+ self.ehlo_or_helo_if_needed()
+ if not self.has_extn("starttls"):
+ raise SMTPNotSupportedError(
+ "STARTTLS extension not supported by server.")
+ (resp, reply) = self.docmd("STARTTLS")
+ if resp == 220:
+ if not _have_ssl:
+ raise RuntimeError("No SSL support included in this Python")
+ if context is not None and keyfile is not None:
+ raise ValueError("context and keyfile arguments are mutually "
+ "exclusive")
+ if context is not None and certfile is not None:
+ raise ValueError("context and certfile arguments are mutually "
+ "exclusive")
+ if keyfile is not None or certfile is not None:
+ import warnings
+ warnings.warn("keyfile and certfile are deprecated, use a "
+ "custom context instead", DeprecationWarning, 2)
+ if context is None:
+ context = ssl._create_stdlib_context(certfile=certfile,
+ keyfile=keyfile)
+ self.sock = context.wrap_socket(self.sock,
+ server_hostname=self._host)
+ self.file = None
+ # RFC 3207:
+ # The client MUST discard any knowledge obtained from
+ # the server, such as the list of SMTP service extensions,
+ # which was not obtained from the TLS negotiation itself.
+ self.helo_resp = None
+ self.ehlo_resp = None
+ self.esmtp_features = {}
+ self.does_esmtp = 0
+ else:
+ # RFC 3207:
+ # 501 Syntax error (no parameters allowed)
+ # 454 TLS not available due to temporary reason
+ raise SMTPResponseException(resp, reply)
+ return (resp, reply)
+
+ def sendmail(self, from_addr, to_addrs, msg, mail_options=(),
+ rcpt_options=()):
+ """This command performs an entire mail transaction.
+
+ The arguments are:
+ - from_addr : The address sending this mail.
+ - to_addrs : A list of addresses to send this mail to. A bare
+ string will be treated as a list with 1 address.
+ - msg : The message to send.
+ - mail_options : List of ESMTP options (such as 8bitmime) for the
+ mail command.
+ - rcpt_options : List of ESMTP options (such as DSN commands) for
+ all the rcpt commands.
+
+ msg may be a string containing characters in the ASCII range, or a byte
+ string. A string is encoded to bytes using the ascii codec, and lone
+ \\r and \\n characters are converted to \\r\\n characters.
+
+ If there has been no previous EHLO or HELO command this session, this
+ method tries ESMTP EHLO first. If the server does ESMTP, message size
+ and each of the specified options will be passed to it. If EHLO
+ fails, HELO will be tried and ESMTP options suppressed.
+
+ This method will return normally if the mail is accepted for at least
+ one recipient. It returns a dictionary, with one entry for each
+ recipient that was refused. Each entry contains a tuple of the SMTP
+ error code and the accompanying error message sent by the server.
+
+ This method may raise the following exceptions:
+
+ SMTPHeloError The server didn't reply properly to
+ the helo greeting.
+ SMTPRecipientsRefused The server rejected ALL recipients
+ (no mail was sent).
+ SMTPSenderRefused The server didn't accept the from_addr.
+ SMTPDataError The server replied with an unexpected
+ error code (other than a refusal of
+ a recipient).
+ SMTPNotSupportedError The mail_options parameter includes 'SMTPUTF8'
+ but the SMTPUTF8 extension is not supported by
+ the server.
+
+ Note: the connection will be open even after an exception is raised.
+
+ Example:
+
+ >>> import smtplib
+ >>> s=smtplib.SMTP("localhost")
+ >>> tolist=["one@one.org","two@two.org","three@three.org","four@four.org"]
+ >>> msg = '''\\
+ ... From: Me@my.org
+ ... Subject: testin'...
+ ...
+ ... This is a test '''
+ >>> s.sendmail("me@my.org",tolist,msg)
+ { "three@three.org" : ( 550 ,"User unknown" ) }
+ >>> s.quit()
+
+ In the above example, the message was accepted for delivery to three
+ of the four addresses, and one was rejected, with the error code
+ 550. If all addresses are accepted, then the method will return an
+ empty dictionary.
+
+ """
+ self.ehlo_or_helo_if_needed()
+ esmtp_opts = []
+ if isinstance(msg, str):
+ msg = _fix_eols(msg).encode('ascii')
+ if self.does_esmtp:
+ if self.has_extn('size'):
+ esmtp_opts.append("size=%d" % len(msg))
+ for option in mail_options:
+ esmtp_opts.append(option)
+ (code, resp) = self.mail(from_addr, esmtp_opts)
+ if code != 250:
+ if code == 421:
+ self.close()
+ else:
+ self._rset()
+ raise SMTPSenderRefused(code, resp, from_addr)
+ senderrs = {}
+ if isinstance(to_addrs, str):
+ to_addrs = [to_addrs]
+ for each in to_addrs:
+ (code, resp) = self.rcpt(each, rcpt_options)
+ if (code != 250) and (code != 251):
+ senderrs[each] = (code, resp)
+ if code == 421:
+ self.close()
+ raise SMTPRecipientsRefused(senderrs)
+ if len(senderrs) == len(to_addrs):
+ # the server refused all our recipients
+ self._rset()
+ raise SMTPRecipientsRefused(senderrs)
+ (code, resp) = self.data(msg)
+ if code != 250:
+ if code == 421:
+ self.close()
+ else:
+ self._rset()
+ raise SMTPDataError(code, resp)
+ #if we got here then somebody got our mail
+ return senderrs
+
+ def send_message(self, msg, from_addr=None, to_addrs=None,
+ mail_options=(), rcpt_options=()):
+ """Converts message to a bytestring and passes it to sendmail.
+
+ The arguments are as for sendmail, except that msg is an
+ email.message.Message object. If from_addr is None or to_addrs is
+ None, these arguments are taken from the headers of the Message as
+ described in RFC 2822 (a ValueError is raised if there is more than
+ one set of 'Resent-' headers). Regardless of the values of from_addr and
+ to_addr, any Bcc field (or Resent-Bcc field, when the Message is a
+ resent) of the Message object won't be transmitted. The Message
+ object is then serialized using email.generator.BytesGenerator and
+ sendmail is called to transmit the message. If the sender or any of
+ the recipient addresses contain non-ASCII and the server advertises the
+ SMTPUTF8 capability, the policy is cloned with utf8 set to True for the
+ serialization, and SMTPUTF8 and BODY=8BITMIME are asserted on the send.
+ If the server does not support SMTPUTF8, an SMTPNotSupported error is
+ raised. Otherwise the generator is called without modifying the
+ policy.
+
+ """
+ # 'Resent-Date' is a mandatory field if the Message is resent (RFC 2822
+ # Section 3.6.6). In such a case, we use the 'Resent-*' fields. However,
+ # if there is more than one 'Resent-' block there's no way to
+ # unambiguously determine which one is the most recent in all cases,
+ # so rather than guess we raise a ValueError in that case.
+ #
+ # TODO implement heuristics to guess the correct Resent-* block with an
+ # option allowing the user to enable the heuristics. (It should be
+ # possible to guess correctly almost all of the time.)
+
+ self.ehlo_or_helo_if_needed()
+ resent = msg.get_all('Resent-Date')
+ if resent is None:
+ header_prefix = ''
+ elif len(resent) == 1:
+ header_prefix = 'Resent-'
+ else:
+ raise ValueError("message has more than one 'Resent-' header block")
+ if from_addr is None:
+ # Prefer the sender field per RFC 2822:3.6.2.
+ from_addr = (msg[header_prefix + 'Sender']
+ if (header_prefix + 'Sender') in msg
+ else msg[header_prefix + 'From'])
+ from_addr = email.utils.getaddresses([from_addr])[0][1]
+ if to_addrs is None:
+ addr_fields = [f for f in (msg[header_prefix + 'To'],
+ msg[header_prefix + 'Bcc'],
+ msg[header_prefix + 'Cc'])
+ if f is not None]
+ to_addrs = [a[1] for a in email.utils.getaddresses(addr_fields)]
+ # Make a local copy so we can delete the bcc headers.
+ msg_copy = copy.copy(msg)
+ del msg_copy['Bcc']
+ del msg_copy['Resent-Bcc']
+ international = False
+ try:
+ ''.join([from_addr, *to_addrs]).encode('ascii')
+ except UnicodeEncodeError:
+ if not self.has_extn('smtputf8'):
+ raise SMTPNotSupportedError(
+ "One or more source or delivery addresses require"
+ " internationalized email support, but the server"
+ " does not advertise the required SMTPUTF8 capability")
+ international = True
+ with io.BytesIO() as bytesmsg:
+ if international:
+ g = email.generator.BytesGenerator(
+ bytesmsg, policy=msg.policy.clone(utf8=True))
+ mail_options = (*mail_options, 'SMTPUTF8', 'BODY=8BITMIME')
+ else:
+ g = email.generator.BytesGenerator(bytesmsg)
+ g.flatten(msg_copy, linesep='\r\n')
+ flatmsg = bytesmsg.getvalue()
+ return self.sendmail(from_addr, to_addrs, flatmsg, mail_options,
+ rcpt_options)
+
+ def close(self):
+ """Close the connection to the SMTP server."""
+ try:
+ file = self.file
+ self.file = None
+ if file:
+ file.close()
+ finally:
+ sock = self.sock
+ self.sock = None
+ if sock:
+ sock.close()
+
+ def quit(self):
+ """Terminate the SMTP session."""
+ res = self.docmd("quit")
+ # A new EHLO is required after reconnecting with connect()
+ self.ehlo_resp = self.helo_resp = None
+ self.esmtp_features = {}
+ self.does_esmtp = False
+ self.close()
+ return res
+
+if _have_ssl:
+
+ class SMTP_SSL(SMTP):
+ """ This is a subclass derived from SMTP that connects over an SSL
+ encrypted socket (to use this class you need a socket module that was
+ compiled with SSL support). If host is not specified, '' (the local
+ host) is used. If port is omitted, the standard SMTP-over-SSL port
+ (465) is used. local_hostname and source_address have the same meaning
+ as they do in the SMTP class. keyfile and certfile are also optional -
+ they can contain a PEM formatted private key and certificate chain file
+ for the SSL connection. context also optional, can contain a
+ SSLContext, and is an alternative to keyfile and certfile; If it is
+ specified both keyfile and certfile must be None.
+
+ """
+
+ default_port = SMTP_SSL_PORT
+
+ def __init__(self, host='', port=0, local_hostname=None,
+ keyfile=None, certfile=None,
+ timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
+ source_address=None, context=None):
+ if context is not None and keyfile is not None:
+ raise ValueError("context and keyfile arguments are mutually "
+ "exclusive")
+ if context is not None and certfile is not None:
+ raise ValueError("context and certfile arguments are mutually "
+ "exclusive")
+ if keyfile is not None or certfile is not None:
+ import warnings
+ warnings.warn("keyfile and certfile are deprecated, use a "
+ "custom context instead", DeprecationWarning, 2)
+ self.keyfile = keyfile
+ self.certfile = certfile
+ if context is None:
+ context = ssl._create_stdlib_context(certfile=certfile,
+ keyfile=keyfile)
+ self.context = context
+ SMTP.__init__(self, host, port, local_hostname, timeout,
+ source_address)
+
+ def _get_socket(self, host, port, timeout):
+ if self.debuglevel > 0:
+ self._print_debug('connect:', (host, port))
+ new_socket = socket.create_connection((host, port), timeout,
+ self.source_address)
+ new_socket = self.context.wrap_socket(new_socket,
+ server_hostname=self._host)
+ return new_socket
+
+ __all__.append("SMTP_SSL")
+
+#
+# LMTP extension
+#
+LMTP_PORT = 2003
+
+class LMTP(SMTP):
+ """LMTP - Local Mail Transfer Protocol
+
+ The LMTP protocol, which is very similar to ESMTP, is heavily based
+ on the standard SMTP client. It's common to use Unix sockets for
+ LMTP, so our connect() method must support that as well as a regular
+ host:port server. local_hostname and source_address have the same
+ meaning as they do in the SMTP class. To specify a Unix socket,
+ you must use an absolute path as the host, starting with a '/'.
+
+ Authentication is supported, using the regular SMTP mechanism. When
+ using a Unix socket, LMTP generally don't support or require any
+ authentication, but your mileage might vary."""
+
+ ehlo_msg = "lhlo"
+
+ def __init__(self, host='', port=LMTP_PORT, local_hostname=None,
+ source_address=None):
+ """Initialize a new instance."""
+ SMTP.__init__(self, host, port, local_hostname=local_hostname,
+ source_address=source_address)
+
+ def connect(self, host='localhost', port=0, source_address=None):
+ """Connect to the LMTP daemon, on either a Unix or a TCP socket."""
+ if host[0] != '/':
+ return SMTP.connect(self, host, port, source_address=source_address)
+
+ # Handle Unix-domain sockets.
+ try:
+ self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ self.file = None
+ self.sock.connect(host)
+ except OSError:
+ if self.debuglevel > 0:
+ self._print_debug('connect fail:', host)
+ if self.sock:
+ self.sock.close()
+ self.sock = None
+ raise
+ (code, msg) = self.getreply()
+ if self.debuglevel > 0:
+ self._print_debug('connect:', msg)
+ return (code, msg)
+
+
+# Test the sendmail method, which tests most of the others.
+# Note: This always sends to localhost.
+if __name__ == '__main__':
+ def prompt(prompt):
+ sys.stdout.write(prompt + ": ")
+ sys.stdout.flush()
+ return sys.stdin.readline().strip()
+
+ fromaddr = prompt("From")
+ toaddrs = prompt("To").split(',')
+ print("Enter message, end with ^D:")
+ msg = ''
+ while 1:
+ line = sys.stdin.readline()
+ if not line:
+ break
+ msg = msg + line
+ print("Message length is %d" % len(msg))
+
+ server = SMTP('localhost')
+ server.set_debuglevel(1)
+ server.sendmail(fromaddr, toaddrs, msg)
+ server.quit()
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/sndhdr.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/sndhdr.py
new file mode 100644
index 0000000000000000000000000000000000000000..96595c6974468213e0a93414af95f4981bb609c5
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/sndhdr.py
@@ -0,0 +1,257 @@
+"""Routines to help recognizing sound files.
+
+Function whathdr() recognizes various types of sound file headers.
+It understands almost all headers that SOX can decode.
+
+The return tuple contains the following items, in this order:
+- file type (as SOX understands it)
+- sampling rate (0 if unknown or hard to decode)
+- number of channels (0 if unknown or hard to decode)
+- number of frames in the file (-1 if unknown or hard to decode)
+- number of bits/sample, or 'U' for U-LAW, or 'A' for A-LAW
+
+If the file doesn't have a recognizable type, it returns None.
+If the file can't be opened, OSError is raised.
+
+To compute the total time, divide the number of frames by the
+sampling rate (a frame contains a sample for each channel).
+
+Function what() calls whathdr(). (It used to also use some
+heuristics for raw data, but this doesn't work very well.)
+
+Finally, the function test() is a simple main program that calls
+what() for all files mentioned on the argument list. For directory
+arguments it calls what() for all files in that directory. Default
+argument is "." (testing all files in the current directory). The
+option -r tells it to recurse down directories found inside
+explicitly given directories.
+"""
+
+# The file structure is top-down except that the test program and its
+# subroutine come last.
+
+__all__ = ['what', 'whathdr']
+
+from collections import namedtuple
+
+SndHeaders = namedtuple('SndHeaders',
+ 'filetype framerate nchannels nframes sampwidth')
+
+SndHeaders.filetype.__doc__ = ("""The value for type indicates the data type
+and will be one of the strings 'aifc', 'aiff', 'au','hcom',
+'sndr', 'sndt', 'voc', 'wav', '8svx', 'sb', 'ub', or 'ul'.""")
+SndHeaders.framerate.__doc__ = ("""The sampling_rate will be either the actual
+value or 0 if unknown or difficult to decode.""")
+SndHeaders.nchannels.__doc__ = ("""The number of channels or 0 if it cannot be
+determined or if the value is difficult to decode.""")
+SndHeaders.nframes.__doc__ = ("""The value for frames will be either the number
+of frames or -1.""")
+SndHeaders.sampwidth.__doc__ = ("""Either the sample size in bits or
+'A' for A-LAW or 'U' for u-LAW.""")
+
+def what(filename):
+ """Guess the type of a sound file."""
+ res = whathdr(filename)
+ return res
+
+
+def whathdr(filename):
+ """Recognize sound headers."""
+ with open(filename, 'rb') as f:
+ h = f.read(512)
+ for tf in tests:
+ res = tf(h, f)
+ if res:
+ return SndHeaders(*res)
+ return None
+
+
+#-----------------------------------#
+# Subroutines per sound header type #
+#-----------------------------------#
+
+tests = []
+
+def test_aifc(h, f):
+ import aifc
+ if not h.startswith(b'FORM'):
+ return None
+ if h[8:12] == b'AIFC':
+ fmt = 'aifc'
+ elif h[8:12] == b'AIFF':
+ fmt = 'aiff'
+ else:
+ return None
+ f.seek(0)
+ try:
+ a = aifc.open(f, 'r')
+ except (EOFError, aifc.Error):
+ return None
+ return (fmt, a.getframerate(), a.getnchannels(),
+ a.getnframes(), 8 * a.getsampwidth())
+
+tests.append(test_aifc)
+
+
+def test_au(h, f):
+ if h.startswith(b'.snd'):
+ func = get_long_be
+ elif h[:4] in (b'\0ds.', b'dns.'):
+ func = get_long_le
+ else:
+ return None
+ filetype = 'au'
+ hdr_size = func(h[4:8])
+ data_size = func(h[8:12])
+ encoding = func(h[12:16])
+ rate = func(h[16:20])
+ nchannels = func(h[20:24])
+ sample_size = 1 # default
+ if encoding == 1:
+ sample_bits = 'U'
+ elif encoding == 2:
+ sample_bits = 8
+ elif encoding == 3:
+ sample_bits = 16
+ sample_size = 2
+ else:
+ sample_bits = '?'
+ frame_size = sample_size * nchannels
+ if frame_size:
+ nframe = data_size / frame_size
+ else:
+ nframe = -1
+ return filetype, rate, nchannels, nframe, sample_bits
+
+tests.append(test_au)
+
+
+def test_hcom(h, f):
+ if h[65:69] != b'FSSD' or h[128:132] != b'HCOM':
+ return None
+ divisor = get_long_be(h[144:148])
+ if divisor:
+ rate = 22050 / divisor
+ else:
+ rate = 0
+ return 'hcom', rate, 1, -1, 8
+
+tests.append(test_hcom)
+
+
+def test_voc(h, f):
+ if not h.startswith(b'Creative Voice File\032'):
+ return None
+ sbseek = get_short_le(h[20:22])
+ rate = 0
+ if 0 <= sbseek < 500 and h[sbseek] == 1:
+ ratecode = 256 - h[sbseek+4]
+ if ratecode:
+ rate = int(1000000.0 / ratecode)
+ return 'voc', rate, 1, -1, 8
+
+tests.append(test_voc)
+
+
+def test_wav(h, f):
+ import wave
+ # 'RIFF' 'WAVE' 'fmt '
+ if not h.startswith(b'RIFF') or h[8:12] != b'WAVE' or h[12:16] != b'fmt ':
+ return None
+ f.seek(0)
+ try:
+ w = wave.open(f, 'r')
+ except (EOFError, wave.Error):
+ return None
+ return ('wav', w.getframerate(), w.getnchannels(),
+ w.getnframes(), 8*w.getsampwidth())
+
+tests.append(test_wav)
+
+
+def test_8svx(h, f):
+ if not h.startswith(b'FORM') or h[8:12] != b'8SVX':
+ return None
+ # Should decode it to get #channels -- assume always 1
+ return '8svx', 0, 1, 0, 8
+
+tests.append(test_8svx)
+
+
+def test_sndt(h, f):
+ if h.startswith(b'SOUND'):
+ nsamples = get_long_le(h[8:12])
+ rate = get_short_le(h[20:22])
+ return 'sndt', rate, 1, nsamples, 8
+
+tests.append(test_sndt)
+
+
+def test_sndr(h, f):
+ if h.startswith(b'\0\0'):
+ rate = get_short_le(h[2:4])
+ if 4000 <= rate <= 25000:
+ return 'sndr', rate, 1, -1, 8
+
+tests.append(test_sndr)
+
+
+#-------------------------------------------#
+# Subroutines to extract numbers from bytes #
+#-------------------------------------------#
+
+def get_long_be(b):
+ return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]
+
+def get_long_le(b):
+ return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0]
+
+def get_short_be(b):
+ return (b[0] << 8) | b[1]
+
+def get_short_le(b):
+ return (b[1] << 8) | b[0]
+
+
+#--------------------#
+# Small test program #
+#--------------------#
+
+def test():
+ import sys
+ recursive = 0
+ if sys.argv[1:] and sys.argv[1] == '-r':
+ del sys.argv[1:2]
+ recursive = 1
+ try:
+ if sys.argv[1:]:
+ testall(sys.argv[1:], recursive, 1)
+ else:
+ testall(['.'], recursive, 1)
+ except KeyboardInterrupt:
+ sys.stderr.write('\n[Interrupted]\n')
+ sys.exit(1)
+
+def testall(list, recursive, toplevel):
+ import sys
+ import os
+ for filename in list:
+ if os.path.isdir(filename):
+ print(filename + '/:', end=' ')
+ if recursive or toplevel:
+ print('recursing down:')
+ import glob
+ names = glob.glob(os.path.join(glob.escape(filename), '*'))
+ testall(names, recursive, 0)
+ else:
+ print('*** directory (use -r) ***')
+ else:
+ print(filename + ':', end=' ')
+ sys.stdout.flush()
+ try:
+ print(what(filename))
+ except OSError:
+ print('*** not found ***')
+
+if __name__ == '__main__':
+ test()
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/socketserver.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/socketserver.py
new file mode 100644
index 0000000000000000000000000000000000000000..9e94c76731e812626e2e66d43adeee6726d754c8
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/socketserver.py
@@ -0,0 +1,844 @@
+"""Generic socket server classes.
+
+This module tries to capture the various aspects of defining a server:
+
+For socket-based servers:
+
+- address family:
+ - AF_INET{,6}: IP (Internet Protocol) sockets (default)
+ - AF_UNIX: Unix domain sockets
+ - others, e.g. AF_DECNET are conceivable (see
+- socket type:
+ - SOCK_STREAM (reliable stream, e.g. TCP)
+ - SOCK_DGRAM (datagrams, e.g. UDP)
+
+For request-based servers (including socket-based):
+
+- client address verification before further looking at the request
+ (This is actually a hook for any processing that needs to look
+ at the request before anything else, e.g. logging)
+- how to handle multiple requests:
+ - synchronous (one request is handled at a time)
+ - forking (each request is handled by a new process)
+ - threading (each request is handled by a new thread)
+
+The classes in this module favor the server type that is simplest to
+write: a synchronous TCP/IP server. This is bad class design, but
+saves some typing. (There's also the issue that a deep class hierarchy
+slows down method lookups.)
+
+There are five classes in an inheritance diagram, four of which represent
+synchronous servers of four types:
+
+ +------------+
+ | BaseServer |
+ +------------+
+ |
+ v
+ +-----------+ +------------------+
+ | TCPServer |------->| UnixStreamServer |
+ +-----------+ +------------------+
+ |
+ v
+ +-----------+ +--------------------+
+ | UDPServer |------->| UnixDatagramServer |
+ +-----------+ +--------------------+
+
+Note that UnixDatagramServer derives from UDPServer, not from
+UnixStreamServer -- the only difference between an IP and a Unix
+stream server is the address family, which is simply repeated in both
+unix server classes.
+
+Forking and threading versions of each type of server can be created
+using the ForkingMixIn and ThreadingMixIn mix-in classes. For
+instance, a threading UDP server class is created as follows:
+
+ class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
+
+The Mix-in class must come first, since it overrides a method defined
+in UDPServer! Setting the various member variables also changes
+the behavior of the underlying server mechanism.
+
+To implement a service, you must derive a class from
+BaseRequestHandler and redefine its handle() method. You can then run
+various versions of the service by combining one of the server classes
+with your request handler class.
+
+The request handler class must be different for datagram or stream
+services. This can be hidden by using the request handler
+subclasses StreamRequestHandler or DatagramRequestHandler.
+
+Of course, you still have to use your head!
+
+For instance, it makes no sense to use a forking server if the service
+contains state in memory that can be modified by requests (since the
+modifications in the child process would never reach the initial state
+kept in the parent process and passed to each child). In this case,
+you can use a threading server, but you will probably have to use
+locks to avoid two requests that come in nearly simultaneous to apply
+conflicting changes to the server state.
+
+On the other hand, if you are building e.g. an HTTP server, where all
+data is stored externally (e.g. in the file system), a synchronous
+class will essentially render the service "deaf" while one request is
+being handled -- which may be for a very long time if a client is slow
+to read all the data it has requested. Here a threading or forking
+server is appropriate.
+
+In some cases, it may be appropriate to process part of a request
+synchronously, but to finish processing in a forked child depending on
+the request data. This can be implemented by using a synchronous
+server and doing an explicit fork in the request handler class
+handle() method.
+
+Another approach to handling multiple simultaneous requests in an
+environment that supports neither threads nor fork (or where these are
+too expensive or inappropriate for the service) is to maintain an
+explicit table of partially finished requests and to use a selector to
+decide which request to work on next (or whether to handle a new
+incoming request). This is particularly important for stream services
+where each client can potentially be connected for a long time (if
+threads or subprocesses cannot be used).
+
+Future work:
+- Standard classes for Sun RPC (which uses either UDP or TCP)
+- Standard mix-in classes to implement various authentication
+ and encryption schemes
+
+XXX Open problems:
+- What to do with out-of-band data?
+
+BaseServer:
+- split generic "request" functionality out into BaseServer class.
+ Copyright (C) 2000 Luke Kenneth Casson Leighton
+
+ example: read entries from a SQL database (requires overriding
+ get_request() to return a table entry from the database).
+ entry is processed by a RequestHandlerClass.
+
+"""
+
+# Author of the BaseServer patch: Luke Kenneth Casson Leighton
+
+__version__ = "0.4"
+
+
+import socket
+import selectors
+import os
+import sys
+import threading
+from io import BufferedIOBase
+from time import monotonic as time
+
+__all__ = ["BaseServer", "TCPServer", "UDPServer",
+ "ThreadingUDPServer", "ThreadingTCPServer",
+ "BaseRequestHandler", "StreamRequestHandler",
+ "DatagramRequestHandler", "ThreadingMixIn"]
+if hasattr(os, "fork"):
+ __all__.extend(["ForkingUDPServer","ForkingTCPServer", "ForkingMixIn"])
+if hasattr(socket, "AF_UNIX"):
+ __all__.extend(["UnixStreamServer","UnixDatagramServer",
+ "ThreadingUnixStreamServer",
+ "ThreadingUnixDatagramServer"])
+
+# poll/select have the advantage of not requiring any extra file descriptor,
+# contrarily to epoll/kqueue (also, they require a single syscall).
+if hasattr(selectors, 'PollSelector'):
+ _ServerSelector = selectors.PollSelector
+else:
+ _ServerSelector = selectors.SelectSelector
+
+
+class BaseServer:
+
+ """Base class for server classes.
+
+ Methods for the caller:
+
+ - __init__(server_address, RequestHandlerClass)
+ - serve_forever(poll_interval=0.5)
+ - shutdown()
+ - handle_request() # if you do not use serve_forever()
+ - fileno() -> int # for selector
+
+ Methods that may be overridden:
+
+ - server_bind()
+ - server_activate()
+ - get_request() -> request, client_address
+ - handle_timeout()
+ - verify_request(request, client_address)
+ - server_close()
+ - process_request(request, client_address)
+ - shutdown_request(request)
+ - close_request(request)
+ - service_actions()
+ - handle_error()
+
+ Methods for derived classes:
+
+ - finish_request(request, client_address)
+
+ Class variables that may be overridden by derived classes or
+ instances:
+
+ - timeout
+ - address_family
+ - socket_type
+ - allow_reuse_address
+
+ Instance variables:
+
+ - RequestHandlerClass
+ - socket
+
+ """
+
+ timeout = None
+
+ def __init__(self, server_address, RequestHandlerClass):
+ """Constructor. May be extended, do not override."""
+ self.server_address = server_address
+ self.RequestHandlerClass = RequestHandlerClass
+ self.__is_shut_down = threading.Event()
+ self.__shutdown_request = False
+
+ def server_activate(self):
+ """Called by constructor to activate the server.
+
+ May be overridden.
+
+ """
+ pass
+
+ def serve_forever(self, poll_interval=0.5):
+ """Handle one request at a time until shutdown.
+
+ Polls for shutdown every poll_interval seconds. Ignores
+ self.timeout. If you need to do periodic tasks, do them in
+ another thread.
+ """
+ self.__is_shut_down.clear()
+ try:
+ # XXX: Consider using another file descriptor or connecting to the
+ # socket to wake this up instead of polling. Polling reduces our
+ # responsiveness to a shutdown request and wastes cpu at all other
+ # times.
+ with _ServerSelector() as selector:
+ selector.register(self, selectors.EVENT_READ)
+
+ while not self.__shutdown_request:
+ ready = selector.select(poll_interval)
+ # bpo-35017: shutdown() called during select(), exit immediately.
+ if self.__shutdown_request:
+ break
+ if ready:
+ self._handle_request_noblock()
+
+ self.service_actions()
+ finally:
+ self.__shutdown_request = False
+ self.__is_shut_down.set()
+
+ def shutdown(self):
+ """Stops the serve_forever loop.
+
+ Blocks until the loop has finished. This must be called while
+ serve_forever() is running in another thread, or it will
+ deadlock.
+ """
+ self.__shutdown_request = True
+ self.__is_shut_down.wait()
+
+ def service_actions(self):
+ """Called by the serve_forever() loop.
+
+ May be overridden by a subclass / Mixin to implement any code that
+ needs to be run during the loop.
+ """
+ pass
+
+ # The distinction between handling, getting, processing and finishing a
+ # request is fairly arbitrary. Remember:
+ #
+ # - handle_request() is the top-level call. It calls selector.select(),
+ # get_request(), verify_request() and process_request()
+ # - get_request() is different for stream or datagram sockets
+ # - process_request() is the place that may fork a new process or create a
+ # new thread to finish the request
+ # - finish_request() instantiates the request handler class; this
+ # constructor will handle the request all by itself
+
+ def handle_request(self):
+ """Handle one request, possibly blocking.
+
+ Respects self.timeout.
+ """
+ # Support people who used socket.settimeout() to escape
+ # handle_request before self.timeout was available.
+ timeout = self.socket.gettimeout()
+ if timeout is None:
+ timeout = self.timeout
+ elif self.timeout is not None:
+ timeout = min(timeout, self.timeout)
+ if timeout is not None:
+ deadline = time() + timeout
+
+ # Wait until a request arrives or the timeout expires - the loop is
+ # necessary to accommodate early wakeups due to EINTR.
+ with _ServerSelector() as selector:
+ selector.register(self, selectors.EVENT_READ)
+
+ while True:
+ ready = selector.select(timeout)
+ if ready:
+ return self._handle_request_noblock()
+ else:
+ if timeout is not None:
+ timeout = deadline - time()
+ if timeout < 0:
+ return self.handle_timeout()
+
+ def _handle_request_noblock(self):
+ """Handle one request, without blocking.
+
+ I assume that selector.select() has returned that the socket is
+ readable before this function was called, so there should be no risk of
+ blocking in get_request().
+ """
+ try:
+ request, client_address = self.get_request()
+ except OSError:
+ return
+ if self.verify_request(request, client_address):
+ try:
+ self.process_request(request, client_address)
+ except Exception:
+ self.handle_error(request, client_address)
+ self.shutdown_request(request)
+ except:
+ self.shutdown_request(request)
+ raise
+ else:
+ self.shutdown_request(request)
+
+ def handle_timeout(self):
+ """Called if no new request arrives within self.timeout.
+
+ Overridden by ForkingMixIn.
+ """
+ pass
+
+ def verify_request(self, request, client_address):
+ """Verify the request. May be overridden.
+
+ Return True if we should proceed with this request.
+
+ """
+ return True
+
+ def process_request(self, request, client_address):
+ """Call finish_request.
+
+ Overridden by ForkingMixIn and ThreadingMixIn.
+
+ """
+ self.finish_request(request, client_address)
+ self.shutdown_request(request)
+
+ def server_close(self):
+ """Called to clean-up the server.
+
+ May be overridden.
+
+ """
+ pass
+
+ def finish_request(self, request, client_address):
+ """Finish one request by instantiating RequestHandlerClass."""
+ self.RequestHandlerClass(request, client_address, self)
+
+ def shutdown_request(self, request):
+ """Called to shutdown and close an individual request."""
+ self.close_request(request)
+
+ def close_request(self, request):
+ """Called to clean up an individual request."""
+ pass
+
+ def handle_error(self, request, client_address):
+ """Handle an error gracefully. May be overridden.
+
+ The default is to print a traceback and continue.
+
+ """
+ print('-'*40, file=sys.stderr)
+ print('Exception happened during processing of request from',
+ client_address, file=sys.stderr)
+ import traceback
+ traceback.print_exc()
+ print('-'*40, file=sys.stderr)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args):
+ self.server_close()
+
+
+class TCPServer(BaseServer):
+
+ """Base class for various socket-based server classes.
+
+ Defaults to synchronous IP stream (i.e., TCP).
+
+ Methods for the caller:
+
+ - __init__(server_address, RequestHandlerClass, bind_and_activate=True)
+ - serve_forever(poll_interval=0.5)
+ - shutdown()
+ - handle_request() # if you don't use serve_forever()
+ - fileno() -> int # for selector
+
+ Methods that may be overridden:
+
+ - server_bind()
+ - server_activate()
+ - get_request() -> request, client_address
+ - handle_timeout()
+ - verify_request(request, client_address)
+ - process_request(request, client_address)
+ - shutdown_request(request)
+ - close_request(request)
+ - handle_error()
+
+ Methods for derived classes:
+
+ - finish_request(request, client_address)
+
+ Class variables that may be overridden by derived classes or
+ instances:
+
+ - timeout
+ - address_family
+ - socket_type
+ - request_queue_size (only for stream sockets)
+ - allow_reuse_address
+
+ Instance variables:
+
+ - server_address
+ - RequestHandlerClass
+ - socket
+
+ """
+
+ address_family = socket.AF_INET
+
+ socket_type = socket.SOCK_STREAM
+
+ request_queue_size = 5
+
+ allow_reuse_address = False
+
+ def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
+ """Constructor. May be extended, do not override."""
+ BaseServer.__init__(self, server_address, RequestHandlerClass)
+ self.socket = socket.socket(self.address_family,
+ self.socket_type)
+ if bind_and_activate:
+ try:
+ self.server_bind()
+ self.server_activate()
+ except:
+ self.server_close()
+ raise
+
+ def server_bind(self):
+ """Called by constructor to bind the socket.
+
+ May be overridden.
+
+ """
+ if self.allow_reuse_address:
+ self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ self.socket.bind(self.server_address)
+ self.server_address = self.socket.getsockname()
+
+ def server_activate(self):
+ """Called by constructor to activate the server.
+
+ May be overridden.
+
+ """
+ self.socket.listen(self.request_queue_size)
+
+ def server_close(self):
+ """Called to clean-up the server.
+
+ May be overridden.
+
+ """
+ self.socket.close()
+
+ def fileno(self):
+ """Return socket file number.
+
+ Interface required by selector.
+
+ """
+ return self.socket.fileno()
+
+ def get_request(self):
+ """Get the request and client address from the socket.
+
+ May be overridden.
+
+ """
+ return self.socket.accept()
+
+ def shutdown_request(self, request):
+ """Called to shutdown and close an individual request."""
+ try:
+ #explicitly shutdown. socket.close() merely releases
+ #the socket and waits for GC to perform the actual close.
+ request.shutdown(socket.SHUT_WR)
+ except OSError:
+ pass #some platforms may raise ENOTCONN here
+ self.close_request(request)
+
+ def close_request(self, request):
+ """Called to clean up an individual request."""
+ request.close()
+
+
+class UDPServer(TCPServer):
+
+ """UDP server class."""
+
+ allow_reuse_address = False
+
+ socket_type = socket.SOCK_DGRAM
+
+ max_packet_size = 8192
+
+ def get_request(self):
+ data, client_addr = self.socket.recvfrom(self.max_packet_size)
+ return (data, self.socket), client_addr
+
+ def server_activate(self):
+ # No need to call listen() for UDP.
+ pass
+
+ def shutdown_request(self, request):
+ # No need to shutdown anything.
+ self.close_request(request)
+
+ def close_request(self, request):
+ # No need to close anything.
+ pass
+
+if hasattr(os, "fork"):
+ class ForkingMixIn:
+ """Mix-in class to handle each request in a new process."""
+
+ timeout = 300
+ active_children = None
+ max_children = 40
+ # If true, server_close() waits until all child processes complete.
+ block_on_close = True
+
+ def collect_children(self, *, blocking=False):
+ """Internal routine to wait for children that have exited."""
+ if self.active_children is None:
+ return
+
+ # If we're above the max number of children, wait and reap them until
+ # we go back below threshold. Note that we use waitpid(-1) below to be
+ # able to collect children in size() syscalls instead
+ # of size(): the downside is that this might reap children
+ # which we didn't spawn, which is why we only resort to this when we're
+ # above max_children.
+ while len(self.active_children) >= self.max_children:
+ try:
+ pid, _ = os.waitpid(-1, 0)
+ self.active_children.discard(pid)
+ except ChildProcessError:
+ # we don't have any children, we're done
+ self.active_children.clear()
+ except OSError:
+ break
+
+ # Now reap all defunct children.
+ for pid in self.active_children.copy():
+ try:
+ flags = 0 if blocking else os.WNOHANG
+ pid, _ = os.waitpid(pid, flags)
+ # if the child hasn't exited yet, pid will be 0 and ignored by
+ # discard() below
+ self.active_children.discard(pid)
+ except ChildProcessError:
+ # someone else reaped it
+ self.active_children.discard(pid)
+ except OSError:
+ pass
+
+ def handle_timeout(self):
+ """Wait for zombies after self.timeout seconds of inactivity.
+
+ May be extended, do not override.
+ """
+ self.collect_children()
+
+ def service_actions(self):
+ """Collect the zombie child processes regularly in the ForkingMixIn.
+
+ service_actions is called in the BaseServer's serve_forever loop.
+ """
+ self.collect_children()
+
+ def process_request(self, request, client_address):
+ """Fork a new subprocess to process the request."""
+ pid = os.fork()
+ if pid:
+ # Parent process
+ if self.active_children is None:
+ self.active_children = set()
+ self.active_children.add(pid)
+ self.close_request(request)
+ return
+ else:
+ # Child process.
+ # This must never return, hence os._exit()!
+ status = 1
+ try:
+ self.finish_request(request, client_address)
+ status = 0
+ except Exception:
+ self.handle_error(request, client_address)
+ finally:
+ try:
+ self.shutdown_request(request)
+ finally:
+ os._exit(status)
+
+ def server_close(self):
+ super().server_close()
+ self.collect_children(blocking=self.block_on_close)
+
+
+class _Threads(list):
+ """
+ Joinable list of all non-daemon threads.
+ """
+ def append(self, thread):
+ self.reap()
+ if thread.daemon:
+ return
+ super().append(thread)
+
+ def pop_all(self):
+ self[:], result = [], self[:]
+ return result
+
+ def join(self):
+ for thread in self.pop_all():
+ thread.join()
+
+ def reap(self):
+ self[:] = (thread for thread in self if thread.is_alive())
+
+
+class _NoThreads:
+ """
+ Degenerate version of _Threads.
+ """
+ def append(self, thread):
+ pass
+
+ def join(self):
+ pass
+
+
+class ThreadingMixIn:
+ """Mix-in class to handle each request in a new thread."""
+
+ # Decides how threads will act upon termination of the
+ # main process
+ daemon_threads = False
+ # If true, server_close() waits until all non-daemonic threads terminate.
+ block_on_close = True
+ # Threads object
+ # used by server_close() to wait for all threads completion.
+ _threads = _NoThreads()
+
+ def process_request_thread(self, request, client_address):
+ """Same as in BaseServer but as a thread.
+
+ In addition, exception handling is done here.
+
+ """
+ try:
+ self.finish_request(request, client_address)
+ except Exception:
+ self.handle_error(request, client_address)
+ finally:
+ self.shutdown_request(request)
+
+ def process_request(self, request, client_address):
+ """Start a new thread to process the request."""
+ if self.block_on_close:
+ vars(self).setdefault('_threads', _Threads())
+ t = threading.Thread(target = self.process_request_thread,
+ args = (request, client_address))
+ t.daemon = self.daemon_threads
+ self._threads.append(t)
+ t.start()
+
+ def server_close(self):
+ super().server_close()
+ self._threads.join()
+
+
+if hasattr(os, "fork"):
+ class ForkingUDPServer(ForkingMixIn, UDPServer): pass
+ class ForkingTCPServer(ForkingMixIn, TCPServer): pass
+
+class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
+class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
+
+if hasattr(socket, 'AF_UNIX'):
+
+ class UnixStreamServer(TCPServer):
+ address_family = socket.AF_UNIX
+
+ class UnixDatagramServer(UDPServer):
+ address_family = socket.AF_UNIX
+
+ class ThreadingUnixStreamServer(ThreadingMixIn, UnixStreamServer): pass
+
+ class ThreadingUnixDatagramServer(ThreadingMixIn, UnixDatagramServer): pass
+
+class BaseRequestHandler:
+
+ """Base class for request handler classes.
+
+ This class is instantiated for each request to be handled. The
+ constructor sets the instance variables request, client_address
+ and server, and then calls the handle() method. To implement a
+ specific service, all you need to do is to derive a class which
+ defines a handle() method.
+
+ The handle() method can find the request as self.request, the
+ client address as self.client_address, and the server (in case it
+ needs access to per-server information) as self.server. Since a
+ separate instance is created for each request, the handle() method
+ can define other arbitrary instance variables.
+
+ """
+
+ def __init__(self, request, client_address, server):
+ self.request = request
+ self.client_address = client_address
+ self.server = server
+ self.setup()
+ try:
+ self.handle()
+ finally:
+ self.finish()
+
+ def setup(self):
+ pass
+
+ def handle(self):
+ pass
+
+ def finish(self):
+ pass
+
+
+# The following two classes make it possible to use the same service
+# class for stream or datagram servers.
+# Each class sets up these instance variables:
+# - rfile: a file object from which receives the request is read
+# - wfile: a file object to which the reply is written
+# When the handle() method returns, wfile is flushed properly
+
+
+class StreamRequestHandler(BaseRequestHandler):
+
+ """Define self.rfile and self.wfile for stream sockets."""
+
+ # Default buffer sizes for rfile, wfile.
+ # We default rfile to buffered because otherwise it could be
+ # really slow for large data (a getc() call per byte); we make
+ # wfile unbuffered because (a) often after a write() we want to
+ # read and we need to flush the line; (b) big writes to unbuffered
+ # files are typically optimized by stdio even when big reads
+ # aren't.
+ rbufsize = -1
+ wbufsize = 0
+
+ # A timeout to apply to the request socket, if not None.
+ timeout = None
+
+ # Disable nagle algorithm for this socket, if True.
+ # Use only when wbufsize != 0, to avoid small packets.
+ disable_nagle_algorithm = False
+
+ def setup(self):
+ self.connection = self.request
+ if self.timeout is not None:
+ self.connection.settimeout(self.timeout)
+ if self.disable_nagle_algorithm:
+ self.connection.setsockopt(socket.IPPROTO_TCP,
+ socket.TCP_NODELAY, True)
+ self.rfile = self.connection.makefile('rb', self.rbufsize)
+ if self.wbufsize == 0:
+ self.wfile = _SocketWriter(self.connection)
+ else:
+ self.wfile = self.connection.makefile('wb', self.wbufsize)
+
+ def finish(self):
+ if not self.wfile.closed:
+ try:
+ self.wfile.flush()
+ except socket.error:
+ # A final socket error may have occurred here, such as
+ # the local error ECONNABORTED.
+ pass
+ self.wfile.close()
+ self.rfile.close()
+
+class _SocketWriter(BufferedIOBase):
+ """Simple writable BufferedIOBase implementation for a socket
+
+ Does not hold data in a buffer, avoiding any need to call flush()."""
+
+ def __init__(self, sock):
+ self._sock = sock
+
+ def writable(self):
+ return True
+
+ def write(self, b):
+ self._sock.sendall(b)
+ with memoryview(b) as view:
+ return view.nbytes
+
+ def fileno(self):
+ return self._sock.fileno()
+
+class DatagramRequestHandler(BaseRequestHandler):
+
+ """Define self.rfile and self.wfile for datagram sockets."""
+
+ def setup(self):
+ from io import BytesIO
+ self.packet, self.socket = self.request
+ self.rfile = BytesIO(self.packet)
+ self.wfile = BytesIO()
+
+ def finish(self):
+ self.socket.sendto(self.wfile.getvalue(), self.client_address)
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/stat.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/stat.py
new file mode 100644
index 0000000000000000000000000000000000000000..fc024db3f4fbeeb903272363ee2bad19de0e635b
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/stat.py
@@ -0,0 +1,195 @@
+"""Constants/functions for interpreting results of os.stat() and os.lstat().
+
+Suggested usage: from stat import *
+"""
+
+# Indices for stat struct members in the tuple returned by os.stat()
+
+ST_MODE = 0
+ST_INO = 1
+ST_DEV = 2
+ST_NLINK = 3
+ST_UID = 4
+ST_GID = 5
+ST_SIZE = 6
+ST_ATIME = 7
+ST_MTIME = 8
+ST_CTIME = 9
+
+# Extract bits from the mode
+
+def S_IMODE(mode):
+ """Return the portion of the file's mode that can be set by
+ os.chmod().
+ """
+ return mode & 0o7777
+
+def S_IFMT(mode):
+ """Return the portion of the file's mode that describes the
+ file type.
+ """
+ return mode & 0o170000
+
+# Constants used as S_IFMT() for various file types
+# (not all are implemented on all systems)
+
+S_IFDIR = 0o040000 # directory
+S_IFCHR = 0o020000 # character device
+S_IFBLK = 0o060000 # block device
+S_IFREG = 0o100000 # regular file
+S_IFIFO = 0o010000 # fifo (named pipe)
+S_IFLNK = 0o120000 # symbolic link
+S_IFSOCK = 0o140000 # socket file
+# Fallbacks for uncommon platform-specific constants
+S_IFDOOR = 0
+S_IFPORT = 0
+S_IFWHT = 0
+
+# Functions to test for each file type
+
+def S_ISDIR(mode):
+ """Return True if mode is from a directory."""
+ return S_IFMT(mode) == S_IFDIR
+
+def S_ISCHR(mode):
+ """Return True if mode is from a character special device file."""
+ return S_IFMT(mode) == S_IFCHR
+
+def S_ISBLK(mode):
+ """Return True if mode is from a block special device file."""
+ return S_IFMT(mode) == S_IFBLK
+
+def S_ISREG(mode):
+ """Return True if mode is from a regular file."""
+ return S_IFMT(mode) == S_IFREG
+
+def S_ISFIFO(mode):
+ """Return True if mode is from a FIFO (named pipe)."""
+ return S_IFMT(mode) == S_IFIFO
+
+def S_ISLNK(mode):
+ """Return True if mode is from a symbolic link."""
+ return S_IFMT(mode) == S_IFLNK
+
+def S_ISSOCK(mode):
+ """Return True if mode is from a socket."""
+ return S_IFMT(mode) == S_IFSOCK
+
+def S_ISDOOR(mode):
+ """Return True if mode is from a door."""
+ return False
+
+def S_ISPORT(mode):
+ """Return True if mode is from an event port."""
+ return False
+
+def S_ISWHT(mode):
+ """Return True if mode is from a whiteout."""
+ return False
+
+# Names for permission bits
+
+S_ISUID = 0o4000 # set UID bit
+S_ISGID = 0o2000 # set GID bit
+S_ENFMT = S_ISGID # file locking enforcement
+S_ISVTX = 0o1000 # sticky bit
+S_IREAD = 0o0400 # Unix V7 synonym for S_IRUSR
+S_IWRITE = 0o0200 # Unix V7 synonym for S_IWUSR
+S_IEXEC = 0o0100 # Unix V7 synonym for S_IXUSR
+S_IRWXU = 0o0700 # mask for owner permissions
+S_IRUSR = 0o0400 # read by owner
+S_IWUSR = 0o0200 # write by owner
+S_IXUSR = 0o0100 # execute by owner
+S_IRWXG = 0o0070 # mask for group permissions
+S_IRGRP = 0o0040 # read by group
+S_IWGRP = 0o0020 # write by group
+S_IXGRP = 0o0010 # execute by group
+S_IRWXO = 0o0007 # mask for others (not in group) permissions
+S_IROTH = 0o0004 # read by others
+S_IWOTH = 0o0002 # write by others
+S_IXOTH = 0o0001 # execute by others
+
+# Names for file flags
+
+UF_NODUMP = 0x00000001 # do not dump file
+UF_IMMUTABLE = 0x00000002 # file may not be changed
+UF_APPEND = 0x00000004 # file may only be appended to
+UF_OPAQUE = 0x00000008 # directory is opaque when viewed through a union stack
+UF_NOUNLINK = 0x00000010 # file may not be renamed or deleted
+UF_COMPRESSED = 0x00000020 # OS X: file is hfs-compressed
+UF_HIDDEN = 0x00008000 # OS X: file should not be displayed
+SF_ARCHIVED = 0x00010000 # file may be archived
+SF_IMMUTABLE = 0x00020000 # file may not be changed
+SF_APPEND = 0x00040000 # file may only be appended to
+SF_NOUNLINK = 0x00100000 # file may not be renamed or deleted
+SF_SNAPSHOT = 0x00200000 # file is a snapshot file
+
+
+_filemode_table = (
+ ((S_IFLNK, "l"),
+ (S_IFSOCK, "s"), # Must appear before IFREG and IFDIR as IFSOCK == IFREG | IFDIR
+ (S_IFREG, "-"),
+ (S_IFBLK, "b"),
+ (S_IFDIR, "d"),
+ (S_IFCHR, "c"),
+ (S_IFIFO, "p")),
+
+ ((S_IRUSR, "r"),),
+ ((S_IWUSR, "w"),),
+ ((S_IXUSR|S_ISUID, "s"),
+ (S_ISUID, "S"),
+ (S_IXUSR, "x")),
+
+ ((S_IRGRP, "r"),),
+ ((S_IWGRP, "w"),),
+ ((S_IXGRP|S_ISGID, "s"),
+ (S_ISGID, "S"),
+ (S_IXGRP, "x")),
+
+ ((S_IROTH, "r"),),
+ ((S_IWOTH, "w"),),
+ ((S_IXOTH|S_ISVTX, "t"),
+ (S_ISVTX, "T"),
+ (S_IXOTH, "x"))
+)
+
+def filemode(mode):
+ """Convert a file's mode to a string of the form '-rwxrwxrwx'."""
+ perm = []
+ for table in _filemode_table:
+ for bit, char in table:
+ if mode & bit == bit:
+ perm.append(char)
+ break
+ else:
+ perm.append("-")
+ return "".join(perm)
+
+
+# Windows FILE_ATTRIBUTE constants for interpreting os.stat()'s
+# "st_file_attributes" member
+
+FILE_ATTRIBUTE_ARCHIVE = 32
+FILE_ATTRIBUTE_COMPRESSED = 2048
+FILE_ATTRIBUTE_DEVICE = 64
+FILE_ATTRIBUTE_DIRECTORY = 16
+FILE_ATTRIBUTE_ENCRYPTED = 16384
+FILE_ATTRIBUTE_HIDDEN = 2
+FILE_ATTRIBUTE_INTEGRITY_STREAM = 32768
+FILE_ATTRIBUTE_NORMAL = 128
+FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 8192
+FILE_ATTRIBUTE_NO_SCRUB_DATA = 131072
+FILE_ATTRIBUTE_OFFLINE = 4096
+FILE_ATTRIBUTE_READONLY = 1
+FILE_ATTRIBUTE_REPARSE_POINT = 1024
+FILE_ATTRIBUTE_SPARSE_FILE = 512
+FILE_ATTRIBUTE_SYSTEM = 4
+FILE_ATTRIBUTE_TEMPORARY = 256
+FILE_ATTRIBUTE_VIRTUAL = 65536
+
+
+# If available, use C implementation
+try:
+ from _stat import *
+except ImportError:
+ pass
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/string.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/string.py
new file mode 100644
index 0000000000000000000000000000000000000000..b423ff5dc6f69f022fa153d2c1459639f7ae250a
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/string.py
@@ -0,0 +1,282 @@
+"""A collection of string constants.
+
+Public module variables:
+
+whitespace -- a string containing all ASCII whitespace
+ascii_lowercase -- a string containing all ASCII lowercase letters
+ascii_uppercase -- a string containing all ASCII uppercase letters
+ascii_letters -- a string containing all ASCII letters
+digits -- a string containing all ASCII decimal digits
+hexdigits -- a string containing all ASCII hexadecimal digits
+octdigits -- a string containing all ASCII octal digits
+punctuation -- a string containing all ASCII punctuation characters
+printable -- a string containing all ASCII characters considered printable
+
+"""
+
+__all__ = ["ascii_letters", "ascii_lowercase", "ascii_uppercase", "capwords",
+ "digits", "hexdigits", "octdigits", "printable", "punctuation",
+ "whitespace", "Formatter", "Template"]
+
+import _string
+
+# Some strings for ctype-style character classification
+whitespace = ' \t\n\r\v\f'
+ascii_lowercase = 'abcdefghijklmnopqrstuvwxyz'
+ascii_uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ascii_letters = ascii_lowercase + ascii_uppercase
+digits = '0123456789'
+hexdigits = digits + 'abcdef' + 'ABCDEF'
+octdigits = '01234567'
+punctuation = r"""!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~"""
+printable = digits + ascii_letters + punctuation + whitespace
+
+# Functions which aren't available as string methods.
+
+# Capitalize the words in a string, e.g. " aBc dEf " -> "Abc Def".
+def capwords(s, sep=None):
+ """capwords(s [,sep]) -> string
+
+ Split the argument into words using split, capitalize each
+ word using capitalize, and join the capitalized words using
+ join. If the optional second argument sep is absent or None,
+ runs of whitespace characters are replaced by a single space
+ and leading and trailing whitespace are removed, otherwise
+ sep is used to split and join the words.
+
+ """
+ return (sep or ' ').join(x.capitalize() for x in s.split(sep))
+
+
+####################################################################
+import re as _re
+from collections import ChainMap as _ChainMap
+
+_sentinel_dict = {}
+
+class _TemplateMetaclass(type):
+ pattern = r"""
+ %(delim)s(?:
+ (?P%(delim)s) | # Escape sequence of two delimiters
+ (?P%(id)s) | # delimiter and a Python identifier
+ {(?P%(bid)s)} | # delimiter and a braced identifier
+ (?P) # Other ill-formed delimiter exprs
+ )
+ """
+
+ def __init__(cls, name, bases, dct):
+ super(_TemplateMetaclass, cls).__init__(name, bases, dct)
+ if 'pattern' in dct:
+ pattern = cls.pattern
+ else:
+ pattern = _TemplateMetaclass.pattern % {
+ 'delim' : _re.escape(cls.delimiter),
+ 'id' : cls.idpattern,
+ 'bid' : cls.braceidpattern or cls.idpattern,
+ }
+ cls.pattern = _re.compile(pattern, cls.flags | _re.VERBOSE)
+
+
+class Template(metaclass=_TemplateMetaclass):
+ """A string class for supporting $-substitutions."""
+
+ delimiter = '$'
+ # r'[a-z]' matches to non-ASCII letters when used with IGNORECASE, but
+ # without the ASCII flag. We can't add re.ASCII to flags because of
+ # backward compatibility. So we use the ?a local flag and [a-z] pattern.
+ # See https://bugs.python.org/issue31672
+ idpattern = r'(?a:[_a-z][_a-z0-9]*)'
+ braceidpattern = None
+ flags = _re.IGNORECASE
+
+ def __init__(self, template):
+ self.template = template
+
+ # Search for $$, $identifier, ${identifier}, and any bare $'s
+
+ def _invalid(self, mo):
+ i = mo.start('invalid')
+ lines = self.template[:i].splitlines(keepends=True)
+ if not lines:
+ colno = 1
+ lineno = 1
+ else:
+ colno = i - len(''.join(lines[:-1]))
+ lineno = len(lines)
+ raise ValueError('Invalid placeholder in string: line %d, col %d' %
+ (lineno, colno))
+
+ def substitute(self, mapping=_sentinel_dict, /, **kws):
+ if mapping is _sentinel_dict:
+ mapping = kws
+ elif kws:
+ mapping = _ChainMap(kws, mapping)
+ # Helper function for .sub()
+ def convert(mo):
+ # Check the most common path first.
+ named = mo.group('named') or mo.group('braced')
+ if named is not None:
+ return str(mapping[named])
+ if mo.group('escaped') is not None:
+ return self.delimiter
+ if mo.group('invalid') is not None:
+ self._invalid(mo)
+ raise ValueError('Unrecognized named group in pattern',
+ self.pattern)
+ return self.pattern.sub(convert, self.template)
+
+ def safe_substitute(self, mapping=_sentinel_dict, /, **kws):
+ if mapping is _sentinel_dict:
+ mapping = kws
+ elif kws:
+ mapping = _ChainMap(kws, mapping)
+ # Helper function for .sub()
+ def convert(mo):
+ named = mo.group('named') or mo.group('braced')
+ if named is not None:
+ try:
+ return str(mapping[named])
+ except KeyError:
+ return mo.group()
+ if mo.group('escaped') is not None:
+ return self.delimiter
+ if mo.group('invalid') is not None:
+ return mo.group()
+ raise ValueError('Unrecognized named group in pattern',
+ self.pattern)
+ return self.pattern.sub(convert, self.template)
+
+
+
+########################################################################
+# the Formatter class
+# see PEP 3101 for details and purpose of this class
+
+# The hard parts are reused from the C implementation. They're exposed as "_"
+# prefixed methods of str.
+
+# The overall parser is implemented in _string.formatter_parser.
+# The field name parser is implemented in _string.formatter_field_name_split
+
+class Formatter:
+ def format(self, format_string, /, *args, **kwargs):
+ return self.vformat(format_string, args, kwargs)
+
+ def vformat(self, format_string, args, kwargs):
+ used_args = set()
+ result, _ = self._vformat(format_string, args, kwargs, used_args, 2)
+ self.check_unused_args(used_args, args, kwargs)
+ return result
+
+ def _vformat(self, format_string, args, kwargs, used_args, recursion_depth,
+ auto_arg_index=0):
+ if recursion_depth < 0:
+ raise ValueError('Max string recursion exceeded')
+ result = []
+ for literal_text, field_name, format_spec, conversion in \
+ self.parse(format_string):
+
+ # output the literal text
+ if literal_text:
+ result.append(literal_text)
+
+ # if there's a field, output it
+ if field_name is not None:
+ # this is some markup, find the object and do
+ # the formatting
+
+ # handle arg indexing when empty field_names are given.
+ if field_name == '':
+ if auto_arg_index is False:
+ raise ValueError('cannot switch from manual field '
+ 'specification to automatic field '
+ 'numbering')
+ field_name = str(auto_arg_index)
+ auto_arg_index += 1
+ elif field_name.isdigit():
+ if auto_arg_index:
+ raise ValueError('cannot switch from manual field '
+ 'specification to automatic field '
+ 'numbering')
+ # disable auto arg incrementing, if it gets
+ # used later on, then an exception will be raised
+ auto_arg_index = False
+
+ # given the field_name, find the object it references
+ # and the argument it came from
+ obj, arg_used = self.get_field(field_name, args, kwargs)
+ used_args.add(arg_used)
+
+ # do any conversion on the resulting object
+ obj = self.convert_field(obj, conversion)
+
+ # expand the format spec, if needed
+ format_spec, auto_arg_index = self._vformat(
+ format_spec, args, kwargs,
+ used_args, recursion_depth-1,
+ auto_arg_index=auto_arg_index)
+
+ # format the object and append to the result
+ result.append(self.format_field(obj, format_spec))
+
+ return ''.join(result), auto_arg_index
+
+
+ def get_value(self, key, args, kwargs):
+ if isinstance(key, int):
+ return args[key]
+ else:
+ return kwargs[key]
+
+
+ def check_unused_args(self, used_args, args, kwargs):
+ pass
+
+
+ def format_field(self, value, format_spec):
+ return format(value, format_spec)
+
+
+ def convert_field(self, value, conversion):
+ # do any conversion on the resulting object
+ if conversion is None:
+ return value
+ elif conversion == 's':
+ return str(value)
+ elif conversion == 'r':
+ return repr(value)
+ elif conversion == 'a':
+ return ascii(value)
+ raise ValueError("Unknown conversion specifier {0!s}".format(conversion))
+
+
+ # returns an iterable that contains tuples of the form:
+ # (literal_text, field_name, format_spec, conversion)
+ # literal_text can be zero length
+ # field_name can be None, in which case there's no
+ # object to format and output
+ # if field_name is not None, it is looked up, formatted
+ # with format_spec and conversion and then used
+ def parse(self, format_string):
+ return _string.formatter_parser(format_string)
+
+
+ # given a field_name, find the object it references.
+ # field_name: the field being looked up, e.g. "0.name"
+ # or "lookup[3]"
+ # used_args: a set of which args have been used
+ # args, kwargs: as passed in to vformat
+ def get_field(self, field_name, args, kwargs):
+ first, rest = _string.formatter_field_name_split(field_name)
+
+ obj = self.get_value(first, args, kwargs)
+
+ # loop through the rest of the field_name, doing
+ # getattr or getitem as needed
+ for is_attr, i in rest:
+ if is_attr:
+ obj = getattr(obj, i)
+ else:
+ obj = obj[i]
+
+ return obj, first
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/subprocess.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/subprocess.py
new file mode 100644
index 0000000000000000000000000000000000000000..7d363fa3153fa4b7cdaa892f5b2b595c532091c6
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/subprocess.py
@@ -0,0 +1,1959 @@
+# subprocess - Subprocesses with accessible I/O streams
+#
+# For more information about this module, see PEP 324.
+#
+# Copyright (c) 2003-2005 by Peter Astrand
+#
+# Licensed to PSF under a Contributor Agreement.
+# See http://www.python.org/2.4/license for licensing details.
+
+r"""Subprocesses with accessible I/O streams
+
+This module allows you to spawn processes, connect to their
+input/output/error pipes, and obtain their return codes.
+
+For a complete description of this module see the Python documentation.
+
+Main API
+========
+run(...): Runs a command, waits for it to complete, then returns a
+ CompletedProcess instance.
+Popen(...): A class for flexibly executing a command in a new process
+
+Constants
+---------
+DEVNULL: Special value that indicates that os.devnull should be used
+PIPE: Special value that indicates a pipe should be created
+STDOUT: Special value that indicates that stderr should go to stdout
+
+
+Older API
+=========
+call(...): Runs a command, waits for it to complete, then returns
+ the return code.
+check_call(...): Same as call() but raises CalledProcessError()
+ if return code is not 0
+check_output(...): Same as check_call() but returns the contents of
+ stdout instead of a return code
+getoutput(...): Runs a command in the shell, waits for it to complete,
+ then returns the output
+getstatusoutput(...): Runs a command in the shell, waits for it to complete,
+ then returns a (exitcode, output) tuple
+"""
+
+import builtins
+import errno
+import io
+import os
+import time
+import signal
+import sys
+import threading
+import warnings
+import contextlib
+from time import monotonic as _time
+
+
+__all__ = ["Popen", "PIPE", "STDOUT", "call", "check_call", "getstatusoutput",
+ "getoutput", "check_output", "run", "CalledProcessError", "DEVNULL",
+ "SubprocessError", "TimeoutExpired", "CompletedProcess"]
+ # NOTE: We intentionally exclude list2cmdline as it is
+ # considered an internal implementation detail. issue10838.
+
+try:
+ import msvcrt
+ import _winapi
+ _mswindows = True
+except ModuleNotFoundError:
+ _mswindows = False
+ import _posixsubprocess
+ import select
+ import selectors
+else:
+ from _winapi import (CREATE_NEW_CONSOLE, CREATE_NEW_PROCESS_GROUP,
+ STD_INPUT_HANDLE, STD_OUTPUT_HANDLE,
+ STD_ERROR_HANDLE, SW_HIDE,
+ STARTF_USESTDHANDLES, STARTF_USESHOWWINDOW,
+ ABOVE_NORMAL_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS,
+ HIGH_PRIORITY_CLASS, IDLE_PRIORITY_CLASS,
+ NORMAL_PRIORITY_CLASS, REALTIME_PRIORITY_CLASS,
+ CREATE_NO_WINDOW, DETACHED_PROCESS,
+ CREATE_DEFAULT_ERROR_MODE, CREATE_BREAKAWAY_FROM_JOB)
+
+ __all__.extend(["CREATE_NEW_CONSOLE", "CREATE_NEW_PROCESS_GROUP",
+ "STD_INPUT_HANDLE", "STD_OUTPUT_HANDLE",
+ "STD_ERROR_HANDLE", "SW_HIDE",
+ "STARTF_USESTDHANDLES", "STARTF_USESHOWWINDOW",
+ "STARTUPINFO",
+ "ABOVE_NORMAL_PRIORITY_CLASS", "BELOW_NORMAL_PRIORITY_CLASS",
+ "HIGH_PRIORITY_CLASS", "IDLE_PRIORITY_CLASS",
+ "NORMAL_PRIORITY_CLASS", "REALTIME_PRIORITY_CLASS",
+ "CREATE_NO_WINDOW", "DETACHED_PROCESS",
+ "CREATE_DEFAULT_ERROR_MODE", "CREATE_BREAKAWAY_FROM_JOB"])
+
+
+# Exception classes used by this module.
+class SubprocessError(Exception): pass
+
+
+class CalledProcessError(SubprocessError):
+ """Raised when run() is called with check=True and the process
+ returns a non-zero exit status.
+
+ Attributes:
+ cmd, returncode, stdout, stderr, output
+ """
+ def __init__(self, returncode, cmd, output=None, stderr=None):
+ self.returncode = returncode
+ self.cmd = cmd
+ self.output = output
+ self.stderr = stderr
+
+ def __str__(self):
+ if self.returncode and self.returncode < 0:
+ try:
+ return "Command '%s' died with %r." % (
+ self.cmd, signal.Signals(-self.returncode))
+ except ValueError:
+ return "Command '%s' died with unknown signal %d." % (
+ self.cmd, -self.returncode)
+ else:
+ return "Command '%s' returned non-zero exit status %d." % (
+ self.cmd, self.returncode)
+
+ @property
+ def stdout(self):
+ """Alias for output attribute, to match stderr"""
+ return self.output
+
+ @stdout.setter
+ def stdout(self, value):
+ # There's no obvious reason to set this, but allow it anyway so
+ # .stdout is a transparent alias for .output
+ self.output = value
+
+
+class TimeoutExpired(SubprocessError):
+ """This exception is raised when the timeout expires while waiting for a
+ child process.
+
+ Attributes:
+ cmd, output, stdout, stderr, timeout
+ """
+ def __init__(self, cmd, timeout, output=None, stderr=None):
+ self.cmd = cmd
+ self.timeout = timeout
+ self.output = output
+ self.stderr = stderr
+
+ def __str__(self):
+ return ("Command '%s' timed out after %s seconds" %
+ (self.cmd, self.timeout))
+
+ @property
+ def stdout(self):
+ return self.output
+
+ @stdout.setter
+ def stdout(self, value):
+ # There's no obvious reason to set this, but allow it anyway so
+ # .stdout is a transparent alias for .output
+ self.output = value
+
+
+if _mswindows:
+ class STARTUPINFO:
+ def __init__(self, *, dwFlags=0, hStdInput=None, hStdOutput=None,
+ hStdError=None, wShowWindow=0, lpAttributeList=None):
+ self.dwFlags = dwFlags
+ self.hStdInput = hStdInput
+ self.hStdOutput = hStdOutput
+ self.hStdError = hStdError
+ self.wShowWindow = wShowWindow
+ self.lpAttributeList = lpAttributeList or {"handle_list": []}
+
+ def copy(self):
+ attr_list = self.lpAttributeList.copy()
+ if 'handle_list' in attr_list:
+ attr_list['handle_list'] = list(attr_list['handle_list'])
+
+ return STARTUPINFO(dwFlags=self.dwFlags,
+ hStdInput=self.hStdInput,
+ hStdOutput=self.hStdOutput,
+ hStdError=self.hStdError,
+ wShowWindow=self.wShowWindow,
+ lpAttributeList=attr_list)
+
+
+ class Handle(int):
+ closed = False
+
+ def Close(self, CloseHandle=_winapi.CloseHandle):
+ if not self.closed:
+ self.closed = True
+ CloseHandle(self)
+
+ def Detach(self):
+ if not self.closed:
+ self.closed = True
+ return int(self)
+ raise ValueError("already closed")
+
+ def __repr__(self):
+ return "%s(%d)" % (self.__class__.__name__, int(self))
+
+ __del__ = Close
+else:
+ # When select or poll has indicated that the file is writable,
+ # we can write up to _PIPE_BUF bytes without risk of blocking.
+ # POSIX defines PIPE_BUF as >= 512.
+ _PIPE_BUF = getattr(select, 'PIPE_BUF', 512)
+
+ # poll/select have the advantage of not requiring any extra file
+ # descriptor, contrarily to epoll/kqueue (also, they require a single
+ # syscall).
+ if hasattr(selectors, 'PollSelector'):
+ _PopenSelector = selectors.PollSelector
+ else:
+ _PopenSelector = selectors.SelectSelector
+
+
+if _mswindows:
+ # On Windows we just need to close `Popen._handle` when we no longer need
+ # it, so that the kernel can free it. `Popen._handle` gets closed
+ # implicitly when the `Popen` instance is finalized (see `Handle.__del__`,
+ # which is calling `CloseHandle` as requested in [1]), so there is nothing
+ # for `_cleanup` to do.
+ #
+ # [1] https://docs.microsoft.com/en-us/windows/desktop/ProcThread/
+ # creating-processes
+ _active = None
+
+ def _cleanup():
+ pass
+else:
+ # This lists holds Popen instances for which the underlying process had not
+ # exited at the time its __del__ method got called: those processes are
+ # wait()ed for synchronously from _cleanup() when a new Popen object is
+ # created, to avoid zombie processes.
+ _active = []
+
+ def _cleanup():
+ if _active is None:
+ return
+ for inst in _active[:]:
+ res = inst._internal_poll(_deadstate=sys.maxsize)
+ if res is not None:
+ try:
+ _active.remove(inst)
+ except ValueError:
+ # This can happen if two threads create a new Popen instance.
+ # It's harmless that it was already removed, so ignore.
+ pass
+
+PIPE = -1
+STDOUT = -2
+DEVNULL = -3
+
+
+# XXX This function is only used by multiprocessing and the test suite,
+# but it's here so that it can be imported when Python is compiled without
+# threads.
+
+def _optim_args_from_interpreter_flags():
+ """Return a list of command-line arguments reproducing the current
+ optimization settings in sys.flags."""
+ args = []
+ value = sys.flags.optimize
+ if value > 0:
+ args.append('-' + 'O' * value)
+ return args
+
+
+def _args_from_interpreter_flags():
+ """Return a list of command-line arguments reproducing the current
+ settings in sys.flags, sys.warnoptions and sys._xoptions."""
+ flag_opt_map = {
+ 'debug': 'd',
+ # 'inspect': 'i',
+ # 'interactive': 'i',
+ 'dont_write_bytecode': 'B',
+ 'no_site': 'S',
+ 'verbose': 'v',
+ 'bytes_warning': 'b',
+ 'quiet': 'q',
+ # -O is handled in _optim_args_from_interpreter_flags()
+ }
+ args = _optim_args_from_interpreter_flags()
+ for flag, opt in flag_opt_map.items():
+ v = getattr(sys.flags, flag)
+ if v > 0:
+ args.append('-' + opt * v)
+
+ if sys.flags.isolated:
+ args.append('-I')
+ else:
+ if sys.flags.ignore_environment:
+ args.append('-E')
+ if sys.flags.no_user_site:
+ args.append('-s')
+
+ # -W options
+ warnopts = sys.warnoptions[:]
+ bytes_warning = sys.flags.bytes_warning
+ xoptions = getattr(sys, '_xoptions', {})
+ dev_mode = ('dev' in xoptions)
+
+ if bytes_warning > 1:
+ warnopts.remove("error::BytesWarning")
+ elif bytes_warning:
+ warnopts.remove("default::BytesWarning")
+ if dev_mode:
+ warnopts.remove('default')
+ for opt in warnopts:
+ args.append('-W' + opt)
+
+ # -X options
+ if dev_mode:
+ args.extend(('-X', 'dev'))
+ for opt in ('faulthandler', 'tracemalloc', 'importtime',
+ 'showalloccount', 'showrefcount', 'utf8'):
+ if opt in xoptions:
+ value = xoptions[opt]
+ if value is True:
+ arg = opt
+ else:
+ arg = '%s=%s' % (opt, value)
+ args.extend(('-X', arg))
+
+ return args
+
+
+def call(*popenargs, timeout=None, **kwargs):
+ """Run command with arguments. Wait for command to complete or
+ timeout, then return the returncode attribute.
+
+ The arguments are the same as for the Popen constructor. Example:
+
+ retcode = call(["ls", "-l"])
+ """
+ with Popen(*popenargs, **kwargs) as p:
+ try:
+ return p.wait(timeout=timeout)
+ except: # Including KeyboardInterrupt, wait handled that.
+ p.kill()
+ # We don't call p.wait() again as p.__exit__ does that for us.
+ raise
+
+
+def check_call(*popenargs, **kwargs):
+ """Run command with arguments. Wait for command to complete. If
+ the exit code was zero then return, otherwise raise
+ CalledProcessError. The CalledProcessError object will have the
+ return code in the returncode attribute.
+
+ The arguments are the same as for the call function. Example:
+
+ check_call(["ls", "-l"])
+ """
+ retcode = call(*popenargs, **kwargs)
+ if retcode:
+ cmd = kwargs.get("args")
+ if cmd is None:
+ cmd = popenargs[0]
+ raise CalledProcessError(retcode, cmd)
+ return 0
+
+
+def check_output(*popenargs, timeout=None, **kwargs):
+ r"""Run command with arguments and return its output.
+
+ If the exit code was non-zero it raises a CalledProcessError. The
+ CalledProcessError object will have the return code in the returncode
+ attribute and output in the output attribute.
+
+ The arguments are the same as for the Popen constructor. Example:
+
+ >>> check_output(["ls", "-l", "/dev/null"])
+ b'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n'
+
+ The stdout argument is not allowed as it is used internally.
+ To capture standard error in the result, use stderr=STDOUT.
+
+ >>> check_output(["/bin/sh", "-c",
+ ... "ls -l non_existent_file ; exit 0"],
+ ... stderr=STDOUT)
+ b'ls: non_existent_file: No such file or directory\n'
+
+ There is an additional optional argument, "input", allowing you to
+ pass a string to the subprocess's stdin. If you use this argument
+ you may not also use the Popen constructor's "stdin" argument, as
+ it too will be used internally. Example:
+
+ >>> check_output(["sed", "-e", "s/foo/bar/"],
+ ... input=b"when in the course of fooman events\n")
+ b'when in the course of barman events\n'
+
+ By default, all communication is in bytes, and therefore any "input"
+ should be bytes, and the return value will be bytes. If in text mode,
+ any "input" should be a string, and the return value will be a string
+ decoded according to locale encoding, or by "encoding" if set. Text mode
+ is triggered by setting any of text, encoding, errors or universal_newlines.
+ """
+ if 'stdout' in kwargs:
+ raise ValueError('stdout argument not allowed, it will be overridden.')
+
+ if 'input' in kwargs and kwargs['input'] is None:
+ # Explicitly passing input=None was previously equivalent to passing an
+ # empty string. That is maintained here for backwards compatibility.
+ if kwargs.get('universal_newlines') or kwargs.get('text'):
+ empty = ''
+ else:
+ empty = b''
+ kwargs['input'] = empty
+
+ return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
+ **kwargs).stdout
+
+
+class CompletedProcess(object):
+ """A process that has finished running.
+
+ This is returned by run().
+
+ Attributes:
+ args: The list or str args passed to run().
+ returncode: The exit code of the process, negative for signals.
+ stdout: The standard output (None if not captured).
+ stderr: The standard error (None if not captured).
+ """
+ def __init__(self, args, returncode, stdout=None, stderr=None):
+ self.args = args
+ self.returncode = returncode
+ self.stdout = stdout
+ self.stderr = stderr
+
+ def __repr__(self):
+ args = ['args={!r}'.format(self.args),
+ 'returncode={!r}'.format(self.returncode)]
+ if self.stdout is not None:
+ args.append('stdout={!r}'.format(self.stdout))
+ if self.stderr is not None:
+ args.append('stderr={!r}'.format(self.stderr))
+ return "{}({})".format(type(self).__name__, ', '.join(args))
+
+ def check_returncode(self):
+ """Raise CalledProcessError if the exit code is non-zero."""
+ if self.returncode:
+ raise CalledProcessError(self.returncode, self.args, self.stdout,
+ self.stderr)
+
+
+def run(*popenargs,
+ input=None, capture_output=False, timeout=None, check=False, **kwargs):
+ """Run command with arguments and return a CompletedProcess instance.
+
+ The returned instance will have attributes args, returncode, stdout and
+ stderr. By default, stdout and stderr are not captured, and those attributes
+ will be None. Pass stdout=PIPE and/or stderr=PIPE in order to capture them.
+
+ If check is True and the exit code was non-zero, it raises a
+ CalledProcessError. The CalledProcessError object will have the return code
+ in the returncode attribute, and output & stderr attributes if those streams
+ were captured.
+
+ If timeout is given, and the process takes too long, a TimeoutExpired
+ exception will be raised.
+
+ There is an optional argument "input", allowing you to
+ pass bytes or a string to the subprocess's stdin. If you use this argument
+ you may not also use the Popen constructor's "stdin" argument, as
+ it will be used internally.
+
+ By default, all communication is in bytes, and therefore any "input" should
+ be bytes, and the stdout and stderr will be bytes. If in text mode, any
+ "input" should be a string, and stdout and stderr will be strings decoded
+ according to locale encoding, or by "encoding" if set. Text mode is
+ triggered by setting any of text, encoding, errors or universal_newlines.
+
+ The other arguments are the same as for the Popen constructor.
+ """
+ if input is not None:
+ if kwargs.get('stdin') is not None:
+ raise ValueError('stdin and input arguments may not both be used.')
+ kwargs['stdin'] = PIPE
+
+ if capture_output:
+ if kwargs.get('stdout') is not None or kwargs.get('stderr') is not None:
+ raise ValueError('stdout and stderr arguments may not be used '
+ 'with capture_output.')
+ kwargs['stdout'] = PIPE
+ kwargs['stderr'] = PIPE
+
+ with Popen(*popenargs, **kwargs) as process:
+ try:
+ stdout, stderr = process.communicate(input, timeout=timeout)
+ except TimeoutExpired as exc:
+ process.kill()
+ if _mswindows:
+ # Windows accumulates the output in a single blocking
+ # read() call run on child threads, with the timeout
+ # being done in a join() on those threads. communicate()
+ # _after_ kill() is required to collect that and add it
+ # to the exception.
+ exc.stdout, exc.stderr = process.communicate()
+ else:
+ # POSIX _communicate already populated the output so
+ # far into the TimeoutExpired exception.
+ process.wait()
+ raise
+ except: # Including KeyboardInterrupt, communicate handled that.
+ process.kill()
+ # We don't call process.wait() as .__exit__ does that for us.
+ raise
+ retcode = process.poll()
+ if check and retcode:
+ raise CalledProcessError(retcode, process.args,
+ output=stdout, stderr=stderr)
+ return CompletedProcess(process.args, retcode, stdout, stderr)
+
+
+def list2cmdline(seq):
+ """
+ Translate a sequence of arguments into a command line
+ string, using the same rules as the MS C runtime:
+
+ 1) Arguments are delimited by white space, which is either a
+ space or a tab.
+
+ 2) A string surrounded by double quotation marks is
+ interpreted as a single argument, regardless of white space
+ contained within. A quoted string can be embedded in an
+ argument.
+
+ 3) A double quotation mark preceded by a backslash is
+ interpreted as a literal double quotation mark.
+
+ 4) Backslashes are interpreted literally, unless they
+ immediately precede a double quotation mark.
+
+ 5) If backslashes immediately precede a double quotation mark,
+ every pair of backslashes is interpreted as a literal
+ backslash. If the number of backslashes is odd, the last
+ backslash escapes the next double quotation mark as
+ described in rule 3.
+ """
+
+ # See
+ # http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
+ # or search http://msdn.microsoft.com for
+ # "Parsing C++ Command-Line Arguments"
+ result = []
+ needquote = False
+ for arg in map(os.fsdecode, seq):
+ bs_buf = []
+
+ # Add a space to separate this argument from the others
+ if result:
+ result.append(' ')
+
+ needquote = (" " in arg) or ("\t" in arg) or not arg
+ if needquote:
+ result.append('"')
+
+ for c in arg:
+ if c == '\\':
+ # Don't know if we need to double yet.
+ bs_buf.append(c)
+ elif c == '"':
+ # Double backslashes.
+ result.append('\\' * len(bs_buf)*2)
+ bs_buf = []
+ result.append('\\"')
+ else:
+ # Normal char
+ if bs_buf:
+ result.extend(bs_buf)
+ bs_buf = []
+ result.append(c)
+
+ # Add remaining backslashes, if any.
+ if bs_buf:
+ result.extend(bs_buf)
+
+ if needquote:
+ result.extend(bs_buf)
+ result.append('"')
+
+ return ''.join(result)
+
+
+# Various tools for executing commands and looking at their output and status.
+#
+
+def getstatusoutput(cmd):
+ """Return (exitcode, output) of executing cmd in a shell.
+
+ Execute the string 'cmd' in a shell with 'check_output' and
+ return a 2-tuple (status, output). The locale encoding is used
+ to decode the output and process newlines.
+
+ A trailing newline is stripped from the output.
+ The exit status for the command can be interpreted
+ according to the rules for the function 'wait'. Example:
+
+ >>> import subprocess
+ >>> subprocess.getstatusoutput('ls /bin/ls')
+ (0, '/bin/ls')
+ >>> subprocess.getstatusoutput('cat /bin/junk')
+ (1, 'cat: /bin/junk: No such file or directory')
+ >>> subprocess.getstatusoutput('/bin/junk')
+ (127, 'sh: /bin/junk: not found')
+ >>> subprocess.getstatusoutput('/bin/kill $$')
+ (-15, '')
+ """
+ try:
+ data = check_output(cmd, shell=True, text=True, stderr=STDOUT)
+ exitcode = 0
+ except CalledProcessError as ex:
+ data = ex.output
+ exitcode = ex.returncode
+ if data[-1:] == '\n':
+ data = data[:-1]
+ return exitcode, data
+
+def getoutput(cmd):
+ """Return output (stdout or stderr) of executing cmd in a shell.
+
+ Like getstatusoutput(), except the exit status is ignored and the return
+ value is a string containing the command's output. Example:
+
+ >>> import subprocess
+ >>> subprocess.getoutput('ls /bin/ls')
+ '/bin/ls'
+ """
+ return getstatusoutput(cmd)[1]
+
+
+def _use_posix_spawn():
+ """Check if posix_spawn() can be used for subprocess.
+
+ subprocess requires a posix_spawn() implementation that properly reports
+ errors to the parent process, & sets errno on the following failures:
+
+ * Process attribute actions failed.
+ * File actions failed.
+ * exec() failed.
+
+ Prefer an implementation which can use vfork() in some cases for best
+ performance.
+ """
+ if _mswindows or not hasattr(os, 'posix_spawn'):
+ # os.posix_spawn() is not available
+ return False
+
+ if sys.platform == 'darwin':
+ # posix_spawn() is a syscall on macOS and properly reports errors
+ return True
+
+ # Check libc name and runtime libc version
+ try:
+ ver = os.confstr('CS_GNU_LIBC_VERSION')
+ # parse 'glibc 2.28' as ('glibc', (2, 28))
+ parts = ver.split(maxsplit=1)
+ if len(parts) != 2:
+ # reject unknown format
+ raise ValueError
+ libc = parts[0]
+ version = tuple(map(int, parts[1].split('.')))
+
+ if sys.platform == 'linux' and libc == 'glibc' and version >= (2, 24):
+ # glibc 2.24 has a new Linux posix_spawn implementation using vfork
+ # which properly reports errors to the parent process.
+ return True
+ # Note: Don't use the implementation in earlier glibc because it doesn't
+ # use vfork (even if glibc 2.26 added a pipe to properly report errors
+ # to the parent process).
+ except (AttributeError, ValueError, OSError):
+ # os.confstr() or CS_GNU_LIBC_VERSION value not available
+ pass
+
+ # By default, assume that posix_spawn() does not properly report errors.
+ return False
+
+
+_USE_POSIX_SPAWN = _use_posix_spawn()
+
+
+class Popen(object):
+ """ Execute a child program in a new process.
+
+ For a complete description of the arguments see the Python documentation.
+
+ Arguments:
+ args: A string, or a sequence of program arguments.
+
+ bufsize: supplied as the buffering argument to the open() function when
+ creating the stdin/stdout/stderr pipe file objects
+
+ executable: A replacement program to execute.
+
+ stdin, stdout and stderr: These specify the executed programs' standard
+ input, standard output and standard error file handles, respectively.
+
+ preexec_fn: (POSIX only) An object to be called in the child process
+ just before the child is executed.
+
+ close_fds: Controls closing or inheriting of file descriptors.
+
+ shell: If true, the command will be executed through the shell.
+
+ cwd: Sets the current directory before the child is executed.
+
+ env: Defines the environment variables for the new process.
+
+ text: If true, decode stdin, stdout and stderr using the given encoding
+ (if set) or the system default otherwise.
+
+ universal_newlines: Alias of text, provided for backwards compatibility.
+
+ startupinfo and creationflags (Windows only)
+
+ restore_signals (POSIX only)
+
+ start_new_session (POSIX only)
+
+ pass_fds (POSIX only)
+
+ encoding and errors: Text mode encoding and error handling to use for
+ file objects stdin, stdout and stderr.
+
+ Attributes:
+ stdin, stdout, stderr, pid, returncode
+ """
+ _child_created = False # Set here since __del__ checks it
+
+ def __init__(self, args, bufsize=-1, executable=None,
+ stdin=None, stdout=None, stderr=None,
+ preexec_fn=None, close_fds=True,
+ shell=False, cwd=None, env=None, universal_newlines=None,
+ startupinfo=None, creationflags=0,
+ restore_signals=True, start_new_session=False,
+ pass_fds=(), *, encoding=None, errors=None, text=None):
+ """Create new Popen instance."""
+ _cleanup()
+ # Held while anything is calling waitpid before returncode has been
+ # updated to prevent clobbering returncode if wait() or poll() are
+ # called from multiple threads at once. After acquiring the lock,
+ # code must re-check self.returncode to see if another thread just
+ # finished a waitpid() call.
+ self._waitpid_lock = threading.Lock()
+
+ self._input = None
+ self._communication_started = False
+ if bufsize is None:
+ bufsize = -1 # Restore default
+ if not isinstance(bufsize, int):
+ raise TypeError("bufsize must be an integer")
+
+ if _mswindows:
+ if preexec_fn is not None:
+ raise ValueError("preexec_fn is not supported on Windows "
+ "platforms")
+ else:
+ # POSIX
+ if pass_fds and not close_fds:
+ warnings.warn("pass_fds overriding close_fds.", RuntimeWarning)
+ close_fds = True
+ if startupinfo is not None:
+ raise ValueError("startupinfo is only supported on Windows "
+ "platforms")
+ if creationflags != 0:
+ raise ValueError("creationflags is only supported on Windows "
+ "platforms")
+
+ self.args = args
+ self.stdin = None
+ self.stdout = None
+ self.stderr = None
+ self.pid = None
+ self.returncode = None
+ self.encoding = encoding
+ self.errors = errors
+
+ # Validate the combinations of text and universal_newlines
+ if (text is not None and universal_newlines is not None
+ and bool(universal_newlines) != bool(text)):
+ raise SubprocessError('Cannot disambiguate when both text '
+ 'and universal_newlines are supplied but '
+ 'different. Pass one or the other.')
+
+ # Input and output objects. The general principle is like
+ # this:
+ #
+ # Parent Child
+ # ------ -----
+ # p2cwrite ---stdin---> p2cread
+ # c2pread <--stdout--- c2pwrite
+ # errread <--stderr--- errwrite
+ #
+ # On POSIX, the child objects are file descriptors. On
+ # Windows, these are Windows file handles. The parent objects
+ # are file descriptors on both platforms. The parent objects
+ # are -1 when not using PIPEs. The child objects are -1
+ # when not redirecting.
+
+ (p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite) = self._get_handles(stdin, stdout, stderr)
+
+ # We wrap OS handles *before* launching the child, otherwise a
+ # quickly terminating child could make our fds unwrappable
+ # (see #8458).
+
+ if _mswindows:
+ if p2cwrite != -1:
+ p2cwrite = msvcrt.open_osfhandle(p2cwrite.Detach(), 0)
+ if c2pread != -1:
+ c2pread = msvcrt.open_osfhandle(c2pread.Detach(), 0)
+ if errread != -1:
+ errread = msvcrt.open_osfhandle(errread.Detach(), 0)
+
+ self.text_mode = encoding or errors or text or universal_newlines
+
+ # How long to resume waiting on a child after the first ^C.
+ # There is no right value for this. The purpose is to be polite
+ # yet remain good for interactive users trying to exit a tool.
+ self._sigint_wait_secs = 0.25 # 1/xkcd221.getRandomNumber()
+
+ self._closed_child_pipe_fds = False
+
+ if self.text_mode:
+ if bufsize == 1:
+ line_buffering = True
+ # Use the default buffer size for the underlying binary streams
+ # since they don't support line buffering.
+ bufsize = -1
+ else:
+ line_buffering = False
+
+ try:
+ if p2cwrite != -1:
+ self.stdin = io.open(p2cwrite, 'wb', bufsize)
+ if self.text_mode:
+ self.stdin = io.TextIOWrapper(self.stdin, write_through=True,
+ line_buffering=line_buffering,
+ encoding=encoding, errors=errors)
+ if c2pread != -1:
+ self.stdout = io.open(c2pread, 'rb', bufsize)
+ if self.text_mode:
+ self.stdout = io.TextIOWrapper(self.stdout,
+ encoding=encoding, errors=errors)
+ if errread != -1:
+ self.stderr = io.open(errread, 'rb', bufsize)
+ if self.text_mode:
+ self.stderr = io.TextIOWrapper(self.stderr,
+ encoding=encoding, errors=errors)
+
+ self._execute_child(args, executable, preexec_fn, close_fds,
+ pass_fds, cwd, env,
+ startupinfo, creationflags, shell,
+ p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite,
+ restore_signals, start_new_session)
+ except:
+ # Cleanup if the child failed starting.
+ for f in filter(None, (self.stdin, self.stdout, self.stderr)):
+ try:
+ f.close()
+ except OSError:
+ pass # Ignore EBADF or other errors.
+
+ if not self._closed_child_pipe_fds:
+ to_close = []
+ if stdin == PIPE:
+ to_close.append(p2cread)
+ if stdout == PIPE:
+ to_close.append(c2pwrite)
+ if stderr == PIPE:
+ to_close.append(errwrite)
+ if hasattr(self, '_devnull'):
+ to_close.append(self._devnull)
+ for fd in to_close:
+ try:
+ if _mswindows and isinstance(fd, Handle):
+ fd.Close()
+ else:
+ os.close(fd)
+ except OSError:
+ pass
+
+ raise
+
+ @property
+ def universal_newlines(self):
+ # universal_newlines as retained as an alias of text_mode for API
+ # compatibility. bpo-31756
+ return self.text_mode
+
+ @universal_newlines.setter
+ def universal_newlines(self, universal_newlines):
+ self.text_mode = bool(universal_newlines)
+
+ def _translate_newlines(self, data, encoding, errors):
+ data = data.decode(encoding, errors)
+ return data.replace("\r\n", "\n").replace("\r", "\n")
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, value, traceback):
+ if self.stdout:
+ self.stdout.close()
+ if self.stderr:
+ self.stderr.close()
+ try: # Flushing a BufferedWriter may raise an error
+ if self.stdin:
+ self.stdin.close()
+ finally:
+ if exc_type == KeyboardInterrupt:
+ # https://bugs.python.org/issue25942
+ # In the case of a KeyboardInterrupt we assume the SIGINT
+ # was also already sent to our child processes. We can't
+ # block indefinitely as that is not user friendly.
+ # If we have not already waited a brief amount of time in
+ # an interrupted .wait() or .communicate() call, do so here
+ # for consistency.
+ if self._sigint_wait_secs > 0:
+ try:
+ self._wait(timeout=self._sigint_wait_secs)
+ except TimeoutExpired:
+ pass
+ self._sigint_wait_secs = 0 # Note that this has been done.
+ return # resume the KeyboardInterrupt
+
+ # Wait for the process to terminate, to avoid zombies.
+ self.wait()
+
+ def __del__(self, _maxsize=sys.maxsize, _warn=warnings.warn):
+ if not self._child_created:
+ # We didn't get to successfully create a child process.
+ return
+ if self.returncode is None:
+ # Not reading subprocess exit status creates a zombie process which
+ # is only destroyed at the parent python process exit
+ _warn("subprocess %s is still running" % self.pid,
+ ResourceWarning, source=self)
+ # In case the child hasn't been waited on, check if it's done.
+ self._internal_poll(_deadstate=_maxsize)
+ if self.returncode is None and _active is not None:
+ # Child is still running, keep us alive until we can wait on it.
+ _active.append(self)
+
+ def _get_devnull(self):
+ if not hasattr(self, '_devnull'):
+ self._devnull = os.open(os.devnull, os.O_RDWR)
+ return self._devnull
+
+ def _stdin_write(self, input):
+ if input:
+ try:
+ self.stdin.write(input)
+ except BrokenPipeError:
+ pass # communicate() must ignore broken pipe errors.
+ except OSError as exc:
+ if exc.errno == errno.EINVAL:
+ # bpo-19612, bpo-30418: On Windows, stdin.write() fails
+ # with EINVAL if the child process exited or if the child
+ # process is still running but closed the pipe.
+ pass
+ else:
+ raise
+
+ try:
+ self.stdin.close()
+ except BrokenPipeError:
+ pass # communicate() must ignore broken pipe errors.
+ except OSError as exc:
+ if exc.errno == errno.EINVAL:
+ pass
+ else:
+ raise
+
+ def communicate(self, input=None, timeout=None):
+ """Interact with process: Send data to stdin and close it.
+ Read data from stdout and stderr, until end-of-file is
+ reached. Wait for process to terminate.
+
+ The optional "input" argument should be data to be sent to the
+ child process, or None, if no data should be sent to the child.
+ communicate() returns a tuple (stdout, stderr).
+
+ By default, all communication is in bytes, and therefore any
+ "input" should be bytes, and the (stdout, stderr) will be bytes.
+ If in text mode (indicated by self.text_mode), any "input" should
+ be a string, and (stdout, stderr) will be strings decoded
+ according to locale encoding, or by "encoding" if set. Text mode
+ is triggered by setting any of text, encoding, errors or
+ universal_newlines.
+ """
+
+ if self._communication_started and input:
+ raise ValueError("Cannot send input after starting communication")
+
+ # Optimization: If we are not worried about timeouts, we haven't
+ # started communicating, and we have one or zero pipes, using select()
+ # or threads is unnecessary.
+ if (timeout is None and not self._communication_started and
+ [self.stdin, self.stdout, self.stderr].count(None) >= 2):
+ stdout = None
+ stderr = None
+ if self.stdin:
+ self._stdin_write(input)
+ elif self.stdout:
+ stdout = self.stdout.read()
+ self.stdout.close()
+ elif self.stderr:
+ stderr = self.stderr.read()
+ self.stderr.close()
+ self.wait()
+ else:
+ if timeout is not None:
+ endtime = _time() + timeout
+ else:
+ endtime = None
+
+ try:
+ stdout, stderr = self._communicate(input, endtime, timeout)
+ except KeyboardInterrupt:
+ # https://bugs.python.org/issue25942
+ # See the detailed comment in .wait().
+ if timeout is not None:
+ sigint_timeout = min(self._sigint_wait_secs,
+ self._remaining_time(endtime))
+ else:
+ sigint_timeout = self._sigint_wait_secs
+ self._sigint_wait_secs = 0 # nothing else should wait.
+ try:
+ self._wait(timeout=sigint_timeout)
+ except TimeoutExpired:
+ pass
+ raise # resume the KeyboardInterrupt
+
+ finally:
+ self._communication_started = True
+
+ sts = self.wait(timeout=self._remaining_time(endtime))
+
+ return (stdout, stderr)
+
+
+ def poll(self):
+ """Check if child process has terminated. Set and return returncode
+ attribute."""
+ return self._internal_poll()
+
+
+ def _remaining_time(self, endtime):
+ """Convenience for _communicate when computing timeouts."""
+ if endtime is None:
+ return None
+ else:
+ return endtime - _time()
+
+
+ def _check_timeout(self, endtime, orig_timeout, stdout_seq, stderr_seq,
+ skip_check_and_raise=False):
+ """Convenience for checking if a timeout has expired."""
+ if endtime is None:
+ return
+ if skip_check_and_raise or _time() > endtime:
+ raise TimeoutExpired(
+ self.args, orig_timeout,
+ output=b''.join(stdout_seq) if stdout_seq else None,
+ stderr=b''.join(stderr_seq) if stderr_seq else None)
+
+
+ def wait(self, timeout=None):
+ """Wait for child process to terminate; returns self.returncode."""
+ if timeout is not None:
+ endtime = _time() + timeout
+ try:
+ return self._wait(timeout=timeout)
+ except KeyboardInterrupt:
+ # https://bugs.python.org/issue25942
+ # The first keyboard interrupt waits briefly for the child to
+ # exit under the common assumption that it also received the ^C
+ # generated SIGINT and will exit rapidly.
+ if timeout is not None:
+ sigint_timeout = min(self._sigint_wait_secs,
+ self._remaining_time(endtime))
+ else:
+ sigint_timeout = self._sigint_wait_secs
+ self._sigint_wait_secs = 0 # nothing else should wait.
+ try:
+ self._wait(timeout=sigint_timeout)
+ except TimeoutExpired:
+ pass
+ raise # resume the KeyboardInterrupt
+
+ def _close_pipe_fds(self,
+ p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite):
+ # self._devnull is not always defined.
+ devnull_fd = getattr(self, '_devnull', None)
+
+ with contextlib.ExitStack() as stack:
+ if _mswindows:
+ if p2cread != -1:
+ stack.callback(p2cread.Close)
+ if c2pwrite != -1:
+ stack.callback(c2pwrite.Close)
+ if errwrite != -1:
+ stack.callback(errwrite.Close)
+ else:
+ if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd:
+ stack.callback(os.close, p2cread)
+ if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd:
+ stack.callback(os.close, c2pwrite)
+ if errwrite != -1 and errread != -1 and errwrite != devnull_fd:
+ stack.callback(os.close, errwrite)
+
+ if devnull_fd is not None:
+ stack.callback(os.close, devnull_fd)
+
+ # Prevent a double close of these handles/fds from __init__ on error.
+ self._closed_child_pipe_fds = True
+
+ if _mswindows:
+ #
+ # Windows methods
+ #
+ def _get_handles(self, stdin, stdout, stderr):
+ """Construct and return tuple with IO objects:
+ p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite
+ """
+ if stdin is None and stdout is None and stderr is None:
+ return (-1, -1, -1, -1, -1, -1)
+
+ p2cread, p2cwrite = -1, -1
+ c2pread, c2pwrite = -1, -1
+ errread, errwrite = -1, -1
+
+ if stdin is None:
+ p2cread = _winapi.GetStdHandle(_winapi.STD_INPUT_HANDLE)
+ if p2cread is None:
+ p2cread, _ = _winapi.CreatePipe(None, 0)
+ p2cread = Handle(p2cread)
+ _winapi.CloseHandle(_)
+ elif stdin == PIPE:
+ p2cread, p2cwrite = _winapi.CreatePipe(None, 0)
+ p2cread, p2cwrite = Handle(p2cread), Handle(p2cwrite)
+ elif stdin == DEVNULL:
+ p2cread = msvcrt.get_osfhandle(self._get_devnull())
+ elif isinstance(stdin, int):
+ p2cread = msvcrt.get_osfhandle(stdin)
+ else:
+ # Assuming file-like object
+ p2cread = msvcrt.get_osfhandle(stdin.fileno())
+ p2cread = self._make_inheritable(p2cread)
+
+ if stdout is None:
+ c2pwrite = _winapi.GetStdHandle(_winapi.STD_OUTPUT_HANDLE)
+ if c2pwrite is None:
+ _, c2pwrite = _winapi.CreatePipe(None, 0)
+ c2pwrite = Handle(c2pwrite)
+ _winapi.CloseHandle(_)
+ elif stdout == PIPE:
+ c2pread, c2pwrite = _winapi.CreatePipe(None, 0)
+ c2pread, c2pwrite = Handle(c2pread), Handle(c2pwrite)
+ elif stdout == DEVNULL:
+ c2pwrite = msvcrt.get_osfhandle(self._get_devnull())
+ elif isinstance(stdout, int):
+ c2pwrite = msvcrt.get_osfhandle(stdout)
+ else:
+ # Assuming file-like object
+ c2pwrite = msvcrt.get_osfhandle(stdout.fileno())
+ c2pwrite = self._make_inheritable(c2pwrite)
+
+ if stderr is None:
+ errwrite = _winapi.GetStdHandle(_winapi.STD_ERROR_HANDLE)
+ if errwrite is None:
+ _, errwrite = _winapi.CreatePipe(None, 0)
+ errwrite = Handle(errwrite)
+ _winapi.CloseHandle(_)
+ elif stderr == PIPE:
+ errread, errwrite = _winapi.CreatePipe(None, 0)
+ errread, errwrite = Handle(errread), Handle(errwrite)
+ elif stderr == STDOUT:
+ errwrite = c2pwrite
+ elif stderr == DEVNULL:
+ errwrite = msvcrt.get_osfhandle(self._get_devnull())
+ elif isinstance(stderr, int):
+ errwrite = msvcrt.get_osfhandle(stderr)
+ else:
+ # Assuming file-like object
+ errwrite = msvcrt.get_osfhandle(stderr.fileno())
+ errwrite = self._make_inheritable(errwrite)
+
+ return (p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite)
+
+
+ def _make_inheritable(self, handle):
+ """Return a duplicate of handle, which is inheritable"""
+ h = _winapi.DuplicateHandle(
+ _winapi.GetCurrentProcess(), handle,
+ _winapi.GetCurrentProcess(), 0, 1,
+ _winapi.DUPLICATE_SAME_ACCESS)
+ return Handle(h)
+
+
+ def _filter_handle_list(self, handle_list):
+ """Filter out console handles that can't be used
+ in lpAttributeList["handle_list"] and make sure the list
+ isn't empty. This also removes duplicate handles."""
+ # An handle with it's lowest two bits set might be a special console
+ # handle that if passed in lpAttributeList["handle_list"], will
+ # cause it to fail.
+ return list({handle for handle in handle_list
+ if handle & 0x3 != 0x3
+ or _winapi.GetFileType(handle) !=
+ _winapi.FILE_TYPE_CHAR})
+
+
+ def _execute_child(self, args, executable, preexec_fn, close_fds,
+ pass_fds, cwd, env,
+ startupinfo, creationflags, shell,
+ p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite,
+ unused_restore_signals, unused_start_new_session):
+ """Execute program (MS Windows version)"""
+
+ assert not pass_fds, "pass_fds not supported on Windows."
+
+ if isinstance(args, str):
+ pass
+ elif isinstance(args, bytes):
+ if shell:
+ raise TypeError('bytes args is not allowed on Windows')
+ args = list2cmdline([args])
+ elif isinstance(args, os.PathLike):
+ if shell:
+ raise TypeError('path-like args is not allowed when '
+ 'shell is true')
+ args = list2cmdline([args])
+ else:
+ args = list2cmdline(args)
+
+ if executable is not None:
+ executable = os.fsdecode(executable)
+
+ # Process startup details
+ if startupinfo is None:
+ startupinfo = STARTUPINFO()
+ else:
+ # bpo-34044: Copy STARTUPINFO since it is modified above,
+ # so the caller can reuse it multiple times.
+ startupinfo = startupinfo.copy()
+
+ use_std_handles = -1 not in (p2cread, c2pwrite, errwrite)
+ if use_std_handles:
+ startupinfo.dwFlags |= _winapi.STARTF_USESTDHANDLES
+ startupinfo.hStdInput = p2cread
+ startupinfo.hStdOutput = c2pwrite
+ startupinfo.hStdError = errwrite
+
+ attribute_list = startupinfo.lpAttributeList
+ have_handle_list = bool(attribute_list and
+ "handle_list" in attribute_list and
+ attribute_list["handle_list"])
+
+ # If we were given an handle_list or need to create one
+ if have_handle_list or (use_std_handles and close_fds):
+ if attribute_list is None:
+ attribute_list = startupinfo.lpAttributeList = {}
+ handle_list = attribute_list["handle_list"] = \
+ list(attribute_list.get("handle_list", []))
+
+ if use_std_handles:
+ handle_list += [int(p2cread), int(c2pwrite), int(errwrite)]
+
+ handle_list[:] = self._filter_handle_list(handle_list)
+
+ if handle_list:
+ if not close_fds:
+ warnings.warn("startupinfo.lpAttributeList['handle_list'] "
+ "overriding close_fds", RuntimeWarning)
+
+ # When using the handle_list we always request to inherit
+ # handles but the only handles that will be inherited are
+ # the ones in the handle_list
+ close_fds = False
+
+ if shell:
+ startupinfo.dwFlags |= _winapi.STARTF_USESHOWWINDOW
+ startupinfo.wShowWindow = _winapi.SW_HIDE
+ if not executable:
+ # gh-101283: without a fully-qualified path, before Windows
+ # checks the system directories, it first looks in the
+ # application directory, and also the current directory if
+ # NeedCurrentDirectoryForExePathW(ExeName) is true, so try
+ # to avoid executing unqualified "cmd.exe".
+ comspec = os.environ.get('ComSpec')
+ if not comspec:
+ system_root = os.environ.get('SystemRoot', '')
+ comspec = os.path.join(system_root, 'System32', 'cmd.exe')
+ if not os.path.isabs(comspec):
+ raise FileNotFoundError('shell not found: neither %ComSpec% nor %SystemRoot% is set')
+ if os.path.isabs(comspec):
+ executable = comspec
+ else:
+ comspec = executable
+
+ args = '{} /c "{}"'.format (comspec, args)
+
+ if cwd is not None:
+ cwd = os.fsdecode(cwd)
+
+ sys.audit("subprocess.Popen", executable, args, cwd, env)
+
+ # Start the process
+ try:
+ hp, ht, pid, tid = _winapi.CreateProcess(executable, args,
+ # no special security
+ None, None,
+ int(not close_fds),
+ creationflags,
+ env,
+ cwd,
+ startupinfo)
+ finally:
+ # Child is launched. Close the parent's copy of those pipe
+ # handles that only the child should have open. You need
+ # to make sure that no handles to the write end of the
+ # output pipe are maintained in this process or else the
+ # pipe will not close when the child process exits and the
+ # ReadFile will hang.
+ self._close_pipe_fds(p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite)
+
+ # Retain the process handle, but close the thread handle
+ self._child_created = True
+ self._handle = Handle(hp)
+ self.pid = pid
+ _winapi.CloseHandle(ht)
+
+ def _internal_poll(self, _deadstate=None,
+ _WaitForSingleObject=_winapi.WaitForSingleObject,
+ _WAIT_OBJECT_0=_winapi.WAIT_OBJECT_0,
+ _GetExitCodeProcess=_winapi.GetExitCodeProcess):
+ """Check if child process has terminated. Returns returncode
+ attribute.
+
+ This method is called by __del__, so it can only refer to objects
+ in its local scope.
+
+ """
+ if self.returncode is None:
+ if _WaitForSingleObject(self._handle, 0) == _WAIT_OBJECT_0:
+ self.returncode = _GetExitCodeProcess(self._handle)
+ return self.returncode
+
+
+ def _wait(self, timeout):
+ """Internal implementation of wait() on Windows."""
+ if timeout is None:
+ timeout_millis = _winapi.INFINITE
+ else:
+ timeout_millis = int(timeout * 1000)
+ if self.returncode is None:
+ # API note: Returns immediately if timeout_millis == 0.
+ result = _winapi.WaitForSingleObject(self._handle,
+ timeout_millis)
+ if result == _winapi.WAIT_TIMEOUT:
+ raise TimeoutExpired(self.args, timeout)
+ self.returncode = _winapi.GetExitCodeProcess(self._handle)
+ return self.returncode
+
+
+ def _readerthread(self, fh, buffer):
+ buffer.append(fh.read())
+ fh.close()
+
+
+ def _communicate(self, input, endtime, orig_timeout):
+ # Start reader threads feeding into a list hanging off of this
+ # object, unless they've already been started.
+ if self.stdout and not hasattr(self, "_stdout_buff"):
+ self._stdout_buff = []
+ self.stdout_thread = \
+ threading.Thread(target=self._readerthread,
+ args=(self.stdout, self._stdout_buff))
+ self.stdout_thread.daemon = True
+ self.stdout_thread.start()
+ if self.stderr and not hasattr(self, "_stderr_buff"):
+ self._stderr_buff = []
+ self.stderr_thread = \
+ threading.Thread(target=self._readerthread,
+ args=(self.stderr, self._stderr_buff))
+ self.stderr_thread.daemon = True
+ self.stderr_thread.start()
+
+ if self.stdin:
+ self._stdin_write(input)
+
+ # Wait for the reader threads, or time out. If we time out, the
+ # threads remain reading and the fds left open in case the user
+ # calls communicate again.
+ if self.stdout is not None:
+ self.stdout_thread.join(self._remaining_time(endtime))
+ if self.stdout_thread.is_alive():
+ raise TimeoutExpired(self.args, orig_timeout)
+ if self.stderr is not None:
+ self.stderr_thread.join(self._remaining_time(endtime))
+ if self.stderr_thread.is_alive():
+ raise TimeoutExpired(self.args, orig_timeout)
+
+ # Collect the output from and close both pipes, now that we know
+ # both have been read successfully.
+ stdout = None
+ stderr = None
+ if self.stdout:
+ stdout = self._stdout_buff
+ self.stdout.close()
+ if self.stderr:
+ stderr = self._stderr_buff
+ self.stderr.close()
+
+ # All data exchanged. Translate lists into strings.
+ stdout = stdout[0] if stdout else None
+ stderr = stderr[0] if stderr else None
+
+ return (stdout, stderr)
+
+ def send_signal(self, sig):
+ """Send a signal to the process."""
+ # Don't signal a process that we know has already died.
+ if self.returncode is not None:
+ return
+ if sig == signal.SIGTERM:
+ self.terminate()
+ elif sig == signal.CTRL_C_EVENT:
+ os.kill(self.pid, signal.CTRL_C_EVENT)
+ elif sig == signal.CTRL_BREAK_EVENT:
+ os.kill(self.pid, signal.CTRL_BREAK_EVENT)
+ else:
+ raise ValueError("Unsupported signal: {}".format(sig))
+
+ def terminate(self):
+ """Terminates the process."""
+ # Don't terminate a process that we know has already died.
+ if self.returncode is not None:
+ return
+ try:
+ _winapi.TerminateProcess(self._handle, 1)
+ except PermissionError:
+ # ERROR_ACCESS_DENIED (winerror 5) is received when the
+ # process already died.
+ rc = _winapi.GetExitCodeProcess(self._handle)
+ if rc == _winapi.STILL_ACTIVE:
+ raise
+ self.returncode = rc
+
+ kill = terminate
+
+ else:
+ #
+ # POSIX methods
+ #
+ def _get_handles(self, stdin, stdout, stderr):
+ """Construct and return tuple with IO objects:
+ p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite
+ """
+ p2cread, p2cwrite = -1, -1
+ c2pread, c2pwrite = -1, -1
+ errread, errwrite = -1, -1
+
+ if stdin is None:
+ pass
+ elif stdin == PIPE:
+ p2cread, p2cwrite = os.pipe()
+ elif stdin == DEVNULL:
+ p2cread = self._get_devnull()
+ elif isinstance(stdin, int):
+ p2cread = stdin
+ else:
+ # Assuming file-like object
+ p2cread = stdin.fileno()
+
+ if stdout is None:
+ pass
+ elif stdout == PIPE:
+ c2pread, c2pwrite = os.pipe()
+ elif stdout == DEVNULL:
+ c2pwrite = self._get_devnull()
+ elif isinstance(stdout, int):
+ c2pwrite = stdout
+ else:
+ # Assuming file-like object
+ c2pwrite = stdout.fileno()
+
+ if stderr is None:
+ pass
+ elif stderr == PIPE:
+ errread, errwrite = os.pipe()
+ elif stderr == STDOUT:
+ if c2pwrite != -1:
+ errwrite = c2pwrite
+ else: # child's stdout is not set, use parent's stdout
+ errwrite = sys.__stdout__.fileno()
+ elif stderr == DEVNULL:
+ errwrite = self._get_devnull()
+ elif isinstance(stderr, int):
+ errwrite = stderr
+ else:
+ # Assuming file-like object
+ errwrite = stderr.fileno()
+
+ return (p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite)
+
+
+ def _posix_spawn(self, args, executable, env, restore_signals,
+ p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite):
+ """Execute program using os.posix_spawn()."""
+ if env is None:
+ env = os.environ
+
+ kwargs = {}
+ if restore_signals:
+ # See _Py_RestoreSignals() in Python/pylifecycle.c
+ sigset = []
+ for signame in ('SIGPIPE', 'SIGXFZ', 'SIGXFSZ'):
+ signum = getattr(signal, signame, None)
+ if signum is not None:
+ sigset.append(signum)
+ kwargs['setsigdef'] = sigset
+
+ file_actions = []
+ for fd in (p2cwrite, c2pread, errread):
+ if fd != -1:
+ file_actions.append((os.POSIX_SPAWN_CLOSE, fd))
+ for fd, fd2 in (
+ (p2cread, 0),
+ (c2pwrite, 1),
+ (errwrite, 2),
+ ):
+ if fd != -1:
+ file_actions.append((os.POSIX_SPAWN_DUP2, fd, fd2))
+ if file_actions:
+ kwargs['file_actions'] = file_actions
+
+ self.pid = os.posix_spawn(executable, args, env, **kwargs)
+ self._child_created = True
+
+ self._close_pipe_fds(p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite)
+
+ def _execute_child(self, args, executable, preexec_fn, close_fds,
+ pass_fds, cwd, env,
+ startupinfo, creationflags, shell,
+ p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite,
+ restore_signals, start_new_session):
+ """Execute program (POSIX version)"""
+
+ if isinstance(args, (str, bytes)):
+ args = [args]
+ elif isinstance(args, os.PathLike):
+ if shell:
+ raise TypeError('path-like args is not allowed when '
+ 'shell is true')
+ args = [args]
+ else:
+ args = list(args)
+
+ if shell:
+ # On Android the default shell is at '/system/bin/sh'.
+ unix_shell = ('/system/bin/sh' if
+ hasattr(sys, 'getandroidapilevel') else '/bin/sh')
+ args = [unix_shell, "-c"] + args
+ if executable:
+ args[0] = executable
+
+ if executable is None:
+ executable = args[0]
+
+ sys.audit("subprocess.Popen", executable, args, cwd, env)
+
+ if (_USE_POSIX_SPAWN
+ and os.path.dirname(executable)
+ and preexec_fn is None
+ and not close_fds
+ and not pass_fds
+ and cwd is None
+ and (p2cread == -1 or p2cread > 2)
+ and (c2pwrite == -1 or c2pwrite > 2)
+ and (errwrite == -1 or errwrite > 2)
+ and not start_new_session):
+ self._posix_spawn(args, executable, env, restore_signals,
+ p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite)
+ return
+
+ orig_executable = executable
+
+ # For transferring possible exec failure from child to parent.
+ # Data format: "exception name:hex errno:description"
+ # Pickle is not used; it is complex and involves memory allocation.
+ errpipe_read, errpipe_write = os.pipe()
+ # errpipe_write must not be in the standard io 0, 1, or 2 fd range.
+ low_fds_to_close = []
+ while errpipe_write < 3:
+ low_fds_to_close.append(errpipe_write)
+ errpipe_write = os.dup(errpipe_write)
+ for low_fd in low_fds_to_close:
+ os.close(low_fd)
+ try:
+ try:
+ # We must avoid complex work that could involve
+ # malloc or free in the child process to avoid
+ # potential deadlocks, thus we do all this here.
+ # and pass it to fork_exec()
+
+ if env is not None:
+ env_list = []
+ for k, v in env.items():
+ k = os.fsencode(k)
+ if b'=' in k:
+ raise ValueError("illegal environment variable name")
+ env_list.append(k + b'=' + os.fsencode(v))
+ else:
+ env_list = None # Use execv instead of execve.
+ executable = os.fsencode(executable)
+ if os.path.dirname(executable):
+ executable_list = (executable,)
+ else:
+ # This matches the behavior of os._execvpe().
+ executable_list = tuple(
+ os.path.join(os.fsencode(dir), executable)
+ for dir in os.get_exec_path(env))
+ fds_to_keep = set(pass_fds)
+ fds_to_keep.add(errpipe_write)
+ self.pid = _posixsubprocess.fork_exec(
+ args, executable_list,
+ close_fds, tuple(sorted(map(int, fds_to_keep))),
+ cwd, env_list,
+ p2cread, p2cwrite, c2pread, c2pwrite,
+ errread, errwrite,
+ errpipe_read, errpipe_write,
+ restore_signals, start_new_session, preexec_fn)
+ self._child_created = True
+ finally:
+ # be sure the FD is closed no matter what
+ os.close(errpipe_write)
+
+ self._close_pipe_fds(p2cread, p2cwrite,
+ c2pread, c2pwrite,
+ errread, errwrite)
+
+ # Wait for exec to fail or succeed; possibly raising an
+ # exception (limited in size)
+ errpipe_data = bytearray()
+ while True:
+ part = os.read(errpipe_read, 50000)
+ errpipe_data += part
+ if not part or len(errpipe_data) > 50000:
+ break
+ finally:
+ # be sure the FD is closed no matter what
+ os.close(errpipe_read)
+
+ if errpipe_data:
+ try:
+ pid, sts = os.waitpid(self.pid, 0)
+ if pid == self.pid:
+ self._handle_exitstatus(sts)
+ else:
+ self.returncode = sys.maxsize
+ except ChildProcessError:
+ pass
+
+ try:
+ exception_name, hex_errno, err_msg = (
+ errpipe_data.split(b':', 2))
+ # The encoding here should match the encoding
+ # written in by the subprocess implementations
+ # like _posixsubprocess
+ err_msg = err_msg.decode()
+ except ValueError:
+ exception_name = b'SubprocessError'
+ hex_errno = b'0'
+ err_msg = 'Bad exception data from child: {!r}'.format(
+ bytes(errpipe_data))
+ child_exception_type = getattr(
+ builtins, exception_name.decode('ascii'),
+ SubprocessError)
+ if issubclass(child_exception_type, OSError) and hex_errno:
+ errno_num = int(hex_errno, 16)
+ child_exec_never_called = (err_msg == "noexec")
+ if child_exec_never_called:
+ err_msg = ""
+ # The error must be from chdir(cwd).
+ err_filename = cwd
+ else:
+ err_filename = orig_executable
+ if errno_num != 0:
+ err_msg = os.strerror(errno_num)
+ raise child_exception_type(errno_num, err_msg, err_filename)
+ raise child_exception_type(err_msg)
+
+
+ def _handle_exitstatus(self, sts, _WIFSIGNALED=os.WIFSIGNALED,
+ _WTERMSIG=os.WTERMSIG, _WIFEXITED=os.WIFEXITED,
+ _WEXITSTATUS=os.WEXITSTATUS, _WIFSTOPPED=os.WIFSTOPPED,
+ _WSTOPSIG=os.WSTOPSIG):
+ """All callers to this function MUST hold self._waitpid_lock."""
+ # This method is called (indirectly) by __del__, so it cannot
+ # refer to anything outside of its local scope.
+ if _WIFSIGNALED(sts):
+ self.returncode = -_WTERMSIG(sts)
+ elif _WIFEXITED(sts):
+ self.returncode = _WEXITSTATUS(sts)
+ elif _WIFSTOPPED(sts):
+ self.returncode = -_WSTOPSIG(sts)
+ else:
+ # Should never happen
+ raise SubprocessError("Unknown child exit status!")
+
+
+ def _internal_poll(self, _deadstate=None, _waitpid=os.waitpid,
+ _WNOHANG=os.WNOHANG, _ECHILD=errno.ECHILD):
+ """Check if child process has terminated. Returns returncode
+ attribute.
+
+ This method is called by __del__, so it cannot reference anything
+ outside of the local scope (nor can any methods it calls).
+
+ """
+ if self.returncode is None:
+ if not self._waitpid_lock.acquire(False):
+ # Something else is busy calling waitpid. Don't allow two
+ # at once. We know nothing yet.
+ return None
+ try:
+ if self.returncode is not None:
+ return self.returncode # Another thread waited.
+ pid, sts = _waitpid(self.pid, _WNOHANG)
+ if pid == self.pid:
+ self._handle_exitstatus(sts)
+ except OSError as e:
+ if _deadstate is not None:
+ self.returncode = _deadstate
+ elif e.errno == _ECHILD:
+ # This happens if SIGCLD is set to be ignored or
+ # waiting for child processes has otherwise been
+ # disabled for our process. This child is dead, we
+ # can't get the status.
+ # http://bugs.python.org/issue15756
+ self.returncode = 0
+ finally:
+ self._waitpid_lock.release()
+ return self.returncode
+
+
+ def _try_wait(self, wait_flags):
+ """All callers to this function MUST hold self._waitpid_lock."""
+ try:
+ (pid, sts) = os.waitpid(self.pid, wait_flags)
+ except ChildProcessError:
+ # This happens if SIGCLD is set to be ignored or waiting
+ # for child processes has otherwise been disabled for our
+ # process. This child is dead, we can't get the status.
+ pid = self.pid
+ sts = 0
+ return (pid, sts)
+
+
+ def _wait(self, timeout):
+ """Internal implementation of wait() on POSIX."""
+ if self.returncode is not None:
+ return self.returncode
+
+ if timeout is not None:
+ endtime = _time() + timeout
+ # Enter a busy loop if we have a timeout. This busy loop was
+ # cribbed from Lib/threading.py in Thread.wait() at r71065.
+ delay = 0.0005 # 500 us -> initial delay of 1 ms
+ while True:
+ if self._waitpid_lock.acquire(False):
+ try:
+ if self.returncode is not None:
+ break # Another thread waited.
+ (pid, sts) = self._try_wait(os.WNOHANG)
+ assert pid == self.pid or pid == 0
+ if pid == self.pid:
+ self._handle_exitstatus(sts)
+ break
+ finally:
+ self._waitpid_lock.release()
+ remaining = self._remaining_time(endtime)
+ if remaining <= 0:
+ raise TimeoutExpired(self.args, timeout)
+ delay = min(delay * 2, remaining, .05)
+ time.sleep(delay)
+ else:
+ while self.returncode is None:
+ with self._waitpid_lock:
+ if self.returncode is not None:
+ break # Another thread waited.
+ (pid, sts) = self._try_wait(0)
+ # Check the pid and loop as waitpid has been known to
+ # return 0 even without WNOHANG in odd situations.
+ # http://bugs.python.org/issue14396.
+ if pid == self.pid:
+ self._handle_exitstatus(sts)
+ return self.returncode
+
+
+ def _communicate(self, input, endtime, orig_timeout):
+ if self.stdin and not self._communication_started:
+ # Flush stdio buffer. This might block, if the user has
+ # been writing to .stdin in an uncontrolled fashion.
+ try:
+ self.stdin.flush()
+ except BrokenPipeError:
+ pass # communicate() must ignore BrokenPipeError.
+ if not input:
+ try:
+ self.stdin.close()
+ except BrokenPipeError:
+ pass # communicate() must ignore BrokenPipeError.
+
+ stdout = None
+ stderr = None
+
+ # Only create this mapping if we haven't already.
+ if not self._communication_started:
+ self._fileobj2output = {}
+ if self.stdout:
+ self._fileobj2output[self.stdout] = []
+ if self.stderr:
+ self._fileobj2output[self.stderr] = []
+
+ if self.stdout:
+ stdout = self._fileobj2output[self.stdout]
+ if self.stderr:
+ stderr = self._fileobj2output[self.stderr]
+
+ self._save_input(input)
+
+ if self._input:
+ input_view = memoryview(self._input)
+
+ with _PopenSelector() as selector:
+ if self.stdin and input:
+ selector.register(self.stdin, selectors.EVENT_WRITE)
+ if self.stdout and not self.stdout.closed:
+ selector.register(self.stdout, selectors.EVENT_READ)
+ if self.stderr and not self.stderr.closed:
+ selector.register(self.stderr, selectors.EVENT_READ)
+
+ while selector.get_map():
+ timeout = self._remaining_time(endtime)
+ if timeout is not None and timeout < 0:
+ self._check_timeout(endtime, orig_timeout,
+ stdout, stderr,
+ skip_check_and_raise=True)
+ raise RuntimeError( # Impossible :)
+ '_check_timeout(..., skip_check_and_raise=True) '
+ 'failed to raise TimeoutExpired.')
+
+ ready = selector.select(timeout)
+ self._check_timeout(endtime, orig_timeout, stdout, stderr)
+
+ # XXX Rewrite these to use non-blocking I/O on the file
+ # objects; they are no longer using C stdio!
+
+ for key, events in ready:
+ if key.fileobj is self.stdin:
+ chunk = input_view[self._input_offset :
+ self._input_offset + _PIPE_BUF]
+ try:
+ self._input_offset += os.write(key.fd, chunk)
+ except BrokenPipeError:
+ selector.unregister(key.fileobj)
+ key.fileobj.close()
+ else:
+ if self._input_offset >= len(self._input):
+ selector.unregister(key.fileobj)
+ key.fileobj.close()
+ elif key.fileobj in (self.stdout, self.stderr):
+ data = os.read(key.fd, 32768)
+ if not data:
+ selector.unregister(key.fileobj)
+ key.fileobj.close()
+ self._fileobj2output[key.fileobj].append(data)
+
+ self.wait(timeout=self._remaining_time(endtime))
+
+ # All data exchanged. Translate lists into strings.
+ if stdout is not None:
+ stdout = b''.join(stdout)
+ if stderr is not None:
+ stderr = b''.join(stderr)
+
+ # Translate newlines, if requested.
+ # This also turns bytes into strings.
+ if self.text_mode:
+ if stdout is not None:
+ stdout = self._translate_newlines(stdout,
+ self.stdout.encoding,
+ self.stdout.errors)
+ if stderr is not None:
+ stderr = self._translate_newlines(stderr,
+ self.stderr.encoding,
+ self.stderr.errors)
+
+ return (stdout, stderr)
+
+
+ def _save_input(self, input):
+ # This method is called from the _communicate_with_*() methods
+ # so that if we time out while communicating, we can continue
+ # sending input if we retry.
+ if self.stdin and self._input is None:
+ self._input_offset = 0
+ self._input = input
+ if input is not None and self.text_mode:
+ self._input = self._input.encode(self.stdin.encoding,
+ self.stdin.errors)
+
+
+ def send_signal(self, sig):
+ """Send a signal to the process."""
+ # Skip signalling a process that we know has already died.
+ if self.returncode is None:
+ os.kill(self.pid, sig)
+
+ def terminate(self):
+ """Terminate the process with SIGTERM
+ """
+ self.send_signal(signal.SIGTERM)
+
+ def kill(self):
+ """Kill the process with SIGKILL
+ """
+ self.send_signal(signal.SIGKILL)
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/sysconfig.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/sysconfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..b4401c83aac7f564e7f125ecaf7337251d1e6532
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/sysconfig.py
@@ -0,0 +1,732 @@
+"""Access to Python's configuration information."""
+
+import os
+import sys
+from os.path import pardir, realpath
+
+__all__ = [
+ 'get_config_h_filename',
+ 'get_config_var',
+ 'get_config_vars',
+ 'get_makefile_filename',
+ 'get_path',
+ 'get_path_names',
+ 'get_paths',
+ 'get_platform',
+ 'get_python_version',
+ 'get_scheme_names',
+ 'parse_config_h',
+]
+
+# Keys for get_config_var() that are never converted to Python integers.
+_ALWAYS_STR = {
+ 'MACOSX_DEPLOYMENT_TARGET',
+}
+
+_INSTALL_SCHEMES = {
+ 'posix_prefix': {
+ 'stdlib': '{installed_base}/lib/python{py_version_short}',
+ 'platstdlib': '{platbase}/lib/python{py_version_short}',
+ 'purelib': '{base}/lib/python{py_version_short}/site-packages',
+ 'platlib': '{platbase}/lib/python{py_version_short}/site-packages',
+ 'include':
+ '{installed_base}/include/python{py_version_short}{abiflags}',
+ 'platinclude':
+ '{installed_platbase}/include/python{py_version_short}{abiflags}',
+ 'scripts': '{base}/bin',
+ 'data': '{base}',
+ },
+ 'posix_home': {
+ 'stdlib': '{installed_base}/lib/python',
+ 'platstdlib': '{base}/lib/python',
+ 'purelib': '{base}/lib/python',
+ 'platlib': '{base}/lib/python',
+ 'include': '{installed_base}/include/python',
+ 'platinclude': '{installed_base}/include/python',
+ 'scripts': '{base}/bin',
+ 'data': '{base}',
+ },
+ 'nt': {
+ 'stdlib': '{installed_base}/Lib',
+ 'platstdlib': '{base}/Lib',
+ 'purelib': '{base}/Lib/site-packages',
+ 'platlib': '{base}/Lib/site-packages',
+ 'include': '{installed_base}/Include',
+ 'platinclude': '{installed_base}/Include',
+ 'scripts': '{base}/Scripts',
+ 'data': '{base}',
+ },
+ # NOTE: When modifying "purelib" scheme, update site._get_path() too.
+ 'nt_user': {
+ 'stdlib': '{userbase}/Python{py_version_nodot}',
+ 'platstdlib': '{userbase}/Python{py_version_nodot}',
+ 'purelib': '{userbase}/Python{py_version_nodot}/site-packages',
+ 'platlib': '{userbase}/Python{py_version_nodot}/site-packages',
+ 'include': '{userbase}/Python{py_version_nodot}/Include',
+ 'scripts': '{userbase}/Python{py_version_nodot}/Scripts',
+ 'data': '{userbase}',
+ },
+ 'posix_user': {
+ 'stdlib': '{userbase}/lib/python{py_version_short}',
+ 'platstdlib': '{userbase}/lib/python{py_version_short}',
+ 'purelib': '{userbase}/lib/python{py_version_short}/site-packages',
+ 'platlib': '{userbase}/lib/python{py_version_short}/site-packages',
+ 'include': '{userbase}/include/python{py_version_short}',
+ 'scripts': '{userbase}/bin',
+ 'data': '{userbase}',
+ },
+ 'osx_framework_user': {
+ 'stdlib': '{userbase}/lib/python',
+ 'platstdlib': '{userbase}/lib/python',
+ 'purelib': '{userbase}/lib/python/site-packages',
+ 'platlib': '{userbase}/lib/python/site-packages',
+ 'include': '{userbase}/include',
+ 'scripts': '{userbase}/bin',
+ 'data': '{userbase}',
+ },
+ }
+
+_SCHEME_KEYS = ('stdlib', 'platstdlib', 'purelib', 'platlib', 'include',
+ 'scripts', 'data')
+
+ # FIXME don't rely on sys.version here, its format is an implementation detail
+ # of CPython, use sys.version_info or sys.hexversion
+_PY_VERSION = sys.version.split()[0]
+_PY_VERSION_SHORT = '%d.%d' % sys.version_info[:2]
+_PY_VERSION_SHORT_NO_DOT = '%d%d' % sys.version_info[:2]
+_PREFIX = os.path.normpath(sys.prefix)
+_BASE_PREFIX = os.path.normpath(sys.base_prefix)
+_EXEC_PREFIX = os.path.normpath(sys.exec_prefix)
+_BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix)
+_CONFIG_VARS = None
+_USER_BASE = None
+
+
+def _safe_realpath(path):
+ try:
+ return realpath(path)
+ except OSError:
+ return path
+
+if sys.executable:
+ _PROJECT_BASE = os.path.dirname(_safe_realpath(sys.executable))
+else:
+ # sys.executable can be empty if argv[0] has been changed and Python is
+ # unable to retrieve the real program name
+ _PROJECT_BASE = _safe_realpath(os.getcwd())
+
+if (os.name == 'nt' and
+ _PROJECT_BASE.lower().endswith(('\\pcbuild\\win32', '\\pcbuild\\amd64'))):
+ _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir))
+
+# set for cross builds
+if "_PYTHON_PROJECT_BASE" in os.environ:
+ _PROJECT_BASE = _safe_realpath(os.environ["_PYTHON_PROJECT_BASE"])
+
+def _is_python_source_dir(d):
+ for fn in ("Setup", "Setup.local"):
+ if os.path.isfile(os.path.join(d, "Modules", fn)):
+ return True
+ return False
+
+_sys_home = getattr(sys, '_home', None)
+
+if os.name == 'nt':
+ def _fix_pcbuild(d):
+ if d and os.path.normcase(d).startswith(
+ os.path.normcase(os.path.join(_PREFIX, "PCbuild"))):
+ return _PREFIX
+ return d
+ _PROJECT_BASE = _fix_pcbuild(_PROJECT_BASE)
+ _sys_home = _fix_pcbuild(_sys_home)
+
+def is_python_build(check_home=False):
+ if check_home and _sys_home:
+ return _is_python_source_dir(_sys_home)
+ return _is_python_source_dir(_PROJECT_BASE)
+
+_PYTHON_BUILD = is_python_build(True)
+
+if _PYTHON_BUILD:
+ for scheme in ('posix_prefix', 'posix_home'):
+ _INSTALL_SCHEMES[scheme]['include'] = '{srcdir}/Include'
+ _INSTALL_SCHEMES[scheme]['platinclude'] = '{projectbase}/.'
+
+
+def _subst_vars(s, local_vars):
+ try:
+ return s.format(**local_vars)
+ except KeyError:
+ try:
+ return s.format(**os.environ)
+ except KeyError as var:
+ raise AttributeError('{%s}' % var) from None
+
+def _extend_dict(target_dict, other_dict):
+ target_keys = target_dict.keys()
+ for key, value in other_dict.items():
+ if key in target_keys:
+ continue
+ target_dict[key] = value
+
+
+def _expand_vars(scheme, vars):
+ res = {}
+ if vars is None:
+ vars = {}
+ _extend_dict(vars, get_config_vars())
+
+ for key, value in _INSTALL_SCHEMES[scheme].items():
+ if os.name in ('posix', 'nt'):
+ value = os.path.expanduser(value)
+ res[key] = os.path.normpath(_subst_vars(value, vars))
+ return res
+
+
+def _get_default_scheme():
+ if os.name == 'posix':
+ # the default scheme for posix is posix_prefix
+ return 'posix_prefix'
+ return os.name
+
+
+# NOTE: site.py has copy of this function.
+# Sync it when modify this function.
+def _getuserbase():
+ env_base = os.environ.get("PYTHONUSERBASE", None)
+ if env_base:
+ return env_base
+
+ def joinuser(*args):
+ return os.path.expanduser(os.path.join(*args))
+
+ if os.name == "nt":
+ base = os.environ.get("APPDATA") or "~"
+ return joinuser(base, "Python")
+
+ if sys.platform == "darwin" and sys._framework:
+ return joinuser("~", "Library", sys._framework,
+ "%d.%d" % sys.version_info[:2])
+
+ return joinuser("~", ".local")
+
+
+def _parse_makefile(filename, vars=None):
+ """Parse a Makefile-style file.
+
+ A dictionary containing name/value pairs is returned. If an
+ optional dictionary is passed in as the second argument, it is
+ used instead of a new dictionary.
+ """
+ # Regexes needed for parsing Makefile (and similar syntaxes,
+ # like old-style Setup files).
+ import re
+ _variable_rx = re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)")
+ _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)")
+ _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}")
+
+ if vars is None:
+ vars = {}
+ done = {}
+ notdone = {}
+
+ with open(filename, errors="surrogateescape") as f:
+ lines = f.readlines()
+
+ for line in lines:
+ if line.startswith('#') or line.strip() == '':
+ continue
+ m = _variable_rx.match(line)
+ if m:
+ n, v = m.group(1, 2)
+ v = v.strip()
+ # `$$' is a literal `$' in make
+ tmpv = v.replace('$$', '')
+
+ if "$" in tmpv:
+ notdone[n] = v
+ else:
+ try:
+ if n in _ALWAYS_STR:
+ raise ValueError
+
+ v = int(v)
+ except ValueError:
+ # insert literal `$'
+ done[n] = v.replace('$$', '$')
+ else:
+ done[n] = v
+
+ # do variable interpolation here
+ variables = list(notdone.keys())
+
+ # Variables with a 'PY_' prefix in the makefile. These need to
+ # be made available without that prefix through sysconfig.
+ # Special care is needed to ensure that variable expansion works, even
+ # if the expansion uses the name without a prefix.
+ renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS')
+
+ while len(variables) > 0:
+ for name in tuple(variables):
+ value = notdone[name]
+ m1 = _findvar1_rx.search(value)
+ m2 = _findvar2_rx.search(value)
+ if m1 and m2:
+ m = m1 if m1.start() < m2.start() else m2
+ else:
+ m = m1 if m1 else m2
+ if m is not None:
+ n = m.group(1)
+ found = True
+ if n in done:
+ item = str(done[n])
+ elif n in notdone:
+ # get it on a subsequent round
+ found = False
+ elif n in os.environ:
+ # do it like make: fall back to environment
+ item = os.environ[n]
+
+ elif n in renamed_variables:
+ if (name.startswith('PY_') and
+ name[3:] in renamed_variables):
+ item = ""
+
+ elif 'PY_' + n in notdone:
+ found = False
+
+ else:
+ item = str(done['PY_' + n])
+
+ else:
+ done[n] = item = ""
+
+ if found:
+ after = value[m.end():]
+ value = value[:m.start()] + item + after
+ if "$" in after:
+ notdone[name] = value
+ else:
+ try:
+ if name in _ALWAYS_STR:
+ raise ValueError
+ value = int(value)
+ except ValueError:
+ done[name] = value.strip()
+ else:
+ done[name] = value
+ variables.remove(name)
+
+ if name.startswith('PY_') \
+ and name[3:] in renamed_variables:
+
+ name = name[3:]
+ if name not in done:
+ done[name] = value
+
+ else:
+ # bogus variable reference (e.g. "prefix=$/opt/python");
+ # just drop it since we can't deal
+ done[name] = value
+ variables.remove(name)
+
+ # strip spurious spaces
+ for k, v in done.items():
+ if isinstance(v, str):
+ done[k] = v.strip()
+
+ # save the results in the global dictionary
+ vars.update(done)
+ return vars
+
+
+def get_makefile_filename():
+ """Return the path of the Makefile."""
+ if _PYTHON_BUILD:
+ return os.path.join(_sys_home or _PROJECT_BASE, "Makefile")
+ if hasattr(sys, 'abiflags'):
+ config_dir_name = 'config-%s%s' % (_PY_VERSION_SHORT, sys.abiflags)
+ else:
+ config_dir_name = 'config'
+ if hasattr(sys.implementation, '_multiarch'):
+ config_dir_name += '-%s' % sys.implementation._multiarch
+ return os.path.join(get_path('stdlib'), config_dir_name, 'Makefile')
+
+
+def _get_sysconfigdata_name(check_exists=False):
+ for envvar in ('_PYTHON_SYSCONFIGDATA_NAME', '_CONDA_PYTHON_SYSCONFIGDATA_NAME'):
+ res = os.environ.get(envvar, None)
+ if res and check_exists:
+ try:
+ import importlib.util
+ loader = importlib.util.find_spec(res)
+ except:
+ res = None
+ if res:
+ return res
+ return '_sysconfigdata_{abi}_{platform}_{multiarch}'.format(
+ abi=sys.abiflags,
+ platform=sys.platform,
+ multiarch=getattr(sys.implementation, '_multiarch', ''))
+
+
+def _generate_posix_vars():
+ """Generate the Python module containing build-time variables."""
+ import pprint
+ vars = {}
+ # load the installed Makefile:
+ makefile = get_makefile_filename()
+ try:
+ _parse_makefile(makefile, vars)
+ except OSError as e:
+ msg = "invalid Python installation: unable to open %s" % makefile
+ if hasattr(e, "strerror"):
+ msg = msg + " (%s)" % e.strerror
+ raise OSError(msg)
+ # load the installed pyconfig.h:
+ config_h = get_config_h_filename()
+ try:
+ with open(config_h) as f:
+ parse_config_h(f, vars)
+ except OSError as e:
+ msg = "invalid Python installation: unable to open %s" % config_h
+ if hasattr(e, "strerror"):
+ msg = msg + " (%s)" % e.strerror
+ raise OSError(msg)
+ # On AIX, there are wrong paths to the linker scripts in the Makefile
+ # -- these paths are relative to the Python source, but when installed
+ # the scripts are in another directory.
+ if _PYTHON_BUILD:
+ vars['BLDSHARED'] = vars['LDSHARED']
+
+ # There's a chicken-and-egg situation on OS X with regards to the
+ # _sysconfigdata module after the changes introduced by #15298:
+ # get_config_vars() is called by get_platform() as part of the
+ # `make pybuilddir.txt` target -- which is a precursor to the
+ # _sysconfigdata.py module being constructed. Unfortunately,
+ # get_config_vars() eventually calls _init_posix(), which attempts
+ # to import _sysconfigdata, which we won't have built yet. In order
+ # for _init_posix() to work, if we're on Darwin, just mock up the
+ # _sysconfigdata module manually and populate it with the build vars.
+ # This is more than sufficient for ensuring the subsequent call to
+ # get_platform() succeeds.
+ name = _get_sysconfigdata_name()
+ if 'darwin' in sys.platform:
+ import types
+ module = types.ModuleType(name)
+ module.build_time_vars = vars
+ sys.modules[name] = module
+
+ pybuilddir = 'build/lib.%s-%s' % (get_platform(), _PY_VERSION_SHORT)
+ if hasattr(sys, "gettotalrefcount"):
+ pybuilddir += '-pydebug'
+ os.makedirs(pybuilddir, exist_ok=True)
+ destfile = os.path.join(pybuilddir, name + '.py')
+
+ with open(destfile, 'w', encoding='utf8') as f:
+ f.write('# system configuration generated and used by'
+ ' the sysconfig module\n')
+ f.write('build_time_vars = ')
+ pprint.pprint(vars, stream=f)
+
+ # Create file used for sys.path fixup -- see Modules/getpath.c
+ with open('pybuilddir.txt', 'w', encoding='utf8') as f:
+ f.write(pybuilddir)
+
+def _init_posix(vars):
+ """Initialize the module as appropriate for POSIX systems."""
+ # _sysconfigdata is generated at build time, see _generate_posix_vars()
+ name = _get_sysconfigdata_name(True)
+ _temp = __import__(name, globals(), locals(), ['build_time_vars'], 0)
+ build_time_vars = _temp.build_time_vars
+ vars.update(build_time_vars)
+
+def _init_non_posix(vars):
+ """Initialize the module as appropriate for NT"""
+ # set basic install directories
+ import _imp
+ vars['LIBDEST'] = get_path('stdlib')
+ vars['BINLIBDEST'] = get_path('platstdlib')
+ vars['INCLUDEPY'] = get_path('include')
+ vars['EXT_SUFFIX'] = _imp.extension_suffixes()[0]
+ vars['EXE'] = '.exe'
+ vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT
+ vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable))
+
+#
+# public APIs
+#
+
+
+def parse_config_h(fp, vars=None):
+ """Parse a config.h-style file.
+
+ A dictionary containing name/value pairs is returned. If an
+ optional dictionary is passed in as the second argument, it is
+ used instead of a new dictionary.
+ """
+ if vars is None:
+ vars = {}
+ import re
+ define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n")
+ undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n")
+
+ while True:
+ line = fp.readline()
+ if not line:
+ break
+ m = define_rx.match(line)
+ if m:
+ n, v = m.group(1, 2)
+ try:
+ if n in _ALWAYS_STR:
+ raise ValueError
+ v = int(v)
+ except ValueError:
+ pass
+ vars[n] = v
+ else:
+ m = undef_rx.match(line)
+ if m:
+ vars[m.group(1)] = 0
+ return vars
+
+
+def get_config_h_filename():
+ """Return the path of pyconfig.h."""
+ if _PYTHON_BUILD:
+ if os.name == "nt":
+ inc_dir = os.path.join(_sys_home or _PROJECT_BASE, "PC")
+ else:
+ inc_dir = _sys_home or _PROJECT_BASE
+ else:
+ inc_dir = get_path('platinclude')
+ return os.path.join(inc_dir, 'pyconfig.h')
+
+
+def get_scheme_names():
+ """Return a tuple containing the schemes names."""
+ return tuple(sorted(_INSTALL_SCHEMES))
+
+
+def get_path_names():
+ """Return a tuple containing the paths names."""
+ return _SCHEME_KEYS
+
+
+def get_paths(scheme=_get_default_scheme(), vars=None, expand=True):
+ """Return a mapping containing an install scheme.
+
+ ``scheme`` is the install scheme name. If not provided, it will
+ return the default scheme for the current platform.
+ """
+ if expand:
+ return _expand_vars(scheme, vars)
+ else:
+ return _INSTALL_SCHEMES[scheme]
+
+
+def get_path(name, scheme=_get_default_scheme(), vars=None, expand=True):
+ """Return a path corresponding to the scheme.
+
+ ``scheme`` is the install scheme name.
+ """
+ return get_paths(scheme, vars, expand)[name]
+
+
+def get_config_vars(*args):
+ """With no arguments, return a dictionary of all configuration
+ variables relevant for the current platform.
+
+ On Unix, this means every variable defined in Python's installed Makefile;
+ On Windows it's a much smaller set.
+
+ With arguments, return a list of values that result from looking up
+ each argument in the configuration variable dictionary.
+ """
+ global _CONFIG_VARS
+ if _CONFIG_VARS is None:
+ _CONFIG_VARS = {}
+ # Normalized versions of prefix and exec_prefix are handy to have;
+ # in fact, these are the standard versions used most places in the
+ # Distutils.
+ _CONFIG_VARS['prefix'] = _PREFIX
+ _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX
+ _CONFIG_VARS['py_version'] = _PY_VERSION
+ _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT
+ _CONFIG_VARS['py_version_nodot'] = _PY_VERSION_SHORT_NO_DOT
+ _CONFIG_VARS['installed_base'] = _BASE_PREFIX
+ _CONFIG_VARS['base'] = _PREFIX
+ _CONFIG_VARS['installed_platbase'] = _BASE_EXEC_PREFIX
+ _CONFIG_VARS['platbase'] = _EXEC_PREFIX
+ _CONFIG_VARS['projectbase'] = _PROJECT_BASE
+ try:
+ _CONFIG_VARS['abiflags'] = sys.abiflags
+ except AttributeError:
+ # sys.abiflags may not be defined on all platforms.
+ _CONFIG_VARS['abiflags'] = ''
+
+ if os.name == 'nt':
+ _init_non_posix(_CONFIG_VARS)
+ if os.name == 'posix':
+ _init_posix(_CONFIG_VARS)
+ # For backward compatibility, see issue19555
+ SO = _CONFIG_VARS.get('EXT_SUFFIX')
+ if SO is not None:
+ _CONFIG_VARS['SO'] = SO
+ # Setting 'userbase' is done below the call to the
+ # init function to enable using 'get_config_var' in
+ # the init-function.
+ _CONFIG_VARS['userbase'] = _getuserbase()
+
+ # Always convert srcdir to an absolute path
+ srcdir = _CONFIG_VARS.get('srcdir', _PROJECT_BASE)
+ if os.name == 'posix':
+ if _PYTHON_BUILD:
+ # If srcdir is a relative path (typically '.' or '..')
+ # then it should be interpreted relative to the directory
+ # containing Makefile.
+ base = os.path.dirname(get_makefile_filename())
+ srcdir = os.path.join(base, srcdir)
+ else:
+ # srcdir is not meaningful since the installation is
+ # spread about the filesystem. We choose the
+ # directory containing the Makefile since we know it
+ # exists.
+ srcdir = os.path.dirname(get_makefile_filename())
+ _CONFIG_VARS['srcdir'] = _safe_realpath(srcdir)
+
+ # OS X platforms require special customization to handle
+ # multi-architecture, multi-os-version installers
+ if sys.platform == 'darwin':
+ import _osx_support
+ _osx_support.customize_config_vars(_CONFIG_VARS)
+
+ if args:
+ vals = []
+ for name in args:
+ vals.append(_CONFIG_VARS.get(name))
+ return vals
+ else:
+ return _CONFIG_VARS
+
+
+def get_config_var(name):
+ """Return the value of a single variable using the dictionary returned by
+ 'get_config_vars()'.
+
+ Equivalent to get_config_vars().get(name)
+ """
+ if name == 'SO':
+ import warnings
+ warnings.warn('SO is deprecated, use EXT_SUFFIX', DeprecationWarning, 2)
+ return get_config_vars().get(name)
+
+
+def get_platform():
+ """Return a string that identifies the current platform.
+
+ This is used mainly to distinguish platform-specific build directories and
+ platform-specific built distributions. Typically includes the OS name and
+ version and the architecture (as supplied by 'os.uname()'), although the
+ exact information included depends on the OS; on Linux, the kernel version
+ isn't particularly important.
+
+ Examples of returned values:
+ linux-i586
+ linux-alpha (?)
+ solaris-2.6-sun4u
+
+ Windows will return one of:
+ win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc)
+ win32 (all others - specifically, sys.platform is returned)
+
+ For other non-POSIX platforms, currently just returns 'sys.platform'.
+
+ """
+ if os.name == 'nt':
+ if 'amd64' in sys.version.lower():
+ return 'win-amd64'
+ if '(arm)' in sys.version.lower():
+ return 'win-arm32'
+ if '(arm64)' in sys.version.lower():
+ return 'win-arm64'
+ return sys.platform
+
+ if os.name != "posix" or not hasattr(os, 'uname'):
+ # XXX what about the architecture? NT is Intel or Alpha
+ return sys.platform
+
+ # Set for cross builds explicitly
+ if "_PYTHON_HOST_PLATFORM" in os.environ:
+ return os.environ["_PYTHON_HOST_PLATFORM"]
+
+ # Try to distinguish various flavours of Unix
+ osname, host, release, version, machine = os.uname()
+
+ # Convert the OS name to lowercase, remove '/' characters, and translate
+ # spaces (for "Power Macintosh")
+ osname = osname.lower().replace('/', '')
+ machine = machine.replace(' ', '_')
+ machine = machine.replace('/', '-')
+
+ if osname[:5] == "linux":
+ # At least on Linux/Intel, 'machine' is the processor --
+ # i386, etc.
+ # XXX what about Alpha, SPARC, etc?
+ return "%s-%s" % (osname, machine)
+ elif osname[:5] == "sunos":
+ if release[0] >= "5": # SunOS 5 == Solaris 2
+ osname = "solaris"
+ release = "%d.%s" % (int(release[0]) - 3, release[2:])
+ # We can't use "platform.architecture()[0]" because a
+ # bootstrap problem. We use a dict to get an error
+ # if some suspicious happens.
+ bitness = {2147483647:"32bit", 9223372036854775807:"64bit"}
+ machine += ".%s" % bitness[sys.maxsize]
+ # fall through to standard osname-release-machine representation
+ elif osname[:3] == "aix":
+ return "%s-%s.%s" % (osname, version, release)
+ elif osname[:6] == "cygwin":
+ osname = "cygwin"
+ import re
+ rel_re = re.compile(r'[\d.]+')
+ m = rel_re.match(release)
+ if m:
+ release = m.group()
+ elif osname[:6] == "darwin":
+ import _osx_support
+ osname, release, machine = _osx_support.get_platform_osx(
+ get_config_vars(),
+ osname, release, machine)
+
+ return "%s-%s-%s" % (osname, release, machine)
+
+
+def get_python_version():
+ return _PY_VERSION_SHORT
+
+
+def _print_dict(title, data):
+ for index, (key, value) in enumerate(sorted(data.items())):
+ if index == 0:
+ print('%s: ' % (title))
+ print('\t%s = "%s"' % (key, value))
+
+
+def _main():
+ """Display all information sysconfig detains."""
+ if '--generate-posix-vars' in sys.argv:
+ _generate_posix_vars()
+ return
+ print('Platform: "%s"' % get_platform())
+ print('Python version: "%s"' % get_python_version())
+ print('Current installation scheme: "%s"' % _get_default_scheme())
+ print()
+ _print_dict('Paths', get_paths())
+ print()
+ _print_dict('Variables', get_config_vars())
+
+
+if __name__ == '__main__':
+ _main()
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/tempfile.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/tempfile.py
new file mode 100644
index 0000000000000000000000000000000000000000..8f9cb6c3ca350041765821969d025c45424b7144
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/tempfile.py
@@ -0,0 +1,831 @@
+"""Temporary files.
+
+This module provides generic, low- and high-level interfaces for
+creating temporary files and directories. All of the interfaces
+provided by this module can be used without fear of race conditions
+except for 'mktemp'. 'mktemp' is subject to race conditions and
+should not be used; it is provided for backward compatibility only.
+
+The default path names are returned as str. If you supply bytes as
+input, all return values will be in bytes. Ex:
+
+ >>> tempfile.mkstemp()
+ (4, '/tmp/tmptpu9nin8')
+ >>> tempfile.mkdtemp(suffix=b'')
+ b'/tmp/tmppbi8f0hy'
+
+This module also provides some data items to the user:
+
+ TMP_MAX - maximum number of names that will be tried before
+ giving up.
+ tempdir - If this is set to a string before the first use of
+ any routine from this module, it will be considered as
+ another candidate location to store temporary files.
+"""
+
+__all__ = [
+ "NamedTemporaryFile", "TemporaryFile", # high level safe interfaces
+ "SpooledTemporaryFile", "TemporaryDirectory",
+ "mkstemp", "mkdtemp", # low level safe interfaces
+ "mktemp", # deprecated unsafe interface
+ "TMP_MAX", "gettempprefix", # constants
+ "tempdir", "gettempdir",
+ "gettempprefixb", "gettempdirb",
+ ]
+
+
+# Imports.
+
+import functools as _functools
+import warnings as _warnings
+import io as _io
+import os as _os
+import shutil as _shutil
+import errno as _errno
+from random import Random as _Random
+import sys as _sys
+import weakref as _weakref
+import _thread
+_allocate_lock = _thread.allocate_lock
+
+_text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL
+if hasattr(_os, 'O_NOFOLLOW'):
+ _text_openflags |= _os.O_NOFOLLOW
+
+_bin_openflags = _text_openflags
+if hasattr(_os, 'O_BINARY'):
+ _bin_openflags |= _os.O_BINARY
+
+if hasattr(_os, 'TMP_MAX'):
+ TMP_MAX = _os.TMP_MAX
+else:
+ TMP_MAX = 10000
+
+# This variable _was_ unused for legacy reasons, see issue 10354.
+# But as of 3.5 we actually use it at runtime so changing it would
+# have a possibly desirable side effect... But we do not want to support
+# that as an API. It is undocumented on purpose. Do not depend on this.
+template = "tmp"
+
+# Internal routines.
+
+_once_lock = _allocate_lock()
+
+
+def _exists(fn):
+ try:
+ _os.lstat(fn)
+ except OSError:
+ return False
+ else:
+ return True
+
+
+def _infer_return_type(*args):
+ """Look at the type of all args and divine their implied return type."""
+ return_type = None
+ for arg in args:
+ if arg is None:
+ continue
+ if isinstance(arg, bytes):
+ if return_type is str:
+ raise TypeError("Can't mix bytes and non-bytes in "
+ "path components.")
+ return_type = bytes
+ else:
+ if return_type is bytes:
+ raise TypeError("Can't mix bytes and non-bytes in "
+ "path components.")
+ return_type = str
+ if return_type is None:
+ return str # tempfile APIs return a str by default.
+ return return_type
+
+
+def _sanitize_params(prefix, suffix, dir):
+ """Common parameter processing for most APIs in this module."""
+ output_type = _infer_return_type(prefix, suffix, dir)
+ if suffix is None:
+ suffix = output_type()
+ if prefix is None:
+ if output_type is str:
+ prefix = template
+ else:
+ prefix = _os.fsencode(template)
+ if dir is None:
+ if output_type is str:
+ dir = gettempdir()
+ else:
+ dir = gettempdirb()
+ return prefix, suffix, dir, output_type
+
+
+class _RandomNameSequence:
+ """An instance of _RandomNameSequence generates an endless
+ sequence of unpredictable strings which can safely be incorporated
+ into file names. Each string is eight characters long. Multiple
+ threads can safely use the same instance at the same time.
+
+ _RandomNameSequence is an iterator."""
+
+ characters = "abcdefghijklmnopqrstuvwxyz0123456789_"
+
+ @property
+ def rng(self):
+ cur_pid = _os.getpid()
+ if cur_pid != getattr(self, '_rng_pid', None):
+ self._rng = _Random()
+ self._rng_pid = cur_pid
+ return self._rng
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ c = self.characters
+ choose = self.rng.choice
+ letters = [choose(c) for dummy in range(8)]
+ return ''.join(letters)
+
+def _candidate_tempdir_list():
+ """Generate a list of candidate temporary directories which
+ _get_default_tempdir will try."""
+
+ dirlist = []
+
+ # First, try the environment.
+ for envname in 'TMPDIR', 'TEMP', 'TMP':
+ dirname = _os.getenv(envname)
+ if dirname: dirlist.append(dirname)
+
+ # Failing that, try OS-specific locations.
+ if _os.name == 'nt':
+ dirlist.extend([ _os.path.expanduser(r'~\AppData\Local\Temp'),
+ _os.path.expandvars(r'%SYSTEMROOT%\Temp'),
+ r'c:\temp', r'c:\tmp', r'\temp', r'\tmp' ])
+ else:
+ dirlist.extend([ '/tmp', '/var/tmp', '/usr/tmp' ])
+
+ # As a last resort, the current directory.
+ try:
+ dirlist.append(_os.getcwd())
+ except (AttributeError, OSError):
+ dirlist.append(_os.curdir)
+
+ return dirlist
+
+def _get_default_tempdir():
+ """Calculate the default directory to use for temporary files.
+ This routine should be called exactly once.
+
+ We determine whether or not a candidate temp dir is usable by
+ trying to create and write to a file in that directory. If this
+ is successful, the test file is deleted. To prevent denial of
+ service, the name of the test file must be randomized."""
+
+ namer = _RandomNameSequence()
+ dirlist = _candidate_tempdir_list()
+
+ for dir in dirlist:
+ if dir != _os.curdir:
+ dir = _os.path.abspath(dir)
+ # Try only a few names per directory.
+ for seq in range(100):
+ name = next(namer)
+ filename = _os.path.join(dir, name)
+ try:
+ fd = _os.open(filename, _bin_openflags, 0o600)
+ try:
+ try:
+ with _io.open(fd, 'wb', closefd=False) as fp:
+ fp.write(b'blat')
+ finally:
+ _os.close(fd)
+ finally:
+ _os.unlink(filename)
+ return dir
+ except FileExistsError:
+ pass
+ except PermissionError:
+ # This exception is thrown when a directory with the chosen name
+ # already exists on windows.
+ if (_os.name == 'nt' and _os.path.isdir(dir) and
+ _os.access(dir, _os.W_OK)):
+ continue
+ break # no point trying more names in this directory
+ except OSError:
+ break # no point trying more names in this directory
+ raise FileNotFoundError(_errno.ENOENT,
+ "No usable temporary directory found in %s" %
+ dirlist)
+
+_name_sequence = None
+
+def _get_candidate_names():
+ """Common setup sequence for all user-callable interfaces."""
+
+ global _name_sequence
+ if _name_sequence is None:
+ _once_lock.acquire()
+ try:
+ if _name_sequence is None:
+ _name_sequence = _RandomNameSequence()
+ finally:
+ _once_lock.release()
+ return _name_sequence
+
+
+def _mkstemp_inner(dir, pre, suf, flags, output_type):
+ """Code common to mkstemp, TemporaryFile, and NamedTemporaryFile."""
+
+ names = _get_candidate_names()
+ if output_type is bytes:
+ names = map(_os.fsencode, names)
+
+ for seq in range(TMP_MAX):
+ name = next(names)
+ file = _os.path.join(dir, pre + name + suf)
+ _sys.audit("tempfile.mkstemp", file)
+ try:
+ fd = _os.open(file, flags, 0o600)
+ except FileExistsError:
+ continue # try again
+ except PermissionError:
+ # This exception is thrown when a directory with the chosen name
+ # already exists on windows.
+ if (_os.name == 'nt' and _os.path.isdir(dir) and
+ _os.access(dir, _os.W_OK)):
+ continue
+ else:
+ raise
+ return (fd, _os.path.abspath(file))
+
+ raise FileExistsError(_errno.EEXIST,
+ "No usable temporary file name found")
+
+
+# User visible interfaces.
+
+def gettempprefix():
+ """The default prefix for temporary directories."""
+ return template
+
+def gettempprefixb():
+ """The default prefix for temporary directories as bytes."""
+ return _os.fsencode(gettempprefix())
+
+tempdir = None
+
+def gettempdir():
+ """Accessor for tempfile.tempdir."""
+ global tempdir
+ if tempdir is None:
+ _once_lock.acquire()
+ try:
+ if tempdir is None:
+ tempdir = _get_default_tempdir()
+ finally:
+ _once_lock.release()
+ return tempdir
+
+def gettempdirb():
+ """A bytes version of tempfile.gettempdir()."""
+ return _os.fsencode(gettempdir())
+
+def mkstemp(suffix=None, prefix=None, dir=None, text=False):
+ """User-callable function to create and return a unique temporary
+ file. The return value is a pair (fd, name) where fd is the
+ file descriptor returned by os.open, and name is the filename.
+
+ If 'suffix' is not None, the file name will end with that suffix,
+ otherwise there will be no suffix.
+
+ If 'prefix' is not None, the file name will begin with that prefix,
+ otherwise a default prefix is used.
+
+ If 'dir' is not None, the file will be created in that directory,
+ otherwise a default directory is used.
+
+ If 'text' is specified and true, the file is opened in text
+ mode. Else (the default) the file is opened in binary mode.
+
+ If any of 'suffix', 'prefix' and 'dir' are not None, they must be the
+ same type. If they are bytes, the returned name will be bytes; str
+ otherwise.
+
+ The file is readable and writable only by the creating user ID.
+ If the operating system uses permission bits to indicate whether a
+ file is executable, the file is executable by no one. The file
+ descriptor is not inherited by children of this process.
+
+ Caller is responsible for deleting the file when done with it.
+ """
+
+ prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir)
+
+ if text:
+ flags = _text_openflags
+ else:
+ flags = _bin_openflags
+
+ return _mkstemp_inner(dir, prefix, suffix, flags, output_type)
+
+
+def mkdtemp(suffix=None, prefix=None, dir=None):
+ """User-callable function to create and return a unique temporary
+ directory. The return value is the pathname of the directory.
+
+ Arguments are as for mkstemp, except that the 'text' argument is
+ not accepted.
+
+ The directory is readable, writable, and searchable only by the
+ creating user.
+
+ Caller is responsible for deleting the directory when done with it.
+ """
+
+ prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir)
+
+ names = _get_candidate_names()
+ if output_type is bytes:
+ names = map(_os.fsencode, names)
+
+ for seq in range(TMP_MAX):
+ name = next(names)
+ file = _os.path.join(dir, prefix + name + suffix)
+ _sys.audit("tempfile.mkdtemp", file)
+ try:
+ _os.mkdir(file, 0o700)
+ except FileExistsError:
+ continue # try again
+ except PermissionError:
+ # This exception is thrown when a directory with the chosen name
+ # already exists on windows.
+ if (_os.name == 'nt' and _os.path.isdir(dir) and
+ _os.access(dir, _os.W_OK)):
+ continue
+ else:
+ raise
+ return file
+
+ raise FileExistsError(_errno.EEXIST,
+ "No usable temporary directory name found")
+
+def mktemp(suffix="", prefix=template, dir=None):
+ """User-callable function to return a unique temporary file name. The
+ file is not created.
+
+ Arguments are similar to mkstemp, except that the 'text' argument is
+ not accepted, and suffix=None, prefix=None and bytes file names are not
+ supported.
+
+ THIS FUNCTION IS UNSAFE AND SHOULD NOT BE USED. The file name may
+ refer to a file that did not exist at some point, but by the time
+ you get around to creating it, someone else may have beaten you to
+ the punch.
+ """
+
+## from warnings import warn as _warn
+## _warn("mktemp is a potential security risk to your program",
+## RuntimeWarning, stacklevel=2)
+
+ if dir is None:
+ dir = gettempdir()
+
+ names = _get_candidate_names()
+ for seq in range(TMP_MAX):
+ name = next(names)
+ file = _os.path.join(dir, prefix + name + suffix)
+ if not _exists(file):
+ return file
+
+ raise FileExistsError(_errno.EEXIST,
+ "No usable temporary filename found")
+
+
+class _TemporaryFileCloser:
+ """A separate object allowing proper closing of a temporary file's
+ underlying file object, without adding a __del__ method to the
+ temporary file."""
+
+ file = None # Set here since __del__ checks it
+ close_called = False
+
+ def __init__(self, file, name, delete=True):
+ self.file = file
+ self.name = name
+ self.delete = delete
+
+ # NT provides delete-on-close as a primitive, so we don't need
+ # the wrapper to do anything special. We still use it so that
+ # file.name is useful (i.e. not "(fdopen)") with NamedTemporaryFile.
+ if _os.name != 'nt':
+ # Cache the unlinker so we don't get spurious errors at
+ # shutdown when the module-level "os" is None'd out. Note
+ # that this must be referenced as self.unlink, because the
+ # name TemporaryFileWrapper may also get None'd out before
+ # __del__ is called.
+
+ def close(self, unlink=_os.unlink):
+ if not self.close_called and self.file is not None:
+ self.close_called = True
+ try:
+ self.file.close()
+ finally:
+ if self.delete:
+ unlink(self.name)
+
+ # Need to ensure the file is deleted on __del__
+ def __del__(self):
+ self.close()
+
+ else:
+ def close(self):
+ if not self.close_called:
+ self.close_called = True
+ self.file.close()
+
+
+class _TemporaryFileWrapper:
+ """Temporary file wrapper
+
+ This class provides a wrapper around files opened for
+ temporary use. In particular, it seeks to automatically
+ remove the file when it is no longer needed.
+ """
+
+ def __init__(self, file, name, delete=True):
+ self.file = file
+ self.name = name
+ self.delete = delete
+ self._closer = _TemporaryFileCloser(file, name, delete)
+
+ def __getattr__(self, name):
+ # Attribute lookups are delegated to the underlying file
+ # and cached for non-numeric results
+ # (i.e. methods are cached, closed and friends are not)
+ file = self.__dict__['file']
+ a = getattr(file, name)
+ if hasattr(a, '__call__'):
+ func = a
+ @_functools.wraps(func)
+ def func_wrapper(*args, **kwargs):
+ return func(*args, **kwargs)
+ # Avoid closing the file as long as the wrapper is alive,
+ # see issue #18879.
+ func_wrapper._closer = self._closer
+ a = func_wrapper
+ if not isinstance(a, int):
+ setattr(self, name, a)
+ return a
+
+ # The underlying __enter__ method returns the wrong object
+ # (self.file) so override it to return the wrapper
+ def __enter__(self):
+ self.file.__enter__()
+ return self
+
+ # Need to trap __exit__ as well to ensure the file gets
+ # deleted when used in a with statement
+ def __exit__(self, exc, value, tb):
+ result = self.file.__exit__(exc, value, tb)
+ self.close()
+ return result
+
+ def close(self):
+ """
+ Close the temporary file, possibly deleting it.
+ """
+ self._closer.close()
+
+ # iter() doesn't use __getattr__ to find the __iter__ method
+ def __iter__(self):
+ # Don't return iter(self.file), but yield from it to avoid closing
+ # file as long as it's being used as iterator (see issue #23700). We
+ # can't use 'yield from' here because iter(file) returns the file
+ # object itself, which has a close method, and thus the file would get
+ # closed when the generator is finalized, due to PEP380 semantics.
+ for line in self.file:
+ yield line
+
+
+def NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None,
+ newline=None, suffix=None, prefix=None,
+ dir=None, delete=True, *, errors=None):
+ """Create and return a temporary file.
+ Arguments:
+ 'prefix', 'suffix', 'dir' -- as for mkstemp.
+ 'mode' -- the mode argument to io.open (default "w+b").
+ 'buffering' -- the buffer size argument to io.open (default -1).
+ 'encoding' -- the encoding argument to io.open (default None)
+ 'newline' -- the newline argument to io.open (default None)
+ 'delete' -- whether the file is deleted on close (default True).
+ 'errors' -- the errors argument to io.open (default None)
+ The file is created as mkstemp() would do it.
+
+ Returns an object with a file-like interface; the name of the file
+ is accessible as its 'name' attribute. The file will be automatically
+ deleted when it is closed unless the 'delete' argument is set to False.
+ """
+
+ prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir)
+
+ flags = _bin_openflags
+
+ # Setting O_TEMPORARY in the flags causes the OS to delete
+ # the file when it is closed. This is only supported by Windows.
+ if _os.name == 'nt' and delete:
+ flags |= _os.O_TEMPORARY
+
+ (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags, output_type)
+ try:
+ file = _io.open(fd, mode, buffering=buffering,
+ newline=newline, encoding=encoding, errors=errors)
+
+ return _TemporaryFileWrapper(file, name, delete)
+ except BaseException:
+ _os.unlink(name)
+ _os.close(fd)
+ raise
+
+if _os.name != 'posix' or _sys.platform == 'cygwin':
+ # On non-POSIX and Cygwin systems, assume that we cannot unlink a file
+ # while it is open.
+ TemporaryFile = NamedTemporaryFile
+
+else:
+ # Is the O_TMPFILE flag available and does it work?
+ # The flag is set to False if os.open(dir, os.O_TMPFILE) raises an
+ # IsADirectoryError exception
+ _O_TMPFILE_WORKS = hasattr(_os, 'O_TMPFILE')
+
+ def TemporaryFile(mode='w+b', buffering=-1, encoding=None,
+ newline=None, suffix=None, prefix=None,
+ dir=None, *, errors=None):
+ """Create and return a temporary file.
+ Arguments:
+ 'prefix', 'suffix', 'dir' -- as for mkstemp.
+ 'mode' -- the mode argument to io.open (default "w+b").
+ 'buffering' -- the buffer size argument to io.open (default -1).
+ 'encoding' -- the encoding argument to io.open (default None)
+ 'newline' -- the newline argument to io.open (default None)
+ 'errors' -- the errors argument to io.open (default None)
+ The file is created as mkstemp() would do it.
+
+ Returns an object with a file-like interface. The file has no
+ name, and will cease to exist when it is closed.
+ """
+ global _O_TMPFILE_WORKS
+
+ prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir)
+
+ flags = _bin_openflags
+ if _O_TMPFILE_WORKS:
+ try:
+ flags2 = (flags | _os.O_TMPFILE) & ~_os.O_CREAT
+ fd = _os.open(dir, flags2, 0o600)
+ except IsADirectoryError:
+ # Linux kernel older than 3.11 ignores the O_TMPFILE flag:
+ # O_TMPFILE is read as O_DIRECTORY. Trying to open a directory
+ # with O_RDWR|O_DIRECTORY fails with IsADirectoryError, a
+ # directory cannot be open to write. Set flag to False to not
+ # try again.
+ _O_TMPFILE_WORKS = False
+ except OSError:
+ # The filesystem of the directory does not support O_TMPFILE.
+ # For example, OSError(95, 'Operation not supported').
+ #
+ # On Linux kernel older than 3.11, trying to open a regular
+ # file (or a symbolic link to a regular file) with O_TMPFILE
+ # fails with NotADirectoryError, because O_TMPFILE is read as
+ # O_DIRECTORY.
+ pass
+ else:
+ try:
+ return _io.open(fd, mode, buffering=buffering,
+ newline=newline, encoding=encoding,
+ errors=errors)
+ except:
+ _os.close(fd)
+ raise
+ # Fallback to _mkstemp_inner().
+
+ (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags, output_type)
+ try:
+ _os.unlink(name)
+ return _io.open(fd, mode, buffering=buffering,
+ newline=newline, encoding=encoding, errors=errors)
+ except:
+ _os.close(fd)
+ raise
+
+class SpooledTemporaryFile:
+ """Temporary file wrapper, specialized to switch from BytesIO
+ or StringIO to a real file when it exceeds a certain size or
+ when a fileno is needed.
+ """
+ _rolled = False
+
+ def __init__(self, max_size=0, mode='w+b', buffering=-1,
+ encoding=None, newline=None,
+ suffix=None, prefix=None, dir=None, *, errors=None):
+ if 'b' in mode:
+ self._file = _io.BytesIO()
+ else:
+ self._file = _io.TextIOWrapper(_io.BytesIO(),
+ encoding=encoding, errors=errors,
+ newline=newline)
+ self._max_size = max_size
+ self._rolled = False
+ self._TemporaryFileArgs = {'mode': mode, 'buffering': buffering,
+ 'suffix': suffix, 'prefix': prefix,
+ 'encoding': encoding, 'newline': newline,
+ 'dir': dir, 'errors': errors}
+
+ def _check(self, file):
+ if self._rolled: return
+ max_size = self._max_size
+ if max_size and file.tell() > max_size:
+ self.rollover()
+
+ def rollover(self):
+ if self._rolled: return
+ file = self._file
+ newfile = self._file = TemporaryFile(**self._TemporaryFileArgs)
+ del self._TemporaryFileArgs
+
+ pos = file.tell()
+ if hasattr(newfile, 'buffer'):
+ newfile.buffer.write(file.detach().getvalue())
+ else:
+ newfile.write(file.getvalue())
+ newfile.seek(pos, 0)
+
+ self._rolled = True
+
+ # The method caching trick from NamedTemporaryFile
+ # won't work here, because _file may change from a
+ # BytesIO/StringIO instance to a real file. So we list
+ # all the methods directly.
+
+ # Context management protocol
+ def __enter__(self):
+ if self._file.closed:
+ raise ValueError("Cannot enter context with closed file")
+ return self
+
+ def __exit__(self, exc, value, tb):
+ self._file.close()
+
+ # file protocol
+ def __iter__(self):
+ return self._file.__iter__()
+
+ def close(self):
+ self._file.close()
+
+ @property
+ def closed(self):
+ return self._file.closed
+
+ @property
+ def encoding(self):
+ return self._file.encoding
+
+ @property
+ def errors(self):
+ return self._file.errors
+
+ def fileno(self):
+ self.rollover()
+ return self._file.fileno()
+
+ def flush(self):
+ self._file.flush()
+
+ def isatty(self):
+ return self._file.isatty()
+
+ @property
+ def mode(self):
+ try:
+ return self._file.mode
+ except AttributeError:
+ return self._TemporaryFileArgs['mode']
+
+ @property
+ def name(self):
+ try:
+ return self._file.name
+ except AttributeError:
+ return None
+
+ @property
+ def newlines(self):
+ return self._file.newlines
+
+ def read(self, *args):
+ return self._file.read(*args)
+
+ def readline(self, *args):
+ return self._file.readline(*args)
+
+ def readlines(self, *args):
+ return self._file.readlines(*args)
+
+ def seek(self, *args):
+ return self._file.seek(*args)
+
+ @property
+ def softspace(self):
+ return self._file.softspace
+
+ def tell(self):
+ return self._file.tell()
+
+ def truncate(self, size=None):
+ if size is None:
+ self._file.truncate()
+ else:
+ if size > self._max_size:
+ self.rollover()
+ self._file.truncate(size)
+
+ def write(self, s):
+ file = self._file
+ rv = file.write(s)
+ self._check(file)
+ return rv
+
+ def writelines(self, iterable):
+ file = self._file
+ rv = file.writelines(iterable)
+ self._check(file)
+ return rv
+
+
+class TemporaryDirectory(object):
+ """Create and return a temporary directory. This has the same
+ behavior as mkdtemp but can be used as a context manager. For
+ example:
+
+ with TemporaryDirectory() as tmpdir:
+ ...
+
+ Upon exiting the context, the directory and everything contained
+ in it are removed.
+ """
+
+ def __init__(self, suffix=None, prefix=None, dir=None):
+ self.name = mkdtemp(suffix, prefix, dir)
+ self._finalizer = _weakref.finalize(
+ self, self._cleanup, self.name,
+ warn_message="Implicitly cleaning up {!r}".format(self))
+
+ @classmethod
+ def _rmtree(cls, name):
+ def onerror(func, path, exc_info):
+ if issubclass(exc_info[0], PermissionError):
+ def resetperms(path):
+ try:
+ _os.chflags(path, 0)
+ except AttributeError:
+ pass
+ _os.chmod(path, 0o700)
+
+ try:
+ if path != name:
+ resetperms(_os.path.dirname(path))
+ resetperms(path)
+
+ try:
+ _os.unlink(path)
+ # PermissionError is raised on FreeBSD for directories
+ except (IsADirectoryError, PermissionError):
+ cls._rmtree(path)
+ except FileNotFoundError:
+ pass
+ elif issubclass(exc_info[0], FileNotFoundError):
+ pass
+ else:
+ raise
+
+ _shutil.rmtree(name, onerror=onerror)
+
+ @classmethod
+ def _cleanup(cls, name, warn_message):
+ cls._rmtree(name)
+ _warnings.warn(warn_message, ResourceWarning)
+
+ def __repr__(self):
+ return "<{} {!r}>".format(self.__class__.__name__, self.name)
+
+ def __enter__(self):
+ return self.name
+
+ def __exit__(self, exc, value, tb):
+ self.cleanup()
+
+ def cleanup(self):
+ if self._finalizer.detach():
+ self._rmtree(self.name)
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/this.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/this.py
new file mode 100644
index 0000000000000000000000000000000000000000..e68dd3ff39b04ff857420b98889bee590b344024
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/this.py
@@ -0,0 +1,28 @@
+s = """Gur Mra bs Clguba, ol Gvz Crgref
+
+Ornhgvshy vf orggre guna htyl.
+Rkcyvpvg vf orggre guna vzcyvpvg.
+Fvzcyr vf orggre guna pbzcyrk.
+Pbzcyrk vf orggre guna pbzcyvpngrq.
+Syng vf orggre guna arfgrq.
+Fcnefr vf orggre guna qrafr.
+Ernqnovyvgl pbhagf.
+Fcrpvny pnfrf nera'g fcrpvny rabhtu gb oernx gur ehyrf.
+Nygubhtu cenpgvpnyvgl orngf chevgl.
+Reebef fubhyq arire cnff fvyragyl.
+Hayrff rkcyvpvgyl fvyraprq.
+Va gur snpr bs nzovthvgl, ershfr gur grzcgngvba gb thrff.
+Gurer fubhyq or bar-- naq cersrenoyl bayl bar --boivbhf jnl gb qb vg.
+Nygubhtu gung jnl znl abg or boivbhf ng svefg hayrff lbh'er Qhgpu.
+Abj vf orggre guna arire.
+Nygubhtu arire vf bsgra orggre guna *evtug* abj.
+Vs gur vzcyrzragngvba vf uneq gb rkcynva, vg'f n onq vqrn.
+Vs gur vzcyrzragngvba vf rnfl gb rkcynva, vg znl or n tbbq vqrn.
+Anzrfcnprf ner bar ubaxvat terng vqrn -- yrg'f qb zber bs gubfr!"""
+
+d = {}
+for c in (65, 97):
+ for i in range(26):
+ d[chr(i+c)] = chr((i+13) % 26 + c)
+
+print("".join([d.get(c, c) for c in s]))
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/threading.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/threading.py
new file mode 100644
index 0000000000000000000000000000000000000000..813dae2aa9f8e5d3b565482f033394ba3cbb9bc7
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/threading.py
@@ -0,0 +1,1466 @@
+"""Thread module emulating a subset of Java's threading model."""
+
+import os as _os
+import sys as _sys
+import _thread
+
+from time import monotonic as _time
+from _weakrefset import WeakSet
+from itertools import islice as _islice, count as _count
+try:
+ from _collections import deque as _deque
+except ImportError:
+ from collections import deque as _deque
+
+# Note regarding PEP 8 compliant names
+# This threading model was originally inspired by Java, and inherited
+# the convention of camelCase function and method names from that
+# language. Those original names are not in any imminent danger of
+# being deprecated (even for Py3k),so this module provides them as an
+# alias for the PEP 8 compliant names
+# Note that using the new PEP 8 compliant names facilitates substitution
+# with the multiprocessing module, which doesn't provide the old
+# Java inspired names.
+
+__all__ = ['get_ident', 'active_count', 'Condition', 'current_thread',
+ 'enumerate', 'main_thread', 'TIMEOUT_MAX',
+ 'Event', 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore', 'Thread',
+ 'Barrier', 'BrokenBarrierError', 'Timer', 'ThreadError',
+ 'setprofile', 'settrace', 'local', 'stack_size',
+ 'excepthook', 'ExceptHookArgs']
+
+# Rename some stuff so "from threading import *" is safe
+_start_new_thread = _thread.start_new_thread
+_allocate_lock = _thread.allocate_lock
+_set_sentinel = _thread._set_sentinel
+get_ident = _thread.get_ident
+try:
+ get_native_id = _thread.get_native_id
+ _HAVE_THREAD_NATIVE_ID = True
+ __all__.append('get_native_id')
+except AttributeError:
+ _HAVE_THREAD_NATIVE_ID = False
+ThreadError = _thread.error
+try:
+ _CRLock = _thread.RLock
+except AttributeError:
+ _CRLock = None
+TIMEOUT_MAX = _thread.TIMEOUT_MAX
+del _thread
+
+
+# Support for profile and trace hooks
+
+_profile_hook = None
+_trace_hook = None
+
+def setprofile(func):
+ """Set a profile function for all threads started from the threading module.
+
+ The func will be passed to sys.setprofile() for each thread, before its
+ run() method is called.
+
+ """
+ global _profile_hook
+ _profile_hook = func
+
+def settrace(func):
+ """Set a trace function for all threads started from the threading module.
+
+ The func will be passed to sys.settrace() for each thread, before its run()
+ method is called.
+
+ """
+ global _trace_hook
+ _trace_hook = func
+
+# Synchronization classes
+
+Lock = _allocate_lock
+
+def RLock(*args, **kwargs):
+ """Factory function that returns a new reentrant lock.
+
+ A reentrant lock must be released by the thread that acquired it. Once a
+ thread has acquired a reentrant lock, the same thread may acquire it again
+ without blocking; the thread must release it once for each time it has
+ acquired it.
+
+ """
+ if _CRLock is None:
+ return _PyRLock(*args, **kwargs)
+ return _CRLock(*args, **kwargs)
+
+class _RLock:
+ """This class implements reentrant lock objects.
+
+ A reentrant lock must be released by the thread that acquired it. Once a
+ thread has acquired a reentrant lock, the same thread may acquire it
+ again without blocking; the thread must release it once for each time it
+ has acquired it.
+
+ """
+
+ def __init__(self):
+ self._block = _allocate_lock()
+ self._owner = None
+ self._count = 0
+
+ def __repr__(self):
+ owner = self._owner
+ try:
+ owner = _active[owner].name
+ except KeyError:
+ pass
+ return "<%s %s.%s object owner=%r count=%d at %s>" % (
+ "locked" if self._block.locked() else "unlocked",
+ self.__class__.__module__,
+ self.__class__.__qualname__,
+ owner,
+ self._count,
+ hex(id(self))
+ )
+
+ def acquire(self, blocking=True, timeout=-1):
+ """Acquire a lock, blocking or non-blocking.
+
+ When invoked without arguments: if this thread already owns the lock,
+ increment the recursion level by one, and return immediately. Otherwise,
+ if another thread owns the lock, block until the lock is unlocked. Once
+ the lock is unlocked (not owned by any thread), then grab ownership, set
+ the recursion level to one, and return. If more than one thread is
+ blocked waiting until the lock is unlocked, only one at a time will be
+ able to grab ownership of the lock. There is no return value in this
+ case.
+
+ When invoked with the blocking argument set to true, do the same thing
+ as when called without arguments, and return true.
+
+ When invoked with the blocking argument set to false, do not block. If a
+ call without an argument would block, return false immediately;
+ otherwise, do the same thing as when called without arguments, and
+ return true.
+
+ When invoked with the floating-point timeout argument set to a positive
+ value, block for at most the number of seconds specified by timeout
+ and as long as the lock cannot be acquired. Return true if the lock has
+ been acquired, false if the timeout has elapsed.
+
+ """
+ me = get_ident()
+ if self._owner == me:
+ self._count += 1
+ return 1
+ rc = self._block.acquire(blocking, timeout)
+ if rc:
+ self._owner = me
+ self._count = 1
+ return rc
+
+ __enter__ = acquire
+
+ def release(self):
+ """Release a lock, decrementing the recursion level.
+
+ If after the decrement it is zero, reset the lock to unlocked (not owned
+ by any thread), and if any other threads are blocked waiting for the
+ lock to become unlocked, allow exactly one of them to proceed. If after
+ the decrement the recursion level is still nonzero, the lock remains
+ locked and owned by the calling thread.
+
+ Only call this method when the calling thread owns the lock. A
+ RuntimeError is raised if this method is called when the lock is
+ unlocked.
+
+ There is no return value.
+
+ """
+ if self._owner != get_ident():
+ raise RuntimeError("cannot release un-acquired lock")
+ self._count = count = self._count - 1
+ if not count:
+ self._owner = None
+ self._block.release()
+
+ def __exit__(self, t, v, tb):
+ self.release()
+
+ # Internal methods used by condition variables
+
+ def _acquire_restore(self, state):
+ self._block.acquire()
+ self._count, self._owner = state
+
+ def _release_save(self):
+ if self._count == 0:
+ raise RuntimeError("cannot release un-acquired lock")
+ count = self._count
+ self._count = 0
+ owner = self._owner
+ self._owner = None
+ self._block.release()
+ return (count, owner)
+
+ def _is_owned(self):
+ return self._owner == get_ident()
+
+_PyRLock = _RLock
+
+
+class Condition:
+ """Class that implements a condition variable.
+
+ A condition variable allows one or more threads to wait until they are
+ notified by another thread.
+
+ If the lock argument is given and not None, it must be a Lock or RLock
+ object, and it is used as the underlying lock. Otherwise, a new RLock object
+ is created and used as the underlying lock.
+
+ """
+
+ def __init__(self, lock=None):
+ if lock is None:
+ lock = RLock()
+ self._lock = lock
+ # Export the lock's acquire() and release() methods
+ self.acquire = lock.acquire
+ self.release = lock.release
+ # If the lock defines _release_save() and/or _acquire_restore(),
+ # these override the default implementations (which just call
+ # release() and acquire() on the lock). Ditto for _is_owned().
+ try:
+ self._release_save = lock._release_save
+ except AttributeError:
+ pass
+ try:
+ self._acquire_restore = lock._acquire_restore
+ except AttributeError:
+ pass
+ try:
+ self._is_owned = lock._is_owned
+ except AttributeError:
+ pass
+ self._waiters = _deque()
+
+ def __enter__(self):
+ return self._lock.__enter__()
+
+ def __exit__(self, *args):
+ return self._lock.__exit__(*args)
+
+ def __repr__(self):
+ return "" % (self._lock, len(self._waiters))
+
+ def _release_save(self):
+ self._lock.release() # No state to save
+
+ def _acquire_restore(self, x):
+ self._lock.acquire() # Ignore saved state
+
+ def _is_owned(self):
+ # Return True if lock is owned by current_thread.
+ # This method is called only if _lock doesn't have _is_owned().
+ if self._lock.acquire(0):
+ self._lock.release()
+ return False
+ else:
+ return True
+
+ def wait(self, timeout=None):
+ """Wait until notified or until a timeout occurs.
+
+ If the calling thread has not acquired the lock when this method is
+ called, a RuntimeError is raised.
+
+ This method releases the underlying lock, and then blocks until it is
+ awakened by a notify() or notify_all() call for the same condition
+ variable in another thread, or until the optional timeout occurs. Once
+ awakened or timed out, it re-acquires the lock and returns.
+
+ When the timeout argument is present and not None, it should be a
+ floating point number specifying a timeout for the operation in seconds
+ (or fractions thereof).
+
+ When the underlying lock is an RLock, it is not released using its
+ release() method, since this may not actually unlock the lock when it
+ was acquired multiple times recursively. Instead, an internal interface
+ of the RLock class is used, which really unlocks it even when it has
+ been recursively acquired several times. Another internal interface is
+ then used to restore the recursion level when the lock is reacquired.
+
+ """
+ if not self._is_owned():
+ raise RuntimeError("cannot wait on un-acquired lock")
+ waiter = _allocate_lock()
+ waiter.acquire()
+ self._waiters.append(waiter)
+ saved_state = self._release_save()
+ gotit = False
+ try: # restore state no matter what (e.g., KeyboardInterrupt)
+ if timeout is None:
+ waiter.acquire()
+ gotit = True
+ else:
+ if timeout > 0:
+ gotit = waiter.acquire(True, timeout)
+ else:
+ gotit = waiter.acquire(False)
+ return gotit
+ finally:
+ self._acquire_restore(saved_state)
+ if not gotit:
+ try:
+ self._waiters.remove(waiter)
+ except ValueError:
+ pass
+
+ def wait_for(self, predicate, timeout=None):
+ """Wait until a condition evaluates to True.
+
+ predicate should be a callable which result will be interpreted as a
+ boolean value. A timeout may be provided giving the maximum time to
+ wait.
+
+ """
+ endtime = None
+ waittime = timeout
+ result = predicate()
+ while not result:
+ if waittime is not None:
+ if endtime is None:
+ endtime = _time() + waittime
+ else:
+ waittime = endtime - _time()
+ if waittime <= 0:
+ break
+ self.wait(waittime)
+ result = predicate()
+ return result
+
+ def notify(self, n=1):
+ """Wake up one or more threads waiting on this condition, if any.
+
+ If the calling thread has not acquired the lock when this method is
+ called, a RuntimeError is raised.
+
+ This method wakes up at most n of the threads waiting for the condition
+ variable; it is a no-op if no threads are waiting.
+
+ """
+ if not self._is_owned():
+ raise RuntimeError("cannot notify on un-acquired lock")
+ all_waiters = self._waiters
+ waiters_to_notify = _deque(_islice(all_waiters, n))
+ if not waiters_to_notify:
+ return
+ for waiter in waiters_to_notify:
+ waiter.release()
+ try:
+ all_waiters.remove(waiter)
+ except ValueError:
+ pass
+
+ def notify_all(self):
+ """Wake up all threads waiting on this condition.
+
+ If the calling thread has not acquired the lock when this method
+ is called, a RuntimeError is raised.
+
+ """
+ self.notify(len(self._waiters))
+
+ notifyAll = notify_all
+
+
+class Semaphore:
+ """This class implements semaphore objects.
+
+ Semaphores manage a counter representing the number of release() calls minus
+ the number of acquire() calls, plus an initial value. The acquire() method
+ blocks if necessary until it can return without making the counter
+ negative. If not given, value defaults to 1.
+
+ """
+
+ # After Tim Peters' semaphore class, but not quite the same (no maximum)
+
+ def __init__(self, value=1):
+ if value < 0:
+ raise ValueError("semaphore initial value must be >= 0")
+ self._cond = Condition(Lock())
+ self._value = value
+
+ def acquire(self, blocking=True, timeout=None):
+ """Acquire a semaphore, decrementing the internal counter by one.
+
+ When invoked without arguments: if the internal counter is larger than
+ zero on entry, decrement it by one and return immediately. If it is zero
+ on entry, block, waiting until some other thread has called release() to
+ make it larger than zero. This is done with proper interlocking so that
+ if multiple acquire() calls are blocked, release() will wake exactly one
+ of them up. The implementation may pick one at random, so the order in
+ which blocked threads are awakened should not be relied on. There is no
+ return value in this case.
+
+ When invoked with blocking set to true, do the same thing as when called
+ without arguments, and return true.
+
+ When invoked with blocking set to false, do not block. If a call without
+ an argument would block, return false immediately; otherwise, do the
+ same thing as when called without arguments, and return true.
+
+ When invoked with a timeout other than None, it will block for at
+ most timeout seconds. If acquire does not complete successfully in
+ that interval, return false. Return true otherwise.
+
+ """
+ if not blocking and timeout is not None:
+ raise ValueError("can't specify timeout for non-blocking acquire")
+ rc = False
+ endtime = None
+ with self._cond:
+ while self._value == 0:
+ if not blocking:
+ break
+ if timeout is not None:
+ if endtime is None:
+ endtime = _time() + timeout
+ else:
+ timeout = endtime - _time()
+ if timeout <= 0:
+ break
+ self._cond.wait(timeout)
+ else:
+ self._value -= 1
+ rc = True
+ return rc
+
+ __enter__ = acquire
+
+ def release(self):
+ """Release a semaphore, incrementing the internal counter by one.
+
+ When the counter is zero on entry and another thread is waiting for it
+ to become larger than zero again, wake up that thread.
+
+ """
+ with self._cond:
+ self._value += 1
+ self._cond.notify()
+
+ def __exit__(self, t, v, tb):
+ self.release()
+
+
+class BoundedSemaphore(Semaphore):
+ """Implements a bounded semaphore.
+
+ A bounded semaphore checks to make sure its current value doesn't exceed its
+ initial value. If it does, ValueError is raised. In most situations
+ semaphores are used to guard resources with limited capacity.
+
+ If the semaphore is released too many times it's a sign of a bug. If not
+ given, value defaults to 1.
+
+ Like regular semaphores, bounded semaphores manage a counter representing
+ the number of release() calls minus the number of acquire() calls, plus an
+ initial value. The acquire() method blocks if necessary until it can return
+ without making the counter negative. If not given, value defaults to 1.
+
+ """
+
+ def __init__(self, value=1):
+ Semaphore.__init__(self, value)
+ self._initial_value = value
+
+ def release(self):
+ """Release a semaphore, incrementing the internal counter by one.
+
+ When the counter is zero on entry and another thread is waiting for it
+ to become larger than zero again, wake up that thread.
+
+ If the number of releases exceeds the number of acquires,
+ raise a ValueError.
+
+ """
+ with self._cond:
+ if self._value >= self._initial_value:
+ raise ValueError("Semaphore released too many times")
+ self._value += 1
+ self._cond.notify()
+
+
+class Event:
+ """Class implementing event objects.
+
+ Events manage a flag that can be set to true with the set() method and reset
+ to false with the clear() method. The wait() method blocks until the flag is
+ true. The flag is initially false.
+
+ """
+
+ # After Tim Peters' event class (without is_posted())
+
+ def __init__(self):
+ self._cond = Condition(Lock())
+ self._flag = False
+
+ def _reset_internal_locks(self):
+ # private! called by Thread._reset_internal_locks by _after_fork()
+ self._cond.__init__(Lock())
+
+ def is_set(self):
+ """Return true if and only if the internal flag is true."""
+ return self._flag
+
+ isSet = is_set
+
+ def set(self):
+ """Set the internal flag to true.
+
+ All threads waiting for it to become true are awakened. Threads
+ that call wait() once the flag is true will not block at all.
+
+ """
+ with self._cond:
+ self._flag = True
+ self._cond.notify_all()
+
+ def clear(self):
+ """Reset the internal flag to false.
+
+ Subsequently, threads calling wait() will block until set() is called to
+ set the internal flag to true again.
+
+ """
+ with self._cond:
+ self._flag = False
+
+ def wait(self, timeout=None):
+ """Block until the internal flag is true.
+
+ If the internal flag is true on entry, return immediately. Otherwise,
+ block until another thread calls set() to set the flag to true, or until
+ the optional timeout occurs.
+
+ When the timeout argument is present and not None, it should be a
+ floating point number specifying a timeout for the operation in seconds
+ (or fractions thereof).
+
+ This method returns the internal flag on exit, so it will always return
+ True except if a timeout is given and the operation times out.
+
+ """
+ with self._cond:
+ signaled = self._flag
+ if not signaled:
+ signaled = self._cond.wait(timeout)
+ return signaled
+
+
+# A barrier class. Inspired in part by the pthread_barrier_* api and
+# the CyclicBarrier class from Java. See
+# http://sourceware.org/pthreads-win32/manual/pthread_barrier_init.html and
+# http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/
+# CyclicBarrier.html
+# for information.
+# We maintain two main states, 'filling' and 'draining' enabling the barrier
+# to be cyclic. Threads are not allowed into it until it has fully drained
+# since the previous cycle. In addition, a 'resetting' state exists which is
+# similar to 'draining' except that threads leave with a BrokenBarrierError,
+# and a 'broken' state in which all threads get the exception.
+class Barrier:
+ """Implements a Barrier.
+
+ Useful for synchronizing a fixed number of threads at known synchronization
+ points. Threads block on 'wait()' and are simultaneously awoken once they
+ have all made that call.
+
+ """
+
+ def __init__(self, parties, action=None, timeout=None):
+ """Create a barrier, initialised to 'parties' threads.
+
+ 'action' is a callable which, when supplied, will be called by one of
+ the threads after they have all entered the barrier and just prior to
+ releasing them all. If a 'timeout' is provided, it is used as the
+ default for all subsequent 'wait()' calls.
+
+ """
+ self._cond = Condition(Lock())
+ self._action = action
+ self._timeout = timeout
+ self._parties = parties
+ self._state = 0 #0 filling, 1, draining, -1 resetting, -2 broken
+ self._count = 0
+
+ def wait(self, timeout=None):
+ """Wait for the barrier.
+
+ When the specified number of threads have started waiting, they are all
+ simultaneously awoken. If an 'action' was provided for the barrier, one
+ of the threads will have executed that callback prior to returning.
+ Returns an individual index number from 0 to 'parties-1'.
+
+ """
+ if timeout is None:
+ timeout = self._timeout
+ with self._cond:
+ self._enter() # Block while the barrier drains.
+ index = self._count
+ self._count += 1
+ try:
+ if index + 1 == self._parties:
+ # We release the barrier
+ self._release()
+ else:
+ # We wait until someone releases us
+ self._wait(timeout)
+ return index
+ finally:
+ self._count -= 1
+ # Wake up any threads waiting for barrier to drain.
+ self._exit()
+
+ # Block until the barrier is ready for us, or raise an exception
+ # if it is broken.
+ def _enter(self):
+ while self._state in (-1, 1):
+ # It is draining or resetting, wait until done
+ self._cond.wait()
+ #see if the barrier is in a broken state
+ if self._state < 0:
+ raise BrokenBarrierError
+ assert self._state == 0
+
+ # Optionally run the 'action' and release the threads waiting
+ # in the barrier.
+ def _release(self):
+ try:
+ if self._action:
+ self._action()
+ # enter draining state
+ self._state = 1
+ self._cond.notify_all()
+ except:
+ #an exception during the _action handler. Break and reraise
+ self._break()
+ raise
+
+ # Wait in the barrier until we are released. Raise an exception
+ # if the barrier is reset or broken.
+ def _wait(self, timeout):
+ if not self._cond.wait_for(lambda : self._state != 0, timeout):
+ #timed out. Break the barrier
+ self._break()
+ raise BrokenBarrierError
+ if self._state < 0:
+ raise BrokenBarrierError
+ assert self._state == 1
+
+ # If we are the last thread to exit the barrier, signal any threads
+ # waiting for the barrier to drain.
+ def _exit(self):
+ if self._count == 0:
+ if self._state in (-1, 1):
+ #resetting or draining
+ self._state = 0
+ self._cond.notify_all()
+
+ def reset(self):
+ """Reset the barrier to the initial state.
+
+ Any threads currently waiting will get the BrokenBarrier exception
+ raised.
+
+ """
+ with self._cond:
+ if self._count > 0:
+ if self._state == 0:
+ #reset the barrier, waking up threads
+ self._state = -1
+ elif self._state == -2:
+ #was broken, set it to reset state
+ #which clears when the last thread exits
+ self._state = -1
+ else:
+ self._state = 0
+ self._cond.notify_all()
+
+ def abort(self):
+ """Place the barrier into a 'broken' state.
+
+ Useful in case of error. Any currently waiting threads and threads
+ attempting to 'wait()' will have BrokenBarrierError raised.
+
+ """
+ with self._cond:
+ self._break()
+
+ def _break(self):
+ # An internal error was detected. The barrier is set to
+ # a broken state all parties awakened.
+ self._state = -2
+ self._cond.notify_all()
+
+ @property
+ def parties(self):
+ """Return the number of threads required to trip the barrier."""
+ return self._parties
+
+ @property
+ def n_waiting(self):
+ """Return the number of threads currently waiting at the barrier."""
+ # We don't need synchronization here since this is an ephemeral result
+ # anyway. It returns the correct value in the steady state.
+ if self._state == 0:
+ return self._count
+ return 0
+
+ @property
+ def broken(self):
+ """Return True if the barrier is in a broken state."""
+ return self._state == -2
+
+# exception raised by the Barrier class
+class BrokenBarrierError(RuntimeError):
+ pass
+
+
+# Helper to generate new thread names
+_counter = _count().__next__
+_counter() # Consume 0 so first non-main thread has id 1.
+def _newname(template="Thread-%d"):
+ return template % _counter()
+
+# Active thread administration
+_active_limbo_lock = _allocate_lock()
+_active = {} # maps thread id to Thread object
+_limbo = {}
+_dangling = WeakSet()
+# Set of Thread._tstate_lock locks of non-daemon threads used by _shutdown()
+# to wait until all Python thread states get deleted:
+# see Thread._set_tstate_lock().
+_shutdown_locks_lock = _allocate_lock()
+_shutdown_locks = set()
+
+# Main class for threads
+
+class Thread:
+ """A class that represents a thread of control.
+
+ This class can be safely subclassed in a limited fashion. There are two ways
+ to specify the activity: by passing a callable object to the constructor, or
+ by overriding the run() method in a subclass.
+
+ """
+
+ _initialized = False
+
+ def __init__(self, group=None, target=None, name=None,
+ args=(), kwargs=None, *, daemon=None):
+ """This constructor should always be called with keyword arguments. Arguments are:
+
+ *group* should be None; reserved for future extension when a ThreadGroup
+ class is implemented.
+
+ *target* is the callable object to be invoked by the run()
+ method. Defaults to None, meaning nothing is called.
+
+ *name* is the thread name. By default, a unique name is constructed of
+ the form "Thread-N" where N is a small decimal number.
+
+ *args* is the argument tuple for the target invocation. Defaults to ().
+
+ *kwargs* is a dictionary of keyword arguments for the target
+ invocation. Defaults to {}.
+
+ If a subclass overrides the constructor, it must make sure to invoke
+ the base class constructor (Thread.__init__()) before doing anything
+ else to the thread.
+
+ """
+ assert group is None, "group argument must be None for now"
+ if kwargs is None:
+ kwargs = {}
+ self._target = target
+ self._name = str(name or _newname())
+ self._args = args
+ self._kwargs = kwargs
+ if daemon is not None:
+ self._daemonic = daemon
+ else:
+ self._daemonic = current_thread().daemon
+ self._ident = None
+ if _HAVE_THREAD_NATIVE_ID:
+ self._native_id = None
+ self._tstate_lock = None
+ self._started = Event()
+ self._is_stopped = False
+ self._initialized = True
+ # Copy of sys.stderr used by self._invoke_excepthook()
+ self._stderr = _sys.stderr
+ self._invoke_excepthook = _make_invoke_excepthook()
+ # For debugging and _after_fork()
+ _dangling.add(self)
+
+ def _reset_internal_locks(self, is_alive):
+ # private! Called by _after_fork() to reset our internal locks as
+ # they may be in an invalid state leading to a deadlock or crash.
+ self._started._reset_internal_locks()
+ if is_alive:
+ self._set_tstate_lock()
+ else:
+ # The thread isn't alive after fork: it doesn't have a tstate
+ # anymore.
+ self._is_stopped = True
+ self._tstate_lock = None
+
+ def __repr__(self):
+ assert self._initialized, "Thread.__init__() was not called"
+ status = "initial"
+ if self._started.is_set():
+ status = "started"
+ self.is_alive() # easy way to get ._is_stopped set when appropriate
+ if self._is_stopped:
+ status = "stopped"
+ if self._daemonic:
+ status += " daemon"
+ if self._ident is not None:
+ status += " %s" % self._ident
+ return "<%s(%s, %s)>" % (self.__class__.__name__, self._name, status)
+
+ def start(self):
+ """Start the thread's activity.
+
+ It must be called at most once per thread object. It arranges for the
+ object's run() method to be invoked in a separate thread of control.
+
+ This method will raise a RuntimeError if called more than once on the
+ same thread object.
+
+ """
+ if not self._initialized:
+ raise RuntimeError("thread.__init__() not called")
+
+ if self._started.is_set():
+ raise RuntimeError("threads can only be started once")
+ with _active_limbo_lock:
+ _limbo[self] = self
+ try:
+ _start_new_thread(self._bootstrap, ())
+ except Exception:
+ with _active_limbo_lock:
+ del _limbo[self]
+ raise
+ self._started.wait()
+
+ def run(self):
+ """Method representing the thread's activity.
+
+ You may override this method in a subclass. The standard run() method
+ invokes the callable object passed to the object's constructor as the
+ target argument, if any, with sequential and keyword arguments taken
+ from the args and kwargs arguments, respectively.
+
+ """
+ try:
+ if self._target:
+ self._target(*self._args, **self._kwargs)
+ finally:
+ # Avoid a refcycle if the thread is running a function with
+ # an argument that has a member that points to the thread.
+ del self._target, self._args, self._kwargs
+
+ def _bootstrap(self):
+ # Wrapper around the real bootstrap code that ignores
+ # exceptions during interpreter cleanup. Those typically
+ # happen when a daemon thread wakes up at an unfortunate
+ # moment, finds the world around it destroyed, and raises some
+ # random exception *** while trying to report the exception in
+ # _bootstrap_inner() below ***. Those random exceptions
+ # don't help anybody, and they confuse users, so we suppress
+ # them. We suppress them only when it appears that the world
+ # indeed has already been destroyed, so that exceptions in
+ # _bootstrap_inner() during normal business hours are properly
+ # reported. Also, we only suppress them for daemonic threads;
+ # if a non-daemonic encounters this, something else is wrong.
+ try:
+ self._bootstrap_inner()
+ except:
+ if self._daemonic and _sys is None:
+ return
+ raise
+
+ def _set_ident(self):
+ self._ident = get_ident()
+
+ if _HAVE_THREAD_NATIVE_ID:
+ def _set_native_id(self):
+ self._native_id = get_native_id()
+
+ def _set_tstate_lock(self):
+ """
+ Set a lock object which will be released by the interpreter when
+ the underlying thread state (see pystate.h) gets deleted.
+ """
+ self._tstate_lock = _set_sentinel()
+ self._tstate_lock.acquire()
+
+ if not self.daemon:
+ with _shutdown_locks_lock:
+ _shutdown_locks.add(self._tstate_lock)
+
+ def _bootstrap_inner(self):
+ try:
+ self._set_ident()
+ self._set_tstate_lock()
+ if _HAVE_THREAD_NATIVE_ID:
+ self._set_native_id()
+ self._started.set()
+ with _active_limbo_lock:
+ _active[self._ident] = self
+ del _limbo[self]
+
+ if _trace_hook:
+ _sys.settrace(_trace_hook)
+ if _profile_hook:
+ _sys.setprofile(_profile_hook)
+
+ try:
+ self.run()
+ except:
+ self._invoke_excepthook(self)
+ finally:
+ with _active_limbo_lock:
+ try:
+ # We don't call self._delete() because it also
+ # grabs _active_limbo_lock.
+ del _active[get_ident()]
+ except:
+ pass
+
+ def _stop(self):
+ # After calling ._stop(), .is_alive() returns False and .join() returns
+ # immediately. ._tstate_lock must be released before calling ._stop().
+ #
+ # Normal case: C code at the end of the thread's life
+ # (release_sentinel in _threadmodule.c) releases ._tstate_lock, and
+ # that's detected by our ._wait_for_tstate_lock(), called by .join()
+ # and .is_alive(). Any number of threads _may_ call ._stop()
+ # simultaneously (for example, if multiple threads are blocked in
+ # .join() calls), and they're not serialized. That's harmless -
+ # they'll just make redundant rebindings of ._is_stopped and
+ # ._tstate_lock. Obscure: we rebind ._tstate_lock last so that the
+ # "assert self._is_stopped" in ._wait_for_tstate_lock() always works
+ # (the assert is executed only if ._tstate_lock is None).
+ #
+ # Special case: _main_thread releases ._tstate_lock via this
+ # module's _shutdown() function.
+ lock = self._tstate_lock
+ if lock is not None:
+ assert not lock.locked()
+ self._is_stopped = True
+ self._tstate_lock = None
+ if not self.daemon:
+ with _shutdown_locks_lock:
+ _shutdown_locks.discard(lock)
+
+ def _delete(self):
+ "Remove current thread from the dict of currently running threads."
+ with _active_limbo_lock:
+ del _active[get_ident()]
+ # There must not be any python code between the previous line
+ # and after the lock is released. Otherwise a tracing function
+ # could try to acquire the lock again in the same thread, (in
+ # current_thread()), and would block.
+
+ def join(self, timeout=None):
+ """Wait until the thread terminates.
+
+ This blocks the calling thread until the thread whose join() method is
+ called terminates -- either normally or through an unhandled exception
+ or until the optional timeout occurs.
+
+ When the timeout argument is present and not None, it should be a
+ floating point number specifying a timeout for the operation in seconds
+ (or fractions thereof). As join() always returns None, you must call
+ is_alive() after join() to decide whether a timeout happened -- if the
+ thread is still alive, the join() call timed out.
+
+ When the timeout argument is not present or None, the operation will
+ block until the thread terminates.
+
+ A thread can be join()ed many times.
+
+ join() raises a RuntimeError if an attempt is made to join the current
+ thread as that would cause a deadlock. It is also an error to join() a
+ thread before it has been started and attempts to do so raises the same
+ exception.
+
+ """
+ if not self._initialized:
+ raise RuntimeError("Thread.__init__() not called")
+ if not self._started.is_set():
+ raise RuntimeError("cannot join thread before it is started")
+ if self is current_thread():
+ raise RuntimeError("cannot join current thread")
+
+ if timeout is None:
+ self._wait_for_tstate_lock()
+ else:
+ # the behavior of a negative timeout isn't documented, but
+ # historically .join(timeout=x) for x<0 has acted as if timeout=0
+ self._wait_for_tstate_lock(timeout=max(timeout, 0))
+
+ def _wait_for_tstate_lock(self, block=True, timeout=-1):
+ # Issue #18808: wait for the thread state to be gone.
+ # At the end of the thread's life, after all knowledge of the thread
+ # is removed from C data structures, C code releases our _tstate_lock.
+ # This method passes its arguments to _tstate_lock.acquire().
+ # If the lock is acquired, the C code is done, and self._stop() is
+ # called. That sets ._is_stopped to True, and ._tstate_lock to None.
+ lock = self._tstate_lock
+ if lock is None: # already determined that the C code is done
+ assert self._is_stopped
+ elif lock.acquire(block, timeout):
+ lock.release()
+ self._stop()
+
+ @property
+ def name(self):
+ """A string used for identification purposes only.
+
+ It has no semantics. Multiple threads may be given the same name. The
+ initial name is set by the constructor.
+
+ """
+ assert self._initialized, "Thread.__init__() not called"
+ return self._name
+
+ @name.setter
+ def name(self, name):
+ assert self._initialized, "Thread.__init__() not called"
+ self._name = str(name)
+
+ @property
+ def ident(self):
+ """Thread identifier of this thread or None if it has not been started.
+
+ This is a nonzero integer. See the get_ident() function. Thread
+ identifiers may be recycled when a thread exits and another thread is
+ created. The identifier is available even after the thread has exited.
+
+ """
+ assert self._initialized, "Thread.__init__() not called"
+ return self._ident
+
+ if _HAVE_THREAD_NATIVE_ID:
+ @property
+ def native_id(self):
+ """Native integral thread ID of this thread, or None if it has not been started.
+
+ This is a non-negative integer. See the get_native_id() function.
+ This represents the Thread ID as reported by the kernel.
+
+ """
+ assert self._initialized, "Thread.__init__() not called"
+ return self._native_id
+
+ def is_alive(self):
+ """Return whether the thread is alive.
+
+ This method returns True just before the run() method starts until just
+ after the run() method terminates. The module function enumerate()
+ returns a list of all alive threads.
+
+ """
+ assert self._initialized, "Thread.__init__() not called"
+ if self._is_stopped or not self._started.is_set():
+ return False
+ self._wait_for_tstate_lock(False)
+ return not self._is_stopped
+
+ def isAlive(self):
+ """Return whether the thread is alive.
+
+ This method is deprecated, use is_alive() instead.
+ """
+ import warnings
+ warnings.warn('isAlive() is deprecated, use is_alive() instead',
+ DeprecationWarning, stacklevel=2)
+ return self.is_alive()
+
+ @property
+ def daemon(self):
+ """A boolean value indicating whether this thread is a daemon thread.
+
+ This must be set before start() is called, otherwise RuntimeError is
+ raised. Its initial value is inherited from the creating thread; the
+ main thread is not a daemon thread and therefore all threads created in
+ the main thread default to daemon = False.
+
+ The entire Python program exits when only daemon threads are left.
+
+ """
+ assert self._initialized, "Thread.__init__() not called"
+ return self._daemonic
+
+ @daemon.setter
+ def daemon(self, daemonic):
+ if not self._initialized:
+ raise RuntimeError("Thread.__init__() not called")
+ if self._started.is_set():
+ raise RuntimeError("cannot set daemon status of active thread")
+ self._daemonic = daemonic
+
+ def isDaemon(self):
+ return self.daemon
+
+ def setDaemon(self, daemonic):
+ self.daemon = daemonic
+
+ def getName(self):
+ return self.name
+
+ def setName(self, name):
+ self.name = name
+
+
+try:
+ from _thread import (_excepthook as excepthook,
+ _ExceptHookArgs as ExceptHookArgs)
+except ImportError:
+ # Simple Python implementation if _thread._excepthook() is not available
+ from traceback import print_exception as _print_exception
+ from collections import namedtuple
+
+ _ExceptHookArgs = namedtuple(
+ 'ExceptHookArgs',
+ 'exc_type exc_value exc_traceback thread')
+
+ def ExceptHookArgs(args):
+ return _ExceptHookArgs(*args)
+
+ def excepthook(args, /):
+ """
+ Handle uncaught Thread.run() exception.
+ """
+ if args.exc_type == SystemExit:
+ # silently ignore SystemExit
+ return
+
+ if _sys is not None and _sys.stderr is not None:
+ stderr = _sys.stderr
+ elif args.thread is not None:
+ stderr = args.thread._stderr
+ if stderr is None:
+ # do nothing if sys.stderr is None and sys.stderr was None
+ # when the thread was created
+ return
+ else:
+ # do nothing if sys.stderr is None and args.thread is None
+ return
+
+ if args.thread is not None:
+ name = args.thread.name
+ else:
+ name = get_ident()
+ print(f"Exception in thread {name}:",
+ file=stderr, flush=True)
+ _print_exception(args.exc_type, args.exc_value, args.exc_traceback,
+ file=stderr)
+ stderr.flush()
+
+
+def _make_invoke_excepthook():
+ # Create a local namespace to ensure that variables remain alive
+ # when _invoke_excepthook() is called, even if it is called late during
+ # Python shutdown. It is mostly needed for daemon threads.
+
+ old_excepthook = excepthook
+ old_sys_excepthook = _sys.excepthook
+ if old_excepthook is None:
+ raise RuntimeError("threading.excepthook is None")
+ if old_sys_excepthook is None:
+ raise RuntimeError("sys.excepthook is None")
+
+ sys_exc_info = _sys.exc_info
+ local_print = print
+ local_sys = _sys
+
+ def invoke_excepthook(thread):
+ global excepthook
+ try:
+ hook = excepthook
+ if hook is None:
+ hook = old_excepthook
+
+ args = ExceptHookArgs([*sys_exc_info(), thread])
+
+ hook(args)
+ except Exception as exc:
+ exc.__suppress_context__ = True
+ del exc
+
+ if local_sys is not None and local_sys.stderr is not None:
+ stderr = local_sys.stderr
+ else:
+ stderr = thread._stderr
+
+ local_print("Exception in threading.excepthook:",
+ file=stderr, flush=True)
+
+ if local_sys is not None and local_sys.excepthook is not None:
+ sys_excepthook = local_sys.excepthook
+ else:
+ sys_excepthook = old_sys_excepthook
+
+ sys_excepthook(*sys_exc_info())
+ finally:
+ # Break reference cycle (exception stored in a variable)
+ args = None
+
+ return invoke_excepthook
+
+
+# The timer class was contributed by Itamar Shtull-Trauring
+
+class Timer(Thread):
+ """Call a function after a specified number of seconds:
+
+ t = Timer(30.0, f, args=None, kwargs=None)
+ t.start()
+ t.cancel() # stop the timer's action if it's still waiting
+
+ """
+
+ def __init__(self, interval, function, args=None, kwargs=None):
+ Thread.__init__(self)
+ self.interval = interval
+ self.function = function
+ self.args = args if args is not None else []
+ self.kwargs = kwargs if kwargs is not None else {}
+ self.finished = Event()
+
+ def cancel(self):
+ """Stop the timer if it hasn't finished yet."""
+ self.finished.set()
+
+ def run(self):
+ self.finished.wait(self.interval)
+ if not self.finished.is_set():
+ self.function(*self.args, **self.kwargs)
+ self.finished.set()
+
+
+# Special thread class to represent the main thread
+
+class _MainThread(Thread):
+
+ def __init__(self):
+ Thread.__init__(self, name="MainThread", daemon=False)
+ self._set_tstate_lock()
+ self._started.set()
+ self._set_ident()
+ if _HAVE_THREAD_NATIVE_ID:
+ self._set_native_id()
+ with _active_limbo_lock:
+ _active[self._ident] = self
+
+
+# Dummy thread class to represent threads not started here.
+# These aren't garbage collected when they die, nor can they be waited for.
+# If they invoke anything in threading.py that calls current_thread(), they
+# leave an entry in the _active dict forever after.
+# Their purpose is to return *something* from current_thread().
+# They are marked as daemon threads so we won't wait for them
+# when we exit (conform previous semantics).
+
+class _DummyThread(Thread):
+
+ def __init__(self):
+ Thread.__init__(self, name=_newname("Dummy-%d"), daemon=True)
+
+ self._started.set()
+ self._set_ident()
+ if _HAVE_THREAD_NATIVE_ID:
+ self._set_native_id()
+ with _active_limbo_lock:
+ _active[self._ident] = self
+
+ def _stop(self):
+ pass
+
+ def is_alive(self):
+ assert not self._is_stopped and self._started.is_set()
+ return True
+
+ def join(self, timeout=None):
+ assert False, "cannot join a dummy thread"
+
+
+# Global API functions
+
+def current_thread():
+ """Return the current Thread object, corresponding to the caller's thread of control.
+
+ If the caller's thread of control was not created through the threading
+ module, a dummy thread object with limited functionality is returned.
+
+ """
+ try:
+ return _active[get_ident()]
+ except KeyError:
+ return _DummyThread()
+
+currentThread = current_thread
+
+def active_count():
+ """Return the number of Thread objects currently alive.
+
+ The returned count is equal to the length of the list returned by
+ enumerate().
+
+ """
+ with _active_limbo_lock:
+ return len(_active) + len(_limbo)
+
+activeCount = active_count
+
+def _enumerate():
+ # Same as enumerate(), but without the lock. Internal use only.
+ return list(_active.values()) + list(_limbo.values())
+
+def enumerate():
+ """Return a list of all Thread objects currently alive.
+
+ The list includes daemonic threads, dummy thread objects created by
+ current_thread(), and the main thread. It excludes terminated threads and
+ threads that have not yet been started.
+
+ """
+ with _active_limbo_lock:
+ return list(_active.values()) + list(_limbo.values())
+
+from _thread import stack_size
+
+# Create the main thread object,
+# and make it available for the interpreter
+# (Py_Main) as threading._shutdown.
+
+_main_thread = _MainThread()
+
+def _shutdown():
+ """
+ Wait until the Python thread state of all non-daemon threads get deleted.
+ """
+ # Obscure: other threads may be waiting to join _main_thread. That's
+ # dubious, but some code does it. We can't wait for C code to release
+ # the main thread's tstate_lock - that won't happen until the interpreter
+ # is nearly dead. So we release it here. Note that just calling _stop()
+ # isn't enough: other threads may already be waiting on _tstate_lock.
+ if _main_thread._is_stopped:
+ # _shutdown() was already called
+ return
+
+ # Main thread
+ tlock = _main_thread._tstate_lock
+ # The main thread isn't finished yet, so its thread state lock can't have
+ # been released.
+ assert tlock is not None
+ assert tlock.locked()
+ tlock.release()
+ _main_thread._stop()
+
+ # Join all non-deamon threads
+ while True:
+ with _shutdown_locks_lock:
+ locks = list(_shutdown_locks)
+ _shutdown_locks.clear()
+
+ if not locks:
+ break
+
+ for lock in locks:
+ # mimick Thread.join()
+ lock.acquire()
+ lock.release()
+
+ # new threads can be spawned while we were waiting for the other
+ # threads to complete
+
+
+def main_thread():
+ """Return the main thread object.
+
+ In normal conditions, the main thread is the thread from which the
+ Python interpreter was started.
+ """
+ return _main_thread
+
+# get thread-local implementation, either from the thread
+# module, or from the python fallback
+
+try:
+ from _thread import _local as local
+except ImportError:
+ from _threading_local import local
+
+
+def _after_fork():
+ """
+ Cleanup threading module state that should not exist after a fork.
+ """
+ # Reset _active_limbo_lock, in case we forked while the lock was held
+ # by another (non-forked) thread. http://bugs.python.org/issue874900
+ global _active_limbo_lock, _main_thread
+ global _shutdown_locks_lock, _shutdown_locks
+ _active_limbo_lock = _allocate_lock()
+
+ # fork() only copied the current thread; clear references to others.
+ new_active = {}
+
+ try:
+ current = _active[get_ident()]
+ except KeyError:
+ # fork() was called in a thread which was not spawned
+ # by threading.Thread. For example, a thread spawned
+ # by thread.start_new_thread().
+ current = _MainThread()
+
+ _main_thread = current
+
+ # reset _shutdown() locks: threads re-register their _tstate_lock below
+ _shutdown_locks_lock = _allocate_lock()
+ _shutdown_locks = set()
+
+ with _active_limbo_lock:
+ # Dangling thread instances must still have their locks reset,
+ # because someone may join() them.
+ threads = set(_enumerate())
+ threads.update(_dangling)
+ for thread in threads:
+ # Any lock/condition variable may be currently locked or in an
+ # invalid state, so we reinitialize them.
+ if thread is current:
+ # There is only one active thread. We reset the ident to
+ # its new value since it can have changed.
+ thread._reset_internal_locks(True)
+ ident = get_ident()
+ thread._ident = ident
+ new_active[ident] = thread
+ else:
+ # All the others are already stopped.
+ thread._reset_internal_locks(False)
+ thread._stop()
+
+ _limbo.clear()
+ _active.clear()
+ _active.update(new_active)
+ assert len(_active) == 1
+
+
+if hasattr(_os, "register_at_fork"):
+ _os.register_at_fork(after_in_child=_after_fork)
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/tokenize.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/tokenize.py
new file mode 100644
index 0000000000000000000000000000000000000000..1aee21b5e18fa716dfaa5306fc6aa8a96d253641
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/tokenize.py
@@ -0,0 +1,682 @@
+"""Tokenization help for Python programs.
+
+tokenize(readline) is a generator that breaks a stream of bytes into
+Python tokens. It decodes the bytes according to PEP-0263 for
+determining source file encoding.
+
+It accepts a readline-like method which is called repeatedly to get the
+next line of input (or b"" for EOF). It generates 5-tuples with these
+members:
+
+ the token type (see token.py)
+ the token (a string)
+ the starting (row, column) indices of the token (a 2-tuple of ints)
+ the ending (row, column) indices of the token (a 2-tuple of ints)
+ the original line (string)
+
+It is designed to match the working of the Python tokenizer exactly, except
+that it produces COMMENT tokens for comments and gives type OP for all
+operators. Additionally, all token lists start with an ENCODING token
+which tells you which encoding was used to decode the bytes stream.
+"""
+
+__author__ = 'Ka-Ping Yee '
+__credits__ = ('GvR, ESR, Tim Peters, Thomas Wouters, Fred Drake, '
+ 'Skip Montanaro, Raymond Hettinger, Trent Nelson, '
+ 'Michael Foord')
+from builtins import open as _builtin_open
+from codecs import lookup, BOM_UTF8
+import collections
+from io import TextIOWrapper
+import itertools as _itertools
+import re
+import sys
+from token import *
+from token import EXACT_TOKEN_TYPES
+
+cookie_re = re.compile(r'^[ \t\f]*#.*?coding[:=][ \t]*([-\w.]+)', re.ASCII)
+blank_re = re.compile(br'^[ \t\f]*(?:[#\r\n]|$)', re.ASCII)
+
+import token
+__all__ = token.__all__ + ["tokenize", "generate_tokens", "detect_encoding",
+ "untokenize", "TokenInfo"]
+del token
+
+class TokenInfo(collections.namedtuple('TokenInfo', 'type string start end line')):
+ def __repr__(self):
+ annotated_type = '%d (%s)' % (self.type, tok_name[self.type])
+ return ('TokenInfo(type=%s, string=%r, start=%r, end=%r, line=%r)' %
+ self._replace(type=annotated_type))
+
+ @property
+ def exact_type(self):
+ if self.type == OP and self.string in EXACT_TOKEN_TYPES:
+ return EXACT_TOKEN_TYPES[self.string]
+ else:
+ return self.type
+
+def group(*choices): return '(' + '|'.join(choices) + ')'
+def any(*choices): return group(*choices) + '*'
+def maybe(*choices): return group(*choices) + '?'
+
+# Note: we use unicode matching for names ("\w") but ascii matching for
+# number literals.
+Whitespace = r'[ \f\t]*'
+Comment = r'#[^\r\n]*'
+Ignore = Whitespace + any(r'\\\r?\n' + Whitespace) + maybe(Comment)
+Name = r'\w+'
+
+Hexnumber = r'0[xX](?:_?[0-9a-fA-F])+'
+Binnumber = r'0[bB](?:_?[01])+'
+Octnumber = r'0[oO](?:_?[0-7])+'
+Decnumber = r'(?:0(?:_?0)*|[1-9](?:_?[0-9])*)'
+Intnumber = group(Hexnumber, Binnumber, Octnumber, Decnumber)
+Exponent = r'[eE][-+]?[0-9](?:_?[0-9])*'
+Pointfloat = group(r'[0-9](?:_?[0-9])*\.(?:[0-9](?:_?[0-9])*)?',
+ r'\.[0-9](?:_?[0-9])*') + maybe(Exponent)
+Expfloat = r'[0-9](?:_?[0-9])*' + Exponent
+Floatnumber = group(Pointfloat, Expfloat)
+Imagnumber = group(r'[0-9](?:_?[0-9])*[jJ]', Floatnumber + r'[jJ]')
+Number = group(Imagnumber, Floatnumber, Intnumber)
+
+# Return the empty string, plus all of the valid string prefixes.
+def _all_string_prefixes():
+ # The valid string prefixes. Only contain the lower case versions,
+ # and don't contain any permutations (include 'fr', but not
+ # 'rf'). The various permutations will be generated.
+ _valid_string_prefixes = ['b', 'r', 'u', 'f', 'br', 'fr']
+ # if we add binary f-strings, add: ['fb', 'fbr']
+ result = {''}
+ for prefix in _valid_string_prefixes:
+ for t in _itertools.permutations(prefix):
+ # create a list with upper and lower versions of each
+ # character
+ for u in _itertools.product(*[(c, c.upper()) for c in t]):
+ result.add(''.join(u))
+ return result
+
+def _compile(expr):
+ return re.compile(expr, re.UNICODE)
+
+# Note that since _all_string_prefixes includes the empty string,
+# StringPrefix can be the empty string (making it optional).
+StringPrefix = group(*_all_string_prefixes())
+
+# Tail end of ' string.
+Single = r"[^'\\]*(?:\\.[^'\\]*)*'"
+# Tail end of " string.
+Double = r'[^"\\]*(?:\\.[^"\\]*)*"'
+# Tail end of ''' string.
+Single3 = r"[^'\\]*(?:(?:\\.|'(?!''))[^'\\]*)*'''"
+# Tail end of """ string.
+Double3 = r'[^"\\]*(?:(?:\\.|"(?!""))[^"\\]*)*"""'
+Triple = group(StringPrefix + "'''", StringPrefix + '"""')
+# Single-line ' or " string.
+String = group(StringPrefix + r"'[^\n'\\]*(?:\\.[^\n'\\]*)*'",
+ StringPrefix + r'"[^\n"\\]*(?:\\.[^\n"\\]*)*"')
+
+# Sorting in reverse order puts the long operators before their prefixes.
+# Otherwise if = came before ==, == would get recognized as two instances
+# of =.
+Special = group(*map(re.escape, sorted(EXACT_TOKEN_TYPES, reverse=True)))
+Funny = group(r'\r?\n', Special)
+
+PlainToken = group(Number, Funny, String, Name)
+Token = Ignore + PlainToken
+
+# First (or only) line of ' or " string.
+ContStr = group(StringPrefix + r"'[^\n'\\]*(?:\\.[^\n'\\]*)*" +
+ group("'", r'\\\r?\n'),
+ StringPrefix + r'"[^\n"\\]*(?:\\.[^\n"\\]*)*' +
+ group('"', r'\\\r?\n'))
+PseudoExtras = group(r'\\\r?\n|\Z', Comment, Triple)
+PseudoToken = Whitespace + group(PseudoExtras, Number, Funny, ContStr, Name)
+
+# For a given string prefix plus quotes, endpats maps it to a regex
+# to match the remainder of that string. _prefix can be empty, for
+# a normal single or triple quoted string (with no prefix).
+endpats = {}
+for _prefix in _all_string_prefixes():
+ endpats[_prefix + "'"] = Single
+ endpats[_prefix + '"'] = Double
+ endpats[_prefix + "'''"] = Single3
+ endpats[_prefix + '"""'] = Double3
+
+# A set of all of the single and triple quoted string prefixes,
+# including the opening quotes.
+single_quoted = set()
+triple_quoted = set()
+for t in _all_string_prefixes():
+ for u in (t + '"', t + "'"):
+ single_quoted.add(u)
+ for u in (t + '"""', t + "'''"):
+ triple_quoted.add(u)
+
+tabsize = 8
+
+class TokenError(Exception): pass
+
+class StopTokenizing(Exception): pass
+
+
+class Untokenizer:
+
+ def __init__(self):
+ self.tokens = []
+ self.prev_row = 1
+ self.prev_col = 0
+ self.encoding = None
+
+ def add_whitespace(self, start):
+ row, col = start
+ if row < self.prev_row or row == self.prev_row and col < self.prev_col:
+ raise ValueError("start ({},{}) precedes previous end ({},{})"
+ .format(row, col, self.prev_row, self.prev_col))
+ row_offset = row - self.prev_row
+ if row_offset:
+ self.tokens.append("\\\n" * row_offset)
+ self.prev_col = 0
+ col_offset = col - self.prev_col
+ if col_offset:
+ self.tokens.append(" " * col_offset)
+
+ def untokenize(self, iterable):
+ it = iter(iterable)
+ indents = []
+ startline = False
+ for t in it:
+ if len(t) == 2:
+ self.compat(t, it)
+ break
+ tok_type, token, start, end, line = t
+ if tok_type == ENCODING:
+ self.encoding = token
+ continue
+ if tok_type == ENDMARKER:
+ break
+ if tok_type == INDENT:
+ indents.append(token)
+ continue
+ elif tok_type == DEDENT:
+ indents.pop()
+ self.prev_row, self.prev_col = end
+ continue
+ elif tok_type in (NEWLINE, NL):
+ startline = True
+ elif startline and indents:
+ indent = indents[-1]
+ if start[1] >= len(indent):
+ self.tokens.append(indent)
+ self.prev_col = len(indent)
+ startline = False
+ self.add_whitespace(start)
+ self.tokens.append(token)
+ self.prev_row, self.prev_col = end
+ if tok_type in (NEWLINE, NL):
+ self.prev_row += 1
+ self.prev_col = 0
+ return "".join(self.tokens)
+
+ def compat(self, token, iterable):
+ indents = []
+ toks_append = self.tokens.append
+ startline = token[0] in (NEWLINE, NL)
+ prevstring = False
+
+ for tok in _itertools.chain([token], iterable):
+ toknum, tokval = tok[:2]
+ if toknum == ENCODING:
+ self.encoding = tokval
+ continue
+
+ if toknum in (NAME, NUMBER):
+ tokval += ' '
+
+ # Insert a space between two consecutive strings
+ if toknum == STRING:
+ if prevstring:
+ tokval = ' ' + tokval
+ prevstring = True
+ else:
+ prevstring = False
+
+ if toknum == INDENT:
+ indents.append(tokval)
+ continue
+ elif toknum == DEDENT:
+ indents.pop()
+ continue
+ elif toknum in (NEWLINE, NL):
+ startline = True
+ elif startline and indents:
+ toks_append(indents[-1])
+ startline = False
+ toks_append(tokval)
+
+
+def untokenize(iterable):
+ """Transform tokens back into Python source code.
+ It returns a bytes object, encoded using the ENCODING
+ token, which is the first token sequence output by tokenize.
+
+ Each element returned by the iterable must be a token sequence
+ with at least two elements, a token number and token value. If
+ only two tokens are passed, the resulting output is poor.
+
+ Round-trip invariant for full input:
+ Untokenized source will match input source exactly
+
+ Round-trip invariant for limited input:
+ # Output bytes will tokenize back to the input
+ t1 = [tok[:2] for tok in tokenize(f.readline)]
+ newcode = untokenize(t1)
+ readline = BytesIO(newcode).readline
+ t2 = [tok[:2] for tok in tokenize(readline)]
+ assert t1 == t2
+ """
+ ut = Untokenizer()
+ out = ut.untokenize(iterable)
+ if ut.encoding is not None:
+ out = out.encode(ut.encoding)
+ return out
+
+
+def _get_normal_name(orig_enc):
+ """Imitates get_normal_name in tokenizer.c."""
+ # Only care about the first 12 characters.
+ enc = orig_enc[:12].lower().replace("_", "-")
+ if enc == "utf-8" or enc.startswith("utf-8-"):
+ return "utf-8"
+ if enc in ("latin-1", "iso-8859-1", "iso-latin-1") or \
+ enc.startswith(("latin-1-", "iso-8859-1-", "iso-latin-1-")):
+ return "iso-8859-1"
+ return orig_enc
+
+def detect_encoding(readline):
+ """
+ The detect_encoding() function is used to detect the encoding that should
+ be used to decode a Python source file. It requires one argument, readline,
+ in the same way as the tokenize() generator.
+
+ It will call readline a maximum of twice, and return the encoding used
+ (as a string) and a list of any lines (left as bytes) it has read in.
+
+ It detects the encoding from the presence of a utf-8 bom or an encoding
+ cookie as specified in pep-0263. If both a bom and a cookie are present,
+ but disagree, a SyntaxError will be raised. If the encoding cookie is an
+ invalid charset, raise a SyntaxError. Note that if a utf-8 bom is found,
+ 'utf-8-sig' is returned.
+
+ If no encoding is specified, then the default of 'utf-8' will be returned.
+ """
+ try:
+ filename = readline.__self__.name
+ except AttributeError:
+ filename = None
+ bom_found = False
+ encoding = None
+ default = 'utf-8'
+ def read_or_stop():
+ try:
+ return readline()
+ except StopIteration:
+ return b''
+
+ def find_cookie(line):
+ try:
+ # Decode as UTF-8. Either the line is an encoding declaration,
+ # in which case it should be pure ASCII, or it must be UTF-8
+ # per default encoding.
+ line_string = line.decode('utf-8')
+ except UnicodeDecodeError:
+ msg = "invalid or missing encoding declaration"
+ if filename is not None:
+ msg = '{} for {!r}'.format(msg, filename)
+ raise SyntaxError(msg)
+
+ match = cookie_re.match(line_string)
+ if not match:
+ return None
+ encoding = _get_normal_name(match.group(1))
+ try:
+ codec = lookup(encoding)
+ except LookupError:
+ # This behaviour mimics the Python interpreter
+ if filename is None:
+ msg = "unknown encoding: " + encoding
+ else:
+ msg = "unknown encoding for {!r}: {}".format(filename,
+ encoding)
+ raise SyntaxError(msg)
+
+ if bom_found:
+ if encoding != 'utf-8':
+ # This behaviour mimics the Python interpreter
+ if filename is None:
+ msg = 'encoding problem: utf-8'
+ else:
+ msg = 'encoding problem for {!r}: utf-8'.format(filename)
+ raise SyntaxError(msg)
+ encoding += '-sig'
+ return encoding
+
+ first = read_or_stop()
+ if first.startswith(BOM_UTF8):
+ bom_found = True
+ first = first[3:]
+ default = 'utf-8-sig'
+ if not first:
+ return default, []
+
+ encoding = find_cookie(first)
+ if encoding:
+ return encoding, [first]
+ if not blank_re.match(first):
+ return default, [first]
+
+ second = read_or_stop()
+ if not second:
+ return default, [first]
+
+ encoding = find_cookie(second)
+ if encoding:
+ return encoding, [first, second]
+
+ return default, [first, second]
+
+
+def open(filename):
+ """Open a file in read only mode using the encoding detected by
+ detect_encoding().
+ """
+ buffer = _builtin_open(filename, 'rb')
+ try:
+ encoding, lines = detect_encoding(buffer.readline)
+ buffer.seek(0)
+ text = TextIOWrapper(buffer, encoding, line_buffering=True)
+ text.mode = 'r'
+ return text
+ except:
+ buffer.close()
+ raise
+
+
+def tokenize(readline):
+ """
+ The tokenize() generator requires one argument, readline, which
+ must be a callable object which provides the same interface as the
+ readline() method of built-in file objects. Each call to the function
+ should return one line of input as bytes. Alternatively, readline
+ can be a callable function terminating with StopIteration:
+ readline = open(myfile, 'rb').__next__ # Example of alternate readline
+
+ The generator produces 5-tuples with these members: the token type; the
+ token string; a 2-tuple (srow, scol) of ints specifying the row and
+ column where the token begins in the source; a 2-tuple (erow, ecol) of
+ ints specifying the row and column where the token ends in the source;
+ and the line on which the token was found. The line passed is the
+ physical line.
+
+ The first token sequence will always be an ENCODING token
+ which tells you which encoding was used to decode the bytes stream.
+ """
+ encoding, consumed = detect_encoding(readline)
+ empty = _itertools.repeat(b"")
+ rl_gen = _itertools.chain(consumed, iter(readline, b""), empty)
+ return _tokenize(rl_gen.__next__, encoding)
+
+
+def _tokenize(readline, encoding):
+ lnum = parenlev = continued = 0
+ numchars = '0123456789'
+ contstr, needcont = '', 0
+ contline = None
+ indents = [0]
+
+ if encoding is not None:
+ if encoding == "utf-8-sig":
+ # BOM will already have been stripped.
+ encoding = "utf-8"
+ yield TokenInfo(ENCODING, encoding, (0, 0), (0, 0), '')
+ last_line = b''
+ line = b''
+ while True: # loop over lines in stream
+ try:
+ # We capture the value of the line variable here because
+ # readline uses the empty string '' to signal end of input,
+ # hence `line` itself will always be overwritten at the end
+ # of this loop.
+ last_line = line
+ line = readline()
+ except StopIteration:
+ line = b''
+
+ if encoding is not None:
+ line = line.decode(encoding)
+ lnum += 1
+ pos, max = 0, len(line)
+
+ if contstr: # continued string
+ if not line:
+ raise TokenError("EOF in multi-line string", strstart)
+ endmatch = endprog.match(line)
+ if endmatch:
+ pos = end = endmatch.end(0)
+ yield TokenInfo(STRING, contstr + line[:end],
+ strstart, (lnum, end), contline + line)
+ contstr, needcont = '', 0
+ contline = None
+ elif needcont and line[-2:] != '\\\n' and line[-3:] != '\\\r\n':
+ yield TokenInfo(ERRORTOKEN, contstr + line,
+ strstart, (lnum, len(line)), contline)
+ contstr = ''
+ contline = None
+ continue
+ else:
+ contstr = contstr + line
+ contline = contline + line
+ continue
+
+ elif parenlev == 0 and not continued: # new statement
+ if not line: break
+ column = 0
+ while pos < max: # measure leading whitespace
+ if line[pos] == ' ':
+ column += 1
+ elif line[pos] == '\t':
+ column = (column//tabsize + 1)*tabsize
+ elif line[pos] == '\f':
+ column = 0
+ else:
+ break
+ pos += 1
+ if pos == max:
+ break
+
+ if line[pos] in '#\r\n': # skip comments or blank lines
+ if line[pos] == '#':
+ comment_token = line[pos:].rstrip('\r\n')
+ yield TokenInfo(COMMENT, comment_token,
+ (lnum, pos), (lnum, pos + len(comment_token)), line)
+ pos += len(comment_token)
+
+ yield TokenInfo(NL, line[pos:],
+ (lnum, pos), (lnum, len(line)), line)
+ continue
+
+ if column > indents[-1]: # count indents or dedents
+ indents.append(column)
+ yield TokenInfo(INDENT, line[:pos], (lnum, 0), (lnum, pos), line)
+ while column < indents[-1]:
+ if column not in indents:
+ raise IndentationError(
+ "unindent does not match any outer indentation level",
+ ("", lnum, pos, line))
+ indents = indents[:-1]
+
+ yield TokenInfo(DEDENT, '', (lnum, pos), (lnum, pos), line)
+
+ else: # continued statement
+ if not line:
+ raise TokenError("EOF in multi-line statement", (lnum, 0))
+ continued = 0
+
+ while pos < max:
+ pseudomatch = _compile(PseudoToken).match(line, pos)
+ if pseudomatch: # scan for tokens
+ start, end = pseudomatch.span(1)
+ spos, epos, pos = (lnum, start), (lnum, end), end
+ if start == end:
+ continue
+ token, initial = line[start:end], line[start]
+
+ if (initial in numchars or # ordinary number
+ (initial == '.' and token != '.' and token != '...')):
+ yield TokenInfo(NUMBER, token, spos, epos, line)
+ elif initial in '\r\n':
+ if parenlev > 0:
+ yield TokenInfo(NL, token, spos, epos, line)
+ else:
+ yield TokenInfo(NEWLINE, token, spos, epos, line)
+
+ elif initial == '#':
+ assert not token.endswith("\n")
+ yield TokenInfo(COMMENT, token, spos, epos, line)
+
+ elif token in triple_quoted:
+ endprog = _compile(endpats[token])
+ endmatch = endprog.match(line, pos)
+ if endmatch: # all on one line
+ pos = endmatch.end(0)
+ token = line[start:pos]
+ yield TokenInfo(STRING, token, spos, (lnum, pos), line)
+ else:
+ strstart = (lnum, start) # multiple lines
+ contstr = line[start:]
+ contline = line
+ break
+
+ # Check up to the first 3 chars of the token to see if
+ # they're in the single_quoted set. If so, they start
+ # a string.
+ # We're using the first 3, because we're looking for
+ # "rb'" (for example) at the start of the token. If
+ # we switch to longer prefixes, this needs to be
+ # adjusted.
+ # Note that initial == token[:1].
+ # Also note that single quote checking must come after
+ # triple quote checking (above).
+ elif (initial in single_quoted or
+ token[:2] in single_quoted or
+ token[:3] in single_quoted):
+ if token[-1] == '\n': # continued string
+ strstart = (lnum, start)
+ # Again, using the first 3 chars of the
+ # token. This is looking for the matching end
+ # regex for the correct type of quote
+ # character. So it's really looking for
+ # endpats["'"] or endpats['"'], by trying to
+ # skip string prefix characters, if any.
+ endprog = _compile(endpats.get(initial) or
+ endpats.get(token[1]) or
+ endpats.get(token[2]))
+ contstr, needcont = line[start:], 1
+ contline = line
+ break
+ else: # ordinary string
+ yield TokenInfo(STRING, token, spos, epos, line)
+
+ elif initial.isidentifier(): # ordinary name
+ yield TokenInfo(NAME, token, spos, epos, line)
+ elif initial == '\\': # continued stmt
+ continued = 1
+ else:
+ if initial in '([{':
+ parenlev += 1
+ elif initial in ')]}':
+ parenlev -= 1
+ yield TokenInfo(OP, token, spos, epos, line)
+ else:
+ yield TokenInfo(ERRORTOKEN, line[pos],
+ (lnum, pos), (lnum, pos+1), line)
+ pos += 1
+
+ # Add an implicit NEWLINE if the input doesn't end in one
+ if last_line and last_line[-1] not in '\r\n':
+ yield TokenInfo(NEWLINE, '', (lnum - 1, len(last_line)), (lnum - 1, len(last_line) + 1), '')
+ for indent in indents[1:]: # pop remaining indent levels
+ yield TokenInfo(DEDENT, '', (lnum, 0), (lnum, 0), '')
+ yield TokenInfo(ENDMARKER, '', (lnum, 0), (lnum, 0), '')
+
+
+def generate_tokens(readline):
+ """Tokenize a source reading Python code as unicode strings.
+
+ This has the same API as tokenize(), except that it expects the *readline*
+ callable to return str objects instead of bytes.
+ """
+ return _tokenize(readline, None)
+
+def main():
+ import argparse
+
+ # Helper error handling routines
+ def perror(message):
+ sys.stderr.write(message)
+ sys.stderr.write('\n')
+
+ def error(message, filename=None, location=None):
+ if location:
+ args = (filename,) + location + (message,)
+ perror("%s:%d:%d: error: %s" % args)
+ elif filename:
+ perror("%s: error: %s" % (filename, message))
+ else:
+ perror("error: %s" % message)
+ sys.exit(1)
+
+ # Parse the arguments and options
+ parser = argparse.ArgumentParser(prog='python -m tokenize')
+ parser.add_argument(dest='filename', nargs='?',
+ metavar='filename.py',
+ help='the file to tokenize; defaults to stdin')
+ parser.add_argument('-e', '--exact', dest='exact', action='store_true',
+ help='display token names using the exact type')
+ args = parser.parse_args()
+
+ try:
+ # Tokenize the input
+ if args.filename:
+ filename = args.filename
+ with _builtin_open(filename, 'rb') as f:
+ tokens = list(tokenize(f.readline))
+ else:
+ filename = ""
+ tokens = _tokenize(sys.stdin.readline, None)
+
+ # Output the tokenization
+ for token in tokens:
+ token_type = token.type
+ if args.exact:
+ token_type = token.exact_type
+ token_range = "%d,%d-%d,%d:" % (token.start + token.end)
+ print("%-20s%-15s%-15r" %
+ (token_range, tok_name[token_type], token.string))
+ except IndentationError as err:
+ line, column = err.args[1][1:3]
+ error(err.args[0], filename, (line, column))
+ except TokenError as err:
+ line, column = err.args[1]
+ error(err.args[0], filename, (line, column))
+ except SyntaxError as err:
+ error(err, filename)
+ except OSError as err:
+ error(err)
+ except KeyboardInterrupt:
+ print("interrupted\n")
+ except Exception as err:
+ perror("unexpected error: %s" % err)
+ raise
+
+if __name__ == "__main__":
+ main()
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/tty.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/tty.py
new file mode 100644
index 0000000000000000000000000000000000000000..a72eb6755450bb07d9bb77fb9cdc3cf2f0148534
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/tty.py
@@ -0,0 +1,36 @@
+"""Terminal utilities."""
+
+# Author: Steen Lumholt.
+
+from termios import *
+
+__all__ = ["setraw", "setcbreak"]
+
+# Indexes for termios list.
+IFLAG = 0
+OFLAG = 1
+CFLAG = 2
+LFLAG = 3
+ISPEED = 4
+OSPEED = 5
+CC = 6
+
+def setraw(fd, when=TCSAFLUSH):
+ """Put terminal into a raw mode."""
+ mode = tcgetattr(fd)
+ mode[IFLAG] = mode[IFLAG] & ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON)
+ mode[OFLAG] = mode[OFLAG] & ~(OPOST)
+ mode[CFLAG] = mode[CFLAG] & ~(CSIZE | PARENB)
+ mode[CFLAG] = mode[CFLAG] | CS8
+ mode[LFLAG] = mode[LFLAG] & ~(ECHO | ICANON | IEXTEN | ISIG)
+ mode[CC][VMIN] = 1
+ mode[CC][VTIME] = 0
+ tcsetattr(fd, when, mode)
+
+def setcbreak(fd, when=TCSAFLUSH):
+ """Put terminal into a cbreak mode."""
+ mode = tcgetattr(fd)
+ mode[LFLAG] = mode[LFLAG] & ~(ECHO | ICANON)
+ mode[CC][VMIN] = 1
+ mode[CC][VTIME] = 0
+ tcsetattr(fd, when, mode)
diff --git a/my_container_sandbox/workspace/anaconda3/lib/python3.8/turtle.py b/my_container_sandbox/workspace/anaconda3/lib/python3.8/turtle.py
new file mode 100644
index 0000000000000000000000000000000000000000..6e19032cce2a43598ee35ff8d7f00f3dc13ad700
--- /dev/null
+++ b/my_container_sandbox/workspace/anaconda3/lib/python3.8/turtle.py
@@ -0,0 +1,4140 @@
+#
+# turtle.py: a Tkinter based turtle graphics module for Python
+# Version 1.1b - 4. 5. 2009
+#
+# Copyright (C) 2006 - 2010 Gregor Lingl
+# email: glingl@aon.at
+#
+# This software is provided 'as-is', without any express or implied
+# warranty. In no event will the authors be held liable for any damages
+# arising from the use of this software.
+#
+# Permission is granted to anyone to use this software for any purpose,
+# including commercial applications, and to alter it and redistribute it
+# freely, subject to the following restrictions:
+#
+# 1. The origin of this software must not be misrepresented; you must not
+# claim that you wrote the original software. If you use this software
+# in a product, an acknowledgment in the product documentation would be
+# appreciated but is not required.
+# 2. Altered source versions must be plainly marked as such, and must not be
+# misrepresented as being the original software.
+# 3. This notice may not be removed or altered from any source distribution.
+
+
+"""
+Turtle graphics is a popular way for introducing programming to
+kids. It was part of the original Logo programming language developed
+by Wally Feurzig and Seymour Papert in 1966.
+
+Imagine a robotic turtle starting at (0, 0) in the x-y plane. After an ``import turtle``, give it
+the command turtle.forward(15), and it moves (on-screen!) 15 pixels in
+the direction it is facing, drawing a line as it moves. Give it the
+command turtle.right(25), and it rotates in-place 25 degrees clockwise.
+
+By combining together these and similar commands, intricate shapes and
+pictures can easily be drawn.
+
+----- turtle.py
+
+This module is an extended reimplementation of turtle.py from the
+Python standard distribution up to Python 2.5. (See: http://www.python.org)
+
+It tries to keep the merits of turtle.py and to be (nearly) 100%
+compatible with it. This means in the first place to enable the
+learning programmer to use all the commands, classes and methods
+interactively when using the module from within IDLE run with
+the -n switch.
+
+Roughly it has the following features added:
+
+- Better animation of the turtle movements, especially of turning the
+ turtle. So the turtles can more easily be used as a visual feedback
+ instrument by the (beginning) programmer.
+
+- Different turtle shapes, gif-images as turtle shapes, user defined
+ and user controllable turtle shapes, among them compound
+ (multicolored) shapes. Turtle shapes can be stretched and tilted, which
+ makes turtles very versatile geometrical objects.
+
+- Fine control over turtle movement and screen updates via delay(),
+ and enhanced tracer() and speed() methods.
+
+- Aliases for the most commonly used commands, like fd for forward etc.,
+ following the early Logo traditions. This reduces the boring work of
+ typing long sequences of commands, which often occur in a natural way
+ when kids try to program fancy pictures on their first encounter with
+ turtle graphics.
+
+- Turtles now have an undo()-method with configurable undo-buffer.
+
+- Some simple commands/methods for creating event driven programs
+ (mouse-, key-, timer-events). Especially useful for programming games.
+
+- A scrollable Canvas class. The default scrollable Canvas can be
+ extended interactively as needed while playing around with the turtle(s).
+
+- A TurtleScreen class with methods controlling background color or
+ background image, window and canvas size and other properties of the
+ TurtleScreen.
+
+- There is a method, setworldcoordinates(), to install a user defined
+ coordinate-system for the TurtleScreen.
+
+- The implementation uses a 2-vector class named Vec2D, derived from tuple.
+ This class is public, so it can be imported by the application programmer,
+ which makes certain types of computations very natural and compact.
+
+- Appearance of the TurtleScreen and the Turtles at startup/import can be
+ configured by means of a turtle.cfg configuration file.
+ The default configuration mimics the appearance of the old turtle module.
+
+- If configured appropriately the module reads in docstrings from a docstring
+ dictionary in some different language, supplied separately and replaces
+ the English ones by those read in. There is a utility function
+ write_docstringdict() to write a dictionary with the original (English)
+ docstrings to disc, so it can serve as a template for translations.
+
+Behind the scenes there are some features included with possible
+extensions in mind. These will be commented and documented elsewhere.
+
+"""
+
+_ver = "turtle 1.1b- - for Python 3.1 - 4. 5. 2009"
+
+# print(_ver)
+
+import tkinter as TK
+import types
+import math
+import time
+import inspect
+import sys
+
+from os.path import isfile, split, join
+from copy import deepcopy
+from tkinter import simpledialog
+
+_tg_classes = ['ScrolledCanvas', 'TurtleScreen', 'Screen',
+ 'RawTurtle', 'Turtle', 'RawPen', 'Pen', 'Shape', 'Vec2D']
+_tg_screen_functions = ['addshape', 'bgcolor', 'bgpic', 'bye',
+ 'clearscreen', 'colormode', 'delay', 'exitonclick', 'getcanvas',
+ 'getshapes', 'listen', 'mainloop', 'mode', 'numinput',
+ 'onkey', 'onkeypress', 'onkeyrelease', 'onscreenclick', 'ontimer',
+ 'register_shape', 'resetscreen', 'screensize', 'setup',
+ 'setworldcoordinates', 'textinput', 'title', 'tracer', 'turtles', 'update',
+ 'window_height', 'window_width']
+_tg_turtle_functions = ['back', 'backward', 'begin_fill', 'begin_poly', 'bk',
+ 'circle', 'clear', 'clearstamp', 'clearstamps', 'clone', 'color',
+ 'degrees', 'distance', 'dot', 'down', 'end_fill', 'end_poly', 'fd',
+ 'fillcolor', 'filling', 'forward', 'get_poly', 'getpen', 'getscreen', 'get_shapepoly',
+ 'getturtle', 'goto', 'heading', 'hideturtle', 'home', 'ht', 'isdown',
+ 'isvisible', 'left', 'lt', 'onclick', 'ondrag', 'onrelease', 'pd',
+ 'pen', 'pencolor', 'pendown', 'pensize', 'penup', 'pos', 'position',
+ 'pu', 'radians', 'right', 'reset', 'resizemode', 'rt',
+ 'seth', 'setheading', 'setpos', 'setposition', 'settiltangle',
+ 'setundobuffer', 'setx', 'sety', 'shape', 'shapesize', 'shapetransform', 'shearfactor', 'showturtle',
+ 'speed', 'st', 'stamp', 'tilt', 'tiltangle', 'towards',
+ 'turtlesize', 'undo', 'undobufferentries', 'up', 'width',
+ 'write', 'xcor', 'ycor']
+_tg_utilities = ['write_docstringdict', 'done']
+
+__all__ = (_tg_classes + _tg_screen_functions + _tg_turtle_functions +
+ _tg_utilities + ['Terminator']) # + _math_functions)
+
+_alias_list = ['addshape', 'backward', 'bk', 'fd', 'ht', 'lt', 'pd', 'pos',
+ 'pu', 'rt', 'seth', 'setpos', 'setposition', 'st',
+ 'turtlesize', 'up', 'width']
+
+_CFG = {"width" : 0.5, # Screen
+ "height" : 0.75,
+ "canvwidth" : 400,
+ "canvheight": 300,
+ "leftright": None,
+ "topbottom": None,
+ "mode": "standard", # TurtleScreen
+ "colormode": 1.0,
+ "delay": 10,
+ "undobuffersize": 1000, # RawTurtle
+ "shape": "classic",
+ "pencolor" : "black",
+ "fillcolor" : "black",
+ "resizemode" : "noresize",
+ "visible" : True,
+ "language": "english", # docstrings
+ "exampleturtle": "turtle",
+ "examplescreen": "screen",
+ "title": "Python Turtle Graphics",
+ "using_IDLE": False
+ }
+
+def config_dict(filename):
+ """Convert content of config-file into dictionary."""
+ with open(filename, "r") as f:
+ cfglines = f.readlines()
+ cfgdict = {}
+ for line in cfglines:
+ line = line.strip()
+ if not line or line.startswith("#"):
+ continue
+ try:
+ key, value = line.split("=")
+ except ValueError:
+ print("Bad line in config-file %s:\n%s" % (filename,line))
+ continue
+ key = key.strip()
+ value = value.strip()
+ if value in ["True", "False", "None", "''", '""']:
+ value = eval(value)
+ else:
+ try:
+ if "." in value:
+ value = float(value)
+ else:
+ value = int(value)
+ except ValueError:
+ pass # value need not be converted
+ cfgdict[key] = value
+ return cfgdict
+
+def readconfig(cfgdict):
+ """Read config-files, change configuration-dict accordingly.
+
+ If there is a turtle.cfg file in the current working directory,
+ read it from there. If this contains an importconfig-value,
+ say 'myway', construct filename turtle_mayway.cfg else use
+ turtle.cfg and read it from the import-directory, where
+ turtle.py is located.
+ Update configuration dictionary first according to config-file,
+ in the import directory, then according to config-file in the
+ current working directory.
+ If no config-file is found, the default configuration is used.
+ """
+ default_cfg = "turtle.cfg"
+ cfgdict1 = {}
+ cfgdict2 = {}
+ if isfile(default_cfg):
+ cfgdict1 = config_dict(default_cfg)
+ if "importconfig" in cfgdict1:
+ default_cfg = "turtle_%s.cfg" % cfgdict1["importconfig"]
+ try:
+ head, tail = split(__file__)
+ cfg_file2 = join(head, default_cfg)
+ except Exception:
+ cfg_file2 = ""
+ if isfile(cfg_file2):
+ cfgdict2 = config_dict(cfg_file2)
+ _CFG.update(cfgdict2)
+ _CFG.update(cfgdict1)
+
+try:
+ readconfig(_CFG)
+except Exception:
+ print ("No configfile read, reason unknown")
+
+
+class Vec2D(tuple):
+ """A 2 dimensional vector class, used as a helper class
+ for implementing turtle graphics.
+ May be useful for turtle graphics programs also.
+ Derived from tuple, so a vector is a tuple!
+
+ Provides (for a, b vectors, k number):
+ a+b vector addition
+ a-b vector subtraction
+ a*b inner product
+ k*a and a*k multiplication with scalar
+ |a| absolute value of a
+ a.rotate(angle) rotation
+ """
+ def __new__(cls, x, y):
+ return tuple.__new__(cls, (x, y))
+ def __add__(self, other):
+ return Vec2D(self[0]+other[0], self[1]+other[1])
+ def __mul__(self, other):
+ if isinstance(other, Vec2D):
+ return self[0]*other[0]+self[1]*other[1]
+ return Vec2D(self[0]*other, self[1]*other)
+ def __rmul__(self, other):
+ if isinstance(other, int) or isinstance(other, float):
+ return Vec2D(self[0]*other, self[1]*other)
+ return NotImplemented
+ def __sub__(self, other):
+ return Vec2D(self[0]-other[0], self[1]-other[1])
+ def __neg__(self):
+ return Vec2D(-self[0], -self[1])
+ def __abs__(self):
+ return (self[0]**2 + self[1]**2)**0.5
+ def rotate(self, angle):
+ """rotate self counterclockwise by angle
+ """
+ perp = Vec2D(-self[1], self[0])
+ angle = angle * math.pi / 180.0
+ c, s = math.cos(angle), math.sin(angle)
+ return Vec2D(self[0]*c+perp[0]*s, self[1]*c+perp[1]*s)
+ def __getnewargs__(self):
+ return (self[0], self[1])
+ def __repr__(self):
+ return "(%.2f,%.2f)" % self
+
+
+##############################################################################
+### From here up to line : Tkinter - Interface for turtle.py ###
+### May be replaced by an interface to some different graphics toolkit ###
+##############################################################################
+
+## helper functions for Scrolled Canvas, to forward Canvas-methods
+## to ScrolledCanvas class
+
+def __methodDict(cls, _dict):
+ """helper function for Scrolled Canvas"""
+ baseList = list(cls.__bases__)
+ baseList.reverse()
+ for _super in baseList:
+ __methodDict(_super, _dict)
+ for key, value in cls.__dict__.items():
+ if type(value) == types.FunctionType:
+ _dict[key] = value
+
+def __methods(cls):
+ """helper function for Scrolled Canvas"""
+ _dict = {}
+ __methodDict(cls, _dict)
+ return _dict.keys()
+
+__stringBody = (
+ 'def %(method)s(self, *args, **kw): return ' +
+ 'self.%(attribute)s.%(method)s(*args, **kw)')
+
+def __forwardmethods(fromClass, toClass, toPart, exclude = ()):
+ ### MANY CHANGES ###
+ _dict_1 = {}
+ __methodDict(toClass, _dict_1)
+ _dict = {}
+ mfc = __methods(fromClass)
+ for ex in _dict_1.keys():
+ if ex[:1] == '_' or ex[-1:] == '_' or ex in exclude or ex in mfc:
+ pass
+ else:
+ _dict[ex] = _dict_1[ex]
+
+ for method, func in _dict.items():
+ d = {'method': method, 'func': func}
+ if isinstance(toPart, str):
+ execString = \
+ __stringBody % {'method' : method, 'attribute' : toPart}
+ exec(execString, d)
+ setattr(fromClass, method, d[method]) ### NEWU!
+
+
+class ScrolledCanvas(TK.Frame):
+ """Modeled after the scrolled canvas class from Grayons's Tkinter book.
+
+ Used as the default canvas, which pops up automatically when
+ using turtle graphics functions or the Turtle class.
+ """
+ def __init__(self, master, width=500, height=350,
+ canvwidth=600, canvheight=500):
+ TK.Frame.__init__(self, master, width=width, height=height)
+ self._rootwindow = self.winfo_toplevel()
+ self.width, self.height = width, height
+ self.canvwidth, self.canvheight = canvwidth, canvheight
+ self.bg = "white"
+ self._canvas = TK.Canvas(master, width=width, height=height,
+ bg=self.bg, relief=TK.SUNKEN, borderwidth=2)
+ self.hscroll = TK.Scrollbar(master, command=self._canvas.xview,
+ orient=TK.HORIZONTAL)
+ self.vscroll = TK.Scrollbar(master, command=self._canvas.yview)
+ self._canvas.configure(xscrollcommand=self.hscroll.set,
+ yscrollcommand=self.vscroll.set)
+ self.rowconfigure(0, weight=1, minsize=0)
+ self.columnconfigure(0, weight=1, minsize=0)
+ self._canvas.grid(padx=1, in_ = self, pady=1, row=0,
+ column=0, rowspan=1, columnspan=1, sticky='news')
+ self.vscroll.grid(padx=1, in_ = self, pady=1, row=0,
+ column=1, rowspan=1, columnspan=1, sticky='news')
+ self.hscroll.grid(padx=1, in_ = self, pady=1, row=1,
+ column=0, rowspan=1, columnspan=1, sticky='news')
+ self.reset()
+ self._rootwindow.bind('', self.onResize)
+
+ def reset(self, canvwidth=None, canvheight=None, bg = None):
+ """Adjust canvas and scrollbars according to given canvas size."""
+ if canvwidth:
+ self.canvwidth = canvwidth
+ if canvheight:
+ self.canvheight = canvheight
+ if bg:
+ self.bg = bg
+ self._canvas.config(bg=bg,
+ scrollregion=(-self.canvwidth//2, -self.canvheight//2,
+ self.canvwidth//2, self.canvheight//2))
+ self._canvas.xview_moveto(0.5*(self.canvwidth - self.width + 30) /
+ self.canvwidth)
+ self._canvas.yview_moveto(0.5*(self.canvheight- self.height + 30) /
+ self.canvheight)
+ self.adjustScrolls()
+
+
+ def adjustScrolls(self):
+ """ Adjust scrollbars according to window- and canvas-size.
+ """
+ cwidth = self._canvas.winfo_width()
+ cheight = self._canvas.winfo_height()
+ self._canvas.xview_moveto(0.5*(self.canvwidth-cwidth)/self.canvwidth)
+ self._canvas.yview_moveto(0.5*(self.canvheight-cheight)/self.canvheight)
+ if cwidth < self.canvwidth or cheight < self.canvheight:
+ self.hscroll.grid(padx=1, in_ = self, pady=1, row=1,
+ column=0, rowspan=1, columnspan=1, sticky='news')
+ self.vscroll.grid(padx=1, in_ = self, pady=1, row=0,
+ column=1, rowspan=1, columnspan=1, sticky='news')
+ else:
+ self.hscroll.grid_forget()
+ self.vscroll.grid_forget()
+
+ def onResize(self, event):
+ """self-explanatory"""
+ self.adjustScrolls()
+
+ def bbox(self, *args):
+ """ 'forward' method, which canvas itself has inherited...
+ """
+ return self._canvas.bbox(*args)
+
+ def cget(self, *args, **kwargs):
+ """ 'forward' method, which canvas itself has inherited...
+ """
+ return self._canvas.cget(*args, **kwargs)
+
+ def config(self, *args, **kwargs):
+ """ 'forward' method, which canvas itself has inherited...
+ """
+ self._canvas.config(*args, **kwargs)
+
+ def bind(self, *args, **kwargs):
+ """ 'forward' method, which canvas itself has inherited...
+ """
+ self._canvas.bind(*args, **kwargs)
+
+ def unbind(self, *args, **kwargs):
+ """ 'forward' method, which canvas itself has inherited...
+ """
+ self._canvas.unbind(*args, **kwargs)
+
+ def focus_force(self):
+ """ 'forward' method, which canvas itself has inherited...
+ """
+ self._canvas.focus_force()
+
+__forwardmethods(ScrolledCanvas, TK.Canvas, '_canvas')
+
+
+class _Root(TK.Tk):
+ """Root class for Screen based on Tkinter."""
+ def __init__(self):
+ TK.Tk.__init__(self)
+
+ def setupcanvas(self, width, height, cwidth, cheight):
+ self._canvas = ScrolledCanvas(self, width, height, cwidth, cheight)
+ self._canvas.pack(expand=1, fill="both")
+
+ def _getcanvas(self):
+ return self._canvas
+
+ def set_geometry(self, width, height, startx, starty):
+ self.geometry("%dx%d%+d%+d"%(width, height, startx, starty))
+
+ def ondestroy(self, destroy):
+ self.wm_protocol("WM_DELETE_WINDOW", destroy)
+
+ def win_width(self):
+ return self.winfo_screenwidth()
+
+ def win_height(self):
+ return self.winfo_screenheight()
+
+Canvas = TK.Canvas
+
+
+class TurtleScreenBase(object):
+ """Provide the basic graphics functionality.
+ Interface between Tkinter and turtle.py.
+
+ To port turtle.py to some different graphics toolkit
+ a corresponding TurtleScreenBase class has to be implemented.
+ """
+
+ def _blankimage(self):
+ """return a blank image object
+ """
+ img = TK.PhotoImage(width=1, height=1, master=self.cv)
+ img.blank()
+ return img
+
+ def _image(self, filename):
+ """return an image object containing the
+ imagedata from a gif-file named filename.
+ """
+ return TK.PhotoImage(file=filename, master=self.cv)
+
+ def __init__(self, cv):
+ self.cv = cv
+ if isinstance(cv, ScrolledCanvas):
+ w = self.cv.canvwidth
+ h = self.cv.canvheight
+ else: # expected: ordinary TK.Canvas
+ w = int(self.cv.cget("width"))
+ h = int(self.cv.cget("height"))
+ self.cv.config(scrollregion = (-w//2, -h//2, w//2, h//2 ))
+ self.canvwidth = w
+ self.canvheight = h
+ self.xscale = self.yscale = 1.0
+
+ def _createpoly(self):
+ """Create an invisible polygon item on canvas self.cv)
+ """
+ return self.cv.create_polygon((0, 0, 0, 0, 0, 0), fill="", outline="")
+
+ def _drawpoly(self, polyitem, coordlist, fill=None,
+ outline=None, width=None, top=False):
+ """Configure polygonitem polyitem according to provided
+ arguments:
+ coordlist is sequence of coordinates
+ fill is filling color
+ outline is outline color
+ top is a boolean value, which specifies if polyitem
+ will be put on top of the canvas' displaylist so it
+ will not be covered by other items.
+ """
+ cl = []
+ for x, y in coordlist:
+ cl.append(x * self.xscale)
+ cl.append(-y * self.yscale)
+ self.cv.coords(polyitem, *cl)
+ if fill is not None:
+ self.cv.itemconfigure(polyitem, fill=fill)
+ if outline is not None:
+ self.cv.itemconfigure(polyitem, outline=outline)
+ if width is not None:
+ self.cv.itemconfigure(polyitem, width=width)
+ if top:
+ self.cv.tag_raise(polyitem)
+
+ def _createline(self):
+ """Create an invisible line item on canvas self.cv)
+ """
+ return self.cv.create_line(0, 0, 0, 0, fill="", width=2,
+ capstyle = TK.ROUND)
+
+ def _drawline(self, lineitem, coordlist=None,
+ fill=None, width=None, top=False):
+ """Configure lineitem according to provided arguments:
+ coordlist is sequence of coordinates
+ fill is drawing color
+ width is width of drawn line.
+ top is a boolean value, which specifies if polyitem
+ will be put on top of the canvas' displaylist so it
+ will not be covered by other items.
+ """
+ if coordlist is not None:
+ cl = []
+ for x, y in coordlist:
+ cl.append(x * self.xscale)
+ cl.append(-y * self.yscale)
+ self.cv.coords(lineitem, *cl)
+ if fill is not None:
+ self.cv.itemconfigure(lineitem, fill=fill)
+ if width is not None:
+ self.cv.itemconfigure(lineitem, width=width)
+ if top:
+ self.cv.tag_raise(lineitem)
+
+ def _delete(self, item):
+ """Delete graphics item from canvas.
+ If item is"all" delete all graphics items.
+ """
+ self.cv.delete(item)
+
+ def _update(self):
+ """Redraw graphics items on canvas
+ """
+ self.cv.update()
+
+ def _delay(self, delay):
+ """Delay subsequent canvas actions for delay ms."""
+ self.cv.after(delay)
+
+ def _iscolorstring(self, color):
+ """Check if the string color is a legal Tkinter color string.
+ """
+ try:
+ rgb = self.cv.winfo_rgb(color)
+ ok = True
+ except TK.TclError:
+ ok = False
+ return ok
+
+ def _bgcolor(self, color=None):
+ """Set canvas' backgroundcolor if color is not None,
+ else return backgroundcolor."""
+ if color is not None:
+ self.cv.config(bg = color)
+ self._update()
+ else:
+ return self.cv.cget("bg")
+
+ def _write(self, pos, txt, align, font, pencolor):
+ """Write txt at pos in canvas with specified font
+ and color.
+ Return text item and x-coord of right bottom corner
+ of text's bounding box."""
+ x, y = pos
+ x = x * self.xscale
+ y = y * self.yscale
+ anchor = {"left":"sw", "center":"s", "right":"se" }
+ item = self.cv.create_text(x-1, -y, text = txt, anchor = anchor[align],
+ fill = pencolor, font = font)
+ x0, y0, x1, y1 = self.cv.bbox(item)
+ self.cv.update()
+ return item, x1-1
+
+## def _dot(self, pos, size, color):
+## """may be implemented for some other graphics toolkit"""
+
+ def _onclick(self, item, fun, num=1, add=None):
+ """Bind fun to mouse-click event on turtle.
+ fun must be a function with two arguments, the coordinates
+ of the clicked point on the canvas.
+ num, the number of the mouse-button defaults to 1
+ """
+ if fun is None:
+ self.cv.tag_unbind(item, "" % num)
+ else:
+ def eventfun(event):
+ x, y = (self.cv.canvasx(event.x)/self.xscale,
+ -self.cv.canvasy(event.y)/self.yscale)
+ fun(x, y)
+ self.cv.tag_bind(item, "" % num, eventfun, add)
+
+ def _onrelease(self, item, fun, num=1, add=None):
+ """Bind fun to mouse-button-release event on turtle.
+ fun must be a function with two arguments, the coordinates
+ of the point on the canvas where mouse button is released.
+ num, the number of the mouse-button defaults to 1
+
+ If a turtle is clicked, first _onclick-event will be performed,
+ then _onscreensclick-event.
+ """
+ if fun is None:
+ self.cv.tag_unbind(item, "