
    3jU                       U d dl mZ g dZd dlmZ d dlZd dlZd dlZd dlZd dl	Z	d dl
Zd dlZd dlmZ d dlmZ d dlmZ d dlmZ d d	lmZ ej(                  rd d
lmZ d dlmZ  ej2                  d      Z G d dej6                        Z G d dej:                        Z G d dej:                        Zi Z de!d<   ddZ" G d dejF                        Z$eefZ%e&dk(  rd dlZ ejN                  e$       yy)    )annotations)MetadataEntryMetadataBundleMetadataBundleException)OrderedDictN)common)readPickleGzip)environment)exceptions21)prebase)Iterable)Metadatazmetadata.bundlesc                      e Zd Zy)r   N)__name__
__module____qualname__     E/DATA/.local/lib/python3.12/site-packages/music21/metadata/bundles.pyr   r   .   s    r   r   c                      e Zd ZdZ	 	 	 	 d	 	 	 	 	 	 	 ddZd Zd Zd Zd ZddZ	dd	Z
ed
        Zed        Zed        Zed        Zed        Zy)r   aZ  
    An entry in a metadata bundle.

    The metadata entry holds information about the source of the metadata,
    and can be parsed to reconstitute the score object the metadata was
    derived from:

    >>> #_DOCS_SHOW coreBundle = corpus.corpora.CoreCorpus().metadataBundle
    >>> coreBundle = metadata.bundles.demo_bundle('core')  #_DOCS_HIDE
    >>> metadataEntry = coreBundle.search('bwv66.6')[0]
    >>> metadataEntry
    <music21.metadata.bundles.MetadataEntry 'bach_bwv66_6_mxl'>

    The sourcePath of the metadata entry refers to the file path at which its
    score file is found, but it is usually a relative path to the top of the corpus
    directory.  It is a pathlib object.

    >>> metadataEntry.sourcePath
    PosixPath('bach/bwv66.6.mxl')

    The metadata property contains its :class:`~music21.metadata.RichMetadata` object:

    >>> metadataEntry.metadata
    <music21.metadata.RichMetadata object at 0x...>

    Note that the id is not necessarily the current memory location.

    And the metadata entry can be parsed:

    >>> metadataEntry.parse()
    <music21.stream.Score ...>
    Nc                N    t        |      | _        || _        || _        || _        y N)str_sourcePath_number_metadataPayload_corpusName)self
sourcePathnumbermetadataPayload
corpusNames        r   __init__zMetadataEntry.__init__X   s'     !$J /%r   c                H    | j                   | j                  | j                  fS )z
        This is all the information that is needed for pickling.
        Specifically do not include _corpusName.

        Note do not pickle Pathlib objects, so make sure to do ._sourcePath
        not .sourcePath
        )r   metadatar    r   s    r   __getnewargs__zMetadataEntry.__getnewargs__e   s%     MMKK
 	
r   c                ,    t        | j                        S r   )repr
corpusPathr&   s    r   _reprInternalzMetadataEntry._reprInternals   s    DOO$$r   c                    | j                   S )aI  
        Allows MetadataEntries to be used where file paths are being employed,
        so it can be used with opening and closing, etc.

        Returns self.sourcePath() as a string

        >>> mde1 = metadata.bundles.MetadataEntry(sourcePath='/tmp/myFile.xml')
        >>> mde1.__fspath__()
        '/tmp/myFile.xml'
        )r   r&   s    r   
__fspath__zMetadataEntry.__fspath__v   s     r   c                    ddl m} | j                  '|j                  | j                  | j                        S |j                  | j                        S )Nr   corpus)r    )music21r0   r    parser   )r   r0   s     r   r2   zMetadataEntry.parse   s=    ";;"<<<DD<<00r   c                F    | j                         }|j                  |       y r   )r2   show)r   
showFormatscores      r   r4   zMetadataEntry.show   s    



:r   c                >     | j                   j                  ||fi |S r   )r%   search)r   queryfieldkeywordss       r   r8   zMetadataEntry.search   s     #t}}##E5=H==r   c                V    t         j                  | j                  | j                        S )z^
        Returns the sourcePath as a string, with _number appended if it is not None.
        )r   corpusPathToKeyr   r    r&   s    r   r*   zMetadataEntry.corpusPath   s    
 --doot{{KKr   c                    | j                   S )zK
        Returns the Metadata object that is stored in the bundle.
        )r   r&   s    r   r%   zMetadataEntry.metadata   s    
 $$$r   c                    | j                   S r   )r   r&   s    r   r    zMetadataEntry.number   s    ||r   c                @    t        j                  | j                        S r   )pathlibPathr   r&   s    r   r   zMetadataEntry.sourcePath   s    ||D,,--r   c                    | j                   S r   )r   r&   s    r   r"   zMetadataEntry.corpusName   s    r   ) NNrD   )r   str | pathlib.Pathr    
