
    3jx                       d dl mZ g d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 d dl	mZ  ej                  d	      Z G d
 dej                         Z G d dej                         Z G d de      Z G d de      Z G d de      Z G d de      Z G d dej                         Z G d de      Z G d dej                         Z G d de      Z G d dej                         Z G d  d!ej8                        ZeeeeeeeefZeej
                  z  ez  Z eez  ez  ez  e!z  Z"e#d"k(  rd dl	Z	 e	jH                  e       yy)#    )annotations)Contributor	CopyrightCreatorDateDateBetweenDatePrimitiveDateRelativeDateSelection
DateSingleImprintText	ValueType)IterableN)common)environment)exceptions21)prebasezmetadata.primitivesc                      e Zd ZdZdZdZdZddddddddddddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZddZd	 Z		 	 	 	 dd
Z
d Zed        ZddZddZddZddZed        Zed        Zed        Zy)r   a  
    A single date value, specified by year, month, day, hour, minute, and
    second. Note that this class has been created, instead of using Python's
    datetime, to provide greater flexibility for processing unconventional
    dates, ancient dates, dates with error, and date ranges.

    The :attr:`~music21.metadata.Date.datetime` property can be used to
    retrieve a datetime object when necessary.

    Additionally, each value can be specified as `uncertain` or `approximate`;
    if None, assumed to be certain.

    Date objects are fundamental components of
    :class:`~music21.metadata.DateSingle` and related subclasses that represent
    single dates and date ranges.

    >>> a = metadata.Date(year=1843, yearError='approximate')
    >>> a.year
    1843

    >>> a.yearError
    'approximate'

    >>> a = metadata.Date(year='1843?')
    >>> a.yearError
    'uncertain'

    >>> d = metadata.Date(year=1805, month=3, monthError='approximate')
    >>> str(d)
    '1805/03~/--'

    Note that milliseconds are not retained, as this is a tool for musicology
    and not for file timestamps.  However, unlike datetime objects, dates
    in the distant past are supported (though not currently BC/BCE dates).
    )~x)?z)<{>}N)yearmonthdayhourminutesecond	yearError
monthErrordayError	hourErrorminuteErrorsecondErrorc               L   ||| j                  |      \  }}||| j                  |      \  }}||	| j                  |      \  }}	||
| j                  |      \  }}
||| j                  |      \  }}||| j                  |      \  }}| j                  ||||||       t        j                  t        d z  |      | _        t        j                  t        d z  |      | _        t        j                  t        d z  |      | _        t        j                  t        d z  |      | _        t        j                  t        d z  |      | _	        t        j                  t        d z  |      | _
        || _        || _        |	| _        |
| _        || _        || _        d| _        y )Nr   r   r    r!   r"   r#   )_stripError_sanityChecktcastintr   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   	attrNames)selfr   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   s                H/DATA/.local/lib/python3.12/site-packages/music21/metadata/primitives.py__init__zDate.__init__Z   s    	 1"..t4OD)!3 $ 0 0 7E:?x/ ,,S1MC	 1"..t4OD)+"5"&"2"26":FK+"5"&"2"26":FKt5cV\bcFF3t8T*	VVCHe,
66#d(C(FF3t8T*	ffSXv.ffSXv. $-$."*#,%0%0M    c                0    t        |       t        |      k(  S Nstrr2   others     r3   __eq__zDate.__eq__   s    4yCJ&&r5   c           	     d   g }| j                   | j                  | j                  d}nd}t        | j                        D ]  \  }}||k\  r nt        j                  t        t        | |            }t        j                  t        t        | |dz               }||j                  d       l|dk(  rd}nd}||z  }||t        j                  |      z  }t        |      }|j                  |        d	j                  |dd
       }	t        |      d
kD  r|	ddj                  |d
d       z   z  }	|	S )z
        Return a string representation, including error if defined.

        >>> d = metadata.Date()
        >>> d.loadStr('1030?/12~/?4')
        >>> str(d)
        '1030?/12~/04?'
        N      Error--r   z%04.iz%02.i/   :)r!   r"   r#   	enumerater1   r.   r/   r9   getattrappendr   errorToSymboljoinlen)
r2   msg
breakIndexiattrvalueerrorfmtsubouts
             r3   __str__zDate.__str__   s     99!49LJJ 0GAtJFF3d 34EFF3dWn =>E}

4 6>!C!CEk$4--e44C#h

3! 1" hhs2Aws8a<3#ab'***C
r5   c                   d}t        |t              r| j                  | j                  z   | j                  z   }d}|D ]
  }||v s|} n || j                  v r|j                  |d      }d}nE|| j                  v r|j                  |d      }d}n"|| j                  v r|j                  |d      }d}t        |      }t        |      |fS )a  
        Strip error symbols from a numerical value. Return cleaned source and
        sym. Only one error symbol is expected per string.

        >>> d = metadata.Date()
        >>> d._stripError('1247~')
        (1247, 'approximate')

        >>> d._stripError('63?')
        (63, 'uncertain')

        Milliseconds are not retained -- this is for musicology, not computers:

        >>> d._stripError('4.43')
        (4, None)
        N approximate	uncertainpriority)
