-
Notifications
You must be signed in to change notification settings - Fork 0
Hua work miscs #24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hua work miscs #24
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -18,6 +18,7 @@ | |||||||||||
| import inspect | ||||||||||||
| import argparse | ||||||||||||
| import importlib | ||||||||||||
| import importlib.util | ||||||||||||
| from os import path as op | ||||||||||||
| from rda_python_common.pg_file import PgFile | ||||||||||||
| from rda_python_common.pg_util import PgUtil | ||||||||||||
|
|
@@ -1164,6 +1165,62 @@ def load_opts_alias(self, docname): | |||||||||||
|
|
||||||||||||
| return opts, alias, origin | ||||||||||||
|
|
||||||||||||
| def load_opts_alias_from_pyfile(self, pyfile): | ||||||||||||
| """Load OPTS and ALIAS from a Python file given by path. | ||||||||||||
|
|
||||||||||||
| Uses ``importlib.util.spec_from_file_location`` to import the file | ||||||||||||
| without requiring it to be on ``sys.path``. Resolution order mirrors | ||||||||||||
| :meth:`load_opts_alias`: class attributes first, then module-level. | ||||||||||||
|
|
||||||||||||
| Args: | ||||||||||||
| pyfile (str): Absolute or relative path to the Python source file. | ||||||||||||
|
|
||||||||||||
| Returns: | ||||||||||||
| tuple[dict, dict]: ``(OPTS, ALIAS)`` where ALIAS defaults to ``{}`` | ||||||||||||
| when not found. | ||||||||||||
|
|
||||||||||||
| Raises: | ||||||||||||
| SystemExit: via :func:`PgLOG.pglog` (``LGWNEX``) if the file | ||||||||||||
| cannot be loaded or ``OPTS`` cannot be found. | ||||||||||||
| """ | ||||||||||||
| pyfile = op.abspath(pyfile) | ||||||||||||
| modname = op.splitext(op.basename(pyfile))[0] | ||||||||||||
| try: | ||||||||||||
| spec = importlib.util.spec_from_file_location(modname, pyfile) | ||||||||||||
| mod = importlib.util.module_from_spec(spec) | ||||||||||||
| spec.loader.exec_module(mod) | ||||||||||||
| except Exception as exc: | ||||||||||||
| self.pglog( | ||||||||||||
| "Cannot load module from '{}': {}".format(pyfile, exc), | ||||||||||||
| self.LGWNEX, | ||||||||||||
| ) | ||||||||||||
|
|
||||||||||||
| cls = next( | ||||||||||||
| (obj for _, obj in inspect.getmembers(mod, inspect.isclass) | ||||||||||||
| if obj.__module__ == modname), | ||||||||||||
| None, | ||||||||||||
| ) | ||||||||||||
|
|
||||||||||||
| if cls is not None: | ||||||||||||
| obj = cls() | ||||||||||||
| opts = getattr(obj, 'OPTS', None) | ||||||||||||
| alias = getattr(obj, 'ALIAS', None) | ||||||||||||
| else: | ||||||||||||
| opts = getattr(mod, 'OPTS', None) | ||||||||||||
| alias = getattr(mod, 'ALIAS', None) | ||||||||||||
|
|
||||||||||||
| if opts is None: | ||||||||||||
| self.pglog( | ||||||||||||
| "File '{}' does not define OPTS (checked class and " | ||||||||||||
| "module level)".format(pyfile), | ||||||||||||
| self.LGWNEX, | ||||||||||||
| ) | ||||||||||||
|
|
||||||||||||
| if alias is None: | ||||||||||||
| alias = {} | ||||||||||||
|
|
||||||||||||
| return opts, alias | ||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| # --------------------------------------------------------------------------- | ||||||||||||
| # Command-line entry point | ||||||||||||
|
|
@@ -1174,40 +1231,81 @@ def main(): | |||||||||||
| parser = argparse.ArgumentParser( | ||||||||||||
| description=( | ||||||||||||
| "Convert a .usg help document to reStructuredText (.rst) using RST templates. " | ||||||||||||
| "OPTS and ALIAS are loaded from rda_python_<docname>/<docname>.py: " | ||||||||||||
| "the module is searched first for module-level OPTS/ALIAS variables, " | ||||||||||||
| "then for a class defined in that module that carries both as class " | ||||||||||||
| "attributes." | ||||||||||||
| "OPTS and ALIAS are loaded from rda_python_<docname>/<docname>.py " | ||||||||||||
| "(or from --pyfile if given): " | ||||||||||||
| "the module is searched first for a class that carries both as class " | ||||||||||||
| "attributes, then for module-level OPTS/ALIAS variables." | ||||||||||||
|
Comment on lines
+1236
to
+1237
|
||||||||||||
| "the module is searched first for a class that carries both as class " | |
| "attributes, then for module-level OPTS/ALIAS variables." | |
| "the module is searched first for a class that defines OPTS " | |
| "(and optionally ALIAS) as class attributes, then for module-level " | |
| "OPTS (and optionally ALIAS) variables." |
Copilot
AI
Apr 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--docdir help text says a “per-document RST output directory is created”, but process_docs() writes directly into DOCS['DOCDIR'] (no <docdir>/<docname>/ subdir is created). Consider adjusting the wording to avoid implying a per-document subdirectory.
Copilot
AI
Apr 13, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When --pyfile is provided (and --usgfile is not), ORIGIN remains the default os.getcwd(). This makes parse_docs() look for <cwd>/<docname>.usg, which is inconsistent with the load_opts_alias() path-based behavior (it derives ORIGIN from the module’s location). Consider setting pg.DOCS['ORIGIN'] to the directory containing --pyfile (or returning an origin from load_opts_alias_from_pyfile()) so the default .usg lookup works when bypassing the import convention.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
load_opts_alias_from_pyfile()selects the first class defined in the module, but it doesn’t verify that the class actually definesOPTS(orALIAS). If the module defines any helper class before the config class,optsbecomesNoneand the function errors even when module-levelOPTS(or another class’sOPTS) exists. Consider iterating classes defined in the module and picking the first one wheregetattr(cls, 'OPTS', None)is notNone, otherwise fall back to module-levelOPTS/ALIAS(and avoid instantiating the class just to read class attributes).