int | Noner!   zMetadata | Noner"   r   r   NN)r   r   r   __doc__r#   r'   r+   r-   r2   r4   r8   propertyr*   r%   r    r   r"   r   r   r   r   r   4   s    H 13$(26#%	
&-
&!
& #0
& !	
&
% 1> L L % %   . .    r   r   c                  l   e Zd ZdZd(d)dZd*dZd Zd*dZd Zd*dZ	d*d	Z
d
 Zd*dZd Zd Zd Zd Zd+dZd Zed        Zej*                  d        Zed,d       Zed        Z	 	 	 	 d-dZd Zed(d.d       Zd/dZd Zd Zd Zd Z d Z!ed        Z"d(d Z#	 	 d0d!d"	 	 	 d1d#Z$d$ Z%d% Z&d& Z'd(d'Z(y)2r   a   
    An object that provides access to, searches within, and stores and loads
    multiple Metadata objects.

    >>> #_DOCS_SHOW coreBundle = corpus.corpora.CoreCorpus().metadataBundle
    >>> coreBundle = metadata.bundles.demo_bundle('core')  #_DOCS_HIDE
    >>> coreBundle
    <music21.metadata.bundles.MetadataBundle 'core': {151... entries}>

    (The coreBundle has around 15100 entries; I've put '...' in the
    docs so I don't need to rewrite them every time we add a new piece)

    >>> #_DOCS_SHOW searchResults = coreBundle.search('bach', field='composer')
    >>> searchResults = metadata.bundles.demo_bundle('bach')  #_DOCS_HIDE
    >>> searchResults
    <music21.metadata.bundles.MetadataBundle {363 entries}>

    >>> resultsEntries = searchResults.search('3/4')
    >>> resultsEntries
    <music21.metadata.bundles.MetadataBundle {40 entries}>

    Results are ordered by their source path:

    >>> resultsEntries[0]
    <music21.metadata.bundles.MetadataEntry 'bach_bwv11_6_mxl'>

    To get a score out of the entry, call .parse()

    >>> resultsEntries[0].parse()
    <music21.stream.Score ...>

    Or pass it into converter:

    >>> converter.parse(resultsEntries[0])
    <music21.stream.Score ...>

    A metadata bundle can be instantiated in three ways, (1) from a ``Corpus`` instance,
    or (2) a string indicating which corpus name to draw from, and then calling
    .read() or (3) by calling
    .metadataBundle on a corpus object.  This
    calls `.read()` automatically:

    Method 1:

    >>> coreCorpus = corpus.corpora.CoreCorpus()
    >>> coreBundle = metadata.bundles.MetadataBundle(coreCorpus)
    >>> localCorpus = corpus.corpora.LocalCorpus()
    >>> localBundle = metadata.bundles.MetadataBundle(localCorpus)

    Method 2:

    >>> coreBundle = metadata.bundles.MetadataBundle('core')
    >>> localBundle = metadata.bundles.MetadataBundle('local')

    After calling these you'll need to call ``read()``:

    >>> coreBundle
    <music21.metadata.bundles.MetadataBundle 'core': {0 entries}>
    >>> coreBundle.read()
    <music21.metadata.bundles.MetadataBundle 'core': {151... entries}>
    >>> coreBundle
    <music21.metadata.bundles.MetadataBundle 'core': {151... entries}>

    Method 3:

    >>> coreBundle = corpus.corpora.CoreCorpus().metadataBundle
    >>> localBundle = corpus.corpora.LocalCorpus().metadataBundle

    >>> coreBundle
    <music21.metadata.bundles.MetadataBundle 'core': {151... entries}>

    Additionally, any two metadata bundles can be operated on together as
    though they were sets, allowing us to build up more complex searches:

    >>> #_DOCS_SHOW coreBundle = corpus.corpora.CoreCorpus().metadataBundle
    >>> coreBundle = metadata.bundles.demo_bundle('core')  #_DOCS_HIDE
    >>> #_DOCS_SHOW bachBundle = coreBundle.search('bach', 'composer')
    >>> bachBundle = metadata.bundles.demo_bundle('bach')  #_DOCS_HIDE
    >>> bachBundle
    <music21.metadata.bundles.MetadataBundle {363 entries}>
    >>> #_DOCS_SHOW tripleMeterBundle = coreBundle.search('3/4')
    >>> tripleMeterBundle = metadata.bundles.demo_bundle('3/4')  #_DOCS_HIDE
    >>> tripleMeterBundle
    <music21.metadata.bundles.MetadataBundle {1875 entries}>
    >>> bachBundle.intersection(tripleMeterBundle)
    <music21.metadata.bundles.MetadataBundle {40 entries}>

    Finally, a metadata bundle need not be associated with any corpus at all,
    and can be populated ad hoc:

    >>> anonymousBundle = metadata.bundles.MetadataBundle()
    >>> mdb = corpus.corpora.CoreCorpus().search('monteverdi')[:4]
    >>> paths = [common.getCorpusFilePath() / x.sourcePath for x in mdb]
    >>> failedPaths = anonymousBundle.addFromPaths(
    ...     paths, useMultiprocessing=False)
    >>> failedPaths
    []
    >>> anonymousBundle
    <music21.metadata.bundles.MetadataBundle {4 entries}>
    Nc                D   ddl m} t               | _        t	        |t
        |j                  j                  t        d       f      st        d      d | _
        |  t	        ||j                  j                        r|j                  | _        || _        y || _        d | _        y )Nr   r/   z4Need to take a string, corpus, or None as expression)r1   r0   r   _metadataEntries