isinstancer9   approximateSymbolsuncertainSymbolspriorTimeSymbolsreplacefloatr0   )r2   rO   uncertaintysymfoundchars         r3   r,   zDate._stripError   s    & !%eS!))D,A,AADDYDYYCE3; E  ///eR0+$///eR0)$///eR0( e5z;&&r5   c               .   fd}dk  sdkD  rt        d d      (dkD  sdk  s |      rt        d d d      ||d	k  s|d
kD  rt        d      ||d	k  s|dkD  rt        d      ||d	k  s|dkD  rt        d      y y )Nc                l    dv xr dk(  xs' dk(  xr dkD  xs dk(  xr dk(  xr d uxr dz  S )N)rC      	               rC    )mdyr    r   r   s      r3   
month_failz%Date._sanityCheck.<locals>.month_fail   sZ    m+9r	 T
/sRxT
RsbyRT5ER$QR(Ur5         z$Month must be between 1 and 12, not .ri   zDay z is not possible with month r      zHour must be between 0 and 23;   zMinute must be between 0 and 59zSecond must be between 0 and 59)
ValueError)r2   r   r   r    r!   r"   r#   rp   s    ```    r3   r-   zDate._sanityCheck   s    	U %!)urzCE7!LMM?b7$E3)EtC5(DUG1MNNTBY<==6A:">??6A:">?? 2=r5   c                    | j                         t        j                  dz   v rt        j                  d   S | j                         t        j                  dz   v rt        j                  d   S y)z
        Convert an error string (approximate, uncertain) into a symbol.

        >>> metadata.Date.errorToSymbol('approximate')
        '~'

        >>> metadata.Date.errorToSymbol('uncertain')
        '?'
        )rW   r   )rX   N)lowerr   r[   r\   )rO   s    r3   rH   zDate.errorToSymbol   s_     ;;=D336FFF**1--;;=D11NBB((++ Cr5   c                   t        |t        j                        r| j                  |       nt        |t              r| j	                  |       net        |t
              r| j	                  t        |             n:t        |t              r| j                  |       nt        j                  d|       | j                  | j                  | j                  | j                  | j                  | j                  | j                          y)a"  
        Load values by string, datetime object, or Date object:

        >>> a = metadata.Date(year=1843, month=3, day=3)
        >>> b = metadata.Date()
        >>> b.load(a)
        >>> b.year
        1843

        If there is an error, a ValueError is raised, but the
        incorrect values are retained:

        >>> d = metadata.Date()
        >>> d.load('1999/14/32/25:60:61')
        Traceback (most recent call last):
        ValueError: Month must be between 1 and 12, not 14.
        >>> str(d)
        '1999/14/32/25:60:61'
        zCannot load data: r+   N)rZ   datetimeloadDatetimer9   loadStrr0   r   	loadOtherr   MetadataExceptionr-   r   r   r    r!   r"   r#   r2   rO   s     r3   loadz	Date.load  s    ( eX../e$s#LLs#LLU$t$NN5!003EeW1MNNtyy

#yyT[[ 	 	Rr5   c                |    | j                   D ]-  }t        ||      st        ||      }|dvs!t        | ||       / y)a?  
        Load time data from a datetime object:

        >>> import datetime
        >>> dt = datetime.datetime(2005, 2, 1)
        >>> dt
        datetime.datetime(2005, 2, 1, 0, 0)

        >>> m21mdDate = metadata.Date()
        >>> m21mdDate.loadDatetime(dt)
        >>> str(m21mdDate)
        '2005/02/01'
        )r   NN)r1   hasattrrF   setattr)r2   dtrN   rO   s       r3   r{   zDate.loadDatetime%  s<     NNDr4 D)	)D$. #r5   c           	         | j                   D ]O  }t        ||      t        | |t        ||             |dz   }t        ||      9t        | |t        ||             Q y)aj  
        Load values based on another Date object.  (the "Other" in "loadOther"
        means another Date object, not just anything.

        >>> a = metadata.Date(year=1843, month=3, day=3, yearError='approximate')
        >>> b = metadata.Date()
        >>> b.loadOther(a)
        >>> b.year
        1843
        >>> b.yearError
        'approximate'
        Nr@   )r1   rF   r   )r2   r;   rN   	errorAttrs       r3   r}   zDate.loadOther;  s[     NNDud#/dGE4$89 7N	5),8D)WUI-FG #r5   c                   g }g }|j                  dd      }|j                  dd      }|j                  d      D ]C  }|dk(  rd\  }}n| j                  |      \  }}|j                  |       |j                  |       E t	        t        | j                              D ]T  }t        |      |kD  st        | | j                  |   ||          ||   5t        | | j                  |   dz   ||          V y)	aL  
        Load a string date representation, which might have approximate
        symbols.

        Assume `year/month/day/hour:minute:second`:

        >>> d = metadata.Date()
        >>> d.loadStr('1030?/12~/?4')
        >>> d.month, d.monthError
        (12, 'approximate')

        >>> d.year, d.yearError
        (1030, 'uncertain')

        >>> d.month, d.monthError
        (12, 'approximate')

        >>> d.day, d.dayError
        (4, 'uncertain')

        >>> d = metadata.Date()
        >>> d.loadStr('1834/12/4/4:50:32')
        >>> d.minute, d.second
        (50, 32)
        rD   rB    rV   rA   )NNNr@   )r^   splitr,   rG   rangerJ   r1   r   )r2   dateStrpost	postErrorchunkrO   rP   rM   s           r3   r|   zDate.loadStrO  s    4  "$&	//#s+//#r*]]3'E})u#//6uKKU# ( s4>>*+A4y1}dnnQ/a9Q<+D$.."3g"=y|L	 ,r5   c                    g }| j                   D ],  }t        | |      }| n|j                  t        |             . t	        j                  | S )a  
        Get a datetime object from a metadata.Date() object

        >>> a = metadata.Date(year=1843, month=3, day=3)
        >>> str(a)
        '1843/03/03'

        >>> a.datetime
        datetime.datetime(1843, 3, 3, 0, 0)

        Lack of a required date element raises an exception:

        >>> a = metadata.Date(year=1843, month=3)
        >>> str(a)
        '1843/03/--'

        >>> a.datetime
        Traceback (most recent call last):
        TypeError: function missing required argument 'day' (pos 3)
        )r1   rF   rG   r0   rz   )r2   r   rN   rO   s       r3   rz   zDate.datetime}  sP    ,  NNDD$'E}KKE
