
    3j7                    N   U d dl mZ g d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
  e
j                  d      Z	 	 	 ddZ G d d	      Z G d
 d      Z G d dej                         Z G d dej$                        Zg Zded<   edk(  rd dlZ ej.                  e       yy)    )annotations)JobProcessorMetadataCachingJobcacheMetadataWorkerProcessN)common)environmentzmetadata.cachingc                   ddl m} |j                  d      }| 
|dd ddgz   } t        j                  |       s| f} t        j
                         }|j                          g }| D ])  }|j                  |      }||j                  |||      z  }+ d| d	}	|du rt        j                  |	       nt        j                  |	       |D ]6  }
d
|
 }	|du rt        j                  |	       "t        j                  |	       8 y)zv
    Cache metadata from corpora in `corpusNames` as local cache files.

    Call as ``metadata.cacheMetadata()``
    r   )managerT)skipNoneNlocalcorezcache: final writing time: z secondszpath failed to parse: )music21.corpusr   listLocalCorporaNamesr   
isIterableTimerstartfromNamer   environLocalwarn
printDebug)corpusNamesuseMultiprocessingverboser   localCorporaNamestimerfailingFilePaths
corpusNamecorpusObjectmessagefailingFilePaths              E/DATA/.local/lib/python3.12/site-packages/music21/metadata/caching.pyr   r       s    '55t5D'*gv-@@[)"nLLNE	KKM  "
''
3L667I7TYZZ " ,E7(;G$'"(+*?*;<d?g&##G, ,    c                  R    e Zd ZdZddZd Zd Zd Zd Zd Z	d	 Z
d
 Zed        Zy)r   a
  
    Parses one corpus path, and attempts to extract metadata from it:

    >>> job = metadata.caching.MetadataCachingJob(
    ...     'bach/bwv66.6',
    ...     parseUsingCorpus=True,
    ...     corpusName='core',
    ...     )
    >>> job.jobNumber
    0
    >>> job.corpusName
    'core'
    >>> job.run()
    ((<music21.metadata.bundles.MetadataEntry 'bach_bwv66_6'>,), ())
    >>> results = job.getResults()
    >>> errors = job.getErrors()

    TODO: error list, not just numbers needs to be reported back up.
    Nc                    t        j                  |      | _        g | _        t	        |      | _        g | _        t        |      | _        || _	        y N)
pathlibPathfilePathfilePathErrorsint	jobNumberresultsboolparseUsingCorpusr   )selfr)   r,   r/   r   s        r"   __init__zMetadataCachingJob.__init__e   sA    X. Y $%5 6$r#   c                J   dd l }g | _        | j                         }t        j	                  d| j
                   d|        |1d|j                  v r| j                  |       n| j                  |       ~|j                          | j                         | j                         fS )Nr   zGot ParsedObject from z: Opus)gcr-   parseFilePathr   r   r)   classes	parseOpusparseNonOpuscollect
getResults	getErrors)r0   r4   parsedObjects      r"   runzMetadataCachingJob.runm   s    ))+$T]]O2l^D	F#---|,!!,/


 $.."222r#   c                   ddl m} ddl m} d }	 | j                  du r|j	                  | j
                  d      }|S |j	                  t        | j
                        d      }	 |S # t        $ r|}t        j                  d| j
                   d|        t        j                  t        j                                | j                  j                  | j
                         Y d }~|S d }~ww xY w)	Nr   )	converter)corpusFT)forceSourcezparse failed: z, )music21r?   r@   r/   parser)   str	Exceptionr   r   	traceback
format_excr*   append)r0   r?   r@   r<   es        r"   r5   z MetadataCachingJob.parseFilePath|   s    %"	6$$-(t}}$O   &||C,>D|Q
 	  	6##nT]]O2aS$IJ##I$8$8$:;&&t}}55		6s   +A& &A& &	C+/A1C&&C+c                   ddl m} 	 |j                  j                  j	                  | j
                        }|j                  |j                         }|j                  |j                         |j                  |       t        j                  d|        |j                  j                  | j
                  || j                        }| j                  j                  |       y t        j                  dt        j                   t#        | j
                                      |j                  j                  | j
                  d | j                        }| j                  j                  |       y # t$        $ rM t        j'                  d| j(                   d       t        j'                  t+        j,                                Y y w xY w)Nr   metadatazupdateMetadataCache: storing: )