isinstancer   corporaCorpustyper   _corpusname_name)r   exprr0   s      r   r#   zMetadataBundle.__init__  sx    "AL$fnn&;&;T$Z HI)*`aa37dFNN112DJDKDJDKr   c                &    | j                  |d      S )aU  
        Compute the set-wise `and` of two metadata bundles:

        >>> #_DOCS_SHOW coreBundle = corpus.corpora.CoreCorpus().metadataBundle
        >>> coreBundle = metadata.bundles.demo_bundle('core')  #_DOCS_HIDE
        >>> #_DOCS_SHOW bachBundle = coreBundle.search('bach', 'composer')
        >>> bachBundle = metadata.bundles.demo_bundle('bach')  #_DOCS_HIDE
        >>> bachBundle
        <music21.metadata.bundles.MetadataBundle {363 entries}>
        >>> #_DOCS_SHOW tripleMeterBundle = coreBundle.search('3/4')
        >>> tripleMeterBundle = metadata.bundles.demo_bundle('3/4')  #_DOCS_HIDE
        >>> tripleMeterBundle
        <music21.metadata.bundles.MetadataBundle {1875 entries}>
        >>> bachBundle & tripleMeterBundle
        <music21.metadata.bundles.MetadataBundle {40 entries}>

        Returns a new metadata bundle.
        __and___apply_set_operationr   metadataBundles     r   rV   zMetadataBundle.__and__2  s    & ((
 	
r   c                P    t        |d      r| j                  |j                  k(  ryy)a7  
        True if `expr` is of the same type, and contains an identical set of
        entries, otherwise false:

        >>> #_DOCS_SHOW coreBundle = corpus.corpora.CoreCorpus().metadataBundle
        >>> coreBundle = metadata.bundles.demo_bundle('core')  #_DOCS_HIDE
        >>> #_DOCS_SHOW bachBundle = coreBundle.search('bach', 'composer')
        >>> bachBundle = metadata.bundles.demo_bundle('bach')  #_DOCS_HIDE
        >>> #_DOCS_SHOW corelliBundle = coreBundle.search('corelli', 'composer')
        >>> corelliBundle = metadata.bundles.demo_bundle('corelli')  #_DOCS_HIDE
        >>> bachBundle == corelliBundle
        False
        >>> bachBundle == coreBundle.search(
        ...     'bach',
        ...     field='composer',
        ...     )
        True
        >>> bachBundle == 'foo'
        False

        rL   TF)hasattrrL   )r   others     r   __eq__zMetadataBundle.__eq__J  s)    , 5,-$$(>(>>r   c                &    | j                  |d      S )a9  
        True when one metadata bundle is either a superset or an identical set
        to another bundle:

        >>> #_DOCS_SHOW coreBundle = corpus.corpora.CoreCorpus().metadataBundle
        >>> coreBundle = metadata.bundles.demo_bundle('core')  #_DOCS_HIDE
        >>> #_DOCS_SHOW bachBundle = coreBundle.search('bach', 'composer')
        >>> bachBundle = metadata.bundles.demo_bundle('bach')  #_DOCS_HIDE
        >>> #_DOCS_SHOW corelliBundle = coreBundle.search('corelli', 'composer')
        >>> corelliBundle = metadata.bundles.demo_bundle('corelli')  #_DOCS_HIDE
        >>> bachBundle >= bachBundle
        True
        >>> bachBundle >= corelliBundle
        False
        >>> bachBundle >= coreBundle
        False
        >>> corelliBundle >= bachBundle
        False
        >>> corelliBundle >= corelliBundle
        True
        >>> corelliBundle >= coreBundle
        False
        >>> coreBundle >= bachBundle
        True
        >>> coreBundle >= corelliBundle
        True
        >>> coreBundle >= coreBundle
        True

        Returns boolean.
        __ge___apply_set_predicaterY   s     r   r`   zMetadataBundle.__ge__e      @ ((BBr   c                N    t        | j                  j                               |   S r   )listrL   values)r   is     r   __getitem__zMetadataBundle.__getitem__  s!    D))0023A66r   c                &    | j                  |d      S )a1  
        True when one metadata bundle is either a subset or an identical set to
        another bundle:

        >>> #_DOCS_SHOW coreBundle = corpus.corpora.CoreCorpus().metadataBundle
        >>> coreBundle = metadata.bundles.demo_bundle('core')  #_DOCS_HIDE
        >>> #_DOCS_SHOW bachBundle = coreBundle.search('bach', 'composer')
        >>> bachBundle = metadata.bundles.demo_bundle('bach')  #_DOCS_HIDE
        >>> #_DOCS_SHOW corelliBundle = coreBundle.search('corelli', 'composer')
        >>> corelliBundle = metadata.bundles.demo_bundle('corelli')  #_DOCS_HIDE
        >>> bachBundle > bachBundle
        False
        >>> bachBundle > corelliBundle
        False
        >>> bachBundle > coreBundle
        False
        >>> corelliBundle > bachBundle
        False
        >>> corelliBundle > corelliBundle
        False
        >>> corelliBundle > coreBundle
        False
        >>> coreBundle > bachBundle
        True
        >>> coreBundle > corelliBundle
        True
        >>> coreBundle > coreBundle
        False

        Returns boolean.
        __gt__ra   rY   s     r   rj   zMetadataBundle.__gt__  rc   r   c                &    | j                  |d      S )a7  
        True when one metadata bundle is either a subset or an identical set to
        another bundle:

        >>> #_DOCS_SHOW coreBundle = corpus.corpora.CoreCorpus().metadataBundle
        >>> coreBundle = metadata.bundles.demo_bundle('core')  #_DOCS_HIDE
        >>> #_DOCS_SHOW bachBundle = coreBundle.search('bach', 'composer')
        >>> bachBundle = metadata.bundles.demo_bundle('bach')  #_DOCS_HIDE
        >>> #_DOCS_SHOW corelliBundle = coreBundle.search('corelli', 'composer')
        >>> corelliBundle = metadata.bundles.demo_bundle('corelli')  #_DOCS_HIDE
        >>> bachBundle <= bachBundle
        True
        >>> bachBundle <= corelliBundle
        False
        >>> bachBundle <= coreBundle
        True
        >>> corelliBundle <= bachBundle
        False
        >>> corelliBundle <= corelliBundle
        True
        >>> corelliBundle <= coreBundle
        True
        >>> coreBundle <= bachBundle
        False
        >>> coreBundle <= corelliBundle
        False
        >>> coreBundle <= coreBundle
        True

        Returns boolean.
        __le__ra   rY   s     r   rl   zMetadataBundle.__le__  rc   r   c                ,    t        | j                        S r   )lenrL   r&   s    r   __len__zMetadataBundle.__len__  s    4(())r   c                &    | j                  |d      S )a  
        True when one metadata bundle is a subset of another bundle:

        >>> #_DOCS_SHOW coreBundle = corpus.corpora.CoreCorpus().metadataBundle
        >>> coreBundle = metadata.bundles.demo_bundle('core')  #_DOCS_HIDE
        >>> #_DOCS_SHOW bachBundle = coreBundle.search('bach', 'composer')
        >>> bachBundle = metadata.bundles.demo_bundle('bach')  #_DOCS_HIDE
        >>> #_DOCS_SHOW corelliBundle = coreBundle.search('corelli', 'composer')
        >>> corelliBundle = metadata.bundles.demo_bundle('corelli')  #_DOCS_HIDE
        >>> bachBundle < bachBundle
        False
        >>> bachBundle < corelliBundle
        False
        >>> bachBundle < coreBundle
        True
        >>> corelliBundle < bachBundle
        False
        >>> corelliBundle < corelliBundle
        False
        >>> corelliBundle < coreBundle
        True
        >>> coreBundle < bachBundle
        False
        >>> coreBundle < corelliBundle
        False
        >>> coreBundle < coreBundle
        False

        Return boolean.
        __lt__ra   rY   s     r   rq   zMetadataBundle.__lt__  s    > ((BBr   c                &    | j                  |d      S )aT  
        Compute the set-wise `or` of two metadata bundles:

        >>> #_DOCS_SHOW coreBundle = corpus.corpora.CoreCorpus().metadataBundle
        >>> coreBundle = metadata.bundles.demo_bundle('core')  #_DOCS_HIDE
        >>> #_DOCS_SHOW bachBundle = coreBundle.search('bach', 'composer')
        >>> bachBundle = metadata.bundles.demo_bundle('bach')  #_DOCS_HIDE
        >>> bachBundle
        <music21.metadata.bundles.MetadataBundle {363 entries}>
        >>> #_DOCS_SHOW corelliBundle = coreBundle.search('corelli', 'composer')
        >>> corelliBundle = metadata.bundles.demo_bundle('corelli')  #_DOCS_HIDE
        >>> corelliBundle
        <music21.metadata.bundles.MetadataBundle {1 entry}>
        >>> bachBundle | corelliBundle
        <music21.metadata.bundles.MetadataBundle {364 entries}>

        Returns a new metadata bundle.
        __or__rW   rY   s     r   rs   zMetadataBundle.__or__  s    & ((
 	
r   c                    t        |       dk(  rd}ndt        t        |             z   dz   }| j                  | j                  d| }|S )N   z	{1 entry}{z	 entries}z: )rn   r   rR   )r   statuss     r   r+   zMetadataBundle._reprInternal
  sL    t9> F3s4y>)K7F99 		}Bvh/Fr   c                &    | j                  |d      S )a  
        Compute the set-wise `subtraction` of two metadata bundles:

        >>> #_DOCS_SHOW coreBundle = corpus.corpora.CoreCorpus().metadataBundle
        >>> coreBundle = metadata.bundles.demo_bundle('core')  #_DOCS_HIDE
        >>> #_DOCS_SHOW bachBundle = coreBundle.search('bach', 'composer')
        >>> bachBundle = metadata.bundles.demo_bundle('bach')  #_DOCS_HIDE
        >>> bachBundle
        <music21.metadata.bundles.MetadataBundle {363 entries}>
        >>> #_DOCS_SHOW tripleMeterBundle = coreBundle.search('3/4')
        >>> tripleMeterBundle = metadata.bundles.demo_bundle('3/4')  #_DOCS_HIDE
        >>> tripleMeterBundle
        <music21.metadata.bundles.MetadataBundle {1875 entries}>
        >>> bachBundle - tripleMeterBundle
        <music21.metadata.bundles.MetadataBundle {323 entries}>

        Returns a new metadata bundle.

        >>> bachBundle - bachBundle
        <music21.metadata.bundles.MetadataBundle {0 entries}>
        __sub__rW   rY   s     r   ry   zMetadataBundle.__sub__  s    , ((
 	
r   c                &    | j                  |d      S )aa  
        Compute the set-wise `exclusive or` of two metadata bundles:

        >>> #_DOCS_SHOW coreBundle = corpus.corpora.CoreCorpus().metadataBundle
        >>> coreBundle = metadata.bundles.demo_bundle('core')  #_DOCS_HIDE
        >>> #_DOCS_SHOW bachBundle = coreBundle.search('bach', 'composer')
        >>> bachBundle = metadata.bundles.demo_bundle('bach')  #_DOCS_HIDE
        >>> bachBundle
        <music21.metadata.bundles.MetadataBundle {363 entries}>

        >>> #_DOCS_SHOW tripleMeterBundle = coreBundle.search('3/4')
        >>> tripleMeterBundle = metadata.bundles.demo_bundle('3/4')  #_DOCS_HIDE
        >>> tripleMeterBundle
        <music21.metadata.bundles.MetadataBundle {1875 entries}>
        >>> bachBundle ^ tripleMeterBundle
        <music21.metadata.bundles.MetadataBundle {2158 entries}>

        Returns a new metadata bundle.
        __xor__rW   rY   s     r   r{   zMetadataBundle.__xor__/  s    ( ((
 	
r   c                   t        |t        |             st        d      t        | j                  j                               }t        |j                  j                               } t        ||      |      } t        |              }|D ]>  }|| j                  v r| j                  |   }n|j                  |   }||j                  |<   @ t        |j                  j                               }	t        t        |	d             |_        |S )N'metadataBundle must be a MetadataBundlec                     | d   j                   S Nru   r   mdes    r   <lambda>z5MetadataBundle._apply_set_operation.<locals>.<lambda>\  s    3q6K\K\r   key)rM   rP   r   setrL   keysgetattrre   itemsr   sorted)
r   rZ   operatorselfKeys	otherKeys
resultKeysresultBundler   metadataEntrymdbItemss
             r   rX   z#MetadataBundle._apply_set_operationJ  s    .$t*5)*STTt,,113477<<>?	 ;( ;I F
'1tDz|Cd+++ $ 5 5c : . ? ? D1>L))#.  599V9V9\9\9^4_(3F8?\5^ )_%r   c                    t        |t        |             st        d      t        | j                  j                               }t        |j                  j                               } t        ||      |      S )zZ
        Applies a predicate such as '__or__' to self and another metadataBundle.
        r}   )rM   rP   r   r   rL   r   r   )r   rZ   	predicater   r   s        r   rb   z#MetadataBundle._apply_set_predicate_  sd     .$t*5)*STTt,,113477<<>?	+wx+I66r   c                    | j                   #t        j                  | j                         }||S | j                  yddlm} |j                  | j                        S )a  
        The `corpus.corpora.Corpus` object associated with the metadata
        bundle's name.

        >>> #_DOCS_SHOW coreBundle = corpus.corpora.CoreCorpus().metadataBundle
        >>> coreBundle = metadata.bundles.demo_bundle('core')  #_DOCS_HIDE
        >>> coreBundle
        <music21.metadata.bundles.MetadataBundle 'core': {151... entries}>
        >>> coreBundle.corpus
        <music21.corpus.corpora.CoreCorpus>
        Nr   )manager)rQ   r   unwrapWeakrefrR   music21.corpusr   fromName)r   cObjr   s      r   r0   zMetadataBundle.corpusm  sR     <<#''5D99*		**r   c                8    t        j                  |      | _        y r   )r   wrapWeakrefrQ   )r   	newCorpuss     r   r0   zMetadataBundle.corpus  s    )))4r   c                    | j                   }|y|j                  }t        |t        j                        st        j                  |      S |S )a  
        The filesystem name of the cached metadata bundle, if the metadata
        bundle's name is not None.

        >>> ccPath = corpus.corpora.CoreCorpus().metadataBundle.filePath
        >>> ccPath.name
        'core.p.gz'
        >>> '_metadataCache' in ccPath.parts
        True

        >>> localPath = corpus.corpora.LocalCorpus().metadataBundle.filePath
        >>> localPath.name
        'local.p.gz'

        Local corpora metadata is stored in the scratch dir, not the
        corpus directory

        >>> '_metadataCache' in localPath.parts
        False

        >>> funkCorpus = corpus.corpora.LocalCorpus('funk')
        >>> funkPath = funkCorpus.metadataBundle.filePath
        >>> funkPath.name
        'local-funk.p.gz'
        N)r0   cacheFilePathrM   rA   rB   )r   ccfps      r   filePathzMetadataBundle.filePath  s@    6 KK9//Cc7<<0||C((
r   c                    | j                   S )aM  
        The name of the metadata bundle.

        Can be 'core', 'local', '{name}' where name is the name
        of a named local corpus or None.

        The names 'core' and 'local' refer to the core and local
        corpora respectively: (virtual corpus is currently offline)

        >>> metadata.bundles.MetadataBundle().name is None
        True
        >>> corpus.corpora.CoreCorpus().metadataBundle.name
        'core'

        >>> funkCorpus = corpus.corpora.LocalCorpus('funk')
        >>> funkCorpus.metadataBundle.name
        'funk'

        Return string or None.
        )rS   r&   s    r   rR   zMetadataBundle.name  s    , zzr   c           	        ddl m} g }g }g }	| j                  ?| j                  j                         r%| j                  j	                         j
                  }
nt        j                         }
d|
 }|du rt        j                  |       nt        j                  |       d}d}|D ]  }| j                  |      }|| j                  v r%|j	                         j
                  }||
k  r|dz  }G|dz  }| j                  }|d}|j                  d      r|d	d }|j                  j                  ||||
      }|j!                  |        d}d| d}|du rt        j                  |       nt        j                  |       |r!|j                  j"                  j$                  }n |j                  j"                  j&                  } ||      D ]  }|j                  j"                  j)                  t+        |      |d   |d   t+        |	            }|du rt        j                  |       nt        j                  |       |dz  }|j-                  |d          |	j-                  |d          |d   D ]  }|| j                  |j.                  <    |dz  dk(  s|du s| j1                           | j3                          |du r| j1                          |	S )a  
        Parse and store metadata from numerous files.

        If any files cannot be loaded, their file paths will be collected in a
        list that is returned.

        Returns a list of file paths with errors and stores the extracted
        metadata in `self._metadataEntries`.

        >>> metadataBundle = metadata.bundles.MetadataBundle()
        >>> p = corpus.corpora.CoreCorpus().getWorkList('bach/bwv66.6')
        >>> metadataBundle.addFromPaths(
        ...     p,
        ...     parseUsingCorpus=False,
        ...     useMultiprocessing=False,
        ...     storeOnDisk=False, #_DOCS_HIDE
        ...     )
        []
        >>> len(metadataBundle._metadataEntries)
        1

        Set Verbose to True to get updates even if debug is off.
        r   )r%   Nz"MetadataBundle Modification Time: Tru   corezlocal-   )	jobNumberparseUsingCorpusr"   zSkipped z sources already in cache.remainingJobsr   metadataEntrieserrors2   )r1   r%   r   existsstatst_ctimetimeenvironLocalwarn
printDebugr=   rL   rR   
startswithcachingMetadataCachingJobappendJobProcessorprocess_parallelprocess_serial_reportrn   extendr*   writevalidate)r   pathsr   useMultiprocessingstoreOnDiskverboser%   jobsaccumulatedResultsaccumulatedErrorsmetadataBundleModificationTimemessagecurrentJobNumberskippedJobsCountpathr   pathModificationTimer"   jobcurrentIterationjobProcessorresultr   s                          r   addFromPathszMetadataBundle.addFromPaths  s   > 	%==$)=)=)?-1]]-?-?-A-J-J*-1YY[*67U6VWd?g&##G,D&&t,Cd+++'+yy{';';$'*HH$)$!J!#
$$X.'^
""55*!1%	 6 C KK+ , -..HId?g&##G,#++88IIL#++88GGL"4(F&&33;;D	'z"%&	G $!!'*''0!%%f->&?@$$VH%56!'(9!:BO%%m&>&>? "; 2%*t0C

% )& 	$JJL  r   c                8    | j                   j                          y)ai  
        Clear all keys in a metadata bundle:

        >>> #_DOCS_SHOW coreBundle = corpus.corpora.CoreCorpus().metadataBundle
        >>> coreBundle = metadata.bundles.demo_bundle('core')  #_DOCS_HIDE
        >>> bachBundle = coreBundle.search('bach', 'composer')
        >>> bachBundle
        <music21.metadata.bundles.MetadataBundle {363 entries}>

        >>> bachBundle.clear()
        >>> bachBundle
        <music21.metadata.bundles.MetadataBundle {0 entries}>

        Returns None.

        OMIT_FROM_DOCS

        Do not use the cached bach on this -- the .clear() manipulates the metadata bundle.
        N)rL   clearr&   s    r   r   zMetadataBundle.clear2  s    ( 	##%r   c                0   t        | t        j                        r`	 | j                  t	        j
                         dz        } | j                  }|d   dk(  rt        |      dkD  r|dd }dj                  |      }nqd| v r| j                  d      d   }n| }|j                  t        j                        r|dd }|j                  dd      }|j                  t        j                  d      }|j                  dd      }|| d| S |S # t        $ r Y w xY w)	aB  
        Given a file path or corpus path, return the metadata key:

        >>> mb = metadata.bundles.MetadataBundle()
        >>> key = mb.corpusPathToKey('bach/bwv1007/prelude')
        >>> key.endswith('bach_bwv1007_prelude')
        True

        >>> key = mb.corpusPathToKey('corelli/opus3no1/1grave.xml')
        >>> key.endswith('corelli_opus3no1_1grave_xml')
        True

        Numbers are appended if given

        >>> key = mb.corpusPathToKey('corelli/opus3no1/1grave.xml', number=3)
        >>> key.endswith('corelli_opus3no1_1grave_xml_3')
        True
        r0   r   /ru   N_.)rM   rA   rB   relative_tor   getSourceFilePath