# #   $''r5   c                N    | j                   | j                  | j                  yy)a  
        Return True if any time elements are defined:

        >>> a = metadata.Date(year=1843, month=3, day=3)
        >>> a.hasTime
        False

        >>> b = metadata.Date(year=1843, month=3, day=3, minute=3)
        >>> b.hasTime
        True
        TFr!   r"   r#   r2   s    r3   hasTimezDate.hasTime  s(     II!;;*;;*r5   c                H    | j                   D ]  }t        | |dz          y y)a  
        Return True if any data points have error defined:

        >>> a = metadata.Date(
        ...     year=1843,
        ...     month=3,
        ...     day=3,
        ...     dayError='approximate',
        ...     )
        >>> a.hasError
        True

        >>> b = metadata.Date(
        ...     year=1843,
        ...     month=3,
        ...     day=3,
        ...     minute=3,
        ...     )
        >>> b.hasError
        False

        r@   TF)r1   rF   )r2   rN   s     r3   hasErrorzDate.hasError  s+    0 NNDtTG^,8 # r5   )r   int | str | Noner   r   r    r   r!   r   r"   r   r#   zint | float | str | Noner$   
str | Noner%   r   r&   r   r'   r   r(   r   r)   r   returnbool)rO   zint | float | strr   ztuple[int, str | None])rO   DateParseType)r   zdatetime.datetimer   None)r;   r   r   r   )r   r9   r   r   )__name__
__module____qualname____doc__r[   r\   r]   r4   r<   rT   r,   r-   staticmethodrH   r   r{   r}   r|   propertyrz   r   r   rl   r5   r3   r   r   /   s\   "H $!+ '+'+%)&*(,.2'+(,&*'+)-)-,N#,N %,N #	,N
 $,N &,N ,,N %,N &,N $,N %,N ',N ',N^'%P''(''-''R@. , ,RB/,H(*M\ ( (@  &  r5   r   c                  t    e Zd ZdZd
ddZddZddZd Zed        Z	ed        Z
e
j                  d        Z
y	)r	   a'  
    A default class for all date objects, which can have different types
    and different "relevance" values.

    Note that the interaction between uncertainty on an entire DatePrimitive object
    vs uncertainty on a particular Date value, like month, is ill-defined
    and needs work.
    c                <    g | _         d| _        g | _        || _        y NrV   )_data
_relevance_dataUncertainty	relevance)r2   r   s     r3   r4   zDatePrimitive.__init__  s!    !#

 13"r5   c                    t        |       t        |      u xrO | j                  |j                  k(  xr4 | j                  |j                  k(  xr | j                  |j                  k(  S )a  
        >>> dd = metadata.DateSingle('1805/3/12', 'uncertain')
        >>> dd2 = metadata.DateSingle('1805/3/12', 'uncertain')
        >>> str(dd)
        '1805/03/12'
        >>> dd == dd2
        True
        >>> dd2.relevance='certain'
        >>> dd == dd2
        False
        )typer   r   r   r:   s     r3   r<   zDatePrimitive.__eq__  s^     T
d5k) :

ekk1:--1G1GG: %//9	;r5   c                    t        |       S r7   r8   r   s    r3   _reprInternalzDatePrimitive._reprInternal      4yr5   c                    t        | j                        dk(  ryt        | j                        dk(  rt        | j                  d         S t        | j                  D cg c]  }t        |       c}      S c c}w )Nr   rV   rq   )rJ   r   r9   )r2   rn   s     r3   rT   zDatePrimitive.__str__  s]    tzz?a_!tzz!}%%

3
1A
3443s   A6c                4    | j                   d   j                  S )a  
        Get a datetime object.

        >>> a = metadata.DateSingle('1843/03/03')
        >>> str(a)
        '1843/03/03'

        >>> a.datetime
        datetime.datetime(1843, 3, 3, 0, 0)

        >>> a = metadata.DateSingle('1843/03')
        >>> str(a)
        '1843/03/--'
        r   )r   rz   r   s    r3   rz   zDatePrimitive.datetime  s    " zz!}%%%r5   c                    | j                   S )z
        The relevance attribute takes one of three
        values, `'certain'`, `'approximate'`, or
        `'uncertain'`.
        r   r   s    r3   r   zDatePrimitive.relevance       r5   c                    |dv r*|| _         g | _        | j                  j                  |       y t        j                  d|      )N)certainrW   rX   1Relevance value is not supported by this object: )r   r   rG   r   r~   r   s     r3   r   zDatePrimitive.relevance"  sM    ;;#DO$&D!!!((/00CE9MO Or5   N)r   )r   r9   r   )r   r9   )r   r   r   r   r4   r<   r   rT   r   rz   r   setterrl   r5   r3   r	   r	     s_    #;"5 & &$   O Or5   r	   c                  4     e Zd ZdZdd fdZd ZddZ xZS )r   a?  
    Store a date, either as certain, approximate, or uncertain relevance.

    The relevance attribute is limited within each DateSingle subclass
    depending on the design of the class. Alternative relevance types should be
    configured as other DateSingle subclasses.

    >>> dd = metadata.DateSingle('2009/12/31', 'approximate')
    >>> dd
    <music21.metadata.primitives.DateSingle 2009/12/31>

    >>> str(dd)
    '2009/12/31'

    >>> dd.relevance
    'approximate'

    >>> dd = metadata.DateSingle('1805/3/12', 'uncertain')
    >>> str(dd)
    '1805/03/12'
    c                F    t         |   |       | j                  |       y r7   superr4   _prepareDatar2   datar   	__class__s      r3   r4   zDateSingle.__init__D      #$r5   c                2    t        | j                  d         S )Nr   )r9   r   r   s    r3   rT   zDateSingle.__str__H  s    4::a=!!r5   c                    g | _         | j                  g| _        | j                   j                  t	                      | j                   d   j                  |       y)9
        Assume a string is supplied as argument
        r   N)r   r   r   rG   r   r   r2   r   s     r3   r   zDateSingle._prepareDataK  sD     