sourcePathmetadataPayloadr   z:addFromPaths: got stream without metadata, creating stub: z+Had a problem with extracting metadata for z, piece ignored)rB   rL   bundlesMetadataBundlecorpusPathToKeycleanFilePathRichMetadatamergeupdater   r   MetadataEntryr   r-   rH   r   relativepathrD   rE   r   r)   rF   rG   )r0   r<   rL   
corpusPathrichMetadatametadataEntrys         r"   r8   zMetadataCachingJob.parseNonOpus   s   $	6!))88HH""$J$$0'446""<#8#89##L1''4ZLAC ( 0 0 > >#11$0# !? !
 ##M2''&&,&9&9#d>P>P:Q&R%SU !) 0 0 > >#11$(# !? !
 ##M2 	6}}o_6 i2245	6s   CE1 %BE1 1AGGc           	        ddl m} d}	 t        |j                        D ]  \  }}| j	                  ||       ~ 	 |j                  j                  | j                  d       }| j                  j!                  |       y # t
        $ rY}t        j                  d| d| j                   d|        t        j                  t        j                                Y d }~d }~ww xY w)Nr   rK   1Had a problem with extracting metadata for score  in , whole opus ignored: )rM   rN   )rB   rL   	enumeratescoresparseScoreInsideOpusrE   r   r   r)   r   rF   rG   rO   rV   rR   r-   rH   )r0   r<   rL   scoreNumberscore	exceptionrZ   s          r"   r7   zMetadataCachingJob.parseOpus   s    $ 
	<&/0C0C&D"U))%= 'E !((66))  7 
 	M*  	<C-tDMM?2H+
 ##I$8$8$:;;	<s   0A> >	C ACC c           	     X   ddl m} 	 |j                         }|j                  |j                         |j	                  |       |j                  |j                  j
                  ,t        j                  dt        | j                        z          y |j                  j                  j                  | j                  |j                  j
                        }t        j                  d|        |j                  j                  | j                  |j                  j
                  |      }| j                  j!                  |       y # t"        $ rY}t        j%                  d| d| j                   d	|        t        j                  t'        j(                                Y d }~y d }~ww xY w)
Nr   rK   zLaddFromPaths: got Opus that contains Streams that do not have work numbers: )numberzaddFromPaths: storing: )rM   rf   rN   r\   r]   r^   )rB   rL   rS   rT   rU   rf   r   r   rD   r)   rO   rP   rQ   rR   rV   r-   rH   rE   r   rF   rG   )r0   rc   rb   rL   rY   rX   rZ   rd   s           r"   ra   z'MetadataCachingJob.parseScoreInsideOpus   sq    	%	<#002Lu~~.&~~%)>)>)F''@$--() &--<<LL&& >>00 M 
 ''-j\:< ( 0 0 > >#11 >>00$0 !? !
 ##M2 	<CK= Qmm_$:9+G ##I$8$8$:;;	<s    B	E B4E 	F)AF$$F)c                ,    t        | j                        S r&   )tupler*   r0   s    r"   r;   zMetadataCachingJob.getErrors   s    T(())r#   c                ,    t        | j                        S r&   )rh   r-   ri   s    r"   r:   zMetadataCachingJob.getResults   s    T\\""r#   c                    t        j                         }	 | j                  j                  |      }|S # t        $ r | j                  }Y |S w xY wr&   )r   getCorpusFilePathr)   relative_to
ValueError)r0   rX   rR   s      r"   rR   z MetadataCachingJob.cleanFilePath   sQ    --/
	* MM55jAM   	* MMM	*s   3 AA)r   TN)__name__
