diff options
| author | nkozlovskiy <[email protected]> | 2023-09-29 12:24:06 +0300 | 
|---|---|---|
| committer | nkozlovskiy <[email protected]> | 2023-09-29 12:41:34 +0300 | 
| commit | e0e3e1717e3d33762ce61950504f9637a6e669ed (patch) | |
| tree | bca3ff6939b10ed60c3d5c12439963a1146b9711 /contrib/python/ipython/py3/IPython/lib/display.py | |
| parent | 38f2c5852db84c7b4d83adfcb009eb61541d1ccd (diff) | |
add ydb deps
Diffstat (limited to 'contrib/python/ipython/py3/IPython/lib/display.py')
| -rw-r--r-- | contrib/python/ipython/py3/IPython/lib/display.py | 677 | 
1 files changed, 677 insertions, 0 deletions
| diff --git a/contrib/python/ipython/py3/IPython/lib/display.py b/contrib/python/ipython/py3/IPython/lib/display.py new file mode 100644 index 00000000000..f39f389f98b --- /dev/null +++ b/contrib/python/ipython/py3/IPython/lib/display.py @@ -0,0 +1,677 @@ +"""Various display related classes. + +Authors : MinRK, gregcaporaso, dannystaple +""" +from html import escape as html_escape +from os.path import exists, isfile, splitext, abspath, join, isdir +from os import walk, sep, fsdecode + +from IPython.core.display import DisplayObject, TextDisplayObject + +from typing import Tuple, Iterable, Optional + +__all__ = ['Audio', 'IFrame', 'YouTubeVideo', 'VimeoVideo', 'ScribdDocument', +           'FileLink', 'FileLinks', 'Code'] + + +class Audio(DisplayObject): +    """Create an audio object. + +    When this object is returned by an input cell or passed to the +    display function, it will result in Audio controls being displayed +    in the frontend (only works in the notebook). + +    Parameters +    ---------- +    data : numpy array, list, unicode, str or bytes +        Can be one of + +          * Numpy 1d array containing the desired waveform (mono) +          * Numpy 2d array containing waveforms for each channel. +            Shape=(NCHAN, NSAMPLES). For the standard channel order, see +            http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx +          * List of float or integer representing the waveform (mono) +          * String containing the filename +          * Bytestring containing raw PCM data or +          * URL pointing to a file on the web. + +        If the array option is used, the waveform will be normalized. + +        If a filename or url is used, the format support will be browser +        dependent. +    url : unicode +        A URL to download the data from. +    filename : unicode +        Path to a local file to load the data from. +    embed : boolean +        Should the audio data be embedded using a data URI (True) or should +        the original source be referenced. Set this to True if you want the +        audio to playable later with no internet connection in the notebook. + +        Default is `True`, unless the keyword argument `url` is set, then +        default value is `False`. +    rate : integer +        The sampling rate of the raw data. +        Only required when data parameter is being used as an array +    autoplay : bool +        Set to True if the audio should immediately start playing. +        Default is `False`. +    normalize : bool +        Whether audio should be normalized (rescaled) to the maximum possible +        range. Default is `True`. When set to `False`, `data` must be between +        -1 and 1 (inclusive), otherwise an error is raised. +        Applies only when `data` is a list or array of samples; other types of +        audio are never normalized. + +    Examples +    -------- + +    >>> import pytest +    >>> np = pytest.importorskip("numpy") + +    Generate a sound + +    >>> import numpy as np +    >>> framerate = 44100 +    >>> t = np.linspace(0,5,framerate*5) +    >>> data = np.sin(2*np.pi*220*t) + np.sin(2*np.pi*224*t) +    >>> Audio(data, rate=framerate) +    <IPython.lib.display.Audio object> + +    Can also do stereo or more channels + +    >>> dataleft = np.sin(2*np.pi*220*t) +    >>> dataright = np.sin(2*np.pi*224*t) +    >>> Audio([dataleft, dataright], rate=framerate) +    <IPython.lib.display.Audio object> + +    From URL: + +    >>> Audio("http://www.nch.com.au/acm/8k16bitpcm.wav")  # doctest: +SKIP +    >>> Audio(url="http://www.w3schools.com/html/horse.ogg")  # doctest: +SKIP + +    From a File: + +    >>> Audio('IPython/lib/tests/test.wav')  # doctest: +SKIP +    >>> Audio(filename='IPython/lib/tests/test.wav')  # doctest: +SKIP + +    From Bytes: + +    >>> Audio(b'RAW_WAV_DATA..')  # doctest: +SKIP +    >>> Audio(data=b'RAW_WAV_DATA..')  # doctest: +SKIP + +    See Also +    -------- +    ipywidgets.Audio + +         Audio widget with more more flexibility and options. + +    """ +    _read_flags = 'rb' + +    def __init__(self, data=None, filename=None, url=None, embed=None, rate=None, autoplay=False, normalize=True, *, +                 element_id=None): +        if filename is None and url is None and data is None: +            raise ValueError("No audio data found. Expecting filename, url, or data.") +        if embed is False and url is None: +            raise ValueError("No url found. Expecting url when embed=False") + +        if url is not None and embed is not True: +            self.embed = False +        else: +            self.embed = True +        self.autoplay = autoplay +        self.element_id = element_id +        super(Audio, self).__init__(data=data, url=url, filename=filename) + +        if self.data is not None and not isinstance(self.data, bytes): +            if rate is None: +                raise ValueError("rate must be specified when data is a numpy array or list of audio samples.") +            self.data = Audio._make_wav(data, rate, normalize) + +    def reload(self): +        """Reload the raw data from file or URL.""" +        import mimetypes +        if self.embed: +            super(Audio, self).reload() + +        if self.filename is not None: +            self.mimetype = mimetypes.guess_type(self.filename)[0] +        elif self.url is not None: +            self.mimetype = mimetypes.guess_type(self.url)[0] +        else: +            self.mimetype = "audio/wav" + +    @staticmethod +    def _make_wav(data, rate, normalize): +        """ Transform a numpy array to a PCM bytestring """ +        from io import BytesIO +        import wave + +        try: +            scaled, nchan = Audio._validate_and_normalize_with_numpy(data, normalize) +        except ImportError: +            scaled, nchan = Audio._validate_and_normalize_without_numpy(data, normalize) + +        fp = BytesIO() +        waveobj = wave.open(fp,mode='wb') +        waveobj.setnchannels(nchan) +        waveobj.setframerate(rate) +        waveobj.setsampwidth(2) +        waveobj.setcomptype('NONE','NONE') +        waveobj.writeframes(scaled) +        val = fp.getvalue() +        waveobj.close() + +        return val + +    @staticmethod +    def _validate_and_normalize_with_numpy(data, normalize) -> Tuple[bytes, int]: +        import numpy as np + +        data = np.array(data, dtype=float) +        if len(data.shape) == 1: +            nchan = 1 +        elif len(data.shape) == 2: +            # In wave files,channels are interleaved. E.g., +            # "L1R1L2R2..." for stereo. See +            # http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx +            # for channel ordering +            nchan = data.shape[0] +            data = data.T.ravel() +        else: +            raise ValueError('Array audio input must be a 1D or 2D array') +         +        max_abs_value = np.max(np.abs(data)) +        normalization_factor = Audio._get_normalization_factor(max_abs_value, normalize) +        scaled = data / normalization_factor * 32767 +        return scaled.astype("<h").tobytes(), nchan + +    @staticmethod +    def _validate_and_normalize_without_numpy(data, normalize): +        import array +        import sys + +        data = array.array('f', data) + +        try: +            max_abs_value = float(max([abs(x) for x in data])) +        except TypeError as e: +            raise TypeError('Only lists of mono audio are ' +                'supported if numpy is not installed') from e + +        normalization_factor = Audio._get_normalization_factor(max_abs_value, normalize) +        scaled = array.array('h', [int(x / normalization_factor * 32767) for x in data]) +        if sys.byteorder == 'big': +            scaled.byteswap() +        nchan = 1 +        return scaled.tobytes(), nchan + +    @staticmethod +    def _get_normalization_factor(max_abs_value, normalize): +        if not normalize and max_abs_value > 1: +            raise ValueError('Audio data must be between -1 and 1 when normalize=False.') +        return max_abs_value if normalize else 1 + +    def _data_and_metadata(self): +        """shortcut for returning metadata with url information, if defined""" +        md = {} +        if self.url: +            md['url'] = self.url +        if md: +            return self.data, md +        else: +            return self.data + +    def _repr_html_(self): +        src = """ +                <audio {element_id} controls="controls" {autoplay}> +                    <source src="{src}" type="{type}" /> +                    Your browser does not support the audio element. +                </audio> +              """ +        return src.format(src=self.src_attr(), type=self.mimetype, autoplay=self.autoplay_attr(), +                          element_id=self.element_id_attr()) + +    def src_attr(self): +        import base64 +        if self.embed and (self.data is not None): +            data = base64=base64.b64encode(self.data).decode('ascii') +            return """data:{type};base64,{base64}""".format(type=self.mimetype, +                                                            base64=data) +        elif self.url is not None: +            return self.url +        else: +            return "" + +    def autoplay_attr(self): +        if(self.autoplay): +            return 'autoplay="autoplay"' +        else: +            return '' +     +    def element_id_attr(self): +        if (self.element_id): +            return 'id="{element_id}"'.format(element_id=self.element_id) +        else: +            return '' + +class IFrame(object): +    """ +    Generic class to embed an iframe in an IPython notebook +    """ + +    iframe = """ +        <iframe +            width="{width}" +            height="{height}" +            src="{src}{params}" +            frameborder="0" +            allowfullscreen +            {extras} +        ></iframe> +        """ + +    def __init__( +        self, src, width, height, extras: Optional[Iterable[str]] = None, **kwargs +    ): +        if extras is None: +            extras = [] + +        self.src = src +        self.width = width +        self.height = height +        self.extras = extras +        self.params = kwargs + +    def _repr_html_(self): +        """return the embed iframe""" +        if self.params: +            from urllib.parse import urlencode +            params = "?" + urlencode(self.params) +        else: +            params = "" +        return self.iframe.format( +            src=self.src, +            width=self.width, +            height=self.height, +            params=params, +            extras=" ".join(self.extras), +        ) + + +class YouTubeVideo(IFrame): +    """Class for embedding a YouTube Video in an IPython session, based on its video id. + +    e.g. to embed the video from https://www.youtube.com/watch?v=foo , you would +    do:: + +        vid = YouTubeVideo("foo") +        display(vid) + +    To start from 30 seconds:: + +        vid = YouTubeVideo("abc", start=30) +        display(vid) + +    To calculate seconds from time as hours, minutes, seconds use +    :class:`datetime.timedelta`:: + +        start=int(timedelta(hours=1, minutes=46, seconds=40).total_seconds()) + +    Other parameters can be provided as documented at +    https://developers.google.com/youtube/player_parameters#Parameters +     +    When converting the notebook using nbconvert, a jpeg representation of the video +    will be inserted in the document. +    """ + +    def __init__(self, id, width=400, height=300, allow_autoplay=False, **kwargs): +        self.id=id +        src = "https://www.youtube.com/embed/{0}".format(id) +        if allow_autoplay: +            extras = list(kwargs.get("extras", [])) + ['allow="autoplay"'] +            kwargs.update(autoplay=1, extras=extras) +        super(YouTubeVideo, self).__init__(src, width, height, **kwargs) + +    def _repr_jpeg_(self): +        # Deferred import +        from urllib.request import urlopen + +        try: +            return urlopen("https://img.youtube.com/vi/{id}/hqdefault.jpg".format(id=self.id)).read() +        except IOError: +            return None + +class VimeoVideo(IFrame): +    """ +    Class for embedding a Vimeo video in an IPython session, based on its video id. +    """ + +    def __init__(self, id, width=400, height=300, **kwargs): +        src="https://player.vimeo.com/video/{0}".format(id) +        super(VimeoVideo, self).__init__(src, width, height, **kwargs) + +class ScribdDocument(IFrame): +    """ +    Class for embedding a Scribd document in an IPython session + +    Use the start_page params to specify a starting point in the document +    Use the view_mode params to specify display type one off scroll | slideshow | book + +    e.g to Display Wes' foundational paper about PANDAS in book mode from page 3 + +    ScribdDocument(71048089, width=800, height=400, start_page=3, view_mode="book") +    """ + +    def __init__(self, id, width=400, height=300, **kwargs): +        src="https://www.scribd.com/embeds/{0}/content".format(id) +        super(ScribdDocument, self).__init__(src, width, height, **kwargs) + +class FileLink(object): +    """Class for embedding a local file link in an IPython session, based on path + +    e.g. to embed a link that was generated in the IPython notebook as my/data.txt + +    you would do:: + +        local_file = FileLink("my/data.txt") +        display(local_file) + +    or in the HTML notebook, just:: + +        FileLink("my/data.txt") +    """ + +    html_link_str = "<a href='%s' target='_blank'>%s</a>" + +    def __init__(self, +                 path, +                 url_prefix='', +                 result_html_prefix='', +                 result_html_suffix='<br>'): +        """ +        Parameters +        ---------- +        path : str +            path to the file or directory that should be formatted +        url_prefix : str +            prefix to be prepended to all files to form a working link [default: +            ''] +        result_html_prefix : str +            text to append to beginning to link [default: ''] +        result_html_suffix : str +            text to append at the end of link [default: '<br>'] +        """ +        if isdir(path): +            raise ValueError("Cannot display a directory using FileLink. " +              "Use FileLinks to display '%s'." % path) +        self.path = fsdecode(path) +        self.url_prefix = url_prefix +        self.result_html_prefix = result_html_prefix +        self.result_html_suffix = result_html_suffix + +    def _format_path(self): +        fp = ''.join([self.url_prefix, html_escape(self.path)]) +        return ''.join([self.result_html_prefix, +                        self.html_link_str % \ +                            (fp, html_escape(self.path, quote=False)), +                        self.result_html_suffix]) + +    def _repr_html_(self): +        """return html link to file +        """ +        if not exists(self.path): +            return ("Path (<tt>%s</tt>) doesn't exist. " +                    "It may still be in the process of " +                    "being generated, or you may have the " +                    "incorrect path." % self.path) + +        return self._format_path() + +    def __repr__(self): +        """return absolute path to file +        """ +        return abspath(self.path) + +class FileLinks(FileLink): +    """Class for embedding local file links in an IPython session, based on path + +    e.g. to embed links to files that were generated in the IPython notebook +    under ``my/data``, you would do:: + +        local_files = FileLinks("my/data") +        display(local_files) + +    or in the HTML notebook, just:: + +        FileLinks("my/data") +    """ +    def __init__(self, +                 path, +                 url_prefix='', +                 included_suffixes=None, +                 result_html_prefix='', +                 result_html_suffix='<br>', +                 notebook_display_formatter=None, +                 terminal_display_formatter=None, +                 recursive=True): +        """ +        See :class:`FileLink` for the ``path``, ``url_prefix``, +        ``result_html_prefix`` and ``result_html_suffix`` parameters. + +        included_suffixes : list +          Filename suffixes to include when formatting output [default: include +          all files] + +        notebook_display_formatter : function +          Used to format links for display in the notebook. See discussion of +          formatter functions below. + +        terminal_display_formatter : function +          Used to format links for display in the terminal. See discussion of +          formatter functions below. + +        Formatter functions must be of the form:: + +            f(dirname, fnames, included_suffixes) + +        dirname : str +          The name of a directory +        fnames : list +          The files in that directory +        included_suffixes : list +          The file suffixes that should be included in the output (passing None +          meansto include all suffixes in the output in the built-in formatters) +        recursive : boolean +          Whether to recurse into subdirectories. Default is True. + +        The function should return a list of lines that will be printed in the +        notebook (if passing notebook_display_formatter) or the terminal (if +        passing terminal_display_formatter). This function is iterated over for +        each directory in self.path. Default formatters are in place, can be +        passed here to support alternative formatting. + +        """ +        if isfile(path): +            raise ValueError("Cannot display a file using FileLinks. " +              "Use FileLink to display '%s'." % path) +        self.included_suffixes = included_suffixes +        # remove trailing slashes for more consistent output formatting +        path = path.rstrip('/') + +        self.path = path +        self.url_prefix = url_prefix +        self.result_html_prefix = result_html_prefix +        self.result_html_suffix = result_html_suffix + +        self.notebook_display_formatter = \ +             notebook_display_formatter or self._get_notebook_display_formatter() +        self.terminal_display_formatter = \ +             terminal_display_formatter or self._get_terminal_display_formatter() + +        self.recursive = recursive + +    def _get_display_formatter( +        self, dirname_output_format, fname_output_format, fp_format, fp_cleaner=None +    ): +        """generate built-in formatter function + +        this is used to define both the notebook and terminal built-in +         formatters as they only differ by some wrapper text for each entry + +        dirname_output_format: string to use for formatting directory +         names, dirname will be substituted for a single "%s" which +         must appear in this string +        fname_output_format: string to use for formatting file names, +         if a single "%s" appears in the string, fname will be substituted +         if two "%s" appear in the string, the path to fname will be +          substituted for the first and fname will be substituted for the +          second +        fp_format: string to use for formatting filepaths, must contain +         exactly two "%s" and the dirname will be substituted for the first +         and fname will be substituted for the second +        """ +        def f(dirname, fnames, included_suffixes=None): +            result = [] +            # begin by figuring out which filenames, if any, +            # are going to be displayed +            display_fnames = [] +            for fname in fnames: +                if (isfile(join(dirname,fname)) and +                       (included_suffixes is None or +                        splitext(fname)[1] in included_suffixes)): +                      display_fnames.append(fname) + +            if len(display_fnames) == 0: +                # if there are no filenames to display, don't print anything +                # (not even the directory name) +                pass +            else: +                # otherwise print the formatted directory name followed by +                # the formatted filenames +                dirname_output_line = dirname_output_format % dirname +                result.append(dirname_output_line) +                for fname in display_fnames: +                    fp = fp_format % (dirname,fname) +                    if fp_cleaner is not None: +                        fp = fp_cleaner(fp) +                    try: +                        # output can include both a filepath and a filename... +                        fname_output_line = fname_output_format % (fp, fname) +                    except TypeError: +                        # ... or just a single filepath +                        fname_output_line = fname_output_format % fname +                    result.append(fname_output_line) +            return result +        return f + +    def _get_notebook_display_formatter(self, +                                        spacer="  "): +        """ generate function to use for notebook formatting +        """ +        dirname_output_format = \ +         self.result_html_prefix + "%s/" + self.result_html_suffix +        fname_output_format = \ +         self.result_html_prefix + spacer + self.html_link_str + self.result_html_suffix +        fp_format = self.url_prefix + '%s/%s' +        if sep == "\\": +            # Working on a platform where the path separator is "\", so +            # must convert these to "/" for generating a URI +            def fp_cleaner(fp): +                # Replace all occurrences of backslash ("\") with a forward +                # slash ("/") - this is necessary on windows when a path is +                # provided as input, but we must link to a URI +                return fp.replace('\\','/') +        else: +            fp_cleaner = None + +        return self._get_display_formatter(dirname_output_format, +                                           fname_output_format, +                                           fp_format, +                                           fp_cleaner) + +    def _get_terminal_display_formatter(self, +                                        spacer="  "): +        """ generate function to use for terminal formatting +        """ +        dirname_output_format = "%s/" +        fname_output_format = spacer + "%s" +        fp_format = '%s/%s' + +        return self._get_display_formatter(dirname_output_format, +                                           fname_output_format, +                                           fp_format) + +    def _format_path(self): +        result_lines = [] +        if self.recursive: +            walked_dir = list(walk(self.path)) +        else: +            walked_dir = [next(walk(self.path))] +        walked_dir.sort() +        for dirname, subdirs, fnames in walked_dir: +            result_lines += self.notebook_display_formatter(dirname, fnames, self.included_suffixes) +        return '\n'.join(result_lines) + +    def __repr__(self): +        """return newline-separated absolute paths +        """ +        result_lines = [] +        if self.recursive: +            walked_dir = list(walk(self.path)) +        else: +            walked_dir = [next(walk(self.path))] +        walked_dir.sort() +        for dirname, subdirs, fnames in walked_dir: +            result_lines += self.terminal_display_formatter(dirname, fnames, self.included_suffixes) +        return '\n'.join(result_lines) + + +class Code(TextDisplayObject): +    """Display syntax-highlighted source code. + +    This uses Pygments to highlight the code for HTML and Latex output. + +    Parameters +    ---------- +    data : str +        The code as a string +    url : str +        A URL to fetch the code from +    filename : str +        A local filename to load the code from +    language : str +        The short name of a Pygments lexer to use for highlighting. +        If not specified, it will guess the lexer based on the filename +        or the code. Available lexers: http://pygments.org/docs/lexers/ +    """ +    def __init__(self, data=None, url=None, filename=None, language=None): +        self.language = language +        super().__init__(data=data, url=url, filename=filename) + +    def _get_lexer(self): +        if self.language: +            from pygments.lexers import get_lexer_by_name +            return get_lexer_by_name(self.language) +        elif self.filename: +            from pygments.lexers import get_lexer_for_filename +            return get_lexer_for_filename(self.filename) +        else: +            from pygments.lexers import guess_lexer +            return guess_lexer(self.data) + +    def __repr__(self): +        return self.data + +    def _repr_html_(self): +        from pygments import highlight +        from pygments.formatters import HtmlFormatter +        fmt = HtmlFormatter() +        style = '<style>{}</style>'.format(fmt.get_style_defs('.output_html')) +        return style + highlight(self.data, self._get_lexer(), fmt) + +    def _repr_latex_(self): +        from pygments import highlight +        from pygments.formatters import LatexFormatter +        return highlight(self.data, self._get_lexer(), LatexFormatter()) | 
