bind

digraph InheritanceGraph { graph [bgcolor=transparent, color=lightsteelblue2, fontname=Arial, fontsize=10, outputorder=edgesfirst, overlap=prism, penwidth=2, rankdir=LR, splines=spline, style="dashed, rounded", truecolor=true]; node [colorscheme=pastel19, fontname=Arial, fontsize=10, height=0, penwidth=2, shape=box, style="filled, rounded", width=0]; edge [color=lightslategrey, penwidth=1]; subgraph "cluster_abjad.bind" { graph [label="abjad.bind"]; node [color=1]; "abjad.bind.Wrapper" [URL="../api/abjad/bind.html#abjad.bind.Wrapper", color=black, fontcolor=white, label=Wrapper, target=_top]; } subgraph cluster_builtins { graph [label=builtins]; node [color=2]; "builtins.object" [URL="https://docs.python.org/3.10/library/functions.html#object", label=object, target=_top]; } "builtins.object" -> "abjad.bind.Wrapper"; }


Functions

annotate

Annotates component with indicator.

attach

Attaches attachable to (leaf or container) target.

detach

Detaches indicators-equal-to-argument from target.

abjad.bind.annotate(component, annotation, indicator)[source]

Annotates component with indicator.

Annotates first note in staff:

>>> staff = abjad.Staff("c'4 d' e' f'")
>>> abjad.annotate(staff[0], "bow_direction", abjad.DOWN)
>>> abjad.show(staff)  
>>> abjad.get.annotation(staff[0], "bow_direction")
<Vertical.DOWN: -1>
>>> abjad.get.annotation(staff[0], "bow_fraction") is None
True
>>> abjad.get.annotation(staff[0], "bow_fraction", 99)
99
Return type:

None

abjad.bind.attach(attachable, target, *, check_duplicate_indicator=False, context=None, deactivate=False, direction=None, do_not_test=False, synthetic_offset=None, tag=None, wrapper=False)[source]

Attaches attachable to (leaf or container) target.

Acceptable types of attachable:

* indicator
* abjad.Wrapper
* abjad.BeforeGraceContainer
* abjad.AfterGraceContainer

The class of target is almost always abjad.Leaf. A small number of indicators (like abjad.LilyPondLiteral) can attach to both abjad.Leaf and abjad.Container objects.

Attaches clef to first note in staff:

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

Attaches accent to last note in staff:

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

Works with context names:

>>> voice = abjad.Voice("c'4 d' e' f'", name="MusicVoice")
>>> staff = abjad.Staff([voice], name="MusicStaff")
>>> abjad.attach(abjad.Clef("alto"), 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))

Derives context from attachable.context context when context=None.

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:

>>> 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))

Note that tag must be an abjad.Tag when deactivate=True.

Return type depends on value of wrapper:

  • returns abjad.Wrapper when wrapper is true

  • returns none when wrapper is not true

Return type:

Optional[Wrapper]

abjad.bind.detach(argument, target=None, by_id=False)[source]

Detaches indicators-equal-to-argument from target.

Set by_id to true to detach exact argument from target (rather than detaching all indicators-equal-to-argument).

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)  

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)  

Returns tuple of zero or more detached items.


Internals

Wrapper

Wrapper.

class abjad.bind.Wrapper(annotation=None, check_duplicate_indicator=False, component=None, context=None, deactivate=False, direction=None, indicator=None, synthetic_offset=None, tag=Tag(string=''))[source]

Wrapper.

>>> component = abjad.Note("c'4")
>>> articulation = abjad.Articulation("accent")
>>> abjad.attach(articulation, component, direction=abjad.UP)
>>> abjad.get.wrapper(component)
Wrapper(annotation=None, context=None, deactivate=False, direction=<Vertical.UP: 1>, indicator=Articulation(name='accent'), synthetic_offset=None, tag=Tag(string=''))

Duplicate indicator warnings take two forms.

>>> voice_1 = abjad.Voice("c''4 d'' e'' f''", name="VoiceI")
>>> voice_2 = abjad.Voice("c'4 d' e' f'", name="VoiceII")
>>> staff = abjad.Staff([voice_1, voice_2], simultaneous=True)
>>> abjad.attach(abjad.Clef("alto"), voice_2[0])
>>> abjad.show(staff)  

