Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of mmif rewinder #250

Closed
wants to merge 7 commits into from
1 change: 1 addition & 0 deletions mmif/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from mmif.utils import video_document_helper
from mmif.utils import rewinder
105 changes: 105 additions & 0 deletions mmif/utils/rewinder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import argparse
from pathlib import Path as P

import mmif


def is_valid_choice(choice):
try:
ichoice = int(choice)
if 0 <= ichoice:
return ichoice

Check warning on line 11 in mmif/utils/rewinder.py

View check run for this annotation

Codecov / codecov/patch

mmif/utils/rewinder.py#L8-L11

Added lines #L8 - L11 were not covered by tests
else:
raise ValueError(f"\nInvalid argument for -n. Please enter a positive integer.")
except ValueError:
raise argparse.ArgumentTypeError(f"\nInvalid argument for -n. Please enter a positive integer.")

Check warning on line 15 in mmif/utils/rewinder.py

View check run for this annotation

Codecov / codecov/patch

mmif/utils/rewinder.py#L13-L15

Added lines #L13 - L15 were not covered by tests

def user_choice(mmif_obj:mmif.Mmif) -> int:
"""
Function to ask user to choose the rewind range.

:param mmif_obj: mmif object
:return: int option number
"""

## Give a user options (#, "app", "timestamp") - time order
n = len(mmif_obj.views)
i = 0 # option number

Check warning on line 27 in mmif/utils/rewinder.py

View check run for this annotation

Codecov / codecov/patch

mmif/utils/rewinder.py#L26-L27

Added lines #L26 - L27 were not covered by tests
# header
print("\n" + "{:<4} {:<30} {:<100}".format("num", "timestamp", "app"))
for view in mmif_obj.views:
option = "{:<4} {:<30} {:<100}".format(n-i, str(view.metadata.timestamp), str(view.metadata.app))
print(option)
i += 1

Check warning on line 33 in mmif/utils/rewinder.py

View check run for this annotation

Codecov / codecov/patch

mmif/utils/rewinder.py#L29-L33

Added lines #L29 - L33 were not covered by tests

## User input
while True:
choice = int(input("\nEnter the number to delete from that point by rewinding: "))
try:
if 0 <= choice <= n:
return choice

Check warning on line 40 in mmif/utils/rewinder.py

View check run for this annotation

Codecov / codecov/patch

mmif/utils/rewinder.py#L37-L40

Added lines #L37 - L40 were not covered by tests
else:
print(f"\nInvalid choice. Please enter an integer in the range [0, {n}].")
except ValueError:
print("\nInvalid input. Please enter a valid number.")

Check warning on line 44 in mmif/utils/rewinder.py

View check run for this annotation

Codecov / codecov/patch

mmif/utils/rewinder.py#L42-L44

Added lines #L42 - L44 were not covered by tests


def rewind_mmif(mmif_obj: mmif.Mmif, choice: int, choice_is_viewnum: bool = True) -> mmif.Mmif:
"""
Rewind MMIF by deleting the last N views.
The number of views to rewind is given as a number of "views", or number of "producer apps".
By default, the number argument is interpreted as the number of "views".

:param mmif_obj: mmif object
:param choice: number of views to rewind
:param choice_is_viewnum: if True, choice is the number of views to rewind. If False, choice is the number of producer apps to rewind.
:return: rewound mmif object
"""
if choice_is_viewnum:
for vid in list(v.id for v in mmif_obj.views)[-1:-choice-1:-1]:
mmif_obj.views._items.pop(vid)

Check warning on line 60 in mmif/utils/rewinder.py

View check run for this annotation

Codecov / codecov/patch

mmif/utils/rewinder.py#L58-L60

Added lines #L58 - L60 were not covered by tests
else:
app_count = 0
cur_app = ""
vid_to_pop = []
for v in reversed(mmif_obj.views):
if app_count >= choice:
break
if v.metadata.app != cur_app:
app_count += 1
cur_app = v.metadata.app
vid_to_pop.append(v.id)
for vid in vid_to_pop:
mmif_obj.views._items.pop(vid)
return mmif_obj

Check warning on line 74 in mmif/utils/rewinder.py

View check run for this annotation

Codecov / codecov/patch

mmif/utils/rewinder.py#L62-L74

Added lines #L62 - L74 were not covered by tests


if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Process MMIF file.")
parser.add_argument("mmif_file", help="Path to the MMIF file")
parser.add_argument("-o", '--output', default="rewound.mmif", type=str, help="Path to the rewound MMIF output file (default: rewound.mmif)")
parser.add_argument("-p", '--pretty', action='store_true', help="Pretty print (default: pretty=True)")
parser.add_argument("-n", '--number', default="0", type=is_valid_choice, help="Number of views to rewind (default: 0)")
args = parser.parse_args()

Check warning on line 83 in mmif/utils/rewinder.py

View check run for this annotation

Codecov / codecov/patch

mmif/utils/rewinder.py#L78-L83

Added lines #L78 - L83 were not covered by tests

mmif_obj = mmif.Mmif(open(args.mmif_file).read())

Check warning on line 85 in mmif/utils/rewinder.py

View check run for this annotation

Codecov / codecov/patch

mmif/utils/rewinder.py#L85

Added line #L85 was not covered by tests

if args.number == 0: # If user doesn't know how many views to rewind, give them choices.
choice = user_choice(mmif_obj)

Check warning on line 88 in mmif/utils/rewinder.py

View check run for this annotation

Codecov / codecov/patch

mmif/utils/rewinder.py#L87-L88

Added lines #L87 - L88 were not covered by tests
else:
choice = args.number

Check warning on line 90 in mmif/utils/rewinder.py

View check run for this annotation

Codecov / codecov/patch

mmif/utils/rewinder.py#L90

Added line #L90 was not covered by tests


# Check if the same file name exist in the path and avoid overwriting.
output_fp = P(args.output)
if output_fp.is_file():
parent = output_fp.parent
stem = output_fp.stem
suffix = output_fp.suffix
count = 1
while (parent / f"{stem}_{count}{suffix}").is_file():
count += 1
output_fp = parent / f"{stem}_{count}{suffix}"

Check warning on line 102 in mmif/utils/rewinder.py

View check run for this annotation

Codecov / codecov/patch

mmif/utils/rewinder.py#L94-L102

Added lines #L94 - L102 were not covered by tests

with open(output_fp, 'w') as mmif_file:
mmif_file.write(rewind_mmif(mmif_obj, choice, args.output).serialize(pretty=args.pretty))

Check warning on line 105 in mmif/utils/rewinder.py

View check run for this annotation

Codecov / codecov/patch

mmif/utils/rewinder.py#L104-L105

Added lines #L104 - L105 were not covered by tests
Loading