Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
181 views
unlisted
ubuntu2004
o

��c>�@sddlZddlZddlZddlZddlZddlmZmZddl	m
Z
ddlZddlZddl
mZddlmZddlmZmZddlmZzddlmZWney[ddlmZYnweGd	d
�d
e��Zee�Zdd�Zd
d�Zdd�Zdd�Zdd�Z dd�Z!dS)�N)�urlretrieve�urlopen)�	HTTPError��QQ)�vector)�CachedFunction�dict_key)�decorator_keywords)�instancedoccs�eZdZdZd�fdd�	Zdd�Zdd	�Zd
d�Zdd
�Zdd�Z	dd�Z
dd�Zdd�Zdd�Z
dd�Zdd�Zdd�Z�ZS)�FileCachedFunctiona@

    Function wrapper that implements a cache extending SageMath's CachedFunction.

    Preface a function definition with @file_cached_function to wrap it.  When
    the wrapped function is called the following locations are visited to try
    and obtain the output data:
    - first the cache in working memory
    - then the local filesystem
    - then the internet If the data is not stored in any of these locations
      then the wrapped function is executed.  The output of the function is
      saved in the working memory cache and as a file in the filesystem.

    By default, the file is saved in the directory given by the directory
    argument in the current working directory.  If a name for a environment
    variable is supplied via the env_var argument and this environment variable
    is set to a valid path, then this director is used instead of the current
    working directory.

    A filename is generated from the function arguments.  The default
    implementation requires that
    - the arguments are hashable and convertible to strings via str(),
    - the resulting strings do not contain any characters not allowed in file
      names.

    The remote_database_list accepts the url of a file that should contain a
    list of all files in the remote cache, one file per line.
    This allows bulk downloading the files with the download_all() method.

    The key argument accepts a callable to generate the cache key from the
    function arguments. For details see the documentation of CachedFunction.

    The filename argument accepts a callable that generates the file name from
    the function name and the key.  Whenever key is provided, filename must be
    provided, too.

    EXAMPLES::

        sage: from admcycles.file_cache import file_cached_function, ignore_args_key, ignore_args_filename
        sage: from tempfile import mkdtemp
        sage: from shutil import rmtree
        sage: import os

        sage: tmpdir = mkdtemp()
        sage: # We ignore the second argument for caching
        sage: @file_cached_function(directory=tmpdir, key=ignore_args_key([1]), filename=ignore_args_filename())
        ....: def f(a, b=True):
        ....:     pass
        sage: f(1)
        sage: assert os.path.exists(os.path.join(tmpdir, "f_1.pkl.bz2"))
        ....:
        sage: os.environ["TEST_CACHE_DIR"] = tmpdir
        sage: @file_cached_function(directory="", env_var="TEST_CACHE_DIR")
        ....: def f(a, b=True):
        ....:     pass
        sage: f(1)
        sage: assert os.path.exists(os.path.join(tmpdir, "f_1_True.pkl.bz2"))
        sage: rmtree(tmpdir)
    N�NNc	
s�||_|dur.ztj|}	tj�|	�st�d||	�ntj�|	|�}Wn	ty-Ynw|dur:|dur:t	d��t
t|�j||d�||_
||_||_|jdurVd|_n|��|_||_|\|_|_dS)Nz&%s=%s is not a directory. Ignoring it.z2If key is provided, filename must also be provided)�keyF)�env_var�os�environ�path�isdir�warnings�warn�join�KeyError�
ValueError�superr�__init__�	directory�url�remote_database_list�	go_online�._FileCachedFunction__get_online_lookup_default�filename�pickle_wrapper�unpickle_wrapper)
�self�frrrrrr �pickle_wrappersZenv_dir��	__class__��8/home/user/Introduction lectures/admcycles/file_cache.pyrTs,
��

zFileCachedFunction.__init__cOs$|j|i|��}z|j|WSty-t|�}z|j|WYSty*YnwYn	ty5Ynw|�|�\}}tj�|�sX|j	rXz|�
||�Wn	tyWYnwtj�|�r�z
|�|�}||j|<|WStytYnty�t
�d�Ynw|j|i|��}|�||�|S)NzScan not unpickle file %s, it was probably created with a newer version of SageMath.)�get_key�cache�	TypeErrorr	r�filename_from_argsrr�existsr�_FileCachedFunction__download�IOError�#_FileCachedFunction__load_from_filerrr$�_FileCachedFunction__save)r#�args�kwds�kr �filename_with_path�datr(r(r)�__call__nsD���

�zFileCachedFunction.__call__cCstj�|jd�S)z=
        Returns the path to the configuration file.
        z
filecache.ini)rrrr)r#r(r(r)Z
__config_file�sz FileCachedFunction.__config_filecCsP|��}t��}|�|�z||jjddkrWdSWdSty'YdSw)z|
        Tries to obtain a user specified value from the config file.
        Returns True if this is not possible.
        �
online_lookup�noFT)� _FileCachedFunction__config_file�configparser�ConfigParser�readr$�__name__r)r#�cf�configr(r(r)Z__get_online_lookup_default�s
���z.FileCachedFunction.__get_online_lookup_defaultcCs�|�|�|��}t��}|�|�|rddi||jj<nddi||jj<t|d��}|�|�Wd�dS1s;wYdS)zP
        Saves the default for online lookup in the configuration file.
        r9�yesr:�wN)	�set_online_lookupr;r<r=r>r$r?�open�write)r#�br@rAZ
configfiler(r(r)�set_online_lookup_default�s

"�z,FileCachedFunction.set_online_lookup_defaultcCs |r|jdurtd��||_dS)z�
        Temporarily set whether online lookup is active.
        Use func:`set_online_lookup_default` to save a default.

        It is set to the boolean ``b``.
        Nz.no online database available for this function)rrr)r#rGr(r(r)rD�s
z$FileCachedFunction.set_online_lookupcOs |j|i|��}|�||�dS)a�
        Manually add a value to the cache.

        EXAMPLES::

            sage: from admcycles.file_cache import file_cached_function
            sage: from tempfile import mkdtemp
            sage: from shutil import rmtree
            sage: tmpdir = mkdtemp()
            sage: @file_cached_function(directory=tmpdir)
            ....: def f(a, b=True):
            ....:     pass
            sage: f.set_cache("test", 1, b=False)
            sage: assert f(1, False) == "test"  # This is the cached value
            sage: f.clear_cache()
            sage: f(1, False)
            'test'
            sage: rmtree(tmpdir)

            The above output "test" is the file cached value, as f returns None.
        N)r*r2)r#r7r3r4r5r(r(r)�	set_cache�szFileCachedFunction.set_cachec
CsRztj�|j�st�|j�WdSWdSty(}z	td|j|�|�d}~ww)z_
        Creates the directory if it does not exist yet.
        May throw an OSError.
        zCan not create directoryN)rrrr�mkdir�OSError�print)r#�er(r(r)Z__create_directory�s���z%FileCachedFunction.__create_directorycCs�||j|<|�|�\}}z|��Wn
tyYdSwt�|d��}|jdur.|�|�}tj||dd�Wd�dS1sAwYdS)a�
        Saves the data in the cache file and the in-memory cache.

        EXAMPLES::

            sage: from admcycles.file_cache import file_cached_function
            sage: from tempfile import mkdtemp
            sage: from shutil import rmtree
            sage: tmpdir = mkdtemp()
            sage: @file_cached_function(directory=tmpdir)
            ....: def f(a, b=True):
            ....:     pass
            sage: k = f.get_key(1)
            sage: f._FileCachedFunction__save(k, "test")
            sage: assert f.cache[k] == "test"
            sage: f.clear_cache()
            sage: f(1)
            'test'
            sage: rmtree(tmpdir)

            The above "test" is the file cached value, as f returns None.
        N�wb�)�protocol)	r+r-�%_FileCachedFunction__create_directoryrK�bz2rEr!�pickle�dump)r#r5r7r r6r$r(r(r)Z__save�s
�

"�zFileCachedFunction.__savecCs`|jdur|jj}|dD]
}|dt|�7}q
|d7}n|�|j|�}tj�|j|�}||fS)a�
        Constructs a file name of the form func_name_arg1_arg2_arg3.pkl.bz2

        EXAMPLES::

            sage: from admcycles.file_cache import file_cached_function
            sage: @file_cached_function(directory="dir")
            ....: def f(a, b=True):
            ....:     pass
            sage: k = f.get_key(1)
            sage: f.filename_from_args(k)
            ('f_1_True.pkl.bz2', 'dir/f_1_True.pkl.bz2')
        Nr�_�.pkl.bz2)r r$r?�strrrrr)r#r5r �ar6r(r(r)r-s

z%FileCachedFunction.filename_from_argscCsbt�|d��!}|jdurt�|�Wd�S|�t�|��Wd�S1s*wYdS)zA
        Unplickles the given file and returns the data.
        �rbN)rRrEr"rS�load)r#r6�filer(r(r)Z__load_from_file+s
�$�z#FileCachedFunction.__load_from_filecCsj|jdur	td��z|��Wn
tyYdSwtj�|j|�}zt||�WdSty4YdSw)zl
        Download the given file from the remote database and stores it
        on the file system.
        N�no url provided)	rrrQrK�urllib�parse�urljoinrr)r#r r6�complete_urlr(r(r)Z
__download5s
��zFileCachedFunction.__downloadc
Cs�|jdur	td��|jdurtd��zEt|j�D]<}|�d���}ttjtj	dd�}t|�|ks;t
d�WdStj�
|j|�}tj�|�sTt
d|�|�||�qWdStyq}zt
d	|j|�WYd}~dSd}~ww)
z>
        Download all files from the remote database.
        Nr\z no remote database list providedzutf-8�.rUz&Recived an invalid filename, aborting.ZDownloadingzCan not open)rrrr�decode�strip�set�string�
ascii_letters�digitsrLrrrrr.r/r)r#r �allowedr6rMr(r(r)�download_allFs*


����zFileCachedFunction.download_all)NNNNNr
)r?�
__module__�__qualname__�__doc__rr8r;rrHrDrIrQr2r-r1r/ri�
__classcell__r(r(r&r)rs:*'
rcs�fdd�}|S)ab
    Returns a callable that builds a key from a list of arguments,
    but ignores the arguments with the indices supplied by ignore_arguments.

    EXAMPLES::

        sage: from admcycles.file_cache import ignore_args_key
        sage: key = ignore_args_key([0, 1])
        sage: key("first arg", "second arg", "third arg")
        ('third arg',)
    cst�fdd�t|�D��S)Nc3s �|]\}}|�vr|VqdS�Nr()�.0�i�arg��ignore_argsr(r)�	<genexpr>os�z/ignore_args_key.<locals>.key.<locals>.<genexpr>)�tuple�	enumerate)r3Zinvalid_argsrrr(r)rnszignore_args_key.<locals>.keyr()rsrr(rrr)�ignore_args_keybsrwcCsdd�}|S)a�
    Returns a callable that builds a file name from the key returned by
    ignore_args_key.

    EXAMPLES::

        sage: from admcycles.file_cache import ignore_args_key, ignore_args_filename
        sage: key = ignore_args_key([0, 1])
        sage: filename = ignore_args_filename()
        sage: def test():
        ....:     pass
        sage: filename(test, key("first arg", "second arg", "third arg"))
        'test_third arg.pkl.bz2'
    cSs,|j}|D]
}|dt|�7}q|d7}|S)NrUrV)r?rW)r$rr rXr(r(r)r �s
z&ignore_args_filename.<locals>.filenamer()r r(r(r)�ignore_args_filenametsrxcCst|���t|���fS)aJ
    Converts a rational number to a pair of python integers.

    EXAMPLES::

        sage: from admcycles.file_cache import rational_to_py
        sage: a, b = rational_to_py(QQ(1/2))
        sage: a
        1
        sage: type(a)
        <class 'int'>
        sage: b
        2
        sage: type(b)
        <class 'int'>
    )�int�	numerator�denominator)�qr(r(r)�rational_to_py�sr}cCst|d�t|d�S)a)
    Converts a pair of python integers (a,b) into the rational number a/b.

    EXAMPLES::

        sage: from admcycles.file_cache import py_to_rational
        sage: q = py_to_rational((1, 2))
        sage: q
        1/2
        sage: type(q)
        <class 'sage.rings.rational.Rational'>
    r�r)�tr(r(r)�py_to_rational�s
r�cC�dd�|D�S)a"
    Converts a list of vectors over QQ into a list of tuples of pairs of python integers.

    EXAMPLES::

        sage: from admcycles.file_cache import rational_vectors_to_py
        sage: v = rational_vectors_to_py([vector(QQ, [1/2, 1])])
        sage: v
        [((1, 2), (1, 1))]
    cSsg|]}tdd�|D���qS)cs��|]}t|�VqdSrn)r})rorXr(r(r)rt���z4rational_vectors_to_py.<locals>.<listcomp>.<genexpr>)ru�ro�vr(r(r)�
<listcomp>�sz*rational_vectors_to_py.<locals>.<listcomp>r(��vsr(r(r)�rational_vectors_to_py�sr�cCr�)a�
    Converts a list of tuples of pairs of python integers into a list of sparse vectors over QQ.

    EXAMPLES::

        sage: from admcycles.file_cache import py_to_rational_vectors
        sage: v = py_to_rational_vectors([((1, 2), (1, 1))])
        sage: v
        [(1/2, 1)]
        sage: type(v[0])
        <class 'sage.modules.free_module_element.FreeModuleElement_generic_sparse'>
    cSs$g|]}ttdd�|D�dd��qS)csr�rn)r�)ror|r(r(r)rt�r�z4py_to_rational_vectors.<locals>.<listcomp>.<genexpr>T)�sparse)rrr�r(r(r)r��s$z*py_to_rational_vectors.<locals>.<listcomp>r(r�r(r(r)�py_to_rational_vectors�s
r�)"rrSrRr�urllib.parser]�urllib.requestrr�urllib.errorrr<re�sage.rings.rational_fieldr� sage.modules.free_module_elementr�sage.misc.cachefuncrr	�sage.misc.decoratorsr
�sage.misc.instancedocr�ImportErrorZsage.docs.instancedocr�file_cached_functionrwrxr}r�r�r�r(r(r(r)�<module>s:�H