First form when attempting to attach a contexted indicator to a leaf that already carries a contexted indicator of the same type:

>>> # abjad.attach(abjad.Clef("treble"), voice_2[0])

Second form when attempting to attach a contexted indicator to a leaf governed by some other component carrying a contexted indicator of the same type.

>>> # abjad.attach(abjad.Clef("treble"), voice_1[0])

Attributes Summary

__copy__

Copies wrapper.

__eq__

Is true when self equals argument.

__hash__

Hashes wrapper.

__repr__

Gets repr.

annotation

Gets wrapper annotation.

bundled

Is true when indicator is bundled.

component

Gets start component.

context

Gets context (name).

deactivate

Is true when wrapper deactivates tag.

direction

Gets direction of indicator.

get_item

Gets indicator or bundled indicator.

indicator

Gets indicator.

leaked_start_offset

Gets start offset and checks to see whether indicator leaks to the right.

site_adjusted_start_offset

Gets site-adjusted start offset.

start_offset

Gets start offset.

synthetic_offset

Gets synthetic offset.

tag

Gets and sets tag.

unbundle_indicator

Gets unbundled indicator.


Special methods

__copy__(*arguments)[source]

Copies wrapper.

Preserves annotation flag:

>>> old_staff = abjad.Staff("c'4 d'4 e'4 f'4")
>>> abjad.annotate(old_staff[0], "bow_direction", abjad.DOWN)
>>> string = abjad.lilypond(old_staff)
>>> print(string)
\new Staff
{
    c'4
    d'4
    e'4
    f'4
}
>>> leaf = old_staff[0]
>>> abjad.get.annotation(leaf, "bow_direction")
<Vertical.DOWN: -1>
>>> new_staff = abjad.mutate.copy(old_staff)
>>> string = abjad.lilypond(new_staff)
>>> print(string)
\new Staff
{
    c'4
    d'4
    e'4
    f'4
}
>>> leaf = new_staff[0]
>>> abjad.get.annotation(leaf, "bow_direction")
<Vertical.DOWN: -1>

Preserves tag:

>>> old_staff = abjad.Staff("c'4 d'4 e'4 f'4")
>>> clef = abjad.Clef("alto")
>>> abjad.attach(clef, old_staff[0], tag=abjad.Tag("RED:M1"))
>>> string = abjad.lilypond(old_staff, tags=True)
>>> print(string)
\new Staff
{
      %! M1
      %! RED
    \clef "alto"
    c'4
    d'4
    e'4
    f'4
}
>>> leaf = old_staff[0]
>>> abjad.get.wrapper(leaf)
Wrapper(annotation=None, context='Staff', deactivate=False, direction=None, indicator=Clef(name='alto', hide=False), synthetic_offset=None, tag=Tag(string='RED:M1'))
>>> new_staff = abjad.mutate.copy(old_staff)
>>> string = abjad.lilypond(new_staff, tags=True)
>>> print(string)
\new Staff
{
      %! M1
      %! RED
    \clef "alto"
    c'4
    d'4
    e'4
    f'4
}
>>> leaf = new_staff[0]
>>> abjad.get.wrapper(leaf)
Wrapper(annotation=None, context='Staff', deactivate=False, direction=None, indicator=Clef(name='alto', hide=False), synthetic_offset=None, tag=Tag(string='RED:M1'))

Preserves deactivate flag:

>>> old_staff = abjad.Staff("c'4 d'4 e'4 f'4")
>>> abjad.attach(
...     abjad.Clef("alto"),
...     old_staff[0],
...     deactivate=True,
...     tag=abjad.Tag("RED:M1"),
... )
>>> string = abjad.lilypond(old_staff, tags=True)
>>> print(string)
\new Staff
{
      %! M1
      %! RED
    %@% \clef "alto"
    c'4
    d'4
    e'4
    f'4
}
>>> leaf = old_staff[0]
>>> abjad.get.wrapper(leaf)
Wrapper(annotation=None, context='Staff', deactivate=True, direction=None, indicator=Clef(name='alto', hide=False), synthetic_offset=None, tag=Tag(string='RED:M1'))
>>> new_staff = abjad.mutate.copy(old_staff)
>>> string = abjad.lilypond(new_staff, tags=True)
>>> print(string)
\new Staff
{
      %! M1
      %! RED
    %@% \clef "alto"
    c'4
    d'4
    e'4
    f'4
}
>>> leaf = new_staff[0]
>>> abjad.get.wrapper(leaf)
Wrapper(annotation=None, context='Staff', deactivate=True, direction=None, indicator=Clef(name='alto', hide=False), synthetic_offset=None, tag=Tag(string='RED:M1'))

