Пример #1
0
    def send_head(self):
        """Common code for GET and HEAD commands.

        This sends the response code and MIME headers.

        Return value is either a file object (which has to be copied
        to the outputfile by the caller unless the command was HEAD,
        and must be closed by the caller under all circumstances), or
        None, in which case the caller has nothing further to do.

        """
        path = self.translate_path(self.path)
        f = None
        if self.path.endswith('?md5') is True:
            if os.path.exists(path) is False:
                return 'error not exist'
            else:
                md5 = self.get_md5_small(path)
                print(md5)
                f = BytesIO()
                f.write(bytes(md5, encoding = "utf8"  ))
                length = f.tell()
                f.seek(0)
                self.send_response(200)
                self.send_header("Content-type", "text/html")
                self.send_header("Content-Length", str(length))
                self.end_headers()
                return f
        elif os.path.isdir(path):
            if not self.path.endswith('/'):
                # redirect browser - doing basically what apache does
                self.send_response(301)
                self.send_header("Location", self.path + "/")
                self.end_headers()
                return None
            for index in "index.html", "index.htm":
                index = os.path.join(path, index)
                if os.path.exists(index):
                    path = index
                    break
            else:
##                arkPath = os.path.join(path, "archive")
                return self.list_directory(path)
        ctype = self.guess_type(path)
        try:
            # Always read in binary mode. Opening files in text mode may cause
            # newline translations, making the actual size of the content
            # transmitted *less* than the content-length!
            f = open(path, 'rb')
        except IOError:
            self.send_error(404, "File not found")
            return None
        self.send_response(200)
        self.send_header("Content-type", ctype)
        fs = os.fstat(f.fileno())
        self.send_header("Content-Length", str(fs[6]))
        self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
        self.end_headers()

        return f
Пример #2
0
    def convert(self, sch):
        def mock_open(name, mode):
            self.assertEqual(mode, "rb")
            return stream

        class MockOle:
            def __init__(ole, file):
                self.assertIs(file, stream)
                super().__init__()

            def listdir(ole):
                return [["FileHeader"], ["Storage"]]

            def exists(ole, name):
                return name in {"FileHeader", "Storage"}

            def openstream(ole, name):
                if name == "Storage":
                    return BytesIO(b"\x15\x00\x00\x00"
                                   b"|HEADER=Icon storage\x00")
                self.assertEqual(name, "FileHeader")
                return stream

        class mock_os:
            def stat(fileno):
                return SimpleNamespace(st_mtime=0)

            class path:
                def isabs(path):
                    return True

        stream = BytesIO()
        stream.fileno = lambda: stream

        weight = format(1 + len(sch)).encode("ascii")
        preliminary = (
            b"|HEADER=Protel for Windows - Schematic Capture Binary File "
            b"Version 5.0|WEIGHT=" + weight + b"\x00",
            b"|RECORD=31|FONTIDCOUNT=1|SIZE1=10|FONTNAME1=Times New Roman"
            b"|SYSTEMFONT=1"
            b"|AREACOLOR=16317695|BORDERON=T|CUSTOMX=|CUSTOMY="
            b"|DISPLAY_UNIT=4|HOTSPOTGRIDON=T|HOTSPOTGRIDSIZE="
            b"|SNAPGRIDON=T|SNAPGRIDSIZE=|VISIBLEGRIDON=T"
            b"|VISIBLEGRIDSIZE=10|ISBOC=T|SHEETNUMBERSPACESIZE=4"
            b"|USEMBCS=T\x00",
        )
        for list in preliminary + sch:
            stream.write(len(list).to_bytes(4, "little"))
            stream.write(list)
        stream.seek(0)

        output = StringIO()
        with patch("altium.open", mock_open), \
                patch("altium.OleFileIO", MockOle), \
                patch("altium.os", mock_os), \
                redirect_stdout(output):
            altium.render("dummy.SchDoc", svg.Renderer)
        return output.getvalue()
Пример #3
0
 def convert(self, sch):
     def mock_open(name, mode):
         self.assertEqual(mode, "rb")
         return stream
     
     class MockOle:
         def __init__(ole, file):
             self.assertIs(file, stream)
             super().__init__()
         
         def listdir(ole):
             return [["FileHeader"], ["Storage"]]
         
         def exists(ole, name):
             return name in {"FileHeader", "Storage"}
         
         def openstream(ole, name):
             if name == "Storage":
                 return BytesIO(
                     b"\x15\x00\x00\x00"
                     b"|HEADER=Icon storage\x00"
                 )
             self.assertEqual(name, "FileHeader")
             return stream
     
     class mock_os:
         def stat(fileno):
             return None
     
     stream = BytesIO()
     stream.fileno = lambda: stream
     
     weight = format(1 + len(sch)).encode("ascii")
     preliminary = (
         b"|HEADER=Protel for Windows - Schematic Capture Binary File "
             b"Version 5.0|WEIGHT=" + weight + b"\x00",
         b"|RECORD=31|FONTIDCOUNT=1|SIZE1=10|FONTNAME1=Times New Roman"
             b"|SYSTEMFONT=1"
             b"|AREACOLOR=16317695|BORDERON=T|CUSTOMX=|CUSTOMY="
             b"|DISPLAY_UNIT=4|HOTSPOTGRIDON=T|HOTSPOTGRIDSIZE="
             b"|SNAPGRIDON=T|SNAPGRIDSIZE=|VISIBLEGRIDON=T"
             b"|VISIBLEGRIDSIZE=10|ISBOC=T|SHEETNUMBERSPACESIZE=4"
             b"|USEMBCS=T\x00",
     )
     for list in preliminary + sch:
         stream.write(len(list).to_bytes(4, "little"))
         stream.write(list)
     stream.seek(0)
     
     output = StringIO()
     with patch("altium.open", mock_open), \
             patch("altium.OleFileIO", MockOle), \
             patch("altium.os", mock_os), \
             redirect_stdout(output):
         altium.render("dummy.SchDoc", svg.Renderer)
     return output.getvalue()
Пример #4
0
def rotate_image(data, angle):

    # bug workaround in some PIL versions
    def fileno():
        raise AttributeError

    # open image from data and rotate
    image = Image.open(BytesIO(data))
    rot = image.rotate(angle, expand=True)
    # save image to a file in memory
    memfile = BytesIO()
    memfile.fileno = fileno  # required in some broken PILs
    rot.save(memfile, image.format)
    return memfile.getvalue()
Пример #5
0
def addphotoform(request):
    
    albumname = request.matchdict['albumname']
    
    if request.method == "POST":
        filename = request.POST['jpg'].filename
        inputfile = request.POST['jpg'].file

        
        #put the photo in the store
        key = request.mystore.genkey(albumname, filename)
        request.mystore[key] = inputfile.read()
        
        
        #create the thumbnail
        inputfile.seek(0)
        size = 300, 300
        im = Image.open(inputfile)
        im.thumbnail(size, Image.ANTIALIAS)
        
        #create a file-like object for storing the thumbnail
        imagefile = BytesIO()
        def fileno():
            raise AttributeError
        imagefile.fileno = fileno #hack to make PIL and BytesIO work together...
                
        im.save(imagefile, 'JPEG')  #save thumbnail in jpeg format into imagefile
        
        imagefile.seek(0)
        
        thumbkey = request.mystore.genkey(albumname, filename, thumbnail = True)
        request.mystore[thumbkey] = imagefile.read()

        #store the new photo in the database
        album = DBSession.query(Album).filter(Album.name==albumname).one()
        
        photo = Photo()
        photo.album = album
        photo.filekey = key
        photo.thumbkey = thumbkey
        photo.filename = filename
        DBSession.add(photo)
                
        return HTTPFound(request.route_path("addphotoform",albumname=albumname))
        
    return {}
