
    rh(                    <   S r SSKJr  SSKrSSKJr  SSKrSSKrSSK	r	SSK
Jr  SSKJr  SSK
Jr  \R                  (       a  SSK
Jr  \R"                  " S	5      rS
 r " S S\5      r " S S\	R*                  5      r\/r\S:X  a  SSK
r
\
R2                  " \5        gg)zn
This module defines objects for tracking the derivation of one
:class:`~music21.stream.Stream` from another.
    )annotationsN)	Generator)common)SlottedObjectMixin)environment)base
derivationc                F   ^  [         R                  " T 5      U 4S j5       nU$ )aV  
This decorator can be used for creating a function that returns a new
derivation.  But is currently unused, since it does not take into account `inPlace=True`.
`Stream.cloneEmpty(derivationMethod='derivationMethod')` is preferred for
Streams.

>>> from copy import deepcopy
>>> @derivation.derivationMethod
... def allGreen(n):
...     n2 = deepcopy(n)
...     n2.style.color = 'green'
...     return n2

>>> n = note.Note('C#')
>>> n2 = allGreen(n)
>>> n2.style.color
'green'

>>> n2.name = 'D-'
>>> n2.derivation
<Derivation of <music21.note.Note D-> from <music21.note.Note C#> via 'allGreen'>
c                v   > T" U /UQ70 UD6nXR                   l        TR                  UR                   l        U$ N)r	   origin__name__method)self	argumentskeywordsresultfunctions       L/home/james-whalen/.local/lib/python3.13/site-packages/music21/derivation.pywrapper!derivationMethod.<locals>.wrapper<   s<    $77h7#' #+#4#4     )	functoolswraps)r   r   s   ` r   derivationMethodr   %   s'    . __X 
 Nr   c                  ,   \ rS rSrSrSrSSS jjrSS jrS rS r	S	 r
\SS
 j5       r\R                  SS j5       rSS jr\SS j5       r\R                  SS j5       r\SS j5       r\R                  SS j5       r\SS j5       r\SS j5       rSrg)
DerivationE   a  
A Derivation object keeps track of which Streams (or perhaps other Music21Objects)
a Stream or other music21 object has come from and how.

Derivation is automatically updated by many methods:

>>> import copy
>>> sOrig = stream.Stream(id='orig')
>>> sNew = copy.deepcopy(sOrig)
>>> sNew.id = 'copy'
>>> sNew.derivation
<Derivation of <music21.stream.Stream copy>
    from <music21.stream.Stream orig> via '__deepcopy__'>

>>> sNew.derivation.client
<music21.stream.Stream copy>
>>> sNew.derivation.client is sNew
True
>>> sNew.derivation.origin
<music21.stream.Stream orig>
>>> sNew.derivation.method
'__deepcopy__'


>>> s1 = stream.Stream()
>>> s1.id = 'DerivedStream'
>>> d1 = derivation.Derivation(s1)

>>> s2 = stream.Stream()
>>> s2.id = 'OriginalStream'

>>> d1.method = 'manual'
>>> d1.origin = s2
>>> d1
<Derivation of <music21.stream.Stream DerivedStream> from
    <music21.stream.Stream OriginalStream> via 'manual'>
>>> d1.origin is s2
True

>>> d1.client is s1
True

>>> import copy
>>> d2 = copy.deepcopy(d1)
>>> d2.origin is s2
True

>>> d1.method = 'measure'
>>> d1.method
'measure'

Deleting the origin stream does not change the Derivation, since origin is held by strong ref:

>>> import gc  # Garbage collection
>>> del s2
>>> unused = gc.collect()  # ensure Garbage collection is run
>>> d1
<Derivation of <music21.stream.Stream DerivedStream>
    from <music21.stream.Stream OriginalStream> via 'measure'>

But deleting the client stream changes the Derivation, since client is held by weak ref,
and will also delete the origin (so long as client was ever set)

>>> del s1
>>> unused = gc.collect()  # ensure Garbage collection is run
>>> d1
<Derivation of None from None via 'measure'>
)_client	_clientId_method_origin	_originIdNc                V    S U l         S U l        S U l        S U l        S U l        Xl        g r   r   r    r!   r"   r#   clientr   r&   s     r   __init__Derivation.__init__   s,    37#'!%04#' r   c                j    [        U 5      " 5       nU R                  Ul        U R                  Ul        U$ )z
Manage deepcopying by creating a new reference to the same object. If
the origin no longer exists, than origin is set to None
)typer&   r   )r   memonews      r   __deepcopy__Derivation.__deepcopy__   s*    
 4jl[[
[[

r   c                    U R                   R                  nU R                  (       a  SU R                  < 3OSnSU SU R                   SU R                   U S3$ )z"
representation of the Derivation
z via  <z of z from >)	__class__r   r   r&   r   )r   klassvias      r   __repr__Derivation.__repr__   sR     '')-dkk_%"5'dkk]&cU!DDr   c                x    [         R                  " U R                  5      U l        [        R                  " U 5      $ r   )r   unwrapWeakrefr   r   __getstate__r   s    r   r;   Derivation.__getstate__   s)    ++DLL9!..t44r   c                z    [         R                  " X5        [        R                  " U R                  5      U l        g r   )r   __setstate__r   wrapWeakrefr   )r   states     r   r?   Derivation.__setstate__   s&    ''4))$,,7r   c                    [         R                  " U R                  5      nUc)  U R                  b  S U l        S U l        S U l        S U l        U$ r   )r   r:   r   r    r"   r#   )r   cs     r   r&   Derivation.client   sE      .93!DNDLDL!DNr   c                ~    Uc  S U l         S U l        g [        U5      U l         [        R                  " U5      U l        g r   )r    r   idr   r@   r'   s     r   r&   rE      s4     >!DNDLZDN!--f5DLr   c              #  j   #    U R                   nUb   Uv   UR                  R                   nUb  M  gg7f)a  
Iterator/Generator