ValueErrorpartsrn   joinsplitr   ossepreplace)r   r    r   r*   s       r   r=   zMetadataBundle.corpusPathToKeyH  s   ( h-#//0H0H0JX0UV NNEQx33u:>ab	%J8#%^^H5b9
%
$$RVV,'^
#++C5J#++BFFC8J''S1
  \6(++3  s   &D	 		DDc                    | j                   6| j                   j                         r| j                   j                          yyy)z
        Delete the filesystem cache of a named metadata bundle.

        Does not delete the in-memory metadata bundle.

        Return None.
        N)r   r   unlinkr&   s    r   deletezMetadataBundle.deletez  s8     ==$}}##%$$& & %r   c                &    | j                  |d      S )ag  
        Compute the set-wise difference of two metadata bundles:

        >>> #_DOCS_SHOW coreBundle = corpus.corpora.CoreCorpus().metadataBundle
        >>> coreBundle = metadata.bundles.demo_bundle('core')  #_DOCS_HIDE
        >>> #_DOCS_SHOW bachBundle = coreBundle.search('bach', 'composer')
        >>> bachBundle = metadata.bundles.demo_bundle('bach')  #_DOCS_HIDE
        >>> bachBundle
        <music21.metadata.bundles.MetadataBundle {363 entries}>

        >>> #_DOCS_SHOW tripleMeterBundle = coreBundle.search('3/4')
        >>> tripleMeterBundle = metadata.bundles.demo_bundle('3/4')  #_DOCS_HIDE
        >>> tripleMeterBundle
        <music21.metadata.bundles.MetadataBundle {1875 entries}>

        >>> bachBundle.difference(tripleMeterBundle)
        <music21.metadata.bundles.MetadataBundle {323 entries}>

        Returns a new metadata bundle.
        