Пример #6
0
def generate_thumbnail(albumname, filename):
    log.debug("generating thumbnail for %s/%s"%(albumname, filename))
    
    #get the Photo object:
    album = DBSession.query(Album).filter(Album.name==albumname).one()
    photo = DBSession.query(Photo).filter(Photo.album==album).filter(Photo.filename==filename).one()
        
    #retrieve the original image:
    f = celery.mystore[photo.filekey]    
    
    #create the thumbnail
    size = 300, 300
    inputfile = BytesIO(f)
    im = Image.open(inputfile)
    im.thumbnail(size, Image.ANTIALIAS)
        
    imagefile = BytesIO()
    def fileno():
        raise AttributeError
    imagefile.fileno = fileno #hack to make PIL and BytesIO work together...
                
    im.save(imagefile, 'JPEG')
    imagefile.seek(0)  # put the file cursor back to the origin
    
    #save the thumbnail into the storage system:
    dirname = os.path.dirname(photo.filekey)
    key = celery.mystore.genkey(dirname, filename, thumbnail=True)
    celery.mystore[key] = imagefile.read()
    
    #update photo url:
    photo.thumbkey = key
    DBSession.add(photo)
    
    transaction.commit()
    log.debug('the key is: %s'%key)
    log.debug("thumbnail generation done for %s/%s"%(albumname, filename))
Пример #7
0
    def send_head(self):
        """Common code for GET and HEAD commands.
        This sends the response code and MIME headers.
        Return value is either a file object (which has to be copied
        to the outputfile by the caller unless the command was HEAD,
        and must be closed by the caller under all circumstances), or
        None, in which case the caller has nothing further to do.
        """

        path, b64_encoded = self.translate_path(self.path)

        # Return to requests for files
        file_listing = False
        if path.endswith('/SHTTPSSgetFiles'):
            path = path.split('/SHTTPSSgetFiles')[0]
            file_listing = True

            f = BytesIO()
            f.write(self.list_files(path, b64_encoded))
            length = f.tell()
            f.seek(0)
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', str(length))
            self.end_headers()
            return f

        f = None
        if os.path.isdir(path):
            parts = urllib.parse.urlsplit(self.path)

            # ====================================
            # REDIRECT BROWSER BACK TO PATH WITH /
            # ====================================
            'Only when in a directory, though'

            if not parts.path.endswith('/'):
                # redirect browser - doing basically what apache does
                self.send_response(HTTPStatus.MOVED_PERMANENTLY)
                new_parts = (parts[0], parts[1], parts[2] + '/',
                             parts[3], parts[4])
                new_url = urllib.parse.urlunsplit(new_parts)
                self.send_header("Location", new_url)
                self.end_headers()
                return None

            for index in "index.html", "index.htm":
                index = os.path.join(path, index)
                if os.path.exists(index):
                    path = index
                    break
            else:
                if CorsHandler.uploads_enabled:
                    return self.list_directory(path,b64_encoded)
                else:
                    return self.list_directory(path)


        ctype = self.guess_type(path)
        # check for trailing "/" which should return 404. See Issue17324
        # The test for this was added in test_httpserver.py
        # However, some OS platforms accept a trailingSlash as a filename
        # See discussion on python-dev and Issue34711 regarding
        # parseing and rejection of filenames with a trailing slash
        if path.endswith("/"):
            self.send_error(HTTPStatus.NOT_FOUND, "File not found")
            return None
        try:
            f = open(path, 'rb')
        except OSError:
            self.send_error(HTTPStatus.NOT_FOUND, "File not found")
            return None

        try:
            fs = os.fstat(f.fileno())
            if not CorsHandler.DISABLE_CACHING:
                # Use browser cache if possible
                if ("If-Modified-Since" in self.headers
                        and "If-None-Match" not in self.headers):
                    # compare If-Modified-Since and time of last file modification
                    try:
                        ims = email.utils.parsedate_to_datetime(
                            self.headers["If-Modified-Since"])
                    except (TypeError, IndexError, OverflowError, ValueError):
                        # ignore ill-formed values
                        pass
                    else:
                        if ims.tzinfo is None:
                            # obsolete format with no timezone, cf.
                            # https://tools.ietf.org/html/rfc7231#section-7.1.1.1
                            ims = ims.replace(tzinfo=datetime.timezone.utc)
                        if ims.tzinfo is datetime.timezone.utc:
                            # compare to UTC datetime of last modification
                            last_modif = datetime.datetime.fromtimestamp(
                                fs.st_mtime, datetime.timezone.utc)
                            # remove microseconds, like in If-Modified-Since
                            last_modif = last_modif.replace(microsecond=0)
    
                            if last_modif <= ims:
                                self.send_response(HTTPStatus.NOT_MODIFIED)
                                self.end_headers()
                                f.close()
                                return None

            self.send_response(HTTPStatus.OK)
            self.send_header("Content-type", ctype)
            self.send_header("Last-Modified",
                self.date_time_string(fs.st_mtime))

            # Adding Access-Control-Allow-Origin header
            self.send_header('Access-Control-Allow-Origin','*')
            self.end_headers()

            if CorsHandler.B64_ENCODE_PAYLOAD and b64_encoded:

                # Read in the file and prepare for encoding
                encoded = f.read()
                self.log_message(
                    'Encoding target download file {} ({} bytes, md5sum: {})' \
                        .format(path,
                            len(encoded),
                            md5sum(encoded))
                )

                # TODO: Make iterations configurable
                for i in range(0,2): encoded = b64encode(encoded)

                encoded_length = len(encoded)

                self.log_message(
                    'File encoding success {} ({} bytes, md5sum: {})' \
                        .format(path,
                            encoded_length,
                            md5sum(encoded))
                )

                # Update the content-length header to reflect the length
                # of the encoded value
                self.send_header("Content-Length", encoded_length)
                return BytesIO(encoded)

            else:

                # Update the content-length header with the length of the
                # normal value
                self.send_header("Content-Length", str(fs[6]))

            return f

        except:
            f.close()
            raise
Пример #8
0
    def send_head(self):
        """Send response code and MIME header.

        This is common code for GET and HEAD commands.

        Return value is either a file object (which has to be copied
        to the outputfile by the caller unless the command was HEAD,
        and must be closed by the caller under all circumstances), or
        None, in which case the caller has nothing further to do.

        """
        path = self.translate_path(self.path)
        f = None
        if os.path.isdir(path):
            path_parts = list(self.path.partition('?'))
            if not path_parts[0].endswith('/'):
                # redirect browser - doing basically what apache does
                path_parts[0] += '/'
                self.send_response(301)
                self.send_header("Location", ''.join(path_parts))
                # begin no-cache patch
                # For redirects.  With redirects, caching is even worse and can
                # break more.  Especially with 301 Moved Permanently redirects,
                # like this one.
                self.send_header("Cache-Control", "no-cache, no-store, "
                                 "must-revalidate")
                self.send_header("Pragma", "no-cache")
                self.send_header("Expires", "0")
                # end no-cache patch
                self.end_headers()
                return None
            for index in "index.html", "index.htm":
                index = os.path.join(path, index)
                if os.path.exists(index):
                    path = index
                    break
            else:
                return self.list_directory(path)
        ctype = self.guess_type(path)
        try:
            # Always read in binary mode. Opening files in text mode may cause
            # newline translations, making the actual size of the content
            # transmitted *less* than the content-length!
            f = open(path, 'rb')
        except IOError:
            self.send_error(404, "File not found: {}".format(path))
            return None

        filtered_bytes = None
        if ctype == 'text/html':
            # Comment out any <base> to allow local resolution of relative URLs.
            data = f.read().decode('utf8')
            f.close()
            data = re.sub(r'<base\s([^>]*)>',
                          r'<!--base \g<1>-->',
                          data,
                          flags=re.IGNORECASE)
            data = data.encode('utf8')
            f = StringIO()
            f.write(data)
            filtered_bytes = len(data)
            f.seek(0)

        self.send_response(200)
        if ctype.startswith('text/') or ctype.endswith('+xml'):
            self.send_header("Content-Type",
                             "{0}; charset=UTF-8".format(ctype))
        else:
            self.send_header("Content-Type", ctype)
        if os.path.splitext(path)[1] == '.svgz':
            # Special handling for svgz to make it work nice with browsers.
            self.send_header("Content-Encoding", 'gzip')

        if filtered_bytes is None:
            fs = os.fstat(f.fileno())
            self.send_header('Content-Length', str(fs[6]))
        else:
            self.send_header('Content-Length', filtered_bytes)

        # begin no-cache patch
        # For standard requests.
        self.send_header("Cache-Control", "no-cache, no-store, "
                         "must-revalidate")
        self.send_header("Pragma", "no-cache")
        self.send_header("Expires", "0")
        # end no-cache patch
        self.end_headers()
        return f
