wf


Functions

check_beamed_lone_notes

Checks beamed lone notes.

check_beamed_long_notes

Checks beamed long notes.

check_duplicate_ids

Checks duplicate IDs.

check_empty_containers

Checks empty containers.

check_missing_parents

Checks missing parents.

check_notes_on_wrong_clef

Checks notes and chords on wrong clef.

check_orphaned_dependent_wrappers

Checks orphaned dependent wrappers.

check_out_of_range_pitches

Checks out-of-range notes.

check_overlapping_beams

Checks overlapping beams.

check_overlapping_text_spanners

Checks overlapping text spanners.

check_unmatched_stop_text_spans

Checks unmatched stop text spans.

check_unterminated_hairpins

Checks unterminated hairpins.

check_unterminated_text_spanners

Checks unterminated text spanners.

tabulate_wellformedness

Tabulates wellformedness.

wellformed

Is true when component is wellformed.

abjad.wf.check_beamed_lone_notes(argument) tuple[list, int][source]

Checks beamed lone notes.

Beamed single notes are not wellformed:

>>> voice = abjad.Voice("c'8 d' e' f'")
>>> abjad.attach(abjad.StartBeam(), voice[0])
>>> abjad.attach(abjad.StopBeam(), voice[0])
>>> abjad.show(voice)  
>>> abjad.wf.check_beamed_lone_notes(voice)
([Note("c'8")], 4)

The examples above feature Abjad voice containers because beams are voice-persistent.

abjad.wf.check_beamed_long_notes(argument) tuple[list, int][source]

Checks beamed long notes.

Beamed quarter notes are not wellformed:

>>> voice = abjad.Voice("c'4 d'4 e'4 f'4")
>>> abjad.attach(abjad.StartBeam(), voice[0])
>>> abjad.attach(abjad.StopBeam(), voice[1])
>>> abjad.show(voice)  
>>> abjad.wf.check_beamed_long_notes(voice)
([Note("c'4"), Note("d'4")], 4)

Beamed eighth notes are wellformed:

>>> voice = abjad.Voice("c'8 d'8 e'8 f'8")
>>> abjad.attach(abjad.StartBeam(), voice[0])
>>> abjad.attach(abjad.StopBeam(), voice[1])
>>> abjad.show(voice)  
>>> abjad.wf.check_beamed_long_notes(voice)
([], 4)

The examples above feature Abjad voice containers because beams are voice-persistent.

abjad.wf.check_duplicate_ids(argument) tuple[list, int][source]

Checks duplicate IDs.

abjad.wf.check_empty_containers(argument) tuple[list, int][source]

Checks empty containers.

>>> staff = abjad.Staff("c'4 d' e' f'")
>>> staff.append(abjad.Container())
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
    c'4
    d'4
    e'4
    f'4
    {
    }
}
>>> violators, total = abjad.wf.check_empty_containers(staff)
>>> violators
[Container()]
abjad.wf.check_missing_parents(argument) tuple[list, int][source]

Checks missing parents.

abjad.wf.check_notes_on_wrong_clef(argument) tuple[list, int][source]

Checks notes and chords on wrong clef.

>>> staff = abjad.Staff("c'8 d'8 e'8 f'8")
>>> clef = abjad.Clef("alto")
>>> abjad.attach(clef, staff[0])
>>> violin = abjad.Violin()
>>> abjad.attach(violin, staff[0])
>>> abjad.show(staff)  
>>> abjad.wf.check_notes_on_wrong_clef(staff)
([Note("c'8"), Note("d'8"), Note("e'8"), Note("f'8")], 4)

All instruments allow percussion clef:

>>> staff = abjad.Staff("c'8 d'8 e'8 f'8")
>>> clef = abjad.Clef("percussion")
>>> abjad.attach(clef, staff[0])
>>> violin = abjad.Violin()
>>> abjad.attach(violin, staff[0])
>>> abjad.show(staff)  
>>> abjad.wf.check_notes_on_wrong_clef(staff)
([], 4)
abjad.wf.check_orphaned_dependent_wrappers(argument) tuple[list, int][source]

