-
Notifications
You must be signed in to change notification settings - Fork 2
Floating point values and Python updates #42
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
Open
prkrtg
wants to merge
34
commits into
main
Choose a base branch
from
test_pgupta_fpt
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
0dc65a9
start on a unified CLI callable for WDL
weatherhead99 7b34d3a
clarify a comment
weatherhead99 4799da0
initial attempt at a replacement for ini2acf.pl
weatherhead99 3a11426
script installs and finish initial ini2acf replacement
weatherhead99 8220c16
add minimum required python
weatherhead99 c841ef1
allow executing wdl directly as a module
weatherhead99 7653bb9
add ini2acf subcommand to new CLI app
weatherhead99 694ccf8
fix (very bad) typo in pyproject.toml definition
weatherhead99 07387dd
glob is not a function in pathlib, but a function of Path
weatherhead99 1f6b5b5
refactor CLI command code
weatherhead99 27d08ae
start on preprocessor utility commands
weatherhead99 11d8817
more minor driver CLI fixes
weatherhead99 c6ddfde
add import hacks to all legacy drivers so they can be directly run in…
weatherhead99 a8088e5
finish ini2acf script rewrite
weatherhead99 059e7b0
remove spurious extra prints.
weatherhead99 b1bda95
work on building in gpp preprocessor
weatherhead99 2ae7e89
fix issue in ini2acf where some sections were not emitted
weatherhead99 96dff5a
add missing config tag in generated acf
8046b97
Handle special sequence "Start" that does not require an exit. (#26)
scizen9 600849f
Allow floating point values
prkrtg 1429782
allow float constants
astronomerdave 63edd7e
Ability to use contants for waveforms and slots
prkrtg 2791ac6
fix xvbias
prkrtg 781500f
fix modegen driver to actually append the modes
29fd2be
fix regex for matching taplines
c3471c9
silence a bunch of errors, fix incorrect module numbering
288e098
remove warnings about invalid escape sequences by making regex search…
fd09289
set packages to properly include the library when using standalone build
b3294f6
fix more warnings about invalid regex strings, fix invalid conversion…
2ad6496
fix missing ENABLE statement for the first clock driver definition
d6e99bc
add -ve numbers to Number parsing, and fixes constants generation. DO…
244fe0e
improve negative number parsing. Still not generated properly for usi…
7cbc539
remove extra emitted - sign from XVBias generation
df425c3
Minor bug fix and clean up
prkrtg File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| from wdl.cli import main | ||
|
|
||
| if __name__ == "__main__": | ||
| main() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| from argparse import ArgumentParser | ||
| import sys | ||
| from .commands.driverbase import WDLDriver | ||
| from .commands.legacy_drivers import ( | ||
| SeqParserDriver, ModParserDriver, IncParserDriver, | ||
| WdlParserDriver, WavgenDriver, ModegenDriver, Ini2acfDriver) | ||
|
|
||
| from .commands.preprocess import FindGPP, PreprocessGPP | ||
|
|
||
| import logging | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
| def main(): | ||
| ap = ArgumentParser(prog="wdl", | ||
| description="command line interface to Waveform Definition Language (WDL)") | ||
| ap.add_argument("--debug", help="print verbose debugging output", action="store_true") | ||
| subparsers = ap.add_subparsers(required=True, help="the WDL subcommand to run", | ||
| dest="command_name") | ||
|
|
||
| #NOTE: could have done a fancy autoreg thing here but there's only a few and this is likely | ||
| #clearer until there are lots more IMO | ||
| command_classes: list[type] = [SeqParserDriver, ModParserDriver, IncParserDriver, WdlParserDriver, | ||
| WavgenDriver, ModegenDriver, Ini2acfDriver, FindGPP, PreprocessGPP] | ||
|
|
||
| for cls in command_classes: | ||
| cls.setup_subparser(subparsers) | ||
|
|
||
| args, unknown_args = ap.parse_known_args() | ||
|
|
||
|
|
||
| if args.debug: | ||
| logging.basicConfig(level=logging.DEBUG) | ||
| else: | ||
| logging.basicConfig(level=logging.INFO) | ||
|
|
||
| #the default func is setup by the class method above to just return which class it is | ||
| #that will be operating the command | ||
| run_command_tp: type[WDLDriver] = args.func(args) | ||
|
|
||
| if run_command_tp.ACCEPTS_EXTRA_ARGS: | ||
| obj = run_command_tp(unknown_args, **vars(args)) | ||
| elif len(unknown_args) > 0: | ||
| logger.error("extra (unknown) arguments provided to command that doesn't accept them") | ||
| logger.error(f"those arguments were: {unknown_args}") | ||
| #my instinct is to throw here but that seems unpopular round these parts so just bail out | ||
| sys.exit(1) | ||
| else: | ||
| kwargs = vars(args) | ||
| obj = run_command_tp(**kwargs) | ||
|
|
||
| #run the command | ||
| return obj(cli_mode=True) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| retcode = main() | ||
| sys.exit(retcode) |
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| from abc import ABCMeta, abstractmethod | ||
| from argparse import ArgumentParser, _SubParsersAction, Namespace | ||
| from pathlib import Path | ||
| from io import TextIOWrapper | ||
| from sys import stdin | ||
| from contextlib import contextmanager | ||
| from typing import ContextManager | ||
|
|
||
| class WDLDriver(metaclass=ABCMeta): | ||
| ACCEPTS_EXTRA_ARGS: bool = False | ||
|
|
||
| @classmethod | ||
| def setup_subparser(cls, subparsers: _SubParsersAction, fname_arg_setup: bool=True) -> ArgumentParser: | ||
| """sets up a sub-parser for arguments specific to this particular type of WDL subcommand driver""" | ||
|
|
||
| #Get a name to put in the parser, either explicit or named after the class | ||
| cmdname: str = getattr(cls, "CMD_NAME", cls.__name__) | ||
| cmddesc: str = getattr(cls, "CMD_DESCRIPTION", None) | ||
| parser = subparsers.add_parser(name=cmdname, description=cmddesc) | ||
|
|
||
| if fname_arg_setup: | ||
| parser.add_argument("fname", help="file to read input from. Use '-' to read from stdin") | ||
|
|
||
| def cls_provider(args: Namespace) -> None: | ||
| return cls | ||
|
|
||
| parser.set_defaults(func=cls_provider) | ||
| return parser | ||
|
|
||
| @classmethod | ||
| def find_input_files(cls, basepath: str | Path) -> list[str]: | ||
| if not hasattr(cls, "CMD_FILE_EXTENSIONS"): | ||
| raise AttributeError("don't know file extensions to search for") | ||
| if isinstance(basepath, str): | ||
| basepath: Path = Path(basepath) | ||
| for extn in cls.CMD_FILE_EXTENSIONS: | ||
| possible_files = basepath.glob(f"*.{extn}") | ||
| return possible_files | ||
|
|
||
| def __init__(self, fname: str, **kwargs): | ||
| """The default __init__ of a driver takes a filename and reads it into the ._text attribute of the class. | ||
| Since this is the most common operation of a WDL driver program""" | ||
| self._text = self._read_file_or_stdin(fname) | ||
|
|
||
| @abstractmethod | ||
| def __call__(self, cli_mode: bool) -> None: | ||
| """This method will be called when the driver runs from the command line interface""" | ||
| pass | ||
|
|
||
| @contextmanager | ||
| def _file_or_stdin(self, fname: str) -> ContextManager[TextIOWrapper]: | ||
| """context manager that opens a specified file or uses sys.stdin for the special case of file '-'""" | ||
| if fname == "-": | ||
| yield stdin | ||
| else: | ||
| f = open(fname, "r") | ||
| yield f | ||
| f.close() | ||
|
|
||
| @contextmanager | ||
| def _file_or_stdout(self, output: TextIOWrapper | str) -> ContextManager[TextIOWrapper]: | ||
| if isinstance(output, str): | ||
| f = open(output, "w") | ||
| yield f | ||
| else: | ||
| yield output | ||
|
|
||
| def _read_file_or_stdin(self, fname: str) -> str: | ||
| with self._file_or_stdin(fname) as f: | ||
| return f.read() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,171 @@ | ||
| import logging | ||
| import warnings | ||
| from typing import Optional | ||
| from argparse import ArgumentParser | ||
| from sys import stdout | ||
| import os | ||
| from .driverbase import WDLDriver | ||
|
|
||
| from wdl.ini2acf import generate_acf | ||
|
|
||
|
|
||
| # horrible legacy code imports here, TODO: gradually chip away at it | ||
| import wdl.wavgen as wavgen | ||
| import wdl.modegen as modegen | ||
| from wdl.wdlParser import make_include_sequence, parse_modules, parse_system, make_include | ||
| import wdl.wdlParser as Parser | ||
|
|
||
| # TODO: separate out plotting, no need for this | ||
| import matplotlib.pyplot as plt | ||
|
|
||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| class SeqParserDriver(WDLDriver): | ||
| CMD_NAME: str = "seq" | ||
| CMD_DESCRIPTION: str = "parse a .conf file and make an include list from it" | ||
|
|
||
| def __call__(self, cli_mode: bool) -> int: | ||
| logger.info("making include sequence") | ||
| make_include_sequence(self._text) | ||
| return 0 | ||
|
|
||
|
|
||
| class ModParserDriver(WDLDriver): | ||
| CMD_NAME: str = "mod" | ||
| CMD_DESCRIPTION: str = "parse a .mod file and create .system and .modules from it" | ||
|
|
||
| @classmethod | ||
| def setup_subparser(cls, *args, **kwargs) -> ArgumentParser: | ||
| parser = super().setup_subparser(*args, **kwargs) | ||
| parser.add_argument("--projname", type=str, help="""project name to use. If not given, | ||
| the legacy behaviour is followed (the first line of the input text is assumed to be the project name""") | ||
| return parser | ||
|
|
||
| def __init__(self, fname: str, projname: Optional[str] = None, **kwargs): | ||
| with self._file_or_stdin(fname) as f: | ||
| if projname is None: | ||
| warnings.warn("parsing module file assuming the first line is the project name... please use the --name argument to the command instead") | ||
| projname = f.readline().strip() | ||
|
|
||
| logger.info("project name is: %s", projname) | ||
| self._projname: str = projname | ||
| self._text: str = f.read() | ||
|
|
||
| def __call__(self, cli_mode: bool) -> int: | ||
| logger.debug("writing output to .modules file...") | ||
| self._write_output("CONFIG", "modules", parse_modules(self._text)) | ||
|
|
||
| #Presumably the reason parse_system() here needs no keywords is some hideous global state | ||
| # awfulness. DO NOT MOVE THIS LINE ABOVE THE PREVIOUS ONE, therefore | ||
| logger.debug("writing output to .system file...") | ||
| self._write_output("SYSTEM", "system", parse_system()) | ||
| return 0 | ||
|
|
||
| def _write_output(self, archonkw: str, fileext: str, output: str) -> int: | ||
| fname: str = f"{self._projname}.{fileext}" | ||
| logger.debug("filename is: %s", fname) | ||
| with open(fname, "w") as f: | ||
| f.writelines([f"[{archonkw}]{os.linesep}"]) | ||
| f.write(output) | ||
|
|
||
| class IncParserDriver(WDLDriver): | ||
| CMD_NAME: str = "inc" | ||
| CMD_DESCRIPTION: str = "parse an include file" | ||
|
|
||
| def __call__(self, cli_mode: bool) -> int: | ||
| make_include(self._text) | ||
| return 0 | ||
|
|
||
| class WdlParserDriver(WDLDriver): | ||
| CMD_NAME: str = "wdl" | ||
| CMD_DESCRIPTION: str = "parse the subroutines from a WDL input file" | ||
|
|
||
| def __call__(self, cli_mode: bool) -> int: | ||
| logger.info("parsing WDL file...") | ||
|
|
||
| # TODO:blergh | ||
| global subroutines | ||
| subroutines = Parser.get_subroutines(self._text) | ||
| Parser.get_params(self._text) | ||
| output: str = Parser.parse(self._text) | ||
|
|
||
| #apparently this one just prints it out, to stdout I guess? | ||
| stdout.write(output) | ||
| return 0 | ||
|
|
||
| class WavgenDriver(WDLDriver): | ||
| CMD_NAME: str = "wavgen" | ||
| CMD_DESCRIPTION: str = "generate archon waveforms from WDL description" | ||
|
|
||
| @classmethod | ||
| def setup_subparser(cls, *args, **kwargs) -> ArgumentParser: | ||
| parser = super().setup_subparser(*args, **kwargs) | ||
| parser.add_argument("--plots", action="store_true", help="generate plots to go with waveforms") | ||
| return parser | ||
|
|
||
| def __init__(self, fname: str, plots: bool, **kwargs): | ||
| #For some reason I don't understand, legacy wavegenDriver.py wants the BASE NAME of the project as | ||
| #the argument, not the actual filename. Implement this behaviour here for compatibility even though | ||
| #I must stress it seems a little odd | ||
|
|
||
| self._fname: str = fname | ||
| self._plots: bool = plots | ||
|
|
||
| def __call__(self, cli_mode: bool) -> int: | ||
| # global variable because OF COURSE IT IS | ||
| wavgen.GenerateFigs = self._plots | ||
| wavgen.loadWDL(f"{self._fname}.wdl", self._fname) | ||
|
|
||
| # ok this breaks previous behaviour because even if plot option was false | ||
| # the original program still did a plt.show(). This seems utterly without reason to me | ||
| # so here we only actually do that if it was asked for... | ||
| # Again, all the plots are done with implicit global state rather than using the MPL object interface... | ||
| if self._plots: | ||
| plt.show(block=True) | ||
|
|
||
| return 0 | ||
|
|
||
|
|
||
| class ModegenDriver(WDLDriver): | ||
| CMD_NAME: str = "modegen" | ||
| CMD_DESCRIPTION: str = "generate archon modes from WDL description" | ||
|
|
||
| @classmethod | ||
| def setup_subparser(cls, subparsers) -> ArgumentParser: | ||
| parser = super().setup_subparser(subparsers, fname_arg_setup=False) | ||
| #need two filenames here, a mode file and an acf file | ||
| parser.add_argument("modefile", type=str, help="the mode file to use") | ||
| parser.add_argument("acffile", type=str, help="the ACF file to append to") | ||
| return parser | ||
|
|
||
| def __init__(self, modefile: str, acffile: str, **kwargs): | ||
| self._modefile = modefile | ||
| self._acffile = acffile | ||
|
|
||
| def __call__(self, cli_mode: bool, append: bool=True) -> int: | ||
| mobj = modegen.Modegen(self._modefile, self._acffile) | ||
| mobj.write(append) | ||
| return 0 | ||
|
|
||
| class Ini2acfDriver(WDLDriver): | ||
| CMD_NAME: str = "ini2acf" | ||
| CMD_DESCRIPTION: str = "convert a INI syntax file into ACF" | ||
|
|
||
| @classmethod | ||
| def setup_subparser(cls, subparsers) -> ArgumentParser: | ||
| parser = super().setup_subparser(subparsers) | ||
| parser.add_argument("-o,--outfile",help="output file to use. By default, outputs to stdout", type=str) | ||
| return parser | ||
|
|
||
| def __init__(self, fname: str, outfile: Optional[str]=None, **kwargs): | ||
| super().__init__(fname) | ||
| self._outfile = stdout if outfile is None else outfile | ||
|
|
||
| def __call__(self, cli_mode: bool) -> int: | ||
| outtxt: str = generate_acf(self._text, treat_str_as_content=True) | ||
| with self._file_or_stdout(self._outfile) as f: | ||
| logger.debug(f"outtxt is: {outtxt}") | ||
| f.write(outtxt) | ||
| return 0 |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
this likely needs the same hack as Lexer.py and seqParserDriver.py etc,
old WDL makefiles assume you can call these directly, and also assume that they're sat directly next to top level imports of other WDL stuff. The "new" cli I wrote doesn't. So we need to support both to prevent breakage of old WDL code. I think I didn't find any instance where LexerDriver.py was actually run directly in a Makefile context but I could be wrong about that.