
    rh.#                    l   S SK Jr  S SKJrJr  S SKrS SKr\R                  (       a  S SK	J
r
  / SQr\R                  " S5      rSS jrSS jrSS	 jrSS
 jrSS jrSS jrSS jr\" 5       r\R.                  \4SS jj5       r\R.                  SS j5       r\S:X  a  S SKr\R8                  " 5         gg)    )annotations)Iterable
CollectionN)Fraction)		holdsTypeisNumisInt
isListLike
isIterableclassToClassStrgetClassSettempAttributesaveAttributes_Tc                N    [        U [        5      =(       a    U SL=(       a    U SL$ )z
Check if usrData is an integer and not True or False.

>>> common.isInt(3)
True
>>> common.isInt(False)
False
>>> common.isInt(2.0)
False
TF)
isinstanceintusrDatas    S/home/james-whalen/.local/lib/python3.13/site-packages/music21/common/classTools.pyr	   r	       s%     gs#Tt(;Tu@TT    c                F     U S-   nU SLa  U SLa  gg! [          a     gf = f)a.  
check if usrData is a music21 number (float, int, Fraction),
return boolean and if True casts the value as a Rational number

Differs from `isinstance(usrData, Rational)` which
does not return True for `True, False`, and does not support Decimal

Does not use `isinstance(usrData, Rational)` which is 2-6 times slower
than calling this function (except in the case of Fraction, when
it's 6 times faster, but that's rarer).  (6 times slower on Py3.4, now
only 2x slower in Python 3.10)

Runs by adding 0 to the "number" -- so anything that implements
add to a scalar works

>>> common.isNum(3.0)
True
>>> common.isNum(3)
True
>>> common.isNum('three')
False
>>> common.isNum([2, 3, 4])
False

True and False are NOT numbers:

>>> common.isNum(True)
False
>>> common.isNum(False)
False
>>> common.isNum(None)
False
r   TF)	Exception)r   dummys     r   r   r   .   s8    F!$7%#7 s    
  c                .    [        U [        [        45      $ )a5  
Returns True if is a List or Tuple or their subclasses.

Formerly allowed for set here, but that does not allow for
subscripting (`set([1, 2, 3])[0]` is undefined).

Differs from isinstance(collections.abc.Sequence()) in that
we do not want Streams included even if __contains__, __reversed__,
and count are added, and we do not want to include str or bytes.

>>> common.isListLike([])
True
>>> common.isListLike('sharp')
False
>>> common.isListLike((None, None))
True
>>> common.isListLike({'a', 'b', 'c', 'c'})
False
>>> common.isListLike(stream.Stream())
False
)r   listtupler   s    r   r
   r
   [   s    , ge}--r   c                    [        U [        [        45      (       a  g[        U S5      (       a  U R                  [
        L a  ggg)a  
Returns True if is the object can be iter'd over
and is NOT a string.  Marks it as an Iterable for type checking.

>>> common.isIterable([5, 10])
True
>>> common.isIterable('sharp')
False
>>> common.isIterable((None, None))
True
>>> common.isIterable(stream.Stream())
True

Ranges are not iterators by python 3, but return True

>>> common.isIterable(range(20))
True

Classes are not iterable even if their instances are:

>>> common.isIterable(stream.Stream)
False

* Changed in v7.3: Classes (not instances) are not iterable
F__iter__T)r   strbyteshasattr	__class__typer   s    r   r   r   t   s<    4 'C<((w
##$r   c                    [        U 5      (       d  g [        [        U 5      5      n[        X!5      $ ! [         a     gf = f)a  
Returns True if usrData is a Collection of type checkType.

This reads an item from usrData, so don't use it on something
where iterating destroys the type.

>>> y = [1, 2, 3]
>>> common.classTools.holdsType(y, int)
True
>>> common.classTools.holdsType(5, int)
False
>>> common.classTools.holdsType(['hello'], str)
True

Empty iterators hold the type:

>>> common.classTools.holdsType([], float)
True

Note that a mixed collection holds whatever is first

>>> common.classTools.holdsType((4, 'hello'), int)
True
>>> common.classTools.holdsType((4, 'hello'), str)
False

Works on sets with arbitrary order:

>>> common.classTools.holdsType({2, 10}, int)
True

Intelligent collections will not have their position affected.

>>> m = stream.Measure([note.Note('C'), note.Rest()])
>>> common.classTools.holdsType(m, note.GeneralNote)
True
>>> next(iter(m))
<music21.note.Note C>

>>> r = range(1, 100)
>>> common.classTools.holdsType(r, int)
True
>>> next(iter(r))
1

* New in v9.
FT)r   nextiterr   StopIteration)r   	checkTypefirsts      r   r   r      sC    ` gT']#%++ s   2 
??c                @    [        U 5      R                  SSS9S   SS $ )z
Convert a class object to a class string.

>>> common.classToClassStr(note.Note)
'Note'
>>> common.classToClassStr(chord.Chord)
'Chord'
.   )maxsplitN)r    rsplit)classObjs    r   r   r      s*     x=a04Sb99r   c                |   Uc4  U R                   R                  5        Vs/ s H  o"R                  PM     nnO[        U5      nU R                   R                  5       nU R                   R                  5        Vs/ s H  o"R                  S-   UR                  -   PM      nnX4-   U-   n[        U5      nU$ s  snf s  snf )aT  
Return the classSet for an instance (whether a Music21Object or something else).
See base.Music21Object.classSet for more details.

>>> p = pitch.Pitch()
>>> cs = common.classTools.getClassSet(p)
>>> cs
 frozenset(...)
>>> pitch.Pitch in cs
True
>>> 'music21.pitch.Pitch' in cs
True
>>> 'Pitch' in cs
True
>>> object in cs
True
>>> 'object' in cs
True
>>> note.Note in cs
False

To save time (this IS a performance-critical operation), classNameTuple
can be passed a tuple of names such as ('Pitch', 'object') that
will save the creation time of this set.

>>> cs2 = common.classTools.getClassSet(p, classNameTuple=('Pitch', 'ProtoM21Object'))
>>> 'Pitch' in cs2
True

Use base.Music21Object.classSet in general for music21Objects since it
not only caches the result for each object, it caches the result for the
whole class the first time it is run.
r,   )r#   mro__name__r   
__module__	frozenset)instanceclassNameTuplexclassNameListclassObjListclassListFQ	classListclassSets           r   r   r      s    D -5-?-?-C-C-EF-E-EF^,%%))+L<D<N<N<R<R<TU<Tq<<#%

2<TKU,{:I#HO G
 Vs   B49%B9c              #     #    [        X5      nU[        La  [        XU5         Sv   [        XU5        g! [        XU5        f = f7f)a  
Temporarily set an attribute in an object to another value
and then restore it afterwards.

>>> p = pitch.Pitch('C4')
>>> p.midi
60
>>> with common.classTools.tempAttribute(p, 'nameWithOctave', 'D#5'):
...     p.midi
75
>>> p.nameWithOctave
'C4'

Setting to a new value is optional.

For working with multiple attributes see :func:`~music21.classTools.saveAttributes`.

* New in v7.
N)getattrTEMP_ATTRIBUTE_SENTINELsetattr)obj	attributenew_valtempStorages       r   r   r     s@     * #)K--(-,,s   !A5 AAAc              '     #    0 nU H  n[        X5      X#'   M      Sv   UR                  5        H  u  pE[        XU5        M     g! UR                  5        H  u  pE[        XU5        M     f = f7f)a  
Save a number of attributes in an object and then restore them afterwards.

>>> p = pitch.Pitch('C#2')
>>> with common.classTools.saveAttributes(p, 'name', 'accidental'):
...     p.step = 'E'
...     p.accidental = pitch.Accidental('flat')
...     p.nameWithOctave
'E-2'
>>> p.nameWithOctave
'C#2'

For storing and setting a value on a single attribute see
:func:`~music21.classTools.tempAttribute`.

* New in v7.
N)rA   itemsrC   )rD   attributeListrG   rE   kvs         r   r   r   ,  si     & %'K"	!(!8 #%%'DACA (K%%'DACA (s   A0A &A0'A--A0__main__)r   t.Anyreturnzt.TypeGuard[int])r   rN   rO   z*t.TypeGuard[t.Union[float, int, Fraction]])r   rN   rO   zt.TypeGuard[list | tuple])r   rN   rO   zt.TypeGuard[Iterable])r   rN   r)   ztype[_T]rO   zt.TypeGuard[Collection[_T]])r2   r$   rO   r    )N)rE   r    )rJ   r    rO   zt.Generator[None, None, None])
__future__r   collections.abcr   r   
contextlibtypingtTYPE_CHECKING	fractionsr   __all__TypeVarr   r	   r   r
   r   r   r   r   objectrB   contextmanagerr   r   r5   music21mainTest r   r   <module>r^      s    # 0  ??" YYt_U*Z.2 F6t
:+\ !(  /F - -8  > z r   