Checks orphaned dependent wrappers.

This should normally never happen because Abjad manages dependent wrappers behind the scenes.

This check exists to make sure that any new code added to Abjad doesn’t accidentally mangle dependent-wrapper handling.

>>> voice = abjad.Voice("c'8 [ d' e' f'")
>>> assert len(voice._dependent_wrappers) == 1
>>> wrapper = voice._dependent_wrappers[0]
>>> wrapper
Wrapper(annotation=None, context='Voice', deactivate=False, direction=None, indicator=StartBeam(), synthetic_offset=None, tag=Tag(string=''))
>>> wrapper.component
Note("c'8")
>>> abjad.wf.check_orphaned_dependent_wrappers(voice)
([], 1)
>>> voice[0:1] = [abjad.Note("cs'8")]
>>> voice._dependent_wrappers
[]
>>> abjad.wf.check_orphaned_dependent_wrappers(voice)
([], 0)
>>> voice._dependent_wrappers.append(wrapper)
>>> assert len(voice._dependent_wrappers) == 1
>>> assert wrapper.component not in voice
>>> abjad.wf.check_orphaned_dependent_wrappers(voice)
([Wrapper(annotation=None, context='Voice', deactivate=False, direction=None, indicator=StartBeam(), synthetic_offset=None, tag=Tag(string=''))], 1)
abjad.wf.check_out_of_range_pitches(argument, *, allow_indicators: Sequence[str | Enum] = ()) tuple[list, int][source]

Checks out-of-range notes.

Out of range:

>>> staff = abjad.Staff("c'8 r8 <d fs>8 r8")
>>> violin = abjad.Violin()
>>> abjad.attach(violin, staff[0])
>>> abjad.show(staff)  
>>> abjad.wf.check_out_of_range_pitches(staff)
([Chord('<d fs>8')], 2)

Using allow_indicators:

>>> staff = abjad.Staff("c'8 r8 <d fs>8 r8")
>>> violin = abjad.Violin()
>>> abjad.attach(violin, staff[0])
>>> abjad.attach("ALLOW_OUT_OF_RANGE", staff[2])
>>> abjad.show(staff)  

Does not check for indicator:

>>> violators, total = abjad.wf.check_out_of_range_pitches(staff)
>>> violators
[Chord('<d fs>8')]

Does check for indicator:

>>> violators, total = abjad.wf.check_out_of_range_pitches(
...     staff, allow_indicators=["ALLOW_OUT_OF_RANGE"]
... )
>>> violators
[]
abjad.wf.check_overlapping_beams(argument) tuple[list, int][source]

Checks overlapping beams.

