in2lambda 0.2.0__tar.gz → 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {in2lambda-0.2.0 → in2lambda-0.2.1}/PKG-INFO +2 -2
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/filters/PartPartSolSol/filter.py +1 -1
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/filters/PartSolPartSol/filter.py +1 -1
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/filters/PartsOneSol/filter.py +1 -1
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/filters/PartsSepSol/filter.py +1 -1
- in2lambda-0.2.0/in2lambda/filters/_markdown.py → in2lambda-0.2.1/in2lambda/filters/markdown.py +65 -20
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/katex_convert/katex_convert.py +4 -1
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/main.py +44 -4
- {in2lambda-0.2.0 → in2lambda-0.2.1}/pyproject.toml +3 -3
- {in2lambda-0.2.0 → in2lambda-0.2.1}/LICENSE +0 -0
- {in2lambda-0.2.0 → in2lambda-0.2.1}/README.md +0 -0
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/__init__.py +0 -0
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/api/__init__.py +0 -0
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/api/module.py +0 -0
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/api/part.py +0 -0
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/api/question.py +0 -0
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/filters/PartPartSolSol/__init__.py +0 -0
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/filters/PartPartSolSol/example.tex +0 -0
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/filters/PartSolPartSol/__init__.py +0 -0
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/filters/PartSolPartSol/example.tex +0 -0
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/filters/PartsOneSol/__init__.py +0 -0
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/filters/PartsOneSol/example.tex +0 -0
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/filters/PartsSepSol/__init__.py +0 -0
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/filters/PartsSepSol/example.tex +0 -0
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/filters/__init__.py +0 -0
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/json_convert/__init__.py +0 -0
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/json_convert/json_convert.py +0 -0
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/json_convert/minimal_template.json +0 -0
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/katex_convert/__init__.py +0 -0
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/katex_convert/delete_list.txt +0 -0
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/katex_convert/replace_list.txt +0 -0
- {in2lambda-0.2.0 → in2lambda-0.2.1}/in2lambda/py.typed +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: in2lambda
|
|
3
|
-
Version: 0.2.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Converts content ready for import into Lambda Feedback
|
|
5
5
|
Home-page: https://lambda-feedback.github.io/in2lambda
|
|
6
6
|
License: MIT
|
|
7
7
|
Requires-Python: >=3.10,<4.0
|
in2lambda-0.2.0/in2lambda/filters/_markdown.py → in2lambda-0.2.1/in2lambda/filters/markdown.py
RENAMED
|
@@ -1,5 +1,7 @@
|
|
|
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,7 +15,7 @@ from in2lambda.katex_convert.katex_convert import latex_to_katex
|
|
|
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
|
|
@@ -21,22 +23,45 @@ def image_directories(tex_file: str) -> list[str]:
|
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
|
@@ -44,29 +69,49 @@ def image_path(image_name: str, tex_file: str) -> Optional[str]:
|
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
62
|
-
directory
|
|
63
|
-
|
|
64
|
-
|
|
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
|
|
|
@@ -34,6 +34,9 @@ def latex_to_katex(latex_string: str) -> str:
|
|
|
34
34
|
|
|
35
35
|
Returns:
|
|
36
36
|
Hopefully, a valid KaTeX expression that's similar to the LaTeX expression.
|
|
37
|
+
|
|
38
|
+
Examples:
|
|
39
|
+
>>>
|
|
37
40
|
"""
|
|
38
41
|
katex_string = replace_functions(delete_functions(latex_string))
|
|
39
42
|
return katex_string
|
|
@@ -143,7 +146,7 @@ def brace_remover(latex_string: str, brace_start_index: int) -> str:
|
|
|
143
146
|
|
|
144
147
|
|
|
145
148
|
if __name__ == "__main__":
|
|
146
|
-
latex_input = "
|
|
149
|
+
latex_input = "\\textbf{Vector Algebra:} for two vectors $\\vec{a}$ and $\\vec{b}$ in $\\mathbb{R}^3$ given by \\norm{a}"
|
|
147
150
|
|
|
148
151
|
katex_output = latex_to_katex(latex_input)
|
|
149
152
|
print(katex_output)
|
|
@@ -12,6 +12,41 @@ from in2lambda.api.module import Module
|
|
|
12
12
|
from in2lambda.json_convert import json_convert
|
|
13
13
|
|
|
14
14
|
|
|
15
|
+
def file_type(file: str) -> str:
|
|
16
|
+
"""Determines which pandoc file format to use for a given file.
|
|
17
|
+
|
|
18
|
+
See https://github.com/jgm/pandoc/blob/bad922a69236e22b20d51c4ec0b90c5a6c038433/src/Text/Pandoc/Format.hs#L171
|
|
19
|
+
(or any newer commit) for pandoc's supported file extensions.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
file: A file path with the file extension included.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
An option in `pandoc --list-input-formats` that matches the given file type
|
|
26
|
+
|
|
27
|
+
Examples:
|
|
28
|
+
>>> from in2lambda.main import file_type
|
|
29
|
+
>>> file_type("example.tex")
|
|
30
|
+
'latex'
|
|
31
|
+
>>> file_type("/some/random/path/demo.md")
|
|
32
|
+
'markdown'
|
|
33
|
+
>>> file_type("no_extension")
|
|
34
|
+
Traceback (most recent call last):
|
|
35
|
+
RuntimeError: Unsupported file extension: .no_extension
|
|
36
|
+
>>> file_type("demo.unknown_extension")
|
|
37
|
+
Traceback (most recent call last):
|
|
38
|
+
RuntimeError: Unsupported file extension: .unknown_extension
|
|
39
|
+
"""
|
|
40
|
+
match (extension := file.split(".")[-1].lower()):
|
|
41
|
+
case "tex" | "latex" | "ltx":
|
|
42
|
+
return "latex"
|
|
43
|
+
case "md" | "rmd" | "markdown" | "mdown" | "mdwn" | "mkd" | "mkdn" | "text" | "txt":
|
|
44
|
+
return "markdown"
|
|
45
|
+
case "docx":
|
|
46
|
+
return "docx" # Pandoc doesn't seem to support doc
|
|
47
|
+
raise RuntimeError(f"Unsupported file extension: .{extension}")
|
|
48
|
+
|
|
49
|
+
|
|
15
50
|
def runner(
|
|
16
51
|
question_file: str,
|
|
17
52
|
chosen_filter: str,
|
|
@@ -52,7 +87,9 @@ def runner(
|
|
|
52
87
|
# Parse the Pandoc AST using the relevant panflute filter.
|
|
53
88
|
pf.run_filter(
|
|
54
89
|
filter_module.pandoc_filter,
|
|
55
|
-
doc=pf.convert_text(
|
|
90
|
+
doc=pf.convert_text(
|
|
91
|
+
text, input_format=file_type(question_file), standalone=True
|
|
92
|
+
),
|
|
56
93
|
module=module,
|
|
57
94
|
tex_file=question_file,
|
|
58
95
|
parsing_answers=False,
|
|
@@ -65,7 +102,9 @@ def runner(
|
|
|
65
102
|
|
|
66
103
|
pf.run_filter(
|
|
67
104
|
filter_module.pandoc_filter,
|
|
68
|
-
doc=pf.convert_text(
|
|
105
|
+
doc=pf.convert_text(
|
|
106
|
+
answer_text, input_format=file_type(answer_file), standalone=True
|
|
107
|
+
),
|
|
69
108
|
module=module,
|
|
70
109
|
tex_file=answer_file,
|
|
71
110
|
parsing_answers=True,
|
|
@@ -79,7 +118,8 @@ def runner(
|
|
|
79
118
|
|
|
80
119
|
|
|
81
120
|
@click.command(
|
|
82
|
-
|
|
121
|
+
no_args_is_help=True,
|
|
122
|
+
epilog="See the docs at https://lambda-feedback.github.io/in2lambda/ for more details.",
|
|
83
123
|
)
|
|
84
124
|
@click.argument( # Use resolve_path to get absolute path
|
|
85
125
|
"question_file", type=click.Path(exists=True, readable=True, resolve_path=True)
|
|
@@ -91,7 +131,7 @@ def runner(
|
|
|
91
131
|
[
|
|
92
132
|
i.name
|
|
93
133
|
for i in pkgutil.iter_modules(in2lambda.filters.__path__)
|
|
94
|
-
if i.name
|
|
134
|
+
if i.name != "markdown"
|
|
95
135
|
],
|
|
96
136
|
case_sensitive=False,
|
|
97
137
|
),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "in2lambda"
|
|
3
|
-
version = "0.2.
|
|
4
|
-
description = "
|
|
3
|
+
version = "0.2.1"
|
|
4
|
+
description = "Converts content ready for import into Lambda Feedback"
|
|
5
5
|
authors = []
|
|
6
6
|
license = "MIT"
|
|
7
7
|
readme = "README.md"
|
|
@@ -43,7 +43,7 @@ pre-commit = "^3.3.3"
|
|
|
43
43
|
[tool.poetry.group.docs.dependencies]
|
|
44
44
|
furo = "^2023.8.19"
|
|
45
45
|
myst-parser = "^2.0.0"
|
|
46
|
-
sphinx = "^7.2.
|
|
46
|
+
sphinx = "^7.2.5"
|
|
47
47
|
sphinx-copybutton = "^0.5.2"
|
|
48
48
|
sphinx-design = "^0.5.0"
|
|
49
49
|
sphinx-click = "^5.0.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|