differencerW   rY   s     r   r   zMetadataBundle.difference  s    * ((
 	
r   c                &    | j                  |d      S )ai  
        Compute the set-wise intersection of two metadata bundles:

        >>> #_DOCS_SHOW coreBundle = corpus.corpora.CoreCorpus().metadataBundle
        >>> coreBundle = metadata.bundles.demo_bundle('core')  #_DOCS_HIDE
        >>> #_DOCS_SHOW bachBundle = coreBundle.search('bach', 'composer')
        >>> bachBundle = metadata.bundles.demo_bundle('bach')  #_DOCS_HIDE
        >>> bachBundle
        <music21.metadata.bundles.MetadataBundle {363 entries}>

        >>> #_DOCS_SHOW tripleMeterBundle = coreBundle.search('3/4')
        >>> tripleMeterBundle = metadata.bundles.demo_bundle('3/4')  #_DOCS_HIDE
        >>> tripleMeterBundle
        <music21.metadata.bundles.MetadataBundle {1875 entries}>

        >>> bachBundle.intersection(tripleMeterBundle)
        <music21.metadata.bundles.MetadataBundle {40 entries}>

        Returns a new MetadataBundle.
        intersectionrW   rY   s     r   r   zMetadataBundle.intersection  s    * ((
 	
r   c                &    | j                  |d      S )a  
        True if the set of keys in one metadata bundle are disjoint with
        the set of keys in another:

        >>> #_DOCS_SHOW coreBundle = corpus.corpora.CoreCorpus().metadataBundle
        >>> coreBundle = metadata.bundles.demo_bundle('core')  #_DOCS_HIDE
        >>> #_DOCS_SHOW bachBundle = coreBundle.search('bach', 'composer')
        >>> bachBundle = metadata.bundles.demo_bundle('bach')  #_DOCS_HIDE
        >>> bachBundle
        <music21.metadata.bundles.MetadataBundle {363 entries}>

        >>> #_DOCS_SHOW corelliBundle = coreBundle.search('corelli', 'composer')
        >>> corelliBundle = metadata.bundles.demo_bundle('corelli')  #_DOCS_HIDE
        >>> corelliBundle
        <music21.metadata.bundles.MetadataBundle {1 entry}>

        >>> bachBundle.isdisjoint(corelliBundle)
        True

        >>> #_DOCS_SHOW tripleMeterBundle = coreBundle.search('3/4')
        >>> tripleMeterBundle = metadata.bundles.demo_bundle('3/4')  #_DOCS_HIDE
        >>> tripleMeterBundle
        <music21.metadata.bundles.MetadataBundle {1875 entries}>

        >>> bachBundle.isdisjoint(tripleMeterBundle)
        False

        Returns boolean.
        
isdisjointra   rY   s     r   r   zMetadataBundle.isdisjoint  s    < ((FFr   c                &    | j                  |d      S )a:  
        True if the set of keys in one metadata bundle are a subset of
        the keys in another:

        >>> #_DOCS_SHOW coreBundle = corpus.corpora.CoreCorpus().metadataBundle
        >>> coreBundle = metadata.bundles.demo_bundle('core')  #_DOCS_HIDE
        >>> #_DOCS_SHOW bachBundle = coreBundle.search('bach', 'composer')
        >>> bachBundle = metadata.bundles.demo_bundle('bach')  #_DOCS_HIDE
        >>> bachBundle
        <music21.metadata.bundles.MetadataBundle {363 entries}>

        >>> tripleMeterBachBundle = bachBundle.search('3/4')
        >>> tripleMeterBachBundle
        <music21.metadata.bundles.MetadataBundle {40 entries}>

        >>> tripleMeterBachBundle.issubset(bachBundle)
        True

        >>> bachBundle.issubset(tripleMeterBachBundle)
        False

        Returns boolean.
        issubsetra   rY   s     r   r   zMetadataBundle.issubset  s    0 ((DDr   c                &    | j                  |d      S )a@  
        True if the set of keys in one metadata bundle are a superset of
        the keys in another:

        >>> #_DOCS_SHOW coreBundle = corpus.corpora.CoreCorpus().metadataBundle
        >>> coreBundle = metadata.bundles.demo_bundle('core')  #_DOCS_HIDE
        >>> #_DOCS_SHOW bachBundle = coreBundle.search('bach', 'composer')
        >>> bachBundle = metadata.bundles.demo_bundle('bach')  #_DOCS_HIDE
        >>> bachBundle
        <music21.metadata.bundles.MetadataBundle {363 entries}>

        >>> tripleMeterBachBundle = bachBundle.search('3/4')
        >>> tripleMeterBachBundle
        <music21.metadata.bundles.MetadataBundle {40 entries}>

        >>> tripleMeterBachBundle.issuperset(bachBundle)
        False

        >>> bachBundle.issuperset(tripleMeterBachBundle)
        True

        Returns boolean.
        
issupersetra   rY   s     r   r   zMetadataBundle.issuperset  s    0 ((FFr   c                     ddl m}  ddl m} t        t	        | j
                  | j                  z   t        |j                        z               S )a  
        List all available search field names:

        >>> for field in metadata.bundles.MetadataBundle.listSearchFields():
        ...     field
        ...
        'abstract'
        'accessRights'
        'accompanyingMaterialWriter'
        ...
        'composer'
        'composerAlias'
        'composerCorporate'
        'conceptor'
        'conductor'
        ...
        'dateCreated'
        'dateFirstPublished'
        'dateIssued'
        'dateModified'
        'dateSubmitted'
        'dateValid'
        ...
        'tempoFirst'
        'tempos'
        'textLanguage'
        'textOriginalLanguage'
        'timeSignatureFirst'
        'timeSignatures'
        'title'
        ...
        r   )
properties)RichMetadata)	music21.metadatar   r   tupler   ALL_UNIQUE_NAMESALL_MUSIC21_WORK_IDSre    additionalRichMetadataAttributes)r   r   s     r   listSearchFieldszMetadataBundle.listSearchFields  sJ    D 	01V''--.<@@AB
  	r   c           	     B   t        j                         }|j                          || j                  }|!| j                  t        j                  d      t        |t        j                        st        j                  |      }|j                         s2t        j                  d| j                  d| j                  d       | S t        |      }|j                  | _        t        j                  d| j                   |       dt        | j                        g       | S )a  
        Load cached metadata from the file path suggested by the name of this
        MetadataBundle ('core', 'local', or a name).

        If a specific filepath is given with the `filePath` keyword, attempt to
        load cached metadata from the file at that location.

        If `filePath` is None, and `self.filePath` is also None, do nothing.

        >>> #_DOCS_SHOW coreBundle = metadata.bundles.MetadataBundle('core').read()

        If a metadata is unnamed, and no file path is specified, an exception
        will be thrown:

        >>> anonymousBundle = metadata.bundles.MetadataBundle().read()
        Traceback (most recent call last):
        music21.exceptions21.MetadataException: Unnamed MetadataBundles have
            no default file path to read from.

        z?Unnamed MetadataBundles have no default file path to read from.zno metadata found for: z/; try building cache with corpus.cacheMetadata()zMetadataBundle: loading time:z	md items:)r   Timerstartr   rR   r   MetadataExceptionrM   rA   rB   r   r   r   r	   rL   rn   )r   r   timernewMdbs       r   readzMetadataBundle.read8  s    * }}H		 100  (GLL1||H-H ##)$)) 7@@D		}AO K) & 7 7+IIG%%&!
 	 r   r   )fileExtensionsc               D   ddl m} t        |j                  |            }t	               }|"| |st        d      |j                         \  }}| j                  j                         D ]c  \  }}	|	j                  |	j                  }