Пример #9
0
class _BaseBinaryWrapper:
    def __init__(self, stream: Union[typing.BinaryIO, bytes] = b""):
        if isinstance(stream, bytes) or isinstance(stream, bytearray):
            self.stream = BytesIO(stream)
        else:
            self.stream = stream

    # Wrappings:
    def close(self) -> None:
        return self.stream.close()

    def flush(self) -> None:
        return self.stream.flush()

    def read(self, n: int = -1) -> AnyStr:
        return self.stream.read(n)

    def readable(self) -> bool:
        return self.stream.readable()

    def readline(self, limit: int = -1) -> AnyStr:
        return self.stream.readline(limit)

    def readlines(self, hint: int = -1) -> List[AnyStr]:
        return self.stream.readlines(hint)

    def write(self, s: Union[bytes, bytearray]) -> int:
        return self.stream.write(s)

    def writable(self) -> bool:
        return self.stream.writable()

    def writelines(self, lines: Iterable[AnyStr]) -> None:
        self.stream.writelines(lines)

    def seek(self, offset: int, whence: int = 0) -> int:
        return self.stream.seek(offset, whence)

    def seekable(self) -> bool:
        return self.stream.seekable()

    def tell(self) -> int:
        return self.stream.tell()

    def fileno(self) -> int:
        return self.stream.fileno()

    def __enter__(self):
        self.stream.__enter__()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.stream.__exit__(exc_type, exc_val, exc_tb)

    # helper functions

    def readall(self):
        self.stream.seek(0)
        return self.stream.read()

    def getvalue(self):
        if isinstance(self.stream, BytesIO):
            return self.stream.getvalue()
        pos = self.stream.tell()
        ret = self.readall()
        self.stream.seek(pos)
        return ret

    def align(self, alignment=4):
        if offset := (self.tell() % alignment):
            self.seek(self.tell() + alignment - offset)
Пример #10
0
class DataIO(object):
    """
    This class simply wraps a binary file or a bytes string and implements
    both the file and bytes interface. It allows an input to be provided as
    files of bytes and manipulated indifferently as a file or a bytes object.
    """
    def __init__(self, f):
        if isinstance(f, bytes):
            from io import BytesIO

            self.f = BytesIO(f)
        else:
            self.f = f
        self.view = dataView(dataio=self)

    def __getitem__(self, i):
        stay = self.f.tell()
        sta = i.start
        if sta is None:
            sta = stay
        self.f.seek(sta, 0)
        if i.stop is None:
            data = self.f.read()
        else:
            data = self.f.read(i.stop - sta)
        self.f.seek(stay, 0)
        return data

    def size(self):
        stay = self.f.tell()
        self.f.seek(0, 2)
        sz = self.f.tell()
        self.f.seek(stay, 0)
        return sz

    def read(self, size=-1):
        return self.f.read(size)

    def readline(self, size=-1):
        return self.f.readline(size)

    def readlines(self, size=-1):
        return self.f.readlines(size)

    def xreadlines(self, size=-1):
        return self.f.xreadlines(size)

    def write(self, s):
        return self.f.write(s)

    def writelines(self, l):
        return self.f.writelines(l)

    def seek(self, offset, whence=0):
        return self.f.seek(offset, whence)

    def tell(self):
        return self.f.tell()

    def flush(self):
        return self.f.flush()

    def fileno(self):
        return self.f.fileno()

    def isatty(self):
        return self.f.isatty()

    def next(self):
        return self.f.next()

    def truncate(self, size=0):
        return self.f.truncate(size)

    def close(self):
        return self.f.close()

    @property
    def closed(self):
        return self.f.closed

    @property
    def encoding(self):
        return self.f.encoding

    @property
    def errors(self):
        return self.f.errors

    @property
    def mode(self):
        return self.f.mode

    @property
    def name(self):
        try:
            return self.f.name
        except AttributeError:
            s = bytes(self.f.getvalue())
            return "(sc-%s...)" % ("".join(["%02x" % x for x in s])[:8])

    filename = name

    @property
    def newlines(self):
        return self.f.newlines

    @property
    def softspace(self):
        return self.f.softspace
