|
1 | 1 | """Generic helper functions used during the Pandoc filter stage for markdown conversion.""" |
2 | 2 |
|
| 3 | +import os |
| 4 | +import re |
3 | 5 | from functools import cache |
4 | 6 | from pathlib import Path |
5 | 7 |
|
|
13 | 15 |
|
14 | 16 | @cache |
15 | 17 | def image_directories(tex_file: str) -> list[str]: |
16 | | - """Determines the image directories referenced by `graphicspath` in a given TeX document. |
| 18 | + r"""Determines the image directories referenced by `graphicspath` in a given TeX document. |
17 | 19 |
|
18 | 20 | Args: |
19 | 21 | tex_file: The absolute path to a TeX file |
20 | 22 |
|
21 | 23 | Returns: |
22 | 24 | The exact contents of `graphicspath`, regardless of whether the directories are |
23 | 25 | absolute or relative. |
| 26 | +
|
| 27 | + Examples: |
| 28 | + >>> from in2lambda.filters.markdown import image_directories |
| 29 | + >>> import tempfile |
| 30 | + >>> import os |
| 31 | + >>> # Example TeX file with a graphicspath |
| 32 | + >>> temp_dir = tempfile.mkdtemp() |
| 33 | + >>> tex_file = os.path.join(temp_dir, 'test.tex') |
| 34 | + >>> with open(tex_file, 'w') as f: |
| 35 | + ... f.write("\graphicspath{{subdir1/}{subdir2/}{subdir3/}}") |
| 36 | + 45 |
| 37 | + >>> image_directories(tex_file) |
| 38 | + ['subdir1/', 'subdir2/', 'subdir3/'] |
| 39 | + >>> with open(tex_file, 'w') as f: |
| 40 | + ... f.write("\graphicspath{ { subdir1/ }, { subdir2/ }, { subdir3/ } }") |
| 41 | + 57 |
| 42 | + >>> image_directories.cache_clear() |
| 43 | + >>> image_directories(tex_file) |
| 44 | + ['subdir1/', 'subdir2/', 'subdir3/'] |
| 45 | + >>> with open(tex_file, 'w') as f: |
| 46 | + ... f.write("No image directory") |
| 47 | + 18 |
| 48 | + >>> image_directories.cache_clear() |
| 49 | + >>> image_directories(tex_file) |
| 50 | + [] |
24 | 51 | """ |
25 | 52 | with open(tex_file, "r") as file: |
26 | 53 | for line in file: |
27 | | - # Assumes line is in the format \graphicspath{ {...}, {...}, ...} |
28 | 54 | if "graphicspath" in line: |
29 | | - return [ |
30 | | - i.strip("{").rstrip("}") |
31 | | - for i in line.replace(" ", "")[len("\graphicspath{") : -1].split( |
32 | | - "," |
33 | | - ) |
34 | | - ] |
| 55 | + # Matches anything surrounded by curly braces, but excludes the top level |
| 56 | + # graphicspath brace. |
| 57 | + return [match.strip() for match in re.findall(r"{([^{]*?)}", line)] |
35 | 58 | return [] |
36 | 59 |
|
37 | 60 |
|
| 61 | +# TODO: This assumes the file extension is included, but that isn't required by LaTeX |
| 62 | +# See: https://www.overleaf.com/learn/latex/Inserting_Images#Generating_high-res_and_low-res_images |
38 | 63 | def image_path(image_name: str, tex_file: str) -> Optional[str]: |
39 | | - """Determines the absolute path to an image referenced in a tex_file. |
| 64 | + r"""Determines the absolute path to an image referenced in a tex_file. |
40 | 65 |
|
41 | 66 | Args: |
42 | 67 | image_name: The file name of the image e.g. example.png |
43 | 68 | tex_file: The TeX file that references the image. |
44 | 69 |
|
45 | 70 | Returns: |
46 | 71 | The absolute path to the image if it can be found. If not, it returns None. |
| 72 | +
|
| 73 | + Examples: |
| 74 | + >>> from in2lambda.filters.markdown import image_path |
| 75 | + >>> import tempfile |
| 76 | + >>> import os |
| 77 | + >>> # Example TeX file with a subdirectory |
| 78 | + >>> temp_dir = tempfile.mkdtemp() |
| 79 | + >>> tex_file = os.path.join(temp_dir, 'test.tex') |
| 80 | + >>> with open(tex_file, 'w') as f: |
| 81 | + ... f.write("\graphicspath{{./subdir1/}{./subdir2/}{./subdir3/}}") |
| 82 | + 51 |
| 83 | + >>> # Example image in a relative subdirectory |
| 84 | + >>> sub_dir = os.path.join(temp_dir, 'subdir3') |
| 85 | + >>> os.makedirs(sub_dir) |
| 86 | + >>> with open(os.path.join(sub_dir, 'inside_folder.png'), 'w') as f: |
| 87 | + ... pass |
| 88 | + >>> image_path("inside_folder.png", tex_file) == os.path.join(temp_dir, 'subdir3', "inside_folder.png") |
| 89 | + True |
| 90 | + >>> # Absolute path provided |
| 91 | + >>> image_path(os.path.join(temp_dir, 'subdir3', "inside_folder.png"), tex_file) == os.path.join(temp_dir, 'subdir3', "inside_folder.png") |
| 92 | + True |
47 | 93 | """ |
48 | 94 | # In case the filename is the exact absolute/relative location to the image |
49 | 95 | # When handling relative locations (i.e. begins with dot), first go to the directory of the TeX file. |
50 | | - filename = ( |
51 | | - f"{str(Path(tex_file).parent)}/" if image_name[0] == "." else "" |
52 | | - ) + image_name |
| 96 | + |
| 97 | + filename = os.path.join( |
| 98 | + str(Path(tex_file).parent) if image_name[0] == "." else "", image_name |
| 99 | + ) |
53 | 100 |
|
54 | 101 | if Path(filename).is_file(): |
55 | | - return filename |
| 102 | + return os.path.normpath(filename) |
56 | 103 |
|
57 | 104 | # Absolute or relative directories referenced by `graphicspath` |
58 | 105 | image_locations = image_directories(tex_file) |
59 | 106 |
|
60 | 107 | for directory in image_locations: |
61 | | - if directory[-1] != "/": |
62 | | - directory += "/" |
63 | | - filename = ( |
64 | | - (f"{str(Path(tex_file).parent)}/" if directory[0] == "." else "") |
65 | | - + directory |
66 | | - + image_name |
| 108 | + filename = os.path.join( |
| 109 | + str(Path(tex_file).parent) if directory[0] == "." else "", |
| 110 | + directory, |
| 111 | + image_name, |
67 | 112 | ) |
68 | 113 | if Path(filename).is_file(): |
69 | | - return filename |
| 114 | + return os.path.normpath(filename) |
70 | 115 | return None |
71 | 116 |
|
72 | 117 |
|
|
0 commit comments