!% 0

$&!

14 r5   )rV   r   r   r   )r   r   r   r   r4   rT   r   __classcell__r   s   @r3   r   r   .  s    * "	!r5   r   c                  l     e Zd ZdZdd fdZ fdZed        Zej                  d        ZddZ	 xZ
S )	r
   a  
    Store a relative date, sometime `prior` or sometime `after`, `onorbefore`, or onorafter`.

    >>> dd = metadata.DateRelative('2009/12/31', 'prior')
    >>> str(dd)
    'prior to 2009/12/31'
    >>> dd.relevance = 'after'
    >>> str(dd)
    'after 2009/12/31'

    >>> dd = metadata.DateRelative('2009/12/31', 'certain')
    Traceback (most recent call last):
    music21.exceptions21.MetadataException: Relevance value is not
        supported by this object: 'certain'
    c                F    t         |   |       | j                  |       y r7   r   r   s      r3   r4   zDateRelative.__init__n  s    #$r5   c                ~    | j                   }t        | 	         }|dk(  rd|z   S |dk(  r|dz   S |dk(  r|dz   S d|z   S )Npriorz	prior to 
onorbeforez or earlier	onorafterz	 or laterzafter )r   r   rT   )r2   rdsr   s      r3   rT   zDateRelative.__str__u  sZ    NNW_<##,%%+##b= r5   c                    | j                   S )z
        The relevance attribute takes one of four
        values, `'prior'`, `'after'`, or
        `'onorbefore'` or `'onorafter'`.
        r   r   s    r3   r   zDateRelative.relevance  r   r5   c                    |dk(  rd}|j                         dvrt        j                  d|      |j                         | _        y )Nbeforer   )r   afterr   r   r   )rx   r   r~   r   r   s     r3   r   zDateRelative.relevance  sJ    HE;;= MM00CE9MO O++-r5   c                    g | _         dg| _        | j                   j                  t                      | j                   d   j	                  |       y)r   Nr   )r   r   rG   r   r   r   s     r3   r   zDateRelative._prepareData  s?     
!%

$&!

14 r5   )rV   r   r   )r   r   r   r   r4   rT   r   r   r   r   r   r   s   @r3   r
   r
   [  sE    $ 
!   ( (	!r5   r
   c                  h     e Zd ZdZdd fdZd ZddZed        Zej                  d        Z xZ
S )	r   aB  
    Store a relative date, sometime between two dates:

    >>> dd = metadata.DateBetween(['2009/12/31', '2010/1/28'])
    >>> str(dd)
    '2009/12/31 to 2010/01/28'

    >>> dd = metadata.DateBetween(['2009/12/31', '2010/1/28'], 'certain')
    Traceback (most recent call last):
    music21.exceptions21.MetadataException: Relevance value is not
        supported by this object: 'certain'

    >>> d1 = metadata.Date(year=1605)
    >>> d2 = metadata.Date(year=1608, month='11?')
    >>> dd = metadata.DateBetween([d1, d2])
    >>> str(dd)
    '1605/--/-- to 1608/11?/--'
    c                F    t         |   |       | j                  |       y r7   r   r   s      r3   r4   zDateBetween.__init__  r   r5   c                ~    g }| j                   D ]  }|j                  t        |              dj                  |      S )Nz to )r   rG   r9   rI   r2   rK   rn   s      r3   rT   zDateBetween.__str__  s4    AJJs1v {{3r5   c                    g | _         g | _        |D ]S  }t               }|j                  |       | j                   j	                  |       | j                  j	                  d       U y)zK
        Assume a list of dates as strings is supplied as argument
        Nr   r   r   r   rG   r2   r   partrn   s       r3   r   zDateBetween._prepareData  U     
 "DAFF4LJJa !!((. r5   c                    | j                   S )zT
        The relevance attribute takes only one value:
        `'between'`.
        r   r   s    r3   r   zDateBetween.relevance       r5   c                L    |dk7  rt        j                  d|      || _        y )Nbetweenr   r   r~   r   r   s     r3   r   zDateBetween.relevance  s0    I00CE9MO Or5   )rl   r   r   zIterable[DateParseType])r   r   r   r   r4   rT   r   r   r   r   r   r   s   @r3   r   r     sE    (  /      r5   r   c                  r     e Zd ZdZdZ	 	 d	 d	 fdZd Zd	dZed        Z	e	j                  d        Z	 xZS )
r   a  
    Store a selection of dates, or a collection of dates that might all be
    possible

    >>> dd = metadata.DateSelection(
    ...     ['2009/12/31', '2010/1/28', '1894/1/28'],
    ...     )
    >>> str(dd)
    '2009/12/31 or 2010/01/28 or 1894/01/28'

    >>> dd = metadata.DateSelection(
    ...     [1750, '1775/03?'],
    ...     'and'
    ...     )
    >>> str(dd)
    '1750/--/-- and 1775/03?/--'

    >>> dd = metadata.DateSelection(
    ...     ['2009/12/31', '2010/1/28'],
    ...     'certain',
    ...     )
    Traceback (most recent call last):
    music21.exceptions21.MetadataException: Relevance value is not
        supported by this object: 'certain'

    Note that '1350 or 1351 and 1375' is not supported yet.
    Fc                F    t         |   |       | j                  |       y r7   r   r   s      r3   r4   zDateSelection.__init__	  s      	#$r5   c                    g }| j                   D ]  }|j                  t        |              d| j                   dj	                  |      S )Nr   )r   rG   r9   r   rI   r   s      r3   rT   zDateSelection.__str__  sD    AJJs1v 4??#1%**3//r5   c                    g | _         g | _        |D ]S  }t               }|j                  |       | j                   j	                  |       | j                  j	                  d       U y)zL
        Assume a list of dates as strings is supplied as argument.
        Nr   r   s       r3   r   zDateSelection._prepareData  r   r5   c                    | j                   S )z[
        The relevance attribute takes only two values:
        `'or'` or `'and'`.
        r   r   s    r3   r   zDateSelection.relevance(  r   r5   c                J    |dvrt        j                  d|      || _        y )N)orandr   r   r   s     r3   r   zDateSelection.relevance0  s0    %00CE9MO Or5   )rl   r   r   )r   r   r   r   isSingler4   rT   r   r   r   r   r   r   s   @r3   r   r     s\    < H
 24 . 0/      r5   r   c                      e Zd ZdZ	 	 	 	 d	 	 	 	 	 	 	 ddZd Zd ZddZd Ze	d        Z
e
j                  d	        Z
d
 Zy)r   aA  
    One unit of text data: a title, a name, or some other text data. Store the
    string and a language name or code. This object can be used and/or
    subclassed for a variety for of text storage.

    >>> td = metadata.Text('concerto in d', 'en')
    >>> str(td)
    'concerto in d'
    >>> td.language
    'en'
    Nc                    t        |t              rE|j                  | _        |j                  | _        |j                  | _        |j
                  | _        y || _        || _        || _        || _        y r7   )rZ   r   r   	_languageisTranslatedencodingScheme)r2   r   languager   r   s        r3   r4   zText.__init__L  s^    
 dD!#'::DJ'+~~DN+/+<+<D,0,?,?DDJ%DN ,D"0Dr5   c                    t        | j                  t              r| j                  j                  d      S t        | j                  t              r| j                  S t	        | j                        S )NzUTF-8)rZ   r   bytesdecoder9   r   s    r3   rT   zText.__str___  sK    djj%(::$$W--

C(::tzz?"r5   c                    t        |       S r7   r8   r   s    r3   r   zText._reprInternalg  r   r5   c                   t        |      t        |       ury| j                  |j                  k7  ry| j                  |j                  k7  ry| j                  |j                  k7  ry| j                  |j                  k7  ryy)a  
        >>> t1 = metadata.Text('some text')
        >>> t2 = metadata.Text('some text')
        >>> t1 == t2
        True

        Language, isTranslated, and encodingScheme must all exactly match for equality.

        >>> t2 = metadata.Text('some text', language='en')
        >>> t1 == t2
        False
        >>> t2 = metadata.Text('some text', isTranslated=True)
        >>> t1 == t2
        False
        >>> t2 = metadata.Text('some text', encodingScheme='scheme42')
        >>> t1 == t2
        False

        Comparison with non-Text types, including bare strings,
        will always be considered unequal.

        >>> t1 == 'some text'
        False
        FT)r   r   r   r   r   r:   s     r3   r<   zText.__eq__j  sn    2 ;d4j(::$==ENN* 2 22%"6"66r5   c                    t        |      t        |       urt        S | j                  | j                  | j                  | j
                  f|j                  |j                  |j                  |j
                  fk  S )z@
        Allows for alphabetically sorting two elements
        )r   NotImplementedr   r   r   r   r:   s     r3   __lt__zText.__lt__  se     ;d4j(!!ZZ(9(94;N;NO{{ENNE,>,>@T@TUV	
r5   c                    | j                   S )z
        Set the language of the Text stored within.

        >>> myText = metadata.Text('my text')
        >>> myText.language = 'en'
        >>> myText.language
        'en'
        r   r   s    r3   r   zText.language  s     ~~r5   c                    || _         y r7   r   r   s     r3   r   zText.language  s	    r5   c                X    ddl m} |j                  t        |       | j                        S )a  
        Return a string representation with normalized articles.

        >>> td = metadata.Text('Ale is Dear, The', language='en')
        >>> str(td)
        'Ale is Dear, The'

        >>> td.getNormalizedArticle()
        'The Ale is Dear'

        The language will determine whether the article is moved:

        >>> td.language = 'de'
        >>> td.getNormalizedArticle()
        'Ale is Dear, The'
        r   )text)music21r   prependArticler9   r   )r2   r   s     r3   getNormalizedArticlezText.getNormalizedArticle  s"    " 	!""3t9dnn==r5   )rV   NNN)r   
str | Textr   r   r   bool | Noner   r   r   )r   r   r   r   r4   rT   r   r<   r   r   r   r   r  rl   r5   r3   r   r   =  s    
 #%&*+/,0	11#1  )1 "*	1&##L	
 	 	 __ 
>r5   r   c                  D     e Zd ZdZ	 	 	 ddd	 	 	 	 	 d fdZddZ xZS )	r   u  
    A subclass of text that can also have a role

    >>> c = metadata.primitives.Copyright('Copyright 1945 Florence Price')
    >>> c
    <music21.metadata.primitives.Copyright Copyright 1945 Florence Price>
    >>> c.role is None
    True
    >>> str(c)
    'Copyright 1945 Florence Price'

    The text, language, isTranslated, role, etc. must be identical for equality.

    >>> c2 = metadata.Copyright('Copyright 1945 Florence Price')
    >>> c == c2
    True
    >>> c2 = metadata.Copyright('Copyright © 1945 Florence Price')
    >>> c == c2
    False
    >>> c2 = metadata.Copyright('Copyright 1945 Florence Price', language='en')
    >>> c == c2
    False
    >>> c2 = metadata.Copyright('Copyright 1945 Florence Price', isTranslated=True)
    >>> c == c2
    False
    >>> c2 = metadata.Copyright('Copyright 1945 Florence Price', role='other')
    >>> c == c2
    False

    Comparison against a non-Copyright object will always return False.

    >>> c == 1945
    False
    N)rolec               6    t         |   |||       || _        y r7   )r   r4   r  )r2   r   r   r   r  r   s        r3   r4   zCopyright.__init__  s    
 	x6	r5   c                   t        |      t        |       ury| j                  |j                  k7  ry| j                  |j                  k7  ry| j                  |j                  k7  ry| j                  |j                  k7  ryy)NFT)r   r   r   r   r  r:   s     r3   r<   zCopyright.__eq__  sh    ;d4j(::$==ENN* 2 2299

"r5   )rV   NN)r   r  r   r   r   r  r   )r   r   r   r   r4   r<   r   r   s   @r3   r   r     sB    !H #%&*+/ 	#  )r5   r   c                  n   e Zd ZdZdZddddddd	d
ddd
Zej                         Zej                         Z	dddddd	 	 	 	 	 	 	 	 	 ddZ
d Zd ZddZd dZed        Zej"                  d        Zed        Zej"                  d        Zed        Zej"                  d        Zed        Zed        Zy)!r   a  
    A person that contributed to a work. Can be a composer, lyricist, arranger,
    or other type of contributor.  In MusicXML, these are "creator" elements.

    >>> td = metadata.Contributor(role='composer', name='Chopin, Fryderyk')
    >>> td.role
    'composer'

    >>> td.name
    'Chopin, Fryderyk'

    >>> td.relevance
    'contributor'

    >>> td
    <music21.metadata.primitives.Contributor composer:Chopin, Fryderyk>
    contributorcomposerattributedComposersuspectedComposercomposerAliascomposerCorporatelyricist
librettistarrangerorchestrator
translator)
comcoacoscolcoclyrliblarlortrnNrl   )namenamesr  birthdeathc               `   d | _         |r|| _        nd | _        g | _        |rPt        |t              r| j                  j                  |       n$| j                  j                  t	        |             |rW|D ]R  }t        |t              r| j                  j                  |       /| j                  j                  t	        |             T g | _        d | _        d | _        |%t        |t              st        |      }n|}|| _        |&t        |t              st        |      }	n|}	|	| _        y y r7   )
_roler  _namesrZ   r   rG   _nationalityr!  r"  r   )
r2   r  r   r  r!  r"  keywordsnbirthDSdeathDSs
             r3   r4   zContributor.__init__;  s    
