From 8ba236010fd3ee489c45d25b43522c1a40fc00d3 Mon Sep 17 00:00:00 2001 From: Wes Bonelli Date: Sat, 5 Aug 2023 23:01:31 -0400 Subject: [PATCH] docs: track deprecations in release notes * add script doc/mf6io/mf6ivar/deprecations.py to scrape DFNs and generate markdown table * run deprecations script in docs.yml CI and upload result file as artifact * add deprecations page to ReadTheDocs * add mk_deprecations.py script to convert markdown deprecations to LaTeX table * include deprecations in release notes * add deprecation policy section to DEVELOPER.md --- .build_rtd_docs/conf.py | 9 + .build_rtd_docs/index.rst | 1 + .github/workflows/docs.yml | 26 +- .github/workflows/release.yml | 14 ++ DEVELOPER.md | 16 ++ distribution/build_docs.py | 32 ++- doc/ReleaseNotes/ReleaseNotes.tex | 4 + doc/ReleaseNotes/mk_deprecations.py | 72 ++++++ doc/mf6io/mf6ivar/deprecations.py | 52 ++++ doc/mf6io/mf6ivar/md/deprecations.md | 14 ++ doc/mf6io/mf6ivar/mf6ivar.py | 351 ++++++++++++++------------- doc/mf6io/mf6ivar/readme.md | 2 + 12 files changed, 405 insertions(+), 188 deletions(-) create mode 100644 doc/ReleaseNotes/mk_deprecations.py create mode 100644 doc/mf6io/mf6ivar/deprecations.py create mode 100644 doc/mf6io/mf6ivar/md/deprecations.md diff --git a/.build_rtd_docs/conf.py b/.build_rtd_docs/conf.py index bfd38623e25..42afe291120 100644 --- a/.build_rtd_docs/conf.py +++ b/.build_rtd_docs/conf.py @@ -56,6 +56,15 @@ # copy the file shutil.copy(src, dst) +# -- copy deprecations markdown --------------------------------------------- +print("Copy the deprecations table") +dstdir = "_mf6run" +fpth = "deprecations.md" +src = os.path.join("..", "doc", "mf6io", "mf6ivar", "md", fpth) +dst = os.path.join(dstdir, fpth) +# copy the file +shutil.copy(src, dst) + # -- build the mf6io markdown files ----------------------------------------- print("Build the mf6io markdown files") pth = os.path.join("..", "doc", "mf6io", "mf6ivar") diff --git a/.build_rtd_docs/index.rst b/.build_rtd_docs/index.rst index e5b8ee8cae1..813d5a4daff 100644 --- a/.build_rtd_docs/index.rst +++ b/.build_rtd_docs/index.rst @@ -14,4 +14,5 @@ Contents: MODFLOW 6 Source Code Documentation mf6io _mf6run/run-time-comparison.md + _mf6run/deprecations.md diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 0a1a47e9bc5..67c398b7fdb 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -105,21 +105,35 @@ jobs: run: python benchmark.py env: GITHUB_TOKEN: ${{ github.token }} - - - name: Run sphinx - working-directory: modflow6/.build_rtd_docs - run: make html - + - name: Show benchmarks working-directory: modflow6/distribution run: cat run-time-comparison.md - + - name: Upload benchmarks uses: actions/upload-artifact@v3 with: name: run-time-comparison path: modflow6/distribution/run-time-comparison.md + - name: Collect deprecations + working-directory: modflow6/doc/mf6io/mf6ivar + run: python deprecations.py + + - name: Show deprecations + working-directory: modflow6/doc/mf6io/mf6ivar/md + run: cat deprecations.md + + - name: Upload deprecations + uses: actions/upload-artifact@v3 + with: + name: deprecations + path: modflow6/doc/mf6io/mf6ivar/md/deprecations.md + + - name: Run sphinx + working-directory: modflow6/.build_rtd_docs + run: make html + - name: Upload results uses: actions/upload-artifact@v3 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index efe4b7be4c2..b924c8f9b44 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -353,6 +353,20 @@ jobs: cd modflow6/doc/ReleaseNotes python mk_folder_struct.py -dp "${{ github.workspace }}/$distname" + - name: Collect deprecations + working-directory: modflow6/doc/mf6io/mf6ivar + run: python deprecations.py + + - name: Show deprecations + working-directory: modflow6/doc/mf6io/mf6ivar/md + run: cat deprecations.md + + - name: Upload deprecations + uses: actions/upload-artifact@v3 + with: + name: deprecations + path: modflow6/doc/mf6io/mf6ivar/md/deprecations.md + - name: Build documentation env: # need a GITHUB_TOKEN to download example doc PDF asset from modflow6-examples repo diff --git a/DEVELOPER.md b/DEVELOPER.md index 99e7b4d086d..43c104f0c82 100644 --- a/DEVELOPER.md +++ b/DEVELOPER.md @@ -576,3 +576,19 @@ git branch -d feat-xyz-backup ``` This process can be repeated periodically to stay in sync with the develop branch and keep a clean commit history. + +## Deprecation policy + +To deprecate a MODFLOW 6 input/output option in a DFN file: + +- Add a line `deprecated x.y.z` to the option block in the appropriate DFN file, where `x.y.z` is the version the deprecation is introduced. Mention the deprecation prominently in the release notes. +- If support for the deprecated option is removed (typically after at least 2 minor or major releases or 1 year), add a line `removed x.y.z` to the options block, where `x.y.z` is the version in which support for the option was removed. Mention the removal prominently in the release notes. +- Deprecated/removed options are not removed from DFN files but remain in perpetuity. The `doc/mf6io/mf6ivar/mf6ivar.py` script generates a markdown deprecation table which is converted to LaTeX by `doc/ReleaseNotes/mk_deprecations.py` for inclusion in the MODFLOW 6 release notes. Deprecations and removals should still be mentioned separately in the release notes, however. + +### Finding deprecations + +To search for `deprecated` (or substitute `removed`) options with `git`: + +```shell +git grep 'deprecated' -- '*.dfn' | awk '/^*.dfn:deprecated/' +``` diff --git a/distribution/build_docs.py b/distribution/build_docs.py index 37d5ad57fa6..7ebd88e48c3 100644 --- a/distribution/build_docs.py +++ b/distribution/build_docs.py @@ -30,7 +30,7 @@ _examples_repo_path = _project_root_path.parent / "modflow6-examples" _release_notes_path = _project_root_path / "doc" / "ReleaseNotes" _distribution_path = _project_root_path / "distribution" -_benchmarks_path = _project_root_path / "distribution" / ".benchmarks" +_benchmarks_dir_path = _project_root_path / "distribution" / ".benchmarks" _docs_path = _project_root_path / "doc" _dev_dist_tex_paths = [ _docs_path / "mf6io" / "mf6io.tex", @@ -146,12 +146,12 @@ def test_download_benchmarks(tmp_path, github_user): def build_benchmark_tex( output_path: PathLike, overwrite: bool = False, repo_owner: str = "MODFLOW-USGS" ): - _benchmarks_path.mkdir(parents=True, exist_ok=True) - benchmarks_path = _benchmarks_path / "run-time-comparison.md" + _benchmarks_dir_path.mkdir(parents=True, exist_ok=True) + benchmarks_path = _benchmarks_dir_path / "run-time-comparison.md" # download benchmark artifacts if any exist on GitHub if not benchmarks_path.is_file(): - benchmarks_path = download_benchmarks(_benchmarks_path, repo_owner=repo_owner) + benchmarks_path = download_benchmarks(_benchmarks_dir_path, repo_owner=repo_owner) # run benchmarks again if no benchmarks found on GitHub or overwrite requested if overwrite or not benchmarks_path.is_file(): @@ -172,7 +172,7 @@ def build_benchmark_tex( ) assert not ret, out + err assert tex_path.is_file() - + if (_distribution_path / f"{benchmarks_path.stem}.md").is_file(): assert (_docs_path / "ReleaseNotes" / f"{benchmarks_path.stem}.tex").is_file() @@ -180,7 +180,7 @@ def build_benchmark_tex( @flaky @requires_github def test_build_benchmark_tex(tmp_path): - benchmarks_path = _benchmarks_path / "run-time-comparison.md" + benchmarks_path = _benchmarks_dir_path / "run-time-comparison.md" tex_path = _distribution_path / f"{benchmarks_path.stem}.tex" try: @@ -190,6 +190,22 @@ def test_build_benchmark_tex(tmp_path): tex_path.unlink(missing_ok=True) +def build_deprecations_tex(): + deprecations_path = _docs_path / "mf6io" / "mf6ivar" / "md" / "deprecations.md" + + # convert markdown deprecations to LaTeX + with set_dir(_release_notes_path): + tex_path = Path("deprecations.tex") + tex_path.unlink(missing_ok=True) + out, err, ret = run_cmd( + sys.executable, "mk_deprecations.py", deprecations_path, verbose=True + ) + assert not ret, out + err + assert tex_path.is_file() + + assert (_docs_path / "ReleaseNotes" / f"{deprecations_path.stem}.tex").is_file() + + def build_mf6io_tex_from_dfn(overwrite: bool = False): if overwrite: clean_tex_files() @@ -461,8 +477,8 @@ def build_documentation( example_model_path=example_path, ) - # build LaTeX file describing distribution folder structure - # build_tex_folder_structure(overwrite=True) + # build deprecations table for insertion into LaTex release notes + build_deprecations_tex() if not full: # convert LaTeX to PDF diff --git a/doc/ReleaseNotes/ReleaseNotes.tex b/doc/ReleaseNotes/ReleaseNotes.tex index 2655e9d014d..91689262147 100644 --- a/doc/ReleaseNotes/ReleaseNotes.tex +++ b/doc/ReleaseNotes/ReleaseNotes.tex @@ -297,6 +297,10 @@ \section{MODFLOW~6 Documentation} \noindent Description of the MODFLOW~6 input and output is included in this distribution in the ``doc'' folder as mf6io.pdf. +% ------------------------------------------------- +% if deprecation information exists, then include the deprecation table +\IfFileExists{./deprecations.tex}{\input{./deprecations.tex}}{} + % ------------------------------------------------- % if runtime information exists, then include the run time comparison table \IfFileExists{./run-time-comparison.tex}{\input{./run-time-comparison.tex}}{} diff --git a/doc/ReleaseNotes/mk_deprecations.py b/doc/ReleaseNotes/mk_deprecations.py new file mode 100644 index 00000000000..581d146581e --- /dev/null +++ b/doc/ReleaseNotes/mk_deprecations.py @@ -0,0 +1,72 @@ +# This script converts the markdown deprecations table +# into a latex table for inclusion in the release notes +import argparse +from pathlib import Path +from warnings import warn + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("path") + args = parser.parse_args() + + header = r""" + \section{Deprecations} + + Deprecated/removed options in the current version of MODFLOW 6. Deprecated options are not suggested for use and may (but need not) be removed in a future version of MODFLOW 6. Removed options are no longer available in the current version of MODFLOW 6. + + \small + \begin{longtable}[!htbp]{p{5cm} p{3cm} p{3cm} p{1.5cm}} + \caption{List of deprecations and removals} + \label{table:deprecations} + \tabularnewline + + \hline + \hline + \textbf{File} & \textbf{Option} & \textbf{Deprecated} & \textbf{Removed} \\ + \hline + \endfirsthead + + \hline + \hline + \textbf{File} & \textbf{Option} & \textbf{Deprecated} & \textbf{Removed} \\ + \hline + \endhead + + """ + + footer = r""" + \hline + \end{longtable} + \normalsize + """ + + fname = "deprecations" + fpath = Path(args.path).expanduser().absolute() + fnametex = Path(f"{fname}.tex").absolute() + fnametex.unlink(missing_ok=True) + + # if the markdown file exists, convert it to latex + if fpath.is_file(): + ftex = open(fnametex, 'w') + ftex.write(header) + skipline = True + with open(fpath) as fmd: + for line in fmd: + if not skipline: + ll = line.strip().split('|') + ll = ll[1:-1] + linetex = "& ".join(ll) + linetex = linetex.replace("\\", "/") + linetex += '\\\\' + '\n' + linetex = linetex.replace("%", "\\%") + linetex = linetex.replace("_", "\\_") + ftex.write(linetex) + ftex.write("\\hline\n") + if ":-" in line: + skipline = False + ftex.write(footer) + ftex.close() + print(f"Created LaTex file {fnametex} from markdown deprecations file {fpath}") + else: + warn(f"Deprecations not found: {fpath}") diff --git a/doc/mf6io/mf6ivar/deprecations.py b/doc/mf6io/mf6ivar/deprecations.py new file mode 100644 index 00000000000..52a9e683081 --- /dev/null +++ b/doc/mf6io/mf6ivar/deprecations.py @@ -0,0 +1,52 @@ +import os +from typing import List, Tuple, Optional +from packaging.version import Version +from pathlib import Path + + +def get_deprecations(dfndir) -> List[Tuple[Path, str, Version, Optional[Version]]]: + dfns = Path(dfndir).rglob("*.dfn") + deps = {} + for dfn in dfns: + with open(dfn, "r") as f: + name = None + for line in f: + if line.startswith("#"): + continue + keys = ["deprecated", "removed"] + ikeys = {k: i for i, k in enumerate(keys)} + for key in keys: + if line.startswith("name"): + name = line.split()[1] + if line.startswith(key): + val = deps.get((dfn, key), [None, None]) + key, ver = line.split() + ik = ikeys[key] + val[ik] = val[ik] if val[ik] else Version(ver) + deps[(dfn, name)] = val + + return [(file, key, dep, rem) for (file, key), (dep, rem) in deps.items()] + + +def create_deprecations_file(dfndir, mddir, verbose): + deprecations = get_deprecations(dfndir) + deps_path = (Path(mddir) / 'deprecations.md').absolute() + if verbose: + print(f"Found {len(deprecations)} deprecations, writing {deps_path}") + with open(deps_path, "w") as f: + s = "#### Deprecations\n\n" + s += "The following table lists deprecated options and the versions in which they were deprecated and (optionally) removed.\n\n" + if any(deprecations): + s += "| Model-Package | Option | Deprecated | Removed |\n" + s += "|:--------------|:-------|:-----------|:--------|\n" + for (file, option, deprecated, removed) in deprecations: + s += f"| {file.stem} | {option} | {deprecated} | {removed if removed else ''} |\n" + if len(s) > 0: + s += "\n" + f.write(s) + + +if __name__ == '__main__': + dfndir = os.path.join('.', 'dfn') + mddir = os.path.join('.', 'md') + create_deprecations_file(dfndir, mddir, verbose=True) diff --git a/doc/mf6io/mf6ivar/md/deprecations.md b/doc/mf6io/mf6ivar/md/deprecations.md new file mode 100644 index 00000000000..dd19b29cfc5 --- /dev/null +++ b/doc/mf6io/mf6ivar/md/deprecations.md @@ -0,0 +1,14 @@ +#### Deprecations + +The following table lists deprecated options and the versions in which they were deprecated and (optionally) removed. + +| Model-Package | Option | Deprecated | Removed | +|:--------------|:-------|:-----------|:--------| +| gwf-mvr | unit_conversion | 6.4.2 | | +| gwf-mvr | csv_output_filerecord | 6.1.1 | | +| gwf-mvr | csv_output | 6.1.1 | | +| gwf-mvr | csvfile | 6.1.1 | | +| gwf-mvr | outer_hclose | 6.1.1 | | +| gwf-mvr | outer_rclosebnd | 6.1.1 | | +| gwf-mvr | inner_hclose | 6.1.1 | | + diff --git a/doc/mf6io/mf6ivar/mf6ivar.py b/doc/mf6io/mf6ivar/mf6ivar.py index 4d81cdd52f0..27684de1ada 100644 --- a/doc/mf6io/mf6ivar/mf6ivar.py +++ b/doc/mf6io/mf6ivar/mf6ivar.py @@ -129,10 +129,14 @@ import os +from pathlib import Path import sys from collections import OrderedDict import re import shutil +from tempfile import TemporaryDirectory +from typing import Dict, List, Optional, Tuple +from packaging.version import Version VERBOSE = False for arg in sys.argv: @@ -360,6 +364,9 @@ def write_desc(vardict, block, blk_var_list, varexcludeprefix=None): if 'deprecated' in v: if v['deprecated'] != '': addv = False + if 'removed' in v: + if v['removed'] != '': + addv = False if addv: if v['type'] == 'keyword': n = name.upper() @@ -419,6 +426,9 @@ def write_desc_md(vardict, block, blk_var_list, varexcludeprefix=None): if 'deprecated' in v: if v['deprecated'] != '': addv = False + if 'removed' in v: + if v['removed'] != '': + addv = False if addv: if v['type'] == 'keyword': n = name.upper() @@ -603,54 +613,48 @@ def write_md(f, vardict, component, package): def write_appendix(texdir, allblocks): fname = os.path.join(texdir, 'appendixA.tex') - f = open(fname, 'w') - f.write('\\small\n\\begin{longtable}{p{1.5cm} p{1.5cm} p{3cm} c}\n') - f.write( - '\\caption{List of block names organized by component and input file ' - 'type. OPEN/CLOSE indicates whether or not the block information ' - 'can be contained in separate file} \\tabularnewline \n\n') - # f.write( - # '\\caption{List of all possible blocks} \\tabularnewline \n\\endfirsthead \n\n') - # f.write( - # '\\caption*{List of all possible blocks} \\tabularnewline\n\n') - f.write('\\hline\n\\hline\n') - f.write( - '\\textbf{Component} & \\textbf{FTYPE} & \\textbf{Blockname} & \\textbf{OPEN/CLOSE} \\\\\n') - f.write('\\hline\n\\endfirsthead\n\n\n') - - f.write('\captionsetup{textformat=simple}\n') - f.write('\caption*{\\textbf{Table A--\\arabic{table}.}{\quad}List of block' - ' names organized by component and input file type. OPEN/CLOSE ' - 'indicates whether or not the block information can be contained ' - 'in separate file.---Continued} \\tabularnewline\n') - - f.write('\n\\hline\n\\hline\n') - f.write( - '\\textbf{Component} & \\textbf{FTYPE} & \\textbf{Blockname} & \\textbf{OPEN/CLOSE} \\\\\n') - f.write('\\hline\n\\endhead\n\n\\hline\n\\endfoot\n\n\n') - - lastftype = '' - for b in allblocks: - l = b.strip().split('-') - component, ftype, blockname = l - if lastftype != ftype: - f.write('\\hline\n') - oc = 'yes' - if 'griddata' in blockname.lower(): - oc = 'no' - if 'utl' in component.lower() and \ - 'tas' in ftype.lower() and 'time' in blockname.lower(): - oc = 'no' - s = '{} & {} & {} & {} \\\\ \n'.format(component.upper(), - ftype.upper(), - blockname.upper(), oc) - f.write(s) - lastftype = ftype + with open(fname, 'w') as f: + f.write('\\small\n\\begin{longtable}{p{1.5cm} p{1.5cm} p{3cm} c}\n') + f.write( + '\\caption{List of block names organized by component and input file ' + 'type. OPEN/CLOSE indicates whether or not the block information ' + 'can be contained in separate file} \\tabularnewline \n\n') + f.write('\\hline\n\\hline\n') + f.write( + '\\textbf{Component} & \\textbf{FTYPE} & \\textbf{Blockname} & \\textbf{OPEN/CLOSE} \\\\\n') + f.write('\\hline\n\\endfirsthead\n\n\n') + + f.write('\captionsetup{textformat=simple}\n') + f.write('\caption*{\\textbf{Table A--\\arabic{table}.}{\quad}List of block' + ' names organized by component and input file type. OPEN/CLOSE ' + 'indicates whether or not the block information can be contained ' + 'in separate file.---Continued} \\tabularnewline\n') + + f.write('\n\\hline\n\\hline\n') + f.write( + '\\textbf{Component} & \\textbf{FTYPE} & \\textbf{Blockname} & \\textbf{OPEN/CLOSE} \\\\\n') + f.write('\\hline\n\\endhead\n\n\\hline\n\\endfoot\n\n\n') + + lastftype = '' + for b in allblocks: + l = b.strip().split('-') + component, ftype, blockname = l + if lastftype != ftype: + f.write('\\hline\n') + oc = 'yes' + if 'griddata' in blockname.lower(): + oc = 'no' + if 'utl' in component.lower() and \ + 'tas' in ftype.lower() and 'time' in blockname.lower(): + oc = 'no' + s = '{} & {} & {} & {} \\\\ \n'.format(component.upper(), + ftype.upper(), + blockname.upper(), oc) + f.write(s) + lastftype = ftype - f.write( - '\n\n\\hline\n\\end{longtable}\n\\label{table:blocks}\n\\normalsize\n') - f.close() - return + f.write( + '\n\n\\hline\n\\end{longtable}\n\\label{table:blocks}\n\\normalsize\n') if __name__ == '__main__': @@ -737,142 +741,141 @@ def write_appendix(texdir, allblocks): # setup a markdown file fname = os.path.join(mddir, 'mf6ivar.md') - fmd = open(fname, 'w') - write_md_header(fmd) + with open(fname, 'w') as fmd: + write_md_header(fmd) + + # construct list of dfn files to process in the order of file_order + files = os.listdir(dfndir) + for f in files: + if 'common' in f: + continue + if '.DS_Store' in f: + continue + if os.path.splitext(f)[0] not in file_order: + raise Exception('File not in file_order: ', f) + files = [fname + '.dfn' for fname in file_order if fname + '.dfn' in files] + # files = ['gwf-obs.dfn'] + + # # create rst file for markdown + # fpth = os.path.join(docdir, "mf6io.rst") + # frst = open(fpth, "w") + # s = ".. toctree::\n" + # s += " :maxdepth: 4\n" + # s += " :name: mf6-io\n\n" + # frst.write(s) - # construct list of dfn files to process in the order of file_order - files = os.listdir(dfndir) - for f in files: - if 'common' in f: - continue - if '.DS_Store' in f: - continue - if os.path.splitext(f)[0] not in file_order: - raise Exception('File not in file_order: ', f) - files = [fname + '.dfn' for fname in file_order if fname + '.dfn' in files] - # files = ['gwf-obs.dfn'] - - # # create rst file for markdown - # fpth = os.path.join(docdir, "mf6io.rst") - # frst = open(fpth, "w") - # s = ".. toctree::\n" - # s += " :maxdepth: 4\n" - # s += " :name: mf6-io\n\n" - # frst.write(s) - - for txtname in files: - component, package = os.path.splitext(txtname)[0].split('-')[0:2] - vardict = parse_mf6var_file(os.path.join(dfndir, txtname)) - - # make list of unique block names - blocks = [] - for k in vardict: - v = vardict[k] - b = v['block'] - if b not in blocks: - blocks.append(b) - - # add a full block name to allblocks - for block in blocks: - b = '{}-{}-{}'.format(component, package, block) - allblocks.append(b) - - # go through each block and write information - desc = '% DO NOT MODIFY THIS FILE DIRECTLY. IT IS CREATED BY mf6ivar.py \n\n' - for b in blocks: - blk_var_list = [] - - # Write the name of the block to the latex file - desc += '\item \\textbf{}\n\n'.format('{Block: ' + b.upper() + '}') - - desc += '\\begin{description}\n' - desc += write_desc(vardict, b, blk_var_list, - varexcludeprefix='dev_') - desc += '\\end{description}\n' - - fname = os.path.join(texdir, os.path.splitext(txtname)[ - 0] + '-' + b + '.dat') + for txtname in files: + component, package = os.path.splitext(txtname)[0].split('-')[0:2] + vardict = parse_mf6var_file(os.path.join(dfndir, txtname)) + + # make list of unique block names + blocks = [] + for k in vardict: + v = vardict[k] + b = v['block'] + if b not in blocks: + blocks.append(b) + + # add a full block name to allblocks + for block in blocks: + b = '{}-{}-{}'.format(component, package, block) + allblocks.append(b) + + # go through each block and write information + desc = '% DO NOT MODIFY THIS FILE DIRECTLY. IT IS CREATED BY mf6ivar.py \n\n' + for b in blocks: + blk_var_list = [] + + # Write the name of the block to the latex file + desc += '\item \\textbf{}\n\n'.format('{Block: ' + b.upper() + '}') + + desc += '\\begin{description}\n' + desc += write_desc(vardict, b, blk_var_list, + varexcludeprefix='dev_') + desc += '\\end{description}\n' + + fname = os.path.join(texdir, os.path.splitext(txtname)[ + 0] + '-' + b + '.dat') + f = open(fname, 'w') + s = write_block(vardict, b, blk_var_list, + varexcludeprefix='dev_') + '\n' + f.write(s) + if VERBOSE: + print(s) + f.close() + fname = os.path.join(texdir, + os.path.splitext(txtname)[0] + '-desc' + '.tex') f = open(fname, 'w') - s = write_block(vardict, b, blk_var_list, - varexcludeprefix='dev_') + '\n' + s = desc + '\n' f.write(s) if VERBOSE: print(s) f.close() - fname = os.path.join(texdir, - os.path.splitext(txtname)[0] + '-desc' + '.tex') - f = open(fname, 'w') - s = desc + '\n' - f.write(s) - if VERBOSE: - print(s) - f.close() - - # write markdown description - mdname = os.path.splitext(txtname)[0] - fname = os.path.join(docdir, mdname + '.md') - f = open(fname, 'w') - f.write("### {}\n\n".format(mdname.upper())) - f.write("#### Structure of Blocks\n\n") - f.write("_FOR EACH SIMULATION_\n\n") - desc = "" - for b in blocks: - blk_var_list = [] - - # Write the name of the block to the latex file - desc += '##### Block: {}\n\n'.format(b.upper()) - - desc += write_desc_md(vardict, b, blk_var_list, - varexcludeprefix='dev_') - - if "period" in b.lower(): - f.write("\n_FOR ANY STRESS PERIOD_\n\n") - f.write("```\n") - s = md_replace(write_block(vardict, b, blk_var_list, - varexcludeprefix='dev_', - indent=4)) + "\n" - # s = s.replace("@", "") + "\n" - f.write(s) - f.write("```\n") - if VERBOSE: - print(s) - - f.write("\n#### Explanation of Variables\n\n") - f.write(desc) - - # add examples - s = get_examples(mdname) - if len(s) > 0: - f.write(s) - # add observation table - s = get_obs_table(mdname) - if len(s) > 0: - f.write(s) - - # add observation examples - s = get_obs_examples(mdname) - if len(s) > 0: - f.write(s) - - # close the markdown file - f.close() + # write markdown description + mdname = os.path.splitext(txtname)[0] + fname = os.path.join(docdir, mdname + '.md') + f = open(fname, 'w') + f.write("### {}\n\n".format(mdname.upper())) + f.write("#### Structure of Blocks\n\n") + f.write("_FOR EACH SIMULATION_\n\n") + desc = "" + for b in blocks: + blk_var_list = [] + + # Write the name of the block to the latex file + desc += '##### Block: {}\n\n'.format(b.upper()) + + desc += write_desc_md(vardict, b, blk_var_list, + varexcludeprefix='dev_') + + if "period" in b.lower(): + f.write("\n_FOR ANY STRESS PERIOD_\n\n") + f.write("```\n") + s = md_replace(write_block(vardict, b, blk_var_list, + varexcludeprefix='dev_', + indent=4)) + "\n" + # s = s.replace("@", "") + "\n" + f.write(s) + f.write("```\n") + if VERBOSE: + print(s) + + f.write("\n#### Explanation of Variables\n\n") + f.write(desc) + + # add examples + s = get_examples(mdname) + if len(s) > 0: + f.write(s) + + # add observation table + s = get_obs_table(mdname) + if len(s) > 0: + f.write(s) + + # add observation examples + s = get_obs_examples(mdname) + if len(s) > 0: + f.write(s) + + # close the markdown file + f.close() - # # add to rst catalog - # s = " {}\n".format(os.path.basename(fname)) - # frst.write(s) + # # add to rst catalog + # s = " {}\n".format(os.path.basename(fname)) + # frst.write(s) - # write markdown - write_md(fmd, vardict, component, package) + # write markdown + write_md(fmd, vardict, component, package) - # # close restart catalog - # frst.write("\n\n") - # frst.close() + # # close restart catalog + # frst.write("\n\n") + # frst.close() - if VERBOSE: - for b in allblocks: - print(b) - write_appendix(texdir, allblocks) + if VERBOSE: + for b in allblocks: + print(b) + write_appendix(texdir, allblocks) - # markdown close - fmd.close() + diff --git a/doc/mf6io/mf6ivar/readme.md b/doc/mf6io/mf6ivar/readme.md index 3a78c3273fa..f373fffc9dc 100644 --- a/doc/mf6io/mf6ivar/readme.md +++ b/doc/mf6io/mf6ivar/readme.md @@ -693,3 +693,5 @@ In the description attribute, the capital REPLACE instructs the processor to rep The Python script [mf6ivar.py](mf6ivar.py) will process all of the definition files and create a markdown file, latex files of the variable descriptions, and text files containing the blocks. +# Deprecations +The Python script [deprecations.py](deprecations.py) will search definition files for `deprecated` or `removed` options and create a markdown file containing a table of deprecations and removals. \ No newline at end of file