auto-editor 25.0.0__py3-none-any.whl → 25.1.0__py3-none-any.whl

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.
@@ -124,6 +124,19 @@ def make_timeline(
124
124
  src_index = np.array([], dtype=np.int32)
125
125
  concat = np.concatenate
126
126
 
127
+ try:
128
+ stdenv = __import__("auto_editor.lang.stdenv", fromlist=["lang"])
129
+ env.update(stdenv.make_standard_env())
130
+ except ImportError:
131
+ func = log.error if args.config else log.debug
132
+ func("Failed to import standard env")
133
+
134
+ if args.config:
135
+ # Edit `env` with user-defined code.
136
+ with open("config.pal") as file:
137
+ parser = Parser(Lexer("config.pal", file.read()))
138
+ interpret(env, parser)
139
+
127
140
  for i, src in enumerate(sources):
128
141
  try:
129
142
  parser = Parser(Lexer("`--edit`", args.edit_based_on))
@@ -131,6 +144,7 @@ def make_timeline(
131
144
  log.debug(f"edit: {parser}")
132
145
 
133
146
  env["timebase"] = tb
147
+ env["src"] = f"{src.path}"
134
148
  env["@levels"] = Levels(src, tb, bar, args.no_cache, log, len(sources) < 2)
135
149
 
136
150
  results = interpret(env, parser)
@@ -83,7 +83,9 @@ class SubtitleParser:
83
83
  def edit(self, chunks: Chunks) -> None:
84
84
  for cut in reversed(chunks):
85
85
  the_speed = cut[2]
86
- speed_factor = 1 if the_speed == 99999 else 1 - (1 / the_speed)
86
+ speed_factor = (
87
+ 1 if (the_speed == 0 or the_speed >= 99999) else 1 - (1 / the_speed)
88
+ )
87
89
 
88
90
  new_content = []
89
91
  for content in self.contents:
@@ -47,7 +47,7 @@ class VideoJson(TypedDict):
47
47
  class AudioJson(TypedDict):
48
48
  codec: str
49
49
  samplerate: int
50
- channels: int
50
+ layout: str
51
51
  duration: float
52
52
  bitrate: int
53
53
  lang: str | None
@@ -150,8 +150,8 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
150
150
  for track, a in enumerate(src.audios):
151
151
  aud: AudioJson = {
152
152
  "codec": a.codec,
153
+ "layout": a.layout,
153
154
  "samplerate": a.samplerate,
154
- "channels": a.channels,
155
155
  "duration": a.duration,
156
156
  "bitrate": a.bitrate,
157
157
  "lang": a.lang,
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  import sys
4
4
 
5
5
  from auto_editor.lang.palet import Lexer, Parser, env, interpret
6
+ from auto_editor.lang.stdenv import make_standard_env
6
7
  from auto_editor.lib.err import MyError
7
8
 
8
9
 
@@ -11,6 +12,7 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
11
12
  with open(sys_args[0], encoding="utf-8", errors="ignore") as file:
12
13
  program_text = file.read()
13
14
 
15
+ env.update(make_standard_env())
14
16
  try:
15
17
  interpret(env, Parser(Lexer(sys_args[0], program_text, True)))
16
18
  except (MyError, ZeroDivisionError) as e:
@@ -8,6 +8,7 @@ import auto_editor
8
8
  from auto_editor.analyze import Levels
9
9
  from auto_editor.ffwrapper import initFileInfo
10
10
  from auto_editor.lang.palet import ClosingError, Lexer, Parser, env, interpret
11
+ from auto_editor.lang.stdenv import make_standard_env
11
12
  from auto_editor.lib.data_structs import print_str
12
13
  from auto_editor.lib.err import MyError
13
14
  from auto_editor.utils.bar import Bar
@@ -67,6 +68,7 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
67
68
  env["timebase"] = tb
68
69
  env["@levels"] = Levels(src, tb, bar, False, log, strict)
69
70
 
71
+ env.update(make_standard_env())
70
72
  print(f"Auto-Editor {auto_editor.__version__}")
71
73
  text = None
72
74
 
@@ -85,8 +87,7 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
85
87
  continue
86
88
 
87
89
  try:
88
- lexer = Lexer("repl", text)
89
- parser = Parser(lexer)
90
+ parser = Parser(Lexer("repl", text))
90
91
  if args.debug_parser:
91
92
  print(f"parser: {parser}")
92
93
 
@@ -13,6 +13,7 @@ import numpy as np
13
13
 
14
14
  from auto_editor.ffwrapper import FileInfo, initFileInfo
15
15
  from auto_editor.lang.palet import Lexer, Parser, env, interpret
16
+ from auto_editor.lang.stdenv import make_standard_env
16
17
  from auto_editor.lib.data_structs import Char
17
18
  from auto_editor.lib.err import MyError
18
19
  from auto_editor.utils.log import Log
@@ -309,7 +310,7 @@ def main(sys_args: list[str] | None = None):
309
310
  """Input file must have an extension. Throw error if none is given."""
310
311
 
311
312
  shutil.copy("example.mp4", "example")
312
- run.check(["example", "--no-open"], "must have an extension.")
313
+ run.check(["example", "--no-open"], "must have an extension")
313
314
 
314
315
  return "example"
315
316
 
@@ -355,6 +356,13 @@ def main(sys_args: list[str] | None = None):
355
356
  def premiere_named_export():
356
357
  run.main(["example.mp4"], ["--export", 'premiere:name="Foo Bar"'])
357
358
 
359
+ def export_subtitles():
360
+ cn = fileinfo(run.main(["resources/subtitle.mp4"], []))
361
+
362
+ assert len(cn.videos) == 1
363
+ assert len(cn.audios) == 1
364
+ assert len(cn.subtitles) == 1
365
+
358
366
  def resolution_and_scale():
359
367
  cn = fileinfo(run.main(["example.mp4"], ["--scale", "1.5"]))
360
368
 
@@ -544,6 +552,8 @@ def main(sys_args: list[str] | None = None):
544
552
  )
545
553
 
546
554
  def palet_python_bridge():
555
+ env.update(make_standard_env())
556
+
547
557
  def cases(*cases: tuple[str, Any]) -> None:
548
558
  for text, expected in cases:
549
559
  try:
@@ -743,6 +753,7 @@ def main(sys_args: list[str] | None = None):
743
753
  track_tests,
744
754
  codec_tests,
745
755
  premiere_named_export,
756
+ export_subtitles,
746
757
  export,
747
758
  motion,
748
759
  resolution_and_scale,
@@ -72,6 +72,8 @@ def container_constructor(ext: str) -> Container:
72
72
  vdefault = container.default_video_codec
73
73
  adefault = container.default_audio_codec
74
74
  sdefault = container.default_subtitle_codec
75
+ if sdefault == "none" and ext == "mp4":
76
+ sdefault = "srt"
75
77
 
76
78
  vcodecs = set()
77
79
  acodecs = set()
@@ -251,6 +251,7 @@ class Args:
251
251
  progress: str = "modern"
252
252
  version: bool = False
253
253
  debug: bool = False
254
+ config: bool = False
254
255
  show_ffmpeg_commands: bool = False
255
256
  show_ffmpeg_output: bool = False
256
257
  quiet: bool = False
@@ -1,9 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
- import os
4
3
  import re
5
4
  import subprocess
6
5
  import sys
6
+ from os.path import exists, isdir, isfile, lexists, splitext
7
7
 
8
8
  from auto_editor.ffwrapper import FFmpeg
9
9
  from auto_editor.utils.func import get_stdout
@@ -27,7 +27,7 @@ def download_video(my_input: str, args: Args, ffmpeg: FFmpeg, log: Log) -> str:
27
27
  download_format = "bestvideo[ext=mp4]+bestaudio[ext=m4a]"
28
28
 
29
29
  if args.output_format is None:
30
- output_format = re.sub(r"\W+", "-", os.path.splitext(my_input)[0]) + ".%(ext)s"
30
+ output_format = re.sub(r"\W+", "-", splitext(my_input)[0]) + ".%(ext)s"
31
31
  else:
32
32
  output_format = args.output_format
33
33
 
@@ -57,10 +57,10 @@ def download_video(my_input: str, args: Args, ffmpeg: FFmpeg, log: Log) -> str:
57
57
  msg += "pip or your favorite package manager and make sure it's in PATH."
58
58
  log.error(msg)
59
59
 
60
- if not os.path.isfile(location):
60
+ if not isfile(location):
61
61
  subprocess.run([yt_dlp_path] + cmd)
62
62
 
63
- if not os.path.isfile(location):
63
+ if not isfile(location):
64
64
  log.error(f"Download file wasn't created: {location}")
65
65
 
66
66
  return location
@@ -73,11 +73,16 @@ def valid_input(inputs: list[str], ffmpeg: FFmpeg, args: Args, log: Log) -> list
73
73
  if my_input.startswith("http://") or my_input.startswith("https://"):
74
74
  result.append(download_video(my_input, args, ffmpeg, log))
75
75
  else:
76
- _, ext = os.path.splitext(my_input)
76
+ _, ext = splitext(my_input)
77
77
  if ext == "":
78
- if os.path.isdir(my_input):
78
+ if isdir(my_input):
79
79
  log.error("Input must be a file or a URL, not a directory.")
80
- log.error("Input file must have an extension.")
80
+ if exists(my_input):
81
+ log.error(f"Input file must have an extension: {my_input}")
82
+ if lexists(my_input):
83
+ log.error(f"Input file is a broken symbolic link: {my_input}")
84
+ if my_input.startswith("-"):
85
+ log.error(f"Option/Input file doesn't exist: {my_input}")
81
86
  result.append(my_input)
82
87
 
83
88
  return result
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: auto-editor
3
- Version: 25.0.0
3
+ Version: 25.1.0
4
4
  Summary: Auto-Editor: Effort free video editing!
5
5
  Author-email: WyattBlue <wyattblue@auto-editor.com>
6
6
  License: Unlicense
@@ -1,55 +1,58 @@
1
- auto_editor/__init__.py,sha256=hNpKYQArhnrmhf1u3TNPTwtZw8XS7EeDs-TfBLusM-s,23
2
- auto_editor/__main__.py,sha256=89pW_zaFB8WEyKTGadkALLuv_MFONIcfEu8t0jKqeWI,9774
1
+ auto_editor/__init__.py,sha256=fCfst7bcslfPZvO0BbrT9lF_JtNpW3F_ycN7xJnpJis,23
2
+ auto_editor/__main__.py,sha256=OlPCTG3t8phhLnyXT8bQlqsA4O97mDhmJTanJCgb82Q,9964
3
3
  auto_editor/analyze.py,sha256=pHoSZ_-wyV1hLJyJpPg9Ha7oecjdGHGJ0a4hbKnb9NY,11779
4
- auto_editor/edit.py,sha256=ihyCi9YyIV-WYP81pOnc5jG8n-e8m5aMogg27XVxPVY,11268
5
- auto_editor/ffwrapper.py,sha256=RU74pfZUMEIVdpvZVVoJt92AILBGkYaPLZbI94Y0i60,7832
4
+ auto_editor/edit.py,sha256=-AtEOHTvBnLlvvYkDyDbh9weGOOui6vsbyJZbEoYljI,11447
5
+ auto_editor/ffwrapper.py,sha256=NnhD4TvKyaap0Y2MQ7aIUQfeLJwfNbjTj5bLUpoMEI4,7888
6
6
  auto_editor/help.py,sha256=BFiP7vBz42TUzum4-zaQIrV1OY7kHeN0pe0MPE0T5xw,7997
7
- auto_editor/make_layers.py,sha256=ybTxPRD6bDbEX-7e9qu4OYUvYkrdNb4BjnN9hzwkRiQ,8496
7
+ auto_editor/make_layers.py,sha256=8uFy5SvMArAP-5slYJrxa_iGAEwimQBFeM-T01VORVw,8995
8
8
  auto_editor/output.py,sha256=D8NCJwwmcjDf5rvoBnWKu5XY7QtxF3thxbnTxKAxGu8,8043
9
9
  auto_editor/preview.py,sha256=noWkgyzdE14zwG8ZDYxLDual5iVt6zYTt4HTe-QAgFY,3029
10
10
  auto_editor/timeline.py,sha256=d9Qhup2pBwsj7j9kF-Iw22xHbQvGx-keDq2eLI11Mt4,7117
11
- auto_editor/validate_input.py,sha256=JQt7J5xOBJDp6lnd2sQptpYhf7Z_hyxNEzLsE9E7LKU,2596
11
+ auto_editor/validate_input.py,sha256=_9vtbNxodhVPf4PzTAH67LSj2K-HS6kShJOARmUMJdY,2904
12
12
  auto_editor/vanparse.py,sha256=f0vViZ-aYtDxEyVrFHJ5X2pPTQAfqtw3N2gZgzn51kU,10002
13
13
  auto_editor/wavfile.py,sha256=7N2LX_WfFVRnoXrKveLvuyTYpIz2htpGqfCD8tR4kJ8,9168
14
14
  auto_editor/formats/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- auto_editor/formats/fcp11.py,sha256=VwJWJs1qNDIVC8-pswipmKCk0e4V3LnE5fAMA0pPWVg,5857
16
- auto_editor/formats/fcp7.py,sha256=fH86sxhlUysWisjvlqzZJgDrRpj3dSzFG-Eho2sehdc,17610
15
+ auto_editor/formats/fcp11.py,sha256=Sff8fLZw0s0G88EVeBsn9vwzzga_KHIt2pGMww3V5jA,5411
16
+ auto_editor/formats/fcp7.py,sha256=vd7cW8vwoTvFlp4Tc5DYSn-A7i9ck3jJJdKNqWVtFVQ,20285
17
17
  auto_editor/formats/json.py,sha256=Br-xHVHj59C0OPP2FwfJeht_fImepRXsaw0iDFvK7-w,7693
18
18
  auto_editor/formats/shotcut.py,sha256=-ES854LLFCMCBe100JRJedDmuk8zPev17aQMTrzPv-g,4923
19
19
  auto_editor/formats/utils.py,sha256=GIZw28WHuCIaZ_zMI0v6Kxbq0QaIpbLsdSegdYwQxQ8,1990
20
20
  auto_editor/lang/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  auto_editor/lang/json.py,sha256=OsNcYlfEj8ZLlzLK-gkLcrCCKI7mJz9rpe-6XLr4f9U,9231
22
+ auto_editor/lang/libintrospection.py,sha256=6H1rGp0wqaCud5IPaoEmzULGnYt6ec7_0h32ATcw2oY,261
22
23
  auto_editor/lang/libmath.py,sha256=z33A161Oe6vYYK7R6pgYjdZZe63dQkN38Qf36TL3prg,847
23
- auto_editor/lang/palet.py,sha256=m22TQnKomUM2quxIH4bz7ya_gM166rbJ5pW7Ei-43IA,59712
24
+ auto_editor/lang/palet.py,sha256=5sSVPHmQ0o501GvJngYMQWtc7LLbryHKC64JQZmQvVY,22020
25
+ auto_editor/lang/stdenv.py,sha256=k_O1vQX9kk4WENuTtmnLoowuxRkcnNmwOEwXqscriU0,42079
24
26
  auto_editor/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
27
  auto_editor/lib/contracts.py,sha256=a3ZT-bGMa3-UjWKKFrEwLayw2Gl-rhqd5Bmvmrj85oE,7413
26
28
  auto_editor/lib/data_structs.py,sha256=xyB6aEcpdB9NNWp_dU3d2ds5Z8zOfHXNX4mNQLh2pNw,6977
27
29
  auto_editor/lib/err.py,sha256=UlszQJdzMZwkbT8x3sY4GkCV_5x9yrd6uVVUzvA8iiI,35
28
30
  auto_editor/render/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
31
  auto_editor/render/audio.py,sha256=darKvlglNXkknSUaPnH-qEUyccM1Awnv03_Px4yY81I,8844
30
- auto_editor/render/subtitle.py,sha256=g195kDN0LcwKlZeQMCflXPH5n_74iwCk1RPLSQ5eP34,4373
32
+ auto_editor/render/subtitle.py,sha256=CNcU_hmLwfZ2yvmSllIK-pB7ge_YdXHR-fnnOVUO9m8,4425
31
33
  auto_editor/render/video.py,sha256=gMVcLehC_QpdtIzNLR_7tv2CZmYeEWisS_5as4ceHV0,12971
32
34
  auto_editor/subcommands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
35
  auto_editor/subcommands/desc.py,sha256=GDrKJYiHMaeTrplZAceXl1JwoqD78XsV2_5lc0Xd7po,869
34
- auto_editor/subcommands/info.py,sha256=7Sgt9WR0rWxe7juCRKseMxW6gKv3z3voqFcL8-MOVVM,6927
36
+ auto_editor/subcommands/info.py,sha256=t5n43HLt9hpMFSIfGV777X4zIPBAFugOKlpCfRjiKxY,6921
35
37
  auto_editor/subcommands/levels.py,sha256=ZB8_9jbOA5s1AQUcUNZDiLAjyJOKl7Be2YeVWdkOr0Q,4071
36
- auto_editor/subcommands/palet.py,sha256=tbQoRWoT4jR3yu0etGApfprM-oQgXIjC-rIY-QG3nM0,655
37
- auto_editor/subcommands/repl.py,sha256=OfxIOBjE7W12UemfaaxMnzHcmV5cUTt7g5328R7rAYU,3116
38
+ auto_editor/subcommands/palet.py,sha256=ONzTqemaQq9YEfIOsDRNnwzfqnEMUMSXIQrETxyroRU,749
39
+ auto_editor/subcommands/repl.py,sha256=hpdF-CrOzdkChmj7zhx8P-lNWLmFfVR_VAnSUt0aaNU,3176
38
40
  auto_editor/subcommands/subdump.py,sha256=af_XBf7kaevqHn1A71z8C-7x8pS5WKD9FE_ugkCw6rk,665
39
- auto_editor/subcommands/test.py,sha256=Qg_zY1Cg8Mo7JXsUWFEJxJZAe5pkkXyK4ydnBVpG0I8,24992
41
+ auto_editor/subcommands/test.py,sha256=PdJAIR6HRTL_FGVPYlQMq4uW-5U4Hz515O29nPbSZyg,25322
40
42
  auto_editor/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
43
  auto_editor/utils/bar.py,sha256=RJqkJ8gNr8op_Z-2hh48ExjSonmTPX-RshctK_itv14,3988
42
44
  auto_editor/utils/chunks.py,sha256=J-eGKtEz68gFtRrj1kOSgH4Tj_Yz6prNQ7Xr-d9NQJw,52
43
45
  auto_editor/utils/cmdkw.py,sha256=XApxw7FZBOEJV9N4LHhdw1GVfHbFfCjr-zCZ1gJsSvY,6002
44
- auto_editor/utils/container.py,sha256=qSoS5d8JqLRH4_BIWfnJ-37eCKKe_J290yrUNULGT94,2643
46
+ auto_editor/utils/container.py,sha256=RnpoMmMYmn7o69LmMbBFHW4TsP3K52jYDhG9qzWXmAs,2720
45
47
  auto_editor/utils/encoder.py,sha256=auNYo7HXbcU4iTUCc0LE5lpwFmSvdWvBm6-5KIaRK8w,2983
46
48
  auto_editor/utils/func.py,sha256=kcxCOqe-tg6k-kxutIran8LpffRiHDjKB6rm-ngFiSU,4460
47
49
  auto_editor/utils/log.py,sha256=M2QKeQHMRNLm3HMVUKedZPRprT2u5dipOStiO4miPBk,3613
48
50
  auto_editor/utils/subtitle_tools.py,sha256=TjjVPiT8bWzZJcrZjF7ddpgfIsVkLE4LyxXzBswHAGU,693
49
- auto_editor/utils/types.py,sha256=JdAwfuT9Ty_FXUm89GUTo0M8FPFrXbqnlk-g4pWP1_k,11609
50
- auto_editor-25.0.0.dist-info/LICENSE,sha256=yiq99pWITHfqS0pbZMp7cy2dnbreTuvBwudsU-njvIM,1210
51
- auto_editor-25.0.0.dist-info/METADATA,sha256=ucOoacVK0LCr-DKicxIkO9w6Zx2LWvlfMPgBiXucYkk,6137
52
- auto_editor-25.0.0.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
53
- auto_editor-25.0.0.dist-info/entry_points.txt,sha256=-H7zdTw4MqnAcwrN5xTNkGIhzZtJMxS9r6lTMeR9-aA,240
54
- auto_editor-25.0.0.dist-info/top_level.txt,sha256=ky1HUkqq9i034c4CUU_0wBw0xZsxxyGEak1eTbdvpyA,12
55
- auto_editor-25.0.0.dist-info/RECORD,,
51
+ auto_editor/utils/types.py,sha256=sw78iiERM5aDjkCvgBcVaRCen0OTd-04GYYfhzX1PmA,11634
52
+ docs/build.py,sha256=8nJM_CgkSL5ilvzcJDGNjzoWpCphPJKZKguHazG6YK8,1641
53
+ auto_editor-25.1.0.dist-info/LICENSE,sha256=yiq99pWITHfqS0pbZMp7cy2dnbreTuvBwudsU-njvIM,1210
54
+ auto_editor-25.1.0.dist-info/METADATA,sha256=-ykd7lb64wdOX5OM7-ZsOhGr_CV4nmJKDomNyPzzvbY,6137
55
+ auto_editor-25.1.0.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
56
+ auto_editor-25.1.0.dist-info/entry_points.txt,sha256=-H7zdTw4MqnAcwrN5xTNkGIhzZtJMxS9r6lTMeR9-aA,240
57
+ auto_editor-25.1.0.dist-info/top_level.txt,sha256=jBV5zlbWRbKOa-xaWPvTD45QL7lGExx2BDzv-Ji4dTw,17
58
+ auto_editor-25.1.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (72.1.0)
2
+ Generator: setuptools (74.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
docs/build.py ADDED
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import os
4
+ import sys
5
+
6
+ # Put 'auto_editor' in Python path
7
+ sys.path.append(os.path.dirname(os.path.dirname(__file__)))
8
+
9
+ import auto_editor.vanparse as vanparse
10
+ from auto_editor.__main__ import main_options
11
+ from auto_editor.lang.palet import Lexer, Parser, env, interpret
12
+ from auto_editor.lang.stdenv import make_standard_env
13
+ from auto_editor.vanparse import OptionText
14
+
15
+
16
+ def main():
17
+ parser = vanparse.ArgumentParser("Auto-Editor")
18
+ parser = main_options(parser)
19
+
20
+ with open("src/ref/options.html", "w") as file:
21
+ file.write(
22
+ '{{ header-desc "Options" "These are the options and flags that auto-editor uses." }}\n'
23
+ "<body>\n"
24
+ "{{ nav }}\n"
25
+ '<section class="section">\n'
26
+ '<div class="container">\n'
27
+ )
28
+ for op in parser.args:
29
+ if isinstance(op, OptionText):
30
+ file.write(f"<h2>{op.text}</h2>\n")
31
+ else:
32
+ file.write(f"<h3><code>{op.names[0]}</code></h3>\n")
33
+ if len(op.names) > 1:
34
+ file.write(
35
+ "<h4><code>"
36
+ + "</code> <code>".join(op.names[1:])
37
+ + "</code></h4>\n"
38
+ )
39
+
40
+ file.write(f"<p>{op.help}</p>\n")
41
+
42
+ file.write("</div>\n</section>\n</body>\n</html>\n\n")
43
+
44
+ env.update(make_standard_env())
45
+ with open("doc.pal") as sourcefile:
46
+ try:
47
+ interpret(env, Parser(Lexer("doc.pal", sourcefile.read())))
48
+ except Exception as e:
49
+ print(e)
50
+ quit(1)
51
+
52
+ if __name__ == "__main__":
53
+ main()