DIDI #%$%""4(""4:.a&KK&&q)KK&&tAw/	  )+&*
&*
eZ0$U+ DJeZ0$U+ DJ r5   c                8    | j                    d| j                   S )NrD   r  r  r   s    r3   r   zContributor._reprInternalj  s    ))Adii[))r5   c                4    | j                   sy| j                   S r   )r  r   s    r3   rT   zContributor.__str__m  s    yyyyr5   c                   t        |      t        |       ury| j                  |j                  k7  ryt        | j                        t        |j                        k7  ryt	        t        | j                        t        |j                              D ]  \  }}||k7  s y | j                  |j                  k7  ry| j                  |j                  k7  ryy)ar  
        >>> c1 = metadata.Contributor(
        ...         role='composer',
        ...         name='The Composer',
        ...         birth='1923',
        ...         death='2013'
        ... )
        >>> c2 = metadata.Contributor(
        ...         role='composer',
        ...         name='The Composer',
        ...         birth='1923',
        ...         death='2013'
        ... )

        Names, role, birth, and death must all be identical for equality.

        >>> c1 == c2
        True
        >>> c2.role = 'lyricist'
        >>> c1 == c2
        False
        >>> c2 = metadata.Contributor(
        ...         role='composer',
        ...         name='A Composer',
        ...         birth='1923',
        ...         death='2013'
        ... )
        >>> c1 == c2
        False
        >>> c2 = metadata.Contributor(
        ...         role='composer',
        ...         names=['A Composer', 'The Composer'],
        ...         birth='1923',
        ...         death='2013'
        ... )
        >>> c1 == c2
        False
        >>> c2 = metadata.Contributor(
        ...         role='composer',
        ...         name='The Composer',
        ...         birth='1924',
        ...         death='2013'
        ... )
        >>> c1 == c2
        False
        >>> c2 = metadata.Contributor(
        ...         role='composer',
        ...         name='The Composer',
        ...         birth='1923',
        ...         death='2012'
        ... )
        >>> c1 == c2
        False

        Comparison with a non-Contributor object always returns False.

        >>> c1 == 'The Composer'
        False
        FT)r   r$  rJ   r%  zipsortedr!  r"  )r2   r;   r  	otherNames       r3   r<   zContributor.__eq__r  s    x ;d4j(::$t{{s5<<00"6$++#6u||8LMOD)y   N ::$::$r5   c                    | j                   y| j                  1| j                  j                  }| j                   j                  }||z
  S t        j                  j                         | j                   j                  z
  S )a  
        Calculate the age at death of the Contributor, returning a
        datetime.timedelta object.

        >>> a = metadata.Contributor(
        ...     name='Beethoven, Ludwig van',
        ...     role='composer',
        ...     birth='1770/12/17',
        ...     death='1827/3/26',
        ...     )

        >>> a.birth
        <music21.metadata.primitives.DateSingle 1770/12/17>

        >>> a.age()
        datetime.timedelta(days=20552)

        >>> a.age().days
        20552

        >>> years = a.age().days // 365
        >>> years
        56

        If the composer is still alive, it returns the composer's current age.

        >>> shaw = metadata.Contributor(
        ...     name='Shaw, Caroline',
        ...     role='composer',
        ...     birth='1982/08/01',
        ...     )
        >>> shaw_years = shaw.age().days // 365

        This test will fail in 2067:

        >>> 36 < shaw_years < 85
        True
        N)r!  r"  rz   now)r2   rn   bs      r3   agezContributor.age  sg    N ::::!