Пример #11
0
class Pdb(pdb.Pdb, ConfigurableClass, object):

    DefaultConfig = DefaultConfig
    config_filename = '.pdbrc.py'

    def __init__(self, *args, **kwds):
        self.ConfigFactory = kwds.pop('Config', None)
        self.start_lineno = kwds.pop('start_lineno', None)
        self.start_filename = kwds.pop('start_filename', None)
        self.config = self.get_config(self.ConfigFactory)
        self.config.setup(self)
        if self.config.disable_pytest_capturing:
            self._disable_pytest_capture_maybe()
        super(Pdb, self).__init__(*args, **kwds)
        self.prompt = self.config.prompt
        self.display_list = {}  # frame --> (name --> last seen value)
        self.sticky = self.config.sticky_by_default
        self.first_time_sticky = self.sticky
        self.sticky_ranges = {}  # frame --> (start, end)
        self.tb_lineno = {}  # frame --> lineno where the exception raised
        self.history = []
        self.show_hidden_frames = False
        self.hidden_frames = []
        self.stdout = self.ensure_file_can_write_unicode(self.stdout)
        self.sticky_stdout = self.stdout

    def ensure_file_can_write_unicode(self, f):
        # Wrap with an encoder, but only if not already wrapped
        if (not hasattr(f, 'stream') and getattr(f, 'encoding', False)
                and f.encoding.lower() != 'utf-8'):
            f = codecs.getwriter('utf-8')(getattr(f, 'buffer', f))

        return f

    def _disable_pytest_capture_maybe(self):
        try:
            import py.test
            # Force raising of ImportError if pytest is not installed.
            py.test.config
        except (ImportError, AttributeError):
            return
        try:
            capman = py.test.config.pluginmanager.getplugin('capturemanager')
            capman.suspendcapture()
        except KeyError:
            pass
        except AttributeError:
            # Newer pytest with support ready, or very old py.test for which
            # this hack does not work.
            pass

    def interaction(self, frame, traceback):
        # Restore the previous signal handler at the Pdb prompt.
        if getattr(pdb.Pdb, '_previous_sigint_handler', None):
            try:
                signal.signal(signal.SIGINT, pdb.Pdb._previous_sigint_handler)
            except ValueError:  # ValueError: signal only works in main thread
                pass
            else:
                pdb.Pdb._previous_sigint_handler = None
        ret = self.setup(frame, traceback)
        if ret:
            # no interaction desired at this time (happens if .pdbrc contains
            # a command like "continue")
            self.forget()
            return
        if self.config.exec_if_unfocused:
            self.exec_if_unfocused()
        self.print_stack_entry(self.stack[self.curindex])
        self.print_hidden_frames_count()
        completer = fancycompleter.setup()
        old_completer = completer.config.readline.get_completer()
        completer.config.readline.set_completer(self.complete)
        self.config.before_interaction_hook(self)
        # Use _cmdloop on py3 which catches KeyboardInterrupt.
        getattr(self, '_cmdloop', self.cmdloop)()
        completer.config.readline.set_completer(old_completer)
        self.forget()

    def print_hidden_frames_count(self):
        n = len(self.hidden_frames)
        if n and self.config.show_hidden_frames_count:
            plural = n > 1 and "s" or ""
            print(
                "   %d frame%s hidden (try 'help hidden_frames')" %
                (n, plural),
                file=self.stdout,
            )

    def exec_if_unfocused(self):
        import os
        import wmctrl
        term = os.getenv('TERM', '')
        try:
            winid = int(os.getenv('WINDOWID'))
        except (TypeError, ValueError):
            return  # cannot find WINDOWID of the terminal
        active_win = wmctrl.Window.get_active()
        if not active_win or (int(active_win.id, 16) != winid) and \
           not (active_win.wm_class == 'emacs.Emacs' and term.startswith('eterm')):
            os.system(self.config.exec_if_unfocused)

    def setup(self, frame, tb):
        ret = super(Pdb, self).setup(frame, tb)
        if not ret:
            while tb:
                lineno = lasti2lineno(tb.tb_frame.f_code, tb.tb_lasti)
                self.tb_lineno[tb.tb_frame] = lineno
                tb = tb.tb_next
        return ret

    def _is_hidden(self, frame):
        if not self.config.enable_hidden_frames:
            return False

        # Decorated code is always considered to be hidden.
        consts = frame.f_code.co_consts
        if consts and consts[-1] is _HIDE_FRAME:
            return True

        # Do not hide if this frame contains the initial set_trace.
        if frame is getattr(self, "_via_set_trace_frame", None):
            return False

        if frame.f_globals.get('__unittest'):
            return True
        if frame.f_locals.get('__tracebackhide__') \
           or frame.f_globals.get('__tracebackhide__'):
            return True

    def get_stack(self, f, t):
        # show all the frames, except the ones that explicitly ask to be hidden
        fullstack, _ = super(Pdb, self).get_stack(f, t)
        self.fullstack = fullstack
        return self.compute_stack(fullstack)

    def compute_stack(self, fullstack):
        if self.show_hidden_frames:
            return fullstack, len(fullstack) - 1

        self.hidden_frames = []
        newstack = []
        for frame, lineno in fullstack:
            if self._is_hidden(frame):
                self.hidden_frames.append((frame, lineno))
            else:
                newstack.append((frame, lineno))
        stack = newstack
        i = max(0, len(stack) - 1)
        return stack, i

    def refresh_stack(self):
        """
        Recompute the stack after e.g. show_hidden_frames has been modified
        """
        self.stack, _ = self.compute_stack(self.fullstack)
        # find the current frame in the new stack
        for i, (frame, _) in enumerate(self.stack):
            if frame is self.curframe:
                self.curindex = i
                break
        else:
            self.curindex = len(self.stack) - 1
            self.curframe = self.stack[-1][0]
            self.print_current_stack_entry()

    def forget(self):
        if not hasattr(self, 'lineno'):
            # Only forget if not used with recursive set_trace.
            super(Pdb, self).forget()
        self.raise_lineno = {}

    @classmethod
    def _get_all_completions(cls, complete, text):
        r = []
        i = 0
        while True:
            comp = complete(text, i)
            if comp is None:
                break
            i += 1
            r.append(comp)
        return r

    def complete(self, text, state):
        """Handle completions from fancycompleter and original pdb."""
        if state == 0:
            if GLOBAL_PDB:
                GLOBAL_PDB._pdbpp_completing = True
            mydict = self.curframe.f_globals.copy()
            mydict.update(self.curframe.f_locals)
            completer = Completer(mydict)
            self._completions = self._get_all_completions(
                completer.complete, text)

            real_pdb = super(Pdb, self)
            for x in self._get_all_completions(real_pdb.complete, text):
                if x not in self._completions:
                    self._completions.append(x)

            if GLOBAL_PDB:
                del GLOBAL_PDB._pdbpp_completing

            # Remove "\t" from fancycompleter if there are pdb completions.
            if len(self._completions) > 1 and self._completions[0] == "\t":
                self._completions.pop(0)

        try:
            return self._completions[state]
        except IndexError:
            return None

    def _init_pygments(self):
        if not self.config.use_pygments:
            return False
        try:
            from pygments.lexers import PythonLexer
            from pygments.formatters import TerminalFormatter, Terminal256Formatter
        except ImportError:
            return False

        if hasattr(self, '_fmt'):
            return True
        if hasattr(self.config, 'formatter'):
            self._fmt = self.config.formatter
        else:
            if (self.config.use_terminal256formatter
                    or (self.config.use_terminal256formatter is None
                        and "256color" in os.environ.get("TERM", ""))):
                Formatter = Terminal256Formatter
            else:
                Formatter = TerminalFormatter
            self._fmt = Formatter(bg=self.config.bg,
                                  colorscheme=self.config.colorscheme)
        self._lexer = PythonLexer()
        return True

    stack_entry_regexp = re.compile(r'(.*?)\(([0-9]+?)\)(.*)', re.DOTALL)

    def format_stack_entry(self, frame_lineno, lprefix=': '):
        entry = super(Pdb, self).format_stack_entry(frame_lineno, lprefix)
        entry = self.try_to_decode(entry)
        if self.config.highlight:
            match = self.stack_entry_regexp.match(entry)
            if match:
                filename, lineno, other = match.groups()
                filename = Color.set(self.config.filename_color, filename)
                lineno = Color.set(self.config.line_number_color, lineno)
                entry = '%s(%s)%s' % (filename, lineno, other)
        return entry

    def try_to_decode(self, s):
        for encoding in self.config.encodings:
            try:
                return s.decode(encoding)
            except (UnicodeDecodeError, AttributeError):
                pass
        return s

    def format_source(self, src):
        if not self._init_pygments():
            return src
        from pygments import highlight
        src = self.try_to_decode(src)
        return highlight(src, self._lexer, self._fmt)

    def format_line(self, lineno, marker, line):
        lineno = '%4d' % lineno
        if self.config.highlight:
            lineno = Color.set(self.config.line_number_color, lineno)
        line = '%s  %2s %s' % (lineno, marker, line)
        if self.config.highlight and marker == '->':
            line = setbgcolor(line, self.config.current_line_color)
        return line

    def parseline(self, line):
        if line.startswith('!!'):
            # force the "standard" behaviour, i.e. first check for the
            # command, then for the variable name to display
            line = line[2:]
            return super(Pdb, self).parseline(line)

        # pdb++ "smart command mode": don't execute commands if a variable
        # with the name exits in the current contex; this prevents pdb to quit
        # if you type e.g. 'r[0]' by mystake.
        cmd, arg, newline = super(Pdb, self).parseline(line)

        if arg and arg.endswith('?'):
            if hasattr(self, 'do_' + cmd):
                cmd, arg = ('help', cmd)
            elif arg.endswith('??'):
                arg = cmd + arg.split('?')[0]
                cmd = 'source'
                self.do_inspect(arg)
                self.stdout.write('%-28s\n' % Color.set(Color.red, 'Source:'))
            else:
                arg = cmd + arg.split('?')[0]
                cmd = 'inspect'
                return cmd, arg, newline

        # f-strings.
        if (cmd == 'f' and len(newline) > 1
                and (newline[1] == "'" or newline[1] == '"')):
            return super(Pdb, self).parseline('!' + line)

        if cmd and hasattr(self,
                           'do_' + cmd) and (cmd in self.curframe.f_globals
                                             or cmd in self.curframe.f_locals
                                             or arg.startswith('=')):
            return super(Pdb, self).parseline('!' + line)

        if cmd == "list" and arg.startswith("("):
            # heuristic: handle "list(..." as the builtin.
            line = '!' + line
            return super(Pdb, self).parseline(line)

        return cmd, arg, newline

    def do_inspect(self, arg):
        obj = self._getval(arg)

        data = OrderedDict()
        data['Type'] = type(obj).__name__
        data['String Form'] = str(obj).strip()
        try:
            data['Length'] = len(obj)
        except TypeError:
            pass
        try:
            data['File'] = inspect.getabsfile(obj)
        except TypeError:
            pass

        if (isinstance(obj, type) and hasattr(obj, '__init__')
                and getattr(obj, '__module__') != '__builtin__'):
            # Class - show definition and docstring for constructor
            data['Docstring'] = obj.__doc__
            data['Constructor information'] = ''
            try:
                data[' Definition'] = '%s%s' % (arg, signature(obj))
            except ValueError:
                pass
            data[' Docstring'] = obj.__init__.__doc__
        else:
            try:
                data['Definition'] = '%s%s' % (arg, signature(obj))
            except (TypeError, ValueError):
                pass
            data['Docstring'] = obj.__doc__

        for key, value in data.items():
            formatted_key = Color.set(Color.red, key + ':')
            self.stdout.write('%-28s %s\n' % (formatted_key, value))

    def default(self, line):
        self.history.append(line)
        return super(Pdb, self).default(line)

    def do_help(self, arg):
        try:
            return super(Pdb, self).do_help(arg)
        except AttributeError:
            print("*** No help for '{command}'".format(command=arg),
                  file=self.stdout)

    do_help.__doc__ = pdb.Pdb.do_help.__doc__

    def help_hidden_frames(self):
        print("""\
Some frames might be marked as "hidden": by default, hidden frames are not
shown in the stack trace, and cannot be reached using ``up`` and ``down``.
You can use ``hf_unhide`` to tell pdb to ignore the hidden status (i.e., to
treat hidden frames as normal ones), and ``hf_hide`` to hide them again.
``hf_list`` prints a list of hidden frames.

Frames can marked as hidden in the following ways:

- by using the @pdb.hideframe function decorator

- by having __tracebackhide__=True in the locals or the globals of the function
  (this hides py.test internal stuff)

- by having __unittest=True in the globals of the function (this hides
  unittest internal stuff)
""",
              file=self.stdout)

    def do_hf_unhide(self, arg):
        """
        {hf_show}
        unhide hidden frames, i.e. make it possible to ``up`` or ``down``
        there
        """
        self.show_hidden_frames = True
        self.refresh_stack()

    def do_hf_hide(self, arg):
        """
        {hf_hide}
        (re)hide hidden frames, if they have been unhidden by ``hf_unhide``
        """
        self.show_hidden_frames = False
        self.refresh_stack()

    def do_hf_list(self, arg):
        for frame_lineno in self.hidden_frames:
            print(self.format_stack_entry(frame_lineno, pdb.line_prefix),
                  file=self.stdout)

    def do_longlist(self, arg):
        """
        {longlist|ll}
        List source code for the current function.

        Differently than list, the whole function is displayed; the
        current line is marked with '->'.  In case of post-mortem
        debugging, the line which effectively raised the exception is
        marked with '>>'.

        If the 'highlight' config option is set and pygments is
        installed, the source code is colorized.
        """
        self.lastcmd = 'longlist'
        self._printlonglist()

    def _printlonglist(self, linerange=None):
        try:
            if self.curframe.f_code.co_name == '<module>':
                # inspect.getsourcelines is buggy in this case: if we just
                # pass the frame, it returns the source for the first function
                # defined in the module.  Instead, we want the full source
                # code of the module
                lines, _ = inspect.findsource(self.curframe)
                lineno = 1
            else:
                try:
                    lines, lineno = inspect.getsourcelines(self.curframe)
                except Exception as e:
                    print('** Error in inspect.getsourcelines: %s **' % e,
                          file=self.stdout)
                    return
        except IOError as e:
            print('** Error: %s **' % e, file=self.stdout)
            return
        if linerange:
            start, end = linerange
            start = max(start, lineno)
            end = min(end, lineno + len(lines))
            lines = lines[start - lineno:end - lineno]
            lineno = start
        self._print_lines_pdbpp(lines, lineno)

    def _print_lines_pdbpp(self, lines, lineno, print_markers=True):
        exc_lineno = self.tb_lineno.get(self.curframe, None)
        lines = [line[:-1] for line in lines]  # remove the trailing '\n'
        lines = [line.replace('\t', '    ')
                 for line in lines]  # force tabs to 4 spaces
        width, height = self.get_terminal_size()

        if self.config.truncate_long_lines:
            maxlength = max(width - 9, 16)
            lines = [line[:maxlength] for line in lines]
        else:
            maxlength = max(map(len, lines))

        if self.config.highlight:
            lines = [line.ljust(maxlength) for line in lines]
            src = self.format_source('\n'.join(lines))
            lines = src.splitlines()
        if height >= 6:
            last_marker_line = max(self.curframe.f_lineno,
                                   exc_lineno if exc_lineno else 0) - lineno
            if last_marker_line >= 0:
                maxlines = last_marker_line + height * 2 // 3
                if len(lines) > maxlines:
                    lines = lines[:maxlines]
                    lines.append('...')
        for i, line in enumerate(lines):
            marker = ''
            if lineno == self.curframe.f_lineno and print_markers:
                marker = '->'
            elif lineno == exc_lineno and print_markers:
                marker = '>>'
            lines[i] = self.format_line(lineno, marker, line)
            lineno += 1
        print('\n'.join(lines), file=self.stdout)

    do_ll = do_longlist

    def do_list(self, arg):
        oldstdout = self.stdout
        self.stdout = StringIO()
        super(Pdb, self).do_list(arg)
        src = self.format_source(self.stdout.getvalue())
        self.stdout = oldstdout
        print(src, file=self.stdout, end='')

    do_list.__doc__ = pdb.Pdb.do_list.__doc__
    do_l = do_list

    def do_continue(self, arg):
        if arg != '':
            self.do_tbreak(arg)
        return super(Pdb, self).do_continue('')

    do_continue.__doc__ = pdb.Pdb.do_continue.__doc__
    do_c = do_cont = do_continue

    def do_pp(self, arg):
        width, height = self.get_terminal_size()
        try:
            pprint.pprint(self._getval(arg), self.stdout, width=width)
        except:
            pass

    do_pp.__doc__ = pdb.Pdb.do_pp.__doc__

    def do_debug(self, arg):
        # this is a hack (as usual :-))
        #
        # inside the original do_debug, there is a call to the global "Pdb" to
        # instantiate the recursive debugger: we want to intercept this call
        # and instantiate *our* Pdb, passing our custom config. Therefore we
        # dynamically rebind the globals.
        Config = self.ConfigFactory

        class PdbppWithConfig(self.__class__):
            def __init__(self, *args):
                kwds = dict(Config=Config)
                super(PdbppWithConfig, self).__init__(*args, **kwds)

                # Backport of fix for bpo-31078 (not yet merged).
                self.use_rawinput = self.use_rawinput

        if sys.version_info < (3, ):
            do_debug_func = pdb.Pdb.do_debug.im_func
        else:
            do_debug_func = pdb.Pdb.do_debug

        newglobals = do_debug_func.__globals__.copy()
        newglobals['Pdb'] = PdbppWithConfig
        orig_do_debug = rebind_globals(do_debug_func, newglobals)

        # Handle any exception, e.g. SyntaxErrors.
        # This is about to be improved in Python itself (3.8, 3.7.3?).
        try:
            return orig_do_debug(self, arg)
        except Exception:
            exc_info = sys.exc_info()[:2]
            msg = traceback.format_exception_only(*exc_info)[-1].strip()
            if hasattr(self, 'error'):
                self.error(msg)
            else:
                # For py27.
                print('***', msg, file=self.stdout)

    do_debug.__doc__ = pdb.Pdb.do_debug.__doc__

    def do_interact(self, arg):
        """
        interact

        Start an interative interpreter whose global namespace
        contains all the names found in the current scope.
        """
        ns = self.curframe.f_globals.copy()
        ns.update(self.curframe.f_locals)
        code.interact("*interactive*", local=ns)

    def do_track(self, arg):
        """
        track expression

        Display a graph showing which objects are referred by the
        value of the expression.  This command requires pypy to be in
        the current PYTHONPATH.
        """
        try:
            from rpython.translator.tool.reftracker import track
        except ImportError:
            print('** cannot import pypy.translator.tool.reftracker **',
                  file=self.stdout)
            return
        try:
            val = self._getval(arg)
        except:
            pass
        else:
            track(val)

    def _get_display_list(self):
        return self.display_list.setdefault(self.curframe, {})

    def _getval_or_undefined(self, arg):
        try:
            return eval(arg, self.curframe.f_globals, self.curframe.f_locals)
        except NameError:
            return undefined

    def do_display(self, arg):
        """
        display expression

        Add expression to the display list; expressions in this list
        are evaluated at each step, and printed every time its value
        changes.

        WARNING: since the expressions is evaluated multiple time, pay
        attention not to put expressions with side-effects in the
        display list.
        """
        try:
            value = self._getval_or_undefined(arg)
        except:
            return
        self._get_display_list()[arg] = value

    def do_undisplay(self, arg):
        """
        undisplay expression

        Remove expression from the display list.
        """
        try:
            del self._get_display_list()[arg]
        except KeyError:
            print('** %s not in the display list **' % arg, file=self.stdout)

    def _print_if_sticky(self):
        old_stdout = self.stdout
        self.stdout = self.sticky_stdout
        if self.sticky:
            if self.first_time_sticky:
                self.first_time_sticky = False
            else:
                self.stdout.write(CLEARSCREEN)
            frame, lineno = self.stack[self.curindex]
            filename = self.canonic(frame.f_code.co_filename)
            s = '> %s(%r)' % (filename, lineno)
            print(s, file=self.stdout)
            print(file=self.stdout)
            sticky_range = self.sticky_ranges.get(self.curframe, None)
            self._printlonglist(sticky_range)

            if '__exception__' in frame.f_locals:
                exc = frame.f_locals['__exception__']
                if len(exc) == 2:
                    exc_type, exc_value = exc
                    s = ''
                    try:
                        try:
                            s = exc_type.__name__
                        except AttributeError:
                            s = str(exc_type)
                        if exc_value is not None:
                            s += ': '
                            s += str(exc_value)
                    except KeyboardInterrupt:
                        raise
                    except:
                        s += '(unprintable exception)'
                    print(Color.set(self.config.line_number_color, ' ' + s),
                          file=self.stdout)
                    return
            if '__return__' in frame.f_locals:
                rv = frame.f_locals['__return__']
                try:
                    s = repr(rv)
                except KeyboardInterrupt:
                    raise
                except:
                    s = '(unprintable return value)'
                print(Color.set(self.config.line_number_color, ' return ' + s),
                      file=self.stdout)
        self.stdout = old_stdout

    def do_sticky(self, arg):
        """
        sticky [start end]

        Toggle sticky mode. When in sticky mode, it clear the screen
        and longlist the current functions, making the source
        appearing always in the same position. Useful to follow the
        flow control of a function when doing step-by-step execution.

        If ``start`` and ``end`` are given, sticky mode is enabled and
        only lines within that range (extremes included) will be
        displayed.
        """
        arg_list = arg.split()
        if len(arg_list) == 1 or len(arg_list) == 3:
            # We want to output to a tty
            self.sticky_stdout = open(arg_list[0], 'w')
            arg = " ".join(arg_list[1:])

        if arg:
            try:
                start, end = map(int, arg.split())
            except ValueError:
                print('** Error when parsing argument: %s **' % arg,
                      file=self.stdout)
                return
            self.sticky = True
            self.sticky_ranges[self.curframe] = start, end + 1
        else:
            self.sticky = not self.sticky
            self.sticky_range = None
        self._print_if_sticky()

    def print_stack_trace(self):
        try:
            for frame_index, frame_lineno in enumerate(self.stack):
                self.print_stack_entry(frame_lineno, frame_index=frame_index)
        except KeyboardInterrupt:
            pass

    def print_stack_entry(self,
                          frame_lineno,
                          prompt_prefix=pdb.line_prefix,
                          frame_index=None):
        frame_index = frame_index if frame_index is not None else self.curindex
        frame, lineno = frame_lineno
        if frame is self.curframe:
            print("[%d] >" % frame_index, file=self.stdout, end=" ")
        else:
            print("[%d]  " % frame_index, file=self.stdout, end=" ")
        print(self.format_stack_entry(frame_lineno, prompt_prefix),
              file=self.stdout)

    def print_current_stack_entry(self):
        if self.sticky:
            self._print_if_sticky()
        else:
            self.print_stack_entry(self.stack[self.curindex])

    def preloop(self):
        RED = "\033[1;31m"
        RESET = "\033[0;0m"
        self._print_if_sticky()
        display_list = self._get_display_list()
        for expr, oldvalue in display_list.items():
            newvalue = self._getval_or_undefined(expr)
            # check for identity first; this prevents custom __eq__ to
            # be called at every loop, and also prevents instances
            # whose fields are changed to be displayed
            if newvalue is not oldvalue or newvalue != oldvalue:
                display_list[expr] = newvalue
                print(RED + '%s: %r --> %r' % (expr, oldvalue, newvalue),
                      RESET,
                      file=self.sticky_stdout)
            else:
                print('%s: %r' % (expr, oldvalue), file=self.sticky_stdout)

    def _get_position_of_arg(self, arg):
        try:
            obj = self._getval(arg)
        except:
            return None, None, None
        if isinstance(obj, str):
            return obj, 1, None
        try:
            filename = inspect.getabsfile(obj)
            lines, lineno = inspect.getsourcelines(obj)
        except (IOError, TypeError) as e:
            print('** Error: %s **' % e, file=self.stdout)
            return None, None, None
        return filename, lineno, lines

    def do_source(self, arg):
        _, lineno, lines = self._get_position_of_arg(arg)
        if lineno is None:
            return
        self._print_lines_pdbpp(lines, lineno, print_markers=False)

    def do_frame(self, arg):
        try:
            arg = int(arg)
        except (ValueError, TypeError):
            print('*** Expected a number, got "{0}"'.format(arg),
                  file=self.stdout)
            return
        if arg < 0 or arg >= len(self.stack):
            print('*** Out of range', file=self.stdout)
        else:
            self.curindex = arg
            self.curframe = self.stack[self.curindex][0]
            self.curframe_locals = self.curframe.f_locals
            self.print_current_stack_entry()
            self.lineno = None

    do_f = do_frame

    def do_up(self, arg='1'):
        arg = '1' if arg == '' else arg
        try:
            arg = int(arg)
        except (ValueError, TypeError):
            print('*** Expected a number, got "{0}"'.format(arg),
                  file=self.stdout)
            return
        if self.curindex - arg < 0:
            print('*** Oldest frame', file=self.stdout)
        else:
            self.curindex = self.curindex - arg
            self.curframe = self.stack[self.curindex][0]
            self.curframe_locals = self.curframe.f_locals
            self.print_current_stack_entry()
            self.lineno = None

    do_up.__doc__ = pdb.Pdb.do_up.__doc__
    do_u = do_up

    def do_down(self, arg='1'):
        arg = '1' if arg == '' else arg
        try:
            arg = int(arg)
        except (ValueError, TypeError):
            print('*** Expected a number, got "{0}"'.format(arg),
                  file=self.stdout)
            return
        if self.curindex + arg >= len(self.stack):
            print('*** Newest frame', file=self.stdout)
        else:
            self.curindex = self.curindex + arg
            self.curframe = self.stack[self.curindex][0]
            self.curframe_locals = self.curframe.f_locals
            self.print_current_stack_entry()
            self.lineno = None

    do_down.__doc__ = pdb.Pdb.do_down.__doc__
    do_d = do_down

    def get_terminal_size(self):
        fallback = (80, 24)
        try:
            from shutil import get_terminal_size
        except ImportError:
            try:
                import termios
                import fcntl
                import struct
                fd = self.stdout.fileno()
                call = fcntl.ioctl(fd, termios.TIOCGWINSZ, "\x00" * 8)
                height, width = struct.unpack("hhhh", call)[:2]
            except (SystemExit, KeyboardInterrupt):
                raise
            except:
                width = int(os.environ.get('COLUMNS', fallback[0]))
                height = int(os.environ.get('COLUMNS', fallback[1]))
            # Work around above returning width, height = 0, 0 in Emacs
            width = width if width != 0 else fallback[0]
            height = height if height != 0 else fallback[1]
            return width, height
        else:
            # We are not going to care about the os environment variable
            # of LINES and COLUMNS because it refers to the wrong tty
            try:
                size = os.get_terminal_size(self.stdout.fileno())
            except (AttributeError, ValueError, OSError):
                # stdout is None, closed, detached, or not a terminal, or
                # os.get_terminal_size() is unsupported
                size = os.terminal_size(fallback)
            columns = size.columns
            lines = size.lines

            return os.terminal_size((columns, lines))

    def _open_editor(self, editor, lineno, filename):
        filename = filename.replace('"', '\\"')
        os.system('%s +%d "%s"' % (editor, lineno, filename))

    def _get_current_position(self):
        frame = self.curframe
        lineno = frame.f_lineno
        filename = os.path.abspath(frame.f_code.co_filename)
        return filename, lineno

    def do_edit(self, arg):
        "Open an editor visiting the current file at the current line"
        if arg == '':
            filename, lineno = self._get_current_position()
        else:
            filename, lineno, _ = self._get_position_of_arg(arg)
            if filename is None:
                return
        # this case handles code generated with py.code.Source()
        # filename is something like '<0-codegen foo.py:18>'
        match = re.match(r'.*<\d+-codegen (.*):(\d+)>', filename)
        if match:
            filename = match.group(1)
            lineno = int(match.group(2))
        editor = self.config.editor
        self._open_editor(editor, lineno, filename)

    do_ed = do_edit

    def _get_history(self):
        return [s for s in self.history if not side_effects_free.match(s)]

    def _get_history_text(self):
        import linecache
        line = linecache.getline(self.start_filename, self.start_lineno)
        nspaces = len(line) - len(line.lstrip())
        indent = ' ' * nspaces
        history = [indent + s for s in self._get_history()]
        return '\n'.join(history) + '\n'

    def _open_stdin_paste(self, stdin_paste, lineno, filename, text):
        proc = subprocess.Popen(
            [stdin_paste, '+%d' % lineno, filename], stdin=subprocess.PIPE)
        proc.stdin.write(text)
        proc.stdin.close()

    def _put(self, text):
        stdin_paste = self.config.stdin_paste
        if stdin_paste is None:
            print('** Error: the "stdin_paste" option is not configured **',
                  file=self.stdout)
        filename = self.start_filename
        lineno = self.start_lineno
        self._open_stdin_paste(stdin_paste, lineno, filename, text)

    def do_put(self, arg):
        text = self._get_history_text()
        self._put(text)

    def do_paste(self, arg):
        arg = arg.strip()
        old_stdout = self.stdout
        self.stdout = StringIO()
        self.onecmd(arg)
        text = self.stdout.getvalue()
        self.stdout = old_stdout
        sys.stdout.write(text)
        self._put(text)

    def set_trace(self, frame=None):
        """Remember starting frame.

        This is used with pytest, which does not use pdb.set_trace().
        """
        if frame is None:
            frame = sys._getframe().f_back
        self._via_set_trace_frame = frame
        return super(Pdb, self).set_trace(frame)

    def is_skipped_module(self, module_name):
        """Backport for https://bugs.python.org/issue36130.

        Fixed in Python 3.8+.
        """
        if module_name is None:
            return False
        return super(Pdb, self).is_skipped_module(module_name)
