Skip to content

Commit

Permalink
Fixed leaf split bug. Closes #1018.
Browse files Browse the repository at this point in the history
  • Loading branch information
trevorbaca committed Aug 21, 2018
1 parent 39efe28 commit 791b897
Show file tree
Hide file tree
Showing 18 changed files with 387 additions and 292 deletions.
54 changes: 8 additions & 46 deletions abjad/core/Container.py
Original file line number Diff line number Diff line change
Expand Up @@ -1043,10 +1043,8 @@ def _split_by_duration(
tie_split_notes=tie_split_notes,
repeat_ties=repeat_ties,
)
# check input
duration = Duration(duration)
assert 0 <= duration, repr(duration)
# if zero duration then return empty list and self
if duration == 0:
return [], self
# get split point score offset
Expand All @@ -1061,44 +1059,6 @@ def _split_by_duration(
stop_offset = timespan.stop_offset
if start_offset < cross_offset < stop_offset:
duration_crossing_descendants.append(descendant)
# get any duration-crossing measure descendents
measures = []
# if we must split a power-of-two measure at non-power-of-two
# split point then go ahead and transform the power-of-two measure
# to non-power-of-two equivalent now;
# code that crawls and splits later on will be happier
if len(measures) == 1:
raise Exception('measures no longer exist')
measure = measures[0]
timespan = inspect(measure).timespan()
start_offset = timespan.start_offset
split_point_in_measure = global_split_point - start_offset
if measure.has_non_power_of_two_denominator:
pass
elif not mathtools.is_nonnegative_integer_power_of_two(
split_point_in_measure.denominator):
non_power_of_two_factors = self._remove_powers_of_two(
split_point_in_measure.denominator
)
non_power_of_two_factors = mathtools.factors(
non_power_of_two_factors)
non_power_of_two_product = 1
for non_power_of_two_factor in non_power_of_two_factors:
non_power_of_two_product *= non_power_of_two_factor
measure._scale_denominator(non_power_of_two_product)
# rederive duration crossers with possibly new measure contents
timespan = inspect(self).timespan()
cross_offset = timespan.start_offset + duration
duration_crossing_descendants = []
for descendant in inspect(self).descendants():
timespan = inspect(descendant).timespan()
start_offset = timespan.start_offset
stop_offset = timespan.stop_offset
if start_offset < cross_offset < stop_offset:
duration_crossing_descendants.append(descendant)
elif 1 < len(measures):
raise Exception('measures no longer exist')
raise Exception('measures can not nest.')
# any duration-crossing leaf will be at end of list
bottom = duration_crossing_descendants[-1]
did_split_leaf = False
Expand All @@ -1109,15 +1069,18 @@ def _split_by_duration(
timespan = inspect(bottom).timespan()
start_offset = timespan.start_offset
split_point_in_bottom = global_split_point - start_offset
left_list, right_list = bottom._split_by_durations(
new_leaves = bottom._split_by_durations(
[split_point_in_bottom],
fracture_spanners=fracture_spanners,
tie_split_notes=tie_split_notes,
repeat_ties=repeat_ties,
)
right = right_list[0]
leaf_right_of_split = right
leaf_left_of_split = left_list[-1]
for leaf in new_leaves:
timespan = inspect(leaf).timespan()
if timespan.stop_offset == global_split_point:
leaf_left_of_split = leaf
if timespan.start_offset == global_split_point:
leaf_right_of_split = leaf
duration_crossing_containers = duration_crossing_descendants[:-1]
if not len(duration_crossing_containers):
return left_list, right_list
Expand Down Expand Up @@ -1146,8 +1109,7 @@ def _split_by_duration(
highest_level_component_right_of_split = component
break
else:
message = 'should not be able to get here.'
raise ValueError(message)
raise ValueError('should not be able to get here.')
# crawl back up through duration-crossing containers
# and fracture spanners if requested
if fracture_spanners:
Expand Down
6 changes: 3 additions & 3 deletions abjad/core/Leaf.py
Original file line number Diff line number Diff line change
Expand Up @@ -584,9 +584,9 @@ def _split_by_durations(
result_leaves._attach_tie_to_leaves(
repeat_ties=repeat_ties,
)
assert isinstance(result_selections, list), repr(result_selections)
assert all(isinstance(_, abjad.Selection) for _ in result_selections)
return result_selections
assert isinstance(result_leaves, abjad.Selection)
assert all(isinstance(_, abjad.Leaf) for _ in result_leaves)
return result_leaves

### PRIVATE PROPERTIES ###

Expand Down
4 changes: 3 additions & 1 deletion abjad/system/IOManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ def open_file(
*,
application: str = None,
line_number: int = None,
test: bool = None,
):
"""
Opens ``file_path``.
Expand Down Expand Up @@ -460,7 +461,8 @@ def open_file(
command = f'{viewer} +{line_number} {file_path}'
else:
command = f'{viewer} {file_path}'
IOManager.spawn_subprocess(command)
if not test:
IOManager.spawn_subprocess(command)

@staticmethod
def open_last_log() -> None:
Expand Down
16 changes: 9 additions & 7 deletions abjad/top/play.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
def play(argument):
r"""
import typing
from .persist import persist


def play(argument: typing.Any, test: bool = None) -> None:
"""
Plays ``argument``.
.. container:: example
Expand All @@ -14,13 +18,11 @@ def play(argument):
Appends ``.midi`` filename extension under other operating systems.
Opens MIDI file.
Returns none.
"""
import abjad
from abjad import abjad_configuration
from abjad.system.IOManager import IOManager
assert hasattr(argument, '__illustrate__')
result = abjad.persist(argument).as_midi()
result = persist(argument).as_midi()
midi_file_path = result[0]
midi_player = abjad_configuration['midi_player']
abjad.IOManager.open_file(midi_file_path, midi_player)
IOManager.open_file(midi_file_path, application=midi_player, test=test)
38 changes: 22 additions & 16 deletions scr/devel/fix-tests
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,13 @@ def fix_test_case_names():
result
total_test_cases += total_test_cases_in_module
total_nonmatching_names += total_nonmatching_names_in_module
print('Total test modules: {}'.format(total_test_modules))
print('Total test cases: {}'.format(total_test_cases))
print(f'Total test modules: {total_test_modules}')
print(f'Total test cases: {total_test_cases}')
if total_nonmatching_names == 1:
suffix = ''
else:
suffix = 's'
print('Total misnamed test case name{}: {}'.format(
suffix, total_nonmatching_names))
print(f'Total misnamed test case name{suffix}: {total_nonmatching_names}')


def process_test_module_name_fixes(test_module, directory):
Expand All @@ -40,7 +39,8 @@ def process_test_module_name_fixes(test_module, directory):
with open(full_module_name, 'r') as file_pointer:
lines = file_pointer.readlines()
for line in lines:
if line.startswith('def test') or line.startswith('#def test'):
if ((line.startswith('def test') or line.startswith('#def test')) and
'init' not in line):
test_cases_in_current_module += 1

# TODO: replace with regex
Expand All @@ -60,11 +60,13 @@ def process_test_module_name_fixes(test_module, directory):

if not actual_test_case_prefix == desired_test_case_prefix:
total_nonmatching_names_in_current_module += 1
print('NONMATCHING in {}'.format(test_module))
print(f'NONMATCHING in {test_module}')
new_line = line.replace(
actual_test_case_prefix, desired_test_case_prefix)
print('OLD LINE: {}'.format(line.strip('\n')))
print('NEW LINE: {}'.format(new_line.strip('\n')))
stripped_line = line.strip('\n')
stripped_new_line = new_line.strip('\n')
print(f"OLD LINE: {stripped_line}")
print(f"NEW LINE: {stripped_new_line}")
choice = 'y'
if choice.lower() == 'y':
new_lines.append(new_line)
Expand Down Expand Up @@ -100,14 +102,15 @@ def fix_test_case_numbers():
misnumbered_cases_in_current_module = result[1]
total_test_cases += test_cases_in_current_module
total_misnumbered_cases += misnumbered_cases_in_current_module
print('Total test modules: {}'.format(total_test_modules))
print('Total test cases: {}'.format(total_test_cases))
print(f'Total test modules: {total_test_modules}')
print(f'Total test cases: {total_test_cases}')
if total_misnumbered_cases == 1:
suffix = ''
else:
suffix = 's'
print('Total misnumbered test case name{}: {}'.format(
suffix, total_misnumbered_cases))
print(
f'Total misnumbered test case name{suffix}: {total_misnumbered_cases}'
)


def process_test_module_number_fixes(test_module, directory):
Expand All @@ -121,7 +124,8 @@ def process_test_module_number_fixes(test_module, directory):
lines = file_pointer.readlines()
current_case_number = 1
for line in lines:
if line.startswith('def test') or line.startswith('#def test'):
if ((line.startswith('def test') or line.startswith('#def test')) and
'init' not in line):
test_cases_in_current_module += 1
desired_test_case_number = str(current_case_number).zfill(2)

Expand All @@ -131,11 +135,13 @@ def process_test_module_number_fixes(test_module, directory):

if not actual_test_case_number == desired_test_case_number:
misnumbered_cases_in_current_module += 1
print('NONMATCHING in {}'.format(test_module))
print(f'NONMATCHING in {test_module}')
new_line = line.replace(
actual_test_case_number, desired_test_case_number)
print('OLD LINE: {}'.format(line.strip('\n')))
print('NEW LINE: {}'.format(new_line.strip('\n')))
stripped_line = line.strip('\n')
stripped_new_line = new_line.strip('\n')
print(f"OLD LINE: {stripped_line}")
print(f"NEW LINE: {stripped_new_line}")
choice = 'y'
if choice.lower() == 'y':
new_lines.append(new_line)
Expand Down
Loading

0 comments on commit 791b897

Please sign in to comment.