##A

##Aq5L$$((*TZZ-@-@@@r5   c                L    | j                   rt        | j                   d         S y)a_  
        Returns the text name, or the first of many names entered.

        >>> td = metadata.Contributor(
        ...     role='composer',
        ...     names=['Chopin, Fryderyk', 'Chopin, Frederick'],
        ...     )
        >>> td.name
        'Chopin, Fryderyk'

        >>> td.names
        ['Chopin, Fryderyk', 'Chopin, Frederick']
        r   N)r%  r9   r   s    r3   r  zContributor.name  s!      ;;t{{1~&&r5   c                Z    g | _         | j                   j                  t        |             y r7   )r%  rG   r   r   s     r3   r  zContributor.name  s!     4;'r5   c                `    g }| j                   D ]  }|j                  t        |              |S )an  
        Returns all names in a list.

        >>> td = metadata.Contributor(
        ...     role='composer',
        ...     names=['Chopin, Fryderyk', 'Chopin, Frederick'],
        ...     )
        >>> td.names
        ['Chopin, Fryderyk', 'Chopin, Frederick']

        >>> td.names = ['Czerny', 'Spohr']
        >>> td.names
        ['Czerny', 'Spohr']
        )r%  rG   r9   )r2   rK   r(  s      r3   r   zContributor.names  s,    " AJJs1v 
r5   c                    t        j                  |      st        j                  d      g | _        |D ]&  }| j                  j                  t        |             ( y )Nz3.names must be a list -- do you mean .name instead?)r   
isIterabler   r~   r%  rG   r   )r2   valuesr(  s      r3   r   zContributor.names#  sO      (00EG GAKKtAw' r5   c                    | j                   S )a#  
        The role is what part this Contributor plays in the work.  Both
        full roll strings and roll abbreviations may be used.

        >>> td = metadata.Contributor()
        >>> td.role = 'composer'
        >>> td.role
        'composer'

        In case of a Humdrum role abbreviation, the role that is set
        is the full name:

        >>> td.role = 'lor'
        >>> td.role
        'orchestrator'

        Roles can be created on the fly:

        >>> td.role = 'court jester'
        >>> td.role
        'court jester'
        )r$  r   s    r3   r  zContributor.role,  s    0 zzr5   c                    ||| j                   j                         v r|| _        y || j                   v r| j                   |   | _        y || _        y r7   )roleAbbreviationsDictr;  r$  r   s     r3   r  zContributor.roleF  sK    =ET%?%?%F%F%HHDJd00033E:DJDJr5   c                    | j                         } | t        j                  v rt        j                  |    S t        j                  d|       )z
        Convert `abbreviation` to role name:

        >>> metadata.Contributor.abbreviationToRole('com')
        'composer'

        >>> metadata.Contributor.abbreviationToRole('lib')
        'librettist'
        zno such role: )rx   r   r>  r   r~   )abbreviations    r3   abbreviationToRolezContributor.abbreviationToRoleO  sO     $))+;<<<44\BB00  013 3r5   c                    t         j                  D ]8  }| j                         t         j                  |   j                         k(  s6|c S  t        j                  d|        )z
        Convert `roleName` to role abbreviation:

        >>> metadata.Contributor.roleToAbbreviation('composer')
        'com'
        zNo such role: )r   r>  rx   r   r~   )roleNamerole_ids     r3   roleToAbbreviationzContributor.roleToAbbreviationa  sV     #88G~~;#D#DW#M#S#S#UU 9 ,,~hZ-HIIr5   )