Yields the Streams which this Derivation's client Stream was derived
from. This provides a way to obtain all Streams that the client passed
through, such as those created by
:meth:`~music21.stream.Stream.getElementsByClass` or
:meth:`~music21.stream.Stream.flatten`.

>>> s1 = stream.Stream()
>>> s1.id = 's1'
>>> s1.repeatAppend(note.Note(), 10)
>>> s1.repeatAppend(note.Rest(), 10)
>>> s2 = s1.notesAndRests.stream()
>>> s2.id = 's2'
>>> s3 = s2.getElementsByClass(note.Note).stream()
>>> s3.id = 's3'
>>> for y in s3.derivation.chain():
...     print(y)
<music21.stream.Stream s2>
<music21.stream.Stream s1>

>>> list(s3.derivation.chain()) == [s2, s1]
True
N)r   r	   )r   origs     r   chainDerivation.chain   s2     4 +/++J??))D s   -33c                    U R                   $ )a  
Returns or sets the string of the method that was used to generate this
Stream.

>>> s = stream.Stream()
>>> s.derivation.method is None
True

>>> sNotes = s.notes.stream()
>>> sNotes.derivation.method
'notes'

Some examples are 'getElementsByClass' etc.

>>> s = stream.Stream()
>>> s.id = 'lonelyStream'
>>> s.append(clef.TrebleClef())
>>> s.append(note.Note())
>>> sNotes = s.notes.stream()
>>> sNotes.derivation
<Derivation of <music21.stream.Stream lonelyStream>
    from <music21.stream.Stream lonelyStream> via 'notes'>

>>> derived = sNotes.derivation
>>> derived.method
'notes'

>>> derived.method = 'blah'
>>> derived.method
'blah'

>>> derived is sNotes.derivation
True
>>> sNotes.derivation.method
'blah'
r!   r<   s    r   r   Derivation.method   s    L ||r   c                    Xl         g r   rM   )r   r   s     r   r   rN     s    r   c                    U R                   $ r   )r"   r<   s    r   r   Derivation.origin#  s    ||r   c                T    Uc  S U l         S U l        g [        U5      U l         Xl        g r   )r#   r"   rG   )r   r   s     r   r   rQ   '  s'     >!DNDLZDN!Lr   c                    U R                   $ )z
Return the Python id (=memory location) of the origin.
(Same as id(derivation.origin).  Not the same as derivation.origin.ind)
)r#   r<   s    r   originIdDerivation.originId2  s     ~~r   c                N    [        U R                  5       5      nU(       a  US   $ g)a  
Return a reference to the oldest source of this Stream; that is, chain
calls to :attr:`~music21.stream.Stream.derivesFrom` until we get to a
Stream that cannot be further derived.

>>> s1 = stream.Stream()
>>> s1.repeatAppend(note.Note(), 10)
>>> s1.repeatAppend(note.Rest(), 10)
>>> s2 = s1.notesAndRests.stream()
>>> s3 = s2.getElementsByClass(note.Note).stream()
>>> s3.derivation.rootDerivation is s1
True
N)listrJ   )r   derivationChains     r   rootDerivationDerivation.rootDerivation:  s%     tzz|,"2&&r   r%   r   )r&   base.Music21Object | None)returnr\   )r]   z)Generator[base.Music21Object, None, None])r]   
str | None)r   r^   )r   r\   )r]   z
int | None)r   
__module____qualname____firstlineno____doc__	__slots__r(   r.   r7   r;   r?   propertyr&   setterrJ   r   r   rT   rZ   __static_attributes__ r   r   r   r   E   s    CNI
E5
8   ]]6 6*> % %N ]]    ]]" "    r   r   c                      \ rS rSrSrg)TestiR  rg   N)r   r_   r`   ra   rf   rg   r   r   ri   ri   R  s    r   ri   __main__)rb   
__future__r   weakrefcollections.abcr   r   typingtunittestmusic21r   music21.common.objectsr   r   TYPE_CHECKINGr   EnvironmentenvironLocalr   r   TestCaseri   
_DOC_ORDERr   mainTestrg   r   r   <module>ry      s    #  %     5  ?? &&|4@H# HZ	8 	 \
zT r   