diff --git a/docs/Project.toml b/docs/Project.toml index 3de9e340e..9ac5d4bf0 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -2,8 +2,10 @@ CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +DocumenterInterLinks = "d12716ef-a0f6-4df4-a9f1-a5a34e75c656" InfrastructureSystems = "2cd47ed4-ca9b-11e9-27f2-ab636a7671f1" Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306" [compat] InfrastructureSystems = "2" +Documenter = "1" diff --git a/docs/make.jl b/docs/make.jl index db7d61b0a..d783d5ff2 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,6 +1,14 @@ using Documenter, InfrastructureSystems import DataStructures: OrderedDict using Literate +using DocumenterInterLinks + +links = InterLinks( + "Documenter" => "https://documenter.juliadocs.org/stable/", + "Julia" => "https://docs.julialang.org/en/v1/", + "JuliaFormatter" => "https://domluna.github.io/JuliaFormatter.jl/stable/", + "PowerSystems" => "https://nrel-sienna.github.io/PowerSystems.jl/stable/", +) if haskey(ENV, "GITHUB_ACTIONS") ENV["JULIA_DEBUG"] = "Documenter" @@ -17,6 +25,19 @@ pages = OrderedDict( "dev_guide/logging.md", ], "Style Guide" => "style.md", + "Documentation Best Practices" => Any[ + "Explanation" => "docs_best_practices/explanation.md", + "How to..." => Any[ + "Complete Basic Requirements Checklist" => "docs_best_practices/how-to/requirements_checklist.md", + "Clean Up General Formatting" => "docs_best_practices/how-to/general_formatting.md", + "Write a Tutorial" => "docs_best_practices/how-to/write_a_tutorial.md", + "Write a How-To Guide" => "docs_best_practices/how-to/write_a_how-to.md", + "Organize APIs and Write Docstrings" => "docs_best_practices/how-to/write_docstrings_org_api.md", + "Troubleshoot Common Errors" => "docs_best_practices/how-to/troubleshoot.md", + "Compile and View Documentation Locally" => "docs_best_practices/how-to/compile.md", + "View Draft Documentation on Github" => "docs_best_practices/how-to/view_github.md",], + "Reference" => Any["docs_best_practices/reference/useful_links.md",], + ], "API" => "InfrastructureSystems.md" ) @@ -51,7 +72,7 @@ makedocs( size_threshold = nothing), sitename = "InfrastructureSystems.jl", pages = Any[p for p in pages], - warnonly = Documenter.except(), + plugins = [links], ) diff --git a/docs/src/InfrastructureSystems.md b/docs/src/InfrastructureSystems.md index 1d3236ed9..72c07bdc1 100644 --- a/docs/src/InfrastructureSystems.md +++ b/docs/src/InfrastructureSystems.md @@ -1,5 +1,7 @@ # [InfrastructureSystems API Reference](@id API_ref) ```@autodocs -Modules = [InfrastructureSystems] +Modules = [InfrastructureSystems, + InfrastructureSystems.Simulation, + InfrastructureSystems.Optimization] ``` diff --git a/docs/src/assets/comp_after.png b/docs/src/assets/comp_after.png new file mode 100644 index 000000000..6430c2928 Binary files /dev/null and b/docs/src/assets/comp_after.png differ diff --git a/docs/src/assets/comp_before.png b/docs/src/assets/comp_before.png new file mode 100644 index 000000000..d18f52cc9 Binary files /dev/null and b/docs/src/assets/comp_before.png differ diff --git a/docs/src/dev_guide/logging.md b/docs/src/dev_guide/logging.md index 9ff909f09..d71d52f96 100644 --- a/docs/src/dev_guide/logging.md +++ b/docs/src/dev_guide/logging.md @@ -1,4 +1,4 @@ -# Logging +# [Logging](@id log) `InfrastructureSystems.jl` provides a `MultiLogger` object that allows customized logging to console and file. Refer to the [logging diff --git a/docs/src/docs_best_practices/explanation.md b/docs/src/docs_best_practices/explanation.md new file mode 100644 index 000000000..d6a4ea734 --- /dev/null +++ b/docs/src/docs_best_practices/explanation.md @@ -0,0 +1,44 @@ +# Explanation + +## History and Motivation + +During the first phase of Sienna's (previously SIIP's) development, Sienna used a 3-part +documentation organization, based on the expected needs of different user personas: + + - **Modeler**: Users that want to use existing functionality + - **Model Developer**: Users that want to develop custom structs, components, models, and/or workflows + - **Code Base Developers**: Users that want to add new core functionalities or fix bugs in the core capabilities + +However, as Sienna's user base has expanded, it has become apparent that this previous +organization is no longer serving. As of 2024, a new effort is underway to clean up and +re-organize the Sienna documentation according to the 4-part [Diataxis](https://diataxis.fr/) +framework, a well-established, systematic approach to technical documentation split up into: + + - [Tutorials](https://diataxis.fr/tutorials/) + - [How-to guides](https://diataxis.fr/how-to-guides/) + - [Reference](https://diataxis.fr/reference/) + - [Explanation](https://diataxis.fr/explanation/) + +In addition, the current documentation has multiple quality issues, including misformatted +text, broken reference links, and documentation that has been written but is not visible to +users in the API ("missing docstrings"). While the [style guide](@ref style_guide) +has been available, the guide focuses primarily on the style of code itself, without +providing clear guidelines and best practices for other parts of the documentation besides +docstrings. In addition, the first stage of Sienna's development coincided with the initial +development of the [`Documenter.jl`](https://documenter.juliadocs.org/stable/) package. +Early versions of Sienna's packages were documented requiring `Documenter.jl` v0.27, and in +the meantime, `Documenter.jl` has released its v1.0 and onwards, which contain much +more rigorous checks for documentation quality. Sienna's packages have not kept up with +these improvements. + +## Purpose of the Documentation Best Practices + +We aim to remedy the historical issues above through a concerted clean up and +re-organization effort and compliance with `Documenter.jl` >v1.0's quality control checks, +following these best practice guidelines. These guidelines are not intended to reiterate +[Diataxis](https://diataxis.fr/), beyond regularly reminding contributers to refer to them +-- and contributers should read the [Diataxis](https://diataxis.fr/) website in its entirety +before getting started. Instead, the best practices are intended to bridge the gap where +there are Julia- or Sienna-specific recommendations, either to consistently implement the +Diataxis framework or to highlight common documentation issues throughout the Sienna +packages that need to be addressed as part of our concerted clean-up effort. diff --git a/docs/src/docs_best_practices/how-to/compile.md b/docs/src/docs_best_practices/how-to/compile.md new file mode 100644 index 000000000..ebf377a2b --- /dev/null +++ b/docs/src/docs_best_practices/how-to/compile.md @@ -0,0 +1,70 @@ +# Compile and View Documentation Locally + +## Pre-Step a: Update Docs Environment (First Time) + +The first time you compile documentation for a package, make sure the `docs/` environment +(i.e., `docs/Manifest.toml`, not the main `Manifest.toml` in the root of the repository) +is pointing to your local version of the package, so it compiles your local changes: + +``` +julia --project=docs +using Pkg +Pkg.develop(path = "..") +``` + +## Pre-Step b: Auto-Generate Structs (If Needed) + +Most documentation changes are made directly to markdown (.md) files, but if you changed one +of Sienna's .json descriptor files, you must first +[follow the instructions here](@ref "Auto-Generation of Component Structs") to auto-generate +the structs from the .json to have your changes propagated into the markdown files used for +documentation. + +**Example**: You updated `PowerSystems.jl`' +[`power_system_structs.json`](https://github.com/NREL-Sienna/PowerSystems.jl/blob/main/src/descriptors/power_system_structs.json) +file. + +From a terminal at the root of the repository (i.e., `PowerSystems.jl`), run: + +``` +julia --project=. +using InfrastructureSystems +InfrastructureSystems.generate_structs( + "./src/descriptors/power_system_structs.json", + "./src/models/generated", +) +``` + +## Pre-Step c: Run the Formatter (Before Submitting a Pull Request) + +To automatically format the documentation to conform with the [style guide](@ref style_guide), +run in a terminal at the root of the repository: + +``` +julia scripts/formatter/formatter_code.jl +``` + +Resolve any errors and re-run until error-free. See how to [Troubleshoot Common Errors](@ref) +for help. + +This is not a necessary step to compile, but needs to be done at least once to pass pull +request checks. + +## Step 1: Compile + +To compile, run in a terminal at the root of the repository: + +``` +julia --project=docs docs/make.jl +``` + +Resolve any errors and re-run until error-free. See how to [Troubleshoot Common Errors](@ref) +for help. + +## Step 2: View + +Click on the newly-created `index.html` file (e.g., +`SomeSiennaPackage/docs/build/index.html`) to view your locally compiled documentation in a +browser. + +Visually verify formatting and that code blocks compile as expected. diff --git a/docs/src/docs_best_practices/how-to/general_formatting.md b/docs/src/docs_best_practices/how-to/general_formatting.md new file mode 100644 index 000000000..b0d5f02a6 --- /dev/null +++ b/docs/src/docs_best_practices/how-to/general_formatting.md @@ -0,0 +1,89 @@ +# Clean Up General Formatting + +These recommendations are to make navigating our documentation effortless for users, while +addressing common markdown formatting issues in the existing Sienna documentation: + +## Format in back-ticks + +All package names, types, functions, methods, and parameters, etc. should formatted in +back-ticks: + +!!! tip "Do" + + ``` + `max_active_power` + ``` + + compiles as `max_active_power` + +!!! warning "Don't" + + ``` + max_active_power + ``` + + compiles as max_active_power + +## [Put hyperlinks everywhere](@id hyperlinks) + +All types, function, and methods should have hyperlinks to the correct docstring, accounting +for multiple methods of the same name due to Julia's multiple dispatch. +[`Documenter.jl`](https://documenter.juliadocs.org/stable/) will link to the first +occurrance in documentation. If that's not the one you're referring to, copy the entire +signature with types into the hyperlink reference. + +!!! tip "Do" + + ``` + [`get_time_series_values`](@ref) + ``` + + Or + + ``` + [`get_time_series_values` from a `ForecastCache`](@ref get_time_series_values( + owner::TimeSeriesOwners, + forecast::Forecast, + start_time::Dates.DateTime; + len::Union{Nothing, Int} = nothing, + ignore_scaling_factors = false, + )) + ``` + +!!! warning "Don't" + + ``` + `get_time_series_values` + ``` + + Or + + ``` + get_time_series_values + ``` + +## Add links to other Sienna packages + +All other Sienna package names should have documentation (not Git repo) hyperlinks: + +!!! tip "Do" + + ```[`PowerSystems.jl`](https://nrel-sienna.github.io/PowerSystems.jl/stable/)``` + +!!! warning "Don't" + + ``` + `PowerSystems.jl` + ``` + + Or + + ``` + PSY + ``` + + Or + + ``` + [`PowerSystems.jl`](https://github.com/NREL-Sienna/PowerSystems.jl) + ``` diff --git a/docs/src/docs_best_practices/how-to/requirements_checklist.md b/docs/src/docs_best_practices/how-to/requirements_checklist.md new file mode 100644 index 000000000..0ae72407f --- /dev/null +++ b/docs/src/docs_best_practices/how-to/requirements_checklist.md @@ -0,0 +1,38 @@ +# Complete Basic Requirements Checklist + +Sienna packages should follow the [Diataxis](https://diataxis.fr/) +framework, be strictly compiled with [`Documenter.jl`](https://documenter.juliadocs.org/stable/) +v1.0 or greater, and be automatically formatted with +[`JuliaFormatter.jl`](https://domluna.github.io/JuliaFormatter.jl/stable/). + +## For New Packages + +The [`SiennaTemplate.jl`](https://github.com/NREL-Sienna/SiennaTemplate.jl) Git repo has the +required environments and formatting and documentation code. Start from this template. + +## For Existing Packages + +Existing Sienna packages will need to be updated with these requirements, but these will +only need to be addressed once: + + 1. Organize the top-level documentation to follow the [Diataxis](https://diataxis.fr/) + framework (plus a welcome page/section). This might be a significant undertaking. See: + + + How to [Write a How-to Guide](@ref) + + How to [Write a Tutorial](@ref) + + How to [Organize APIs and Write Docstrings](@ref) + + 2. Update the Project.toml file in the `docs/` folder to replace `compat` requirements of + `Documenter = "0.27"` with `Documenter = "1.0"` + 3. Update the `docs/make.jl` file to call + [`Documenter.makedocs`](https://documenter.juliadocs.org/stable/lib/public/#Documenter.makedocs) + *without* the `warnonly` `kwarg` (i.e., all errors caught by `makedocs` must be resolved before + merging). [See an example here](https://github.com/NREL-Sienna/InfrastructureSystems.jl/blob/768438a40c46767560891ec493cf87ed232a2b2b/docs/make.jl#L47). + + + See How-to [Troubleshoot Common Errors](@ref) if this results in a host of errors. + 4. Update the `scripts/formatter/formatter_code.jl` to format the markdown .md files in the + `docs/` folder, calling `format`() with the `kwarg` `format_markdown = true`. See + [these](https://github.com/NREL-Sienna/InfrastructureSystems.jl/blob/768438a40c46767560891ec493cf87ed232a2b2b/scripts/formatter/formatter_code.jl#L13) + [three](https://github.com/NREL-Sienna/InfrastructureSystems.jl/blob/768438a40c46767560891ec493cf87ed232a2b2b/scripts/formatter/formatter_code.jl#L8) + [links](https://github.com/NREL-Sienna/InfrastructureSystems.jl/blob/768438a40c46767560891ec493cf87ed232a2b2b/scripts/formatter/formatter_code.jl#L23) + for examples of the updated lines. diff --git a/docs/src/docs_best_practices/how-to/troubleshoot.md b/docs/src/docs_best_practices/how-to/troubleshoot.md new file mode 100644 index 000000000..f9da9cd57 --- /dev/null +++ b/docs/src/docs_best_practices/how-to/troubleshoot.md @@ -0,0 +1,92 @@ +# Troubleshoot Common Errors + +## [`Error: ## docstrings not included in the manual`](@id miss_doc) + +**Problem**: Docstrings have been written, but have not been properly mapped to either a +public or internal API. There may be multiple issues to iterate through: + + 1. Verify there is an Internal API .md file to catch doctrings for structs/functions that are + not exported. + [Example here](https://github.com/NREL-Sienna/SiennaTemplate.jl/blob/main/docs/src/reference/internal.md) + + 2. Identify the `*.jl` file for one of your missing docstrings. Are other docstrings in that file + visible in the compiled API .html? + + + **YES**: Check whether those other docstrings are listed in the Public API .md file in a + [`@docs` block](@extref). Either: + + * Add the missing struct/function names to an appropriate `@docs` block in the + API .md if it is manually organized. See below if this creates a + [`no docs found`](@ref no_docs) error. + * Preferrably, [switch to `@autodocs`](@ref use_autodocs) with the `*.jl` file + as one of its `Pages` instead. + + + **No**: add a new [`@autodocs` block](@extref) in the Public API .md file with that + `*.jl` file as one of its `Pages`. + 3. Are these docstrings from `InfrastructureSystems.jl`? Follow how-to + [selectively export docstrings from `InfrastructureSystems.jl`](@ref docs_from_is). + +## [`Error: no docs found for SomeFunction` or `[:docs_block]` error](@id no_docs) + +No docstring has been written for `SomeFunction`. +Find the `*.jl` file containing `SomeFunction` and add a docstring. + +## `Error: duplicate docs found` + +> **Example**: `Error: duplicate docs found for 'PowerSimulations.SimulationProblemResults' in src\reference\PowerSimulations.md` + +**Problem**: The same `.jl` file has been found more than once by `Documenter.jl`, which matches +based on the end of a file path. + + 1. Determine which file the function is located in + + > **Example**: `simulation_problem_results.jl` for `PowerSimulations.SimulationProblemResults` + + 2. Check whether that file is listed more than once in an `@autodocs` `Pages` list in the + API markdown file (e.g., `PowerSimulations.md` or `public.md`). Remove duplicates. + 3. Also check for other files with the same partial ending in the `@autodocs` `Pages` lists + in the API .md file. Specify more of that file path to distinguish it. + + > **Example**: Change `Pages = ["problem_results.jl"]` to `Pages = ["operation/problem_results.jl"]` + +## `Parsing error for input` from `JuliaFormatter` + +**Problem**: `JuliaFormatter` 1.0 gives an uninformative error message when it can't parse +something, with unhelpful line numbers. Common causes are something that is not proper Julia +syntax inside a `julia` markdown block: + +````markdown +```julia +Whoops, +``` +```` + +Or a single bracket in a markdown file: + +```julia +] add PowerSystems +``` + +Workarounds: + + - Avoid the single bracket with alternatives: + +```julia +using Pkg; +Pkg.add(["PowerSystems"]); +``` + + - If you can't avoid it: + + 1. Remove the text with single bracket (or other problem) temporarily + 2. Run the formatter once to format the rest of the file + 3. Add the text back in + 4. Add the `ignore` keyword argument with the file name to + [`JuliaFormatter.format`](@extref `JuliaFormatter.format-Tuple{Any}`) in `scripts/formatter/formatter_code.jl` + to skip the file in the future: + +```julia +ignore = ["problem-file.md"] +``` + +You might need to iterate through multiple files. diff --git a/docs/src/docs_best_practices/how-to/view_github.md b/docs/src/docs_best_practices/how-to/view_github.md new file mode 100644 index 000000000..6da6ff6c9 --- /dev/null +++ b/docs/src/docs_best_practices/how-to/view_github.md @@ -0,0 +1,11 @@ +# View Draft Documentation on Github + + 1. Create a pull request on Github. + + 2. Verify the Documentation/build check was successful (takes a few minutes). + 3. Preview it in a browser following this url format: + + > https://nrel-sienna.github.io/.jl/previews/PR/ + +*This only works if the PR is on the root repository, not a fork.* Otherwise, work with a +maintainer to move your PR to the root repository. diff --git a/docs/src/docs_best_practices/how-to/write_a_how-to.md b/docs/src/docs_best_practices/how-to/write_a_how-to.md new file mode 100644 index 000000000..842065e47 --- /dev/null +++ b/docs/src/docs_best_practices/how-to/write_a_how-to.md @@ -0,0 +1,97 @@ +# Write a How-to Guide + +A How-To guides a user trying to accomplish a certain task in their work, or address a +problem or series of linked problems. + +## Prepare + + - If you have not read [Diataxis](https://diataxis.fr/), first read it in its entirety. + - If you have read it, skim the pages on [How-to guides](https://diataxis.fr/how-to-guides/) and + the [difference between a tutorial and how-to guide](https://diataxis.fr/tutorials-how-to/) + to refresh your memory and refer back throughout the process. + - Look at an example: this page, how to [Compile and View Documentation Locally](@ref), and + how to [Troubleshoot Common Errors](@ref) are all examples. + +## Follow the Do's and Don't's + +The [Diataxis How-to's](https://diataxis.fr/how-to-guides/) page should be your main reference +as you write, but in addition, use these guidelines to +ensure we follow Diataxis and avoid common pitfalls from previous versions of Sienna +documentation: + +```@contents +Pages = ["write_a_how-to.md"] +Depth = 3:3 +``` + +### Omit the Unnecessary + +!!! tip "Do" + + Jump the user right to a logical starting point in the code using `#hide` or + [`@setup`](https://documenter.juliadocs.org/stable/man/syntax/#reference-at-setup) + blocks. + +!!! tip "Do" + + [Configure the logger](@ref log) or load/build a `System` that returns very + few log statements. Use semi-colons at line ends to hide return statements if need be. + +### Make it effortless to read + +!!! tip "Do" + + Split code examples into ideally 1 (to 3) lines ONLY, with a short preface + to explain what each line is doing, even if it's obvious to you. + +### Move Docstring Material to the APIs + +An issue with earlier versions of Sienna documentation was basic reference information +located in pages other than the APIs. +See how-to [Organize APIs and Write Docstrings](@ref) if needed to make that information +easier to find. + +!!! tip "Do" + + Preface each call to a new function with a hyperlink to that function's + docstring so the user can find more detail + +!!! warning "Don't" + + Include digressive details about different keyword arguments or versions of + a function. + +### Minimize or Eliminate How-To Guides with a Single Step + +A how-to guide has a *sequence* of steps -- if your guide only has a single step, ask +yourself if you are compensating for a lack of information in the API's. + +!!! tip "Do" + + Move how-to guides with a single function to being Examples in that + function's docstring. See [Writing Documentation](@extref). + +### Remove Other Reference Material + +Particularly when editing existing pages, watch out for other +[Reference](https://diataxis.fr/reference/) material. + +!!! tip "Do" + + Move tables and lists of information into Reference pages and link to them instead + +### Follow the Guidelines on Cleaning Up General Formatting + +!!! tip "Do" + + Follow How-to [Clean Up General Formatting](@ref). + +### Look at the compiled .html! + +!!! tip "Do" + + - [Compile](@ref "Compile and View Documentation Locally") the how-to guide regularly and + look at it + - Check all code examples gave the expected results without erroring + - Check for length of the code examples and iteratively adjust to make it easy + to read diff --git a/docs/src/docs_best_practices/how-to/write_a_tutorial.md b/docs/src/docs_best_practices/how-to/write_a_tutorial.md new file mode 100644 index 000000000..41b79fe35 --- /dev/null +++ b/docs/src/docs_best_practices/how-to/write_a_tutorial.md @@ -0,0 +1,151 @@ +# Write a Tutorial + +Tutorials are learning experiences to give our users confidence and experience in using +Sienna. + +## Prepare + + - If you have not read [Diataxis](https://diataxis.fr/), first read it in its entirety. + - If you have read it, skim the pages on [Tutorials](https://diataxis.fr/tutorials/) and + the [difference between a tutorial and how-to guide](https://diataxis.fr/tutorials-how-to/) + to refresh your memory and refer back throughout the process. + - Look at an example: `PowerSystems.jl`'s + [Working with Time Series](https://nrel-sienna.github.io/PowerSystems.jl/stable/tutorials/working_with_time_series/) + +!!! warning + + Historically, many of Sienna's "tutorials" have blended all 4 types of documentation in + the [Diataxis](https://diataxis.fr/) framework. If you are editing, be prepared to move + material to related Explanation and How-to pages and into function docstrings in the APIs + as you work. + + If you starting a new tutorial, ask yourself if a tutorial is appropriate for what + you're trying to show, or if you should be writing a how-to instead. + See also how to [Write a How-to Guide](@ref). + +## Follow the Do's and Don't's + +The [Diataxis Tutorials](https://diataxis.fr/tutorials/) page should be your main reference +as you write, but in addition, use these functional and aesthetic guidelines to +ensure we follow Diataxis and avoid common pitfalls from previous versions of Sienna +documentation: + +```@contents +Pages = ["write_a_tutorial.md"] +Depth = 3:3 +``` + +### Give it a story + +The tutorial should have a logical flow, rather than be a series of disconnected code +demonstrations. + +!!! tip "Do" + + Use either named + [`@example`](https://documenter.juliadocs.org/stable/man/syntax/#reference-at-example) + or named + [`@repl`](https://documenter.juliadocs.org/stable/man/syntax/#@repl-block) blocks to + ensure all code compiles in order in the same environment and ensuring each step builds + on the previous steps in your story: + + ````markdown + ```@example my_tutorial + + ``` + ```` + +!!! warning "Don't" + + Use a series of `julia` markdown blocks. These won't be compiled, failing the + intention of a tutorial and introducing high likelihood of errors as syntax changes. + + ````markdown + ```julia + + ``` + ```` + +### Make it reproducible + +A user should be able to copy and paste every code block in the tutorial in order and get +the exact results seen on the documentation page. + +!!! tip "Do" + + Display all code, starting from `using SomeSiennaPackage`. Example: See + [Working with Time Series](@extref tutorial_time_series). + +!!! warning "Don't" + + Use `#hide` or + [`@setup`](https://documenter.juliadocs.org/stable/man/syntax/#reference-at-setup) + blocks. + +### Make it effortless to read + +!!! tip "Do" + + Split code examples into ideally 1 (to 3) lines ONLY, with a short preface + to explain what each line is doing, even if it's obvious to you. + +!!! warning "Don't" + + Use blocks of example code and/or return statements that go over 1 screen + length in the compiled .html. They are very hard to follow and allow a user to tune out + or give up. + +### Make it realistic and relatable + +!!! tip "Do" + + Take the time to define some realistic example data. + +!!! warning "Don't" + + Use `zero()` or `one()` for all example data. + +### Only show relevant log and return statements + +!!! tip "Do" + + [Configure the logger](@ref log) or load/build a `System` that returns very + few log statements. Use semi-colons at line ends to hide return statements if need be. + +!!! warning "Don't" + + Show extensive or confusing log or return statements that bog down a reader with + information that isn't directly relevant to what you're trying to teach. + +### Remove other types of documentation + +Particularly when editing existing material, watch out for material that should be +moved elsewhere according to Diataxis principles: + +!!! tip "Do" + + Preface each call to a new function with a hyperlink to that function's + docstring so the user can find more detail + +!!! warning "Don't" + + Include definitions and details about different keyword arguments or versions of + a function in the tutorial itself. Some basic information is OK, but details and + examples live in the docstrings, and they especially shouldn't be included in the + tutorial **in lieu of** being in the docstrings. + +### Follow the Guidelines on Cleaning Up General Formatting + +!!! tip "Do" + + Follow How-to [Clean Up General Formatting](@ref). + +### Look at the compiled .html! + +!!! tip "Do" + + - [Compile](@ref "Compile and View Documentation Locally") the tutorial regularly and + look at it + - Check all code examples gave the expected results without erroring + - Check for length of the code examples and iteratively adjust to make it easy + to read diff --git a/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md b/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md new file mode 100644 index 000000000..77cc191ab --- /dev/null +++ b/docs/src/docs_best_practices/how-to/write_docstrings_org_api.md @@ -0,0 +1,230 @@ +# Organize APIs and Write Docstrings + +Docstrings for all structs, methods, and functions belong in the public or internal APIs, +organized under the [Reference](https://diataxis.fr/reference/) section in Diataxis organization. +Refer to this page particularly while editing Sienna docstrings and APIs for +guidance on common problems in our existing documentation. + +## Prepare + + - If you have not read [Diataxis](https://diataxis.fr/), first read it in its entirety. + - Refer back to the Diataxis [Reference](https://diataxis.fr/reference/) section while + working. + - Read and follow Julia's guidance on [Writing Documentation](@extref), + which mainly applies to docstrings + - Read the sections on `Documenter.jl`'s [`@docs` block](@extref) and + [`@autodocs` block](@extref), and follow the guidance below on using `@autodocs` + wherever possible + +## Follow the Do's and Don't's + +Julia and `Documenter.jl`'s guidance above should be your main reference, but in addition, +follow these do's and don't to avoid common pitfalls from previous versions of Sienna +documentation: + +```@contents +Pages = ["write_docstrings_org_api.md"] +Depth = 3:3 +``` + +### Look at the compiled .html! + +!!! tip "Do" + + - [Compile](@ref "Compile and View Documentation Locally") regularly and + look at the APIs + - Check method signatures and argument lists are formatted correctly + +### Ensure All Docstrings Are Located in the APIs + +!!! tip "Do" + + Include a Public API markdown file for exported structs, functions, and methods, and an + Internals API for private functions. See + [`PowerSystems.jl`](https://nrel-sienna.github.io/PowerSystems.jl/stable/) + for an example with a Public API organized with `@autodocs` ([see next](@ref use_autodocs)) + or [`SiennaTemplate.jl`](https://github.com/NREL-Sienna/SiennaTemplate.jl) for a basic + template when starting a new package. + +!!! tip "Do" + + Migrate all existing Formulation Libraries and Model Libraries into the Public API. + +!!! tip "Do" + + If you want to make a docstring visible outside of the API (e.g., in a tutorial), use + a [non-canonical reference](@extref noncanonical-block). + +### [Automate Adding Docstrings in the Public API with `@autodocs`](@id use_autodocs) + +!!! tip "Do" + + Use [`@autodocs` block](@extref)s in the Public API markdown file to automatically find + all docstrings in a file. Example: + + ````markdown + ## Variables + ```@autodocs + Modules = [SomeSiennaPackage] + Pages = ["variables.jl"] + Public = true + Private = false + ``` + ```` + +!!! warning "Don't" + + Manually list out the struts or methods on a topic in a [`@docs` block](@extref), + because that introduces more work whenever we add something new or make a change. + Example: + + ````markdown + ## Variables + ```@docs + variable1 + variable2 + ``` + ```` + + Consider re-organizing code if need be, so all related functions are in the same file(s) + (e.g., `variables.jl`). + +### [Selectively Export Docstrings from `InfrastructureSystems.jl`](@id docs_from_is) + +If you are working in another Sienna package (e.g., `SomeSiennaPackage.jl`) that imports and +exports code from `InfrastructureSystems.jl`: + +!!! tip "Do" + + List the files containing necessary `InfrastructureSystems.jl` structs and methods in + `SomeSiennaPackage.jl`'s Public API markdown file, then explicitly filter by what + `SomeSiennaPackage.jl` exports. Example: + + ````markdown + ```@autodocs + Modules = [InfrastructureSystems] + Pages = ["production_variable_cost_curve.jl", # examples + "cost_aliases.jl", + ] + Order = [:type, :function] + Filter = t -> nameof(t) in names(SomeSiennaPackage) + ``` + ```` + +!!! warning "Don't" + + List `InfrastructureSystems` as one of the `modules` in [`Documenter.makedocs`](@extref) + in the `make.jl` file. `Documenter.jl` will + look to map **all** `InfrastructureSystems.jl` docstrings into the API, resulting in + hundreds of [missing docstring](@ref miss_doc) errors. Example: + + ```julia + makedocs(; + modules = [SomeSiennaPackage, InfrastructureSystems], + format = Documenter.HTML(; + prettyurls = haskey(ENV, "GITHUB_ACTIONS"), + size_threshold = nothing), + sitename = "SomeSiennaPackage.jl", + pages = Any[p for p in pages], + ) + ``` + +### Ensure All Docstrings Have a Function Signature and Arguments List + +!!! tip "Do" + + Check all exported docstrings have a function signature and detailed arguments list + *visible in the API when you compile it*. Example: + + ![A docstring with function signature and args list](../../assets/comp_after.png) + +!!! warning "Don't" + + Leave docstrings that just have a description unaddressed. Example: + + ![A single line docstring](../../assets/comp_before.png) + +### Automate Updating Docstring Arguments Lists + +This is not commonly done in Sienna yet, but a goal is to improve our use of +[`DocStringExtensions.jl`](https://docstringextensions.juliadocs.org/stable) for automation: + +!!! tip "Do" + + Use + [`DocStringExtensions.TYPEDFIELDS`](https://docstringextensions.juliadocs.org/stable/#DocStringExtensions.TYPEDFIELDS) + to automatically compile arguments lists. Example: + + ````markdown + """ + SomeSiennaStruct(arg1, arg2) + + # Arguments + $(TYPEDFIELDS) + + This is the docstring line. + """ + struct SomeSiennaStruct <: OperationalCost + "Documentation for argument 1" + arg1::ProductionVariableCostCurve + "Documentation for argument 2" + arg2::Float64 + end + ```` + +!!! warning "Don't" + + Copy and paste arguments lists into the docstring, which opens opportunity for + out-of-date errors when arguments are added or reordered. Example: + + ````markdown + """ + SomeSiennaStruct(arg1, arg2) + + This is the docstring line. + + # Arguments + - `arg2::Float64`: Documentation for argument 2 + - `arg1::ProductionVariableCostCurve`: Documentation for argument 1 + """ + struct SomeSiennaStruct <: OperationalCost + arg1::ProductionVariableCostCurve + arg2::Float64 + end + ```` + +### Add `See also` Links to Functions with the Same Name + +!!! tip "Do" + + To help users navigate Julia's multiple dispatch, add `See also` paragraphs at the + bottom of function docstrings other versions of the function with the same name, using + the guidance on [adding a specific hyperlink](@ref hyperlinks). + Example: + + ``` + See also + [`get_time_series_array` by name from storage](@ref get_time_series_array( + ::Type{T}, + owner::TimeSeriesOwners, + name::AbstractString; + start_time::Union{Nothing, Dates.DateTime} = nothing, + len::Union{Nothing, Int} = nothing, + ignore_scaling_factors = false, + features..., + ) where {T <: TimeSeriesData}), + [`get_time_series_array` from a `StaticTimeSeriesCache`](@ref get_time_series_array( + owner::TimeSeriesOwners, + time_series::StaticTimeSeries, + start_time::Union{Nothing, Dates.DateTime} = nothing; + len::Union{Nothing, Int} = nothing, + ignore_scaling_factors = false, + )) + ``` + +### Follow the Guidelines on Cleaning Up General Formatting + +!!! tip "Do" + + Follow How-to [Clean Up General Formatting](@ref), especially by adding + hyperlinks to other Sienna structs that appear within an arguments list. diff --git a/docs/src/docs_best_practices/reference/useful_links.md b/docs/src/docs_best_practices/reference/useful_links.md new file mode 100644 index 000000000..7d1bc8654 --- /dev/null +++ b/docs/src/docs_best_practices/reference/useful_links.md @@ -0,0 +1,11 @@ +# Useful Links + + - [Diataxis](https://diataxis.fr/): Reference for the new + documentation framework Sienna is striving to follow (not specific to Julia) + - Julia's guidance on [Writing Documentation](@extref) + - [`Documenter.jl`](https://documenter.juliadocs.org/stable/): Julia's documentation + package, the [Syntax](https://documenter.juliadocs.org/stable/man/syntax/) and + [Showcase](https://documenter.juliadocs.org/stable/showcase/) pages are + especially useful + - [`SiennaTemplate.jl` Git repository](https://github.com/NREL-Sienna/SiennaTemplate.jl): A + template for new Sienna packages that includes the required documentation framework. diff --git a/scripts/formatter/formatter_code.jl b/scripts/formatter/formatter_code.jl index c501c6802..9ae5b8c36 100644 --- a/scripts/formatter/formatter_code.jl +++ b/scripts/formatter/formatter_code.jl @@ -22,7 +22,7 @@ for main_path in main_paths separate_kwargs_with_semicolon = true, format_markdown = true, # Brackets in code blocks cause formatter to fail, ignore for now - ignore = ["style.md", "index.md", "tests.md"], + ignore = ["style.md", "index.md", "tests.md", "troubleshoot.md"], # always_use_return = true. # Disabled since it throws a lot of false positives ) diff --git a/src/Optimization/Optimization.jl b/src/Optimization/Optimization.jl index 0f26cb08c..05739454b 100644 --- a/src/Optimization/Optimization.jl +++ b/src/Optimization/Optimization.jl @@ -28,6 +28,13 @@ import ..InfrastructureSystems: convert_for_path, InvalidValue +using DocStringExtensions + +@template (FUNCTIONS, METHODS) = """ + $(TYPEDSIGNATURES) + $(DOCSTRING) + """ + export OptimizationProblemResults export OptimizationProblemResultsExport export OptimizerStats diff --git a/src/Optimization/optimization_problem_results.jl b/src/Optimization/optimization_problem_results.jl index d2cef4540..2b52489f1 100644 --- a/src/Optimization/optimization_problem_results.jl +++ b/src/Optimization/optimization_problem_results.jl @@ -320,8 +320,7 @@ end """ Return the values for the requested variable key for a problem. -Accepts a vector of keys for the return of the values. If the time stamps and keys are -loaded using the [`load_results!`](@ref) function it will read from memory. +Accepts a vector of keys for the return of the values. # Arguments @@ -349,8 +348,7 @@ end """ Return the values for the requested variable keys for a problem. -Accepts a vector of keys for the return of the values. If the time stamps and keys are -loaded using the [`load_results!`](@ref) function it will read from memory. +Accepts a vector of keys for the return of the values. # Arguments @@ -394,8 +392,7 @@ end """ Return the values for the requested dual key for a problem. -Accepts a vector of keys for the return of the values. If the time stamps and keys are -loaded using the [`load_results!`](@ref) function it will read from memory. +Accepts a vector of keys for the return of the values. # Arguments @@ -423,8 +420,7 @@ end """ Return the values for the requested dual keys for a problem. -Accepts a vector of keys for the return of the values. If the time stamps and keys are -loaded using the [`load_results!`](@ref) function it will read from memory. +Accepts a vector of keys for the return of the values. # Arguments @@ -467,8 +463,7 @@ end """ Return the values for the requested parameter key for a problem. -Accepts a vector of keys for the return of the values. If the time stamps and keys are -loaded using the [`load_results!`](@ref) function it will read from memory. +Accepts a vector of keys for the return of the values. # Arguments @@ -496,8 +491,7 @@ end """ Return the values for the requested parameter keys for a problem. -Accepts a vector of keys for the return of the values. If the time stamps and keys are -loaded using the [`load_results!`](@ref) function it will read from memory. +Accepts a vector of keys for the return of the values. # Arguments @@ -541,8 +535,7 @@ end """ Return the values for the requested aux_variable key for a problem. -Accepts a vector of keys for the return of the values. If the time stamps and keys are -loaded using the [`load_results!`](@ref) function it will read from memory. +Accepts a vector of keys for the return of the values. # Arguments @@ -570,8 +563,7 @@ end """ Return the values for the requested aux_variable keys for a problem. -Accepts a vector of keys for the return of the values. If the time stamps and keys are -loaded using the [`load_results!`](@ref) function it will read from memory. +Accepts a vector of keys for the return of the values. # Arguments @@ -615,8 +607,7 @@ end """ Return the values for the requested expression key for a problem. -Accepts a vector of keys for the return of the values. If the time stamps and keys are -loaded using the [`load_results!`](@ref) function it will read from memory. +Accepts a vector of keys for the return of the values. # Arguments @@ -644,8 +635,7 @@ end """ Return the values for the requested expression keys for a problem. -Accepts a vector of keys for the return of the values. If the time stamps and keys are -loaded using the [`load_results!`](@ref) function it will read from memory. +Accepts a vector of keys for the return of the values. # Arguments diff --git a/src/Simulation/Simulation.jl b/src/Simulation/Simulation.jl index 6a3cc3bb7..ccfe0cbf5 100644 --- a/src/Simulation/Simulation.jl +++ b/src/Simulation/Simulation.jl @@ -11,4 +11,11 @@ import ..InfrastructureSystems: include("enums.jl") +using DocStringExtensions + +@template (FUNCTIONS, METHODS) = """ + $(TYPEDSIGNATURES) + $(DOCSTRING) + """ + end