r  str | Text | Noner   zIterable[str | Text]r  rF  r!  None | DateSingle | strr"  rG  r   )r   zdatetime.timedelta | None)r   r   r   r   r   r>  keysroleAbbreviationsr;  	roleNamesr4   r   rT   r<   r5  r   r  r   r   r  r   rA  rE  rl   r5   r3   r   r     sb   ( I  #"" .224%,,.I (,-/'+.2.2-!$-! +-! %	-!
 ,-! ,-!^*
IZ/Af  ( 
[[( (
  * \\( (  2 
[[  3 3" J Jr5   r   c                      e Zd ZdZdZy)r   aT  
    A person that created a work. Can be a composer, lyricist, arranger, or
    other type of contributor.

    In MusicXML, these are "creator" elements.

    >>> td = metadata.Creator(role='composer', name='Chopin, Fryderyk')
    >>> td.role
    'composer'

    >>> td.name
    'Chopin, Fryderyk'

    >>> td.relevance
    'creator'
    creatorN)r   r   r   r   r   rl   r5   r3   r   r   r  s    & Ir5   r   c                      e Zd ZdZd Zy)r   z>
    An object representation of imprint, or publication.
    c                    || _         y r7   )r'  )r2   r'  s     r3   r4   zImprint.__init__  s	     r5   N)r   r   r   r   r4   rl   r5   r3   r   r     s    !r5   r   c                  B    e Zd Zd Zd Zd Zd Zd Zd Zd Z	d Z
d	 Zy
)Testc                    ddl m} |j                  j                  d      }d|_        | j                  |j                  d       | j                  |j                  d       y )Nr   metadatazmy texten)r   rS  
primitivesr   r   assertEqualr   r   )r2   rS  r   s      r3   testTextzTest.testText  sJ    $""''	2Y/.r5   c                    ddl m} |j                  j                  dd      }| j	                  |j
                  d       | j	                  |j                  d       | j	                  |j                  d       y )Nr   rR  r  Gilles Binchoisr,  r
  )r   rS  rU  r   rV  r  r   r  )r2   rS  r
  s      r3   testContributorzTest.testContributor  sk    $))55" 6 
 	)):6..>))+<=r5   c                    ddl m} |j                  j                  dd      }| j	                  |j
                  d       | j	                  |j                  d       | j	                  |j                  d       y )Nr   rR  r  rY  r,  rL  )r   rS  rU  r   rV  r  r   r  )r2   rS  rL  s      r3   testCreatorzTest.testCreator  sg    $%%--" . 
 	z2**I6'89r5   c                b   ddl m} |j                  j                  dd      }|j                  j                  d      }| j	                  |j
                  d       | j	                  |j                  d       | j	                  |j
                  d       | j	                  |j                  d       y )	Nr   rR  i3  rW   )r   r$   z1843?)r   rX   )r   rS  rU  r   rV  r   r$   )r2   rS  date1date2s       r3   testDatezTest.testDate  s    $##((dm(L##((g(6T*-8T*+6r5   c                ,   | j                  t        d      5  t        d       d d d        dD ]3  \  }}}| j                  t        d      5  t        |||       d d d        5 | j                  t        d      5  t        d	       d d d        | j                  t        d
      5  t        d       d d d        | j                  t        d      5  t        d       d d d        | j                  t        ddd             | j                  t        dd             | j                  t        dd             | j                  t        ddd             y # 1 sw Y   6xY w# 1 sw Y   AxY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w)NzMonth must be.*not 13   )r   ))    NN)r   NN)ri   rC   N)   rj   N)rk   rj   i  zDay.*is not possible)r   r   r    Hour   )r!   Minute=   )r"   Second)r#   i  rj   rk   )r   r    rr   ri   rt   ru   r   )assertRaisesRegexrv   r   assertIsNotNone)r2   rn   rm   ro   s       r3   testDateValueErrorzTest.testDateValueError  s5   ##J0GHrN IGAq! ''
