
    3j&                       d Z ddlmZ ddlmZmZ ddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddlZddlZddlZg dZddlmZ ej(                  r ej*                  d      ZddZdd	dd
Zd ZddZddZddZd Zedd       ZddZddZ  e!d       e!e"       e!e#      e$e%e&e'e(e)ejT                  e!e+ejX                  ejZ                  ej\                  e/hZ0dddddZ1d dZ2e3dk(  rddl4Z4 e4jj                          yy)!zO
If it doesn't fit anywhere else in the common directory, you'll find it here!
    )annotations)CallableIterableN)
cleanedFlatNotationdefaultDeepcopyflattenListgetMissingImportStrgetPlatformmacOSVersion	pitchListrunningInNotebooksortModulesunique)cache_Tc                @    | D cg c]  }|D ]  }|  c}}S c c}}w )a"  
    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      @/DATA/.local/lib/python3.12/site-packages/music21/common/misc.pyr   r   1   s$     !-AWDDAAAs   )keyc                   t               }g }| D ]6  }|r	 ||      }n|}||v r|j                  |       |j                  |       8 |S )a  
    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   B   sR    2 5D
CGEED=

2  J    c                    | syt        |       dk(  r| d   }t        j                  d| d      S dj                  |       }t        j                  d| d      S )	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	   l   s     	[	Q	N#]^_]` aX  [ \ 	\ IIk"Nqc RY \] 	]r!   c                     t        j                         dk(  ryt        j                         dk(  ryt        j                  dk(  ryt        j                  S )aH  
    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                     t               dk7  ryt        d t        j                         d   j	                  d      D              ^} }|r|d   nd}t        |      dkD  r|d   nd}| ||fS )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  2   K   | ]  }t        |        y wN)int).0vs     r   	<genexpr>zmacOSVersion.<locals>.<genexpr>   s     )[:ZQ#a&:Zs   r   .r#   )r
   tupler2   mac_versplitr%   )majorminor_and_maintenanceminormaintenances       r   r   r      sz     }  %*)[(:J:J:LQ:O:U:UVY:Z)[$[!E!(=!!$1E.12G.H1.L'*RSK5+&&r!   c                   g }i }| D ]}  }|||j                   <   |j                  }t        j                  |      }t	        j
                  |d         }t	        j                  |      }|j                  |||j                   f        |j                          |j                          |D cg c]  \  }}}||    }	}}}|	S c c}}}w )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)

moduleListrM   modNameToModmodfprI   lastmodrL   modNameoutModss
             r   r   r      s     DL%(S\\"\\wwr{..a),,w'Wgs||45  	IIKLLNFJKd)B'7|G$dGKN Ls   -Cc                j    ddj                  | D cg c]  }|j                   c}      z   dz   S c c}w )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      s5     f=fA,,f=>>DD=s   0
c                 0    t               ryt               ryy)aW  
    return bool if we are running under Jupyter Notebook (not IPython terminal)
    or Google Colabatory (colab) or Marimo.

    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)
    TF)runningInJupyterOrColabrunningInMarimor   r!   r   r   r      s      		r!   c                 P    t         j                  j                  j                  dk(  S )N	OutStream)sysstderr	__class__rG   r   r!   r   r]   r]      s    ::((K77r!   c                 Z    dt         j                  vryt        d      j                         S )NmarimoF)ra   modules
__import__running_in_notebookr   r!   r   r^   r^      s%    s{{"h3355r!   r   )ignoreAttributesc          	     <   |i }| j                  d      }|dd \  }}} || }||t        |       <   |j                         D ]W  \  }}	||v rt        ||d       t	        |	      t
        v rt        |||	       7t        ||t        j                  |	|             Y |S )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memori   rvfuncargsstatenewattrvalues
             r   r   r     s    2 |			1	B2AD$
+CDCM {{}e##Ct$%[55Cu%Ct}}UD9: % Jr!   c                0    t        j                  dd|       S )aA  
    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])rO   zIterable[t.Any]r   zlist[object])r   boolr8   )ru   zt.Anyri   zIterable[str])r   r   r   r   )6__doc__
__future__r   collections.abcr   r   rs   r4   r2   r   ra   r&   rJ   typestypingtweakref__all__	functoolsr   TYPE_CHECKINGTypeVarr   r   r   r	   r
   r   r   r   r   r]   r^   rq   EllipsisNotImplementedr9   floatr   complexbytesr   CodeTyperangeBuiltinFunctionTypeFunctionTyperefpropertyrr   r   r   rG   music21mainTestr   r!   r   <module>r      s    # .  	  	 
      ??	4B
B" <@ $T]<*'(0E  "86  	JX^ 4guc	NND%	u11KK )PR )X4 zG r!   