
    rhr&                    2   S r SSKJr  SSKJrJr  SSKrSSKrSSKrSSK	r	SSK
r
SSKrSSKrSSKrSSKrSSKrSSKJr  / SQr\R(                  (       a  \R*                  " S5      rSS jrSS	.SS
 jjrS rSS jrSS jrSS jrS rSS jr\" SSS5      SS j5       r\ " S5      \ " \!5      \ " \"5      \#\$\%\&\'\(\RR                  \ \*\RV                  \RX                  \RZ                  \.1r/S SS.S!S jjjr0S"S jr1\2S:X  a  SSK3r3\3Rh                  " 5         gg)#zO
If it doesn't fit anywhere else in the common directory, you'll find it here!
    )annotations)CallableIterableN)
deprecated)
flattenListgetMissingImportStrgetPlatformmacOSVersionsortModules	pitchListuniquerunningInNotebookdefaultDeepcopycleanedFlatNotation_Tc                H    U  VVs/ s H  o  H  o"PM     M     snn$ s  snnf )z
Flatten a list of lists into a flat list:

>>> l = [[1, 2, 3], [4, 5], [6]]
>>> common.flattenList(l)
[1, 2, 3, 4, 5, 6]

But not a list of lists-of-lists!

>>> l2 = [[1, 2, 3], [4, 5], [6, [7, 8]]]
>>> common.flattenList(l2)
[1, 2, 3, 4, 5, 6, [7, 8]]
 )originalListsublistitems      M/home/james-whalen/.local/lib/python3.13/site-packages/music21/common/misc.pyr   r   2   s$     !-AWDDAAAs   )keyc                   [        5       n/ nU  H>  nU(       a	  U" U5      nOUnXR;   a  M  UR                  U5        UR                  U5        M@     U$ )aq  
Return a List of unique items from an iterable, preserving order.
(unlike casting to a set and back)

(And why is this not already in Python?)

>>> common.misc.unique([3, 2, 4, 3, 2, 5])
[3, 2, 4, 5]

Works on any iterable, but order might not be preserved for sets, etc.

>>> common.misc.unique(range(5))
[0, 1, 2, 3, 4]

If key is a function then use that to get the value:

>>> s = converter.parse('tinyNotation: c4 E d C f# e a')
>>> common.misc.unique(s.recurse().notes, key=lambda n: n.name)
 [<music21.note.Note C>,
  <music21.note.Note E>,
  <music21.note.Note D>,
  <music21.note.Note F#>,
  <music21.note.Note A>]
)setaddappend)r   r   seenoutelelKeys         r   r   r   C   sP    2 5D
CGEE=

