<commit_before># -*- encoding: utf-8 -*-
from __future__ import print_function
import collections
import copy
from abjad import attach
from abjad import new
from abjad.tools import datastructuretools
from abjad.tools import scoretools
from abjad.tools import selectortools
from abjad.tools import sequencetools
from abjad.tools import spannertools
from consort.tools.HashCachingObject import HashCachingObject


class AttachmentExpression(HashCachingObject):
    r'''An attachment specifier.

    ..  container:: example

        ::

            >>> import consort
            >>> attachment_expression = consort.AttachmentExpression(
            ...     attachments=(indicatortools.Articulation('>'),),
            ...     selector=selectortools.Selector().by_leaves().by_run(Note)[0],
            ...     )
            >>> print(format(attachment_expression))
            consort.tools.AttachmentExpression(
                attachments=datastructuretools.TypedList(
                    [
                        indicatortools.Articulation('>'),
                        ]
                    ),
                selector=selectortools.Selector(
                    callbacks=(
                        selectortools.PrototypeSelectorCallback(
                            prototype=scoretools.Leaf,
                            ),
                        selectortools.RunSelectorCallback(
                            prototype=scoretools.Note,
                            ),
                        selectortools.ItemSelectorCallback(
                            item=0,
                            apply_to_each=True,
                            ),
                        ),
                    ),
                )

        ::

            >>> attachment_expression = consort.AttachmentExpression(
            ...     attachments=(
            ...         consort.SimpleDynamicExpression(
            ...             hairpin_start_token='sfz',
            ...             hairpin_stop_token='o',
            ...             ),
            ...         ),
            ...     selector=selectortools.Selector().by_leaves().by_run(Note),
            ...     )

        ::

            >>> staff = Staff("c'8 r8 d'8 e'8 r8 f'8 g'8 a'8")
            >>> attachment_expression(staff)
            >>> print(format(staff))
            \new Staff {
                c'8 \sfz
                r8
                \override Hairpin #'circled-tip = ##t
                d'8 \> \sfz
                e'8 \!
                \revert Hairpin #'circled-tip
                r8
                \override Hairpin #'circled-tip = ##t
                f'8 \> \sfz
                g'8
                a'8 \!
                \revert Hairpin #'circled-tip
            }

    ..  container:: example

        ::

            >>> attachment_expression = consort.AttachmentExpression(
            ...     attachments=spannertools.Slur(),
            ...     )
            >>> staff = Staff("c'4 d'4 e'4 f'4")
            >>> attachment_expression(staff)
            >>> print(format(staff))
            \new Staff {
                c'4 (
                d'4
                e'4
                f'4 )
            }

    '''

    ### CLASS VARIABLES ###

    __slots__ = (
        '_attachments',
        '_scope',
        '_selector',
        '_is_annotation',
        )

    ### INITIALIZER ###

    def __init__(
        self,
        attachments=None,
        selector=None,
        scope=None,
        is_annotation=None,
        ):
        HashCachingObject.__init__(self)
        if attachments is not None:
            if not isinstance(attachments, collections.Sequence):
                attachments = (attachments,)
            attachments = datastructuretools.TypedList(attachments)
        self._attachments = attachments
        if selector is not None:
            assert isinstance(selector, selectortools.Selector)
        self._selector = selector
        if scope is not None:
            if isinstance(scope, type):
                assert issubclass(scope, scoretools.Component)
            else:
                assert isinstance(scope, (scoretools.Component, str))
        self._scope = scope
        if is_annotation is not None:
            is_annotation = bool(is_annotation)
        self._is_annotation = is_annotation

    ### PUBLIC METHODS ###

    def __call__(
        self,
        music,
        name=None,
        rotation=0,
        ):
        if not self.attachments:
            return
        all_attachments = datastructuretools.CyclicTuple(self.attachments)
        selector = self.selector
        if selector is None:
            selector = selectortools.Selector()
        selections = selector(music)
        for i, selection in enumerate(selections, rotation):
            attachments = all_attachments[i]
            #print(i, selection)
            if attachments is None:
                continue
            if not isinstance(attachments, tuple):
                attachments = (attachments,)
            for attachment in attachments:
                #print('\t' + repr(attachment))
                # spanners
                if isinstance(attachment, spannertools.Spanner):
                    attachment = copy.copy(attachment)
                    attach(attachment, selection, name=name)
                elif isinstance(attachment, type) and \
                    issubclass(attachment, spannertools.Spanner):
                    attachment = attachment()
                    attach(attachment, selection, name=name)
                # expressions
                elif hasattr(attachment, '__call__'):
                    try:
                        attachment(selection, rotation=rotation, name=name)
                    except TypeError:
                        try:
                            attachment(selection, name=name)
                        except TypeError:
                            raise AttributeError(attachment)
                # indicators
                else:
                    if isinstance(selection, scoretools.Leaf):
                        selection = (selection,)
                    for component in selection:
                        attachment = copy.copy(attachment)<commit_msg>AttachmentExpression now handles seed= and rotation=.<commit_after># -*- encoding: utf-8 -*-
