mirror of
https://github.com/iluvcapra/ptulsconv.git
synced 2025-12-31 08:50:48 +00:00
Merge branch 'master' of https://github.com/iluvcapra/ptulsconv
This commit is contained in:
2
.github/workflows/python-package.yml
vendored
2
.github/workflows/python-package.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
python-version: [3.7, 3.8, 3.9]
|
python-version: [3.7, 3.8, 3.9, "3.10"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -104,3 +104,4 @@ venv.bak/
|
|||||||
.mypy_cache/
|
.mypy_cache/
|
||||||
.DS_Store
|
.DS_Store
|
||||||
/example/Charade/Session File Backups/
|
/example/Charade/Session File Backups/
|
||||||
|
lcov.info
|
||||||
|
|||||||
4
.idea/.gitignore
generated
vendored
4
.idea/.gitignore
generated
vendored
@@ -1,4 +0,0 @@
|
|||||||
|
|
||||||
# Default ignored files
|
|
||||||
/workspace.xml
|
|
||||||
/tasks.xml
|
|
||||||
19
.idea/dictionaries/jamie.xml
generated
19
.idea/dictionaries/jamie.xml
generated
@@ -1,19 +0,0 @@
|
|||||||
<component name="ProjectDictionaryState">
|
|
||||||
<dictionary name="jamie">
|
|
||||||
<words>
|
|
||||||
<w>adlib</w>
|
|
||||||
<w>bottompadding</w>
|
|
||||||
<w>fmpxml</w>
|
|
||||||
<w>futura</w>
|
|
||||||
<w>leftpadding</w>
|
|
||||||
<w>lineafter</w>
|
|
||||||
<w>linebefore</w>
|
|
||||||
<w>ptulsconv</w>
|
|
||||||
<w>retval</w>
|
|
||||||
<w>smpte</w>
|
|
||||||
<w>subheader</w>
|
|
||||||
<w>timecode</w>
|
|
||||||
<w>timespan</w>
|
|
||||||
</words>
|
|
||||||
</dictionary>
|
|
||||||
</component>
|
|
||||||
9
.idea/dictionaries/jamiehardt.xml
generated
9
.idea/dictionaries/jamiehardt.xml
generated
@@ -1,9 +0,0 @@
|
|||||||
<component name="ProjectDictionaryState">
|
|
||||||
<dictionary name="jamiehardt">
|
|
||||||
<words>
|
|
||||||
<w>fmpxmlresult</w>
|
|
||||||
<w>frac</w>
|
|
||||||
<w>mins</w>
|
|
||||||
</words>
|
|
||||||
</dictionary>
|
|
||||||
</component>
|
|
||||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
6
.idea/inspectionProfiles/profiles_settings.xml
generated
@@ -1,6 +0,0 @@
|
|||||||
<component name="InspectionProjectProfileManager">
|
|
||||||
<settings>
|
|
||||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
|
||||||
<version value="1.0" />
|
|
||||||
</settings>
|
|
||||||
</component>
|
|
||||||
4
.idea/misc.xml
generated
4
.idea/misc.xml
generated
@@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9 (ptulsconv)" project-jdk-type="Python SDK" />
|
|
||||||
</project>
|
|
||||||
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectModuleManager">
|
|
||||||
<modules>
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/ptulsconv.iml" filepath="$PROJECT_DIR$/.idea/ptulsconv.iml" />
|
|
||||||
</modules>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
14
.idea/ptulsconv.iml
generated
14
.idea/ptulsconv.iml
generated
@@ -1,14 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="PYTHON_MODULE" version="4">
|
|
||||||
<component name="NewModuleRootManager">
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="jdk" jdkName="Python 3.9 (ptulsconv)" jdkType="Python SDK" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
</component>
|
|
||||||
<component name="PyDocumentationSettings">
|
|
||||||
<option name="format" value="PLAIN" />
|
|
||||||
<option name="myDocStringFormat" value="Plain" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
||||||
Binary file not shown.
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
from ptulsconv.docparser.ptuls_grammar import protools_text_export_grammar
|
from ptulsconv.docparser.ptuls_grammar import protools_text_export_grammar
|
||||||
|
|
||||||
__version__ = '0.8.2'
|
__version__ = '0.8.3'
|
||||||
__author__ = 'Jamie Hardt'
|
__author__ = 'Jamie Hardt'
|
||||||
__license__ = 'MIT'
|
__license__ = 'MIT'
|
||||||
|
|||||||
@@ -2,12 +2,15 @@ from fractions import Fraction
|
|||||||
import re
|
import re
|
||||||
import math
|
import math
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
class TimecodeFormat(namedtuple("_TimecodeFormat", "frame_duration logical_fps drop_frame")):
|
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)
|
frame_count = smpte_to_frame_count(smpte, self.logical_fps, drop_frame_hint=self.drop_frame)
|
||||||
|
if frame_count is None:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
return frame_count * self.frame_duration
|
return frame_count * self.frame_duration
|
||||||
|
|
||||||
def seconds_to_smpte(self, seconds: Fraction) -> str:
|
def seconds_to_smpte(self, seconds: Fraction) -> str:
|
||||||
@@ -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]
|
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, sep, ff, frac = m.groups()
|
||||||
hh, mm, ss, ff, frac = int(hh), int(mm), int(ss), int(ff), float(frac or 0.0)
|
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):
|
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 = m.groups()
|
||||||
feet, frm, frac = int(feet), int(frm), float(frac or 0.0)
|
feet, frm, frac = int(feet), int(frm), float(frac or 0.0)
|
||||||
|
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ def create_adr_reports(lines: List[ADRLine], tc_display_format: TimecodeFormat,
|
|||||||
# return parsed
|
# 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 = parse_document(input_file)
|
||||||
session_tc_format = session.header.timecode_format
|
session_tc_format = session.header.timecode_format
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ class SessionDescriptor:
|
|||||||
|
|
||||||
def markers_timed(self) -> Iterator[Tuple['MarkerDescriptor', Fraction]]:
|
def markers_timed(self) -> Iterator[Tuple['MarkerDescriptor', Fraction]]:
|
||||||
for marker in self.markers:
|
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
|
yield marker, marker_time
|
||||||
|
|
||||||
def tracks_clips(self) -> Iterator[Tuple['TrackDescriptor', 'TrackClipDescriptor']]:
|
def tracks_clips(self) -> Iterator[Tuple['TrackDescriptor', 'TrackClipDescriptor']]:
|
||||||
|
|||||||
20
ptulsconv/footage.py
Normal file
20
ptulsconv/footage.py
Normal file
@@ -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)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import ffmpeg # ffmpeg-python
|
#import ffmpeg # ffmpeg-python
|
||||||
|
|
||||||
# TODO: Implement movie export
|
# TODO: Implement movie export
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ from reportlab.platypus.frames import Frame
|
|||||||
from reportlab.pdfbase import pdfmetrics
|
from reportlab.pdfbase import pdfmetrics
|
||||||
from reportlab.pdfbase.ttfonts import TTFont
|
from reportlab.pdfbase.ttfonts import TTFont
|
||||||
|
|
||||||
|
from typing import List
|
||||||
|
|
||||||
# TODO: A Generic report useful for spotting
|
# TODO: A Generic report useful for spotting
|
||||||
# TODO: A report useful for M&E mixer's notes
|
# 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
|
# This is from https://code.activestate.com/recipes/576832/ for
|
||||||
# generating page count messages
|
# generating page count messages
|
||||||
@@ -36,7 +38,7 @@ class ReportCanvas(canvas.Canvas):
|
|||||||
|
|
||||||
def draw_page_number(self, page_count):
|
def draw_page_number(self, page_count):
|
||||||
self.saveState()
|
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))
|
self.drawString(0.5 * inch, 0.5 * inch, "Page %d of %d" % (self._pageNumber, page_count))
|
||||||
right_edge = self._pagesize[0] - 0.5 * inch
|
right_edge = self._pagesize[0] - 0.5 * inch
|
||||||
self.drawRightString(right_edge, 0.5 * inch, self._report_date.strftime("%m/%d/%Y %H:%M"))
|
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,
|
document_header: str,
|
||||||
client: str,
|
client: str,
|
||||||
document_subheader: 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
|
right_margin = top_margin = bottom_margin = 0.5 * inch
|
||||||
page_box = GRect(0., 0., page_size[0], page_size[1])
|
page_box = GRect(0., 0., page_size[0], page_size[1])
|
||||||
_, page_box = page_box.split_x(left_margin, direction='l')
|
_, page_box = page_box.split_x(left_margin, direction='l')
|
||||||
@@ -72,15 +75,22 @@ def make_doc_template(page_size, filename, document_title,
|
|||||||
header_box, page_box = page_box.split_y(0.75 * inch, direction='d')
|
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')
|
title_box, report_box = header_box.split_x(3.5 * inch, direction='r')
|
||||||
|
|
||||||
page_template = PageTemplate(id="Main",
|
on_page_lambda = (lambda c, _:
|
||||||
frames=[Frame(page_box.min_x, page_box.min_y, page_box.width, page_box.height)],
|
draw_header_footer(c, report_box, title_box,
|
||||||
onPage=lambda c, _: draw_header_footer(c, report_box, title_box, footer_box,
|
footer_box,title=title,
|
||||||
title=title, supervisor=supervisor,
|
supervisor=supervisor,
|
||||||
document_subheader=document_subheader,
|
document_subheader=document_subheader,
|
||||||
client=client,
|
client=client, doc_title=document_header))
|
||||||
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=frames,
|
||||||
|
onPage=on_page_lambda)
|
||||||
|
|
||||||
|
for font in fonts:
|
||||||
|
pdfmetrics.registerFont(font)
|
||||||
|
|
||||||
pdfmetrics.registerFont(TTFont('Futura', 'Futura.ttc'))
|
|
||||||
doc = ADRDocTemplate(filename,
|
doc = ADRDocTemplate(filename,
|
||||||
title=document_title,
|
title=document_title,
|
||||||
author=supervisor,
|
author=supervisor,
|
||||||
@@ -97,6 +107,8 @@ def time_format(mins, zero_str="-"):
|
|||||||
"""
|
"""
|
||||||
Formats a duration `mins` into a string
|
Formats a duration `mins` into a string
|
||||||
"""
|
"""
|
||||||
|
if mins is None:
|
||||||
|
return zero_str
|
||||||
if mins == 0. and zero_str is not None:
|
if mins == 0. and zero_str is not None:
|
||||||
return zero_str
|
return zero_str
|
||||||
elif mins < 60.:
|
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,
|
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., ])
|
(_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.)
|
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, "Futura", 11, 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.saveState()
|
||||||
a_canvas.setLineWidth(0.5)
|
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, 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:
|
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:
|
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)
|
a_canvas.drawCentredString(footer_box.min_x + footer_box.width / 2., footer_box.min_y, supervisor)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ from ptulsconv.pdf import make_doc_template
|
|||||||
|
|
||||||
# TODO: A Continuity
|
# 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 = getSampleStyleSheet()['Normal']
|
||||||
scene_style.fontName = 'Futura'
|
scene_style.fontName = font_name
|
||||||
scene_style.leftIndent = 0.
|
scene_style.leftIndent = 0.
|
||||||
scene_style.leftPadding = 0.
|
scene_style.leftPadding = 0.
|
||||||
scene_style.spaceAfter = 18.
|
scene_style.spaceAfter = 18.
|
||||||
@@ -29,7 +29,7 @@ def table_for_scene(scene, tc_format):
|
|||||||
style = [('VALIGN', (0, 0), (-1, -1), 'TOP'),
|
style = [('VALIGN', (0, 0), (-1, -1), 'TOP'),
|
||||||
('LEFTPADDING', (0, 0), (0, 0), 0.0),
|
('LEFTPADDING', (0, 0), (0, 0), 0.0),
|
||||||
('BOTTOMPADDING', (0, 0), (-1, -1), 12.),
|
('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])
|
return Table(data=[row], style=style, colWidths=[1.0 * inch, 6.5 * inch])
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
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)
|
columns = build_columns(lines, include_omitted=include_omitted, reel_list=reel_list)
|
||||||
data, style, columns_widths = populate_columns(lines, columns, include_omitted, page_size)
|
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(('FONTSIZE', (0, 0), (-1, -1), 9.))
|
||||||
style.append(('LINEBELOW', (0, 0), (-1, 0), 1.0, colors.black))
|
style.append(('LINEBELOW', (0, 0), (-1, 0), 1.0, colors.black))
|
||||||
# style.append(('LINEBELOW', (0, 1), (-1, -1), 0.25, colors.gray))
|
# 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
|
title = "%s Line Count" % lines[0].title
|
||||||
filename = title + '.pdf'
|
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]
|
story = [Spacer(height=0.5 * inch, width=1.), table]
|
||||||
|
|
||||||
style = getSampleStyleSheet()['Normal']
|
style = getSampleStyleSheet()['Normal']
|
||||||
style.fontName = 'Futura'
|
style.fontName = font_name
|
||||||
style.fontSize = 12.
|
style.fontSize = 12.
|
||||||
style.spaceBefore = 16.
|
style.spaceBefore = 16.
|
||||||
style.spaceAfter = 16.
|
style.spaceAfter = 16.
|
||||||
|
|||||||
@@ -40,17 +40,17 @@ def build_aux_data_field(line: ADRLine):
|
|||||||
return "<br />".join(entries)
|
return "<br />".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()
|
story = list()
|
||||||
|
|
||||||
this_scene = None
|
this_scene = None
|
||||||
scene_style = getSampleStyleSheet()['Normal']
|
scene_style = getSampleStyleSheet()['Normal']
|
||||||
scene_style.fontName = 'Futura'
|
scene_style.fontName = font_name
|
||||||
scene_style.leftIndent = 0.
|
scene_style.leftIndent = 0.
|
||||||
scene_style.leftPadding = 0.
|
scene_style.leftPadding = 0.
|
||||||
scene_style.spaceAfter = 18.
|
scene_style.spaceAfter = 18.
|
||||||
line_style = getSampleStyleSheet()['Normal']
|
line_style = getSampleStyleSheet()['Normal']
|
||||||
line_style.fontName = 'Futura'
|
line_style.fontName = font_name
|
||||||
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
table_style = [('VALIGN', (0, 0), (-1, -1), 'TOP'),
|
table_style = [('VALIGN', (0, 0), (-1, -1), 'TOP'),
|
||||||
|
|||||||
@@ -11,11 +11,12 @@ from reportlab.platypus import Paragraph
|
|||||||
|
|
||||||
from .__init__ import GRect
|
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
|
from ptulsconv.docparser.adr_entity import ADRLine
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
font_name = 'Helvetica'
|
||||||
|
|
||||||
def draw_header_block(canvas, rect, record: ADRLine):
|
def draw_header_block(canvas, rect, record: ADRLine):
|
||||||
rect.draw_text_cell(canvas, record.cue_number, "Helvetica", 44, vertical_align='m')
|
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):
|
def draw_character_row(canvas, rect, record: ADRLine):
|
||||||
label_frame, value_frame = rect.split_x(1.25 * inch)
|
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)
|
line = "%s / %s" % (record.character_id, record.character_name)
|
||||||
if record.actor_name is not None:
|
if record.actor_name is not None:
|
||||||
line = line + " / " + record.actor_name
|
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'])
|
rect.draw_border(canvas, ['min_y', 'max_y'])
|
||||||
|
|
||||||
|
|
||||||
def draw_cue_number_block(canvas, rect, record: ADRLine):
|
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, 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')
|
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)
|
inset_x=10., inset_y=2., draw_baseline=True)
|
||||||
|
|
||||||
tags = {'tv': 'TV',
|
tags = {'tv': 'TV',
|
||||||
@@ -49,7 +50,7 @@ def draw_cue_number_block(canvas, rect, record: ADRLine):
|
|||||||
if getattr(record, key):
|
if getattr(record, key):
|
||||||
tag_field = tag_field + tags[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')
|
inset_x=10., inset_y=2., vertical_align='t')
|
||||||
rect.draw_border(canvas, 'max_x')
|
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(
|
(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')
|
[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.)
|
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)
|
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.)
|
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)
|
inset_x=10., inset_y=2., draw_baseline=True)
|
||||||
|
|
||||||
rect.draw_border(canvas, 'max_x')
|
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)
|
reason_label, reason_value = reason_cell.split_x(.75 * inch)
|
||||||
notes_label, notes_value = notes_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')
|
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,
|
inset_x=5., inset_y=5., draw_baseline=True,
|
||||||
vertical_align='b')
|
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')
|
inset_x=5., inset_y=5., vertical_align='t')
|
||||||
|
|
||||||
style = getSampleStyleSheet()['BodyText']
|
style = getSampleStyleSheet()['BodyText']
|
||||||
style.fontName = 'Futura'
|
style.fontName = font_name
|
||||||
style.fontSize = 12
|
style.fontSize = 12
|
||||||
style.leading = 14
|
style.leading = 14
|
||||||
|
|
||||||
@@ -96,10 +97,10 @@ def draw_reason_block(canvas, rect, record: ADRLine):
|
|||||||
def draw_prompt(canvas, rect, prompt=""):
|
def draw_prompt(canvas, rect, prompt=""):
|
||||||
label, block = rect.split_y(0.20 * inch, direction='d')
|
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 = getSampleStyleSheet()['BodyText']
|
||||||
style.fontName = 'Futura'
|
style.fontName = font_name
|
||||||
style.fontSize = 14
|
style.fontSize = 14
|
||||||
|
|
||||||
style.leading = 24
|
style.leading = 24
|
||||||
@@ -116,10 +117,10 @@ def draw_prompt(canvas, rect, prompt=""):
|
|||||||
def draw_notes(canvas, rect, note=""):
|
def draw_notes(canvas, rect, note=""):
|
||||||
label, block = rect.split_y(0.20 * inch, direction='d')
|
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 = getSampleStyleSheet()['BodyText']
|
||||||
style.fontName = 'Futura'
|
style.fontName = font_name
|
||||||
style.fontSize = 14
|
style.fontSize = 14
|
||||||
style.leading = 24
|
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, last_line = content_rect.divide_y([12., 12., 24., 24., 24., 24.], direction='d')
|
||||||
|
|
||||||
lines[0].draw_text_cell(canvas,
|
lines[0].draw_text_cell(canvas,
|
||||||
"Time for this line: %.1f mins" % (recording_time_sec_this_line / 60.), "Futura", 9.)
|
"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.), "Futura", 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: ______________", "Futura", 9., vertical_align='b')
|
lines[2].draw_text_cell(canvas, "Actual Start: ______________", font_name, 9., vertical_align='b')
|
||||||
lines[3].draw_text_cell(canvas, "Record Date: ______________", "Futura", 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: ______________", "Futura", 9., vertical_align='b')
|
lines[4].draw_text_cell(canvas, "Engineer: ______________", font_name, 9., vertical_align='b')
|
||||||
lines[5].draw_text_cell(canvas, "Location: ______________", "Futura", 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):
|
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 []
|
spotting_name = [record.spot] if record.spot is not None else []
|
||||||
pages_s = ["Line %i of %i" % (line_no, total_lines)]
|
pages_s = ["Line %i of %i" % (line_no, total_lines)]
|
||||||
footer_s = " - ".join(report_date_s + spotting_name + pages_s)
|
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):
|
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 is not None
|
||||||
assert outfile[-4:] == '.pdf', "Output file must have 'pdf' extension!"
|
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: GRect = GRect(0, 0, letter[0], letter[1])
|
||||||
page = page.inset(inch * 0.5)
|
page = page.inset(inch * 0.5)
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ from ..broadcast_timecode import TimecodeFormat
|
|||||||
from ..docparser.adr_entity import ADRLine
|
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])
|
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:
|
for n in character_numbers:
|
||||||
char_lines = [line for line in lines if not line.omitted and line.character_id == n]
|
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 = []
|
story = []
|
||||||
|
|
||||||
prompt_style = getSampleStyleSheet()['Normal']
|
prompt_style = getSampleStyleSheet()['Normal']
|
||||||
prompt_style.fontName = 'Futura'
|
prompt_style.fontName = font_name
|
||||||
prompt_style.fontSize = 18.
|
prompt_style.fontSize = 18.
|
||||||
|
|
||||||
prompt_style.leading = 24.
|
prompt_style.leading = 24.
|
||||||
@@ -47,7 +47,7 @@ def output_report(lines: List[ADRLine], tc_display_format: TimecodeFormat):
|
|||||||
prompt_style.rightIndent = 1.5 * inch
|
prompt_style.rightIndent = 1.5 * inch
|
||||||
|
|
||||||
number_style = getSampleStyleSheet()['Normal']
|
number_style = getSampleStyleSheet()['Normal']
|
||||||
number_style.fontName = 'Futura'
|
number_style.fontName = font_name
|
||||||
number_style.fontSize = 14
|
number_style.fontSize = 14
|
||||||
|
|
||||||
number_style.leading = 24
|
number_style.leading = 24
|
||||||
|
|||||||
1
setup.py
1
setup.py
@@ -26,6 +26,7 @@ setup(name='ptulsconv',
|
|||||||
"Programming Language :: Python :: 3.7",
|
"Programming Language :: Python :: 3.7",
|
||||||
"Programming Language :: Python :: 3.8",
|
"Programming Language :: Python :: 3.8",
|
||||||
"Programming Language :: Python :: 3.9",
|
"Programming Language :: Python :: 3.9",
|
||||||
|
"Programming Language :: Python :: 3.10",
|
||||||
"Development Status :: 4 - Beta",
|
"Development Status :: 4 - Beta",
|
||||||
"Topic :: Text Processing :: Filters"],
|
"Topic :: Text Processing :: Filters"],
|
||||||
packages=['ptulsconv'],
|
packages=['ptulsconv'],
|
||||||
|
|||||||
4
test-coverage.sh
Executable file
4
test-coverage.sh
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
coverage run -m pytest . ; coverage-lcov
|
||||||
|
|
||||||
@@ -4,7 +4,7 @@ import os.path
|
|||||||
|
|
||||||
|
|
||||||
class TestRobinHood1(unittest.TestCase):
|
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):
|
def test_header_export(self):
|
||||||
|
|
||||||
@@ -4,7 +4,7 @@ import os.path
|
|||||||
|
|
||||||
|
|
||||||
class TestRobinHood5(unittest.TestCase):
|
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):
|
def test_skipped_segments(self):
|
||||||
session = parse_document(self.path)
|
session = parse_document(self.path)
|
||||||
@@ -4,7 +4,7 @@ import os.path
|
|||||||
|
|
||||||
|
|
||||||
class TestRobinHood6(unittest.TestCase):
|
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):
|
def test_a_track(self):
|
||||||
session = parse_document(self.path)
|
session = parse_document(self.path)
|
||||||
@@ -4,7 +4,7 @@ import os.path
|
|||||||
|
|
||||||
|
|
||||||
class TestRobinHoodDF(unittest.TestCase):
|
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):
|
def test_header_export_df(self):
|
||||||
session = parse_document(self.path)
|
session = parse_document(self.path)
|
||||||
34
tests/functional/test_pdf_export.py
Normal file
34
tests/functional/test_pdf_export.py
Normal file
@@ -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()
|
||||||
@@ -97,14 +97,14 @@ class TestTagCompiler(unittest.TestCase):
|
|||||||
|
|
||||||
markers = [doc_entity.MarkerDescriptor(number=1,
|
markers = [doc_entity.MarkerDescriptor(number=1,
|
||||||
location="01:00:00:00",
|
location="01:00:00:00",
|
||||||
time_reference=48000 * 60,
|
time_reference=48000 * 3600,
|
||||||
units="Samples",
|
units="Samples",
|
||||||
name="Marker 1 {Part=1}",
|
name="Marker 1 {Part=1}",
|
||||||
comments=""
|
comments=""
|
||||||
),
|
),
|
||||||
doc_entity.MarkerDescriptor(number=2,
|
doc_entity.MarkerDescriptor(number=2,
|
||||||
location="01:00:01:00",
|
location="01:00:01:00",
|
||||||
time_reference=48000 * 61,
|
time_reference=48000 * 3601,
|
||||||
units="Samples",
|
units="Samples",
|
||||||
name="Marker 2 {Part=2}",
|
name="Marker 2 {Part=2}",
|
||||||
comments="[M1]"
|
comments="[M1]"
|
||||||
@@ -4,7 +4,7 @@ import os.path
|
|||||||
|
|
||||||
|
|
||||||
class TaggingIntegratedTests(unittest.TestCase):
|
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):
|
def test_event_list(self):
|
||||||
with open(self.path, 'r') as f:
|
with open(self.path, 'r') as f:
|
||||||
Reference in New Issue
Block a user