abjad.bind

abjad.bind.annotate(component, key, value)

Annotates component with key equal to value.

abjad.bind.attach(indicator, component, *[, ...])

Attaches indicator to component.

abjad.bind.detach(indicator, component, *[, ...])

Detaches indicators equals to indicator from component.

abjad.bind.annotate(component: Component, key: str, value: object) None[source]

Annotates component with key equal to value.

Annotations do not affect LilyPond output.

>>> staff = abjad.Staff("c'4 d' e' f'")
>>> abjad.annotate(staff[0], "motive_number", 6)
>>> abjad.show(staff)  
>>> abjad.get.annotation(staff[0], "motive_number")
6
abjad.bind.attach(indicator: Any, component: Component, *, check_duplicate_indicator: bool = False, context: str | None = None, deactivate: bool = False, direction: Vertical | None = None, do_not_test: bool = False, synthetic_offset: Offset | None = None, tag: Tag | None = None) None[source]

Attaches indicator to component.

The class of component is almost always a leaf. (A small number of indicators can attach to both leaves and containers.) Acceptable types of indicator:

* indicator
* abjad.Wrapper
* abjad.BeforeGraceContainer (DEPRECATED)
* abjad.AfterGraceContainer  (DEPRECATED)

Attaches articulation to last note in staff:

>>> staff = abjad.Staff("c'4 d' e' f'")
>>> articulation = abjad.Articulation(">")
>>> abjad.attach(articulation, staff[-1])
>>> abjad.show(staff)  

The check_duplicate_indicator=False keyword. Consider the case of a score with two staves. In the usual case, it is necessary to attach a metronome mark to the first note of only one of the two staves:

>>> staff_1 = abjad.Staff("c''4 d''4 e''4 f''4")
>>> staff_2 = abjad.Staff("c'4 d'4 e'4 f'4")
>>> score = abjad.Score([staff_1, staff_2])
>>> metronome_mark = abjad.MetronomeMark(abjad.Duration(1, 4), 52)
>>> abjad.attach(metronome_mark, staff_1[0])
>>> abjad.show(score)  

But what should happen when a conflicting metronome mark is attached at the same moment in a different context? Abjad allows this behavior, but it is not clear what it should mean to have two metronome marks in effect at the same time. Set check_duplicate_indicators=True to raise an exception instead.

The context=None keyword. Indicators that affect many notes, rests or chords in a row define the context at which they take effect. Clefs effect all notes on a staff, for example, which is why attaching a clef to the first note in a staff effects all the others:

>>> clef = abjad.Clef("alto")
>>> clef.context
'Staff'
>>> staff = abjad.Staff("c'4 d' e' f'")
>>> abjad.attach(clef, staff[0])
>>> abjad.show(staff)  
>>> for leaf in abjad.select.leaves(staff):
...     leaf, abjad.get.effective(leaf, abjad.Clef)
... 
(Note("c'4"), Clef(name='alto', hide=False))
(Note("d'4"), Clef(name='alto', hide=False))
(Note("e'4"), Clef(name='alto', hide=False))
(Note("f'4"), Clef(name='alto', hide=False))

This example sets context="MusicStaff" to show that the alto clef governs all notes in a custom staff context (rather than the default staff context):

>>> voice = abjad.Voice("c'4 d' e' f'", name="MusicVoice")
>>> staff = abjad.Staff([voice], name="MusicStaff")
>>> clef = abjad.Clef("alto")
>>> abjad.attach(clef, voice[0], context="MusicStaff")
>>> abjad.show(staff)  
>>> for leaf in abjad.select.leaves(staff):
...     leaf, abjad.get.effective(leaf, abjad.Clef)
... 
(Note("c'4"), Clef(name='alto', hide=False))
(Note("d'4"), Clef(name='alto', hide=False))
(Note("e'4"), Clef(name='alto', hide=False))
(Note("f'4"), Clef(name='alto', hide=False))

If multiple contexted indicators are attached at the same offset then abjad.attach() raises abjad.PersistentIndicatorError if all indicators are active. But simultaneous contexted indicators are allowed if only one is active (and all others are inactive):

>>> staff = abjad.Staff("c'4 d' e' f'")
>>> abjad.attach(abjad.Clef("treble"), staff[0])
>>> abjad.attach(
...     abjad.Clef("alto"),
...     staff[0],
...     deactivate=True,
...     tag=abjad.Tag("+PARTS"),
... )
>>> abjad.attach(
...     abjad.Clef("tenor"),
...     staff[0],
...     deactivate=True,
...     tag=abjad.Tag("+PARTS"),
... )
>>> abjad.show(staff)  

Active indicator is always effective when competing inactive indicators are present:

>>> for note in staff:
...     clef = abjad.get.effective(staff[0], abjad.Clef)
...     note, clef
... 
(Note("c'4"), Clef(name='treble', hide=False))
(Note("d'4"), Clef(name='treble', hide=False))
(Note("e'4"), Clef(name='treble', hide=False))
(Note("f'4"), Clef(name='treble', hide=False))

But a lone inactivate indicator is effective when no active indicator is present. Note that tag must be an abjad.Tag when deactivate=True:

>>> staff = abjad.Staff("c'4 d' e' f'")
>>> abjad.attach(
...     abjad.Clef("alto"),
...     staff[0],
...     deactivate=True,
...     tag=abjad.Tag("+PARTS"),
... )
>>> abjad.show(staff)  
>>> for note in staff:
...     clef = abjad.get.effective(staff[0], abjad.Clef)
...     note, clef
... 
(Note("c'4"), Clef(name='alto', hide=False))
(Note("d'4"), Clef(name='alto', hide=False))
(Note("e'4"), Clef(name='alto', hide=False))
(Note("f'4"), Clef(name='alto', hide=False))
abjad.bind.detach(indicator, component: Component, *, by_id: bool = False) tuple[source]

Detaches indicators equals to indicator from component. Returns tuple of zero or more detached items.

Detaches articulations from first note in staff:

>>> staff = abjad.Staff("c'4 d' e' f'")
>>> abjad.attach(abjad.Articulation(">"), staff[0])
>>> abjad.show(staff)  
>>> abjad.detach(abjad.Articulation, staff[0])
(Articulation(name='>'),)
>>> abjad.show(staff)  

Set by_id to true to detach exact indicator from component (rather than detaching all indicatorslequal to indicator). The use of by_id is motivated by the following.

Consider the three document-specifier markups below:

>>> markup_1 = abjad.Markup(r"\markup tutti")
>>> markup_2 = abjad.Markup(r"\markup { with the others }")
>>> markup_3 = abjad.Markup(r"\markup { with the others }")

Markups two and three compare equal:

>>> markup_2 == markup_3
True

But document-tagging like this makes sense for score and two diferent parts:

>>> staff = abjad.Staff("c'4 d' e' f'")
>>> abjad.attach(
...     markup_1, staff[0], direction=abjad.UP, tag=abjad.Tag(string="+SCORE")
... )
>>> abjad.attach(
...     markup_2,
...     staff[0],
...     deactivate=True,
...     direction=abjad.UP,
...     tag=abjad.Tag("+PARTS_VIOLIN_1"),
... )
>>> abjad.attach(
...     markup_3,
...     staff[0],
...     deactivate=True,
...     direction=abjad.UP,
...     tag=abjad.Tag("+PARTS_VIOLIN_2"),
... )
>>> abjad.show(staff)  
>>> string = abjad.lilypond(staff, tags=True)
>>> print(string)
\new Staff
{
    c'4
      %! +SCORE
    ^ \markup tutti
      %! +PARTS_VIOLIN_1
    %@% ^ \markup { with the others }
      %! +PARTS_VIOLIN_2
    %@% ^ \markup { with the others }
    d'4
    e'4
    f'4
}

The question is then how to detach just one of the two markups that compare equal to each other?

Passing in one of the markup objects directory doesn’t work. This is because detach tests for equality to input argument:

>>> markups = abjad.detach(markup_2, staff[0])
>>> for markup in markups:
...     markup
... 
Markup(string='\\markup { with the others }')
Markup(string='\\markup { with the others }')
>>> abjad.show(staff)  
>>> string = abjad.lilypond(staff, tags=True)
>>> print(string)
\new Staff
{
    c'4
      %! +SCORE
    ^ \markup tutti
    d'4
    e'4
    f'4
}

We start again:

>>> staff = abjad.Staff("c'4 d' e' f'")
>>> abjad.attach(
...     markup_1, staff[0], direction=abjad.UP, tag=abjad.Tag(string="+SCORE")
... )
>>> abjad.attach(
...     markup_2,
...     staff[0],
...     deactivate=True,
...     direction=abjad.UP,
...     tag=abjad.Tag("+PARTS_VIOLIN_1"),
... )
>>> abjad.attach(
...     markup_3,
...     staff[0],
...     deactivate=True,
...     direction=abjad.UP,
...     tag=abjad.Tag("+PARTS_VIOLIN_2"),
... )
>>> abjad.show(staff)  
>>> string = abjad.lilypond(staff, tags=True)
>>> print(string)
\new Staff
{
    c'4
      %! +SCORE
    ^ \markup tutti
      %! +PARTS_VIOLIN_1
    %@% ^ \markup { with the others }
      %! +PARTS_VIOLIN_2
    %@% ^ \markup { with the others }
    d'4
    e'4
    f'4
}

This time we set by_id to true. Now detach checks the exact id of its input argument (rather than just testing for equality). This gives us what we want:

>>> markups = abjad.detach(markup_2, staff[0], by_id=True)
>>> for markup in markups:
...     markup
... 
Markup(string='\\markup { with the others }')
>>> abjad.show(staff)  
>>> string = abjad.lilypond(staff, tags=True)
>>> print(string)
\new Staff
{
    c'4
      %! +SCORE
    ^ \markup tutti
      %! +PARTS_VIOLIN_2
    %@% ^ \markup { with the others }
    d'4
    e'4
    f'4
}

REGRESSION. Attach-detach-attach pattern works correctly when detaching wrappers:

>>> staff = abjad.Staff("c'4 d' e' f'")
>>> abjad.attach(abjad.Clef("alto"), staff[0])
>>> abjad.show(staff)  
>>> wrapper = abjad.get.wrappers(staff[0])[0]
>>> abjad.detach(wrapper, wrapper.component)
(Wrapper(annotation=None, context='Staff', deactivate=False, direction=None, indicator=Clef(name='alto', hide=False), synthetic_offset=None, tag=Tag(string='')),)
>>> abjad.show(staff)  
>>> abjad.attach(abjad.Clef("tenor"), staff[0])
>>> abjad.show(staff)