
    rhj                       S SK Jr  / SQrS SKJr  S SKrS SKrS SKrS SK	J
r
  S SK	Jr  S SK	Jr  S SK	Jr  \R                  " S	5      r " S
 S\R                   5      r " S S\R                   5      r " S S\5      r " S S\5      r " S S\5      r " S S\5      r " S S\R                   5      r " S S\5      r " S S\R                   5      r " S S\5      r " S S\R                   5      r " S  S!\R8                  5      r\\\\\\\\4r\\R
                  -  \-  r \\-  \-  \-  \!-  r"\#S":X  a  S SK	r	\	RH                  " \5        gg)#    )annotations)
Contributor	CopyrightCreatorDateDateBetweenDateRelativeDateSelection
DateSingleImprintText)IterableN)common)environment)exceptions21)prebasezmetadata.primitivesc                  
   \ rS rSrSrSrSrSrSSSSSSSSSSSSS.                       SS jjrSS	 jr	S
 r
    SS jrS r\S 5       rSS jrSS jrSS jrSS jr\S 5       r\S 5       r\S 5       rSrg)r   .   ac  
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   Ub  Uc  U R                  U5      u  pUb  Uc  U R                  U5      u  p(Ub  U	c  U R                  U5      u  p9Ub  U
c  U R                  U5      u  pJUb  Uc  U R                  U5      u  p[Ub  Uc  U R                  U5      u  plU R                  XX4XVS9  [        R                  " [        S -  U5      U l        [        R                  " [        S -  U5      U l        [        R                  " [        S -  U5      U l        [        R                  " [        S -  U5      U l        [        R                  " [        S -  U5      U l	        [        R                  " [        S -  U5      U l
        Xpl        Xl        Xl        Xl        Xl        Xl        SU l        g )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                U/home/james-whalen/.local/lib/python3.13/site-packages/music21/metadata/primitives.py__init__Date.__init__Y   sv    	 1"..t4OD!3 $ 0 0 7E?x/ ,,S1MC	 1"..t4OD+"5"&"2"26":F+"5"&"2"26":FtcVcFF3t8T*	VVCHe,
66#d(C(FF3t8T*	ffSXv.ffSXv. $-$."*#,%0%0M    c                0    [        U 5      [        U5      :H  $ Nstrr1   others     r2   __eq__Date.__eq__   s    4yCJ&&r5   c           	     t   / nU R                   c  U R                  c  U R                  c  SnOSn[        U R                  5       H  u  p4X2:  a    O[
        R                  " [        [        X5      5      n[
        R                  " [        [        XS-   5      5      nUc  UR                  S5        Mm  US:X  a  SnOSnXu-  nUb  U[        R                  U5      -  n[        U5      nUR                  U5        M     S	R                  USS
 5      n	[        U5      S
:  a  U	SSR                  US
S 5      -   -  n	U	$ )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"   	enumerater0   r-   r.   r9   getattrappendr   errorToSymboljoinlen)
r1   msg
breakIndexiattrvalueerrorfmtsubouts
             r2   __str__Date.__str__   s    99!49LJJ 0GAFF3 34EFF3Wn =>E}

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

3! 1" hhs2Aws8a<3#ab'***C
r5   c                   Sn[        U[        5      (       a  U R                  U R                  -   U R                  -   nSnU H  nXS;   d  M
  Un  O   X@R                  ;   a  UR                  US5      nSnOGX@R                  ;   a  UR                  US5      nSnO#X@R                  ;   a  UR                  US5      nSn[        U5      n[        U5      U4$ )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floatr/   )r1   rP   uncertaintysymfoundchars         r2   r+   Date._stripError   s    & !%eS!!))D,A,AADDYDYYCE; E  ///eR0+///eR0)///eR0( e5z;&&r5   c               Z  ^^^ UUU4S jnTb  TS:  d  TS:  a  [        ST S35      eTb0  TS:  d  TS:  d  Tb!  U" TTT5      (       a  [        ST ST S35      eUb  US	:  d  US
:  a  [        S5      eUb  US	:  d  US:  a  [        S5      eUb  US	:  d  US:  a  [        S5      eg g )Nc                   > TS;   =(       a    TS:H  =(       d@    TS:H  =(       a    TS:  =(       d(    TS:H  =(       a    TS:H  =(       a    TS L=(       a    TS-  $ )N)rD      	               rD    )mdyr   r   r   s      r2   
month_fail%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 .rl   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)r1   r   r   r   r    r!   r"   rs   s    ```    r2   r,   Date._sanityCheck   s    	U %!)urzCE7!LMM?b7$E3)E)EtC5(DUG1MNNTBY<==6A:">??6A:">?? 2=r5   c                    U R                  5       [        R                  S-   ;   a  [        R                  S   $ U R                  5       [        R                  S-   ;   a  [        R                  S   $ g)z
Convert an error string (approximate, uncertain) into a symbol.

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

>>> metadata.Date.errorToSymbol('uncertain')
'?'
)rY   r   )rZ   N)lowerr   r]   r^   )rP   s    r2   rI   Date.errorToSymbol   s_     ;;=D336FFF**1--;;=D11NBB((++ Cr5   c           	     4   [        U[        R                  5      (       a  U R                  U5        O[        U[        5      (       a  U R	                  U5        Op[        U[
        5      (       a  U R	                  [        U5      5        O@[        U[        5      (       a  U R                  U5        O[        R                  " SU 35      eU R                  U R                  U R                  U R                  U R                  U R                  U R                   S9  g)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)r\   datetimeloadDatetimer9   loadStrr/   r   	loadOtherr   MetadataExceptionr,   r   r   r   r    r!   r"   r1   rP   s     r2   load	Date.load  s    ( eX..//e$s##LLs##LLU$t$$NN5!003EeW1MNNtyy

#yyT[[ 	 	Rr5   c                    U R                    H4  n[        X5      (       d  M  [        X5      nUS;  d  M(  [        XU5        M6     g)z
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)r0   hasattrrG   setattr)r1   dtrO   rP   s       r2   r   Date.loadDatetime$  s9     NNDr  )	)D. #r5   c           	         U R                    HN  n[        X5      c  M  [        X[        X5      5        US-   n[        X5      c  M9  [        X[        X5      5        MP     g)a  
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'
NrA   )r0   rG   r   )r1   r;   rO   	errorAttrs       r2   r   Date.loadOther:  sO     NNDu#/GE$89 7N	5,8DWU-FG #r5   c                   / n/ nUR                  SS5      nUR                  SS5      nUR                  S5       HC  nUS:X  a  Su  pVOU R                  U5      u  pVUR                  U5        UR                  U5        ME     [	        [        U R                  5      5       HT  n[        U5      U:  d  M  [        X R                  U   X'   5        X7   c  M6  [        X R                  U   S-   X7   5        MV     g)	a  
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)
rE   rC    rX   rB   )NNNrA   )r`   splitr+   rH   rangerK   r0   r   )r1   dateStrpost	postErrorchunkrP   rQ   rN   s           r2   r   Date.loadStrN  s    4  "$&	//#s+//#r*]]3'E})u#//6KKU# ( s4>>*+A4y1}nnQ/9<+D.."3g"=y|L	 ,r5   c                    / nU R                    H-  n[        X5      nUc    OUR                  [        U5      5        M/     [        R                  " U6 $ )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)
)r0   rG   rH   r/   r   )r1   r   rO   rP   s       r2   r   Date.datetime|  sN    ,  NNDD'E}KKE
# #   $''r5   c                T    U R                   c  U R                  c  U R                  b  gg)z
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"   r1   s    r2   hasTimeDate.hasTime  s(     II!;;*;;*r5   c                L    U R                    H  n[        XS-   5      c  M    g   g)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

rA   TF)r0   rG   )r1   rO   s     r2   hasErrorDate.hasError  s)    0 NNDtG^,8 # r5   )r0   r   r%   r    r&   r!   r'   r   r$   r"   r(   r   r#   )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)rP   zint | float | strr   ztuple[int, str | None])rP   DateParseType)r   zdatetime.datetimer   None)r;   r   r   r   )r   r9   r   r   )__name__
__module____qualname____firstlineno____doc__r]   r^   r_   r3   r<   rU   r+   r,   staticmethodrI   r   r   r   r   propertyr   r   r   __static_attributes__ro   r5   r2   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                      \ rS rSrSrSSS jjrSS jrSS jrS r\	S 5       r
\	S 5       r\R                  S	 5       rS
rg)DatePrimitivei  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                :    / U l         SU l        / U l        Xl        g NrX   )_data
_relevance_dataUncertainty	relevance)r1   r   s     r2   r3   DatePrimitive.__init__  s    !#

 13"r5   c                    [        U 5      [        U5      L =(       aY    U R                  UR                  :H  =(       a9    U R                  UR                  :H  =(       a    U R                  UR                  :H  $ )z
>>> 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     r2   r<   DatePrimitive.__eq__  s^     T
d5k) :

ekk1:--1G1GG: %//9	;r5   c                    [        U 5      $ r7   r8   r   s    r2   _reprInternalDatePrimitive._reprInternal      4yr5   c                    [        U R                  5      S:X  a  g[        U R                  5      S:X  a  [        U R                  S   5      $ [        U R                   Vs/ s H  n[        U5      PM     sn5      $ s  snf )Nr   rX   ru   )rK   r   r9   )r1   rq   s     r2   rU   DatePrimitive.__str__  s]    tzz?a_!tzz!}%%

3
1A
3443s   A;c                4    U R                   S   R                  $ )z
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   r   r   s    r2   r   DatePrimitive.datetime  s    " zz!}%%%r5   c                    U R                   $ )zd
The relevance attribute takes one of three
values, `'certain'`, `'approximate'`, or
`'uncertain'`.
r   r   s    r2   r   DatePrimitive.relevance       r5   c                    US;   a)  Xl         / U l        U R                  R                  U5        g [        R                  " SU< 35      e)N)certainrY   rZ   1Relevance value is not supported by this object: )r   r   rH   r   r   r   s     r2   r   r   !  sK    ;;#O$&D!!!((/00CE9MO Or5   )r   r   r   r   N)r   )r   r9   r   )r   r9   )r   r   r   r   r   r3   r<   r   rU   r   r   r   setterr   ro   r5   r2   r   r     s_    #;"5 & &$   O Or5   r   c                  D   ^  \ rS rSrSrSSU 4S jjjrS rSS jrSrU =r	$ )	r   i-  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U ]  U5        U R                  U5        g r7   superr3   _prepareDatar1   datar   	__class__s      r2   r3   DateSingle.__init__C      #$r5   c                2    [        U R                  S   5      $ )Nr   )r9   r   r   s    r2   rU   DateSingle.__str__G  s    4::a=!!r5   c                    / U l         U R                  /U l        U R                   R                  [	        5       5        U R                   S   R                  U5        g))
Assume a string is supplied as argument
r   N)r   r   r   rH   r   r   r1   r   s     r2   r   DateSingle._prepareDataJ  sD     
!% 0

$&!

14 r5   )r   r   )rX   r   r   r   )
r   r   r   r   r   r3   rU   r   r   __classcell__r   s   @r2   r   r   -  s!    *   "	! 	!r5   r   c                  ~   ^  \ rS rSrSrS	S
U 4S jjjrU 4S jr\S 5       r\R                  S 5       rS
S jr
SrU =r$ )r	   iZ  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U ]  U5        U R                  U5        g r7   r   r   s      r2   r3   DateRelative.__init__m  s    #$r5   c                   > U R                   n[        TU ]	  5       nUS:X  a  SU-   $ US:X  a  US-   $ US:X  a  US-   $ SU-   $ )Npriorz	prior to 
onorbeforez or earlier	onorafterz	 or laterzafter )r   r   rU   )r1   rdsr   s      r2   rU   DateRelative.__str__t  sZ    NNW_<##,%%+##b= r5   c                    U R                   $ )zm
The relevance attribute takes one of four
values, `'prior'`, `'after'`, or
`'onorbefore'` or `'onorafter'`.
r   r   s    r2   r   DateRelative.relevance  r   r5   c                    US:X  a  SnUR                  5       S;  a  [        R                  " SU< 35      eUR                  5       U l        g )Nbeforer   )r   afterr   r   r   )r}   r   r   r   r   s     r2   r   r     sJ    HE;;= MM00CE9MO O++-r5   c                    / U l         S/U l        U R                   R                  [        5       5        U R                   S   R	                  U5        g)r   Nr   )r   r   rH   r   r   r   s     r2   r   DateRelative._prepareData  s?     
!%

$&!

14 r5   r   r   r   )rX   r   r   )r   r   r   r   r   r3   rU   r   r   r   r   r   r   r   s   @r2   r	   r	   Z  sO    $   
!   ( (	! 	!r5   r	   c                  x   ^  \ rS rSrSrS	S
U 4S jjjrS rS
S jr\S 5       r	\	R                  S 5       r	SrU =r$ )r   i  a
  
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U ]  U5        U R                  U5        g r7   r   r   s      r2   r3   DateBetween.__init__  r   r5   c                    / nU R                    H  nUR                  [        U5      5        M     SR                  U5      $ )Nz to )r   rH   r9   rJ   r1   rL   rq   s      r2   rU   DateBetween.__str__  s4    AJJs1v {{3r5   c                    / U l         / U l        U HT  n[        5       nUR                  U5        U R                   R	                  U5        U R                  R	                  S5        MV     g)z;
Assume a list of dates as strings is supplied as argument
Nr   r   r   r   rH   r1   r   partrq   s       r2   r   DateBetween._prepareData  U     
 "DAFF4LJJa !!((. r5   c                    U R                   $ )z<
The relevance attribute takes only one value:
`'between'`.
r   r   s    r2   r   DateBetween.relevance       r5   c                P    US:w  a  [         R                  " SU< 35      eXl        g )Nbetweenr   r   r   r   r   s     r2   r   r     s.    I00CE9MO Or5   r   )ro   r  r   zIterable[DateParseType])r   r   r   r   r   r3   rU   r   r   r   r   r   r   r   s   @r2   r   r     sJ    (    /      r5   r   c                     ^  \ rS rSrSrSr  S
 SU 4S jjjrS rSS jr\	S 5       r
\
R                  S 5       r
S	rU =r$ )r
   i  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U ]  U5        U R                  U5        g r7   r   r   s      r2   r3   DateSelection.__init__  s      	#$r5   c                    / nU R                    H  nUR                  [        U5      5        M     SU R                   S3R	                  U5      $ )Nr   )r   rH   r9   r   rJ   r   s      r2   rU   DateSelection.__str__  sD    AJJs1v 4??#1%**3//r5   c                    / U l         / U l        U HT  n[        5       nUR                  U5        U R                   R	                  U5        U R                  R	                  S5        MV     g)z<
Assume a list of dates as strings is supplied as argument.
Nr   r   s       r2   r   DateSelection._prepareData  r   r5   c                    U R                   $ )zC
The relevance attribute takes only two values:
`'or'` or `'and'`.
r   r   s    r2   r   DateSelection.relevance'  r  r5   c                P    US;  a  [         R                  " SU< 35      eXl        g )N)orandr   r  r   s     r2   r   r  /  s.    %00CE9MO Or5   r   )ro   r  r  )r   r   r   r   r   isSingler3   rU   r   r   r   r   r   r   r   s   @r2   r
   r
     sa    < H
 24 .   0/      r5   r
   c                      \ rS rSrSr    S       SS jjrS rS rSS jrS r	\
S	 5       r\R                  S
 5       rS rSrg)r   i<  a  
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                    [        U[        5      (       aE  UR                  U l        UR                  U l        UR                  U l        UR
                  U l        g Xl        X l        X0l        X@l        g r7   )r\   r   r   	_languageisTranslatedencodingScheme)r1   r   languager  r  s        r2   r3   Text.__init__K  sY    
 dD!!#'::DJ'+~~DN+/+<+<D,0,?,?DJ%N ,"0r5   c                    [        U R                  [        5      (       a  U R                  R                  S5      $ [        U R                  [        5      (       a  U R                  $ [	        U R                  5      $ )NzUTF-8)r\   r   bytesdecoder9   r   s    r2   rU   Text.__str__^  sQ    djj%((::$$W--

C((::tzz?"r5   c                    [        U 5      $ r7   r8   r   s    r2   r   Text._reprInternalf  r   r5   c                   [        U5      [        U 5      La  gU R                  UR                  :w  a  gU R                  UR                  :w  a  gU R                  UR                  :w  a  gU R                  UR                  :w  a  gg)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     r2   r<   Text.__eq__i  sn    2 ;d4j(::$==ENN* 2 22%"6"66r5   c                    [        U5      [        U 5      La  [        $ U R                  U R                  U R                  U R
                  4UR                  UR                  UR                  UR
                  4:  $ )z0
Allows for alphabetically sorting two elements
)r   NotImplementedr   r  r  r  r:   s     r2   __lt__Text.__lt__  se     ;d4j(!!ZZ(9(94;N;NO{{ENNE,>,>@T@TUV	
r5   c                    U R                   $ )z
Set the language of the Text stored within.

>>> myText = metadata.Text('my text')
>>> myText.language = 'en'
>>> myText.language
'en'
r  r   s    r2   r  Text.language  s     ~~r5   c                    Xl         g r7   r'  r   s     r2   r  r(    s    r5   c                X    SSK Jn  UR                  [        U 5      U R                  5      $ )aI  
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  )r1   r+  s     r2   getNormalizedArticleText.getNormalizedArticle  s"    " 	!""3t9dnn==r5   )r   r  r  r  )rX   NNN)r   
str | Textr  r   r  bool | Noner  r   r   )r   r   r   r   r   r3   rU   r   r<   r$  r   r  r   r.  r   ro   r5   r2   r   r   <  s    
 #%&*+/,0	11#1  )1 "*	1&##L	
 	 	 __ 
>r5   r   c                  V   ^  \ rS rSrSr   SSS.     SU 4S jjjjrS	S jrSrU =r$ )
r   i  uk  
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               2   > [         TU ]  XU5        X@l        g r7   )r   r3   r3  )r1   r   r  r  r3  r   s        r2   r3   Copyright.__init__  s    
 	6	r5   c                   [        U5      [        U 5      La  gU R                  UR                  :w  a  gU R                  UR                  :w  a  gU R                  UR                  :w  a  gU R                  UR                  :w  a  gg)NFT)r   r   r  r  r3  r:   s     r2   r<   Copyright.__eq__  sh    ;d4j(::$==ENN* 2 2299

"r5   )rX   NN)r   r0  r  r   r  r1  r   )	r   r   r   r   r   r3   r<   r   r   r   s   @r2   r   r     sL    !H #%&*+/ 	#  )  r5   r   c                  ~   \ rS rSrSrSrSSSSSS	S
SSSS.
r\R                  5       r\R                  5       r
SSSSSS.         S S jjrS rS rS!S jrS"S jr\S 5       r\R$                  S 5       r\S 5       r\R$                  S 5       r\S 5       r\R$                  S 5       r\S 5       r\S 5       rSrg)#r   i  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trnNro   )namenamesr3  birthdeathc                  S U l         U(       a  X0l        OS U l        / U l        U(       aU  [        U[        5      (       a  U R                  R                  U5        O$U R                  R                  [	        U5      5        U(       a_  U HY  n[        U[        5      (       a  U R                  R                  U5        M5  U R                  R                  [	        U5      5        M[     / U l        S U l        S U l        Ub)  [        U[        5      (       d  [        U5      nOUnXl        Ub*  [        U[        5      (       d  [        U5      n	OUn	Xl        g g r7   )
_roler3  _namesr\   r   rH   _nationalityrP  rQ  r   )
r1   rN  rO  r3  rP  rQ  keywordsnbirthDSdeathDSs
             r2   r3   Contributor.__init__:  s    
IDI #%$%%""4(""4:.a&&KK&&q)KK&&tAw/	  )+&*
&*
eZ00$U+ JeZ00$U+ J r5   c                8    U R                    SU R                   3$ )NrE   r3  rN  r   s    r2   r   Contributor._reprInternali  s    ))Adii[))r5   c                >    U R                   (       d  gU R                   $ r   )rN  r   s    r2   rU   Contributor.__str__l  s    yyyyr5   c                   [        U5      [        U 5      La  gU R                  UR                  :w  a  g[        U R                  5      [        UR                  5      :w  a  g[	        [        U R                  5      [        UR                  5      5       H  u  p#X#:w  d  M    g   U R                  UR                  :w  a  gU R                  UR                  :w  a  gg)a  
>>> 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   rS  rK   rT  zipsortedrP  rQ  )r1   r;   rN  	otherNames       r2   r<   Contributor.__eq__q  s    x ;d4j(::$t{{s5<<00"6$++#6u||8LMOD   N ::$::$r5   c                   U R                   c  gU R                  b0  U R                  R                  nU R                   R                  nX-
  $ [        R                  R                  5       U R                   R                  -
  $ )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)rP  rQ  r   now)r1   rq   bs      r2   ageContributor.age  se    N ::::!

##A

##A5L$$((*TZZ-@-@@@r5   c                V    U R                   (       a  [        U R                   S   5      $ g)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)rT  r9   r   s    r2   rN  Contributor.name  s!      ;;t{{1~&&r5   c                Z    / U l         U R                   R                  [        U5      5        g r7   )rT  rH   r   r   s     r2   rN  rk    s!     4;'r5   c                d    / nU R                    H  nUR                  [        U5      5        M     U$ )a  
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']
)rT  rH   r9   )r1   rL   rW  s      r2   rO  Contributor.names  s,    " AJJs1v 
r5   c                    [         R                  " U5      (       d  [        R                  " S5      e/ U l        U H'  nU R                  R                  [        U5      5        M)     g )Nz3.names must be a list -- do you mean .name instead?)r   
isIterabler   r   rT  rH   r   )r1   valuesrW  s      r2   rO  rn  "  sR      ((00EG GAKKtAw' r5   c                    U R                   $ )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'
)rS  r   s    r2   r3  Contributor.role+  s    0 zzr5   c                    Ub  XR                   R                  5       ;   a  Xl        g XR                   ;   a  U R                   U   U l        g Xl        g r7   )roleAbbreviationsDictrq  rS  r   s     r2   r3  rs  E  sC    =E%?%?%F%F%HHJ00033E:DJJr5   c                    U R                  5       n U [        R                  ;   a  [        R                  U    $ [        R                  " SU < 35      e)z
Convert `abbreviation` to role name:

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

>>> metadata.Contributor.abbreviationToRole('lib')
'librettist'
zno such role: )r}   r   ru  r   r   )abbreviations    r2   abbreviationToRoleContributor.abbreviationToRoleN  sO     $))+;<<<44\BB00  013 3r5   c                    [         R                   H:  nU R                  5       [         R                  U   R                  5       :X  d  M8  Us  $    [        R                  " SU  35      e)zi
Convert `roleName` to role abbreviation:

>>> metadata.Contributor.roleToAbbreviation('composer')
'com'
zNo such role: )r   ru  r}   r   r   )roleNamerole_ids     r2   roleToAbbreviationContributor.roleToAbbreviation`  sV     #88G~~;#D#DW#M#S#S#UU 9 ,,~hZ-HIIr5   )rT  rU  rS  rP  rQ  r3  )
rN  str | Text | NonerO  zIterable[str | Text]r3  r  rP  None | DateSingle | strrQ  r  r   )r   zdatetime.timedelta | None)r   r   r   r   r   r   ru  keysroleAbbreviationsrq  	roleNamesr3   r   rU   r<   rh  r   rN  r   rO  r3  r   rx  r}  r   ro   r5   r2   r   r     sb   ( I  #"" .224%,,.I (,-/'+.2.2-!$-! +-! %	-!
 ,-! ,-!^*
IZ/Af  ( 
[[( (
  * \\( (  2 
[[  3 3" J Jr5   r   c                      \ rS rSrSrSrSrg)r   iq  a(  
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'
creatorro   N)r   r   r   r   r   r   r   ro   r5   r2   r   r   q  s    & Ir5   r   c                      \ rS rSrSrS rSrg)r   i  z6
An object representation of imprint, or publication.
c                    Xl         g r7   rV  )r1   rV  s     r2   r3   Imprint.__init__  s     r5   r  N)r   r   r   r   r   r3   r   ro   r5   r2   r   r     s    !r5   r   c                  J    \ rS rSrS rS rS rS rS rS r	S r
S	 rS
 rSrg)Testi  c                    SSK Jn  UR                  R                  S5      nSUl        U R                  UR                  S5        U R                  UR                  S5        g )Nr   metadatazmy texten)r,  r  
primitivesr   r  assertEqualr   r  )r1   r  r+  s      r2   testTextTest.testText  sJ    $""''	2Y/.r5   c                    SSK Jn  UR                  R                  SSS9nU R	                  UR
                  S5        U R	                  UR                  S5        U R	                  UR                  S5        g )Nr   r  r:  Gilles Binchoisr\  r9  )r,  r  r  r   r  r3  r   rN  )r1   r  r9  s      r2   testContributorTest.testContributor  sk    $))55" 6 
 	)):6..>))+<=r5   c                    SSK Jn  UR                  R                  SSS9nU R	                  UR
                  S5        U R	                  UR                  S5        U R	                  UR                  S5        g )Nr   r  r:  r  r\  r  )r,  r  r  r   r  r3  r   rN  )r1   r  r  s      r2   testCreatorTest.testCreator  sg    $%%--" . 
 	z2**I6'89r5   c                V   SSK Jn  UR                  R                  SSS9nUR                  R                  SS9nU R	                  UR
                  S5        U R	                  UR                  S5        U R	                  UR
                  S5        U R	                  UR                  S5        g )	Nr   r  i3  rY   )r   r#   z1843?)r   rZ   )r,  r  r  r   r  r   r#   )r1   r  date1date2s       r2   testDateTest.testDate  s    $##((dm(L##((g(6T*-8T*+6r5   c                *   U R                  [        S5         [        SS9  S S S 5        S H/  u  pnU R                  [        S5         [        X2US9  S S S 5        M1     U R                  [        S5         [        SS	9  S S S 5        U R                  [        S
5         [        SS9  S S S 5        U R                  [        S5         [        SS9  S S S 5        U R                  [        SSSS95        U R                  [        SSS95        U R                  [        SSS95        U R                  [        SSSS95        g ! , (       d  f       GN#= f! , (       d  f       GM4  = f! , (       d  f       N= f! , (       d  f       N= f! , (       d  f       N= f)NzMonth must be.*not 13   )r   ))    NN)r   NN)rl   rD   N)   rm   N)rn   rm   i  zDay.*is not possible)r   r   r   Hour   )r    Minute=   )r!   Second)r"   i  rm   rn   )r   r   rv   rl   rx   ry   r   )assertRaisesRegexrz   r   assertIsNotNone)r1   rq   rp   rr   s       r2   testDateValueErrorTest.testDateValueError  s1   ##J0GHrN IGA! ''
4JK!!, 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;   
D=E4
E"
E3
F=
E
E	"
E03
F
Fc                :   SSK Jn  UR                  R                  SS5      nU R	                  [        U5      S5        U R	                  [        UR                  5      S5        U R	                  UR                  S5        U R	                  UR                  S/5        g )Nr   r  
2009/12/31rY   ru   )
r,  r  r  r   r  r9   rK   r   r   r   )r1   r  
dateSingles      r2   testDateSingleTest.testDateSingle  s}    $((33-)
Z,7Z--.2..>44}oFr5   c                :   SSK Jn  UR                  R                  SS5      nU R	                  [        U5      S5        U R	                  UR                  S5        U R	                  [        UR                  5      S5        U R	                  UR                  S /5        g )Nr   r  z
2001/12/31r   zprior to 2001/12/31ru   )
r,  r  r  r	   r  r9   r   rK   r   r   )r1   r  dateRelatives      r2   testDateRelativeTest.testDateRelative  s|    $**77gN\*,AB//9\//0!466?r5   c                :   SSK Jn  UR                  R                  S5      nU R	                  [        U5      S5        U R	                  UR                  S5        U R	                  UR                  S S /5        U R	                  [        UR                  5      S5        g )Nr   r  )r  	2010/1/28z2009/12/31 to 2010/01/28r  rm   )
r,  r  r  r   r  r9   r   r   rK   r   )r1   r  dateBetweens      r2   testDateBetweenTest.testDateBetween#  s    $))55')[)+EF..	:55d|D[../3r5   c                @   SSK Jn  UR                  R                  / SQS5      nU R	                  [        U5      S5        U R	                  UR                  S5        U R	                  UR                  / SQ5        U R	                  [        UR                  5      S5        g )Nr   r  )r  r  z	1894/1/28r  z&2009/12/31 or 2010/01/28 or 1894/01/28)NNNr?   )
r,  r  r  r
   r  r9   r   r   rK   r   )r1   r  dateSelections      r2   testDateSelectionTest.testDateSelection-  s    $ ++994
 	]+A	C00$7779KL]00115r5   ro   N)r   r   r   r   r  r  r  r  r  r  r  r  r  r   ro   r5   r2   r  r    s2    /	>	:
7B2G@46r5   r  __main__)%
__future__r   __all__collections.abcr   r   typingr-   unittestr,  r   r   r   r   EnvironmentenvironLocalProtoM21Objectr   r   r   r	   r   r
   r   r   r   r   r   TestCaser  
_DOC_ORDERr9   r   r/   	ValueTyper   mainTestro   r5   r2   <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T r5   