Пример #12
0
class DataIO(BinFormat):
    """This class wraps a binary file or a string of bytes and provides both
    the file and bytes API.
    """

    def __init__(self, f):
        if isinstance(f,bytes):
            self.f=BytesIO(f)
        else:
            self.f=f

    def __getitem__(self,i):
        stay = self.f.tell()
        sta = i.start or stay
        self.f.seek(sta,0)
        if i.stop is None:
            data = self.f.read()
        else:
            data = self.f.read(i.stop-sta)
        self.f.seek(stay,0)
        return data

    def read(self,size=-1):
        return self.f.read(size)

    def readline(self,size=-1):
        return self.f.readline(size)

    def readlines(self,size=-1):
        return self.f.readlines(size)

    def xreadlines(self,size=-1):
        return self.f.xreadlines(size)

    def write(self,s):
        return self.f.write(s)

    def writelines(self,l):
        return self.f.writelines(l)

    def seek(self,offset,whence=0):
        return self.f.seek(offset,whence)

    def tell(self):
        return self.f.tell()

    def flush(self):
        return self.f.flush()

    def fileno(self):
        return self.f.fileno()

    def isatty(self):
        return self.f.isatty()

    def next(self):
        return self.f.next()

    def truncate(self,size=0):
        return self.f.truncate(size)

    def close(self):
        return self.f.close()

    @property
    def closed(self):
        return self.f.closed

    @property
    def encoding(self):
        return self.f.encoding

    @property
    def errors(self):
        return self.f.errors

    @property
    def mode(self):
        return self.f.mode

    @property
    def name(self):
        try:
            return self.f.name
        except AttributeError:
            try:
                from builtins import bytes
            except ImportError:
                pass
            s = bytes(self.f.getvalue())
            return '(sc-%s...)'%(''.join(["%02x"%x for x in s])[:8])

    filename = name

    @property
    def newlines(self):
        return self.f.newlines

    @property
    def softspace(self):
        return self.f.softspace
