From 33817135a04c4b2d79e844bc4db5053d3df69488 Mon Sep 17 00:00:00 2001 From: Mark Wolfman Date: Sun, 3 May 2020 22:56:35 -0500 Subject: [PATCH] All examples now build, plus added examples to travis build. --- .gitignore | 1 + .travis.yml | 4 ++ dungeonsheets/make_sheets.py | 43 ++++++++++++--------- dungeonsheets/spells/spells_s.py | 66 ++++++++++++++++---------------- tests/test_make_sheets.py | 4 ++ 5 files changed, 66 insertions(+), 52 deletions(-) diff --git a/.gitignore b/.gitignore index 7a4e612..4279610 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Generated output PDFs (and intermediate files) examples/*.pdf examples/*.aux +examples/*.tex # Emacs temp files *~ diff --git a/.travis.yml b/.travis.yml index c9df04f..07eb2b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,10 @@ python: - "3.6" - "3.7" - "3.8" +before_install: + - sudo add-apt-repository -y ppa:malteworld/ppa + - sudo apt -q update + - sudo apt-get -y install pdftk # command to install dependencies install: - pip install -r requirements.txt diff --git a/dungeonsheets/make_sheets.py b/dungeonsheets/make_sheets.py index 6845ccc..a5a8113 100644 --- a/dungeonsheets/make_sheets.py +++ b/dungeonsheets/make_sheets.py @@ -24,10 +24,11 @@ character sheet.""" bold_re = re.compile(r'\*\*([^*]+)\*\*') it_re = re.compile(r'\*([^*]+)\*') -tt_re = re.compile(r'``([^`]+)``') +verb_re = re.compile(r'``([^`]+)``') # A dice string, with optinal backticks: ``1d6 + 3`` dice_re = re.compile(r'`*(\d+d\d+(?:\s*\+\s*\d+)?)`*') + def rst_to_latex(rst): """Basic markup of RST to LaTeX code.""" if rst is None: @@ -38,10 +39,11 @@ def rst_to_latex(rst): tex = tex.replace(c, '\\' + c) tex = bold_re.sub(r'\\textbf{\1}', tex) tex = it_re.sub(r'\\textit{\1}', tex) + tex = verb_re.sub(r'\\begin{verbatim}{\1}\\end{verbatim}', tex) tex = dice_re.sub(r'\\texttt{\1}', tex) - tex = tt_re.sub(r'\\texttt{\1}', tex) for c in ['#', '$', '%', '&', '~', '_', '^']: tex = tex.replace(c, '\\' + c) + return tex @@ -70,22 +72,22 @@ def text_box(string): return new_string -def create_druid_shapes_pdf(character, basename): +def create_druid_shapes_pdf(character, basename, keep_temp_files=False): template = jinja_env.get_template('druid_shapes_template.tex') - return create_latex_pdf(character, basename, template) + return create_latex_pdf(character, basename, template, keep_temp_files=keep_temp_files) -def create_spellbook_pdf(character, basename): +def create_spellbook_pdf(character, basename, keep_temp_files=False): template = jinja_env.get_template('spellbook_template.tex') - return create_latex_pdf(character, basename, template) + return create_latex_pdf(character, basename, template, keep_temp_files=keep_temp_files) -def create_features_pdf(character, basename): +def create_features_pdf(character, basename, keep_temp_files=False): template = jinja_env.get_template('features_template.tex') - return create_latex_pdf(character, basename, template) + return create_latex_pdf(character, basename, template, keep_temp_files=keep_temp_files) -def create_latex_pdf(character, basename, template): +def create_latex_pdf(character, basename, template, keep_temp_files=False): tex = template.render(character=character) # Create tex document tex_file = f'{basename}.tex' @@ -109,19 +111,22 @@ def create_latex_pdf(character, basename, template): # Compile the PDF pdf_file = f'{basename}.pdf' output_dir = os.path.abspath(os.path.dirname(pdf_file)) + tex_command_line = ['pdflatex', '--output-directory', output_dir, + '-halt-on-error', '-interaction=nonstopmode', + tex_file] try: - result = subprocess.run(['pdflatex', '--output-directory', - output_dir, tex_file, '-halt-on-error'], + result = subprocess.run(tex_command_line, stdout=subprocess.DEVNULL, timeout=30) except FileNotFoundError: # Remove temporary files remove_temp_files(basename) raise exceptions.LatexNotFoundError() else: - if result.returncode == 0: + if result.returncode == 0 and not keep_temp_files: remove_temp_files(basename) - else: - raise exceptions.LatexError(f'Processing of {basename}.tex failed.') + if result.returncode != 0: + raise exceptions.LatexError(f'Processing of {basename}.tex failed.' + f' See {basename}.log for details.') def create_spells_pdf(character, basename, flatten=False): @@ -431,7 +436,7 @@ def _make_pdf_pdftk(fields, src_pdf, basename, flatten=False): os.remove(fdfname) -def make_sheet(character_file, character=None, flatten=False): +def make_sheet(character_file, character=None, flatten=False, debug=False): """Prepare a PDF character sheet from the given character file. Parameters @@ -463,7 +468,7 @@ def make_sheet(character_file, character=None, flatten=False): feat_base = '{:s}_feats'.format( os.path.splitext(character_file)[0]) try: - create_features_pdf(character=character, basename=feat_base) + create_features_pdf(character=character, basename=feat_base, keep_temp_files=debug) except exceptions.LatexNotFoundError as e: log.warning('``pdflatex`` not available. Skipping features book ' f'for {character.name}') @@ -473,7 +478,7 @@ def make_sheet(character_file, character=None, flatten=False): # Create spell book spellbook_base = os.path.splitext(character_file)[0] + '_spellbook' try: - create_spellbook_pdf(character=character, basename=spellbook_base) + create_spellbook_pdf(character=character, basename=spellbook_base, keep_temp_files=debug) except exceptions.LatexNotFoundError as e: log.warning('``pdflatex`` not available. Skipping spellbook ' f'for {character.name}') @@ -484,7 +489,7 @@ def make_sheet(character_file, character=None, flatten=False): if len(wild_shapes) > 0: shapes_base = os.path.splitext(character_file)[0] + '_wild_shapes' try: - create_druid_shapes_pdf(character=character, basename=shapes_base) + create_druid_shapes_pdf(character=character, basename=shapes_base, keep_temp_files=debug) except exceptions.LatexNotFoundError as e: log.warning('``pdflatex`` not available. Skipping wild shapes list ' f'for {character.name}') @@ -546,7 +551,7 @@ def main(): for filename in filenames: print(f"Processing {os.path.splitext(filename)[0]}...", end='') try: - make_sheet(character_file=filename, flatten=(not args.editable)) + make_sheet(character_file=filename, flatten=(not args.editable), debug=args.debug) except exceptions.CharacterFileFormatError as e: # Only raise the failed exception if this file is explicitly given print('invalid') diff --git a/dungeonsheets/spells/spells_s.py b/dungeonsheets/spells/spells_s.py index 992fd11..339f47a 100644 --- a/dungeonsheets/spells/spells_s.py +++ b/dungeonsheets/spells/spells_s.py @@ -87,39 +87,39 @@ class ScorchingRay(Spell): class Scrying(Spell): - """You can see and hear a particular creature you choose that is on the same plane - of existence as you. The target must make a W isdom saving throw, which is - modified by how well you know the target and the sort of physical connection you - have to it. If a target knows you're casting this spell, it can fail the saving - throw voluntarily if it wants to be observed. + """You can see and hear a particular creature you choose that is on + the same plane of existence as you. The target must make a W isdom + saving throw, which is modified by how well you know the target + and the sort of physical connection you have to it. If a target + knows you're casting this spell, it can fail the saving throw + voluntarily if it wants to be observed. + + Knowledge - Save Modifier + ========================= + Secondhand (you have heard of the target) - +5 + Firsthand (you have met the target) - +0 + Familiar (you know the target well) - -5 + + Connection - Save Modifier + ========================== + Likeness or picture - -2 + Possession or garment - -4 + Body part, lock of hair, bit of nail, or the like - -10 + + On a successful save, the target isn't affected, and you can't use + this spell against it again for 24 hours. + + On a failed save, the spell creates an invisible sensor within 10 + feet of the target. You can see and hear through the sensor as if + you w ere there. The sensor moves with the target, remaining + within 10 feet of it for the duration. A creature that can see + invisible objects sees the sensor as a luminous orb about the size + of your fist. + + Instead of targeting a creature, you can choose a location you + have seen before as the target of this spell. When you do, the + sensor appears at that location and doesn't move. - Knowledge                 Save - Modifier - Secondhand (you have heard of the target) +5 - Firsthand (you have met - the target)      +0 - Familiar (you know the target well)     -5 - - Connection -                Save Modifier - Likeness or picture               -2 - Posession or - garment            -4 - Body part, lock of hair, bit of nail, or the like -10 - - On - a successful save, the target isn't affected, and you can't use this spell - against it again for 24 hours. - - On a failed save, the spell creates an invisible - sensor within 10 feet of the target. You can see and hear through the sensor as - if you w ere there. The sensor moves with the target, remaining within 10 feet - of it for the duration. A creature that can see invisible objects sees the - sensor as a luminous orb about the size of your fist. - - Instead of targeting a - creature, you can choose a location you have seen before as the target of this - spell. When you do, the sensor appears at that location and doesn't move. """ name = "Scrying" level = 5 @@ -1508,7 +1508,7 @@ class Symbol(Spell): Each target must make a Wisdom saving throw and becomes frightened for 1 minute on a failed save. While frightened, the target drops whatever it is holding and must move at least 20 feet away from the glyph on each of ist - turns, if able.  + turns, if able. Hopelessness Each target must make a Charisma saving throw. On diff --git a/tests/test_make_sheets.py b/tests/test_make_sheets.py index 0984ce3..b1803f8 100644 --- a/tests/test_make_sheets.py +++ b/tests/test_make_sheets.py @@ -47,3 +47,7 @@ class MarkdownTestCase(unittest.TestCase): def test_no_text(self): text = make_sheets.rst_to_latex(None) self.assertEqual(text, '') + + def test_verbatim(self): + text = make_sheets.rst_to_latex('``hello, world``') + self.assertIn(r'\begin{verbatim}', text)