|r|
j                  |vr0||j                  v r?|	j                  ||      d   sU|	|j                  |<   e t        t        t        |j                  j                               d             |_        |r |j                  di |S |S )a  
        Perform search, on all stored metadata, permit regular expression
        matching.

        >>> workList = corpus.corpora.CoreCorpus().getWorkList('ciconia')
        >>> metadataBundle = metadata.bundles.MetadataBundle()
        >>> failedPaths = metadataBundle.addFromPaths(
        ...     workList,
        ...     parseUsingCorpus=False,
        ...     useMultiprocessing=False,
        ...     storeOnDisk=False, #_DOCS_HIDE
        ...     )
        >>> failedPaths
        []

        >>> searchResult = metadataBundle.search(
        ...     'cicon',
        ...     field='composer'
        ...     )
        >>> searchResult
        <music21.metadata.bundles.MetadataBundle {1 entry}>
        >>> len(searchResult)
        1
        >>> searchResult[0]
        <music21.metadata.bundles.MetadataEntry 'ciconia_quod_jactatur_xml'>
        >>> searchResult = metadataBundle.search(
        ...     'cicon',
        ...     field='composer',
        ...     fileExtensions=('.krn',),
        ...     )
        >>> len(searchResult)  # no files in this format
        0

        >>> searchResult = metadataBundle.search(
        ...     'cicon',
        ...     field='composer',
        ...     fileExtensions=('.xml',),
        ...     )
        >>> len(searchResult)
        1

        Searches can also use keyword args:

        >>> metadataBundle.search(composer='cicon')
        <music21.metadata.bundles.MetadataBundle {1 entry}>
        r   )rO   zQuery cannot be emptyc                     | d   j                   S r   r   r   s    r   r   z'MetadataBundle.search.<locals>.<lambda>  s    3q6#4#4r   r   r   )music21.corpus.corporarO   r   translateExtensionsr   r   popitemrL   r   r%   r   suffixr8   r   r   re   )r   r9   r:   r   r;   rO   acceptable_extensionsnewMetadataBundler   r   sps              r   r8   zMetadataBundle.searchk  s(   p 	2*-f.H.H.X*Y*,=U]-.EFF#++-LE5"&"7"7"="="?C%%-))B$:O)O'888##E51!4:G!2237 #@ .94)::@@BC46.7* +$++7h77  r   c                &    | j                  |d      S )ay  
        Compute the set-wise symmetric difference of two metadata bundles:

        >>> #_DOCS_SHOW coreBundle = corpus.corpora.CoreCorpus().metadataBundle
        >>> coreBundle = metadata.bundles.demo_bundle('core')  #_DOCS_HIDE
        >>> #_DOCS_SHOW bachBundle = coreBundle.search('bach', 'composer')
        >>> bachBundle = metadata.bundles.demo_bundle('bach')  #_DOCS_HIDE
        >>> bachBundle
        <music21.metadata.bundles.MetadataBundle {363 entries}>
        >>> #_DOCS_SHOW tripleMeterBundle = coreBundle.search('3/4')
        >>> tripleMeterBundle = metadata.bundles.demo_bundle('3/4')  #_DOCS_HIDE
        >>> tripleMeterBundle
        <music21.metadata.bundles.MetadataBundle {1875 entries}>
        >>> bachBundle.symmetric_difference(tripleMeterBundle)
        <music21.metadata.bundles.MetadataBundle {2158 entries}>

        Returns a new MetadataBundle.
        symmetric_differencerW   rY   s     r   r	  z#MetadataBundle.symmetric_difference  s    & (("
 	
