
    3j(                    0   d Z ddlmZ ddlZddlm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 ej                  rddl
mZ  ej"                  d	      Zd
 Z G d de      Z G d de	j*                        ZegZedk(  rddl
Z
 e
j2                  e       yy)zn
This module defines objects for tracking the derivation of one
:class:`~music21.stream.Stream` from another.
    )annotationsN)	Generator)common)SlottedObjectMixin)environment)base
derivationc                B     t        j                          fd       }|S )a  
    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                x     | g|i |}| |j                   _        j                  |j                   _        |S N)r	   origin__name__method)self	argumentskeywordsresultfunctions       ?/DATA/.local/lib/python3.12/site-packages/music21/derivation.pywrapperz!derivationMethod.<locals>.wrapper;   s>    $77h7#' #+#4#4     )	functoolswraps)r   r   s   ` r   derivationMethodr   $   s'    . __X 
 Nr   c                     e Zd ZdZdZdddZddZd Zd Zd Z	e
dd	       Zej                  dd
       ZddZe
dd       Zej                  dd       Ze
dd       Zej                  dd       Ze
dd       Ze
dd       Zy)
Derivationa  
    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                X    d | _         d | _        d | _        d | _        d | _        || _        y r   )r   r   r   r    r!   clientr   r#   s     r   __init__zDerivation.__init__   s.    37#'!%04#' r   c                j     t        |              }| j                  |_        | j                  |_        |S )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__zDerivation.__deepcopy__   s,    
 d4jl[[
[[

r   c                    | j                   j                  }| j                  rd| j                  nd}d| d| j                   d| j                   | dS )z2
        representation of the Derivation
        z via  <z of z from >)	__class__r   r   r#   r   )r   klassvias      r   __repr__zDerivation.__repr__   sR     '')-dkk_%"5'dkk]&cU!DDr   c                t    t        j                  | j                        | _        t        j                  |       S r   )r   unwrapWeakrefr   r   __getstate__r   s    r   r5   zDerivation.__getstate__   s)    ++DLL9!..t44r   c                x    t        j                  | |       t        j                  | j                        | _        y r   )r   __setstate__r   wrapWeakrefr   )r   states     r   r8   zDerivation.__setstate__   s(    ''e4))$,,7r   c                    t        j                  | j                        }|(| j                  d | _        d | _        d | _        d | _        |S r   )r   r4   r   r   r    r!   )r   cs     r   r#   zDerivation.client   sE      .93!DNDLDL!DNr   c                z    |d | _         d | _        y t        |      | _         t        j                  |      | _        y r   )r   r   idr   r9   r$   s     r   r#   zDerivation.client   s4     >!DNDLZDN!--f5DLr   c              #  d   K   | j                   }|| |j                  j                   }|yyw)aR  
        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   chainzDerivation.chain   s3     4 +/++J??))D s   +00c                    | j                   S )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   r6   s    r   r   zDerivation.method   s    L ||r   c                    || _         y r   rC   )r   r   s     r   r   zDerivation.method  s	    r   c                    | j                   S r   )r    r6   s    r   r   zDerivation.origin!  s    ||r   c                T    |d | _         d | _        y t        |      | _         || _        y r   )r!   r    r>   )r   r   s     r   r   zDerivation.origin%  s)     >!DNDLZDN!DLr   c                    | j                   S )z
        Return the Python id (=memory location) of the origin.
        (Same as id(derivation.origin).  Not the same as derivation.origin.ind)
        )r!   r6   s    r   originIdzDerivation.originId0  s     ~~r   c                D    t        | j                               }|r|d   S y)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)listrA   )r   derivationChains     r   rootDerivationzDerivation.rootDerivation8  s%     tzz|,"2&&r   r   )r#   base.Music21Object | None)returnrN   )rO   z)Generator[base.Music21Object, None, None])rO   
str | None)r   rP   )r   rN   )rO   z
int | None)r   
__module____qualname____doc__	__slots__r%   r*   r2   r5   r8   propertyr#   setterrA   r   r   rH   rM    r   r   r   r   D   s    BLI
E5
8   ]]6 6*> % %N ]]    ]]" "    r   r   c                      e Zd Zy)TestN)r   rQ   rR   rW   r   r   rY   rY   P  s    r   rY   __main__)rS   
__future__r   weakrefcollections.abcr   r   typingtunittestmusic21r   music21.common.objectsr   r   TYPE_CHECKINGr   EnvironmentenvironLocalr   r   TestCaserY   
_DOC_ORDERr   mainTestrW   r   r   <module>ri      s    #  %     5  ?? '{&&|4@G# GX	8 	 \
zGT r   