Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ Instructions: Add a subsection under `[Unreleased]` for additions, fixes, change

## [Unreleased]

# Added

- You can now specify the debug level *after* the command (e.g., `pretext -v debug build` can now also be entered as `pretext build -v debug`).
- Temporary directories created by core pretext will now be cleaned up at all debug levels. To save them for debugging, use the `--save-tmp-dirs` flag, as in `pretext --save-tmp-dirs build`.

## [2.41.2] - 2026-06-07

Includes updates to core through commit: [fc8221d](https://github.com/PreTeXtBook/pretext/commit/fc8221d5b8e7027f686729102e169c482fbd1fe5)
Expand Down
2 changes: 1 addition & 1 deletion pretext/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
VERSION = get_version("pretext", Path(__file__).parent.parent)


CORE_COMMIT = "fc8221d5b8e7027f686729102e169c482fbd1fe5"
CORE_COMMIT = "7bef656c9f303489fc07d719df52108c1970ca26"


def activate() -> None:
Expand Down
60 changes: 56 additions & 4 deletions pretext/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,48 @@ def try_except(ctx: click.Context, *args: Any, **kwargs: Any) -> Any:

CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])

_VERBOSITY_HELP = "Sets the severity of log messaging: DEBUG for all, INFO (default) for most, then WARNING, ERROR, and CRITICAL for decreasing verbosity."


def set_log_level(
_ctx: click.Context, _param: click.Parameter, value: Optional[str]
) -> None:
_ = (_ctx, _param) # Click's callback protocol requires these; not used here.
if value:
log.setLevel(value.upper())


class PreTeXtGroup(click.Group):
"""Click Group that injects a -v/--verbosity option into every subcommand so that
`pretext build -v debug` works in addition to the canonical `pretext -v debug build`.
"""

def command(self, *args: Any, **kwargs: Any) -> Any:
original_decorator = super().command(*args, **kwargs)