Пример #13
0
class VerifiableStream(BinaryIO):
    """A binary stream whose contents can be verified to not have changed.

    The stream does not accept a HMAC key, but generates it randomly as a nonce. While unusual,
    this is intentional -- these streams are meant to be used as part of model serialization,
    where their nonces and HMAC codes are stored in a cryptographically signed metadata file.
    In other words, the HMAC simply ensures that stream's data has not changed, and does not
    guarantee the data's origin -- that's the metadata signature's job.

    The stream is meant to be used in the following sequence:
        - instantiate the stream
        - write all data to the stream (the stream is not readable yet!)
        - call "finalize()" on the stream, saving the returned nonce and HMAC code
        - read data from the stream (the stream is not writable any more!)
    """
    def __init__(self):
        """Create a new VerifiableStream with a random nonce."""
        self._finalized = False
        self._random_nonce = os.urandom(
            16)  # this is bytes, be careful trying to add strings to it
        self._underlying_stream = BytesIO()
        self._hmac_state = hmac.new(self._random_nonce, digestmod=HASHER)

    def _ensure_finalized(self):
        """Raise an error if the stream has not already been finalized."""
        if not self._finalized:
            raise AssertionError(
                "Expected the stream to be finalized, but it was not!")

    def _ensure_not_finalized(self):
        """Raise an error if the stream has already been finalized."""
        if self._finalized:
            raise AssertionError(
                "Expected the stream to not be finalized, but it was!")

    def finalize(self):
        """Calculate the HMAC code for the stream, disable writing and enable reading.

        Returns:
            tuple (nonce, HMAC code)  (both of type string)
        """
        self._ensure_not_finalized()

        self._finalized = True

        nonce_string = _convert_base64_bytes_to_string(self._random_nonce)
        hmac_string = _convert_base64_bytes_to_string(
            self._hmac_state.digest())

        return nonce_string, hmac_string

    # methods for writing require that the stream not be finalized
    def writable(self) -> bool:
        """Return True if the stream is writable, and False otherwise."""
        if self._finalized:
            return False
        else:
            return self._underlying_stream.writable()

    @validate(b=bytes)
    def write(self, b: bytes) -> int:
        """Write the given binary data to the stream, and include it in the HMAC calculation."""
        self._ensure_not_finalized()
        num_bytes = self._underlying_stream.write(b)
        self._hmac_state.update(b)
        return num_bytes

    def writelines(self, lines: Iterable[bytes]) -> None:
        """Write lines to a stream"""
        self._ensure_not_finalized(
        )  # technically done by `write` but doesn't hurt to be safe
        for line in lines:
            self.write(line)
        return None

    # methods for reading require that the stream is finalized
    def readable(self) -> bool:
        """Return True if the stream is readable, and False otherwise."""
        if self._finalized:
            return self._underlying_stream.readable()
        else:
            return False

    def read(self, size=None) -> bytes:
        """Read bytes from stream"""
        self._ensure_finalized()
        return self._underlying_stream.read(size)

    def readall(self) -> bytes:
        """Read lines from stream"""
        raise NotImplementedError(
            "`VerifiablStream` does not implement `readall` since the underlying BtytesIO does not "
            "implement it.")

    def readline(self, size=None) -> bytes:
        """Read a line from stream"""
        self._ensure_finalized()
        return self._underlying_stream.readline(size)

    def readlines(self, size=None) -> List[bytes]:
        """Read lines from stream"""
        self._ensure_finalized()
        return self._underlying_stream.readlines(size)

    def read1(self, size) -> bytes:
        """Read bytes from stream"""
        self._ensure_finalized()
        return self._underlying_stream.read1(size)

    def readinto(self, b) -> Optional[int]:
        """Read bytes into another buffer"""
        self._ensure_finalized()
        return self._underlying_stream.readinto(b)

    def readinto1(self, b) -> Optional[int]:
        """Read bytes into another buffer"""
        self._ensure_finalized()
        return self._underlying_stream.readinto1(b)

    # seeking requires a finalized stream
    def seekable(self):
        """Return True if the read pointer in the stream can be moved, and False otherwise."""
        if self._finalized:
            return self._underlying_stream.seekable()
        else:
            return False

    def seek(self, *args, **kwargs) -> int:
        """Seek to a new position. Return the new position"""
        self._ensure_finalized()
        return self._underlying_stream.seek(*args, **kwargs)

    def truncate(self, size: Optional[int] = ...) -> None:
        """Truncate the stream"""
        raise NotImplementedError(
            "`VerifiableStream` does not support truncation. It is too "
            "complicated to keep track of the hmac digests")

    def close(self):
        """Close the stream, discarding its data. Will raise an error if not finalized yet."""
        if self._finalized:
            return self._underlying_stream.close()
        else:
            raise AssertionError(
                "Attempting to close an unfinalized VerifiableStream. This is "
                "almost certainly a bug.")

    # a bunch of attributes/methods that are always accessible
    def isatty(self) -> bool:
        """Determine whether this is a terminal"""
        return self._underlying_stream.isatty()

    @property
    def closed(self) -> bool:
        """Determine whether the stream is closed"""
        return self._underlying_stream.closed

    def fileno(self) -> int:
        """Return the underlying file descriptor"""
        # this will technically raise UnsuportedOperation, but better to let BytesIO do that
        return self._underlying_stream.fileno()

    def mode(self) -> str:
        """Return the underlying file descriptor"""
        # this doesn't exist for the underlying stream
        raise AssertionError(
            "`VerifiableStream` does not have a mode. This is probably a bug in "
            "something assuming that the stream is a backed by a file")

    def name(self) -> str:
        """Return the underlying file descriptor"""
        # this doesn't exist for the underlying stream
        raise AssertionError(
            "`VerifiableStream` does not have a name. This is probably a bug in "
            "something assuming the stream is a file descriptor")

    def flush(self) -> None:
        """Flush the underlying stream"""
        # this technically does nothing in BytesIO
        return self._underlying_stream.flush()

    def tell(self) -> int:
        """Tell the current position"""
        return self._underlying_stream.tell()

    # context manager methods
    def __enter__(self) -> "VerifiableStream":
        """Enter"""
        return self

    def __exit__(
        self,
        exc_type: Optional[Type[BaseException]],
        exc_val: Optional[BaseException],
        exc_tb: Optional[TracebackType],
    ) -> bool:
        """Exit"""
        return self._underlying_stream.__exit__(exc_type, exc_val, exc_tb)