Copies all properties except component.

Copy operations must supply component after wrapper copy.

Return type:

Wrapper

overridden __eq__(argument)[source]

Is true when self equals argument.

Return type:

bool

overridden __hash__()[source]

Hashes wrapper.

Return type:

int

overridden __repr__()[source]

Gets repr.

Return type:

str


Methods

bundled()[source]

Is true when indicator is bundled.

get_item()[source]

Gets indicator or bundled indicator.

unbundle_indicator()[source]

Gets unbundled indicator.


Read/write properties

deactivate

Is true when wrapper deactivates tag.

tag

Gets and sets tag.


Read-only properties

annotation

Gets wrapper annotation.

>>> note = abjad.Note("c'4")
>>> articulation = abjad.Articulation("accent")
>>> abjad.attach(articulation, note, direction=abjad.UP)
>>> wrapper = abjad.get.wrapper(note)
>>> wrapper.annotation is None
True
>>> note = abjad.Note("c'4")
>>> articulation = abjad.Articulation("accent")
>>> abjad.annotate(note, "foo", articulation)
>>> abjad.get.annotation(note, "foo")
Articulation(name='accent')
component

Gets start component.

Returns component or none.

context

Gets context (name).

direction

Gets direction of indicator.

indicator

Gets indicator.

leaked_start_offset

Gets start offset and checks to see whether indicator leaks to the right.

This is either the wrapper’s synthetic offset (if set); or the START offset of the wrapper’s component (if indicator DOES NOT leak); or else the STOP offset of the wrapper’s component (if indicator DOES leak).

Start- and stop-text-spans attach to the same leaf. But stop-text-span leaks to the right:

>>> voice = abjad.Voice("c'2 d'2")
>>> start_text_span = abjad.StartTextSpan()
>>> abjad.attach(start_text_span, voice[0])
>>> stop_text_span = abjad.StopTextSpan(leak=True)
>>> abjad.attach(stop_text_span, voice[0])
>>> abjad.show(voice)  
>>> string = abjad.lilypond(voice)
>>> print(string)
\new Voice
{
    c'2
    \startTextSpan
    <>
    \stopTextSpan
    d'2
}

Start offset and leaked start offset are the same for start-text-span:

>>> wrapper = abjad.get.wrapper(voice[0], abjad.StartTextSpan)
>>> wrapper.start_offset, wrapper.leaked_start_offset
(Offset((0, 1)), Offset((0, 1)))

Start offset and leaked start offset differ for stop-text-span:

>>> wrapper = abjad.get.wrapper(voice[0], abjad.StopTextSpan)
>>> wrapper.start_offset, wrapper.leaked_start_offset
(Offset((0, 1)), Offset((1, 2)))
site_adjusted_start_offset

Gets site-adjusted start offset.

>>> staff = abjad.Staff("c'4")
>>> abjad.attach(abjad.Ottava(-1, site="before"), staff[0])
>>> abjad.attach(abjad.Ottava(0, site="after"), staff[0])
>>> for wrapper in abjad.get.wrappers(staff[0], abjad.Ottava):
...     wrapper.indicator, wrapper.site_adjusted_start_offset
... 
(Ottava(n=-1, site='before'), Offset((0, 1)))
(Ottava(n=0, site='after'), Offset((1, 4)))

Indicators with site equal to absolute_after, after or closing give a site-adjusted start offset equal to the stop offset of the wrapper’s component.

Indicators with any other site give a site-adjusted start offset equal to the start offset of the wrapper’s component. This is the usual case, and means that site-adjusted start offset equals vanilla start offset.

But if synthetic_offset is set then synthetic_offset is returned directly without examining the format site at all.

start_offset

Gets start offset.

This is either the wrapper’s synthetic offset or the start offset of the wrapper’s component.

synthetic_offset

Gets synthetic offset.