From e0e3e1717e3d33762ce61950504f9637a6e669ed Mon Sep 17 00:00:00 2001
From: nkozlovskiy <nmk@ydb.tech>
Date: Fri, 29 Sep 2023 12:24:06 +0300
Subject: add ydb deps

---
 .../py3/IPython/testing/plugin/ipdoctest.py        | 299 +++++++++++++++++++++
 1 file changed, 299 insertions(+)
 create mode 100644 contrib/python/ipython/py3/IPython/testing/plugin/ipdoctest.py

(limited to 'contrib/python/ipython/py3/IPython/testing/plugin/ipdoctest.py')

diff --git a/contrib/python/ipython/py3/IPython/testing/plugin/ipdoctest.py b/contrib/python/ipython/py3/IPython/testing/plugin/ipdoctest.py
new file mode 100644
index 0000000000..e7edf9837f
--- /dev/null
+++ b/contrib/python/ipython/py3/IPython/testing/plugin/ipdoctest.py
@@ -0,0 +1,299 @@
+"""Nose Plugin that supports IPython doctests.
+
+Limitations:
+
+- When generating examples for use as doctests, make sure that you have
+  pretty-printing OFF.  This can be done either by setting the
+  ``PlainTextFormatter.pprint`` option in your configuration file to  False, or
+  by interactively disabling it with  %Pprint.  This is required so that IPython
+  output matches that of normal Python, which is used by doctest for internal
+  execution.
+
+- Do not rely on specific prompt numbers for results (such as using
+  '_34==True', for example).  For IPython tests run via an external process the
+  prompt numbers may be different, and IPython tests run as normal python code
+  won't even have these special _NN variables set at all.
+"""
+
+#-----------------------------------------------------------------------------
+# Module imports
+
+# From the standard library
+import doctest
+import logging
+import re
+
+from testpath import modified_env
+
+#-----------------------------------------------------------------------------
+# Module globals and other constants
+#-----------------------------------------------------------------------------
+
+log = logging.getLogger(__name__)
+
+
+#-----------------------------------------------------------------------------
+# Classes and functions
+#-----------------------------------------------------------------------------
+
+
+class DocTestFinder(doctest.DocTestFinder):
+    def _get_test(self, obj, name, module, globs, source_lines):
+        test = super()._get_test(obj, name, module, globs, source_lines)
+
+        if bool(getattr(obj, "__skip_doctest__", False)) and test is not None:
+            for example in test.examples:
+                example.options[doctest.SKIP] = True
+
+        return test
+
+
+class IPDoctestOutputChecker(doctest.OutputChecker):
+    """Second-chance checker with support for random tests.
+
+    If the default comparison doesn't pass, this checker looks in the expected
+    output string for flags that tell us to ignore the output.
+    """
+
+    random_re = re.compile(r'#\s*random\s+')
+
+    def check_output(self, want, got, optionflags):
+        """Check output, accepting special markers embedded in the output.
+
+        If the output didn't pass the default validation but the special string
+        '#random' is included, we accept it."""
+
+        # Let the original tester verify first, in case people have valid tests
+        # that happen to have a comment saying '#random' embedded in.
+        ret = doctest.OutputChecker.check_output(self, want, got,
+                                                 optionflags)
+        if not ret and self.random_re.search(want):
+            #print >> sys.stderr, 'RANDOM OK:',want  # dbg
+            return True
+
+        return ret
+
+
+# A simple subclassing of the original with a different class name, so we can
+# distinguish and treat differently IPython examples from pure python ones.
+class IPExample(doctest.Example): pass
+
+
+class IPDocTestParser(doctest.DocTestParser):
+    """
+    A class used to parse strings containing doctest examples.
+
+    Note: This is a version modified to properly recognize IPython input and
+    convert any IPython examples into valid Python ones.
+    """
+    # This regular expression is used to find doctest examples in a
+    # string.  It defines three groups: `source` is the source code
+    # (including leading indentation and prompts); `indent` is the
+    # indentation of the first (PS1) line of the source code; and
+    # `want` is the expected output (including leading indentation).
+
+    # Classic Python prompts or default IPython ones
+    _PS1_PY = r'>>>'
+    _PS2_PY = r'\.\.\.'
+
+    _PS1_IP = r'In\ \[\d+\]:'
+    _PS2_IP = r'\ \ \ \.\.\.+:'
+
+    _RE_TPL = r'''
+        # Source consists of a PS1 line followed by zero or more PS2 lines.
+        (?P<source>
+            (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*)    # PS1 line
+            (?:\n           [ ]*  (?P<ps2> %s) .*)*)  # PS2 lines
+        \n? # a newline
+        # Want consists of any non-blank lines that do not start with PS1.
+        (?P<want> (?:(?![ ]*$)    # Not a blank line
+                     (?![ ]*%s)   # Not a line starting with PS1
+                     (?![ ]*%s)   # Not a line starting with PS2
+                     .*$\n?       # But any other line
+                  )*)
+                  '''
+
+    _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
+                                 re.MULTILINE | re.VERBOSE)
+
+    _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
+                                 re.MULTILINE | re.VERBOSE)
+
+    # Mark a test as being fully random.  In this case, we simply append the
+    # random marker ('#random') to each individual example's output.  This way
+    # we don't need to modify any other code.
+    _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
+
+    def ip2py(self,source):
+        """Convert input IPython source into valid Python."""
+        block = _ip.input_transformer_manager.transform_cell(source)
+        if len(block.splitlines()) == 1:
+            return _ip.prefilter(block)
+        else:
+            return block
+
+    def parse(self, string, name='<string>'):
+        """
+        Divide the given string into examples and intervening text,
+        and return them as a list of alternating Examples and strings.
+        Line numbers for the Examples are 0-based.  The optional
+        argument `name` is a name identifying this string, and is only
+        used for error messages.
+        """
+
+        #print 'Parse string:\n',string # dbg
+
+        string = string.expandtabs()
+        # If all lines begin with the same indentation, then strip it.
+        min_indent = self._min_indent(string)
+        if min_indent > 0:
+            string = '\n'.join([l[min_indent:] for l in string.split('\n')])
+
+        output = []
+        charno, lineno = 0, 0
+
+        # We make 'all random' tests by adding the '# random' mark to every
+        # block of output in the test.
+        if self._RANDOM_TEST.search(string):
+            random_marker = '\n# random'
+        else:
+            random_marker = ''
+
+        # Whether to convert the input from ipython to python syntax
+        ip2py = False
+        # Find all doctest examples in the string.  First, try them as Python
+        # examples, then as IPython ones
+        terms = list(self._EXAMPLE_RE_PY.finditer(string))
+        if terms:
+            # Normal Python example
+            Example = doctest.Example
+        else:
+            # It's an ipython example.
+            terms = list(self._EXAMPLE_RE_IP.finditer(string))
+            Example = IPExample
+            ip2py = True
+
+        for m in terms:
+            # Add the pre-example text to `output`.
+            output.append(string[charno:m.start()])
+            # Update lineno (lines before this example)
+            lineno += string.count('\n', charno, m.start())
+            # Extract info from the regexp match.
+            (source, options, want, exc_msg) = \
+                     self._parse_example(m, name, lineno,ip2py)
+
+            # Append the random-output marker (it defaults to empty in most
+            # cases, it's only non-empty for 'all-random' tests):
+            want += random_marker
+
+            # Create an Example, and add it to the list.
+            if not self._IS_BLANK_OR_COMMENT(source):
+                output.append(Example(source, want, exc_msg,
+                                      lineno=lineno,
+                                      indent=min_indent+len(m.group('indent')),
+                                      options=options))
+            # Update lineno (lines inside this example)
+            lineno += string.count('\n', m.start(), m.end())
+            # Update charno.
+            charno = m.end()
+        # Add any remaining post-example text to `output`.
+        output.append(string[charno:])
+        return output
+
+    def _parse_example(self, m, name, lineno,ip2py=False):
+        """
+        Given a regular expression match from `_EXAMPLE_RE` (`m`),
+        return a pair `(source, want)`, where `source` is the matched
+        example's source code (with prompts and indentation stripped);
+        and `want` is the example's expected output (with indentation
+        stripped).
+
+        `name` is the string's name, and `lineno` is the line number
+        where the example starts; both are used for error messages.
+
+        Optional:
+        `ip2py`: if true, filter the input via IPython to convert the syntax
+        into valid python.
+        """
+
+        # Get the example's indentation level.
+        indent = len(m.group('indent'))
+
+        # Divide source into lines; check that they're properly
+        # indented; and then strip their indentation & prompts.
+        source_lines = m.group('source').split('\n')
+
+        # We're using variable-length input prompts
+        ps1 = m.group('ps1')
+        ps2 = m.group('ps2')
+        ps1_len = len(ps1)
+
+        self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
+        if ps2:
+            self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
+
+        source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
+
+        if ip2py:
+            # Convert source input from IPython into valid Python syntax
+            source = self.ip2py(source)
+
+        # Divide want into lines; check that it's properly indented; and
+        # then strip the indentation.  Spaces before the last newline should
+        # be preserved, so plain rstrip() isn't good enough.
+        want = m.group('want')
+        want_lines = want.split('\n')
+        if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
+            del want_lines[-1]  # forget final newline & spaces after it
+        self._check_prefix(want_lines, ' '*indent, name,
+                           lineno + len(source_lines))
+
+        # Remove ipython output prompt that might be present in the first line
+        want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
+
+        want = '\n'.join([wl[indent:] for wl in want_lines])
+
+        # If `want` contains a traceback message, then extract it.
+        m = self._EXCEPTION_RE.match(want)
+        if m:
+            exc_msg = m.group('msg')
+        else:
+            exc_msg = None
+
+        # Extract options from the source.
+        options = self._find_options(source, name, lineno)
+
+        return source, options, want, exc_msg
+
+    def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
+        """
+        Given the lines of a source string (including prompts and
+        leading indentation), check to make sure that every prompt is
+        followed by a space character.  If any line is not followed by
+        a space character, then raise ValueError.
+
+        Note: IPython-modified version which takes the input prompt length as a
+        parameter, so that prompts of variable length can be dealt with.
+        """
+        space_idx = indent+ps1_len
+        min_len = space_idx+1
+        for i, line in enumerate(lines):
+            if len(line) >=  min_len and line[space_idx] != ' ':
+                raise ValueError('line %r of the docstring for %s '
+                                 'lacks blank after %s: %r' %
+                                 (lineno+i+1, name,
+                                  line[indent:space_idx], line))
+
+
+SKIP = doctest.register_optionflag('SKIP')
+
+
+class IPDocTestRunner(doctest.DocTestRunner,object):
+    """Test runner that synchronizes the IPython namespace with test globals.
+    """
+
+    def run(self, test, compileflags=None, out=None, clear_globs=True):
+        # Override terminal size to standardise traceback format
+        with modified_env({'COLUMNS': '80', 'LINES': '24'}):
+            return super(IPDocTestRunner,self).run(test,
+                                                   compileflags,out,clear_globs)
-- 
cgit v1.2.3