Пример #14
0
 def test_svg(self):
     def mock_open(name, mode):
         self.assertEqual(mode, "rb")
         return stream
     
     class MockOle:
         def __init__(ole, file):
             self.assertIs(file, stream)
             super().__init__()
         
         def openstream(ole, name):
             self.assertEqual(name, "FileHeader")
             return stream
     
     class mock_os:
         def stat(fileno):
             return None
     
     stream = BytesIO()
     stream.fileno = lambda: stream
     
     sch = (
         b"\x00",
         b"|RECORD=31|FONTIDCOUNT=1|SIZE1=10|FONTNAME1=Times New Roman"
             b"|SYSTEMFONT=1"
             b"|AREACOLOR=16317695|BORDERON=T|CUSTOMX=|CUSTOMY="
             b"|DISPLAY_UNIT=4|HOTSPOTGRIDON=T|HOTSPOTGRIDSIZE="
             b"|SNAPGRIDON=T|SNAPGRIDSIZE=|VISIBLEGRIDON=T"
             b"|VISIBLEGRIDSIZE=10|ISBOC=T|SHEETNUMBERSPACESIZE=4"
             b"|USEMBCS=T\x00",
         b"|RECORD=15|LOCATION.X=100|LOCATION.Y=200|XSIZE=40|YSIZE=30"
             b"|COLOR=7846673|AREACOLOR=3381725|ISSOLID=T|OWNERPARTID=-1"
             b"|UNIQUEID=\x00",
     )
     for list in sch:
         stream.write(len(list).to_bytes(4, "little"))
         stream.write(list)
     stream.seek(0)
     
     output = StringIO()
     with patch("altium.open", mock_open), \
             patch("altium.OleFileIO", MockOle), \
             patch("altium.os", mock_os), \
             redirect_stdout(output):
         altium.convert("dummy.SchDoc", svg.Renderer)
     
     output = XML(output.getvalue())
     SVG = "{http://www.w3.org/2000/svg}"
     
     self.assertEqual(output.tag, SVG + "svg")
     for [dimension, expected] in (("width", 11.506), ("height", 7.606)):
         with self.subTest(dimension):
             value = output.get(dimension)
             self.assertTrue(value.endswith("in"))
             self.assertAlmostEqual(float(value[:-2]), expected, 3)
     for [name, value] in (
         ("viewBox", "-0.3,-760.3 1150.6,760.6"),
         ("stroke-width", "1"),
     ):
         with self.subTest(name):
             self.assertEqual(output.get(name), value)
     
     [style, defs, border, sheet] = output
     self.assertEqual(style.tag, SVG + "style")
     self.assertEqual(defs.tag, SVG + "defs")
     self.assertEqual(border.tag, SVG + "g")
     self.assertCountEqual(border.items(), (
         ("transform", "translate(0, -760)"),
     ))
     
     self.assertEqual(sheet.tag, SVG + "rect")
     self.assertCountEqual(sheet.items(), (
         ("transform",  "translate(100, -200)"),
         ("width", "40"), ("height", "30"),
         ("stroke-width", "0.6"), ("class", "solid"),
         ("style", "fill: #DD9933; stroke: #11BB77"),
     ))