__module____qualname____doc__r1   r=   r5   r8   r7   ra   r;   r:   propertyrR    r#   r"   r   r   O   sE    *%3 !6F+4#<N*#
  r#   r   c                  D    e Zd ZdZed        Zedd       Zedd       Zy)r   a2  
    Processes metadata-caching jobs, either serially (e.g. single-threaded) or
    in parallel, as a generator.

    Yields a dictionary of:

    * MetadataEntry instances
    * failed file paths
    * the last processed file path
    * the number of remaining jobs

    >>> jobs = []
    >>> mdb = corpus.corpora.CoreCorpus().search('monteverdi')[:3]
    >>> paths = [x.sourcePath for x in mdb]

    >>> for corpusPath in paths:
    ...     job = metadata.caching.MetadataCachingJob(
    ...         corpusPath,
    ...         parseUsingCorpus=True,
    ...         corpusName='core',
    ...         )
    ...     jobs.append(job)
    >>> jobGenerator = metadata.caching.JobProcessor.process_serial(jobs)
    >>> for result in jobGenerator:
    ...     print(result['remainingJobs'])
    ...
    2
    1
    0
    c                ,    | |z
  }d| d|  d| d| }|S )z3
        Report on the current job status.
        zupdated z of z files; total errors: z ... last file: rt   )	totalJobsremainingJobsr)   filePathErrorCountcompletedJobsr    s         r"   _reportzJobProcessor._report'  sA    
 "M1}oT) 5/0 1"% 	
 r#   Nc              #    K   |xs t        j                         }t        |d      }t        |       }t	        ||      }t
        j                  d| d| d       g }t        j                         }t        j                         }t        |      D cg c]  }t        ||       }}|D ]  }|j                           | r| D ]&  }	|j                  t        j                  |	             ( t        t        |             D ]]  }
t        j                   |j#                               }	|	j%                         }|	j'                         }|dz  }|||	j(                  |d _ |D ]  }|j                  d        |j+                          |j-                          |j-                          |D ]  }|j+                           yc c}w w)a  
        Process jobs in parallel, with `processCount` processes.

        If `processCount` is none, use 1 fewer process than the number of
        available cores.

        jobs is a list of :class:`~music21.metadata.MetadataCachingJob` objects.

           zProcessing z jobs in parallel, with z processes.metadataEntrieserrorsr)   rx   N)r   cpusmaxlenminr   r   multiprocessingJoinableQueueQueueranger   r   putpickledumpsloadsgetr:   r;   r)   joinclose)jobsprocessCountrx   r-   	job_queueresult_queue_workersworkerjobunused_jobCounterr   _workers                r"   process_parallelzJobProcessor.process_parallel6  s     $4v{{}<+D	<7-(@kZ	\#113	&,,.!,/1/q !L9/ 	 1FLLN fll3/0 %*3t9%5!ll<#3#3#56..*"'.$ #%2	  &6 GMM$ FKKM /1s   BGF>$DGc              #     K   t        |       }| D ]-  }|j                         \  }}|dz  }|||j                  |d / yw)z(
        Process jobs serially.
        r}   r~   N)r   r=   r)   )r   rx   r   r-   r   s        r"   process_serialzJobProcessor.process_serialg  sN     
 D	C!ggiOGVQM#* LL!.	  s   ?Ar&   )r   zlist[MetadataCachingJob])ro   rp   rq   rr   staticmethodr{   r   r   rt   r#   r"   r   r     sE    B 
 
 - -`  r#   r   c                  (     e Zd ZdZ fdZd Z xZS )r   z[
    A worker process for use by the multithreaded metadata-caching job
    processor.
    c                >    t         |           || _        || _        y r&   )superr1   r   r   )r0   r   r   	__class__s      r"   r1   zWorkerProcess.__init__  s    "(r#   c                R   	 | j                   j                         }|| j                   j                          y t        j                  |      }|j                          | j                   j                          | j                  j                  t        j                  |d             )Nr   )protocol)	r   r   	task_doner   r   r=   r   r   r   )r0   r   s     r"   r=   zWorkerProcess.run  sz    ..$$&C{((*,,s#CGGINN$$&!!&,,sQ"?@ r#   )ro   rp   rq   rr   r1   r=   __classcell__)r   s   @r"   r   r   |  s    )
Ar#   r   c                      e Zd Zy)TestN)ro   rp   rq   rt   r#   r"   r   r     s    r#   r   z
list[type]
_DOC_ORDER__main__)NTF)
__future__r   __all__r   r'   r   rF   unittestrB   r   r	   Environmentr   r   r   r   Processr   TestCaser   r   __annotations__ro   mainTestrt   r#   r"   <module>r      s    #       &{&&'9: #%))-^p plp pnAO++ A>	8 	
 
J zGT r#   