r   c                &    | j                  |d      S )aA  
        Compute the set-wise union of two metadata bundles:

        >>> #_DOCS_SHOW coreBundle = corpus.corpora.CoreCorpus().metadataBundle
        >>> coreBundle = metadata.bundles.demo_bundle('core')  #_DOCS_HIDE
        >>> #_DOCS_SHOW bachBundle = coreBundle.search('bach', 'composer')
        >>> bachBundle = metadata.bundles.demo_bundle('bach')  #_DOCS_HIDE
        >>> bachBundle
        <music21.metadata.bundles.MetadataBundle {363 entries}>
        >>> beethovenBundle = coreBundle.search(
        ...     'beethoven',
        ...     field='composer',
        ...     )
        >>> beethovenBundle
        <music21.metadata.bundles.MetadataBundle {23 entries}>

        >>> bachBundle.union(beethovenBundle)
        <music21.metadata.bundles.MetadataBundle {386 entries}>

        Returns a new MetadataBundle.
        unionrW   rY   s     r   r  zMetadataBundle.union  s    , ((
 	
r   c                   t        j                         }|j                          t        j	                  dg       g }t               }| j                  j                         D ]  \  }}|j                  }||v rt        |t              r-|j                  d      r|j                  |j                         Tt        |t              rt        j                  |      }|j                         st        j                          |z  }|j#                         s|j%                  |       |j                  |j                          |D ]  }| j                  |=  d| d}t        j	                  |       t'        |      S )z
        Validate each metadata entry in a metadata bundle.

        If the entry represents a non-virtual corpus asset, test that its
        source path is locatable on disk.  If not, remove the metadata entry
        from the metadata bundle.
        zMetadataBundle: validating...zhttp:z'MetadataBundle: finished validating in z	 seconds.)r   r   r   r   r   r   rL   r   r   rM   r   r   addrA   rB   is_absolutegetCorpusFilePathr   r   rn   )r   r   invalidatedKeysvalidatedPathsr   r   r   r   s           r   r   zMetadataBundle.validate  sA    !@ AB"&"7"7"="="?C '11J^+*c*z/D/DW/M""=#;#;<J,$\\*5
))+#557*D
$$&&&s+}778' #@( #C%%c* #;E7)L(?##r   c                ^   |xs | j                   }| j                   | j                   }t        j                  d|g       | j                  }d| _        t	        j
                  | d      }t        j                  |d      5 }|j                  |       ddd       || _        | S # 1 sw Y   xY w)a  
        Write the metadata bundle to disk as a pickle file.

        If `filePath` is None, use `self.filePath`.

        Returns the metadata bundle.

        >>> #_DOCS_SHOW bachBundle = coreBundle.search('bach', 'composer')
        >>> bachBundle = metadata.bundles.demo_bundle('bach')  #_DOCS_HIDE
        >>> bachBundle
        <music21.metadata.bundles.MetadataBundle {363 entries}>
        >>> bachBundle.filePath is None
        True

        >>> import os
        >>> e = environment.Environment()
        >>> tempFilePath = e.getTempFile()
        >>> bachBundle.write(filePath=tempFilePath)
        <music21.metadata.bundles.MetadataBundle {363 entries}>
        >>> os.remove(tempFilePath)
        NzMetadataBundle: writing:   )protocolwb)	r   r   r   rQ   pickledumpsgzipopenr   )r   r   storedCorpusClientuncompressedoutFps        r   r   zMetadataBundle.write  s    , ,t}}==$}}H##%?$JK!%DL "<<q9L 8T*eL) +-DL	 +*s    B##B,r   )rT   z,'music21.corpus.corpora.Corpus' | str | None)rZ   r   )rZ   r   r   r   )returnzpathlib.Path | None)FTTF)r   rE   r    rF   )r  NonerG   )r9   z