4JK!1!, LK ##J7bM 8##J9O :##J9O : 	Tt1"=>Tr23T34Tr"R@A- IH LK 879999s;   EE%:E2%E>F
E"%E/	2E;>F
Fc                :   ddl m} |j                  j                  dd      }| j	                  t        |      d       | j	                  t        |j                        d       | j	                  |j                  d       | j	                  |j                  dg       y )Nr   rR  
2009/12/31rW   rq   )
r   rS  rU  r   rV  r9   rJ   r   r   r   )r2   rS  
dateSingles      r3   testDateSinglezTest.testDateSingle  s}    $((33-)
Z,7Z--.2..>44}oFr5   c                :   ddl m} |j                  j                  dd      }| j	                  t        |      d       | j	                  |j                  d       | j	                  t        |j                        d       | j	                  |j                  d g       y )Nr   rR  z
2001/12/31r   zprior to 2001/12/31rq   )
r   rS  rU  r
   rV  r9   r   rJ   r   r   )r2   rS  dateRelatives      r3   testDateRelativezTest.testDateRelative  s|    $**77gN\*,AB//9\//0!466?r5   c                :   ddl m} |j                  j                  d      }| j	                  t        |      d       | j	                  |j                  d       | j	                  |j                  d d g       | j	                  t        |j                        d       y )Nr   rR  )ro  	2010/1/28z2009/12/31 to 2010/01/28r   rj   )
r   rS  rU  r   rV  r9   r   r   rJ   r   )r2   rS  dateBetweens      r3   testDateBetweenzTest.testDateBetween$  s    $))55')[)+EF..	:55d|D[../3r5   c                @   ddl m} |j                  j                  g dd      }| j	                  t        |      d       | j	                  |j                  d       | j	                  |j                  g d       | j	                  t        |j                        d       y )Nr   rR  )ro  rv  z	1894/1/28r   z&2009/12/31 or 2010/01/28 or 1894/01/28)NNNr>   )
r   rS  rU  r   rV  r9   r   r   rJ   r   )r2   rS  dateSelections      r3   testDateSelectionzTest.testDateSelection.  s    $ ++994
 	]+A	C00$7779KL]00115r5   N)r   r   r   rW  rZ  r\  r`  rm  rq  rt  rx  r{  rl   r5   r3   rP  rP    s2    /	>	:
7B2G@46r5   rP  __main__)%
__future__r   __all__collections.abcr   rz   typingr.   unittestr   r   r   r   r   EnvironmentenvironLocalProtoM21Objectr   r	   r   r
   r   r   r   r   r   r   r   TestCaserP  
_DOC_ORDERr9   r   r0   r   r   mainTestrl   r5   r3   <module>r     s   # %         '{&&'<=^7!! ^DZOG** ZOz&! &!ZB!= B!L? - ? JO M O nE>7!! E>T7 7ziJ'(( iJ\k 4!g$$ !@m68 m6h 		
 X&&&s*${*94S8	 zGT r5   