from __future__ import print_function
import collections
import copy
import funcsigs
from abjad import attach
from abjad import new
from abjad.tools import datastructuretools
from abjad.tools import scoretools
from abjad.tools import selectortools
from abjad.tools import sequencetools
from abjad.tools import spannertools
from consort.tools.HashCachingObject import HashCachingObject


class AttachmentExpression(HashCachingObject):
    r'''An attachment specifier.

    ..  container:: example

        ::

            >>> import consort
            >>> attachment_expression = consort.AttachmentExpression(
            ...     attachments=(indicatortools.Articulation('>'),),
            ...     selector=selectortools.Selector().by_leaves().by_run(Note)[0],
            ...     )
            >>> print(format(attachment_expression))
            consort.tools.AttachmentExpression(
                attachments=datastructuretools.TypedList(
                    [
                        indicatortools.Articulation('>'),
                        ]
                    ),
                selector=selectortools.Selector(
                    callbacks=(
                        selectortools.PrototypeSelectorCallback(
                            prototype=scoretools.Leaf,
                            ),
                        selectortools.RunSelectorCallback(
                            prototype=scoretools.Note,
                            ),
                        selectortools.ItemSelectorCallback(
                            item=0,
                            apply_to_each=True,
                            ),
                        ),
                    ),
                )

        ::

            >>> attachment_expression = consort.AttachmentExpression(
            ...     attachments=(
            ...         consort.SimpleDynamicExpression(
            ...             hairpin_start_token='sfz',
            ...             hairpin_stop_token='o',
            ...             ),
            ...         ),
            ...     selector=selectortools.Selector().by_leaves().by_run(Note),
            ...     )

        ::

            >>> staff = Staff("c'8 r8 d'8 e'8 r8 f'8 g'8 a'8")
            >>> attachment_expression(staff)
            >>> print(format(staff))
            \new Staff {
                c'8 \sfz
                r8
                \override Hairpin #'circled-tip = ##t
                d'8 \> \sfz
                e'8 \!
                \revert Hairpin #'circled-tip
                r8
                \override Hairpin #'circled-tip = ##t
                f'8 \> \sfz
                g'8
                a'8 \!
                \revert Hairpin #'circled-tip
            }

    ..  container:: example

        ::

            >>> attachment_expression = consort.AttachmentExpression(
            ...     attachments=spannertools.Slur(),
            ...     )
            >>> staff = Staff("c'4 d'4 e'4 f'4")
            >>> attachment_expression(staff)
            >>> print(format(staff))
            \new Staff {
                c'4 (
                d'4
                e'4
                f'4 )
            }

    '''

    ### CLASS VARIABLES ###

    __slots__ = (
        '_attachments',
        '_scope',
        '_selector',
        '_is_annotation',
        )

    ### INITIALIZER ###

    def __init__(
        self,
        attachments=None,
        selector=None,
        scope=None,
        is_annotation=None,
        ):
        HashCachingObject.__init__(self)
        if attachments is not None:
            if not isinstance(attachments, collections.Sequence):
                attachments = (attachments,)
            attachments = datastructuretools.TypedList(attachments)
        self._attachments = attachments
        if selector is not None:
            assert isinstance(selector, selectortools.Selector)
        self._selector = selector
        if scope is not None:
            if isinstance(scope, type):
                assert issubclass(scope, scoretools.Component)
            else:
                assert isinstance(scope, (scoretools.Component, str))
        self._scope = scope
        if is_annotation is not None:
            is_annotation = bool(is_annotation)
        self._is_annotation = is_annotation

    ### PUBLIC METHODS ###

    def __call__(
        self,
        music,
        name=None,
        rotation=0,
        ):
        if not self.attachments:
            return
        all_attachments = datastructuretools.CyclicTuple(self.attachments)
        selector = self.selector
        if selector is None:
            selector = selectortools.Selector()
        selections = selector(music)
        for i, selection in enumerate(selections, rotation):
            attachments = all_attachments[i]
            #print(i, selection)
            if attachments is None:
                continue
            if not isinstance(attachments, tuple):
                attachments = (attachments,)
            for attachment in attachments:
                #print('\t' + repr(attachment))
                # spanners
                if isinstance(attachment, spannertools.Spanner):
                    attachment = copy.copy(attachment)
                    attach(attachment, selection, name=name)
                elif isinstance(attachment, type) and \
                    issubclass(attachment, spannertools.Spanner):
                    attachment = attachment()
                    attach(attachment, selection, name=name)
                # expressions
                elif hasattr(attachment, '__call__'):
                    signature = funcsigs.signature(attachment.__call__)
                    if 'seed' in signature.parameters:
                        attachment(selection, seed=rotation, name=name)
                    elif 'rotation' in signature.parameters:
                        attachment(selection, rotation=rotation, name=name)
                    else:
                        attachment(selection, name=name)
                # indicators
                else:
                    if isinstance(selection, scoretools.Leaf):
                        selection = (selection,)
                    for component in selection:
                        attachment = copy.copy(attachment)
{'fraction_non_alphanumeric': 0.08783622946917401, 'fraction_numerical': 0.004443386495278902, 'mean_word_length': 1.305890962312477, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 77, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2255261', 'n_tokens_mistral': 3078, 'n_tokens_neox': 2907, 'n_words': 614}