str | Noner   zIterable[str]))r   r   r   rH   r#   rV   r^   r`   rh   rj   rl   ro   rq   rs   r+   ry   r{   rX   rb   rI   r0   setterr   rR   r   r   staticmethodr=   r   r   r   r   r   r   r   r   r8   r	  r  r   r   r   r   r   r   r      s`   cN&
06 CD7 CD CD*CB
0
6
6*7 + +. ]]5 5 " "H  8 h!T&, / /b
'
4
4G@E4G4 ' 'R1j W!
 )+W!W!
 &W!r
0
6%$N/r   r   zdict[str, MetadataBundle]_test_bundlesc                   | t         v r	t         |    S | dk(  r'ddlm}  |       j                  t         d<   t         d   S | dk(  r&t	        d      j                  dd      }|t         d<   |S | dk(  r't	        d      j                  dd      }|t         d<   |S | dk(  r%t	        d      j                  d      }|t         d<   |S t        d	|       )
z5
    This helps with testing by reusing bundles.
    r   r   
CoreCorpusbachcomposercorellir:   z3/4zno demo bundle called )r!  r  r$  rZ   demo_bundler8   r   )whichr$  
bachBundlecorelliBundletripleMeterBundles        r   r)  r)  Z  s     U##5 * ; ;fV$$ (//
C
 *f	#F+229J2O#0i ~'/66u=0e  
-eY7
88r   c                      e Zd Zd Zd Zy)Testc                    ddl m}  |       }|j                  }|j                  d      d   }| j	                  t        |      d       y )Nr   r#  zbwv66.6z;<music21.metadata.bundles.MetadataEntry 'bach_bwv66_6_mxl'>)r  r$  rZ   r8   assertEqualr)   )r   r$  cc
coreBundler   s        r   testOneFromCorpuszTest.testOneFromCorpusx  sE    5\&&
")))4Q7m,V	Xr   c                   ddl m}  |       }|j                  d      }t               }|j	                  |ddd      }| j                  |       |j                  dd      }| j                  t        |      d	       | j                  t        |d         d
       |j                  ddd      }| j                  t        |      d       |j                  ddd      }| j                  t        |      d	       y )Nr   r#  ciconiaF)r   r   r   ciconr&  r(  ru   zD<music21.metadata.bundles.MetadataEntry 'ciconia_quod_jactatur_xml'>)z.krn)r:   r   )z.xml)
r  r$  getWorkListr   r   assertFalser8   r1  rn   r)   )r   r$  r2  workListmdbfailedPathssearchResults          r   testFileExtensionszTest.testFileExtensions  s   5\>>),&&"$	 ' 
 	%zz " 
 	\*A.l1o._	azz$ " 

 	\*A.zz$ " 

 	\*A.r   N)r   r   r   r4  r>  r   r   r   r/  r/  v  s    X/r   r/  __main__)r*  r   )(
__future__r   __all__collectionsr   r  r   rA   r  r   typingtunittestr1   r   music21.common.fileToolsr	   r
   r   r   TYPE_CHECKINGcollections.abcr   r   r   Environmentr   Music21Exceptionr   ProtoM21Objectr   r   r!  __annotations__r)  TestCaser/  
_DOC_ORDERr   mainTestr   r   r   <module>rP     s    # $  	       3     ??() '{&&'9:	l;; 	} G** } FVW++ VB% ,.( -98(/8 (/\ 
 zGT r   