>>> voice = abjad.Voice("c'8 [ d' [ e' f' ]")
>>> string = abjad.lilypond(voice)
>>> print(string)
\new Voice
{
    c'8
    [
    d'8
    [
    e'8
    f'8
    ]
}
>>> abjad.wf.check_overlapping_beams(voice)
([Note("d'8")], 3)
>>> voice = abjad.Voice("c'8 [ d' [ e' ] f' ]")
>>> string = abjad.lilypond(voice)
>>> print(string)
\new Voice
{
    c'8
    [
    d'8
    [
    e'8
    ]
    f'8
    ]
}
>>> abjad.wf.check_overlapping_beams(voice)
([Note("d'8")], 4)
>>> voice = abjad.Voice("c'8 [ d' e' f' ]")
>>> string = abjad.lilypond(voice)
>>> print(string)
\new Voice
{
    c'8
    [
    d'8
    e'8
    f'8
    ]
}
>>> abjad.wf.check_overlapping_beams(voice)
([], 2)
abjad.wf.check_overlapping_text_spanners(argument) tuple[list, int][source]

Checks overlapping text spanners.

Overlapping text spanners are not wellformed:

>>> voice = abjad.Voice("c'4 d' e' f'")
>>> abjad.text_spanner(voice)
>>> abjad.text_spanner(voice[1:3])
>>> string = abjad.lilypond(voice)
>>> print(string)
\new Voice
{
    c'4
    \startTextSpan
    d'4
    \startTextSpan
    e'4
    \stopTextSpan
    f'4
    \stopTextSpan
}
>>> abjad.wf.check_overlapping_text_spanners(voice)
([Note("d'4")], 2)

Overlapping text spanners with different IDs are wellformed:

>>> voice = abjad.Voice("c'4 d' e' f'")
>>> abjad.text_spanner(voice)
>>> command = r"\startTextSpanOne"
>>> start_text_span = abjad.StartTextSpan(command=command)
>>> abjad.attach(start_text_span, voice[1])
>>> command = r"\stopTextSpanOne"
>>> stop_text_span = abjad.StopTextSpan(command=command)
>>> abjad.attach(stop_text_span, voice[2])
>>> string = abjad.lilypond(voice)
>>> print(string)
\new Voice
{
    c'4
    \startTextSpan
    d'4
    \startTextSpanOne
    e'4
    \stopTextSpanOne
    f'4
    \stopTextSpan
}
>>> abjad.wf.check_overlapping_text_spanners(voice)
([], 2)

Enchained text spanners do not overlap (and are wellformed):

>>> voice = abjad.Voice("c'4 d' e' f'")
>>> abjad.text_spanner(voice[:3])
>>> abjad.text_spanner(voice[-2:])
>>> string = abjad.lilypond(voice)
>>> print(string)
\new Voice
{
    c'4
    \startTextSpan
    d'4
    e'4
    \stopTextSpan
    \startTextSpan
    f'4
    \stopTextSpan
}
>>> abjad.wf.check_overlapping_text_spanners(voice)
([], 2)

REGRESSION. Matching start- and stop-text-spans on a single leaf do not overlap (and are wellformed) iff stop-text-span leaks to the right:

>>> voice = abjad.Voice("c'2 d'2 e'2 f'2")
>>> abjad.attach(abjad.StartTextSpan(), voice[0])
>>> stop_text_span = abjad.StopTextSpan(leak=True)
>>> abjad.attach(stop_text_span, voice[0])
>>> abjad.attach(abjad.StartTextSpan(), voice[2])
>>> stop_text_span = abjad.StopTextSpan()
>>> abjad.attach(stop_text_span, voice[3])
>>> abjad.show(voice)  
>>> string = abjad.lilypond(voice)
>>> print(string)
\new Voice
{
    c'2
    \startTextSpan
    <>
    \stopTextSpan
    d'2
    e'2
    \startTextSpan
    f'2
    \stopTextSpan
}
>>> abjad.wf.check_overlapping_text_spanners(voice)
([], 2)
abjad.wf.check_unmatched_stop_text_spans(argument) tuple[list, int][source]

Checks unmatched stop text spans.

Unmatched stop text span is not wellformed:

>>> voice = abjad.Voice("c'4 c'4 c'4 c'4")
>>> stop_text_span = abjad.StopTextSpan()
>>> abjad.attach(stop_text_span, voice[-1])
>>> string = abjad.lilypond(voice)
>>> print(string)
\new Voice
{
    c'4
    c'4
    c'4
    c'4
    \stopTextSpan
}
>>> abjad.wf.check_unmatched_stop_text_spans(voice)
([Note("c'4")], 0)

Matched stop text span is wellformed:

>>> voice = abjad.Voice("c'4 c'4 c'4 c'4")
>>> start_text_span = abjad.StartTextSpan()
>>> abjad.attach(start_text_span, voice[0])
>>> stop_text_span = abjad.StopTextSpan()
>>> abjad.attach(stop_text_span, voice[-1])
>>> abjad.show(voice)  
>>> abjad.wf.wellformed(voice)
True
abjad.wf.check_unterminated_hairpins(argument) tuple[list, int][source]

Checks unterminated hairpins.

Unterminated crescendo is not wellformed:

>>> voice = abjad.Voice("c'4 c'4 c'4 c'4")
>>> start_hairpin = abjad.StartHairpin("<")
>>> abjad.attach(start_hairpin, voice[0])
>>> string = abjad.lilypond(voice)
>>> print(string)
\new Voice
{
    c'4
    \<
    c'4
    c'4
    c'4
}
>>> abjad.wf.check_unterminated_hairpins(voice)
([Note("c'4")], 1)

Even with start dynamic:

>>> voice = abjad.Voice("c'4 c'4 c'4 c'4")
>>> dynamic = abjad.Dynamic("f")
>>> abjad.attach(dynamic, voice[0])
>>> start_hairpin = abjad.StartHairpin("<")
>>> abjad.attach(start_hairpin, voice[0])
>>> string = abjad.lilypond(voice)
>>> print(string)
\new Voice
{
    c'4
    \f
    \<
    c'4
    c'4
    c'4
}
>>> abjad.wf.check_unterminated_hairpins(voice)
([Note("c'4")], 1)

Terminated crescendo is wellformed:

>>> voice = abjad.Voice("c'4 c'4 c'4 c'4")
>>> start_hairpin = abjad.StartHairpin("<")
>>> abjad.attach(start_hairpin, voice[0])
>>> dynamic = abjad.Dynamic("f")
>>> abjad.attach(dynamic, voice[-1])
>>> abjad.show(voice)  
>>> abjad.wf.wellformed(voice)
True

Bang-terminated crescendo is wellformed:

>>> voice = abjad.Voice("c'4 c'4 c'4 c'4")
>>> start_hairpin = abjad.StartHairpin("<")
>>> abjad.attach(start_hairpin, voice[0])
>>> stop_hairpin = abjad.StopHairpin()
>>> abjad.attach(stop_hairpin, voice[-1])
>>> abjad.show(voice)  
>>> abjad.wf.wellformed(voice)
True
abjad.wf.check_unterminated_text_spanners(argument) tuple[list, int][source]

Checks unterminated text spanners.

Unterminated text spanner is not wellformed:

>>> voice = abjad.Voice("c'4 c'4 c'4 c'4")
>>> start_text_span = abjad.StartTextSpan()
>>> abjad.attach(start_text_span, voice[0])
>>> string = abjad.lilypond(voice)
>>> print(string)
\new Voice
{
    c'4
    \startTextSpan
    c'4
    c'4
    c'4
}
>>> abjad.wf.check_unterminated_text_spanners(voice)
([Note("c'4")], 1)

Terminated text span is wellformed:

>>> voice = abjad.Voice("c'4 c'4 c'4 c'4")
>>> start_text_span = abjad.StartTextSpan()
>>> abjad.attach(start_text_span, voice[0])
>>> stop_text_span = abjad.StopTextSpan()
>>> abjad.attach(stop_text_span, voice[-1])
>>> abjad.show(voice)  
>>> abjad.wf.wellformed(voice)
True
abjad.wf.tabulate_wellformedness(component, check_beamed_lone_notes: bool = True, check_beamed_long_notes: bool = True, check_duplicate_ids: bool = True, check_empty_containers: bool = True, check_missing_parents: bool = True, check_notes_on_wrong_clef: bool = True, check_orphaned_dependent_wrappers: bool = True, check_out_of_range_pitches: bool = True, check_overlapping_beams: bool = True, check_overlapping_text_spanners: bool = True, check_unmatched_stop_text_spans: bool = True, check_unterminated_hairpins: bool = True, check_unterminated_text_spanners: bool = True) tuple[int, str][source]

Tabulates wellformedness.

abjad.wf.wellformed(component, check_beamed_lone_notes: bool = True, check_beamed_long_notes: bool = True, check_duplicate_ids: bool = True, check_empty_containers: bool = True, check_missing_parents: bool = True, check_notes_on_wrong_clef: bool = True, check_orphaned_dependent_wrappers: bool = True, check_out_of_range_pitches: bool = True, check_overlapping_beams: bool = True, check_overlapping_text_spanners: bool = True, check_unmatched_stop_text_spans: bool = True, check_unterminated_hairpins: bool = True, check_unterminated_text_spanners: bool = True) bool[source]

Is true when component is wellformed.