diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index abcf070..c8dded9 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -16,7 +16,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: [3.7, 3.8, 3.9] + python-version: [3.7, 3.8, 3.9, "3.10"] steps: - uses: actions/checkout@v2 diff --git a/.gitignore b/.gitignore index ac58e49..e7ef7c4 100644 --- a/.gitignore +++ b/.gitignore @@ -104,3 +104,4 @@ venv.bak/ .mypy_cache/ .DS_Store /example/Charade/Session File Backups/ +lcov.info diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index a566bfe..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ - -# Default ignored files -/workspace.xml -/tasks.xml diff --git a/.idea/dictionaries/jamie.xml b/.idea/dictionaries/jamie.xml deleted file mode 100644 index 07f35a2..0000000 --- a/.idea/dictionaries/jamie.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - adlib - bottompadding - fmpxml - futura - leftpadding - lineafter - linebefore - ptulsconv - retval - smpte - subheader - timecode - timespan - - - \ No newline at end of file diff --git a/.idea/dictionaries/jamiehardt.xml b/.idea/dictionaries/jamiehardt.xml deleted file mode 100644 index 8339c00..0000000 --- a/.idea/dictionaries/jamiehardt.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - fmpxmlresult - frac - mins - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2d..0000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index ce59ae2..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 922e7b3..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/ptulsconv.iml b/.idea/ptulsconv.iml deleted file mode 100644 index cd0c393..0000000 --- a/.idea/ptulsconv.iml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/shelf/Uncommitted_changes_before_Update_at_5_20_21,_8_09_PM_[Default_Changelist]/Charade.ptx b/.idea/shelf/Uncommitted_changes_before_Update_at_5_20_21,_8_09_PM_[Default_Changelist]/Charade.ptx deleted file mode 100644 index e3cb912..0000000 Binary files a/.idea/shelf/Uncommitted_changes_before_Update_at_5_20_21,_8_09_PM_[Default_Changelist]/Charade.ptx and /dev/null differ diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/ptulsconv/__init__.py b/ptulsconv/__init__.py index 8bb00ec..fc5dc5d 100644 --- a/ptulsconv/__init__.py +++ b/ptulsconv/__init__.py @@ -1,5 +1,5 @@ from ptulsconv.docparser.ptuls_grammar import protools_text_export_grammar -__version__ = '0.8.2' +__version__ = '0.8.3' __author__ = 'Jamie Hardt' __license__ = 'MIT' diff --git a/ptulsconv/broadcast_timecode.py b/ptulsconv/broadcast_timecode.py index 46bbc78..c0c6366 100644 --- a/ptulsconv/broadcast_timecode.py +++ b/ptulsconv/broadcast_timecode.py @@ -2,13 +2,16 @@ from fractions import Fraction import re import math from collections import namedtuple - +from typing import Optional class TimecodeFormat(namedtuple("_TimecodeFormat", "frame_duration logical_fps drop_frame")): - def smpte_to_seconds(self, smpte: str) -> Fraction: + def smpte_to_seconds(self, smpte: str) -> Optional[Fraction]: frame_count = smpte_to_frame_count(smpte, self.logical_fps, drop_frame_hint=self.drop_frame) - return frame_count * self.frame_duration + if frame_count is None: + return None + else: + return frame_count * self.frame_duration def seconds_to_smpte(self, seconds: Fraction) -> str: frame_count = int(seconds / self.frame_duration) @@ -28,7 +31,11 @@ def smpte_to_frame_count(smpte_rep_string: str, frames_per_logical_second: int, """ assert frames_per_logical_second in [24, 25, 30, 48, 50, 60] - m = re.search("(\d?\d)[:;](\d\d)[:;](\d\d)([:;])(\d\d)(\.\d+)?", smpte_rep_string) + m = re.search(r'(\d?\d)[:;](\d\d)[:;](\d\d)([:;])(\d\d)(\.\d+)?', smpte_rep_string) + + if m is None: + return None + hh, mm, ss, sep, ff, frac = m.groups() hh, mm, ss, ff, frac = int(hh), int(mm), int(ss), int(ff), float(frac or 0.0) @@ -81,7 +88,7 @@ def frame_count_to_smpte(frame_count: int, frames_per_logical_second: int, drop_ def footage_to_frame_count(footage_string): - m = re.search("(\d+)\+(\d+)(\.\d+)?", footage_string) + m = re.search(r'(\d+)\+(\d+)(\.\d+)?', footage_string) feet, frm, frac = m.groups() feet, frm, frac = int(feet), int(frm), float(frac or 0.0) diff --git a/ptulsconv/commands.py b/ptulsconv/commands.py index cae642d..cc80979 100644 --- a/ptulsconv/commands.py +++ b/ptulsconv/commands.py @@ -126,7 +126,7 @@ def create_adr_reports(lines: List[ADRLine], tc_display_format: TimecodeFormat, # return parsed -def convert(input_file, major_mode='fmpxml', output=sys.stdout, warnings=True): +def convert(input_file, major_mode, output=sys.stdout, warnings=True): session = parse_document(input_file) session_tc_format = session.header.timecode_format diff --git a/ptulsconv/docparser/doc_entity.py b/ptulsconv/docparser/doc_entity.py index 8fd1f76..04beb3e 100644 --- a/ptulsconv/docparser/doc_entity.py +++ b/ptulsconv/docparser/doc_entity.py @@ -21,7 +21,8 @@ class SessionDescriptor: def markers_timed(self) -> Iterator[Tuple['MarkerDescriptor', Fraction]]: for marker in self.markers: - marker_time = self.header.convert_timecode(marker.location) + marker_time = Fraction(marker.time_reference, int(self.header.sample_rate)) + #marker_time = self.header.convert_timecode(marker.location) yield marker, marker_time def tracks_clips(self) -> Iterator[Tuple['TrackDescriptor', 'TrackClipDescriptor']]: diff --git a/ptulsconv/footage.py b/ptulsconv/footage.py new file mode 100644 index 0000000..0d70bd0 --- /dev/null +++ b/ptulsconv/footage.py @@ -0,0 +1,20 @@ +from fractions import Fraction +import re +import math +from collections import namedtuple +from typing import Optional + +def footage_to_seconds(footage: str) -> Optional[Fraction]: + m = re.match(r'(\d+)\+(\d+)(\.\d+)?') + if m is None: + return None + + feet, frames = m.groups() + feet, frames = int(feet), int(frames) + + fps = 24 + frames_per_foot = 16 + + total_frames = feet * 16 + frames + + return Fraction(total_frames, fps) \ No newline at end of file diff --git a/ptulsconv/movie_export.py b/ptulsconv/movie_export.py index c104ad6..c0f4fa3 100644 --- a/ptulsconv/movie_export.py +++ b/ptulsconv/movie_export.py @@ -1,4 +1,4 @@ -import ffmpeg # ffmpeg-python +#import ffmpeg # ffmpeg-python # TODO: Implement movie export diff --git a/ptulsconv/pdf/__init__.py b/ptulsconv/pdf/__init__.py index 3cd319c..cf17a3a 100644 --- a/ptulsconv/pdf/__init__.py +++ b/ptulsconv/pdf/__init__.py @@ -9,9 +9,11 @@ from reportlab.platypus.frames import Frame from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont +from typing import List + # TODO: A Generic report useful for spotting # TODO: A report useful for M&E mixer's notes - +# TODO: Use a default font that doesn't need to be installed # This is from https://code.activestate.com/recipes/576832/ for # generating page count messages @@ -36,7 +38,7 @@ class ReportCanvas(canvas.Canvas): def draw_page_number(self, page_count): self.saveState() - self.setFont("Futura", 10) + self.setFont('Helvetica', 10) #FIXME make this customizable self.drawString(0.5 * inch, 0.5 * inch, "Page %d of %d" % (self._pageNumber, page_count)) right_edge = self._pagesize[0] - 0.5 * inch self.drawRightString(right_edge, 0.5 * inch, self._report_date.strftime("%m/%d/%Y %H:%M")) @@ -60,7 +62,8 @@ def make_doc_template(page_size, filename, document_title, document_header: str, client: str, document_subheader: str, - left_margin=0.5 * inch) -> ADRDocTemplate: + left_margin=0.5 * inch, + fonts: List[TTFont] = []) -> ADRDocTemplate: right_margin = top_margin = bottom_margin = 0.5 * inch page_box = GRect(0., 0., page_size[0], page_size[1]) _, page_box = page_box.split_x(left_margin, direction='l') @@ -71,16 +74,23 @@ def make_doc_template(page_size, filename, document_title, footer_box, page_box = page_box.split_y(0.25 * inch, direction='u') header_box, page_box = page_box.split_y(0.75 * inch, direction='d') title_box, report_box = header_box.split_x(3.5 * inch, direction='r') - + + on_page_lambda = (lambda c, _: + draw_header_footer(c, report_box, title_box, + footer_box,title=title, + supervisor=supervisor, + document_subheader=document_subheader, + client=client, doc_title=document_header)) + + frames = [Frame(page_box.min_x, page_box.min_y, page_box.width, page_box.height)] + page_template = PageTemplate(id="Main", - frames=[Frame(page_box.min_x, page_box.min_y, page_box.width, page_box.height)], - onPage=lambda c, _: draw_header_footer(c, report_box, title_box, footer_box, - title=title, supervisor=supervisor, - document_subheader=document_subheader, - client=client, - doc_title=document_header)) + frames=frames, + onPage=on_page_lambda) + + for font in fonts: + pdfmetrics.registerFont(font) - pdfmetrics.registerFont(TTFont('Futura', 'Futura.ttc')) doc = ADRDocTemplate(filename, title=document_title, author=supervisor, @@ -97,6 +107,8 @@ def time_format(mins, zero_str="-"): """ Formats a duration `mins` into a string """ + if mins is None: + return zero_str if mins == 0. and zero_str is not None: return zero_str elif mins < 60.: @@ -108,11 +120,11 @@ def time_format(mins, zero_str="-"): def draw_header_footer(a_canvas: ReportCanvas, left_box, right_box, footer_box, title: str, supervisor: str, - document_subheader: str, client: str, doc_title=""): + document_subheader: str, client: str, doc_title="", font_name='Helvetica'): (_supervisor_box, client_box,), title_box = right_box.divide_y([16., 16., ]) - title_box.draw_text_cell(a_canvas, title, "Futura", 18, inset_y=2., inset_x=5.) - client_box.draw_text_cell(a_canvas, client, "Futura", 11, inset_y=2., inset_x=5.) + title_box.draw_text_cell(a_canvas, title, font_name, 18, inset_y=2., inset_x=5.) + client_box.draw_text_cell(a_canvas, client, font_name, 11, inset_y=2., inset_x=5.) a_canvas.saveState() a_canvas.setLineWidth(0.5) @@ -129,13 +141,13 @@ def draw_header_footer(a_canvas: ReportCanvas, left_box, right_box, footer_box, (doc_title_cell, spotting_version_cell,), _ = left_box.divide_y([18., 14], direction='d') - doc_title_cell.draw_text_cell(a_canvas, doc_title, 'Futura', 14., inset_y=2.) + doc_title_cell.draw_text_cell(a_canvas, doc_title, font_name, 14., inset_y=2.) if document_subheader is not None: - spotting_version_cell.draw_text_cell(a_canvas, document_subheader, 'Futura', 12., inset_y=2.) + spotting_version_cell.draw_text_cell(a_canvas, document_subheader, font_name, 12., inset_y=2.) if supervisor is not None: - a_canvas.setFont('Futura', 11.) + a_canvas.setFont(font_name, 11.) a_canvas.drawCentredString(footer_box.min_x + footer_box.width / 2., footer_box.min_y, supervisor) diff --git a/ptulsconv/pdf/continuity.py b/ptulsconv/pdf/continuity.py index 7e02d56..4cc4650 100644 --- a/ptulsconv/pdf/continuity.py +++ b/ptulsconv/pdf/continuity.py @@ -12,9 +12,9 @@ from ptulsconv.pdf import make_doc_template # TODO: A Continuity -def table_for_scene(scene, tc_format): +def table_for_scene(scene, tc_format, font_name = 'Helvetica'): scene_style = getSampleStyleSheet()['Normal'] - scene_style.fontName = 'Futura' + scene_style.fontName = font_name scene_style.leftIndent = 0. scene_style.leftPadding = 0. scene_style.spaceAfter = 18. @@ -29,7 +29,7 @@ def table_for_scene(scene, tc_format): style = [('VALIGN', (0, 0), (-1, -1), 'TOP'), ('LEFTPADDING', (0, 0), (0, 0), 0.0), ('BOTTOMPADDING', (0, 0), (-1, -1), 12.), - ('FONTNAME', (0, 0), (-1, -1), 'Futura')] + ('FONTNAME', (0, 0), (-1, -1), font_name)] return Table(data=[row], style=style, colWidths=[1.0 * inch, 6.5 * inch]) diff --git a/ptulsconv/pdf/line_count.py b/ptulsconv/pdf/line_count.py index 29bf4c8..d3f28a3 100644 --- a/ptulsconv/pdf/line_count.py +++ b/ptulsconv/pdf/line_count.py @@ -202,16 +202,16 @@ def populate_columns(lines: List[ADRLine], columns, include_omitted, _page_size) def output_report(lines: List[ADRLine], reel_list: List[str], include_omitted=False, - page_size=portrait(letter)): + page_size=portrait(letter), font_name='Helvetica'): columns = build_columns(lines, include_omitted=include_omitted, reel_list=reel_list) data, style, columns_widths = populate_columns(lines, columns, include_omitted, page_size) - style.append(('FONTNAME', (0, 0), (-1, -1), "Futura")) + style.append(('FONTNAME', (0, 0), (-1, -1), font_name)) style.append(('FONTSIZE', (0, 0), (-1, -1), 9.)) style.append(('LINEBELOW', (0, 0), (-1, 0), 1.0, colors.black)) # style.append(('LINEBELOW', (0, 1), (-1, -1), 0.25, colors.gray)) - pdfmetrics.registerFont(TTFont('Futura', 'Futura.ttc')) + #pdfmetrics.registerFont(TTFont('Futura', 'Futura.ttc')) title = "%s Line Count" % lines[0].title filename = title + '.pdf' @@ -230,7 +230,7 @@ def output_report(lines: List[ADRLine], reel_list: List[str], include_omitted=Fa story = [Spacer(height=0.5 * inch, width=1.), table] style = getSampleStyleSheet()['Normal'] - style.fontName = 'Futura' + style.fontName = font_name style.fontSize = 12. style.spaceBefore = 16. style.spaceAfter = 16. diff --git a/ptulsconv/pdf/summary_log.py b/ptulsconv/pdf/summary_log.py index 2c472d9..5d3fc2f 100644 --- a/ptulsconv/pdf/summary_log.py +++ b/ptulsconv/pdf/summary_log.py @@ -40,17 +40,17 @@ def build_aux_data_field(line: ADRLine): return "
".join(entries) -def build_story(lines: List[ADRLine], tc_rate: TimecodeFormat): +def build_story(lines: List[ADRLine], tc_rate: TimecodeFormat, font_name='Helvetica'): story = list() this_scene = None scene_style = getSampleStyleSheet()['Normal'] - scene_style.fontName = 'Futura' + scene_style.fontName = font_name scene_style.leftIndent = 0. scene_style.leftPadding = 0. scene_style.spaceAfter = 18. line_style = getSampleStyleSheet()['Normal'] - line_style.fontName = 'Futura' + line_style.fontName = font_name for line in lines: table_style = [('VALIGN', (0, 0), (-1, -1), 'TOP'), diff --git a/ptulsconv/pdf/supervisor_1pg.py b/ptulsconv/pdf/supervisor_1pg.py index 1b7e015..b3828c9 100644 --- a/ptulsconv/pdf/supervisor_1pg.py +++ b/ptulsconv/pdf/supervisor_1pg.py @@ -11,11 +11,12 @@ from reportlab.platypus import Paragraph from .__init__ import GRect -from ptulsconv.broadcast_timecode import TimecodeFormat +from ptulsconv.broadcast_timecode import TimecodeFormat, footage_to_frame_count from ptulsconv.docparser.adr_entity import ADRLine import datetime +font_name = 'Helvetica' def draw_header_block(canvas, rect, record: ADRLine): rect.draw_text_cell(canvas, record.cue_number, "Helvetica", 44, vertical_align='m') @@ -23,19 +24,19 @@ def draw_header_block(canvas, rect, record: ADRLine): def draw_character_row(canvas, rect, record: ADRLine): label_frame, value_frame = rect.split_x(1.25 * inch) - label_frame.draw_text_cell(canvas, "CHARACTER", "Futura", 10, force_baseline=9.) + label_frame.draw_text_cell(canvas, "CHARACTER", font_name, 10, force_baseline=9.) line = "%s / %s" % (record.character_id, record.character_name) if record.actor_name is not None: line = line + " / " + record.actor_name - value_frame.draw_text_cell(canvas, line, "Futura", 12, force_baseline=9.) + value_frame.draw_text_cell(canvas, line, font_name, 12, force_baseline=9.) rect.draw_border(canvas, ['min_y', 'max_y']) def draw_cue_number_block(canvas, rect, record: ADRLine): (label_frame, number_frame,), aux_frame = rect.divide_y([0.20 * inch, 0.375 * inch], direction='d') - label_frame.draw_text_cell(canvas, "CUE NUMBER", "Futura", 10, + label_frame.draw_text_cell(canvas, "CUE NUMBER", font_name, 10, inset_y=5., vertical_align='t') - number_frame.draw_text_cell(canvas, record.cue_number, "Futura", 14, + number_frame.draw_text_cell(canvas, record.cue_number, font_name, 14, inset_x=10., inset_y=2., draw_baseline=True) tags = {'tv': 'TV', @@ -49,7 +50,7 @@ def draw_cue_number_block(canvas, rect, record: ADRLine): if getattr(record, key): tag_field = tag_field + tags[key] + " " - aux_frame.draw_text_cell(canvas, tag_field, "Futura", 10, + aux_frame.draw_text_cell(canvas, tag_field, font_name, 10, inset_x=10., inset_y=2., vertical_align='t') rect.draw_border(canvas, 'max_x') @@ -58,13 +59,13 @@ def draw_timecode_block(canvas, rect, record: ADRLine, tc_display_format: Timeco (in_label_frame, in_frame, out_label_frame, out_frame), _ = rect.divide_y( [0.20 * inch, 0.25 * inch, 0.20 * inch, 0.25 * inch], direction='d') - in_label_frame.draw_text_cell(canvas, "IN", "Futura", 10, + in_label_frame.draw_text_cell(canvas, "IN", font_name, 10, vertical_align='t', inset_y=5., inset_x=5.) - in_frame.draw_text_cell(canvas, tc_display_format.seconds_to_smpte(record.start), "Futura", 14, + in_frame.draw_text_cell(canvas, tc_display_format.seconds_to_smpte(record.start), font_name, 14, inset_x=10., inset_y=2., draw_baseline=True) - out_label_frame.draw_text_cell(canvas, "OUT", "Futura", 10, + out_label_frame.draw_text_cell(canvas, "OUT", font_name, 10, vertical_align='t', inset_y=5., inset_x=5.) - out_frame.draw_text_cell(canvas, tc_display_format.seconds_to_smpte(record.finish), "Futura", 14, + out_frame.draw_text_cell(canvas, tc_display_format.seconds_to_smpte(record.finish), font_name, 14, inset_x=10., inset_y=2., draw_baseline=True) rect.draw_border(canvas, 'max_x') @@ -75,16 +76,16 @@ def draw_reason_block(canvas, rect, record: ADRLine): reason_label, reason_value = reason_cell.split_x(.75 * inch) notes_label, notes_value = notes_cell.split_x(.75 * inch) - reason_label.draw_text_cell(canvas, "Reason:", "Futura", 12, + reason_label.draw_text_cell(canvas, "Reason:", font_name, 12, inset_x=5., inset_y=5., vertical_align='b') - reason_value.draw_text_cell(canvas, record.reason or "", "Futura", 12, + reason_value.draw_text_cell(canvas, record.reason or "", font_name, 12, inset_x=5., inset_y=5., draw_baseline=True, vertical_align='b') - notes_label.draw_text_cell(canvas, "Note:", "Futura", 12, + notes_label.draw_text_cell(canvas, "Note:", font_name, 12, inset_x=5., inset_y=5., vertical_align='t') style = getSampleStyleSheet()['BodyText'] - style.fontName = 'Futura' + style.fontName = font_name style.fontSize = 12 style.leading = 14 @@ -96,10 +97,10 @@ def draw_reason_block(canvas, rect, record: ADRLine): def draw_prompt(canvas, rect, prompt=""): label, block = rect.split_y(0.20 * inch, direction='d') - label.draw_text_cell(canvas, "PROMPT", "Futura", 10, vertical_align='t', inset_y=5., inset_x=0.) + label.draw_text_cell(canvas, "PROMPT", font_name, 10, vertical_align='t', inset_y=5., inset_x=0.) style = getSampleStyleSheet()['BodyText'] - style.fontName = 'Futura' + style.fontName = font_name style.fontSize = 14 style.leading = 24 @@ -116,10 +117,10 @@ def draw_prompt(canvas, rect, prompt=""): def draw_notes(canvas, rect, note=""): label, block = rect.split_y(0.20 * inch, direction='d') - label.draw_text_cell(canvas, "NOTES", "Futura", 10, vertical_align='t', inset_y=5., inset_x=0.) + label.draw_text_cell(canvas, "NOTES", font_name, 10, vertical_align='t', inset_y=5., inset_x=0.) style = getSampleStyleSheet()['BodyText'] - style.fontName = 'Futura' + style.fontName = font_name style.fontSize = 14 style.leading = 24 @@ -175,12 +176,12 @@ def draw_aux_block(canvas, rect, recording_time_sec_this_line, recording_time_se lines, last_line = content_rect.divide_y([12., 12., 24., 24., 24., 24.], direction='d') lines[0].draw_text_cell(canvas, - "Time for this line: %.1f mins" % (recording_time_sec_this_line / 60.), "Futura", 9.) - lines[1].draw_text_cell(canvas, "Running time: %03.1f mins" % (recording_time_sec / 60.), "Futura", 9.) - lines[2].draw_text_cell(canvas, "Actual Start: ______________", "Futura", 9., vertical_align='b') - lines[3].draw_text_cell(canvas, "Record Date: ______________", "Futura", 9., vertical_align='b') - lines[4].draw_text_cell(canvas, "Engineer: ______________", "Futura", 9., vertical_align='b') - lines[5].draw_text_cell(canvas, "Location: ______________", "Futura", 9., vertical_align='b') + "Time for this line: %.1f mins" % (recording_time_sec_this_line / 60.), font_name, 9.) + lines[1].draw_text_cell(canvas, "Running time: %03.1f mins" % (recording_time_sec / 60.), font_name, 9.) + lines[2].draw_text_cell(canvas, "Actual Start: ______________", font_name, 9., vertical_align='b') + lines[3].draw_text_cell(canvas, "Record Date: ______________", font_name, 9., vertical_align='b') + lines[4].draw_text_cell(canvas, "Engineer: ______________", font_name, 9., vertical_align='b') + lines[5].draw_text_cell(canvas, "Location: ______________", font_name, 9., vertical_align='b') def draw_footer(canvas, rect, record: ADRLine, report_date, line_no, total_lines): @@ -189,7 +190,7 @@ def draw_footer(canvas, rect, record: ADRLine, report_date, line_no, total_lines spotting_name = [record.spot] if record.spot is not None else [] pages_s = ["Line %i of %i" % (line_no, total_lines)] footer_s = " - ".join(report_date_s + spotting_name + pages_s) - rect.draw_text_cell(canvas, footer_s, font_name="Futura", font_size=10., inset_y=2.) + rect.draw_text_cell(canvas, footer_s, font_name=font_name, font_size=10., inset_y=2.) def create_report_for_character(records, report_date, tc_display_format: TimecodeFormat): @@ -200,7 +201,7 @@ def create_report_for_character(records, report_date, tc_display_format: Timecod assert outfile is not None assert outfile[-4:] == '.pdf', "Output file must have 'pdf' extension!" - pdfmetrics.registerFont(TTFont('Futura', 'Futura.ttc')) + #pdfmetrics.registerFont(TTFont('Futura', 'Futura.ttc')) page: GRect = GRect(0, 0, letter[0], letter[1]) page = page.inset(inch * 0.5) diff --git a/ptulsconv/pdf/talent_sides.py b/ptulsconv/pdf/talent_sides.py index e3b3e60..aed7933 100644 --- a/ptulsconv/pdf/talent_sides.py +++ b/ptulsconv/pdf/talent_sides.py @@ -16,9 +16,9 @@ from ..broadcast_timecode import TimecodeFormat from ..docparser.adr_entity import ADRLine -def output_report(lines: List[ADRLine], tc_display_format: TimecodeFormat): +def output_report(lines: List[ADRLine], tc_display_format: TimecodeFormat, font_name="Helvetica"): character_numbers = set([n.character_id for n in lines]) - pdfmetrics.registerFont(TTFont('Futura', 'Futura.ttc')) + #pdfmetrics.registerFont(TTFont('Futura', 'Futura.ttc')) for n in character_numbers: char_lines = [line for line in lines if not line.omitted and line.character_id == n] @@ -39,7 +39,7 @@ def output_report(lines: List[ADRLine], tc_display_format: TimecodeFormat): story = [] prompt_style = getSampleStyleSheet()['Normal'] - prompt_style.fontName = 'Futura' + prompt_style.fontName = font_name prompt_style.fontSize = 18. prompt_style.leading = 24. @@ -47,7 +47,7 @@ def output_report(lines: List[ADRLine], tc_display_format: TimecodeFormat): prompt_style.rightIndent = 1.5 * inch number_style = getSampleStyleSheet()['Normal'] - number_style.fontName = 'Futura' + number_style.fontName = font_name number_style.fontSize = 14 number_style.leading = 24 diff --git a/setup.py b/setup.py index 4382a7c..a5220c7 100644 --- a/setup.py +++ b/setup.py @@ -26,6 +26,7 @@ setup(name='ptulsconv', "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", "Development Status :: 4 - Beta", "Topic :: Text Processing :: Filters"], packages=['ptulsconv'], diff --git a/test-coverage.sh b/test-coverage.sh new file mode 100755 index 0000000..5b7dca1 --- /dev/null +++ b/test-coverage.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +coverage run -m pytest . ; coverage-lcov + diff --git a/tests/test_robinhood1.py b/tests/export_tests/test_robinhood1.py similarity index 97% rename from tests/test_robinhood1.py rename to tests/export_tests/test_robinhood1.py index cbe8ed1..38b128e 100644 --- a/tests/test_robinhood1.py +++ b/tests/export_tests/test_robinhood1.py @@ -4,7 +4,7 @@ import os.path class TestRobinHood1(unittest.TestCase): - path = os.path.dirname(__file__) + '/export_cases/Robin Hood Spotting.txt' + path = os.path.dirname(__file__) + '/../export_cases/Robin Hood Spotting.txt' def test_header_export(self): diff --git a/tests/test_robinhood5.py b/tests/export_tests/test_robinhood5.py similarity index 95% rename from tests/test_robinhood5.py rename to tests/export_tests/test_robinhood5.py index e38e040..99ebd4d 100644 --- a/tests/test_robinhood5.py +++ b/tests/export_tests/test_robinhood5.py @@ -4,7 +4,7 @@ import os.path class TestRobinHood5(unittest.TestCase): - path = os.path.dirname(__file__) + '/export_cases/Robin Hood Spotting5.txt' + path = os.path.dirname(__file__) + '/../export_cases/Robin Hood Spotting5.txt' def test_skipped_segments(self): session = parse_document(self.path) diff --git a/tests/test_robinhood6.py b/tests/export_tests/test_robinhood6.py similarity index 94% rename from tests/test_robinhood6.py rename to tests/export_tests/test_robinhood6.py index 024f662..55e5373 100644 --- a/tests/test_robinhood6.py +++ b/tests/export_tests/test_robinhood6.py @@ -4,7 +4,7 @@ import os.path class TestRobinHood6(unittest.TestCase): - path = os.path.dirname(__file__) + '/export_cases/Robin Hood Spotting6.txt' + path = os.path.dirname(__file__) + '/../export_cases/Robin Hood Spotting6.txt' def test_a_track(self): session = parse_document(self.path) diff --git a/tests/test_robinhooddf.py b/tests/export_tests/test_robinhooddf.py similarity index 93% rename from tests/test_robinhooddf.py rename to tests/export_tests/test_robinhooddf.py index d92a2d1..bb8070a 100644 --- a/tests/test_robinhooddf.py +++ b/tests/export_tests/test_robinhooddf.py @@ -4,7 +4,7 @@ import os.path class TestRobinHoodDF(unittest.TestCase): - path = os.path.dirname(__file__) + '/export_cases/Robin Hood SpottingDF.txt' + path = os.path.dirname(__file__) + '/../export_cases/Robin Hood SpottingDF.txt' def test_header_export_df(self): session = parse_document(self.path) diff --git a/tests/functional/test_pdf_export.py b/tests/functional/test_pdf_export.py new file mode 100644 index 0000000..1261f3d --- /dev/null +++ b/tests/functional/test_pdf_export.py @@ -0,0 +1,34 @@ +import unittest + +import tempfile + +import os.path +import os +import glob + +from ptulsconv import commands + +class TestBroadcastTimecode(unittest.TestCase): + def test_report_generation(self): + """ + Setp through every text file in export_cases and make sure it can + be converted into PDF docs without throwing an error + """ + files = [os.path.dirname(__file__) + "/../export_cases/Robin Hood Spotting.txt"] + #files.append(os.path.dirname(__file__) + "/../export_cases/Robin Hood Spotting2.txt") + for path in files: + tempdir = tempfile.TemporaryDirectory() + os.chdir(tempdir.name) + try: + commands.convert(path, major_mode='doc') + except: + assert False, "Error processing file %s" % path + finally: + tempdir.cleanup() + + + + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_adr_entity.py b/tests/unittests/test_adr_entity.py similarity index 100% rename from tests/test_adr_entity.py rename to tests/unittests/test_adr_entity.py diff --git a/tests/test_broadcast_timecode.py b/tests/unittests/test_broadcast_timecode.py similarity index 100% rename from tests/test_broadcast_timecode.py rename to tests/unittests/test_broadcast_timecode.py diff --git a/tests/test_doc_entities.py b/tests/unittests/test_doc_entities.py similarity index 100% rename from tests/test_doc_entities.py rename to tests/unittests/test_doc_entities.py diff --git a/tests/test_tag_compiler.py b/tests/unittests/test_tag_compiler.py similarity index 99% rename from tests/test_tag_compiler.py rename to tests/unittests/test_tag_compiler.py index 78c6b2e..db4e4fb 100644 --- a/tests/test_tag_compiler.py +++ b/tests/unittests/test_tag_compiler.py @@ -97,14 +97,14 @@ class TestTagCompiler(unittest.TestCase): markers = [doc_entity.MarkerDescriptor(number=1, location="01:00:00:00", - time_reference=48000 * 60, + time_reference=48000 * 3600, units="Samples", name="Marker 1 {Part=1}", comments="" ), doc_entity.MarkerDescriptor(number=2, location="01:00:01:00", - time_reference=48000 * 61, + time_reference=48000 * 3601, units="Samples", name="Marker 2 {Part=2}", comments="[M1]" diff --git a/tests/test_tag_interpreter.py b/tests/unittests/test_tag_interpreter.py similarity index 100% rename from tests/test_tag_interpreter.py rename to tests/unittests/test_tag_interpreter.py diff --git a/tests/test_tagging.py b/tests/unittests/test_tagging.py similarity index 97% rename from tests/test_tagging.py rename to tests/unittests/test_tagging.py index b6ffc18..34fcc29 100644 --- a/tests/test_tagging.py +++ b/tests/unittests/test_tagging.py @@ -4,7 +4,7 @@ import os.path class TaggingIntegratedTests(unittest.TestCase): - path = os.path.dirname(__file__) + '/export_cases/Tag Tests/Tag Tests.txt' + path = os.path.dirname(__file__) + '/../export_cases/Tag Tests/Tag Tests.txt' def test_event_list(self): with open(self.path, 'r') as f: diff --git a/tests/test_utils.py b/tests/unittests/test_utils.py similarity index 100% rename from tests/test_utils.py rename to tests/unittests/test_utils.py