def decorator(f: Callable[..., Any]) -> Any:
f = click.option(
"--verbosity",
"-v",
default=None,
expose_value=False,
is_eager=True,
callback=set_log_level,
type=click.Choice(
["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
case_sensitive=False,
),
help=_VERBOSITY_HELP,
)(f)
return original_decorator(f)

return decorator


# Click command-line interface
@click.group(invoke_without_command=True, context_settings=CONTEXT_SETTINGS)
@click.group(
cls=PreTeXtGroup, invoke_without_command=True, context_settings=CONTEXT_SETTINGS
)
@click.pass_context
# Allow a verbosity command:
@click_log.simple_verbosity_option(
Expand All @@ -96,8 +135,13 @@ def try_except(ctx: click.Context, *args: Any, **kwargs: Any) -> Any:
is_flag=True,
help='Display list of build/view "targets" available in the project manifest.',
)
@click.option(
"--save-tmp-dirs",
is_flag=True,
help="Do not clean temporary directories after a build or generate. Might be useful for debugging (previously calling -v debug would also save these directories).",
)
@nice_errors
def main(ctx: click.Context, targets: bool) -> None:
def main(ctx: click.Context, targets: bool, save_tmp_dirs: bool) -> None:
"""
Command line tools for quickly creating, authoring, and building PreTeXt projects.

Expand Down Expand Up @@ -177,7 +221,7 @@ def main(ctx: click.Context, targets: bool) -> None:
f"No project.ptx manifest found in current workspace. Using global configuration specified in '~/.ptx/{VERSION}/project.ptx'."
)
# Add project to context so it can be used in subcommands
ctx.obj = {"project": project}
ctx.obj = {"project": project, "save_tmp_dirs": save_tmp_dirs}


@main.result_callback()
Expand Down Expand Up @@ -552,6 +596,7 @@ def build(
# Create a new project, apply overlay, and get target. Note, the CLI always finds changes to the root folder of the project, so we don't need to specify a path to the project.ptx file.
# Use the project discovered in the main command.
project = ctx.obj["project"]
save_tmp_dirs = ctx.obj.get("save_tmp_dirs", False)

# Check to see whether target_name is a path to a file:
if target_name and Path(target_name).is_file():
Expand Down Expand Up @@ -620,7 +665,11 @@ def build(
for t in targets:
log.info(f"Generating assets for {t.name}")
t.generate_assets(
only_changed=False, xmlid=xmlid, clean=clean, skip_cache=True
only_changed=False,
xmlid=xmlid,
clean=clean,
skip_cache=True,
clean_tmp_dirs=not save_tmp_dirs,
)
no_generate = True
except Exception as e:
Expand All @@ -645,6 +694,7 @@ def build(
xmlid=xmlid,
no_knowls=no_knowls,
latex=latex,
clean_tmp_dirs=not save_tmp_dirs,
)
if t.format == "html" and t.compression is None:
log.info(
Expand Down Expand Up @@ -761,6 +811,7 @@ def generate(
return

project = ctx.obj["project"]
save_tmp_dirs = ctx.obj.get("save_tmp_dirs", False)
# Now create the target if the target_name is not missing.
try:
target = project.get_target(name=target_name)
Expand All @@ -780,6 +831,7 @@ def generate(
clean=clean,
skip_cache=force,
slow=slow,
clean_tmp_dirs=not save_tmp_dirs,
)
# Check if there are errors reported by the build by looking at the error_flush_handler.
if utils.has_errors(error_flush_handler):
Expand Down
26 changes: 15 additions & 11 deletions pretext/project/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ def save_asset_table(self, asset_table: pt.AssetTable) -> None:
) as f:
json.dump(asset_table, f)

def ensure_myopenmath_xml(self) -> None:
def ensure_myopenmath_xml(self, clean_tmp_dirs: bool = True) -> None:
"""
Ensures that the myopenmath xml files are present if the source contains myopenmath exercises. Needed to generate other "static" assets and targets.
"""
Expand All @@ -607,14 +607,16 @@ def ensure_myopenmath_xml(self) -> None:
f"MyOpenMath problem {prob_num} does not exist, generating"
)
self.generate_assets(
requested_asset_types=["myopenmath"], only_changed=False
requested_asset_types=["myopenmath"],
only_changed=False,
clean_tmp_dirs=clean_tmp_dirs,
)
# Only need to generate once a single missing file is discovered.
break
else:
log.debug("Source does not contain myopenmath problems")

def ensure_webwork_reps(self) -> None:
def ensure_webwork_reps(self, clean_tmp_dirs: bool = True) -> None:
"""
Ensures that the webwork representation file is present if the source contains webwork problems. This is needed to build or generate other assets.
"""
Expand All @@ -634,7 +636,9 @@ def ensure_webwork_reps(self) -> None:
f'At least one WeBWorK representation file (for webwork problem with id "{id}") does not exist, generating'
)
self.generate_assets(
requested_asset_types=["webwork"], only_changed=False
requested_asset_types=["webwork"],
only_changed=False,
clean_tmp_dirs=clean_tmp_dirs,
)
break
else:
Expand Down Expand Up @@ -720,6 +724,7 @@ def build(
xmlid: t.Optional[str] = None,
no_knowls: bool = False,
latex: bool = False,
clean_tmp_dirs: bool = True,
) -> None:
# Add cli.version to stringparams. Use only the major and minor version numbers.
self.stringparams["cli.version"] = VERSION[: VERSION.rfind(".")]
Expand All @@ -744,11 +749,11 @@ def build(
self.ensure_asset_directories()

# verify that a webwork_representations.xml file exists if it is needed; generated if needed.
self.ensure_webwork_reps()
self.ensure_webwork_reps(clean_tmp_dirs=clean_tmp_dirs)

# Generate needed assets unless requested not to.
if generate:
self.generate_assets(xmlid=xmlid)
self.generate_assets(xmlid=xmlid, clean_tmp_dirs=clean_tmp_dirs)

# Ensure the output directories exist.
self.ensure_output_directory()
Expand Down Expand Up @@ -936,7 +941,7 @@ def build(
log.critical(f"Unknown format {self.format}")
# Delete temporary directories left behind by core:
try:
core.release_temporary_directories()
core.release_temporary_directories(any_log_level=clean_tmp_dirs)
except Exception as e:
log.error(
"Unable to release temporary directories. Please report this error to pretext-support"
Expand All @@ -952,6 +957,7 @@ def generate_assets(
clean: bool = False,
skip_cache: bool = False,
slow: bool = False,
clean_tmp_dirs: bool = True,
) -> None:
"""
Generates assets for the current target. Options:
Expand Down Expand Up @@ -1320,11 +1326,9 @@ def generate_assets(
# log.debug(e, exc_info=True)
# Delete temporary directories left behind by core:
try:
core.release_temporary_directories()
core.release_temporary_directories(any_log_level=clean_tmp_dirs)
except Exception as e:
log.error(
"Unable to release temporary directories. Please report this error to pretext-support"
)
log.debug("Unable to release temporary directories.")
log.debug(e, exc_info=True)
# After all assets are generated, update the asset cache (but we shouldn't do this if we didn't generate any assets successfully)
log.debug(f"Updated these assets successfully: {successful_assets}")
Expand Down
Loading