Пример #15
0
class DataIO(object):
    def __init__(self, f):
        if isinstance(f, bytes):
            self.f = BytesIO(f)
        else:
            self.f = f

    def __getitem__(self, i):
        self.f.seek(i.start, 0)
        return self.f.read(i.stop - i.start)

    def read(self, size=-1):
        return self.f.read(size)

    def readline(self, size=-1):
        return self.f.readline(size)

    def readlines(self, size=-1):
        return self.f.readlines(size)

    def xreadlines(self, size=-1):
        return self.f.xreadlines(size)

    def write(self, s):
        return self.f.write(s)

    def writelines(self, l):
        return self.f.writelines(l)

    def seek(self, offset, whence=0):
        return self.f.seek(offset, whence)

    def tell(self):
        return self.f.tell()

    def flush(self):
        return self.f.flush()

    def fileno(self):
        return self.f.fileno()

    def isatty(self):
        return self.f.isatty()

    def next(self):
        return self.f.next()

    def truncate(self, size=0):
        return self.f.truncate(size)

    def close(self):
        return self.f.close()

    @property
    def closed(self):
        return self.f.closed

    @property
    def encoding(self):
        return self.f.encoding

    @property
    def errors(self):
        return self.f.errors

    @property
    def mode(self):
        return self.f.mode

    @property
    def name(self):
        try:
            return self.f.name
        except AttributeError:
            from builtins import bytes
            s = bytes(self.f.getvalue())
            return '(sc-%s...)' % (''.join(["%02x" % x for x in s])[:8])

    filename = name

    @property
    def newlines(self):
        return self.f.newlines

    @property
    def softspace(self):
        return self.f.softspace