2  J    c                    U (       d  g[        U 5      S:X  a  U S   n[        R                  " SU S35      $ SR                  U 5      n[        R                  " SU S35      $ )	a  
Given a list of missing module names, returns a nicely-formatted message to the user
that gives instructions on how to expand music21 with optional packages.


>>> print(common.getMissingImportStr(['matplotlib']))
Certain music21 functions might need the optional package matplotlib;
if you run into errors, install it by following the instructions at
https://www.music21.org/music21docs/installing/installAdditional.html

>>> print(common.getMissingImportStr(['matplotlib', 'numpy']))
Certain music21 functions might need these optional packages: matplotlib, numpy;
if you run into errors, install them by following the instructions at
https://www.music21.org/music21docs/installing/installAdditional.html
N   r   z:Certain music21 functions might need the optional package z;
                  if you run into errors, install it by following the instructions at
                  https://www.music21.org/music21docs/installing/installAdditional.html, z>Certain music21 functions might need these optional packages: z;
                   if you run into errors, install them by following the instructions at
                   https://www.music21.org/music21docs/installing/installAdditional.html)lentextwrapdedentjoin)modNameListms     r   r   r   m   s      	[	Q	N#]^_]` aX  [ \ 	\ IIk"Nqc RY \] 	]r!   c                     [         R                  " 5       S:X  a  g[         R                  " 5       S:X  a  g[        R                  S:X  a  g[        R                  $ )a,  
Return the name of the platform, where platforms are divided
between 'win' (for Windows), 'darwin' (for MacOS X), and 'nix' for
(GNU/Linux and other variants).

Does not discern between Linux/FreeBSD, etc.

Lowercase names are for backwards compatibility -- this existed before
the platform module.
WindowswinDarwindarwinposixnix)platformsystemosnamer   r!   r   r	   r	      s@     I%		h	&	G	wwr!   c                     [        5       S:w  a  g[        S [        R                  " 5       S   R	                  S5       5       5      tpU(       a  US   OSn[        U5      S:  a  US   OSnXU4$ )z
On a Mac returns the current version as a tuple of (currently 3) ints,
such as: (10, 5, 6) for 10.5.6.

On other systems, returns (0, 0, 0)
r/   )r   r   r   c              3  8   #    U  H  n[        U5      v   M     g 7fN)int).0vs     r   	<genexpr>macOSVersion.<locals>.<genexpr>   s     )[:ZQ#a&&:Zs   r   .r#   )r	   tupler2   mac_versplitr%   )majorminor_and_maintenanceminormaintenances       r   r
   r
      su     }  %*)[(:J:J:LQ:O:U:UVY:Z)[$[!E(=!!$1E.12G.H1.L'*RSK+&&r!   c                   / n0 nU  H  nX2UR                   '   UR                  n[        R                  " U5      n[        R
                  " US   5      n[        R                  " U5      nUR                  XgUR                   45        M     UR                  5         UR                  5         U VVVs/ s H
  u  pgoU   PM     n	nnnU	$ s  snnnf )z
Sort a list of imported module names such that most recently modified is
first.  In ties, last access time is used then module name

Will return a different order each time depending on the last mod time
   )
__name____file__r4   stattime	localtimeasctimer   sortreverse)

moduleListrN   modNameToModmodfprJ   lastmodrM   modNameoutModss
             r   r   r      s     DL%(S\\"\\wwr{..a),,w'Ws||45  	IIKLLNFJKd)B7G$dGKN Ls   0Cc                n    SSR                  U  Vs/ s H  oR                  PM     sn5      -   S-   $ s  snf )z
utility method that replicates the previous behavior of
lists of pitches.

May be moved in v8 or later to a common.testing or test.X module.
[r$   ])r(   nameWithOctave)pitchLxs     r   r   r      s3     f=f,,f=>>DD=s   2
c                 V    [         R                  R                  R                  S:X  a  gg)a6  
return bool if we are running under Jupyter Notebook (not IPython terminal)
or Google Colabatory (colab).

Methods based on:

https://stackoverflow.com/questions/15411967/how-can-i-check-if-code-is-executed-in-the-ipython-notebook

(No tests provided here, since results will differ depending on environment)
	OutStreamTF)sysstderr	__class__rH   r   r!   r   r   r      s"     zz$$3r!   v9v10zuse runningInNotebook() insteadc                     [        5       $ )z3
DEPRECATED in v9: use runningInNotebook() instead
)r   r   r!   r   runningUnderIPythonre      s    
 r!   r   )ignoreAttributesc          	     @   Uc  0 nU R                  S5      nUSS u  pEnU" U6 nXq[        U 5      '   UR                  5        HY  u  pX;   a  [        XxS5        M  [	        U	5      [
        ;   a  [        XxU	5        M9  [        Xx[        R                  " X5      5        M[     U$ )a  
Unfortunately, it is not possible to do something like::

    def __deepcopy__(self, memo):
        if self._noDeepcopy:
            return self.__class__()
        else:
            copy.deepcopy(self, memo, ignore__deepcopy__=True)

Or, else: return NotImplemented

so that's what this is for::

    def __deepcopy__(self, memo):
        if self._noDeepcopy:
            return self.__class__()
        else:
            return common.defaultDeepcopy(self, memo)

Does a deepcopy of the state returned by `__reduce_ex__` for protocol 4.

* Changed in v9: callInit is removed, replaced with ignoreAttributes.
  uses `__reduce_ex__` internally.
N      )__reduce_ex__iditemssetattrtype_IMMUTABLE_DEEPCOPY_TYPEScopydeepcopy)
objmemorf   rvfuncargsstatenewattrvalues
             r   r   r      s    2 |			1	B2AD
+CCM {{}#Ct$%[55Cu%Ct}}U9: % Jr!   c                2    [         R                  " SSU 5      $ )a%  
Returns a copy of the given string where each occurrence of a flat note
specified with a 'b' is replaced by a '-'.

music_str is a string containing a note specified (for example in a chord)

Returns a new string with flats only specified with '-'.

>>> common.cleanedFlatNotation('Cb')
'C-'
z([A-Ga-g])bz\1-)resub)	music_strs    r   r   r   ,  s     66-33r!   __main__)r   zIterable[Iterable[_T]]returnzlist[_T])r   r   r   zCallable | Noner   list)r   str)r   ztuple[int, int, int])rP   zIterable[t.Any]r   zlist[object])r   boolr8   )rr   zt.Anyrf   zIterable[str])r~   r   r   r   )5__doc__
__future__r   collections.abcr   r   rp   r4   r2   r|   r_   r&   rK   typestypingtweakrefmusic21.common.decoratorsr   __all__TYPE_CHECKINGTypeVarr   r   r   r   r	   r
   r   r   r   re   rn   EllipsisNotImplementedr9   floatr   complexbytesr   CodeTyperangeBuiltinFunctionTypeFunctionTyperefpropertyro   r   r   rH   music21mainTestr   r!   r   <module>r      s&   # .  	  	 
      0 ??	
4B
B" <@ $T]>*'(0E" D%:; <  	JX^ 4guc	NND%	u11KK )PR ) )X4 z r!   