diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 7a6c6429a..f7b6bbca4 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -48,6 +48,7 @@ jobs:
pydoc-markdown
./make_interview_docs.py ../docassemble-ALDashboard
./fix-doc-titles.sh
+ ./fix-doc-anchors.py
- uses: actions/setup-node@v3
with:
node-version: 20
diff --git a/.github/workflows/test-deploy.yml b/.github/workflows/test-deploy.yml
index f5e2f5ac6..0f375d7fc 100644
--- a/.github/workflows/test-deploy.yml
+++ b/.github/workflows/test-deploy.yml
@@ -48,6 +48,7 @@ jobs:
pydoc-markdown
./make_interview_docs.py ../docassemble-ALDashboard
./fix-doc-titles.sh
+ ./fix-doc-anchors.py
- uses: actions/setup-node@v3
with:
node-version: 20
diff --git a/docs/authoring/writing_review_screen.md b/docs/authoring/writing_review_screen.md
index 4747edc58..265ce5b55 100644
--- a/docs/authoring/writing_review_screen.md
+++ b/docs/authoring/writing_review_screen.md
@@ -24,7 +24,7 @@ This page is a step-by-step tutorial on how to write a review screen, and covers
- [Step 1: AL Review Generator](#step-1-al-review-generator)
- [Step 2: Understanding and Editing the Generated Review Screen](#step-2-understanding-and-editing-the-generated-review-screen)
- [Edits to the Review Screen](#edits-to-the-review-screen)
- - [Step 4: Things to add to the review screen](#step-4-things-to-add-to-the-review-screen)
+ - [Step 3: Things to add to the review screen](#step-3-things-to-add-to-the-review-screen)
## Why make a review screen?
diff --git a/docs/components/ALDashboard/aldashboard.md b/docs/components/ALDashboard/aldashboard.md
index 72843872f..388095e2a 100644
--- a/docs/components/ALDashboard/aldashboard.md
+++ b/docs/components/ALDashboard/aldashboard.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [ALDashboard.aldashboard](#ALDashboard.aldashboard)
+* ALDashboard.aldashboard
* [speedy\_get\_users](#ALDashboard.aldashboard.speedy_get_users)
* [speedy\_get\_sessions](#ALDashboard.aldashboard.speedy_get_sessions)
* [dashboard\_get\_session\_variables](#ALDashboard.aldashboard.dashboard_get_session_variables)
@@ -19,9 +19,7 @@ sidebar_label: aldashboard
title: ALDashboard.aldashboard
---
-
-
-#### speedy\_get\_users()
+#### speedy\_get\_users() {#ALDashboard.aldashboard.speedy\_get\_users}
```python
def speedy_get_users() -> List[Dict[int, str]]
@@ -29,9 +27,7 @@ def speedy_get_users() -> List[Dict[int, str]]
Return a list of all users in the database. Possibly faster than get_user_list().
-
-
-#### speedy\_get\_sessions(user\_id: Optional[int] = None, filename: Optional[str] = None, filter\_step1: bool = True, metadata\_key\_name: str = "metadata")
+#### speedy\_get\_sessions(user\_id: Optional[int] = None, filename: Optional[str] = None, filter\_step1: bool = True, metadata\_key\_name: str = "metadata") {#ALDashboard.aldashboard.speedy\_get\_sessions}
```python
def speedy_get_sessions(user_id: Optional[int] = None,
@@ -48,9 +44,7 @@ user_id,
modtime,
key
-
-
-#### dashboard\_get\_session\_variables(session\_id: str, filename: str)
+#### dashboard\_get\_session\_variables(session\_id: str, filename: str) {#ALDashboard.aldashboard.dashboard\_get\_session\_variables}
```python
def dashboard_get_session_variables(session_id: str, filename: str)
@@ -58,9 +52,7 @@ def dashboard_get_session_variables(session_id: str, filename: str)
Return the variables and steps for a given session ID and YAML filename in serializable dictionary format.
-
-
-## ALPackageInstaller Objects
+## ALPackageInstaller Objects {#ALDashboard.aldashboard.ALPackageInstaller}
```python
class ALPackageInstaller(DAObject)
@@ -68,9 +60,7 @@ class ALPackageInstaller(DAObject)
Methods and state for installing AssemblyLine.
-
-
-#### get\_validated\_github\_username(access\_token: str)
+#### get\_validated\_github\_username(access\_token: str) {#ALDashboard.aldashboard.ALPackageInstaller.get\_validated\_github\_username}
```python
def get_validated_github_username(access_token: str)
@@ -79,9 +69,7 @@ def get_validated_github_username(access_token: str)
Given a valid GitHub `access_token`, returns the username associated with it.
Otherwise, adds one or more errors to the installer.
-
-
-## ErrorList Objects
+## ErrorList Objects {#ALDashboard.aldashboard.ErrorList}
```python
class ErrorList(DAList)
@@ -89,9 +77,7 @@ class ErrorList(DAList)
Contains `ErrorLikeObject`s so they can be recognized by docassemble.
-
-
-## ErrorLikeObject Objects
+## ErrorLikeObject Objects {#ALDashboard.aldashboard.ErrorLikeObject}
```python
class ErrorLikeObject(DAObject)
@@ -101,9 +87,7 @@ An object with a `template_name` that identifies the DALazyTemplate that will
show its error. It can contain any other attributes so its template can access them
as needed. DAObject doesn't seem to be enough to allow template definition.
-
-
-#### install\_fonts(the\_font\_files: DAFileList)
+#### install\_fonts(the\_font\_files: DAFileList) {#ALDashboard.aldashboard.install\_fonts}
```python
def install_fonts(the_font_files: DAFileList)
@@ -111,9 +95,7 @@ def install_fonts(the_font_files: DAFileList)
Install fonts to the server and restart both supervisor and unoconv.
-
-
-#### list\_installed\_fonts()
+#### list\_installed\_fonts() {#ALDashboard.aldashboard.list\_installed\_fonts}
```python
def list_installed_fonts()
@@ -121,9 +103,7 @@ def list_installed_fonts()
List the fonts installed on the server.
-
-
-#### nicer\_interview\_filename(filename: str)
+#### nicer\_interview\_filename(filename: str) {#ALDashboard.aldashboard.nicer\_interview\_filename}
```python
def nicer_interview_filename(filename: str) -> str
@@ -132,9 +112,7 @@ def nicer_interview_filename(filename: str) -> str
Given a filename like docassemble.playground10ALWeaver:data/questions/assembly_line.yml,
return a less cluttered name like: playground10ALWeaver:assembly_line
-
-
-#### list\_question\_files\_in\_package(package\_name: str)
+#### list\_question\_files\_in\_package(package\_name: str) {#ALDashboard.aldashboard.list\_question\_files\_in\_package}
```python
def list_question_files_in_package(package_name: str) -> Optional[List[str]]
@@ -151,9 +129,7 @@ List all the files in the 'data/questions' directory of a package.
- `List[str]` - A list of filenames in the 'data/questions' directory of the package.
-
-
-#### list\_question\_files\_in\_docassemble\_packages()
+#### list\_question\_files\_in\_docassemble\_packages() {#ALDashboard.aldashboard.list\_question\_files\_in\_docassemble\_packages}
```python
def list_question_files_in_docassemble_packages()
diff --git a/docs/components/ALDashboard/create_package.md b/docs/components/ALDashboard/create_package.md
index 0322b122f..ccbb7355a 100644
--- a/docs/components/ALDashboard/create_package.md
+++ b/docs/components/ALDashboard/create_package.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [ALDashboard.create\_package](#ALDashboard.create_package)
+* ALDashboard.create\_package
* [create\_package\_zip](#ALDashboard.create_package.create_package_zip)
---
@@ -8,9 +8,7 @@ sidebar_label: create_package
title: ALDashboard.create_package
---
-
-
-#### create\_package\_zip(pkgname: str, info: dict, author\_info: dict, folders\_and\_files: dict, fileobj: Optional[DAFile] = None)
+#### create\_package\_zip(pkgname: str, info: dict, author\_info: dict, folders\_and\_files: dict, fileobj: Optional[DAFile] = None) {#ALDashboard.create\_package.create\_package\_zip}
```python
def create_package_zip(pkgname: str,
diff --git a/docs/components/ALDashboard/docx_wrangling.md b/docs/components/ALDashboard/docx_wrangling.md
index 0c08978f8..6b907d708 100644
--- a/docs/components/ALDashboard/docx_wrangling.md
+++ b/docs/components/ALDashboard/docx_wrangling.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [ALDashboard.docx\_wrangling](#ALDashboard.docx_wrangling)
+* ALDashboard.docx\_wrangling
* [update\_docx](#ALDashboard.docx_wrangling.update_docx)
* [get\_labeled\_docx\_runs](#ALDashboard.docx_wrangling.get_labeled_docx_runs)
* [modify\_docx\_with\_openai\_guesses](#ALDashboard.docx_wrangling.modify_docx_with_openai_guesses)
@@ -10,9 +10,7 @@ sidebar_label: docx_wrangling
title: ALDashboard.docx_wrangling
---
-
-
-#### update\_docx(document: Union[docx.document.Document, str], modified\_runs: List[Tuple[int, int, str, int]])
+#### update\_docx(document: Union[docx.document.Document, str], modified\_runs: List[Tuple[int, int, str, int]]) {#ALDashboard.docx\_wrangling.update\_docx}
```python
def update_docx(
@@ -35,9 +33,7 @@ Update the document with modified runs.
The modified document.
-
-
-#### get\_labeled\_docx\_runs(docx\_path: str, custom\_people\_names: Optional[Tuple[str, str]] = None, openai\_client: Optional[OpenAI] = None)
+#### get\_labeled\_docx\_runs(docx\_path: str, custom\_people\_names: Optional[Tuple[str, str]] = None, openai\_client: Optional[OpenAI] = None) {#ALDashboard.docx\_wrangling.get\_labeled\_docx\_runs}
```python
def get_labeled_docx_runs(
@@ -59,9 +55,7 @@ Scan the DOCX and return a list of modified text with Jinja2 variable names inse
A list of tuples, each containing a paragraph number, run number, and the modified text of the run.
-
-
-#### modify\_docx\_with\_openai\_guesses(docx\_path: str)
+#### modify\_docx\_with\_openai\_guesses(docx\_path: str) {#ALDashboard.docx\_wrangling.modify\_docx\_with\_openai\_guesses}
```python
def modify_docx_with_openai_guesses(docx_path: str) -> docx.document.Document
diff --git a/docs/components/ALDashboard/package_scanner.md b/docs/components/ALDashboard/package_scanner.md
index 4a98a74ce..db9f5e76c 100644
--- a/docs/components/ALDashboard/package_scanner.md
+++ b/docs/components/ALDashboard/package_scanner.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [ALDashboard.package\_scanner](#ALDashboard.package_scanner)
+* ALDashboard.package\_scanner
* [URL](#ALDashboard.package_scanner.URL)
* [PARAMETERS](#ALDashboard.package_scanner.PARAMETERS)
* [DELAY\_BETWEEN\_QUERYS](#ALDashboard.package_scanner.DELAY_BETWEEN_QUERYS)
@@ -12,27 +12,19 @@ sidebar_label: package_scanner
title: ALDashboard.package_scanner
---
-
-
-#### URL
+#### URL {#ALDashboard.package\_scanner.URL}
The basic URL to use the GitHub API
-
-
-#### PARAMETERS
+#### PARAMETERS {#ALDashboard.package\_scanner.PARAMETERS}
Additional parameters for the query (by default 100 items per page)
-
-
-#### DELAY\_BETWEEN\_QUERYS
+#### DELAY\_BETWEEN\_QUERYS {#ALDashboard.package\_scanner.DELAY\_BETWEEN\_QUERYS}
The time to wait between different queries to GitHub
-
-
-#### getUrl(url)
+#### getUrl(url) {#ALDashboard.package\_scanner.getUrl}
```python
def getUrl(url)
@@ -40,9 +32,7 @@ def getUrl(url)
Given a URL it returns its body
-
-
-#### fetch\_github\_repos(github\_user, sub\_queries)
+#### fetch\_github\_repos(github\_user, sub\_queries) {#ALDashboard.package\_scanner.fetch\_github\_repos}
```python
def fetch_github_repos(github_user, sub_queries) -> dict
diff --git a/docs/components/ALDashboard/project_maintenance.md b/docs/components/ALDashboard/project_maintenance.md
index 56cd1c59b..1c2cfaa39 100644
--- a/docs/components/ALDashboard/project_maintenance.md
+++ b/docs/components/ALDashboard/project_maintenance.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [ALDashboard.project\_maintenance](#ALDashboard.project_maintenance)
+* ALDashboard.project\_maintenance
* [get\_package\_names](#ALDashboard.project_maintenance.get_package_names)
* [add\_tag\_to\_repos](#ALDashboard.project_maintenance.add_tag_to_repos)
* [process\_packages\_and\_add\_tag](#ALDashboard.project_maintenance.process_packages_and_add_tag)
@@ -17,9 +17,7 @@ sidebar_label: project_maintenance
title: ALDashboard.project_maintenance
---
-
-
-#### get\_package\_names(server\_name: str)
+#### get\_package\_names(server\_name: str) {#ALDashboard.project\_maintenance.get\_package\_names}
```python
def get_package_names(server_name: str) -> List[str]
@@ -36,9 +34,7 @@ Fetches the JSON file from the given docassemble server and extracts package nam
- `List[str]` - List of package names.
-
-
-#### add\_tag\_to\_repos(token: str, org\_name: str, repo\_names: List[str], tag: str)
+#### add\_tag\_to\_repos(token: str, org\_name: str, repo\_names: List[str], tag: str) {#ALDashboard.project\_maintenance.add\_tag\_to\_repos}
```python
def add_tag_to_repos(token: str, org_name: str, repo_names: List[str],
@@ -67,9 +63,7 @@ Adds a specific tag to each repository in the given list.
add_tag_to_repos(personal_access_token, organization_name, repositories, tag_to_add)
-
-
-#### process\_packages\_and\_add\_tag(server\_name: str, token: str, org\_name: str, tag: str)
+#### process\_packages\_and\_add\_tag(server\_name: str, token: str, org\_name: str, tag: str) {#ALDashboard.project\_maintenance.process\_packages\_and\_add\_tag}
```python
def process_packages_and_add_tag(server_name: str, token: str, org_name: str,
@@ -86,9 +80,7 @@ and adds a specified tag to each repository.
- `org_name` _str_ - Name of the GitHub organization.
- `tag` _str_ - Tag to be added to each repository.
-
-
-#### get\_project\_by\_name(token: str, org\_name: str, project\_name: str)
+#### get\_project\_by\_name(token: str, org\_name: str, project\_name: str) {#ALDashboard.project\_maintenance.get\_project\_by\_name}
```python
def get_project_by_name(token: str, org_name: str,
@@ -108,9 +100,7 @@ Finds a GitHub Next-Generation project by its name within an organization using
- `dict` - The GitHub project object, or None if not found.
-
-
-#### get\_repos\_by\_topic(token: str, org\_name: str, topic: str)
+#### get\_repos\_by\_topic(token: str, org\_name: str, topic: str) {#ALDashboard.project\_maintenance.get\_repos\_by\_topic}
```python
def get_repos_by_topic(token: str, org_name: str,
@@ -130,9 +120,7 @@ Fetches repositories in an organization that have a specific topic.
- `List[Repository]` - A list of repository objects that have the specified topic.
-
-
-#### add\_issues\_and\_create\_cards(token: str, org\_name: str, project\_name: str, topic: str, issue\_title: str, issue\_body: str)
+#### add\_issues\_and\_create\_cards(token: str, org\_name: str, project\_name: str, topic: str, issue\_title: str, issue\_body: str) {#ALDashboard.project\_maintenance.add\_issues\_and\_create\_cards}
```python
def add_issues_and_create_cards(token: str, org_name: str, project_name: str,
@@ -151,9 +139,7 @@ Adds an issue to each repository with a specific topic and creates a card for ea
- `issue_title` _str_ - Title of the issue.
- `issue_body` _str_ - Body of the issue.
-
-
-#### find\_issues\_by\_title(token: str, org\_name: str, repo\_names: List[str], issue\_title: str)
+#### find\_issues\_by\_title(token: str, org\_name: str, repo\_names: List[str], issue\_title: str) {#ALDashboard.project\_maintenance.find\_issues\_by\_title}
```python
def find_issues_by_title(token: str, org_name: str, repo_names: List[str],
@@ -174,9 +160,7 @@ Finds issues in a list of repositories with a specific title.
- `list` - A list of issue node IDs.
-
-
-#### add\_issue\_to\_project(token: str, project\_id: str, issue\_node\_id: str)
+#### add\_issue\_to\_project(token: str, project\_id: str, issue\_node\_id: str) {#ALDashboard.project\_maintenance.add\_issue\_to\_project}
```python
def add_issue_to_project(token: str, project_id: str,
@@ -191,9 +175,7 @@ Adds an issue to a Next-Generation GitHub project.
- `project_id` _str_ - Node ID of the GitHub project.
- `issue_node_id` _str_ - Node ID of the GitHub issue.
-
-
-#### link\_issue\_title\_to\_project(token: str, org\_name: str, project\_name: str, topic: str, issue\_title: str)
+#### link\_issue\_title\_to\_project(token: str, org\_name: str, project\_name: str, topic: str, issue\_title: str) {#ALDashboard.project\_maintenance.link\_issue\_title\_to\_project}
```python
def link_issue_title_to_project(token: str, org_name: str, project_name: str,
@@ -210,9 +192,7 @@ Links issues with a specific title in repositories with a certain topic to a Nex
- `topic` _str_ - The GitHub topic to filter repositories by.
- `issue_title` _str_ - Title of the issue to link.
-
-
-#### main()
+#### main() {#ALDashboard.project\_maintenance.main}
```python
def main() -> None
diff --git a/docs/components/ALDashboard/translation.md b/docs/components/ALDashboard/translation.md
index a617dc70a..320c41e49 100644
--- a/docs/components/ALDashboard/translation.md
+++ b/docs/components/ALDashboard/translation.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [ALDashboard.translation](#ALDashboard.translation)
+* ALDashboard.translation
* [gpt\_is\_available](#ALDashboard.translation.gpt_is_available)
* [may\_have\_mako](#ALDashboard.translation.may_have_mako)
* [may\_have\_html](#ALDashboard.translation.may_have_html)
@@ -15,9 +15,7 @@ sidebar_label: translation
title: ALDashboard.translation
---
-
-
-#### gpt\_is\_available()
+#### gpt\_is\_available() {#ALDashboard.translation.gpt\_is\_available}
```python
def gpt_is_available() -> bool
@@ -25,9 +23,7 @@ def gpt_is_available() -> bool
Return True if the GPT API is available.
-
-
-#### may\_have\_mako(text: str)
+#### may\_have\_mako(text: str) {#ALDashboard.translation.may\_have\_mako}
```python
def may_have_mako(text: str) -> bool
@@ -35,9 +31,7 @@ def may_have_mako(text: str) -> bool
Return True if the text appears to contain any Mako code, such as $\{...\} or % at the beginning of a line.
-
-
-#### may\_have\_html(text: str)
+#### may\_have\_html(text: str) {#ALDashboard.translation.may\_have\_html}
```python
def may_have_html(text: str) -> bool
@@ -45,9 +39,7 @@ def may_have_html(text: str) -> bool
Return True if the text appears to contain any HTML code, such as <p> or <div>.
-
-
-#### translate\_fragments\_gpt(fragments: Union[str, List[Tuple[int, str]]], source\_language: str, tr\_lang: str, interview\_context: Optional[str] = None, special\_words: Optional[Dict[int, str]] = None, model="gpt-4.1-nano", openai\_base\_url: Optional[str] = None, max\_output\_tokens: Optional[int] = None, max\_input\_tokens: Optional[int] = None, openai\_api: Optional[str] = None)
+#### translate\_fragments\_gpt(fragments: Union[str, List[Tuple[int, str]]], source\_language: str, tr\_lang: str, interview\_context: Optional[str] = None, special\_words: Optional[Dict[int, str]] = None, model="gpt-4.1-nano", openai\_base\_url: Optional[str] = None, max\_output\_tokens: Optional[int] = None, max\_input\_tokens: Optional[int] = None, openai\_api: Optional[str] = None) {#ALDashboard.translation.translate\_fragments\_gpt}
```python
def translate_fragments_gpt(
@@ -84,29 +76,21 @@ You can optionally provide an alternative model, but it must support JSON mode.
A dictionary where the keys are the indices of the fragments and the values are the translated text.
-
-
-## Translation Objects
+## Translation Objects {#ALDashboard.translation.Translation}
```python
class Translation(NamedTuple)
```
-
-
-#### file: `DAFile`
+#### file: `DAFile` {#ALDashboard.translation.Translation.file}
an XLSX or XLIFF file
-
-
-#### untranslated\_segments: `int`
+#### untranslated\_segments: `int` {#ALDashboard.translation.Translation.untranslated\_segments}
Number of rows in the output that have untranslated text - one for each question, subquestion, field, etc.
-
-
-#### translation\_file(yaml\_filename: str, tr\_lang: str, use\_gpt=False, use\_google\_translate=False, openai\_api: Optional[str] = None, max\_tokens=4000, interview\_context: Optional[str] = None, special\_words: Optional[Dict[int, str]] = None, model: Optional[str] = None, openai\_base\_url: Optional[str] = None, max\_input\_tokens: Optional[int] = None, max\_output\_tokens: Optional[int] = None)
+#### translation\_file(yaml\_filename: str, tr\_lang: str, use\_gpt=False, use\_google\_translate=False, openai\_api: Optional[str] = None, max\_tokens=4000, interview\_context: Optional[str] = None, special\_words: Optional[Dict[int, str]] = None, model: Optional[str] = None, openai\_base\_url: Optional[str] = None, max\_input\_tokens: Optional[int] = None, max\_output\_tokens: Optional[int] = None) {#ALDashboard.translation.translation\_file}
```python
def translation_file(yaml_filename: str,
diff --git a/docs/components/ALDashboard/validate_docx.md b/docs/components/ALDashboard/validate_docx.md
index 0f47d4d65..5dbf7d9f9 100644
--- a/docs/components/ALDashboard/validate_docx.md
+++ b/docs/components/ALDashboard/validate_docx.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [ALDashboard.validate\_docx](#ALDashboard.validate_docx)
+* ALDashboard.validate\_docx
* [CallAndDebugUndefined](#ALDashboard.validate_docx.CallAndDebugUndefined)
* [\_\_getitem\_\_](#ALDashboard.validate_docx.CallAndDebugUndefined.__getitem__)
* [get\_jinja\_errors](#ALDashboard.validate_docx.get_jinja_errors)
@@ -10,9 +10,7 @@ sidebar_label: validate_docx
title: ALDashboard.validate_docx
---
-
-
-## CallAndDebugUndefined Objects
+## CallAndDebugUndefined Objects {#ALDashboard.validate\_docx.CallAndDebugUndefined}
```python
class CallAndDebugUndefined(DebugUndefined)
@@ -21,15 +19,11 @@ class CallAndDebugUndefined(DebugUndefined)
Handles Jinja2 undefined errors by printing the name of the undefined variable.
Extended to handle callable methods.
-
-
-#### \_\_getitem\_\_
+#### \_\_getitem\_\_ {#ALDashboard.validate\_docx.CallAndDebugUndefined.\_\_getitem\_\_}
type: ignore
-
-
-#### get\_jinja\_errors(the\_file: str)
+#### get\_jinja\_errors(the\_file: str) {#ALDashboard.validate\_docx.get\_jinja\_errors}
```python
def get_jinja_errors(the_file: str) -> Optional[str]
diff --git a/docs/components/ALKiln/automated_testing.mdx b/docs/components/ALKiln/automated_testing.mdx
index 73cbe53db..2a649682f 100644
--- a/docs/components/ALKiln/automated_testing.mdx
+++ b/docs/components/ALKiln/automated_testing.mdx
@@ -460,7 +460,7 @@ The `value` for a row setting a signature doesn't matter. All signatures will be
### Other story table notes
-([Moving](writing_tests.mdx#unused-rows))
+([Moving](writing_tests.mdx#unused_rows))
Don't worry about accidentally including variables that won't show up during the test. Extra rows will be ignored.
@@ -626,7 +626,7 @@ The phrase should be inside double quotation marks and should NOT itself contain
([Moving](writing_tests.mdx#a11y))
-The `accessibility` Step can check a page for its accessibility by running [aXe-core](https://github.com/dequelabs/axe-core) on the page.
+The `accessibility` Step can check a page for its accessibility by running [aXe-core](https://github.com/dequelabs/axe-core) on the page.
```
Then I check the page for accessibility issues
@@ -1389,7 +1389,7 @@ When you want to update to a new version of the ALKiln, update that sha manually
([Moving](security.mdx#freeze))
-This section requires prior technical knowledge about [npm](https://docs.npmjs.com/about-npm) and [GitHub workflow files](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions). Feel free to [ask us](/docs/get_started/beginners_guide.md#join) any questions you might have.
+This section requires prior technical knowledge about [npm](https://docs.npmjs.com/about-npm) and [GitHub workflow files](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions). Feel free to [ask us](/docs/get_started/intro.md#join-the-community) any questions you might have.
You can use an exact npm version of ALKiln by using your workflow file's `ALKILN_VERSION` input. The default uses a carat, for example `^4.0.0`. That means it will use the latest minor or patch in version 4 of ALKiln. You can instead use an exact version, for example `4.3.0`. See our section on [setting optional inputs](#optional-inputs).
@@ -1491,7 +1491,7 @@ Among other things, the workflow file:
You can also use the whole suite of GitHub's workflow and action functionality to do other things, like creating issues when tests fail.
-These following sections probably require prior technical knowledge about [GitHub workflow files](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions). Feel free to [ask us](/docs/get_started/beginners_guide.md#join) any questions you might have.
+These following sections probably require prior technical knowledge about [GitHub workflow files](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions). Feel free to [ask us](/docs/get_started/intro.md#join-the-community) any questions you might have.
### Required inputs
diff --git a/docs/components/ALKiln/troubleshooting.mdx b/docs/components/ALKiln/troubleshooting.mdx
index d02a09db0..c52b75954 100644
--- a/docs/components/ALKiln/troubleshooting.mdx
+++ b/docs/components/ALKiln/troubleshooting.mdx
@@ -154,7 +154,7 @@ This is a reference error. It means docassemble tried to get the value for a var
- It may be that you have a typo in a [variable name or value](#var-val) in your test.
- It may be that you are [setting the value incorrectly](writing_tests.mdx#values) in your test. [Checkboxes are especially complex fields to set](writing_tests.mdx#checkboxes).
-The mistake may have happened on a page much farther back than you expect with a field ALKiln [skipped](writing_tests.mdx#unused-rows).
+The mistake may have happened on a page much farther back than you expect with a field ALKiln [skipped](writing_tests.mdx#unused_rows).
**Debugging:**
@@ -188,7 +188,7 @@ Some possible causes:
## Skipped rows or variables {#skipped}
-If you look in a [test suite report](writing_tests.mdx#report) and see that ALKiln [skipped setting a variable](writing_tests.mdx#unused-rows), your test code might be [missing a field or value](#missing) that it needs in order to fill out that field.
+If you look in a [test suite report](writing_tests.mdx#report) and see that ALKiln [skipped setting a variable](writing_tests.mdx#unused_rows), your test code might be [missing a field or value](#missing) that it needs in order to fill out that field.
If the test still passed, the variable probably belongs to a field that was optional.
@@ -205,7 +205,7 @@ You can check your test code for incorrect variable or value names in a few diff
-1. If you give every question in your interview an id, the [report](writing_tests.mdx#report) can help show you where the test failed or where ALKiln skipped setting variables. For each test, the report often has a list of question ids. For each question id, the report has a list of variables that ALKiln set on the page that had the error. If the test failed, you can see what question id the test got to. You can also check previous questions to see what variables are missing from each of those pages - what [fields ALKiln skipped](writing_tests.mdx#unused-rows).
+1. If you give every question in your interview an id, the [report](writing_tests.mdx#report) can help show you where the test failed or where ALKiln skipped setting variables. For each test, the report often has a list of question ids. For each question id, the report has a list of variables that ALKiln set on the page that had the error. If the test failed, you can see what question id the test got to. You can also check previous questions to see what variables are missing from each of those pages - what [fields ALKiln skipped](writing_tests.mdx#unused_rows).
1. It is more annoying, but in most cases[^except] you can copy the variable name from your test and search for it in your interview code. You can do the same for values of multiple choice questions.
1. Alternatively, in most cases[^except] you can go through the interview manually, but follow this procedure:
1. For every single page (even if you think this page has nothing to do with the problem), click on the `>` in the nav bar to see the source of the page.
diff --git a/docs/components/ALKiln/writing_tests.mdx b/docs/components/ALKiln/writing_tests.mdx
index 73c505b6e..550d94fdc 100644
--- a/docs/components/ALKiln/writing_tests.mdx
+++ b/docs/components/ALKiln/writing_tests.mdx
@@ -2174,7 +2174,7 @@ alkiln:
`ALKILN_BEAR_SIZE` is the name of the environment variable. `"small_bear"` is the value of the environment variable. All the interviews on your server can see these config values, including the interview that runs your tests, so you are actually setting these values for all the tests that you run on your server with tests.
-# GitHub env vars {#github-vars}
+### GitHub env vars {#github-vars}
In GitHub, you can make [GitHub workflow environment variables](https://docs.github.com/en/actions/learn-github-actions/variables#defining-environment-variables-for-a-single-workflow) by putting them in the `env` key in your [workflow file](#workflows):
diff --git a/docs/components/ALThemeTemplate/althemetemplate_overview.md b/docs/components/ALThemeTemplate/althemetemplate_overview.md
index 907a97c38..ea02a321c 100644
--- a/docs/components/ALThemeTemplate/althemetemplate_overview.md
+++ b/docs/components/ALThemeTemplate/althemetemplate_overview.md
@@ -162,7 +162,7 @@ cd bootstrap-5.1.3
npm install
```
-Place the `custom.scss` file you wrote from [the above section](#creating-a-custom-theme-from-source-instead-of-with-a-theme-generator)
+Place the `custom.scss` file you wrote from [the above section](#creating-a-custom-theme)
in the unzipped bootstrap-5.1.3 folder, and use `npm` to compile the theme file.
```bash
diff --git a/docs/components/ALToolbox/Addup.md b/docs/components/ALToolbox/Addup.md
index 2675eff84..c8484f736 100644
--- a/docs/components/ALToolbox/Addup.md
+++ b/docs/components/ALToolbox/Addup.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [ALToolbox.Addup](#ALToolbox.Addup)
+* ALToolbox.Addup
* [Addup](#ALToolbox.Addup.Addup)
* [\_\_init\_\_](#ALToolbox.Addup.Addup.__init__)
* [g](#ALToolbox.Addup.Addup.g)
@@ -10,9 +10,7 @@ sidebar_label: Addup
title: ALToolbox.Addup
---
-
-
-## Addup Objects
+## Addup Objects {#ALToolbox.Addup.Addup}
```python
class Addup()
@@ -24,9 +22,7 @@ This class provides functionality to sum specific numeric fields from all
items in a docassemble DAList, which is useful for financial calculations
and data aggregation in legal document automation.
-
-
-#### \_\_init\_\_(listName, varName)
+#### \_\_init\_\_(listName, varName) {#ALToolbox.Addup.Addup.\_\_init\_\_}
```python
def __init__(listName, varName)
@@ -40,9 +36,7 @@ Initialize the Addup calculator and compute the sum immediately.
- `listName` - A DAList object containing items with numeric fields.
- `varName` _str_ - The name of the field to sum across all list items.
-
-
-#### g(listName, varName)
+#### g(listName, varName) {#ALToolbox.Addup.Addup.g}
```python
def g(listName, varName) -> float
diff --git a/docs/components/ALToolbox/ThreePartsDate.md b/docs/components/ALToolbox/ThreePartsDate.md
index c00b794ff..8a2a280a4 100644
--- a/docs/components/ALToolbox/ThreePartsDate.md
+++ b/docs/components/ALToolbox/ThreePartsDate.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [ALToolbox.ThreePartsDate](#ALToolbox.ThreePartsDate)
+* ALToolbox.ThreePartsDate
* [check\_empty\_parts](#ALToolbox.ThreePartsDate.check_empty_parts)
* [ThreePartsDate](#ALToolbox.ThreePartsDate.ThreePartsDate)
* [validate](#ALToolbox.ThreePartsDate.ThreePartsDate.validate)
@@ -14,9 +14,7 @@ sidebar_label: ThreePartsDate
title: ALToolbox.ThreePartsDate
---
-
-
-#### check\_empty\_parts(item: str, default\_msg="{} is not a valid date")
+#### check\_empty\_parts(item: str, default\_msg="{} is not a valid date") {#ALToolbox.ThreePartsDate.check\_empty\_parts}
```python
def check_empty_parts(item: str,
@@ -52,17 +50,13 @@ what needs to be entered. Currently only handles US date format.
>>> check_empty_parts("12/25/2023")
None
-
-
-## ThreePartsDate Objects
+## ThreePartsDate Objects {#ALToolbox.ThreePartsDate.ThreePartsDate}
```python
class ThreePartsDate(CustomDataType)
```
-
-
-#### validate(cls, item: str)
+#### validate(cls, item: str) {#ALToolbox.ThreePartsDate.ThreePartsDate.validate}
```python
@classmethod
@@ -85,9 +79,7 @@ Validate a date string in MM/DD/YYYY format.
- `DAValidationError` - If the date string is invalid or cannot be parsed.
-
-
-#### transform(cls, item)
+#### transform(cls, item) {#ALToolbox.ThreePartsDate.ThreePartsDate.transform}
```python
@classmethod
@@ -105,9 +97,7 @@ Transform a date string into a datetime object.
datetime or None: The parsed datetime object, or None if empty.
-
-
-#### default\_for(cls, item)
+#### default\_for(cls, item) {#ALToolbox.ThreePartsDate.ThreePartsDate.default\_for}
```python
@classmethod
@@ -125,17 +115,13 @@ Convert a datetime object to MM/dd/yyyy format string.
str or None: The formatted date string, or None if empty.
-
-
-## BirthDate Objects
+## BirthDate Objects {#ALToolbox.ThreePartsDate.BirthDate}
```python
class BirthDate(ThreePartsDate)
```
-
-
-#### validate(cls, item: str)
+#### validate(cls, item: str) {#ALToolbox.ThreePartsDate.BirthDate.validate}
```python
@classmethod
diff --git a/docs/components/ALToolbox/addenda.md b/docs/components/ALToolbox/addenda.md
index 3b3971b4e..c4a7d05d9 100644
--- a/docs/components/ALToolbox/addenda.md
+++ b/docs/components/ALToolbox/addenda.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [ALToolbox.addenda](#ALToolbox.addenda)
+* ALToolbox.addenda
* [myTable](#ALToolbox.addenda.myTable)
* [\_\_init\_\_](#ALToolbox.addenda.myTable.__init__)
* [myTextList](#ALToolbox.addenda.myTextList)
@@ -14,9 +14,7 @@ sidebar_label: addenda
title: ALToolbox.addenda
---
-
-
-## myTable Objects
+## myTable Objects {#ALToolbox.addenda.myTable}
```python
class myTable()
@@ -28,9 +26,7 @@ This class processes DAList objects containing 'Individual' or 'T
and converts them into structured table format suitable for document addenda.
It handles data sanitization and formatting for display purposes.
-
-
-#### \_\_init\_\_(tblData, tblTitle, tblHeader)
+#### \_\_init\_\_(tblData, tblTitle, tblHeader) {#ALToolbox.addenda.myTable.\_\_init\_\_}
```python
def __init__(tblData, tblTitle, tblHeader)
@@ -44,9 +40,7 @@ Initialize a table from DAList data with title and headers.
- `tblTitle` _str_ - The title for the table.
- `tblHeader` - The column headers for the table.
-
-
-## myTextList Objects
+## myTextList Objects {#ALToolbox.addenda.myTextList}
```python
class myTextList()
@@ -58,9 +52,7 @@ This class handles text content that might be too long to fit in the main form
by truncating it at a specified limit and storing the overflow text for use
in addenda or continuation pages.
-
-
-#### \_\_init\_\_(text, limit, title)
+#### \_\_init\_\_(text, limit, title) {#ALToolbox.addenda.myTextList.\_\_init\_\_}
```python
def __init__(text, limit, title)
@@ -74,9 +66,7 @@ Initialize text processing with truncation limits.
- `limit` _int_ - The character limit for the main form field.
- `title` _str_ - The title or identifier for the text field.
-
-
-#### g(text, limit, title)
+#### g(text, limit, title) {#ALToolbox.addenda.myTextList.g}
```python
def g(text, limit, title) -> None
@@ -106,9 +96,7 @@ in an addendum section if truncation occurs.
>>> text_handler = myTextList("Very long text...", 100, "Description")
>>> # If text > 100 chars, text_cutoff will end with " (See Addendum.)"
-
-
-#### safe\_json2(the\_object, level=0, is\_key=False)
+#### safe\_json2(the\_object, level=0, is\_key=False) {#ALToolbox.addenda.safe\_json2}
```python
def safe_json2(the_object, level=0, is_key=False) -> Any
@@ -144,9 +132,7 @@ ISO strings.
>>> safe_json2(obj)
- `\{"date"` - "12/25/2023"\}
-
-
-#### type\_name(the\_object)
+#### type\_name(the\_object) {#ALToolbox.addenda.type\_name}
```python
def type_name(the_object) -> str
diff --git a/docs/components/ALToolbox/al_income.md b/docs/components/ALToolbox/al_income.md
index fdcbc107a..bc574237a 100644
--- a/docs/components/ALToolbox/al_income.md
+++ b/docs/components/ALToolbox/al_income.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [ALToolbox.al\_income](#ALToolbox.al_income)
+* ALToolbox.al\_income
* [times\_per\_year](#ALToolbox.al_income.times_per_year)
* [recent\_years](#ALToolbox.al_income.recent_years)
* [ALPeriodicAmount](#ALToolbox.al_income.ALPeriodicAmount)
@@ -73,9 +73,7 @@ sidebar_label: al_income
title: ALToolbox.al_income
---
-
-
-#### times\_per\_year(times\_per\_year\_list: List[Tuple[int, str]], times\_per\_year: float)
+#### times\_per\_year(times\_per\_year\_list: List[Tuple[int, str]], times\_per\_year: float) {#ALToolbox.al\_income.times\_per\_year}
```python
def times_per_year(times_per_year_list: List[Tuple[int, str]],
@@ -124,9 +122,7 @@ the nearest whole integer.
>>> times_per_year([(12, "Monthly")], 5)
'Five times per year'
-
-
-#### recent\_years(past: int = 25, order: str = "descending", future: int = 1)
+#### recent\_years(past: int = 25, order: str = "descending", future: int = 1) {#ALToolbox.al\_income.recent\_years}
```python
def recent_years(past: int = 25,
@@ -160,9 +156,7 @@ birthdate.
>>> recent_years(past=2, order="ascending", future=0)
[2022, 2023]
-
-
-## ALPeriodicAmount Objects
+## ALPeriodicAmount Objects {#ALToolbox.al\_income.ALPeriodicAmount}
```python
class ALPeriodicAmount(DAObject)
@@ -182,9 +176,7 @@ is 1 (a year).
- `display_name` _str, optional_ - If present, will have a translated string to show the
user, as opposed to a raw english string from the program.
-
-
-#### \_\_str\_\_()
+#### \_\_str\_\_() {#ALToolbox.al\_income.ALPeriodicAmount.\_\_str\_\_}
```python
def __str__() -> str
@@ -196,9 +188,7 @@ Returns the income's total value as a string representation.
The string representation of this income's total value.
-
-
-#### total(times\_per\_year: float = 1)
+#### total(times\_per\_year: float = 1) {#ALToolbox.al\_income.ALPeriodicAmount.total}
```python
def total(times_per_year: float = 1) -> Decimal
@@ -227,9 +217,7 @@ To calculate `.total()`, an ALPeriodicAmount must have a `.times_per_year` and `
>>> income.total(12) # Monthly total
Decimal('1000')
-
-
-## ALIncome Objects
+## ALIncome Objects {#ALToolbox.al\_income.ALIncome}
```python
class ALIncome(ALPeriodicAmount)
@@ -254,9 +242,7 @@ is 1 (a year).
- `source` _str, optional_ - The "source" of the income, like a "job" or a "house".
- `owner` _str, optional_ - Full name of the income's owner as a single string.
-
-
-#### total(times\_per\_year: float = 1)
+#### total(times\_per\_year: float = 1) {#ALToolbox.al\_income.ALIncome.total}
```python
def total(times_per_year: float = 1) -> Decimal
@@ -282,9 +268,7 @@ It can also have `.is_hourly` and `.hours_per_period`.
The calculated income amount for the specified frequency.
-
-
-## ALExpense Objects
+## ALExpense Objects {#ALToolbox.al\_income.ALExpense}
```python
class ALExpense(ALPeriodicAmount)
@@ -292,9 +276,7 @@ class ALExpense(ALPeriodicAmount)
Not much changes from ALPeriodic Amount, just the generic object questions
-
-
-## ALIncomeList Objects
+## ALIncomeList Objects {#ALToolbox.al\_income.ALIncomeList}
```python
class ALIncomeList(DAList)
@@ -309,9 +291,7 @@ This list expects its items to have the following attributes and methods:
- value: Amount value
- total(): Calculate total amount for a given frequency
-
-
-#### init(\*pargs, \*\*kwargs)
+#### init(\*pargs, \*\*kwargs) {#ALToolbox.al\_income.ALIncomeList.init}
```python
def init(*pargs, **kwargs) -> None
@@ -327,9 +307,7 @@ the list contains appropriate income objects for processing.
- `*pargs` - Variable length argument list passed to parent class.
- `**kwargs` - Arbitrary keyword arguments passed to parent class.
-
-
-#### sources()
+#### sources() {#ALToolbox.al\_income.ALIncomeList.sources}
```python
def sources() -> Set[str]
@@ -352,9 +330,7 @@ Returns a set of the unique sources in the ALIncomeList.
>>> income_list.sources()
\{'wages', 'tips'\}
-
-
-#### matches(source: SourceType, exclude\_source: Optional[SourceType] = None)
+#### matches(source: SourceType, exclude\_source: Optional[SourceType] = None) {#ALToolbox.al\_income.ALIncomeList.matches}
```python
def matches(source: SourceType,
@@ -389,9 +365,7 @@ by their source. The source parameter may be a string or a list.
>>> len(wages_only)
2
-
-
-#### total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None, owner: Optional[str] = None)
+#### total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None, owner: Optional[str] = None) {#ALToolbox.al\_income.ALIncomeList.total}
```python
def total(times_per_year: float = 1,
@@ -432,9 +406,7 @@ exclude deductions.
>>> income_list.total(source="wages") # Annual wages only
Decimal('60000.00')
-
-
-#### move\_checks\_to\_list(selected\_types: Optional[DADict] = None, selected\_terms: Optional[Mapping] = None)
+#### move\_checks\_to\_list(selected\_types: Optional[DADict] = None, selected\_terms: Optional[Mapping] = None) {#ALToolbox.al\_income.ALIncomeList.move\_checks\_to\_list}
```python
def move_checks_to_list(selected_types: Optional[DADict] = None,
@@ -455,9 +427,7 @@ work well.
- `selected_types` _Optional[DADict]_ - A dictionary of selected types.
- `selected_terms` _Optional[Mapping]_ - A mapping of selected terms.
-
-
-## ALJob Objects
+## ALJob Objects {#ALToolbox.al\_income.ALJob}
```python
class ALJob(ALIncome)
@@ -488,9 +458,7 @@ Can be stored in an ALJobList.
- `employer` _Individual, optional_ - A docassemble Individual object, employer.address is the address
and employer.phone is the phone.
-
-
-#### init(\*pargs, \*\*kwargs)
+#### init(\*pargs, \*\*kwargs) {#ALToolbox.al\_income.ALJob.init}
```python
def init(*pargs, **kwargs)
@@ -501,9 +469,7 @@ Initialize an ALJob object with employer setup.
Initializes the employer attribute based on the employer_type if available,
defaulting to Individual type if no specific type is set.
-
-
-#### gross\_total(times\_per\_year: float = 1)
+#### gross\_total(times\_per\_year: float = 1) {#ALToolbox.al\_income.ALJob.gross\_total}
```python
def gross_total(times_per_year: float = 1) -> Decimal
@@ -525,9 +491,7 @@ representing the `.value` attribute of the item.
The calculated gross income amount for the specified frequency.
-
-
-#### deductions(times\_per\_year: float = 1)
+#### deductions(times\_per\_year: float = 1) {#ALToolbox.al\_income.ALJob.deductions}
```python
def deductions(times_per_year: float = 1) -> Decimal
@@ -549,9 +513,7 @@ Returns the total deductions from someone's pay over the specified times_pe
The calculated deduction amount for the specified frequency.
-
-
-#### net\_total(times\_per\_year: float = 1)
+#### net\_total(times\_per\_year: float = 1) {#ALToolbox.al\_income.ALJob.net\_total}
```python
def net_total(times_per_year: float = 1) -> Decimal
@@ -580,9 +542,7 @@ Returns the net income over a time period, found using
per hour if hourly). This will force the gathering of the ALJob's `.value`
and `.deduction` attributes.
-
-
-#### employer\_name\_address\_phone()
+#### employer\_name\_address\_phone() {#ALToolbox.al\_income.ALJob.employer\_name\_address\_phone}
```python
def employer_name_address_phone() -> str
@@ -599,9 +559,7 @@ attributes.
A formatted string containing employer name, optionally with address
and/or phone number if available.
-
-
-#### normalized\_hours(times\_per\_year: float = 1)
+#### normalized\_hours(times\_per\_year: float = 1) {#ALToolbox.al\_income.ALJob.normalized\_hours}
```python
def normalized_hours(times_per_year: float = 1) -> float
@@ -635,9 +593,7 @@ based on the self.hours_per_period and self.times_per_year attributes.
This will force the gathering of the attributes `.hours_per_period` and
`.times_per_year`.
-
-
-## ALJobList Objects
+## ALJobList Objects {#ALToolbox.al\_income.ALJobList}
```python
class ALJobList(ALIncomeList)
@@ -647,9 +603,7 @@ Represents a list of ALJobs. Adds the `.gross_total()` and
`.net_total()` methods to the ALIncomeList class. It's a more common
way of reporting income than ALItemizedJobList.
-
-
-#### init(\*pargs, \*\*kwargs)
+#### init(\*pargs, \*\*kwargs) {#ALToolbox.al\_income.ALJobList.init}
```python
def init(*pargs, **kwargs)
@@ -662,9 +616,7 @@ Initialize an ALJobList with ALJob as the default object type.
- `*pargs` - Variable length argument list passed to parent class.
- `**kwargs` - Arbitrary keyword arguments passed to parent class.
-
-
-#### total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None, owner: Optional[str] = None)
+#### total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None, owner: Optional[str] = None) {#ALToolbox.al\_income.ALJobList.total}
```python
def total(times_per_year: float = 1,
@@ -680,9 +632,7 @@ string or a list.
`times_per_year` is some denominator of a year. E.g, to express a weekly
period, use 52. The default is 1 (a year).
-
-
-#### gross\_total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None)
+#### gross\_total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None) {#ALToolbox.al\_income.ALJobList.gross\_total}
```python
def gross_total(times_per_year: float = 1,
@@ -705,9 +655,7 @@ string or a list.
The sum of the gross incomes of its ALJobs divided by the time times_per_year.
-
-
-#### net\_total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None)
+#### net\_total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None) {#ALToolbox.al\_income.ALJobList.net\_total}
```python
def net_total(times_per_year: float = 1,
@@ -733,9 +681,7 @@ If the job is hourly, the `net_total()` may not be comparable to the
The sum of the net incomes of its ALJobs divided by the time times_per_year.
-
-
-#### deductions(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None)
+#### deductions(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None) {#ALToolbox.al\_income.ALJobList.deductions}
```python
def deductions(times_per_year: float = 1,
@@ -758,9 +704,7 @@ will use all sources.
The sum of the deductions of its ALJobs divided by the time times_per_year.
-
-
-## ALExpenseList Objects
+## ALExpenseList Objects {#ALToolbox.al\_income.ALExpenseList}
```python
class ALExpenseList(ALIncomeList)
@@ -773,9 +717,7 @@ value: The monetary value of the expense
source: The source category of the expense
display_name: Human-readable name for display
-
-
-## ALAsset Objects
+## ALAsset Objects {#ALToolbox.al\_income.ALAsset}
```python
class ALAsset(ALIncome)
@@ -802,9 +744,7 @@ Can be stored in an ALAssetList.
- `owner` _str, optional_ - Full name of the asset owner as a single string.
- `source` _str, optional_ - The "source" of the asset, like "vase".
-
-
-#### total(times\_per\_year: float = 1)
+#### total(times\_per\_year: float = 1) {#ALToolbox.al\_income.ALAsset.total}
```python
def total(times_per_year: float = 1) -> Decimal
@@ -823,9 +763,7 @@ Returns the .value attribute divided by the times per year you want to calculate
- `Decimal` - The .value attribute divided by the times per year.
-
-
-#### equity(loan\_attribute="balance")
+#### equity(loan\_attribute="balance") {#ALToolbox.al\_income.ALAsset.equity}
```python
def equity(loan_attribute="balance") -> Decimal
@@ -842,9 +780,7 @@ Returns the total equity in the asset (e.g., market value minus balance).
- `Decimal` - The total equity in the asset.
-
-
-## ALAssetList Objects
+## ALAssetList Objects {#ALToolbox.al\_income.ALAssetList}
```python
class ALAssetList(ALIncomeList)
@@ -869,9 +805,7 @@ total value of all assets, use the `market_value()` method.
- `owner` _str, optional_ - Full name of the asset owner as a single string.
- `source` _str, optional_ - The "source" of the asset, like "vase".
-
-
-#### market\_value(source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None)
+#### market\_value(source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None) {#ALToolbox.al\_income.ALAssetList.market\_value}
```python
def market_value(source: Optional[SourceType] = None,
@@ -894,9 +828,7 @@ You can filter the assets by `source`. `source` can be a string or a list.
- `Decimal` - The total market value of the assets.
-
-
-#### balance(source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None)
+#### balance(source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None) {#ALToolbox.al\_income.ALAssetList.balance}
```python
def balance(source: Optional[SourceType] = None,
@@ -919,9 +851,7 @@ You can filter the assets by `source`. `source` can be a string or a list.
- `Decimal` - The total balance of the assets.
-
-
-#### equity(source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None, loan\_attribute: str = "balance")
+#### equity(source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None, loan\_attribute: str = "balance") {#ALToolbox.al\_income.ALAssetList.equity}
```python
def equity(source: Optional[SourceType] = None,
@@ -945,9 +875,7 @@ specified, or if the asset's source satisfies the source criteria, the equi
- `Decimal` - The total equity in the assets.
-
-
-#### owners(source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None)
+#### owners(source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None) {#ALToolbox.al\_income.ALAssetList.owners}
```python
def owners(source: Optional[SourceType] = None,
@@ -970,9 +898,7 @@ You can filter the assets by `source`. `source` can be a string or a list.
- `Set[str]` - A set of the unique owners of the assets.
-
-
-## ALVehicle Objects
+## ALVehicle Objects {#ALToolbox.al\_income.ALVehicle}
```python
class ALVehicle(ALAsset)
@@ -997,9 +923,7 @@ statement forms.
- `owner` _str_ - Full name of the vehicle owner.
- `source` _str, optional_ - The source of the asset, defaults to 'vehicle'.
-
-
-#### year\_make\_model(separator: str = " / ")
+#### year\_make\_model(separator: str = " / ") {#ALToolbox.al\_income.ALVehicle.year\_make\_model}
```python
def year_make_model(separator: str = " / ") -> str
@@ -1028,9 +952,7 @@ Triggers gathering those attributes and formats them as a single string.
>>> vehicle.year_make_model(separator=", ")
'2020, Toyota, Camry'
-
-
-## ALVehicleList Objects
+## ALVehicleList Objects {#ALToolbox.al\_income.ALVehicleList}
```python
class ALVehicleList(ALAssetList)
@@ -1038,9 +960,7 @@ class ALVehicleList(ALAssetList)
List of ALVehicles. Extends ALAssetList.
-
-
-## ALSimpleValue Objects
+## ALSimpleValue Objects {#ALToolbox.al\_income.ALSimpleValue}
```python
class ALSimpleValue(DAObject)
@@ -1056,9 +976,7 @@ item in an ALSimpleValueList.
negative value to the total of the item.
- `source` _str, optional_ - The "source" of the item, like "vase".
-
-
-#### total()
+#### total() {#ALToolbox.al\_income.ALSimpleValue.total}
```python
def total() -> Decimal
@@ -1075,9 +993,7 @@ object. The `total()` method may return unexpected results in that case.
The total value of the item, taking into account the transaction type.
-
-
-#### \_\_str\_\_()
+#### \_\_str\_\_() {#ALToolbox.al\_income.ALSimpleValue.\_\_str\_\_}
```python
def __str__() -> str
@@ -1085,9 +1001,7 @@ def __str__() -> str
Returns the total as a formatted string
-
-
-## ALSimpleValueList Objects
+## ALSimpleValueList Objects {#ALToolbox.al\_income.ALSimpleValueList}
```python
class ALSimpleValueList(DAList)
@@ -1095,9 +1009,7 @@ class ALSimpleValueList(DAList)
Represents a filterable DAList of ALSimpleValues.
-
-
-#### sources()
+#### sources() {#ALToolbox.al\_income.ALSimpleValueList.sources}
```python
def sources() -> Set
@@ -1109,9 +1021,7 @@ Returns a set of the unique sources of values stored in the list.
A set of the unique sources of values stored in the list.
-
-
-#### total(source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None)
+#### total(source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None) {#ALToolbox.al\_income.ALSimpleValueList.total}
```python
def total(source: Optional[SourceType] = None,
@@ -1132,9 +1042,7 @@ string or a list.
The total value in the list.
-
-
-## ALItemizedValue Objects
+## ALItemizedValue Objects {#ALToolbox.al\_income.ALItemizedValue}
```python
class ALItemizedValue(DAObject)
@@ -1165,9 +1073,7 @@ job's net total.
If the ".exists" attribute is False or undefined, the item will not be used
when calculating totals.
-
-
-#### income\_fields(use\_exists=True)
+#### income\_fields(use\_exists=True) {#ALToolbox.al\_income.ALItemizedValue.income\_fields}
```python
def income_fields(use_exists=True) -> List[Dict[str, Any]]
@@ -1185,9 +1091,7 @@ to be passed to a `code` attribute of a question's fields
A list of dictionaries representing the fields for an itemized value.
-
-
-#### total()
+#### total() {#ALToolbox.al\_income.ALItemizedValue.total}
```python
def total() -> Decimal
@@ -1213,9 +1117,7 @@ returns 0. Otherwise returns the decimal value of the item.
>>> item_disabled.total()
Decimal('0')
-
-
-#### \_\_str\_\_()
+#### \_\_str\_\_() {#ALToolbox.al\_income.ALItemizedValue.\_\_str\_\_}
```python
def __str__() -> str
@@ -1223,9 +1125,7 @@ def __str__() -> str
Returns a string of the value of the item with two decimal places.
-
-
-## ALItemizedValueDict Objects
+## ALItemizedValueDict Objects {#ALToolbox.al\_income.ALItemizedValueDict}
```python
class ALItemizedValueDict(DAOrderedDict)
@@ -1242,9 +1142,7 @@ and one for deductions.
Should only be accessed through an ALItemizedJob. Otherwise
you may get unexpected results.
-
-
-#### hook\_after\_gather()
+#### hook\_after\_gather() {#ALToolbox.al\_income.ALItemizedValueDict.hook\_after\_gather}
```python
def hook_after_gather() -> None
@@ -1258,9 +1156,7 @@ See https://docassemble.org/docs/objects.html#DAList.hook_after_gather.
If a developer wants to remove these items _before_ gathering is finished,
they can use similar code in their question's `validation code:`
-
-
-#### total()
+#### total() {#ALToolbox.al\_income.ALItemizedValueDict.total}
```python
def total() -> Decimal
@@ -1284,9 +1180,7 @@ as not existing (exists=False).
>>> value_dict.total()
Decimal('1000') # Only includes wages, not bonus
-
-
-#### \_\_str\_\_()
+#### \_\_str\_\_() {#ALToolbox.al\_income.ALItemizedValueDict.\_\_str\_\_}
```python
def __str__() -> str
@@ -1295,9 +1189,7 @@ def __str__() -> str
Returns a string of the dictionary's key/value pairs as two-element lists in a list.
E.g. '[["federal_taxes", "2500.00"], ["wages", "15.50"]]'
-
-
-## ALItemizedJob Objects
+## ALItemizedJob Objects {#ALToolbox.al\_income.ALItemizedJob}
```python
class ALItemizedJob(DAObject)
@@ -1359,9 +1251,7 @@ income in code.
and the total of money going in and money coming out.
- A user must be able to add their own arbitrary items.
-
-
-#### total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None)
+#### total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None) {#ALToolbox.al\_income.ALItemizedJob.total}
```python
def total(times_per_year: float = 1,
@@ -1382,9 +1272,7 @@ Alias for ALItemizedJob.gross_total to integrate with ALIncomeList math.
The gross total of the job.
-
-
-#### gross\_total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None)
+#### gross\_total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None) {#ALToolbox.al\_income.ALItemizedJob.gross\_total}
```python
def gross_total(times_per_year: float = 1,
@@ -1410,9 +1298,7 @@ If you use sources from deductions, they will be ignored.
- `Decimal` - The sum of positive values for the given parameters.
-
-
-#### deduction\_total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None)
+#### deduction\_total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None) {#ALToolbox.al\_income.ALItemizedJob.deduction\_total}
```python
def deduction_total(times_per_year: float = 1,
@@ -1438,9 +1324,7 @@ filter the items by `source`. `source` can be a string or a list.
- `Decimal` - The sum of deductions for the given parameters as a positive value.
-
-
-#### net\_total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None)
+#### net\_total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None) {#ALToolbox.al\_income.ALItemizedJob.net\_total}
```python
def net_total(times_per_year: float = 1,
@@ -1466,9 +1350,7 @@ string or a list. E.g. "full time" or ["full time", "un
- `Decimal` - The net value (gross minus deductions) for the given parameters.
-
-
-#### employer\_name\_address\_phone()
+#### employer\_name\_address\_phone() {#ALToolbox.al\_income.ALItemizedJob.employer\_name\_address\_phone}
```python
def employer_name_address_phone() -> str
@@ -1481,9 +1363,7 @@ address and phone number.
A string containing the employer's name, address, and phone number.
-
-
-#### normalized\_hours(times\_per\_year: float = 1)
+#### normalized\_hours(times\_per\_year: float = 1) {#ALToolbox.al\_income.ALItemizedJob.normalized\_hours}
```python
def normalized_hours(times_per_year: float = 1) -> float
@@ -1504,9 +1384,7 @@ For example, if the person works 10 hours a week, it will return
The normalized number of hours worked in the given time period.
-
-
-## ALItemizedJobList Objects
+## ALItemizedJobList Objects {#ALToolbox.al\_income.ALItemizedJobList}
```python
class ALItemizedJobList(DAList)
@@ -1515,9 +1393,7 @@ class ALItemizedJobList(DAList)
Represents a list of ALItemizedJobs that can have both payments and money
out. This is a less common way of reporting income.
-
-
-#### sources(which\_side: Optional[str] = None)
+#### sources(which\_side: Optional[str] = None) {#ALToolbox.al\_income.ALItemizedJobList.sources}
```python
def sources(which_side: Optional[str] = None) -> Set[str]
@@ -1535,9 +1411,7 @@ By default gets from both sides, if which_side is "deductions", only g
A set of the unique sources in all of the jobs.
-
-
-#### total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None)
+#### total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None) {#ALToolbox.al\_income.ALItemizedJobList.total}
```python
def total(times_per_year: float = 1,
@@ -1559,9 +1433,7 @@ ALIncomeList math.
The gross total of the list.
-
-
-#### gross\_total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None)
+#### gross\_total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None) {#ALToolbox.al\_income.ALItemizedJobList.gross\_total}
```python
def gross_total(times_per_year: float = 1,
@@ -1588,9 +1460,7 @@ string or a list.
- `Decimal` - The sum of the gross incomes for the given parameters.
-
-
-#### deduction\_total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None)
+#### deduction\_total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None) {#ALToolbox.al\_income.ALItemizedJobList.deduction\_total}
```python
def deduction_total(times_per_year: float = 1,
@@ -1617,9 +1487,7 @@ string or a list.
- `Decimal` - The sum of the deductions for the given parameters.
-
-
-#### net\_total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None)
+#### net\_total(times\_per\_year: float = 1, source: Optional[SourceType] = None, exclude\_source: Optional[SourceType] = None) {#ALToolbox.al\_income.ALItemizedJobList.net\_total}
```python
def net_total(times_per_year: float = 1,
diff --git a/docs/components/ALToolbox/altoolbox_overview.md b/docs/components/ALToolbox/altoolbox_overview.md
index a9b6e8990..16add7d38 100644
--- a/docs/components/ALToolbox/altoolbox_overview.md
+++ b/docs/components/ALToolbox/altoolbox_overview.md
@@ -71,7 +71,7 @@ content: |
Context-specific help goes here.
```
-[API for `collapse_template`](misc#collapse_template), and [Code for `collapse_template`](https://github.com/SuffolkLITLab/docassemble-ALToolbox/blob/main/docassemble/ALToolbox/misc.py)
+[API for `collapse_template`](misc#ALToolbox.misc.collapse_template), and [Code for `collapse_template`](https://github.com/SuffolkLITLab/docassemble-ALToolbox/blob/main/docassemble/ALToolbox/misc.py)
## Display markdown template with a scroll bar
diff --git a/docs/components/ALToolbox/business_days.md b/docs/components/ALToolbox/business_days.md
index f82be3a6d..fe97777f2 100644
--- a/docs/components/ALToolbox/business_days.md
+++ b/docs/components/ALToolbox/business_days.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [ALToolbox.business\_days](#ALToolbox.business_days)
+* ALToolbox.business\_days
* [standard\_holidays](#ALToolbox.business_days.standard_holidays)
* [non\_business\_days](#ALToolbox.business_days.non_business_days)
* [is\_business\_day](#ALToolbox.business_days.is_business_day)
@@ -12,9 +12,7 @@ sidebar_label: business_days
title: ALToolbox.business_days
---
-
-
-#### standard\_holidays(year, country="US", subdiv="MA", add\_holidays: Optional[Mapping] = None, remove\_holidays: Optional[Iterable[str]] = None)
+#### standard\_holidays(year, country="US", subdiv="MA", add\_holidays: Optional[Mapping] = None, remove\_holidays: Optional[Iterable[str]] = None) {#ALToolbox.business\_days.standard\_holidays}
```python
def standard_holidays(
@@ -77,9 +75,7 @@ holidays observed by a local court, but should be very close to accurate.
)
```
-
-
-#### non\_business\_days(year, country="US", subdiv="MA", add\_holidays: Optional[Mapping] = None, remove\_holidays: Optional[Iterable[str]] = None, first\_n\_dates=0, last\_n\_dates=0)
+#### non\_business\_days(year, country="US", subdiv="MA", add\_holidays: Optional[Mapping] = None, remove\_holidays: Optional[Iterable[str]] = None, first\_n\_dates=0, last\_n\_dates=0) {#ALToolbox.business\_days.non\_business\_days}
```python
def non_business_days(year,
@@ -132,9 +128,7 @@ both weekends (Saturdays and Sundays) and official holidays.
)
```
-
-
-#### is\_business\_day(date: Union[str, DADateTime], country="US", subdiv="MA", add\_holidays: Optional[Mapping] = None, remove\_holidays: Optional[Iterable[str]] = None)
+#### is\_business\_day(date: Union[str, DADateTime], country="US", subdiv="MA", add\_holidays: Optional[Mapping] = None, remove\_holidays: Optional[Iterable[str]] = None) {#ALToolbox.business\_days.is\_business\_day}
```python
def is_business_day(date: Union[str, DADateTime],
@@ -186,9 +180,7 @@ in the specified jurisdiction. Business days are considered to be:
is_business_uk = is_business_day("2023-12-26", country="UK") # Boxing Day
```
-
-
-#### get\_next\_business\_day(start\_date: Union[str, DADateTime], wait\_n\_days=1, country="US", subdiv="MA", add\_holidays: Optional[Mapping] = None, remove\_holidays: Optional[Iterable[str]] = None)
+#### get\_next\_business\_day(start\_date: Union[str, DADateTime], wait\_n\_days=1, country="US", subdiv="MA", add\_holidays: Optional[Mapping] = None, remove\_holidays: Optional[Iterable[str]] = None) {#ALToolbox.business\_days.get\_next\_business\_day}
```python
def get_next_business_day(
@@ -252,9 +244,7 @@ https://github.com/dr-prodigy/python-holidays/tree/master/holidays/countries
# Will skip March 17th as it's now considered a holiday
```
-
-
-#### get\_date\_after\_n\_business\_days(start\_date: Union[str, DADateTime], wait\_n\_days=1, country="US", subdiv="MA", add\_holidays: Optional[Mapping] = None, remove\_holidays: Optional[Iterable[str]] = None)
+#### get\_date\_after\_n\_business\_days(start\_date: Union[str, DADateTime], wait\_n\_days=1, country="US", subdiv="MA", add\_holidays: Optional[Mapping] = None, remove\_holidays: Optional[Iterable[str]] = None) {#ALToolbox.business\_days.get\_date\_after\_n\_business\_days}
```python
def get_date_after_n_business_days(
diff --git a/docs/components/ALToolbox/copy_button.md b/docs/components/ALToolbox/copy_button.md
index eddfa8a32..6d518f0d6 100644
--- a/docs/components/ALToolbox/copy_button.md
+++ b/docs/components/ALToolbox/copy_button.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [ALToolbox.copy\_button](#ALToolbox.copy_button)
+* ALToolbox.copy\_button
* [copy\_button\_html](#ALToolbox.copy_button.copy_button_html)
---
@@ -8,9 +8,7 @@ sidebar_label: copy_button
title: ALToolbox.copy_button
---
-
-
-#### copy\_button\_html(text\_to\_copy: str, text\_before: str = "", label: str = "Copy", tooltip\_inert\_text: str = "Copy to clipboard", tooltip\_copied\_text: str = "Copied!", copy\_template\_block: bool = False, scroll\_class: str = "", style\_class: str = "", adjust\_height: str = "")
+#### copy\_button\_html(text\_to\_copy: str, text\_before: str = "", label: str = "Copy", tooltip\_inert\_text: str = "Copy to clipboard", tooltip\_copied\_text: str = "Copied!", copy\_template\_block: bool = False, scroll\_class: str = "", style\_class: str = "", adjust\_height: str = "") {#ALToolbox.copy\_button.copy\_button\_html}
```python
def copy_button_html(text_to_copy: str,
diff --git a/docs/components/ALToolbox/display_template.md b/docs/components/ALToolbox/display_template.md
index c79cdfe02..e2f1cfcf5 100644
--- a/docs/components/ALToolbox/display_template.md
+++ b/docs/components/ALToolbox/display_template.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [ALToolbox.display\_template](#ALToolbox.display_template)
+* ALToolbox.display\_template
* [display\_template](#ALToolbox.display_template.display_template)
---
@@ -8,9 +8,7 @@ sidebar_label: display_template
title: ALToolbox.display_template
---
-
-
-#### display\_template(template, scrollable=True, collapse=False, copy=False, classname="bg-light", class\_name=None)
+#### display\_template(template, scrollable=True, collapse=False, copy=False, classname="bg-light", class\_name=None) {#ALToolbox.display\_template.display\_template}
```python
def display_template(template,
diff --git a/docs/components/ALToolbox/llms.md b/docs/components/ALToolbox/llms.md
index c0aad096b..243f14636 100644
--- a/docs/components/ALToolbox/llms.md
+++ b/docs/components/ALToolbox/llms.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [ALToolbox.llms](#ALToolbox.llms)
+* ALToolbox.llms
* [chat\_completion](#ALToolbox.llms.chat_completion)
* [extract\_fields\_from\_text](#ALToolbox.llms.extract_fields_from_text)
* [match\_goals\_from\_text](#ALToolbox.llms.match_goals_from_text)
@@ -32,9 +32,7 @@ sidebar_label: llms
title: ALToolbox.llms
---
-
-
-#### chat\_completion(system\_message: Optional[str] = None, user\_message: Optional[str] = None, openai\_client: Optional[OpenAI] = None, openai\_api: Optional[str] = None, temperature: float = 0.5, json\_mode=False, model: str = "gpt-4o", messages: Optional[List[Dict[str, str]]] = None, skip\_moderation: bool = True, openai\_base\_url: Optional[str] = None, max\_output\_tokens: Optional[int] = None, max\_input\_tokens: Optional[int] = None)
+#### chat\_completion(system\_message: Optional[str] = None, user\_message: Optional[str] = None, openai\_client: Optional[OpenAI] = None, openai\_api: Optional[str] = None, temperature: float = 0.5, json\_mode=False, model: str = "gpt-4o", messages: Optional[List[Dict[str, str]]] = None, skip\_moderation: bool = True, openai\_base\_url: Optional[str] = None, max\_output\_tokens: Optional[int] = None, max\_input\_tokens: Optional[int] = None) {#ALToolbox.llms.chat\_completion}
```python
def chat_completion(
@@ -77,9 +75,7 @@ Includes support for token limits, minimal error handling, and moderation.
A string with the response from the API endpoint or JSON data if json_mode is True
-
-
-#### extract\_fields\_from\_text(text: str, field\_list: Dict[str, str], openai\_client: Optional[OpenAI] = None, openai\_api: Optional[str] = None, temperature: float = 0, model="gpt-4o-mini")
+#### extract\_fields\_from\_text(text: str, field\_list: Dict[str, str], openai\_client: Optional[OpenAI] = None, openai\_api: Optional[str] = None, temperature: float = 0, model="gpt-4o-mini") {#ALToolbox.llms.extract\_fields\_from\_text}
```python
def extract_fields_from_text(text: str,
@@ -106,9 +102,7 @@ Extracts fields from text.
A dictionary of fields extracted from the text
-
-
-#### match\_goals\_from\_text(question: str, user\_response: str, goals: Dict[str, str], openai\_client: Optional[OpenAI] = None, openai\_api: Optional[str] = None, temperature: float = 0, model="gpt-4o-mini")
+#### match\_goals\_from\_text(question: str, user\_response: str, goals: Dict[str, str], openai\_client: Optional[OpenAI] = None, openai\_api: Optional[str] = None, temperature: float = 0, model="gpt-4o-mini") {#ALToolbox.llms.match\_goals\_from\_text}
```python
def match_goals_from_text(question: str,
@@ -137,9 +131,7 @@ Reads a user's message and determines whether it meets a set of goals, with
A dictionary of fields extracted from the text
-
-
-#### classify\_text(text: str, choices: Dict[str, str], default\_response: str = "null", openai\_client: Optional[OpenAI] = None, openai\_api: Optional[str] = None, temperature: float = 0, model="gpt-4o-mini")
+#### classify\_text(text: str, choices: Dict[str, str], default\_response: str = "null", openai\_client: Optional[OpenAI] = None, openai\_api: Optional[str] = None, temperature: float = 0, model="gpt-4o-mini") {#ALToolbox.llms.classify\_text}
```python
def classify_text(text: str,
@@ -168,9 +160,7 @@ Given a text, classify it into one of the provided choices with the assistance o
The classification of the text.
-
-
-#### synthesize\_user\_responses(messages: List[Dict[str, str]], custom\_instructions: Optional[str] = "", openai\_client: Optional[OpenAI] = None, openai\_api: Optional[str] = None, temperature: float = 0, model: str = "gpt-4o-mini")
+#### synthesize\_user\_responses(messages: List[Dict[str, str]], custom\_instructions: Optional[str] = "", openai\_client: Optional[OpenAI] = None, openai\_api: Optional[str] = None, temperature: float = 0, model: str = "gpt-4o-mini") {#ALToolbox.llms.synthesize\_user\_responses}
```python
def synthesize_user_responses(messages: List[Dict[str, str]],
@@ -198,9 +188,7 @@ into a single, coherent reply.
A synthesized response from the user.
-
-
-#### define\_fields\_from\_dict(field\_dict: Dict[str, Any], fields\_to\_ignore: Optional[List] = None)
+#### define\_fields\_from\_dict(field\_dict: Dict[str, Any], fields\_to\_ignore: Optional[List] = None) {#ALToolbox.llms.define\_fields\_from\_dict}
```python
def define_fields_from_dict(field_dict: Dict[str, Any],
@@ -221,9 +209,7 @@ fields_to_ignore is provided, those fields will also be ignored.
None. Should be used to ensure safety when defining fields from untrusted
sources. E.g., ["user_is_logged_in"]
-
-
-## Goal Objects
+## Goal Objects {#ALToolbox.llms.Goal}
```python
class Goal(DAObject)
@@ -237,9 +223,7 @@ A class to represent a goal.
- `description` _str_ - A description of the goal
- `satisfied` _bool_ - Whether the goal is satisfied
-
-
-#### response\_satisfies\_me\_or\_follow\_up(messages: List[Dict[str, str]], openai\_client: Optional[OpenAI] = None, model="gpt-4o-mini", system\_message: Optional[str] = None, llm\_assumed\_role: Optional[str] = "teacher", user\_assumed\_role: Optional[str] = "student")
+#### response\_satisfies\_me\_or\_follow\_up(messages: List[Dict[str, str]], openai\_client: Optional[OpenAI] = None, model="gpt-4o-mini", system\_message: Optional[str] = None, llm\_assumed\_role: Optional[str] = "teacher", user\_assumed\_role: Optional[str] = "student") {#ALToolbox.llms.Goal.response\_satisfies\_me\_or\_follow\_up}
```python
def response_satisfies_me_or_follow_up(
@@ -268,9 +252,7 @@ if the user's response satisfies the goal.
The text of the next question to ask the user or the string "satisfied"
-
-
-#### get\_next\_question(thread\_so\_far: List[Dict[str, str]], openai\_client: Optional[OpenAI] = None, model="gpt-4o-mini")
+#### get\_next\_question(thread\_so\_far: List[Dict[str, str]], openai\_client: Optional[OpenAI] = None, model="gpt-4o-mini") {#ALToolbox.llms.Goal.get\_next\_question}
```python
def get_next_question(thread_so_far: List[Dict[str, str]],
@@ -291,9 +273,7 @@ Returns the text of the next question to ask the user.
The text of the next question to ask the user.
-
-
-## GoalDict Objects
+## GoalDict Objects {#ALToolbox.llms.GoalDict}
```python
class GoalDict(DADict)
@@ -301,9 +281,7 @@ class GoalDict(DADict)
A class to represent a DADict of Goals.
-
-
-#### satisfied()
+#### satisfied() {#ALToolbox.llms.GoalDict.satisfied}
```python
def satisfied() -> bool
@@ -315,9 +293,7 @@ Returns True if all goals are satisfied, False otherwise.
True if all goals are satisfied, False otherwise.
-
-
-## GoalQuestion Objects
+## GoalQuestion Objects {#ALToolbox.llms.GoalQuestion}
```python
class GoalQuestion(DAObject)
@@ -331,9 +307,7 @@ A class to represent a question about a goal.
- `question` _str_ - The question to ask the user
- `response` _str_ - The user's response to the question
-
-
-#### complete()
+#### complete() {#ALToolbox.llms.GoalQuestion.complete}
```python
@property
@@ -342,9 +316,7 @@ def complete()
Returns True if the goal, question, and response attributes are present.
-
-
-## GoalSatisfactionList Objects
+## GoalSatisfactionList Objects {#ALToolbox.llms.GoalSatisfactionList}
```python
class GoalSatisfactionList(DAList)
@@ -379,9 +351,7 @@ open ai:
- `initial_draft` _str_ - The initial draft of the user's response
- `initial_question` _str_ - The original question posed in the interview
-
-
-#### mark\_satisfied\_goals()
+#### mark\_satisfied\_goals() {#ALToolbox.llms.GoalSatisfactionList.mark\_satisfied\_goals}
```python
def mark_satisfied_goals() -> None
@@ -390,9 +360,7 @@ def mark_satisfied_goals() -> None
Marks goals as satisfied if the user's response satisfies the goal.
This should be used as soon as the user gives their initial reply.
-
-
-#### keep\_going()
+#### keep\_going() {#ALToolbox.llms.GoalSatisfactionList.keep\_going}
```python
def keep_going() -> bool
@@ -404,9 +372,7 @@ Returns True if there is at least one unsatisfied goal and if the number of foll
True if there is at least one unsatisfied goal and if the number of follow-up questions asked is less than the question limit, False otherwise.
-
-
-#### need\_more\_questions()
+#### need\_more\_questions() {#ALToolbox.llms.GoalSatisfactionList.need\_more\_questions}
```python
def need_more_questions() -> bool
@@ -421,9 +387,7 @@ and updating the next question to be asked.
True if there is at least one unsatisfied goal, False otherwise.
-
-
-#### satisfied()
+#### satisfied() {#ALToolbox.llms.GoalSatisfactionList.satisfied}
```python
def satisfied() -> bool
@@ -435,9 +399,7 @@ Returns True if all goals are satisfied, False otherwise.
True if all goals are satisfied, False otherwise.
-
-
-#### get\_next\_goal\_and\_question()
+#### get\_next\_goal\_and\_question() {#ALToolbox.llms.GoalSatisfactionList.get\_next\_goal\_and\_question}
```python
def get_next_goal_and_question() -> tuple
@@ -450,9 +412,7 @@ Returns the next unsatisfied goal, along with a follow-up question to ask the us
A tuple of (Goal, str) where the first item is the next unsatisfied goal and the second item is the next question to ask the user, if relevant.
If the user's response to the last question satisfied the goal, returns (None, None).
-
-
-#### synthesize\_draft\_response()
+#### synthesize\_draft\_response() {#ALToolbox.llms.GoalSatisfactionList.synthesize\_draft\_response}
```python
def synthesize_draft_response() -> str
@@ -464,9 +424,7 @@ Returns a draft response that synthesizes the user's responses to the quest
A draft response that synthesizes the user's responses to the questions.
-
-
-#### provide\_feedback(feedback\_prompt: str = "")
+#### provide\_feedback(feedback\_prompt: str = "") {#ALToolbox.llms.GoalSatisfactionList.provide\_feedback}
```python
def provide_feedback(
@@ -484,9 +442,7 @@ Returns feedback to the user based on the goals they satisfied.
Feedback to the user based on the goals they satisfied.
-
-
-## IntakeQuestion Objects
+## IntakeQuestion Objects {#ALToolbox.llms.IntakeQuestion}
```python
class IntakeQuestion(DAObject)
@@ -499,9 +455,7 @@ A class to represent a question in an LLM-assisted intake questionnaire.
- `question` _str_ - The question to ask the user
- `response` _str_ - The user's response to the question
-
-
-#### complete()
+#### complete() {#ALToolbox.llms.IntakeQuestion.complete}
```python
@property
@@ -510,9 +464,7 @@ def complete()
Returns True if the question and response attributes are present.
-
-
-## IntakeQuestionList Objects
+## IntakeQuestionList Objects {#ALToolbox.llms.IntakeQuestionList}
```python
class IntakeQuestionList(DAList)
@@ -544,9 +496,7 @@ embeddings at the moment.
- `out_of_questions` _bool_ - Whether the user has run out of questions to answer
- `qualifies` _bool_ - Whether the user qualifies based on the criteria
-
-
-#### need\_more\_questions()
+#### need\_more\_questions() {#ALToolbox.llms.IntakeQuestionList.need\_more\_questions}
```python
def need_more_questions() -> bool
diff --git a/docs/components/ALToolbox/misc.md b/docs/components/ALToolbox/misc.md
index 96de280b3..d2267d946 100644
--- a/docs/components/ALToolbox/misc.md
+++ b/docs/components/ALToolbox/misc.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [ALToolbox.misc](#ALToolbox.misc)
+* ALToolbox.misc
* [thousands](#ALToolbox.misc.thousands)
* [tel](#ALToolbox.misc.tel)
* [fa\_icon](#ALToolbox.misc.fa_icon)
@@ -28,9 +28,7 @@ sidebar_label: misc
title: ALToolbox.misc
---
-
-
-#### thousands(num: Union[float, str, Decimal], show\_decimals=False)
+#### thousands(num: Union[float, str, Decimal], show\_decimals=False) {#ALToolbox.misc.thousands}
```python
def thousands(num: Union[float, str, Decimal], show_decimals=False) -> str
@@ -63,9 +61,7 @@ closest int.
>>> thousands(1234.56, show_decimals=True)
'1,234.56'
-
-
-#### tel(phone\_number)
+#### tel(phone\_number) {#ALToolbox.misc.tel}
```python
def tel(phone_number) -> str
@@ -91,9 +87,7 @@ and dial the number on mobile devices or applications that support tel links.
>>> tel("555-123-4567")
'<a href="tel:555-123-4567">555-123-4567</a>'
-
-
-#### fa\_icon(icon: str, color: Optional[str] = "primary", color\_css: Optional[str] = None, size: Optional[str] = "sm", fa\_class: str = "fa-solid", aria\_hidden: bool = True)
+#### fa\_icon(icon: str, color: Optional[str] = "primary", color\_css: Optional[str] = None, size: Optional[str] = "sm", fa\_class: str = "fa-solid", aria\_hidden: bool = True) {#ALToolbox.misc.fa\_icon}
```python
def fa_icon(icon: str,
@@ -129,9 +123,7 @@ you more control over the icon that is inserted.
HTML for a font-awesome icon of the specified size and color.
-
-
-#### space(var\_name: str, prefix=" ", suffix="")
+#### space(var\_name: str, prefix=" ", suffix="") {#ALToolbox.misc.space}
```python
def space(var_name: str, prefix=" ", suffix="") -> str
@@ -163,9 +155,7 @@ if the variable name is valid and the variable is defined and has a value.
>>> space("undefined_var")
"" # if variable is not defined
-
-
-#### yes\_no\_unknown(var\_name: str, condition: Optional[bool], unknown="Unknown", placeholder=0)
+#### yes\_no\_unknown(var\_name: str, condition: Optional[bool], unknown="Unknown", placeholder=0) {#ALToolbox.misc.yes\_no\_unknown}
```python
def yes_no_unknown(var_name: str,
@@ -204,9 +194,7 @@ False (explicitly no) and None (unknown/not answered).
>>> yes_no_unknown("user_answer", False, "Unknown", 0)
0
-
-
-#### number\_to\_letter(n: Optional[int])
+#### number\_to\_letter(n: Optional[int]) {#ALToolbox.misc.number\_to\_letter}
```python
def number_to_letter(n: Optional[int]) -> str
@@ -236,9 +224,7 @@ with Excel/Google Sheets column naming conventions. 27=AA, 28=AB...
>>> number_to_letter(27)
'AA'
-
-
-#### collapse\_template(template: DALazyTemplate, classname: str | None = None, closed\_icon: str = "caret-right", open\_icon: str = "caret-down", collapsed: bool = True)
+#### collapse\_template(template: DALazyTemplate, classname: str | None = None, closed\_icon: str = "caret-right", open\_icon: str = "caret-down", collapsed: bool = True) {#ALToolbox.misc.collapse\_template}
```python
def collapse_template(template: DALazyTemplate,
@@ -280,9 +266,7 @@ The default icons are "right caret" which displays when the text is co
>>> collapse_template(my_template, classname="bg-primary", collapsed=False)
'<div id="..." class="al_collapse_template">...</div>'
-
-
-#### tabbed\_templates\_html(tab\_group\_name: str, \*pargs)
+#### tabbed\_templates\_html(tab\_group\_name: str, \*pargs) {#ALToolbox.misc.tabbed\_templates\_html}
```python
def tabbed_templates_html(tab_group_name: str, *pargs) -> str
@@ -312,9 +296,7 @@ subject becomes the tab label and the content becomes the tab panel content.
>>> tabbed_templates_html("my_tabs", template1, template2, template3)
'<ul class="nav nav-tabs" id="my_tabs">...</ul><div class="tab-content">...</div>'
-
-
-#### review\_widget(\*, up\_action: str, down\_action: str, review\_action: Optional[str] = None, thumbs\_display: str = "Did we help you?", review\_display: str = "Thank you for your feedback. Let us know what we could do better", submit\_review\_button: str = "Add your review", post\_review\_display: str = "Thank you for your review!")
+#### review\_widget(\*, up\_action: str, down\_action: str, review\_action: Optional[str] = None, thumbs\_display: str = "Did we help you?", review\_display: str = "Thank you for your feedback. Let us know what we could do better", submit\_review\_button: str = "Add your review", post\_review\_display: str = "Thank you for your review!") {#ALToolbox.misc.review\_widget}
```python
def review_widget(
@@ -353,9 +335,7 @@ a submit button appears, and once the text review is submitted (or after the thu
the HTML string of the widget
-
-
-#### sum\_if\_defined(\*pargs)
+#### sum\_if\_defined(\*pargs) {#ALToolbox.misc.sum\_if\_defined}
```python
def sum_if_defined(*pargs) -> Union[int, float, Decimal]
@@ -382,9 +362,7 @@ that are defined. Undefined variables are skipped rather than causing errors.
>>> sum_if_defined("income1", "income2", "income3")
# Returns sum of defined income variables, skipping any undefined ones
-
-
-#### add\_records(obj, labels)
+#### add\_records(obj, labels) {#ALToolbox.misc.add\_records}
```python
def add_records(obj, labels) -> Any
@@ -413,9 +391,7 @@ including name, description, and reference for creating a demo landing page.
>>> add_records(my_list, interviews)
# my_list[0].name = "intake", description = "Intake Interview", etc.
-
-
-#### output\_checkbox(value\_to\_check: bool, checked\_value: str = "[X]", unchecked\_value: str = "[ ]")
+#### output\_checkbox(value\_to\_check: bool, checked\_value: str = "[X]", unchecked\_value: str = "[ ]") {#ALToolbox.misc.output\_checkbox}
```python
def output_checkbox(value_to_check: bool,
@@ -450,9 +426,7 @@ useful for creating checkboxes in document templates.
>>> output_checkbox(False, checked_value="YES", unchecked_value="NO")
'NO'
-
-
-#### nice\_county\_name(address: Address)
+#### nice\_county\_name(address: Address) {#ALToolbox.misc.nice\_county\_name}
```python
def nice_county_name(address: Address) -> str
@@ -481,9 +455,7 @@ Autocomplete does by default, remove it to get a cleaner display name.
>>> nice_county_name(address_without_county)
''
-
-
-#### button\_array(buttons: List[ButtonDict], custom\_container\_class="", custom\_link\_class="")
+#### button\_array(buttons: List[ButtonDict], custom\_container\_class="", custom\_link\_class="") {#ALToolbox.misc.button\_array}
```python
def button_array(buttons: List[ButtonDict],
@@ -519,9 +491,7 @@ of privileges.
- `str` - HTML for a grid of buttons that mimics docassemble's button field type.
-
-
-#### none\_to\_empty(val: Any)
+#### none\_to\_empty(val: Any) {#ALToolbox.misc.none\_to\_empty}
```python
def none_to_empty(val: Any) -> Any
@@ -543,9 +513,7 @@ without raising an error.
a DAEmpty if the value is None, otherwise the value
-
-
-#### option\_or\_other(variable\_name: str, other\_variable\_name: Optional[str] = None)
+#### option\_or\_other(variable\_name: str, other\_variable\_name: Optional[str] = None) {#ALToolbox.misc.option\_or\_other}
```python
def option_or_other(variable_name: str,
@@ -565,9 +533,7 @@ This is useful for filling in a template and to prevent the word 'Other
the value of the variable if it is not 'Other', otherwise the value of the other variable
-
-
-#### true\_values\_with\_other(variable\_name: str, other\_variable\_name: Optional[str] = None)
+#### true\_values\_with\_other(variable\_name: str, other\_variable\_name: Optional[str] = None) {#ALToolbox.misc.true\_values\_with\_other}
```python
def true_values_with_other(
@@ -592,9 +558,7 @@ This is useful for filling in a template and to prevent the word 'Other
A list of values that are True, with the value of the 'other'
variable appended to the end of the list if 'other'/'Other' was selected.
-
-
-#### include\_a\_year(text: str, field: Optional[str] = None)
+#### include\_a\_year(text: str, field: Optional[str] = None) {#ALToolbox.misc.include\_a\_year}
```python
def include_a_year(text: str, field: Optional[str] = None) -> bool
@@ -630,9 +594,7 @@ birthdate or a moving date.
True
>>> include_a_year("Born long ago") # raises DAValidationError
-
-
-#### is\_leap\_year(year: int)
+#### is\_leap\_year(year: int) {#ALToolbox.misc.is\_leap\_year}
```python
def is_leap_year(year: int) -> bool
@@ -648,9 +610,7 @@ Helper function for `age_in_years` to determine if a year is a leap year.
True if the year is a leap year, False otherwise.
-
-
-#### age\_in\_years(the\_date: Union[str, DADateTime])
+#### age\_in\_years(the\_date: Union[str, DADateTime]) {#ALToolbox.misc.age\_in\_years}
```python
def age_in_years(the_date: Union[str, DADateTime]) -> int
@@ -666,9 +626,7 @@ Calculate the age in years from a date (treated like a date of birth).
The age in years as an integer.
-
-
-#### format\_date\_if\_defined(date\_object\_name: str, \*pargs, default: str = "", \*\*kwargs)
+#### format\_date\_if\_defined(date\_object\_name: str, \*pargs, default: str = "", \*\*kwargs) {#ALToolbox.misc.format\_date\_if\_defined}
```python
def format_date_if_defined(date_object_name: str,
diff --git a/docs/components/ALToolbox/save_input_data.md b/docs/components/ALToolbox/save_input_data.md
index fa05e3fc4..6771fc445 100644
--- a/docs/components/ALToolbox/save_input_data.md
+++ b/docs/components/ALToolbox/save_input_data.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [ALToolbox.save\_input\_data](#ALToolbox.save_input_data)
+* ALToolbox.save\_input\_data
* [save\_input\_data](#ALToolbox.save_input_data.save_input_data)
---
@@ -8,9 +8,7 @@ sidebar_label: save_input_data
title: ALToolbox.save_input_data
---
-
-
-#### save\_input\_data(title: str = "", input\_dict: Optional[Dict[str, Any]] = None, tags: Optional[List[str]] = None)
+#### save\_input\_data(title: str = "", input\_dict: Optional[Dict[str, Any]] = None, tags: Optional[List[str]] = None) {#ALToolbox.save\_input\_data.save\_input\_data}
```python
def save_input_data(title: str = "",
diff --git a/docs/components/AssemblyLine/al_courts.md b/docs/components/AssemblyLine/al_courts.md
index 05aeed8e8..98da4ab92 100644
--- a/docs/components/AssemblyLine/al_courts.md
+++ b/docs/components/AssemblyLine/al_courts.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [AssemblyLine.al\_courts](#AssemblyLine.al_courts)
+* AssemblyLine.al\_courts
* [ALCourt](#AssemblyLine.al_courts.ALCourt)
* [init](#AssemblyLine.al_courts.ALCourt.init)
* [short\_label](#AssemblyLine.al_courts.ALCourt.short_label)
@@ -27,9 +27,7 @@ title: AssemblyLine.al_courts
Package for a very simple / MVP list of courts that is mostly signature compatible w/ MACourts for now
-
-
-## ALCourt Objects
+## ALCourt Objects {#AssemblyLine.al\_courts.ALCourt}
```python
class ALCourt(Court)
@@ -42,9 +40,7 @@ address and can use any of those three features of the court to do the filtering
A list of cities? A list of counties? Instead, we use a function on the CourtList object that filters courts by
address and can use any of those three features of the court to do the filtering.-->
-
-
-#### init(\*pargs, \*\*kwargs)
+#### init(\*pargs, \*\*kwargs) {#AssemblyLine.al\_courts.ALCourt.init}
```python
def init(*pargs, **kwargs) -> None
@@ -57,9 +53,7 @@ Create a new court object.
- `*pargs` - Standard DAObject positional arguments
- `**kwargs` - Standard DAObject keyword arguments
-
-
-#### short\_label()
+#### short\_label() {#AssemblyLine.al\_courts.ALCourt.short\_label}
```python
def short_label() -> str
@@ -74,9 +68,7 @@ list.
- `str` - string representing the court's name, with city if needed to disambiguate
-
-
-#### short\_label\_and\_address()
+#### short\_label\_and\_address() {#AssemblyLine.al\_courts.ALCourt.short\_label\_and\_address}
```python
def short_label_and_address() -> str
@@ -89,9 +81,7 @@ More concise version without description; suitable for a responsive case.
- `str` - string representing the court's name and address
-
-
-#### short\_description()
+#### short\_description() {#AssemblyLine.al\_courts.ALCourt.short\_description}
```python
def short_description() -> str
@@ -105,9 +95,7 @@ buttons.
- `str` - string representing the court's name and description
-
-
-#### from\_row(df\_row: Union[pd.Series, pd.DataFrame], ensure\_lat\_long: bool = True)
+#### from\_row(df\_row: Union[pd.Series, pd.DataFrame], ensure\_lat\_long: bool = True) {#AssemblyLine.al\_courts.ALCourt.from\_row}
```python
def from_row(df_row: Union[pd.Series, pd.DataFrame],
@@ -124,9 +112,7 @@ with existing attributes or methods of DAObject
- `df_row` - Pandas Series object
- `ensure_lat_long` - bool, whether to use Google Maps to geocode the address if we don't have coordinates
-
-
-#### geolocate()
+#### geolocate() {#AssemblyLine.al\_courts.ALCourt.geolocate}
```python
def geolocate() -> None
@@ -136,9 +122,7 @@ Use Google Maps to geocode the court's address and store the result in the
Deprecated: use geocode() instead.
-
-
-#### geocode()
+#### geocode() {#AssemblyLine.al\_courts.ALCourt.geocode}
```python
def geocode() -> None
@@ -146,9 +130,7 @@ def geocode() -> None
Use Google Maps to geocode the court's address and store the result in the location attribute.
-
-
-## ALCourtLoader Objects
+## ALCourtLoader Objects {#AssemblyLine.al\_courts.ALCourtLoader}
```python
class ALCourtLoader(DAObject)
@@ -163,9 +145,7 @@ Built around Pandas dataframe.
- `filename` _str_ - Path to the file containing court information.
- `converters` _Dict[str, Callable]_ - A dictionary of functions to apply to columns in the dataframe.
-
-
-#### init(\*pargs, \*\*kwargs)
+#### init(\*pargs, \*\*kwargs) {#AssemblyLine.al\_courts.ALCourtLoader.init}
```python
def init(*pargs, **kwargs) -> None
@@ -178,9 +158,7 @@ Create a new courtloader object.
- `*pargs` - Standard DAObject positional arguments
- `**kwargs` - Standard DAObject keyword arguments
-
-
-#### all\_courts()
+#### all\_courts() {#AssemblyLine.al\_courts.ALCourtLoader.all\_courts}
```python
def all_courts() -> List[Tuple[int, str]]
@@ -192,9 +170,7 @@ Return a list of all courts in the spreadsheet.
List[Tuple[int, str]]: List of tuples where each tuple contains (dataframe_index, display_value). The dataframe_index (int) can be used with as_court() to retrieve the full court object. The display_value (str) is the court's name or other display column value.
-
-
-#### unique\_column\_values(column\_name: str)
+#### unique\_column\_values(column\_name: str) {#AssemblyLine.al\_courts.ALCourtLoader.unique\_column\_values}
```python
def unique_column_values(column_name: str) -> Set[str]
@@ -213,9 +189,7 @@ Retrieve a set of unique values present in a specified dataframe column.
- A set containing unique values from the specified column.
- Returns an empty set if the column does not exist or an error occurs.
-
-
-#### county\_list(column\_name: str = "address\_county")
+#### county\_list(column\_name: str = "address\_county") {#AssemblyLine.al\_courts.ALCourtLoader.county\_list}
```python
def county_list(column_name: str = "address_county") -> Set[str]
@@ -233,9 +207,7 @@ Typically used to get a list of all possible counties that have a court.
- `Set[str]` - A list of all unique values in the specified row in the given spreadsheet
-
-
-#### county\_has\_one\_court(county\_name: str, county\_column: str = "address\_county")
+#### county\_has\_one\_court(county\_name: str, county\_column: str = "address\_county") {#AssemblyLine.al\_courts.ALCourtLoader.county\_has\_one\_court}
```python
def county_has_one_court(county_name: str,
@@ -256,9 +228,7 @@ in the spreadsheet. Returns False otherwise.
- `bool` - True if there is only one court associated with the specified county in the spreadsheet.
-
-
-#### county\_court(intrinsicName: str, county\_name: str, county\_column: str = "address\_county")
+#### county\_court(intrinsicName: str, county\_name: str, county\_column: str = "address\_county") {#AssemblyLine.al\_courts.ALCourtLoader.county\_court}
```python
def county_court(intrinsicName: str,
@@ -281,9 +251,7 @@ when you know there is exactly one match
- `ALCourt` - The first court matching the county name.
-
-
-#### matching\_courts\_in\_county(county\_name: str, county\_column: str = "address\_county", display\_column: str = "name", search\_string: Optional[str] = None, search\_columns: Optional[Union[List[str], str]] = None)
+#### matching\_courts\_in\_county(county\_name: str, county\_column: str = "address\_county", display\_column: str = "name", search\_string: Optional[str] = None, search\_columns: Optional[Union[List[str], str]] = None) {#AssemblyLine.al\_courts.ALCourtLoader.matching\_courts\_in\_county}
```python
def matching_courts_in_county(
@@ -316,9 +284,7 @@ the second element is the display value from the specified display_column.
List[Tuple[int, str]]: List of tuples where each tuple contains (dataframe_index, display_value). The dataframe_index (int) can be used with as_court() to retrieve the full court object. The display_value (str) is the court's name or other display column value.
-
-
-#### filter\_courts(court\_types: Optional[Union[List[str], str]], column: str = "department", display\_column: str = "name", search\_string: Optional[str] = None, search\_columns: Optional[Union[List[str], str]] = None)
+#### filter\_courts(court\_types: Optional[Union[List[str], str]], column: str = "department", display\_column: str = "name", search\_string: Optional[str] = None, search\_columns: Optional[Union[List[str], str]] = None) {#AssemblyLine.al\_courts.ALCourtLoader.filter\_courts}
```python
def filter_courts(
@@ -350,9 +316,7 @@ is determined by the `display_column`.
List[Tuple[int, str]]: List of tuples where each tuple contains (dataframe_index, display_value). The dataframe_index (int) can be used with as_court() to retrieve the full court object. The display_value (str) is the court's name or other display column value.
-
-
-#### as\_court(intrinsicName: str, index: Union[int, str], ensure\_lat\_long: bool = True)
+#### as\_court(intrinsicName: str, index: Union[int, str], ensure\_lat\_long: bool = True) {#AssemblyLine.al\_courts.ALCourtLoader.as\_court}
```python
def as_court(intrinsicName: str,
diff --git a/docs/components/AssemblyLine/al_document.md b/docs/components/AssemblyLine/al_document.md
index acd0998f7..0aab38a99 100644
--- a/docs/components/AssemblyLine/al_document.md
+++ b/docs/components/AssemblyLine/al_document.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [AssemblyLine.al\_document](#AssemblyLine.al_document)
+* AssemblyLine.al\_document
* [random\_suffix](#AssemblyLine.al_document.random_suffix)
* [base\_name](#AssemblyLine.al_document.base_name)
* [label](#AssemblyLine.al_document.label)
@@ -122,9 +122,7 @@ sidebar_label: al_document
title: AssemblyLine.al_document
---
-
-
-#### random\_suffix(length: int = 8)
+#### random\_suffix(length: int = 8) {#AssemblyLine.al\_document.random\_suffix}
```python
def random_suffix(length: int = 8) -> str
@@ -144,9 +142,7 @@ a true GUID.
- `str` - A random string of lowercase letters and digits.
-
-
-#### base\_name(filename: str)
+#### base\_name(filename: str) {#AssemblyLine.al\_document.base\_name}
```python
def base_name(filename: str) -> str
@@ -163,9 +159,7 @@ Extracts the base name of a file without its extension.
- `str` - The base name of the file without its extension.
-
-
-#### label(dictionary: dict)
+#### label(dictionary: dict) {#AssemblyLine.al\_document.label}
```python
def label(dictionary: dict) -> str
@@ -185,9 +179,7 @@ dictionary item. Useful for working with the `columns` method of an ALAddendumFi
- `str` - The value of the first dictionary item or an empty string if not found.
-
-
-#### key(dictionary: dict)
+#### key(dictionary: dict) {#AssemblyLine.al\_document.key}
```python
def key(dictionary: dict) -> str
@@ -207,9 +199,7 @@ dictionary item. Useful for working with the `columns` method of an ALAddendumFi
- `str` - The key of the first dictionary item or an empty string if not found.
-
-
-#### safeattr(object: Any, key: str)
+#### safeattr(object: Any, key: str) {#AssemblyLine.al\_document.safeattr}
```python
def safeattr(object: Any, key: str) -> str
@@ -232,9 +222,7 @@ Safely retrieve an attribute or key value from an object.
The `location` attribute of an Address object or any LatitudeLongitude attribute of a DAObject is always skipped.
-
-
-#### html\_safe\_str(the\_string: str)
+#### html\_safe\_str(the\_string: str) {#AssemblyLine.al\_document.html\_safe\_str}
```python
def html_safe_str(the_string: str) -> str
@@ -251,9 +239,7 @@ Convert a string into a format that's safe for use as an HTML class or ID.
- `str` - A string that's safe for use as an HTML class or ID.
-
-
-#### table\_row(title: str, button\_htmls: List[str] = [])
+#### table\_row(title: str, button\_htmls: List[str] = []) {#AssemblyLine.al\_document.table\_row}
```python
def table_row(title: str, button_htmls: List[str] = []) -> str
@@ -271,9 +257,7 @@ Generate an HTML row string for an AL document-styled table.
- `str` - An HTML string representing a row in an AL document-styled table.
-
-
-#### pdf\_page\_parity(pdf\_path: str)
+#### pdf\_page\_parity(pdf\_path: str) {#AssemblyLine.al\_document.pdf\_page\_parity}
```python
def pdf_page_parity(pdf_path: str) -> Literal["even", "odd"]
@@ -292,9 +276,7 @@ if it is not divisible by 2.
Literal["even", "odd"]: The parity of the number of pages in the PDF
-
-
-#### add\_blank\_page(pdf\_path: str)
+#### add\_blank\_page(pdf\_path: str) {#AssemblyLine.al\_document.add\_blank\_page}
```python
def add_blank_page(pdf_path: str) -> None
@@ -306,9 +288,7 @@ Add a blank page to the end of a PDF.
- `pdf_path` _str_ - Path to the PDF in the filesystem
-
-
-## ALAddendumField Objects
+## ALAddendumField Objects {#AssemblyLine.al\_document.ALAddendumField}
```python
class ALAddendumField(DAObject)
@@ -336,9 +316,7 @@ is not currently supported.
The attributes `headers` and `field_style` are planned for future releases and are not currently implemented.
-
-
-#### init(\*pargs, \*\*kwargs)
+#### init(\*pargs, \*\*kwargs) {#AssemblyLine.al\_document.ALAddendumField.init}
```python
def init(*pargs, **kwargs) -> None
@@ -351,9 +329,7 @@ Standard DAObject init method.
- `*pargs` - Positional arguments
- `**kwargs` - Keyword arguments
-
-
-#### overflow\_value(preserve\_newlines: bool = False, input\_width: int = 80, overflow\_message: str = "", preserve\_words: bool = True)
+#### overflow\_value(preserve\_newlines: bool = False, input\_width: int = 80, overflow\_message: str = "", preserve\_words: bool = True) {#AssemblyLine.al\_document.ALAddendumField.overflow\_value}
```python
def overflow_value(preserve_newlines: bool = False,
@@ -388,9 +364,7 @@ content adheres to whitespace preferences specified by the parameters.
- `Any` - The portion of the variable exceeding the content safe for display, considered as overflow.
-
-
-#### max\_lines(input\_width: int = 80)
+#### max\_lines(input\_width: int = 80) {#AssemblyLine.al\_document.ALAddendumField.max\_lines}
```python
def max_lines(input_width: int = 80) -> int
@@ -407,9 +381,7 @@ Compute the maximum number of lines that can fit in the input given the specifie
- `int` - The maximum number of lines accommodated by the input width.
-
-
-#### value()
+#### value() {#AssemblyLine.al\_document.ALAddendumField.value}
```python
def value() -> Any
@@ -424,9 +396,7 @@ without the necessity of toggling between various sections or pages.
- `Any` - The whole value of the field, irrespective of overflow.
-
-
-#### has\_overflow(overflow\_message: str = "", input\_width: int = 80, preserve\_newlines: bool = False, \_original\_value: Optional[str] = None, preserve\_words: bool = True)
+#### has\_overflow(overflow\_message: str = "", input\_width: int = 80, preserve\_newlines: bool = False, \_original\_value: Optional[str] = None, preserve\_words: bool = True) {#AssemblyLine.al\_document.ALAddendumField.has\_overflow}
```python
def has_overflow(overflow_message: str = "",
@@ -457,9 +427,7 @@ Return True only if the value's length exceeds the overflow trigger.
- `bool` - True if the value's length exceeds the overflow trigger, False otherwise.
-
-
-#### original\_or\_overflow\_message(overflow\_message: str = "", input\_width: int = 80, preserve\_newlines: bool = False, \_original\_value: Optional[str] = None, preserve\_words: bool = True)
+#### original\_or\_overflow\_message(overflow\_message: str = "", input\_width: int = 80, preserve\_newlines: bool = False, \_original\_value: Optional[str] = None, preserve\_words: bool = True) {#AssemblyLine.al\_document.ALAddendumField.original\_or\_overflow\_message}
```python
def original_or_overflow_message(
@@ -493,9 +461,7 @@ Unlike safe_value(), this will never output a partial value.
Union[str, List[Any]]: Either a string representing the overflow message or the original value
-
-
-#### safe\_value(overflow\_message: str = "", input\_width: int = 80, preserve\_newlines: bool = False, \_original\_value: Optional[str] = None, preserve\_words: bool = True)
+#### safe\_value(overflow\_message: str = "", input\_width: int = 80, preserve\_newlines: bool = False, \_original\_value: Optional[str] = None, preserve\_words: bool = True) {#AssemblyLine.al\_document.ALAddendumField.safe\_value}
```python
def safe_value(overflow_message: str = "",
@@ -536,9 +502,7 @@ with a single space.
Union[str, List[Any]]: The portion of the variable that fits within the overflow trigger.
-
-
-#### value\_if\_defined()
+#### value\_if\_defined() {#AssemblyLine.al\_document.ALAddendumField.value\_if\_defined}
```python
def value_if_defined() -> Any
@@ -552,9 +516,7 @@ This method ensures that the addendum does not inadvertently trigger docassemble
- `Any` - The value of the field if it exists, otherwise an empty string.
-
-
-#### \_\_str\_\_()
+#### \_\_str\_\_() {#AssemblyLine.al\_document.ALAddendumField.\_\_str\_\_}
```python
def __str__()
@@ -566,9 +528,7 @@ Represent the ALAddendumField instance as a string.
- `str` - The string representation of the value contained within the field.
-
-
-#### columns(skip\_empty\_attributes: bool = True, skip\_attributes: Optional[set] = None)
+#### columns(skip\_empty\_attributes: bool = True, skip\_attributes: Optional[set] = None) {#AssemblyLine.al\_document.ALAddendumField.columns}
```python
def columns(skip_empty_attributes: bool = True,
@@ -597,9 +557,7 @@ from the first value in the list. Empty attributes and the `complete` attribute
The "location" attribute of an Address object is always skipped in the column list.
-
-
-#### type()
+#### type() {#AssemblyLine.al\_document.ALAddendumField.type}
```python
def type() -> str
@@ -616,9 +574,7 @@ Categories:
- `str` - The type category of the value.
-
-
-#### is\_list()
+#### is\_list() {#AssemblyLine.al\_document.ALAddendumField.is\_list}
```python
def is_list() -> bool
@@ -630,9 +586,7 @@ Check if the field contains a list value, whether it consists of objects, dictio
- `bool` - True if the field contains a list, otherwise False.
-
-
-#### is\_object\_list()
+#### is\_object\_list() {#AssemblyLine.al\_document.ALAddendumField.is\_object\_list}
```python
def is_object_list() -> bool
@@ -644,9 +598,7 @@ Determine if the field contains a list of dictionaries or objects.
- `bool` - True if the field contains a list of dictionaries or objects, otherwise False.
-
-
-#### overflow\_markdown()
+#### overflow\_markdown() {#AssemblyLine.al\_document.ALAddendumField.overflow\_markdown}
```python
def overflow_markdown() -> str
@@ -662,9 +614,7 @@ to manually control the output's format.
- `str` - A markdown representation of the overflow values.
-
-
-#### overflow\_docx(path: str = "docassemble.ALDocumentDict:data/templates/addendum\_table.docx")
+#### overflow\_docx(path: str = "docassemble.ALDocumentDict:data/templates/addendum\_table.docx") {#AssemblyLine.al\_document.ALAddendumField.overflow\_docx}
```python
def overflow_docx(
@@ -688,9 +638,7 @@ fetching the overflow values using the `overflow_value()` method.
A docx template with the inserted table.
-
-
-## ALAddendumFieldDict Objects
+## ALAddendumFieldDict Objects {#AssemblyLine.al\_document.ALAddendumFieldDict}
```python
class ALAddendumFieldDict(DAOrderedDict)
@@ -710,9 +658,7 @@ Adding a new entry will implicitly set the `field_name` attribute of the field
- `style` _str_ - Determines the display behavior. If set to "overflow_only",
only the overflow text will be displayed.
-
-
-#### init(\*pargs, \*\*kwargs)
+#### init(\*pargs, \*\*kwargs) {#AssemblyLine.al\_document.ALAddendumFieldDict.init}
```python
def init(*pargs, **kwargs) -> None
@@ -725,9 +671,7 @@ Standard DAObject init method.
- `*pargs` - Positional arguments
- `**kwargs` - Keyword arguments
-
-
-#### initializeObject(\*pargs, \*\*kwargs)
+#### initializeObject(\*pargs, \*\*kwargs) {#AssemblyLine.al\_document.ALAddendumFieldDict.initializeObject}
```python
def initializeObject(*pargs, **kwargs) -> Any
@@ -749,9 +693,7 @@ its own field name by setting the `field_name` attribute.
The new dictionary entry created
-
-
-#### from\_list(data: List[Dict])
+#### from\_list(data: List[Dict]) {#AssemblyLine.al\_document.ALAddendumFieldDict.from\_list}
```python
def from_list(data: List[Dict]) -> None
@@ -764,9 +706,7 @@ Populate the dictionary using a list of field data.
- `data` _list_ - List of dictionaries containing ield data with keys "field_name"
and "overflow_trigger".
-
-
-#### defined\_fields(style: str = "overflow\_only")
+#### defined\_fields(style: str = "overflow\_only") {#AssemblyLine.al\_document.ALAddendumFieldDict.defined\_fields}
```python
def defined_fields(style: str = "overflow_only") -> list
@@ -784,9 +724,7 @@ Fetch a list of fields that are defined.
- `list` - List of defined fields based on the specified style.
-
-
-#### overflow()
+#### overflow() {#AssemblyLine.al\_document.ALAddendumFieldDict.overflow}
```python
def overflow() -> list
@@ -798,9 +736,7 @@ Retrieve fields that have overflowed their character limits.
- `list` - A list of fields with overflow values.
-
-
-#### has\_overflow()
+#### has\_overflow() {#AssemblyLine.al\_document.ALAddendumFieldDict.has\_overflow}
```python
def has_overflow() -> bool
@@ -812,9 +748,7 @@ Determine if any field within the dictionary exceeds its overflow limit.
- `bool` - True if at least one field overflows, False otherwise.
-
-
-## DALazyAttribute Objects
+## DALazyAttribute Objects {#AssemblyLine.al\_document.DALazyAttribute}
```python
class DALazyAttribute(DAObject)
@@ -830,9 +764,7 @@ The implementation leverages docassemble's object pickling process by custo
- `instanceName` _str_ - A unique identifier for the object instance, if available.
-
-
-#### \_\_getstate\_\_()
+#### \_\_getstate\_\_() {#AssemblyLine.al\_document.DALazyAttribute.\_\_getstate\_\_}
```python
def __getstate__() -> dict
@@ -848,9 +780,7 @@ persisted across page loads.
- `dict` - A dictionary containing only the `instanceName` if it exists, or empty otherwise.
-
-
-## ALDocument Objects
+## ALDocument Objects {#AssemblyLine.al\_document.ALDocument}
```python
class ALDocument(DADict)
@@ -983,9 +913,7 @@ on the final download screen.
my_doc.overflow_fields.gathered = True
```
-
-
-#### init(\*pargs, \*\*kwargs)
+#### init(\*pargs, \*\*kwargs) {#AssemblyLine.al\_document.ALDocument.init}
```python
def init(*pargs, **kwargs) -> None
@@ -998,9 +926,7 @@ Standard DAObject init method.
- `*pargs` - Positional arguments
- `**kwargs` - Keyword arguments
-
-
-#### as\_pdf(key: str = "final", refresh: bool = True, pdfa: bool = False, append\_matching\_suffix: bool = True)
+#### as\_pdf(key: str = "final", refresh: bool = True, pdfa: bool = False, append\_matching\_suffix: bool = True) {#AssemblyLine.al\_document.ALDocument.as\_pdf}
```python
def as_pdf(key: str = "final",
@@ -1023,9 +949,7 @@ Generates a PDF version of the assembled document.
- `DAFile` - Assembled document in PDF format, possibly combined with addendum.
-
-
-#### as\_docx(key: str = "final", refresh: bool = True, append\_matching\_suffix: bool = True)
+#### as\_docx(key: str = "final", refresh: bool = True, append\_matching\_suffix: bool = True) {#AssemblyLine.al\_document.ALDocument.as\_docx}
```python
def as_docx(key: str = "final",
@@ -1046,9 +970,7 @@ Generates a DOCX version of the assembled document, if possible. Falls back to P
- `DAFile` - Assembled document in DOCX or PDF format.
-
-
-#### as\_list(key: str = "final", refresh: bool = True)
+#### as\_list(key: str = "final", refresh: bool = True) {#AssemblyLine.al\_document.ALDocument.as\_list}
```python
def as_list(key: str = "final", refresh: bool = True) -> List[DAFile]
@@ -1066,9 +988,7 @@ Generates a list containing the main document and its addendum, if applicable.
- `List[DAFile]` - List containing the main document and possibly its addendum.
-
-
-#### need\_addendum()
+#### need\_addendum() {#AssemblyLine.al\_document.ALDocument.need\_addendum}
```python
def need_addendum() -> bool
@@ -1081,9 +1001,7 @@ First checks if the addendum is enabled, and then checks if there's overflo
- `bool` - True if an addendum is needed, False otherwise.
-
-
-#### has\_overflow()
+#### has\_overflow() {#AssemblyLine.al\_document.ALDocument.has\_overflow}
```python
def has_overflow() -> bool
@@ -1095,9 +1013,7 @@ Checks if the document has fields that exceed their character limits.
- `bool` - True if there are overflow fields, False otherwise.
-
-
-#### overflow()
+#### overflow() {#AssemblyLine.al\_document.ALDocument.overflow}
```python
def overflow() -> list
@@ -1109,9 +1025,7 @@ Retrieves a list of fields that have overflowed their character limits.
- `list` - List of overflow fields.
-
-
-#### original\_or\_overflow\_message(field\_name: str, overflow\_message: str = "", input\_width: int = 80, preserve\_newlines: bool = False, \_original\_value: Optional[str] = None, preserve\_words: bool = True)
+#### original\_or\_overflow\_message(field\_name: str, overflow\_message: str = "", input\_width: int = 80, preserve\_newlines: bool = False, \_original\_value: Optional[str] = None, preserve\_words: bool = True) {#AssemblyLine.al\_document.ALDocument.original\_or\_overflow\_message}
```python
def original_or_overflow_message(
@@ -1149,9 +1063,7 @@ Unlike safe_value(), this will never output a partial value.
Union[str, List[Any]]: Either the original value or the overflow message, never a truncated value.
-
-
-#### safe\_value(field\_name: str, overflow\_message: Optional[str] = None, preserve\_newlines: bool = False, input\_width: int = 80, preserve\_words: bool = True)
+#### safe\_value(field\_name: str, overflow\_message: Optional[str] = None, preserve\_newlines: bool = False, input\_width: int = 80, preserve\_words: bool = True) {#AssemblyLine.al\_document.ALDocument.safe\_value}
```python
def safe_value(field_name: str,
@@ -1176,9 +1088,7 @@ Retrieve the "safe" value of a specified field, which is shorter than
- `str` - The "safe" value of the specified field.
-
-
-#### overflow\_value(field\_name: str, overflow\_message: Optional[str] = None, preserve\_newlines: bool = False, input\_width: int = 80, preserve\_words: bool = True)
+#### overflow\_value(field\_name: str, overflow\_message: Optional[str] = None, preserve\_newlines: bool = False, input\_width: int = 80, preserve\_words: bool = True) {#AssemblyLine.al\_document.ALDocument.overflow\_value}
```python
def overflow_value(field_name: str,
@@ -1203,9 +1113,7 @@ Retrieve the "overflow" value of a specified field, which is the amoun
- `str` - The "overflow" value of the specified field.
-
-
-#### is\_enabled(refresh: bool = True)
+#### is\_enabled(refresh: bool = True) {#AssemblyLine.al\_document.ALDocument.is\_enabled}
```python
def is_enabled(refresh: bool = True) -> bool
@@ -1227,9 +1135,7 @@ A document is "enabled" if:
- `bool` - True if the document is enabled, otherwise False.
-
-
-## ALStaticDocument Objects
+## ALStaticDocument Objects {#AssemblyLine.al\_document.ALStaticDocument}
```python
class ALStaticDocument(DAStaticFile)
@@ -1265,9 +1171,7 @@ A class for initializing static documents for inclusion in an ALDocumentBundle w
Consider handling files in `/data/templates` if deemed useful, potentially by copying into a DAFile using `pdf_concatenate()`.
-
-
-#### init(\*pargs, \*\*kwargs)
+#### init(\*pargs, \*\*kwargs) {#AssemblyLine.al\_document.ALStaticDocument.init}
```python
def init(*pargs, **kwargs) -> None
@@ -1280,9 +1184,7 @@ Standard DAObject init method.
- `*pargs` - Positional arguments
- `**kwargs` - Keyword arguments
-
-
-#### \_\_getitem\_\_(key)
+#### \_\_getitem\_\_(key) {#AssemblyLine.al\_document.ALStaticDocument.\_\_getitem\_\_}
```python
def __getitem__(key)
@@ -1294,9 +1196,7 @@ Override to ensure 'final' and 'private' keys always exist a
- `ALStaticDocument` - Returns self.
-
-
-#### as\_list(key: str = "final", refresh: bool = True)
+#### as\_list(key: str = "final", refresh: bool = True) {#AssemblyLine.al\_document.ALStaticDocument.as\_list}
```python
def as_list(key: str = "final", refresh: bool = True) -> List[DAStaticFile]
@@ -1314,9 +1214,7 @@ Get the document as a list.
- `List[DAStaticFile]` - A list containing this document.
-
-
-#### as\_pdf(key: str = "final", pdfa: bool = False, filename: str = "", append\_matching\_suffix: bool = True, refresh: bool = False)
+#### as\_pdf(key: str = "final", pdfa: bool = False, filename: str = "", append\_matching\_suffix: bool = True, refresh: bool = False) {#AssemblyLine.al\_document.ALStaticDocument.as\_pdf}
```python
def as_pdf(key: str = "final",
@@ -1341,9 +1239,7 @@ Convert the document into PDF format.
Union[DAStaticFile, DAFile]: The document in PDF format.
-
-
-#### as\_docx(key: str = "final", refresh: bool = True, append\_matching\_suffix: bool = False)
+#### as\_docx(key: str = "final", refresh: bool = True, append\_matching\_suffix: bool = False) {#AssemblyLine.al\_document.ALStaticDocument.as\_docx}
```python
def as_docx(
@@ -1365,9 +1261,7 @@ Convert the document into DOCX format, if possible. If not, return as PDF.
Union[DAStaticFile, DAFile]: The document in DOCX or PDF format.
-
-
-#### show(\*\*kwargs)
+#### show(\*\*kwargs) {#AssemblyLine.al\_document.ALStaticDocument.show}
```python
def show(**kwargs) -> DAFile
@@ -1386,9 +1280,7 @@ This method provides a workaround for problems generating thumbnails.
- `DAFile` - Displayable version of the document.
-
-
-#### is\_enabled(\*\*kwargs)
+#### is\_enabled(\*\*kwargs) {#AssemblyLine.al\_document.ALStaticDocument.is\_enabled}
```python
def is_enabled(**kwargs) -> bool
@@ -1405,9 +1297,7 @@ Check if the document is enabled.
- `bool` - True if the document is enabled, otherwise False.
-
-
-## ALDocumentBundle Objects
+## ALDocumentBundle Objects {#AssemblyLine.al\_document.ALDocumentBundle}
```python
class ALDocumentBundle(DAList)
@@ -1452,9 +1342,7 @@ bundles, each can be rendered as a merged PDF or a list of documents.
zipped_files = bundle.as_zip()
```
-
-
-#### init(\*pargs, \*\*kwargs)
+#### init(\*pargs, \*\*kwargs) {#AssemblyLine.al\_document.ALDocumentBundle.init}
```python
def init(*pargs, **kwargs) -> None
@@ -1467,9 +1355,7 @@ Standard DAObject init method.
- `*pargs` - Positional arguments
- `**kwargs` - Keyword arguments
-
-
-#### as\_pdf(key: str = "final", refresh: bool = True, pdfa: bool = False, append\_matching\_suffix: bool = True, ensure\_parity: Optional[Literal["even", "odd"]] = None)
+#### as\_pdf(key: str = "final", refresh: bool = True, pdfa: bool = False, append\_matching\_suffix: bool = True, ensure\_parity: Optional[Literal["even", "odd"]] = None) {#AssemblyLine.al\_document.ALDocumentBundle.as\_pdf}
```python
def as_pdf(
@@ -1498,9 +1384,7 @@ Returns a consolidated PDF of all enabled documents in the bundle.
- `Optional[DAFile]` - Combined PDF file or None if no documents are enabled.
-
-
-#### \_\_str\_\_()
+#### \_\_str\_\_() {#AssemblyLine.al\_document.ALDocumentBundle.\_\_str\_\_}
```python
def __str__() -> str
@@ -1514,9 +1398,7 @@ the PDF by default.
- `str` - String representation of the PDF.
-
-
-#### as\_zip(key: str = "final", refresh: bool = True, pdfa: bool = False, title: str = "", format: Optional[str] = "pdf", include\_pdf: Optional[bool] = True)
+#### as\_zip(key: str = "final", refresh: bool = True, pdfa: bool = False, title: str = "", format: Optional[str] = "pdf", include\_pdf: Optional[bool] = True) {#AssemblyLine.al\_document.ALDocumentBundle.as\_zip}
```python
def as_zip(key: str = "final",
@@ -1543,9 +1425,7 @@ Returns a zip file containing all enabled documents in the bundle in the specifi
- `DAFile` - A zip file containing the enabled documents.
-
-
-#### preview(refresh: bool = True)
+#### preview(refresh: bool = True) {#AssemblyLine.al\_document.ALDocumentBundle.preview}
```python
def preview(refresh: bool = True) -> Optional[DAFile]
@@ -1562,9 +1442,7 @@ Returns a preview version of the bundle as a PDF.
- `Optional[DAFile]` - Preview PDF file or None if no documents are enabled.
-
-
-#### has\_enabled\_documents(refresh=False)
+#### has\_enabled\_documents(refresh=False) {#AssemblyLine.al\_document.ALDocumentBundle.has\_enabled\_documents}
```python
def has_enabled_documents(refresh=False) -> bool
@@ -1581,9 +1459,7 @@ Checks if there is at least one enabled document in the bundle.
- `bool` - True if there's at least one enabled document, otherwise False.
-
-
-#### enabled\_documents(refresh: bool = True)
+#### enabled\_documents(refresh: bool = True) {#AssemblyLine.al\_document.ALDocumentBundle.enabled\_documents}
```python
def enabled_documents(refresh: bool = True) -> List[Any]
@@ -1600,9 +1476,7 @@ Retrieves all enabled documents within the bundle.
- `List[Any]` - List of enabled documents.
-
-
-#### as\_flat\_list(key: str = "final", refresh: bool = True)
+#### as\_flat\_list(key: str = "final", refresh: bool = True) {#AssemblyLine.al\_document.ALDocumentBundle.as\_flat\_list}
```python
def as_flat_list(key: str = "final", refresh: bool = True) -> List[DAFile]
@@ -1620,9 +1494,7 @@ Flattens and returns all enabled documents in the bundle, even from nested bundl
- `List[DAFile]` - Flattened list of enabled documents.
-
-
-#### get\_titles(key: str = "final", refresh: bool = True)
+#### get\_titles(key: str = "final", refresh: bool = True) {#AssemblyLine.al\_document.ALDocumentBundle.get\_titles}
```python
def get_titles(key: str = "final", refresh: bool = True) -> List[str]
@@ -1640,9 +1512,7 @@ Retrieves the titles of all enabled documents in the bundle.
- `List[str]` - Titles of the enabled documents.
-
-
-#### as\_pdf\_list(key: str = "final", refresh: bool = True, pdfa: bool = False)
+#### as\_pdf\_list(key: str = "final", refresh: bool = True, pdfa: bool = False) {#AssemblyLine.al\_document.ALDocumentBundle.as\_pdf\_list}
```python
def as_pdf_list(key: str = "final",
@@ -1663,9 +1533,7 @@ Returns all enabled documents in the bundle as individual PDFs, even from nested
- `List[DAFile]` - List of enabled documents as individual PDFs.
-
-
-#### as\_docx\_list(key: str = "final", refresh: bool = True)
+#### as\_docx\_list(key: str = "final", refresh: bool = True) {#AssemblyLine.al\_document.ALDocumentBundle.as\_docx\_list}
```python
def as_docx_list(key: str = "final", refresh: bool = True) -> List[DAFile]
@@ -1685,9 +1553,7 @@ If a particular document can't be represented as a DOCX, its original forma
- `List[DAFile]` - List of documents represented as DOCX files or in their original format.
-
-
-#### as\_editable\_list(key: str = "final", refresh: bool = True)
+#### as\_editable\_list(key: str = "final", refresh: bool = True) {#AssemblyLine.al\_document.ALDocumentBundle.as\_editable\_list}
```python
def as_editable_list(key: str = "final", refresh: bool = True) -> List[DAFile]
@@ -1707,9 +1573,7 @@ For documents that are not in DOCX or RTF formats, the original file format is r
- `List[DAFile]` - Flat list of documents in DOCX or RTF formats or their original format.
-
-
-#### get\_cacheable\_documents(key: str = "final", pdf: bool = True, docx: bool = False, original: bool = False, refresh: bool = True, pdfa: bool = False, include\_zip: bool = True, include\_full\_pdf: bool = False, append\_matching\_suffix: bool = True, zip\_include\_pdf: Optional[bool] = None, zip\_format: Optional[str] = None)
+#### get\_cacheable\_documents(key: str = "final", pdf: bool = True, docx: bool = False, original: bool = False, refresh: bool = True, pdfa: bool = False, include\_zip: bool = True, include\_full\_pdf: bool = False, append\_matching\_suffix: bool = True, zip\_include\_pdf: Optional[bool] = None, zip\_format: Optional[str] = None) {#AssemblyLine.al\_document.ALDocumentBundle.get\_cacheable\_documents}
```python
def get_cacheable_documents(
@@ -1757,9 +1621,7 @@ DAFile # PDF of whole bundle
Tuple[List[Dict[str, DAFile]], Optional[DAFile], Optional[DAFile]]: A list of dictionaries containing the enabled documents, a zip file of the whole bundle, and a PDF of the whole
-
-
-#### download\_list\_html(key: str = "final", format: str = "pdf", view: bool = True, refresh: bool = True, pdfa: bool = False, include\_zip: bool = True, view\_label="View", view\_icon: str = "eye", download\_label: str = "Download", download\_icon: str = "download", send\_label: str = "Send", send\_icon: str = "envelope", zip\_label: Optional[str] = None, zip\_icon: str = "file-archive", zip\_row\_label: Optional[str] = "", append\_matching\_suffix: bool = True, include\_email: bool = False, use\_previously\_cached\_files: bool = False, include\_full\_pdf: bool = False, full\_pdf\_label: Optional[str] = None, zip\_include\_pdf: Optional[bool] = True, zip\_format: Optional[str] = None)
+#### download\_list\_html(key: str = "final", format: str = "pdf", view: bool = True, refresh: bool = True, pdfa: bool = False, include\_zip: bool = True, view\_label="View", view\_icon: str = "eye", download\_label: str = "Download", download\_icon: str = "download", send\_label: str = "Send", send\_icon: str = "envelope", zip\_label: Optional[str] = None, zip\_icon: str = "file-archive", zip\_row\_label: Optional[str] = "", append\_matching\_suffix: bool = True, include\_email: bool = False, use\_previously\_cached\_files: bool = False, include\_full\_pdf: bool = False, full\_pdf\_label: Optional[str] = None, zip\_include\_pdf: Optional[bool] = True, zip\_format: Optional[str] = None) {#AssemblyLine.al\_document.ALDocumentBundle.download\_list\_html}
```python
def download_list_html(key: str = "final",
@@ -1819,9 +1681,7 @@ Constructs an HTML table displaying a list of documents with 'view' an
- `str` - HTML representation of a table with documents and their associated actions.
-
-
-#### download\_html(key: str = "final", format: str = "pdf", pdfa: bool = False, view: bool = True, refresh: bool = True, view\_label: str = "View", view\_icon: str = "eye", download\_label: str = "Download", download\_icon: str = "download")
+#### download\_html(key: str = "final", format: str = "pdf", pdfa: bool = False, view: bool = True, refresh: bool = True, view\_label: str = "View", view\_icon: str = "eye", download\_label: str = "Download", download\_icon: str = "download") {#AssemblyLine.al\_document.ALDocumentBundle.download\_html}
```python
def download_html(key: str = "final",
@@ -1857,9 +1717,7 @@ Deprecated; use download_list_html instead
- `str` - HTML representation of a table with documents and their associated actions.
-
-
-#### send\_email\_table\_row(key: str = "final", send\_label: str = "Send", send\_icon: str = "envelope")
+#### send\_email\_table\_row(key: str = "final", send\_label: str = "Send", send\_icon: str = "envelope") {#AssemblyLine.al\_document.ALDocumentBundle.send\_email\_table\_row}
```python
def send_email_table_row(key: str = "final",
@@ -1881,9 +1739,7 @@ someone to send the bundle to the specified email address.
- `str` - The generated HTML string for the table row.
-
-
-#### send\_button\_to\_html(email: str, editable: Optional[bool] = None, template\_name: str = "", label: str = "Send", icon: str = "envelope", color: str = "primary", key: str = "final", preferred\_formats: Optional[Union[str, List[str]]] = None)
+#### send\_button\_to\_html(email: str, editable: Optional[bool] = None, template\_name: str = "", label: str = "Send", icon: str = "envelope", color: str = "primary", key: str = "final", preferred\_formats: Optional[Union[str, List[str]]] = None) {#AssemblyLine.al\_document.ALDocumentBundle.send\_button\_to\_html}
```python
def send_button_to_html(
@@ -1917,9 +1773,7 @@ in contrast to send_button_html.
- `str` - The generated HTML string for the button.
-
-
-#### send\_button\_html(key: str = "final", show\_editable\_checkbox: bool = True, template\_name: str = "", label: str = "Send", icon: str = "envelope", preferred\_formats: Optional[Union[str, List[str]]] = None)
+#### send\_button\_html(key: str = "final", show\_editable\_checkbox: bool = True, template\_name: str = "", label: str = "Send", icon: str = "envelope", preferred\_formats: Optional[Union[str, List[str]]] = None) {#AssemblyLine.al\_document.ALDocumentBundle.send\_button\_html}
```python
def send_button_html(
@@ -1955,9 +1809,7 @@ include an editable (Word) copy of the file, if and only if it is available.
- `str` - The generated HTML string for the input box and button.
-
-
-#### send\_email(to: Any = None, key: str = "final", editable: Optional[bool] = None, template: Optional[Any] = None, preferred\_formats: Optional[Union[str, List[str]]] = "pdf", \*\*kwargs)
+#### send\_email(to: Any = None, key: str = "final", editable: Optional[bool] = None, template: Optional[Any] = None, preferred\_formats: Optional[Union[str, List[str]]] = "pdf", \*\*kwargs) {#AssemblyLine.al\_document.ALDocumentBundle.send\_email}
```python
def send_email(to: Any = None,
@@ -1986,9 +1838,7 @@ https://docassemble.org/docs/functions.html#send_email with additional parameter
- `bool` - Indicates if the email was sent successfully.
-
-
-#### is\_enabled(refresh=True)
+#### is\_enabled(refresh=True) {#AssemblyLine.al\_document.ALDocumentBundle.is\_enabled}
```python
def is_enabled(refresh=True) -> bool
@@ -2005,9 +1855,7 @@ Check if the bundle itself is enabled, and if it has at least one enabled child
- `bool` - Indicates if the bundle and its child documents are enabled.
-
-
-#### as\_docx(key: str = "final", refresh: bool = True, append\_matching\_suffix: bool = True)
+#### as\_docx(key: str = "final", refresh: bool = True, append\_matching\_suffix: bool = True) {#AssemblyLine.al\_document.ALDocumentBundle.as\_docx}
```python
def as_docx(key: str = "final",
@@ -2028,9 +1876,7 @@ Convert the enabled documents to a single DOCX file or PDF file if conversion fa
- `DAFile` - A DAFile object containing the concatenated DOCX or PDF file.
-
-
-#### as\_list(key: str = "final", refresh: bool = True)
+#### as\_list(key: str = "final", refresh: bool = True) {#AssemblyLine.al\_document.ALDocumentBundle.as\_list}
```python
def as_list(key: str = "final", refresh: bool = True) -> List[DAFile]
@@ -2048,9 +1894,7 @@ Return a list of enabled documents.
- `List[DAFile]` - A list of enabled DAFile objects.
-
-
-## ALExhibit Objects
+## ALExhibit Objects {#AssemblyLine.al\_document.ALExhibit}
```python
class ALExhibit(DAObject)
@@ -2066,9 +1910,7 @@ Class to represent a single exhibit, with cover page, which may contain multiple
- `label` _str_ - A label, like "A" or "1" for this exhibit in the cover page and table of contents
- `starting_page` _int_ - first page number to use in table of contents
-
-
-#### init(\*pargs, \*\*kwargs)
+#### init(\*pargs, \*\*kwargs) {#AssemblyLine.al\_document.ALExhibit.init}
```python
def init(*pargs, **kwargs) -> None
@@ -2081,9 +1923,7 @@ Standard DAObject init method.
- `*pargs` - Positional arguments
- `**kwargs` - Keyword arguments
-
-
-#### ocr\_ready()
+#### ocr\_ready() {#AssemblyLine.al\_document.ALExhibit.ocr\_ready}
```python
def ocr_ready() -> bool
@@ -2100,9 +1940,7 @@ That situation is likely a developer error, as you shouldn't wait for OCR i
- `bool` - True iff OCR process has finished on all pages.
-
-
-#### ocr\_pages()
+#### ocr\_pages() {#AssemblyLine.al\_document.ALExhibit.ocr\_pages}
```python
def ocr_pages() -> List[DAFile]
@@ -2114,9 +1952,7 @@ Retrieve the OCR-processed version of pages if available, else return the origin
- `List[DAFile]` - List of pages, either OCR-processed or original.
-
-
-#### as\_pdf(\*, refresh: bool = False, prefix: str = "", pdfa: bool = False, add\_page\_numbers: bool = True, add\_cover\_page: bool = True, filename: Optional[str] = None, append\_matching\_suffix: bool = True)
+#### as\_pdf(\*, refresh: bool = False, prefix: str = "", pdfa: bool = False, add\_page\_numbers: bool = True, add\_cover\_page: bool = True, filename: Optional[str] = None, append\_matching\_suffix: bool = True) {#AssemblyLine.al\_document.ALExhibit.as\_pdf}
```python
def as_pdf(*,
@@ -2148,9 +1984,7 @@ Note that these are keyword only parameters, not positional.
- `DAFile` - PDF representation of the exhibit.
-
-
-#### num\_pages()
+#### num\_pages() {#AssemblyLine.al\_document.ALExhibit.num\_pages}
```python
def num_pages() -> int
@@ -2162,9 +1996,7 @@ Calculate the total number of pages in the exhibit.
- `int` - Total page count.
-
-
-#### complete()
+#### complete() {#AssemblyLine.al\_document.ALExhibit.complete}
```python
@property
@@ -2178,9 +2010,7 @@ Indicates if the exhibit is complete.
NOTE: This property always returns True after triggering the required attributes.
-
-
-#### \_\_str\_\_()
+#### \_\_str\_\_() {#AssemblyLine.al\_document.ALExhibit.\_\_str\_\_}
```python
def __str__() -> str
@@ -2192,9 +2022,7 @@ Return the title of the exhibit.
- `str` - Title of the exhibit.
-
-
-#### ocrmypdf\_task(from\_file: Union[DAFile, DAFileList], to\_pdf: DAFile)
+#### ocrmypdf\_task(from\_file: Union[DAFile, DAFileList], to\_pdf: DAFile) {#AssemblyLine.al\_document.ocrmypdf\_task}
```python
def ocrmypdf_task(from_file: Union[DAFile, DAFileList],
@@ -2223,9 +2051,7 @@ This function is designed to be executed as a background task (id: al_exhibit_oc
- `subprocess.TimeoutExpired` - If the ocrmypdf process takes longer than an hour.
-
-
-## ALExhibitList Objects
+## ALExhibitList Objects {#AssemblyLine.al\_document.ALExhibitList}
```python
class ALExhibitList(DAList)
@@ -2242,9 +2068,7 @@ and rendering them into a single PDF file.
Uses A..Z labels by default.
- `auto_ocr` _bool_ - If True, automatically starts OCR processing for uploaded exhibits. Defaults to True.
-
-
-#### init(\*pargs, \*\*kwargs)
+#### init(\*pargs, \*\*kwargs) {#AssemblyLine.al\_document.ALExhibitList.init}
```python
def init(*pargs, **kwargs) -> None
@@ -2257,9 +2081,7 @@ Standard DAObject init method.
- `*pargs` - Positional arguments
- `**kwargs` - Keyword arguments
-
-
-#### as\_pdf(filename="file.pdf", pdfa: bool = False, add\_page\_numbers: bool = False, toc\_pages: int = 0, append\_matching\_suffix: bool = True)
+#### as\_pdf(filename="file.pdf", pdfa: bool = False, add\_page\_numbers: bool = False, toc\_pages: int = 0, append\_matching\_suffix: bool = True) {#AssemblyLine.al\_document.ALExhibitList.as\_pdf}
```python
def as_pdf(filename="file.pdf",
@@ -2284,9 +2106,7 @@ Compiles all exhibits in the list into a single PDF.
- `DAFile` - A single PDF containing all exhibits.
-
-
-#### size\_in\_bytes()
+#### size\_in\_bytes() {#AssemblyLine.al\_document.ALExhibitList.size\_in\_bytes}
```python
def size_in_bytes() -> int
@@ -2298,9 +2118,7 @@ Calculates the total size in bytes of all exhibits in the list.
- `int` - Total size of all exhibits in bytes.
-
-
-#### ocr\_ready()
+#### ocr\_ready() {#AssemblyLine.al\_document.ALExhibitList.ocr\_ready}
```python
def ocr_ready() -> bool
@@ -2312,9 +2130,7 @@ Checks if all exhibits in the list have completed the OCR process.
- `bool` - True if all exhibits are OCRed or if OCR hasn't started. False otherwise.
-
-
-#### hook\_after\_gather()
+#### hook\_after\_gather() {#AssemblyLine.al\_document.ALExhibitList.hook\_after\_gather}
```python
def hook_after_gather() -> None
@@ -2323,9 +2139,7 @@ def hook_after_gather() -> None
Callback function executed after the entire list of exhibits is collected.
Manages auto-labeling and initiates OCR if necessary.
-
-
-## ALExhibitDocument Objects
+## ALExhibitDocument Objects {#AssemblyLine.al\_document.ALExhibitDocument}
```python
class ALExhibitDocument(ALDocument)
@@ -2376,9 +2190,7 @@ objects:
- exhibit_attachment: ALExhibitDocument.using(title="Exhibits", filename="exhibits" , auto_labeler=item_label)
```
-
-
-#### init(\*pargs, \*\*kwargs)
+#### init(\*pargs, \*\*kwargs) {#AssemblyLine.al\_document.ALExhibitDocument.init}
```python
def init(*pargs, **kwargs) -> None
@@ -2391,9 +2203,7 @@ Standard DAObject init method.
- `*pargs` - Positional arguments
- `**kwargs` - Keyword arguments
-
-
-#### has\_overflow()
+#### has\_overflow() {#AssemblyLine.al\_document.ALExhibitDocument.has\_overflow}
```python
def has_overflow() -> bool
@@ -2407,9 +2217,7 @@ This is for compatibility with ALDocument; Exhibits inherently don't have o
- `bool` - Always False for this implementation.
-
-
-#### ocr\_ready()
+#### ocr\_ready() {#AssemblyLine.al\_document.ALExhibitDocument.ocr\_ready}
```python
def ocr_ready() -> bool
@@ -2421,9 +2229,7 @@ Determine if all exhibits within the document have undergone OCR processing.
- `bool` - True if all exhibits have been OCRed or if the OCR process hasn't been initiated.
-
-
-#### \_\_getitem\_\_(key)
+#### \_\_getitem\_\_(key) {#AssemblyLine.al\_document.ALExhibitDocument.\_\_getitem\_\_}
```python
def __getitem__(key)
@@ -2440,9 +2246,7 @@ Overridden method to ensure 'final' and 'private' keys alway
- `ALExhibitDocument` - Returns the current instance of the class.
-
-
-#### as\_list(key: str = "final", refresh: bool = True)
+#### as\_list(key: str = "final", refresh: bool = True) {#AssemblyLine.al\_document.ALExhibitDocument.as\_list}
```python
def as_list(key: str = "final", refresh: bool = True) -> List[DAFile]
@@ -2460,9 +2264,7 @@ Retrieve the document as a list.
- `List[DAFile]` - A list containing the document.
-
-
-#### as\_pdf(key: str = "final", refresh: bool = True, pdfa: bool = False, append\_matching\_suffix: bool = True)
+#### as\_pdf(key: str = "final", refresh: bool = True, pdfa: bool = False, append\_matching\_suffix: bool = True) {#AssemblyLine.al\_document.ALExhibitDocument.as\_pdf}
```python
def as_pdf(key: str = "final",
@@ -2487,9 +2289,7 @@ Render the document as a PDF.
- `DAFile` - The document rendered as a PDF.
-
-
-#### as\_docx(key: str = "final", refresh: bool = True, append\_matching\_suffix: bool = True)
+#### as\_docx(key: str = "final", refresh: bool = True, append\_matching\_suffix: bool = True) {#AssemblyLine.al\_document.ALExhibitDocument.as\_docx}
```python
def as_docx(key: str = "final",
@@ -2510,9 +2310,7 @@ Despite the name, renders the document as a PDF. Provided for signature compatib
- `DAFile` - The document rendered as a PDF.
-
-
-## ALTableDocument Objects
+## ALTableDocument Objects {#AssemblyLine.al\_document.ALTableDocument}
```python
class ALTableDocument(ALDocument)
@@ -2528,9 +2326,7 @@ This class provides functionality to export data as a table in various formats s
- `file` _DAFile, optional_ - Reference to the generated file (can be PDF, DOCX, etc.).
- `table` _???_ - Represents the actual table data. Type and attributes need more context to document.
-
-
-#### init(\*pargs, \*\*kwargs)
+#### init(\*pargs, \*\*kwargs) {#AssemblyLine.al\_document.ALTableDocument.init}
```python
def init(*pargs, **kwargs) -> None
@@ -2543,9 +2339,7 @@ Standard DAObject init method.
- `*pargs` - Positional arguments
- `**kwargs` - Keyword arguments
-
-
-#### has\_overflow()
+#### has\_overflow() {#AssemblyLine.al\_document.ALTableDocument.has\_overflow}
```python
def has_overflow() -> bool
@@ -2559,9 +2353,7 @@ For compatibility with ALDocument; Tables inherently don't have overflow.
- `bool` - Always False for this implementation.
-
-
-#### \_\_getitem\_\_(key)
+#### \_\_getitem\_\_(key) {#AssemblyLine.al\_document.ALTableDocument.\_\_getitem\_\_}
```python
def __getitem__(key)
@@ -2580,9 +2372,7 @@ Overridden to ensure 'final' and 'private' keys always retur
- `DAFile` - The document in its PDF format.
-
-
-#### as\_list(key: str = "final", refresh: bool = True, \*\*kwargs)
+#### as\_list(key: str = "final", refresh: bool = True, \*\*kwargs) {#AssemblyLine.al\_document.ALTableDocument.as\_list}
```python
def as_list(key: str = "final",
@@ -2602,9 +2392,7 @@ Retrieve the document as a list.
- `List[DAFile]` - A list containing the document.
-
-
-#### as\_pdf(key: str = "final", refresh: bool = True, pdfa: bool = False, append\_matching\_suffix: bool = True, \*\*kwargs)
+#### as\_pdf(key: str = "final", refresh: bool = True, pdfa: bool = False, append\_matching\_suffix: bool = True, \*\*kwargs) {#AssemblyLine.al\_document.ALTableDocument.as\_pdf}
```python
def as_pdf(key: str = "final",
@@ -2629,9 +2417,7 @@ Name retained for signature compatibility.
- `DAFile` - The table rendered as an XLSX spreadsheet
-
-
-#### as\_docx(key: str = "bool", refresh: bool = True, append\_matching\_suffix: bool = True)
+#### as\_docx(key: str = "bool", refresh: bool = True, append\_matching\_suffix: bool = True) {#AssemblyLine.al\_document.ALTableDocument.as\_docx}
```python
def as_docx(key: str = "bool",
@@ -2654,9 +2440,7 @@ Name retained for signature compatibility.
- `DAFile` - The table rendered as an XLSX spreadsheet
-
-
-## ALUntransformedDocument Objects
+## ALUntransformedDocument Objects {#AssemblyLine.al\_document.ALUntransformedDocument}
```python
class ALUntransformedDocument(ALDocument)
@@ -2671,9 +2455,7 @@ compatibility with ALDocument.
- `has_addendum` _bool_ - A flag indicating the presence of an addendum in the document.
- `suffix_to_append` _str_ - Suffix that can be appended to file names, defaulting to "preview".
-
-
-#### init(\*pargs, \*\*kwargs)
+#### init(\*pargs, \*\*kwargs) {#AssemblyLine.al\_document.ALUntransformedDocument.init}
```python
def init(*pargs, **kwargs) -> None
@@ -2686,9 +2468,7 @@ Standard DAObject init method.
- `*pargs` - Positional arguments
- `**kwargs` - Keyword arguments
-
-
-#### has\_overflow()
+#### has\_overflow() {#AssemblyLine.al\_document.ALUntransformedDocument.has\_overflow}
```python
def has_overflow() -> bool
@@ -2702,9 +2482,7 @@ For compatibility with ALDocument. Untransformed documents inherently don't
- `bool` - Always False for this implementation.
-
-
-#### as\_list(key: str = "final", refresh: bool = True, \*\*kwargs)
+#### as\_list(key: str = "final", refresh: bool = True, \*\*kwargs) {#AssemblyLine.al\_document.ALUntransformedDocument.as\_list}
```python
def as_list(key: str = "final",
@@ -2724,9 +2502,7 @@ Retrieve the document as a list.
- `List[DAFile]` - A list containing the document.
-
-
-#### as\_pdf(key: str = "final", refresh: bool = True, pdfa: bool = False, append\_matching\_suffix: bool = True, \*\*kwargs)
+#### as\_pdf(key: str = "final", refresh: bool = True, pdfa: bool = False, append\_matching\_suffix: bool = True, \*\*kwargs) {#AssemblyLine.al\_document.ALUntransformedDocument.as\_pdf}
```python
def as_pdf(key: str = "final",
@@ -2752,9 +2528,7 @@ This method is primarily for duck-typing compatibility with ALDocument.
- `DAFile` - The original, untransformed document.
-
-
-#### as\_docx(key: str = "final", refresh: bool = True, append\_matching\_suffix: bool = True)
+#### as\_docx(key: str = "final", refresh: bool = True, append\_matching\_suffix: bool = True) {#AssemblyLine.al\_document.ALUntransformedDocument.as\_docx}
```python
def as_docx(key: str = "final",
@@ -2777,9 +2551,7 @@ This method is primarily for duck-typing compatibility with ALDocument.
- `DAFile` - The original, untransformed document.
-
-
-## ALDocumentUpload Objects
+## ALDocumentUpload Objects {#AssemblyLine.al\_document.ALDocumentUpload}
```python
class ALDocumentUpload(ALUntransformedDocument)
@@ -2788,9 +2560,7 @@ class ALDocumentUpload(ALUntransformedDocument)
Simplified class to handle uploaded documents, without any of the complexity of the
ALExhibitDocument class.
-
-
-#### unpack\_dafilelist(the\_file: DAFileList)
+#### unpack\_dafilelist(the\_file: DAFileList) {#AssemblyLine.al\_document.unpack\_dafilelist}
```python
def unpack_dafilelist(the_file: DAFileList) -> DAFile
diff --git a/docs/components/AssemblyLine/al_general.md b/docs/components/AssemblyLine/al_general.md
index e2b074b97..cb8f679cd 100644
--- a/docs/components/AssemblyLine/al_general.md
+++ b/docs/components/AssemblyLine/al_general.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [AssemblyLine.al\_general](#AssemblyLine.al_general)
+* AssemblyLine.al\_general
* [safe\_subdivision\_type](#AssemblyLine.al_general.safe_subdivision_type)
* [ALAddress](#AssemblyLine.al_general.ALAddress)
* [address\_fields](#AssemblyLine.al_general.ALAddress.address_fields)
@@ -79,9 +79,7 @@ sidebar_label: al_general
title: AssemblyLine.al_general
---
-
-
-#### safe\_subdivision\_type(country\_code: str)
+#### safe\_subdivision\_type(country\_code: str) {#AssemblyLine.al\_general.safe\_subdivision\_type}
```python
def safe_subdivision_type(country_code: str) -> Optional[str]
@@ -99,9 +97,7 @@ If no subdivision type is found, returns None.
- `Optional[str]` - The subdivision type for the country with the given country code.
-
-
-## ALAddress Objects
+## ALAddress Objects {#AssemblyLine.al\_general.ALAddress}
```python
class ALAddress(Address)
@@ -121,9 +117,7 @@ handling of the unit attribute when printing a formatted address.
- `country` _str_ - The country where the person lives.
- `impounded` _Optional[bool]_ - Whether the address is impounded.
-
-
-#### address\_fields(country\_code: Optional[str] = None, default\_state: Optional[str] = None, show\_country: bool = False, show\_county: bool = False, show\_if: Union[str, Dict[str, str], None] = None, allow\_no\_address: bool = False, ask\_if\_impounded: Optional[bool] = False, maxlengths: Optional[Dict[str, int]] = None, required: Optional[Dict[str, bool]] = None)
+#### address\_fields(country\_code: Optional[str] = None, default\_state: Optional[str] = None, show\_country: bool = False, show\_county: bool = False, show\_if: Union[str, Dict[str, str], None] = None, allow\_no\_address: bool = False, ask\_if\_impounded: Optional[bool] = False, maxlengths: Optional[Dict[str, int]] = None, required: Optional[Dict[str, bool]] = None) {#AssemblyLine.al\_general.ALAddress.address\_fields}
```python
def address_fields(
@@ -176,9 +170,7 @@ NOTE: This function is stateful under specific conditions. Refer to the conditio
- Link to ISO-3166-1 alpha-2 codes:
[Officially assigned code elements](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements).
-
-
-#### formatted\_unit(language: Optional[str] = None, require: bool = False, bare: bool = False)
+#### formatted\_unit(language: Optional[str] = None, require: bool = False, bare: bool = False) {#AssemblyLine.al\_general.ALAddress.formatted\_unit}
```python
def formatted_unit(language: Optional[str] = None,
@@ -205,9 +197,7 @@ Returns the unit, formatted appropriately.
the unit number, possibly prefixed with 'Unit'. If the unit attribute exists and is None or an empty
string, the function will return an empty string.
-
-
-#### block(language: Optional[str] = None, international: bool = False, show\_country: Optional[bool] = None, bare: bool = False, long\_state: bool = False, show\_impounded: bool = False)
+#### block(language: Optional[str] = None, international: bool = False, show\_country: Optional[bool] = None, bare: bool = False, long\_state: bool = False, show\_impounded: bool = False) {#AssemblyLine.al\_general.ALAddress.block}
```python
def block(language: Optional[str] = None,
@@ -235,9 +225,7 @@ Returns a one-line formatted address, primarily for geocoding.
- `str` - The one-line formatted address.
-
-
-#### line\_one(language: Optional[str] = None, bare: bool = False, show\_impounded: bool = False)
+#### line\_one(language: Optional[str] = None, bare: bool = False, show\_impounded: bool = False) {#AssemblyLine.al\_general.ALAddress.line\_one}
```python
def line_one(language: Optional[str] = None,
@@ -258,9 +246,7 @@ Returns the first line of the address, including the unit number if it exists.
- `str` - The first line of the address.
-
-
-#### line\_two(language: Optional[str] = None, long\_state: bool = False, show\_impounded: bool = False)
+#### line\_two(language: Optional[str] = None, long\_state: bool = False, show\_impounded: bool = False) {#AssemblyLine.al\_general.ALAddress.line\_two}
```python
def line_two(language: Optional[str] = None,
@@ -281,9 +267,7 @@ Returns the second line of the address, including city, state, and postal code.
- `str` - The second line of the address.
-
-
-#### on\_one\_line(include\_unit: bool = True, omit\_default\_country: bool = True, language: Optional[str] = None, show\_country: Optional[bool] = None, bare: bool = False, long\_state: bool = False, show\_impounded: bool = False)
+#### on\_one\_line(include\_unit: bool = True, omit\_default\_country: bool = True, language: Optional[str] = None, show\_country: Optional[bool] = None, bare: bool = False, long\_state: bool = False, show\_impounded: bool = False) {#AssemblyLine.al\_general.ALAddress.on\_one\_line}
```python
def on_one_line(include_unit: bool = True,
@@ -313,9 +297,7 @@ Returns a one-line formatted address.
- `str` - The one-line formatted address.
-
-
-#### normalized\_address()
+#### normalized\_address() {#AssemblyLine.al\_general.ALAddress.normalized\_address}
```python
def normalized_address() -> Union[Address, "ALAddress"]
@@ -337,9 +319,7 @@ Warning: currently the normalized address will not be redacted if the address is
Normalized address if geocoding is successful, otherwise
the original address.
-
-
-#### state\_name(country\_code: Optional[str] = None)
+#### state\_name(country\_code: Optional[str] = None) {#AssemblyLine.al\_general.ALAddress.state\_name}
```python
def state_name(country_code: Optional[str] = None) -> str
@@ -365,9 +345,7 @@ object. Otherwise, the method uses, in order:
- `str` - The full state name corresponding to the state abbreviation. If an error occurs
or the full name cannot be determined, returns the state abbreviation.
-
-
-## ALAddressList Objects
+## ALAddressList Objects {#AssemblyLine.al\_general.ALAddressList}
```python
class ALAddressList(DAList)
@@ -379,9 +357,7 @@ Extends the DAList class and specifically caters to ALAddress objects.
It provides methods to initialize the list and get a string representation
of the list in a formatted manner.
-
-
-#### init(\*pargs, \*\*kwargs)
+#### init(\*pargs, \*\*kwargs) {#AssemblyLine.al\_general.ALAddressList.init}
```python
def init(*pargs, **kwargs) -> None
@@ -394,9 +370,7 @@ Standard DAObject init method.
- `*pargs` - Positional arguments
- `**kwargs` - Keyword arguments
-
-
-#### \_\_str\_\_()
+#### \_\_str\_\_() {#AssemblyLine.al\_general.ALAddressList.\_\_str\_\_}
```python
def __str__() -> str
@@ -411,9 +385,7 @@ comma-separated manner using the on_one_line method of ALAddress.
- `str` - Formatted string of all addresses in the list.
-
-
-## ALNameList Objects
+## ALNameList Objects {#AssemblyLine.al\_general.ALNameList}
```python
class ALNameList(DAList)
@@ -423,9 +395,7 @@ A class to store a list of IndividualName objects.
Extends the DAList class and is tailored for IndividualName objects.
-
-
-#### init(\*pargs, \*\*kwargs)
+#### init(\*pargs, \*\*kwargs) {#AssemblyLine.al\_general.ALNameList.init}
```python
def init(*pargs, **kwargs) -> None
@@ -438,9 +408,7 @@ Standard DAObject init method.
- `*pargs` - Positional arguments
- `**kwargs` - Keyword arguments
-
-
-#### \_\_str\_\_()
+#### \_\_str\_\_() {#AssemblyLine.al\_general.ALNameList.\_\_str\_\_}
```python
def __str__() -> str
@@ -452,9 +420,7 @@ Provide a string representation of the ALNameList.
- `str` - Formatted string of all names in the list.
-
-
-## ALPeopleList Objects
+## ALPeopleList Objects {#AssemblyLine.al\_general.ALPeopleList}
```python
class ALPeopleList(DAList)
@@ -464,9 +430,7 @@ Class to store a list of ALIndividual objects, representing people.
For example, defendants, plaintiffs, or children.
-
-
-#### init(\*pargs, \*\*kwargs)
+#### init(\*pargs, \*\*kwargs) {#AssemblyLine.al\_general.ALPeopleList.init}
```python
def init(*pargs, **kwargs) -> None
@@ -479,9 +443,7 @@ Standard DAObject init method.
- `*pargs` - Positional arguments
- `**kwargs` - Keyword arguments
-
-
-#### names\_and\_addresses\_on\_one\_line(comma\_string: str = "; ", bare=False)
+#### names\_and\_addresses\_on\_one\_line(comma\_string: str = "; ", bare=False) {#AssemblyLine.al\_general.ALPeopleList.names\_and\_addresses\_on\_one\_line}
```python
def names_and_addresses_on_one_line(comma_string: str = "; ",
@@ -500,9 +462,7 @@ Provide names and addresses of individuals on one line.
- `str` - Formatted string of names followed by addresses.
-
-
-#### familiar(\*\*kwargs)
+#### familiar(\*\*kwargs) {#AssemblyLine.al\_general.ALPeopleList.familiar}
```python
def familiar(**kwargs) -> str
@@ -518,9 +478,7 @@ Provide a list of familiar forms of names of individuals.
- `str` - Formatted string of familiar names.
-
-
-#### familiar\_or(\*\*kwargs)
+#### familiar\_or(\*\*kwargs) {#AssemblyLine.al\_general.ALPeopleList.familiar\_or}
```python
def familiar_or(**kwargs) -> str
@@ -537,9 +495,7 @@ Provide a list of familiar forms of names of individuals separated by 'or
- `str` - Formatted string of familiar names separated by 'or'.
-
-
-#### short\_list(limit: int, truncate\_string: str = ", et. al.")
+#### short\_list(limit: int, truncate\_string: str = ", et. al.") {#AssemblyLine.al\_general.ALPeopleList.short\_list}
```python
def short_list(limit: int, truncate_string: str = ", et. al.") -> str
@@ -557,9 +513,7 @@ Return a subset of the list, truncated with 'et. al.' if it exceeds a
- `str` - Formatted string of names, truncated if needed.
-
-
-#### full\_names(comma\_string=", ", and\_string=word("and"))
+#### full\_names(comma\_string=", ", and\_string=word("and")) {#AssemblyLine.al\_general.ALPeopleList.full\_names}
```python
def full_names(comma_string=", ", and_string=word("and")) -> str
@@ -577,9 +531,7 @@ Return a formatted list of full names of individuals.
- `str` - Formatted string of full names.
-
-
-#### pronoun\_reflexive(\*\*kwargs)
+#### pronoun\_reflexive(\*\*kwargs) {#AssemblyLine.al\_general.ALPeopleList.pronoun\_reflexive}
```python
def pronoun_reflexive(**kwargs) -> str
@@ -602,9 +554,7 @@ If it is plural, return the appropriate plural reflexive pronoun (e.g., "th
- `str` - The reflexive pronoun for the list.
-
-
-## ALIndividual Objects
+## ALIndividual Objects {#AssemblyLine.al\_general.ALIndividual}
```python
class ALIndividual(Individual)
@@ -632,9 +582,7 @@ other addresses, mailing addresses, previous names, aliases, and a preferred nam
Objects as attributes should not be passed directly to the constructor due to
initialization requirements in the docassemble framework. See the `init` method.
-
-
-#### init(\*pargs, \*\*kwargs)
+#### init(\*pargs, \*\*kwargs) {#AssemblyLine.al\_general.ALIndividual.init}
```python
def init(*pargs, **kwargs) -> None
@@ -647,9 +595,7 @@ Standard DAObject init method.
- `*pargs` - Positional arguments
- `**kwargs` - Keyword arguments
-
-
-#### signature\_if\_final(i: str)
+#### signature\_if\_final(i: str) {#AssemblyLine.al\_general.ALIndividual.signature\_if\_final}
```python
def signature_if_final(i: str) -> Union[DAFile, str]
@@ -666,9 +612,7 @@ Returns the individual's signature if `i` is "final", which usual
Union[DAFile, str]: The signature if the condition is met, otherwise an empty string.
-
-
-#### phone\_numbers(country: Optional[str] = None, show\_impounded: bool = False)
+#### phone\_numbers(country: Optional[str] = None, show\_impounded: bool = False) {#AssemblyLine.al\_general.ALIndividual.phone\_numbers}
```python
def phone_numbers(country: Optional[str] = None,
@@ -695,9 +639,7 @@ Supports the following attributes:
- `str` - Formatted string of phone numbers.
-
-
-#### contact\_methods()
+#### contact\_methods() {#AssemblyLine.al\_general.ALIndividual.contact\_methods}
```python
def contact_methods() -> str
@@ -709,9 +651,7 @@ Generates a formatted string of all provided contact methods.
- `str` - A formatted string indicating the available methods to contact the individual.
-
-
-#### merge\_letters(new\_letters: str)
+#### merge\_letters(new\_letters: str) {#AssemblyLine.al\_general.ALIndividual.merge\_letters}
```python
def merge_letters(new_letters: str) -> None
@@ -725,9 +665,7 @@ Avoid using. Only used in 209A.
- `new_letters` _str_ - The new letters to add to the existing list of letters
-
-
-#### formatted\_age()
+#### formatted\_age() {#AssemblyLine.al\_general.ALIndividual.formatted\_age}
```python
def formatted_age() -> str
@@ -739,9 +677,7 @@ Calculates and formats the age of the individual based on their birthdate.
- `str` - Formatted age string that shows the most relevant time unit; for example, if under 2 years, it will return "X months".
-
-
-#### normalized\_address()
+#### normalized\_address() {#AssemblyLine.al\_general.ALIndividual.normalized\_address}
```python
def normalized_address() -> Union[Address, ALAddress]
@@ -753,9 +689,7 @@ Fetches the normalized version of the address.
Union[Address, ALAddress]: The normalized address object.
-
-
-#### name\_fields(person\_or\_business: str = "person", show\_suffix: bool = True, show\_title: bool = False, title\_choices: Optional[Union[List[str], Callable]] = None, show\_if: Union[str, Dict[str, str], None] = None, maxlengths: Optional[Dict[str, int]] = None, suffix\_choices: Optional[Union[List[str], Callable]] = None, title\_options: Optional[Union[List[str], Callable]] = None)
+#### name\_fields(person\_or\_business: str = "person", show\_suffix: bool = True, show\_title: bool = False, title\_choices: Optional[Union[List[str], Callable]] = None, show\_if: Union[str, Dict[str, str], None] = None, maxlengths: Optional[Dict[str, int]] = None, suffix\_choices: Optional[Union[List[str], Callable]] = None, title\_options: Optional[Union[List[str], Callable]] = None) {#AssemblyLine.al\_general.ALIndividual.name\_fields}
```python
def name_fields(
@@ -800,9 +734,7 @@ and other provided parameters.
If `person_or_business` is set to None, the method will offer the end user a choice
and will set appropriate "show ifs" conditions for each type.
-
-
-#### address\_fields(country\_code: str = "US", default\_state: Optional[str] = None, show\_country: bool = False, show\_county: bool = False, show\_if: Union[str, Dict[str, str], None] = None, allow\_no\_address: bool = False, ask\_if\_impounded: bool = False, maxlengths: Optional[Dict[str, int]] = None, required: Optional[Dict[str, bool]] = None)
+#### address\_fields(country\_code: str = "US", default\_state: Optional[str] = None, show\_country: bool = False, show\_county: bool = False, show\_if: Union[str, Dict[str, str], None] = None, allow\_no\_address: bool = False, ask\_if\_impounded: bool = False, maxlengths: Optional[Dict[str, int]] = None, required: Optional[Dict[str, bool]] = None) {#AssemblyLine.al\_general.ALIndividual.address\_fields}
```python
def address_fields(
@@ -836,9 +768,7 @@ Generate field prompts for capturing an address.
List[Dict[str, str]]: A list of dictionaries with field prompts for addresses.
-
-
-#### gender\_fields(show\_help=False, show\_if: Union[str, Dict[str, str], None] = None, maxlengths: Optional[Dict[str, int]] = None, choices: Optional[Union[List[Dict[str, str]], Callable]] = None)
+#### gender\_fields(show\_help=False, show\_if: Union[str, Dict[str, str], None] = None, maxlengths: Optional[Dict[str, int]] = None, choices: Optional[Union[List[Dict[str, str]], Callable]] = None) {#AssemblyLine.al\_general.ALIndividual.gender\_fields}
```python
def gender_fields(
@@ -869,9 +799,7 @@ self-described option.
self-described will provide an input that overrides the value of `gender` and is not persisted.
-
-
-#### pronoun\_fields(show\_help=False, show\_if: Union[str, Dict[str, str], None] = None, required: bool = False, shuffle: bool = False, show\_unknown: Optional[Union[Literal["guess"], bool]] = "guess", maxlengths: Optional[Dict[str, int]] = None, choices: Optional[List[Dict[str, str]]] = None)
+#### pronoun\_fields(show\_help=False, show\_if: Union[str, Dict[str, str], None] = None, required: bool = False, shuffle: bool = False, show\_unknown: Optional[Union[Literal["guess"], bool]] = "guess", maxlengths: Optional[Dict[str, int]] = None, choices: Optional[List[Dict[str, str]]] = None) {#AssemblyLine.al\_general.ALIndividual.pronoun\_fields}
```python
def pronoun_fields(
@@ -902,9 +830,7 @@ Generate fields for capturing pronoun information.
List[Dict[str, str]]: A list of dictionaries with field prompts for pronouns.
-
-
-#### get\_pronouns()
+#### get\_pronouns() {#AssemblyLine.al\_general.ALIndividual.get\_pronouns}
```python
def get_pronouns() -> set
@@ -920,9 +846,7 @@ Can be formatted however the author likes.
- `set` - A set of strings representing the individual's pronouns.
-
-
-#### list\_pronouns()
+#### list\_pronouns() {#AssemblyLine.al\_general.ALIndividual.list\_pronouns}
```python
def list_pronouns() -> str
@@ -935,9 +859,7 @@ the comma_list() function.
- `str` - A formatted string of the individual's pronouns.
-
-
-#### language\_fields(choices: Optional[Union[List[Dict[str, str]], Callable]] = None, style: str = "radio", show\_if: Union[str, Dict[str, str], None] = None, maxlengths: Optional[Dict[str, int]] = None)
+#### language\_fields(choices: Optional[Union[List[Dict[str, str]], Callable]] = None, style: str = "radio", show\_if: Union[str, Dict[str, str], None] = None, maxlengths: Optional[Dict[str, int]] = None) {#AssemblyLine.al\_general.ALIndividual.language\_fields}
```python
def language_fields(
@@ -961,9 +883,7 @@ Generate fields for capturing language preferences.
List[Dict[str, str]]: A list of dictionaries with field prompts for language preferences.
-
-
-#### language\_name()
+#### language\_name() {#AssemblyLine.al\_general.ALIndividual.language\_name}
```python
def language_name() -> str
@@ -977,9 +897,7 @@ Get the human-readable version of the individual's selected language.
it returns the value in `language_other`. Otherwise, it uses the
`language_name` function.
-
-
-#### gender\_male()
+#### gender\_male() {#AssemblyLine.al\_general.ALIndividual.gender\_male}
```python
@property
@@ -991,9 +909,7 @@ Returns True only if the gender is male.
Used to assist with checkbox filling in PDFs with "skip undefined"
turned on.
-
-
-#### gender\_female()
+#### gender\_female() {#AssemblyLine.al\_general.ALIndividual.gender\_female}
```python
@property
@@ -1005,9 +921,7 @@ Returns True only if the gender is female.
Used to assist with checkbox filling in PDFs with "skip undefined"
turned on.
-
-
-#### gender\_other()
+#### gender\_other() {#AssemblyLine.al\_general.ALIndividual.gender\_other}
```python
@property
@@ -1019,9 +933,7 @@ Returns True only if the gender is not male or female.
Used to assist with checkbox filling in PDFs with "skip undefined"
turned on.
-
-
-#### gender\_nonbinary()
+#### gender\_nonbinary() {#AssemblyLine.al\_general.ALIndividual.gender\_nonbinary}
```python
@property
@@ -1033,9 +945,7 @@ Returns True only if the gender is nonbinary.
Used to assist with checkbox filling in PDFs with "skip undefined"
turned on.
-
-
-#### gender\_unknown()
+#### gender\_unknown() {#AssemblyLine.al\_general.ALIndividual.gender\_unknown}
```python
@property
@@ -1047,9 +957,7 @@ Returns True only if the gender is unknown.
Used to assist with checkbox filling in PDFs with "skip undefined"
turned on.
-
-
-#### gender\_undisclosed()
+#### gender\_undisclosed() {#AssemblyLine.al\_general.ALIndividual.gender\_undisclosed}
```python
@property
@@ -1061,9 +969,7 @@ Returns True only if the gender is not disclosed ("prefer-not-to-say")
Used to assist with checkbox filling in PDFs with "skip undefined"
turned on.
-
-
-#### gender\_self\_described()
+#### gender\_self\_described() {#AssemblyLine.al\_general.ALIndividual.gender\_self\_described}
```python
@property
@@ -1075,9 +981,7 @@ Returns True only if the gender is self described.
Used to assist with checkbox filling in PDFs with "skip undefined"
turned on.
-
-
-#### contact\_fields()
+#### contact\_fields() {#AssemblyLine.al\_general.ALIndividual.contact\_fields}
```python
def contact_fields() -> None
@@ -1085,9 +989,7 @@ def contact_fields() -> None
Return field prompts for other contact info
-
-
-#### initials()
+#### initials() {#AssemblyLine.al\_general.ALIndividual.initials}
```python
@property
@@ -1098,9 +1000,7 @@ Returns the initials of the individual as a string.
For example, "Quinten K Steenhuis" would return "QKS".
-
-
-#### address\_block(language=None, international=False, show\_country=False, bare=False, show\_impounded=False)
+#### address\_block(language=None, international=False, show\_country=False, bare=False, show\_impounded=False) {#AssemblyLine.al\_general.ALIndividual.address\_block}
```python
def address_block(language=None,
@@ -1125,9 +1025,7 @@ Generate a formatted address block for mailings.
- `str` - The formatted address block.
-
-
-#### pronoun(\*\*kwargs)
+#### pronoun(\*\*kwargs) {#AssemblyLine.al\_general.ALIndividual.pronoun}
```python
def pronoun(**kwargs) -> str
@@ -1151,9 +1049,7 @@ with `pronouns` taking precedence. As a default, it will either use the value of
- `str` - The appropriate pronoun.
-
-
-#### pronoun\_objective(\*\*kwargs)
+#### pronoun\_objective(\*\*kwargs) {#AssemblyLine.al\_general.ALIndividual.pronoun\_objective}
```python
def pronoun_objective(**kwargs) -> str
@@ -1170,9 +1066,7 @@ Returns the same pronoun as the `pronoun()` method.
- `str` - The appropriate objective pronoun.
-
-
-#### pronoun\_possessive(target, \*\*kwargs)
+#### pronoun\_possessive(target, \*\*kwargs) {#AssemblyLine.al\_general.ALIndividual.pronoun\_possessive}
```python
def pronoun_possessive(target, **kwargs) -> str
@@ -1199,9 +1093,7 @@ and whether the individual is the current user.
- `str` - The appropriate possessive phrase, e.g., "her book", "their document".
-
-
-#### pronoun\_subjective(\*\*kwargs)
+#### pronoun\_subjective(\*\*kwargs) {#AssemblyLine.al\_general.ALIndividual.pronoun\_subjective}
```python
def pronoun_subjective(**kwargs) -> str
@@ -1223,9 +1115,7 @@ is the current user.
- `str` - The appropriate subjective pronoun.
-
-
-#### pronoun\_reflexive(\*\*kwargs)
+#### pronoun\_reflexive(\*\*kwargs) {#AssemblyLine.al\_general.ALIndividual.pronoun\_reflexive}
```python
def pronoun_reflexive(**kwargs) -> str
@@ -1249,9 +1139,7 @@ See: https://www.merriam-webster.com/wordplay/themself
- `str` - The appropriate reflexive pronoun.
-
-
-#### name\_full()
+#### name\_full() {#AssemblyLine.al\_general.ALIndividual.name\_full}
```python
def name_full() -> str
@@ -1267,9 +1155,7 @@ the first name, even if middle, last, or suffix are defined.
- `str` - The individual or business's full name.
-
-
-#### name\_initials()
+#### name\_initials() {#AssemblyLine.al\_general.ALIndividual.name\_initials}
```python
def name_initials() -> str
@@ -1287,9 +1173,7 @@ the "initials" of the first name, even if middle, last, or suffix are
- `str` - The individual's name with the middle name as an initial.
-
-
-#### name\_short()
+#### name\_short() {#AssemblyLine.al\_general.ALIndividual.name\_short}
```python
def name_short() -> str
@@ -1307,9 +1191,7 @@ the first name, even if middle, last, or suffix are defined.
- `str` - The individual'
-
-
-#### familiar(unique\_names: Optional[List[Any]] = None, default: Optional[str] = None)
+#### familiar(unique\_names: Optional[List[Any]] = None, default: Optional[str] = None) {#AssemblyLine.al\_general.ALIndividual.familiar}
```python
def familiar(unique_names: Optional[List[Any]] = None,
@@ -1354,9 +1236,7 @@ the first name, even if middle, last, or suffix are defined.
Who do you want to take care of $\{ children.familiar(unique_names=parents + petitioners, default="the minor") \}
```
-
-
-#### \_\_str\_\_()
+#### \_\_str\_\_() {#AssemblyLine.al\_general.ALIndividual.\_\_str\_\_}
```python
def __str__() -> str
@@ -1373,9 +1253,7 @@ the first name, even if middle, last, or suffix are defined.
- `str` - The individual's name.
-
-
-#### section\_links(nav)
+#### section\_links(nav) {#AssemblyLine.al\_general.section\_links}
```python
def section_links(nav) -> List[str]
@@ -1392,9 +1270,7 @@ Returns a list of clickable navigation links without animation.
- `List[str]` - A list of clickable navigation links without animation.
-
-
-#### will\_send\_to\_real\_court()
+#### will\_send\_to\_real\_court() {#AssemblyLine.al\_general.will\_send\_to\_real\_court}
```python
def will_send_to_real_court() -> bool
@@ -1409,9 +1285,7 @@ The text "dev" or "test" needs to be in the URL root in the
- `bool` - True if the form is being run on the dev, test, or production server.
-
-
-#### filter\_letters(letter\_strings: Union[List[str], str])
+#### filter\_letters(letter\_strings: Union[List[str], str]) {#AssemblyLine.al\_general.filter\_letters}
```python
def filter_letters(letter_strings: Union[List[str], str]) -> str
@@ -1430,9 +1304,7 @@ Avoid using, this is created for 209A.
- `str` - A string of unique letters.
-
-
-#### fa\_icon(icon: str, color: str = "primary", color\_css: Optional[str] = None, size: str = "sm")
+#### fa\_icon(icon: str, color: str = "primary", color\_css: Optional[str] = None, size: str = "sm") {#AssemblyLine.al\_general.fa\_icon}
```python
def fa_icon(icon: str,
@@ -1457,9 +1329,7 @@ a CSS variable (such as Bootstrap theme color) or a true CSS color reference, su
- `str` - HTML for the icon.
-
-
-#### is\_sms\_enabled()
+#### is\_sms\_enabled() {#AssemblyLine.al\_general.is\_sms\_enabled}
```python
def is_sms_enabled() -> bool
@@ -1473,9 +1343,7 @@ See https://docassemble.org/docs/config.html#twilio for more info.
- `bool` - True if there is a non-empty Twilio config on the server, False otherwise
-
-
-#### is\_phone\_or\_email(text: str)
+#### is\_phone\_or\_email(text: str) {#AssemblyLine.al\_general.is\_phone\_or\_email}
```python
def is_phone_or_email(text: str) -> bool
@@ -1500,9 +1368,7 @@ strings.
DAValidationError if the string is neither a valid phone number nor a valid email address.
-
-
-#### github\_modified\_date(github\_user: str, github\_repo\_name: str, auth=None)
+#### github\_modified\_date(github\_user: str, github\_repo\_name: str, auth=None) {#AssemblyLine.al\_general.github\_modified\_date}
```python
def github_modified_date(github_user: str,
@@ -1540,9 +1406,7 @@ The GitHub API is rate-limited to 60 anonymous API queries/hour.
Union[DADateTime, None]: The date that the given GitHub repository was modified or None if API call fails.
-
-
-#### language\_name(language\_code: str)
+#### language\_name(language\_code: str) {#AssemblyLine.al\_general.language\_name}
```python
def language_name(language_code: str) -> str
@@ -1561,9 +1425,7 @@ function.
- `str` - The full name of the language.
-
-
-#### safe\_states\_list(country\_code: str)
+#### safe\_states\_list(country\_code: str) {#AssemblyLine.al\_general.safe\_states\_list}
```python
def safe_states_list(country_code: str) -> List[Dict[str, str]]
@@ -1581,9 +1443,7 @@ an invalid country_code (e.g., a country name spelled out)
List[Dict[str, str]]: A list of dictionaries with field prompts for states.
-
-
-#### has\_parsable\_pronouns(pronouns: str)
+#### has\_parsable\_pronouns(pronouns: str) {#AssemblyLine.al\_general.has\_parsable\_pronouns}
```python
def has_parsable_pronouns(pronouns: str) -> bool
@@ -1600,9 +1460,7 @@ Returns True if the pronouns string can be parsed into a dictionary of pronouns.
True if the pronouns string can be parsed into a dictionary of pronouns, False otherwise
-
-
-#### parse\_custom\_pronouns(pronouns: str)
+#### parse\_custom\_pronouns(pronouns: str) {#AssemblyLine.al\_general.parse\_custom\_pronouns}
```python
def parse_custom_pronouns(pronouns: str) -> Dict[str, str]
@@ -1619,9 +1477,7 @@ Parses a custom pronoun string into a dictionary of pronouns.
a dictionary of pronouns in the format \{"o": objective, "s": subjective, "p": possessive\}
-
-
-#### get\_visible\_al\_nav\_items(nav\_items: List[Union[str, dict]])
+#### get\_visible\_al\_nav\_items(nav\_items: List[Union[str, dict]]) {#AssemblyLine.al\_general.get\_visible\_al\_nav\_items}
```python
def get_visible_al_nav_items(
diff --git a/docs/components/AssemblyLine/background_assembly.md b/docs/components/AssemblyLine/background_assembly.md
index 484dcfc81..ac2c1e198 100644
--- a/docs/components/AssemblyLine/background_assembly.md
+++ b/docs/components/AssemblyLine/background_assembly.md
@@ -161,7 +161,7 @@ Optionally, it will also produce a .ZIP and a .PDF version of the full bundle.
This is called from a YAML block in the Assembly Line standard include files to define the `_downloadable_files`
attribute of a bundle.
-[download_list_html()](al_document.md#download_list_html) has an optional parameter,
+[download_list_html()](al_document.md#AssemblyLine.al_document.ALDocumentBundle.download_list_html) has an optional parameter,
`use_previously_cached_files` which must be set to `True` to make use of the `_downloadable_files`
attribute of the bundle.
diff --git a/docs/components/AssemblyLine/custom_jinja_filters.md b/docs/components/AssemblyLine/custom_jinja_filters.md
index ec4daeaa0..1a143dc72 100644
--- a/docs/components/AssemblyLine/custom_jinja_filters.md
+++ b/docs/components/AssemblyLine/custom_jinja_filters.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [AssemblyLine.custom\_jinja\_filters](#AssemblyLine.custom_jinja_filters)
+* AssemblyLine.custom\_jinja\_filters
* [catchall\_options](#AssemblyLine.custom_jinja_filters.catchall_options)
* [catchall\_label](#AssemblyLine.custom_jinja_filters.catchall_label)
* [catchall\_datatype](#AssemblyLine.custom_jinja_filters.catchall_datatype)
@@ -14,9 +14,7 @@ sidebar_label: custom_jinja_filters
title: AssemblyLine.custom_jinja_filters
---
-
-
-#### catchall\_options(value: Any, \*raw\_items: Any)
+#### catchall\_options(value: Any, \*raw\_items: Any) {#AssemblyLine.custom\_jinja\_filters.catchall\_options}
```python
def catchall_options(value: Any, *raw_items: Any) -> DACatchAll
@@ -69,9 +67,7 @@ fields:
- `DACatchAll` - The modified DACatchAll object with the assigned options.
-
-
-#### catchall\_label(value: Any, label: str)
+#### catchall\_label(value: Any, label: str) {#AssemblyLine.custom\_jinja\_filters.catchall\_label}
```python
def catchall_label(value: Any, label: str) -> DACatchAll
@@ -107,9 +103,7 @@ fields:
- `DACatchAll` - The modified DACatchAll object with the assigned label.
-
-
-#### catchall\_datatype(value: Any, datatype: str)
+#### catchall\_datatype(value: Any, datatype: str) {#AssemblyLine.custom\_jinja\_filters.catchall\_datatype}
```python
def catchall_datatype(value: Any, datatype: str) -> DACatchAll
@@ -137,9 +131,7 @@ Example usage in a DOCX template:
- `DACatchAll` - The modified DACatchAll object with the assigned datatype.
-
-
-#### catchall\_question(value: Any, question: str)
+#### catchall\_question(value: Any, question: str) {#AssemblyLine.custom\_jinja\_filters.catchall\_question}
```python
def catchall_question(value: Any, question: str) -> DACatchAll
@@ -167,9 +159,7 @@ Example usage in a DOCX template:
- `DACatchAll` - The modified DACatchAll object with the assigned question.
-
-
-#### catchall\_subquestion(value: Any, subquestion: str)
+#### catchall\_subquestion(value: Any, subquestion: str) {#AssemblyLine.custom\_jinja\_filters.catchall\_subquestion}
```python
def catchall_subquestion(value: Any, subquestion: str) -> DACatchAll
@@ -197,9 +187,7 @@ Example usage in a DOCX template:
- `DACatchAll` - The modified DACatchAll object with the assigned subquestion.
-
-
-#### if\_final(context: Jinja2Context, value: Any, i: Optional[str] = None, expected\_i: Union[str, List[str]] = "final", placeholder: Optional[str] = None)
+#### if\_final(context: Jinja2Context, value: Any, i: Optional[str] = None, expected\_i: Union[str, List[str]] = "final", placeholder: Optional[str] = None) {#AssemblyLine.custom\_jinja\_filters.if\_final}
```python
@pass_context
@@ -283,9 +271,7 @@ as in an ALDocument's "preview" or "final" values.
- `Any` - The original `value` if `i` matches `expected_i`, otherwise the `placeholder`.
-
-
-#### catchall\_fields\_code(value: Any)
+#### catchall\_fields\_code(value: Any) {#AssemblyLine.custom\_jinja\_filters.catchall\_fields\_code}
```python
def catchall_fields_code(value: Any) -> List[Dict[str, Any]]
diff --git a/docs/components/AssemblyLine/language.md b/docs/components/AssemblyLine/language.md
index 72d1826e4..70c864c14 100644
--- a/docs/components/AssemblyLine/language.md
+++ b/docs/components/AssemblyLine/language.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [AssemblyLine.language](#AssemblyLine.language)
+* AssemblyLine.language
* [get\_local\_languages\_yaml](#AssemblyLine.language.get_local_languages_yaml)
* [get\_tuples](#AssemblyLine.language.get_tuples)
* [get\_language\_list\_dropdown](#AssemblyLine.language.get_language_list_dropdown)
@@ -13,9 +13,7 @@ sidebar_label: language
title: AssemblyLine.language
---
-
-
-#### get\_local\_languages\_yaml()
+#### get\_local\_languages\_yaml() {#AssemblyLine.language.get\_local\_languages\_yaml}
```python
def get_local_languages_yaml() -> str
@@ -27,9 +25,7 @@ Get the path to the local languages.yml file. If it does not exist, it will retu
- `str` - the path to the local languages.yml file if it exists, otherwise the path to the languages.yml file
-
-
-#### get\_tuples(lang\_codes: List[str], languages\_path: Optional[str] = None)
+#### get\_tuples(lang\_codes: List[str], languages\_path: Optional[str] = None) {#AssemblyLine.language.get\_tuples}
```python
def get_tuples(lang_codes: List[str],
@@ -51,9 +47,7 @@ English name from pycountry. If neither is present, it will use the language cod
A list of tuples representing the language name, followed by language ISO 639-1 code.
-
-
-#### get\_language\_list\_dropdown(lang\_codes: List[str], current: str = "", languages\_path: Optional[str] = None, event\_name="al\_change\_language", icon="fa-solid fa-language fa-xl", extra\_class: str = "text-light")
+#### get\_language\_list\_dropdown(lang\_codes: List[str], current: str = "", languages\_path: Optional[str] = None, event\_name="al\_change\_language", icon="fa-solid fa-language fa-xl", extra\_class: str = "text-light") {#AssemblyLine.language.get\_language\_list\_dropdown}
```python
def get_language_list_dropdown(lang_codes: List[str],
@@ -79,9 +73,7 @@ Get a Bootstrap 5 dropdown menu for language selection that can be added to navi
A string containing the HTML for a dropdown menu for language selection.
-
-
-#### get\_language\_list\_dropdown\_item(language: Tuple[str, str], link: bool = True, event\_name="al\_change\_language")
+#### get\_language\_list\_dropdown\_item(language: Tuple[str, str], link: bool = True, event\_name="al\_change\_language") {#AssemblyLine.language.get\_language\_list\_dropdown\_item}
```python
def get_language_list_dropdown_item(language: Tuple[str, str],
@@ -103,9 +95,7 @@ given in the first part of the tuple.
- `str` - A string containing the HTML for a dropdown menu item for language selection.
-
-
-#### get\_language\_list(languages: Optional[List[Tuple[str, str]]] = None, current="", lang\_codes: Optional[List[str]] = None, languages\_path: Optional[str] = None, event\_name="al\_get\_language\_list\_change\_language")
+#### get\_language\_list(languages: Optional[List[Tuple[str, str]]] = None, current="", lang\_codes: Optional[List[str]] = None, languages\_path: Optional[str] = None, event\_name="al\_get\_language\_list\_change\_language") {#AssemblyLine.language.get\_language\_list}
```python
def get_language_list(languages: Optional[List[Tuple[str, str]]] = None,
@@ -134,9 +124,7 @@ tuples containing the language name and language code. This is deprecated and ma
A string containing the HTML for an unordered inline list of language selection.
-
-
-#### get\_language\_list\_item(language, link=True, event\_name="al\_change\_language")
+#### get\_language\_list\_item(language, link=True, event\_name="al\_change\_language") {#AssemblyLine.language.get\_language\_list\_item}
```python
def get_language_list_item(language,
diff --git a/docs/components/AssemblyLine/sessions.md b/docs/components/AssemblyLine/sessions.md
index 1e50687b0..1d0f125a2 100644
--- a/docs/components/AssemblyLine/sessions.md
+++ b/docs/components/AssemblyLine/sessions.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [AssemblyLine.sessions](#AssemblyLine.sessions)
+* AssemblyLine.sessions
* [is\_file\_like](#AssemblyLine.sessions.is_file_like)
* [set\_interview\_metadata](#AssemblyLine.sessions.set_interview_metadata)
* [get\_interview\_metadata](#AssemblyLine.sessions.get_interview_metadata)
@@ -35,9 +35,7 @@ sidebar_label: sessions
title: AssemblyLine.sessions
---
-
-
-#### is\_file\_like(obj: Any)
+#### is\_file\_like(obj: Any) {#AssemblyLine.sessions.is\_file\_like}
```python
def is_file_like(obj: Any) -> bool
@@ -54,9 +52,7 @@ Return True if the object is a file-like object.
- `bool` - True if the object is a file-like object.
-
-
-#### set\_interview\_metadata(filename: str, session\_id: str, data: Dict, metadata\_key\_name="metadata")
+#### set\_interview\_metadata(filename: str, session\_id: str, data: Dict, metadata\_key\_name="metadata") {#AssemblyLine.sessions.set\_interview\_metadata}
```python
def set_interview_metadata(filename: str,
@@ -80,9 +76,7 @@ Standardized metadata dictionary:
- `data` _Dict_ - The metadata to add
- `metadata_key_name` _str, optional_ - The name of the metadata key. Defaults to "metadata".
-
-
-#### get\_interview\_metadata(filename: str, session\_id: str, metadata\_key\_name: str = "metadata")
+#### get\_interview\_metadata(filename: str, session\_id: str, metadata\_key\_name: str = "metadata") {#AssemblyLine.sessions.get\_interview\_metadata}
```python
def get_interview_metadata(
@@ -105,9 +99,7 @@ We implement this with the docassemble jsonstorage table and a dedicated `tag` w
Dict[str, Any]: The metadata associated with the interview
-
-
-#### get\_saved\_interview\_list(filename: Optional[str] = al\_session\_store\_default\_filename, user\_id: Union[int, str, None] = None, metadata\_key\_name: str = "metadata", limit: int = 50, offset: int = 0, filename\_to\_exclude: str = "", exclude\_current\_filename: bool = True, exclude\_filenames: Optional[List[str]] = None, exclude\_newly\_started\_sessions: bool = False)
+#### get\_saved\_interview\_list(filename: Optional[str] = al\_session\_store\_default\_filename, user\_id: Union[int, str, None] = None, metadata\_key\_name: str = "metadata", limit: int = 50, offset: int = 0, filename\_to\_exclude: str = "", exclude\_current\_filename: bool = True, exclude\_filenames: Optional[List[str]] = None, exclude\_newly\_started\_sessions: bool = False) {#AssemblyLine.sessions.get\_saved\_interview\_list}
```python
def get_saved_interview_list(
@@ -150,9 +142,7 @@ an existing interview to the answer set.
List[Dict[str, Any]]: A list of saved sessions for the specified filename.
-
-
-#### find\_matching\_sessions(keyword: str, metadata\_column\_names: Optional[Union[Set[str], List[str]]] = None, filenames: Optional[Union[Set[str], List[str]]] = None, user\_id: Union[int, str, None] = None, metadata\_key\_name: str = "metadata", limit: int = 50, offset: int = 0, filename\_to\_exclude: str = "", exclude\_current\_filename: bool = True, exclude\_filenames: Optional[List[str]] = None, exclude\_newly\_started\_sessions: bool = False, global\_search\_allowed\_roles: Optional[Union[Set[str], List[str]]] = None, metadata\_filters: Optional[Dict[str, Tuple[Any, str, Optional[str]]]] = None)
+#### find\_matching\_sessions(keyword: str, metadata\_column\_names: Optional[Union[Set[str], List[str]]] = None, filenames: Optional[Union[Set[str], List[str]]] = None, user\_id: Union[int, str, None] = None, metadata\_key\_name: str = "metadata", limit: int = 50, offset: int = 0, filename\_to\_exclude: str = "", exclude\_current\_filename: bool = True, exclude\_filenames: Optional[List[str]] = None, exclude\_newly\_started\_sessions: bool = False, global\_search\_allowed\_roles: Optional[Union[Set[str], List[str]]] = None, metadata\_filters: Optional[Dict[str, Tuple[Any, str, Optional[str]]]] = None) {#AssemblyLine.sessions.find\_matching\_sessions}
```python
def find_matching_sessions(
@@ -221,9 +211,7 @@ The keyword search is case-insensitive and will match any part of the metadata c
- `\{"owner"` - ("samantha", "ILIKE", None), "age": (30, ">=", "int"), "status": ("%complete%", "LIKE", None)\}
-
-
-#### delete\_interview\_sessions(user\_id: Optional[int] = None, filename\_to\_exclude: str = al\_session\_store\_default\_filename, exclude\_current\_filename: bool = True)
+#### delete\_interview\_sessions(user\_id: Optional[int] = None, filename\_to\_exclude: str = al\_session\_store\_default\_filename, exclude\_current\_filename: bool = True) {#AssemblyLine.sessions.delete\_interview\_sessions}
```python
def delete_interview_sessions(
@@ -242,9 +230,7 @@ interview_list(action="delete_all") is both quite slow and because it
- `filename_to_exclude` _str, optional_ - The filename to exclude from the results. Defaults to al_session_store_default_filename.
- `exclude_current_filename` _bool, optional_ - Whether to exclude the current filename from the results. Defaults to True.
-
-
-#### interview\_list\_html(filename: str = al\_session\_store\_default\_filename, user\_id: Union[int, str, None] = None, metadata\_key\_name: str = "metadata", exclude\_newly\_started\_sessions=False, date\_label: str = word("Date"), details\_label: str = word("Details"), actions\_label: str = word("Actions"), delete\_label: str = word("Delete"), view\_label: str = word("View"), load\_action: str = "al\_sessions\_fast\_forward\_session", delete\_action: str = "al\_sessions\_delete\_session", view\_only: bool = False, limit: int = 50, offset: int = 0, display\_interview\_title: bool = True, show\_view\_button: bool = True, answers: Optional[List[Dict[str, Any]]] = None)
+#### interview\_list\_html(filename: str = al\_session\_store\_default\_filename, user\_id: Union[int, str, None] = None, metadata\_key\_name: str = "metadata", exclude\_newly\_started\_sessions=False, date\_label: str = word("Date"), details\_label: str = word("Details"), actions\_label: str = word("Actions"), delete\_label: str = word("Delete"), view\_label: str = word("View"), load\_action: str = "al\_sessions\_fast\_forward\_session", delete\_action: str = "al\_sessions\_delete\_session", view\_only: bool = False, limit: int = 50, offset: int = 0, display\_interview\_title: bool = True, show\_view\_button: bool = True, answers: Optional[List[Dict[str, Any]]] = None) {#AssemblyLine.sessions.interview\_list\_html}
```python
def interview_list_html(filename: str = al_session_store_default_filename,
@@ -302,9 +288,7 @@ itself in a way that adds additional steps)
- `str` - HTML-formatted table containing the list of saved answers.
-
-
-#### nice\_interview\_title(answer: Dict[str, str])
+#### nice\_interview\_title(answer: Dict[str, str]) {#AssemblyLine.sessions.nice\_interview\_title}
```python
def nice_interview_title(answer: Dict[str, str]) -> str
@@ -325,9 +309,7 @@ in descending priority order.
- `str` - The human readable interview title
-
-
-#### pascal\_to\_zwspace(text: str)
+#### pascal\_to\_zwspace(text: str) {#AssemblyLine.sessions.pascal\_to\_zwspace}
```python
def pascal_to_zwspace(text: str) -> str
@@ -345,9 +327,7 @@ with word breaks on small viewports.
- `str` - The text with zero-width spaces inserted
-
-
-#### nice\_interview\_subtitle(answer: Dict[str, str], exclude\_identical=True)
+#### nice\_interview\_subtitle(answer: Dict[str, str], exclude\_identical=True) {#AssemblyLine.sessions.nice\_interview\_subtitle}
```python
def nice_interview_subtitle(answer: Dict[str, str],
@@ -368,9 +348,7 @@ If exclude_identical, return empty string when title is the same as the subtitle
- `str` - The human readable interview subtitle
-
-
-#### radial\_progress(answer: Dict[str, Union[str, int]])
+#### radial\_progress(answer: Dict[str, Union[str, int]]) {#AssemblyLine.sessions.radial\_progress}
```python
def radial_progress(answer: Dict[str, Union[str, int]]) -> str
@@ -387,9 +365,7 @@ Return HTML for a radial progress bar, or the number of steps if progress isn
- `str` - the HTML as a string
-
-
-#### local\_date(utcstring: Optional[str])
+#### local\_date(utcstring: Optional[str]) {#AssemblyLine.sessions.local\_date}
```python
def local_date(utcstring: Optional[str]) -> DADateTime
@@ -406,9 +382,7 @@ Return a localized date from a UTC string.
- `DADateTime` - The localized date
-
-
-#### session\_list\_html(filename: Optional[str] = None, user\_id: Union[int, str, None] = None, metadata\_key\_name: str = "metadata", filename\_to\_exclude: str = al\_session\_store\_default\_filename, exclude\_current\_filename: bool = True, exclude\_filenames: Optional[List[str]] = None, exclude\_newly\_started\_sessions: bool = False, name\_label: str = word("Title"), date\_label: str = word("Date modified"), details\_label: str = word("Progress"), actions\_label: str = word("Actions"), delete\_label: str = word("Delete"), rename\_label: str = word("Rename"), rename\_action: str = "interview\_list\_rename\_action", delete\_action: str = "interview\_list\_delete\_session", copy\_action: str = "interview\_list\_copy\_action", clone\_label: str = word("Copy as answer set"), show\_title: bool = True, show\_copy\_button: bool = True, limit: int = 50, offset: int = 0, answers: Optional[List[Dict[str, Any]]] = None)
+#### session\_list\_html(filename: Optional[str] = None, user\_id: Union[int, str, None] = None, metadata\_key\_name: str = "metadata", filename\_to\_exclude: str = al\_session\_store\_default\_filename, exclude\_current\_filename: bool = True, exclude\_filenames: Optional[List[str]] = None, exclude\_newly\_started\_sessions: bool = False, name\_label: str = word("Title"), date\_label: str = word("Date modified"), details\_label: str = word("Progress"), actions\_label: str = word("Actions"), delete\_label: str = word("Delete"), rename\_label: str = word("Rename"), rename\_action: str = "interview\_list\_rename\_action", delete\_action: str = "interview\_list\_delete\_session", copy\_action: str = "interview\_list\_copy\_action", clone\_label: str = word("Copy as answer set"), show\_title: bool = True, show\_copy\_button: bool = True, limit: int = 50, offset: int = 0, answers: Optional[List[Dict[str, Any]]] = None) {#AssemblyLine.sessions.session\_list\_html}
```python
def session_list_html(
@@ -471,9 +445,7 @@ user sessions. The results exclude the answer set filename by default.
- `str` - HTML-formatted table containing the list of user sessions.
-
-
-#### rename\_interview\_answers(filename: str, session\_id: str, new\_name: str, metadata\_key\_name: str = "metadata")
+#### rename\_interview\_answers(filename: str, session\_id: str, new\_name: str, metadata\_key\_name: str = "metadata") {#AssemblyLine.sessions.rename\_interview\_answers}
```python
def rename_interview_answers(filename: str,
@@ -494,9 +466,7 @@ metadata that may be present.
If exception is raised in set_session_variables, this will silently fail but log the error.
-
-
-#### set\_current\_session\_metadata(data: Dict[str, Any], metadata\_key\_name: str = "metadata")
+#### set\_current\_session\_metadata(data: Dict[str, Any], metadata\_key\_name: str = "metadata") {#AssemblyLine.sessions.set\_current\_session\_metadata}
```python
def set_current_session_metadata(data: Dict[str, Any],
@@ -510,9 +480,7 @@ Set metadata for the current session, such as the title, in an unencrypted datab
- `data` _Dict[str, Any]_ - The metadata to set
- `metadata_key_name` _str, optional_ - The name of the metadata key. Defaults to "metadata".
-
-
-#### rename\_current\_session(new\_name: str, metadata\_key\_name: str = "metadata")
+#### rename\_current\_session(new\_name: str, metadata\_key\_name: str = "metadata") {#AssemblyLine.sessions.rename\_current\_session}
```python
def rename_current_session(new_name: str,
@@ -527,9 +495,7 @@ metadata that might be present.
- `new_name` _str_ - The new name to set for the interview
- `metadata_key_name` _str, optional_ - The name of the metadata key. Defaults to "metadata".
-
-
-#### save\_interview\_answers(filename: str = al\_session\_store\_default\_filename, variables\_to\_filter: Union[Set[str], List[str], None] = None, metadata: Optional[Dict] = None, metadata\_key\_name: str = "metadata", original\_interview\_filename=None, source\_filename=None, source\_session=None, additional\_variables\_to\_filter=None)
+#### save\_interview\_answers(filename: str = al\_session\_store\_default\_filename, variables\_to\_filter: Union[Set[str], List[str], None] = None, metadata: Optional[Dict] = None, metadata\_key\_name: str = "metadata", original\_interview\_filename=None, source\_filename=None, source\_session=None, additional\_variables\_to\_filter=None) {#AssemblyLine.sessions.save\_interview\_answers}
```python
def save_interview_answers(filename: str = al_session_store_default_filename,
@@ -561,9 +527,7 @@ Copies the answers from a given session into a new session with a specified inte
- `str` - ID of the new session.
-
-
-#### get\_filtered\_session\_variables(filename: Optional[str] = None, session\_id: Optional[str] = None, variables\_to\_filter: Optional[Union[Set[str], List[str]]] = None, additional\_variables\_to\_filter: Optional[Union[Set[str], List[str]]] = None)
+#### get\_filtered\_session\_variables(filename: Optional[str] = None, session\_id: Optional[str] = None, variables\_to\_filter: Optional[Union[Set[str], List[str]]] = None, additional\_variables\_to\_filter: Optional[Union[Set[str], List[str]]] = None) {#AssemblyLine.sessions.get\_filtered\_session\_variables}
```python
def get_filtered_session_variables(
@@ -590,9 +554,7 @@ from the current interview.
Dict[str, Any]: A dictionary of filtered session variables.
-
-
-#### get\_filtered\_session\_variables\_string(filename: Optional[str] = None, session\_id: Optional[str] = None, variables\_to\_filter: Union[Set[str], List[str], None] = None, additional\_variables\_to\_filter: Optional[Union[Set[str], List[str]]] = None, indent: int = 4)
+#### get\_filtered\_session\_variables\_string(filename: Optional[str] = None, session\_id: Optional[str] = None, variables\_to\_filter: Union[Set[str], List[str], None] = None, additional\_variables\_to\_filter: Optional[Union[Set[str], List[str]]] = None, indent: int = 4) {#AssemblyLine.sessions.get\_filtered\_session\_variables\_string}
```python
def get_filtered_session_variables_string(
@@ -620,9 +582,7 @@ If no filename and session ID are provided, the current session's variables
- `str` - A JSON-formatted string of filtered session variables.
-
-
-#### load\_interview\_answers(old\_interview\_filename: str, old\_session\_id: str, new\_session: bool = False, new\_interview\_filename: Optional[str] = None, variables\_to\_filter: Optional[List[str]] = None, additional\_variables\_to\_filter: Optional[List[str]] = None)
+#### load\_interview\_answers(old\_interview\_filename: str, old\_session\_id: str, new\_session: bool = False, new\_interview\_filename: Optional[str] = None, variables\_to\_filter: Optional[List[str]] = None, additional\_variables\_to\_filter: Optional[List[str]] = None) {#AssemblyLine.sessions.load\_interview\_answers}
```python
def load_interview_answers(
@@ -653,9 +613,7 @@ the active session. This function is primarily used for migrating answers betwee
Optional[Union[int, bool]]: ID of the newly created session if `new_session` is True, otherwise True or False based on success.
-
-
-#### load\_interview\_json(json\_string: str, new\_session: bool = False, new\_interview\_filename: Optional[str] = None, variables\_to\_filter: Optional[List[str]] = None)
+#### load\_interview\_json(json\_string: str, new\_session: bool = False, new\_interview\_filename: Optional[str] = None, variables\_to\_filter: Optional[List[str]] = None) {#AssemblyLine.sessions.load\_interview\_json}
```python
def load_interview_json(
@@ -681,9 +639,7 @@ If the `new_session` argument is not set, the JSON answers will be loaded into t
Optional[Union[int, bool]]: ID of the newly created session if `new_session` is True, otherwise True or False based on success.
-
-
-#### export\_interview\_variables(filename: Optional[str] = None, session\_id: Optional[str] = None, variables\_to\_filter: Union[Set, List[str], None] = None, output: DAFile = None, additional\_variables\_to\_filter: Union[Set, List[str], None] = None)
+#### export\_interview\_variables(filename: Optional[str] = None, session\_id: Optional[str] = None, variables\_to\_filter: Union[Set, List[str], None] = None, output: DAFile = None, additional\_variables\_to\_filter: Union[Set, List[str], None] = None) {#AssemblyLine.sessions.export\_interview\_variables}
```python
def export_interview_variables(
@@ -712,9 +668,7 @@ The resultant output is compatible with `set_session_variables(process_objects=T
- `DAFile` - DAFile with a JSON representation of the answers
-
-
-#### is\_valid\_json(json\_string: str)
+#### is\_valid\_json(json\_string: str) {#AssemblyLine.sessions.is\_valid\_json}
```python
def is_valid_json(json_string: str) -> bool
@@ -731,9 +685,7 @@ Checks if the provided string is a valid JSON-formatted string.
- `bool` - True if the string is a valid JSON, otherwise it raises a validation error and returns False.
-
-
-#### config\_with\_language\_fallback(config\_key: str, top\_level\_config\_key: Optional[str] = None)
+#### config\_with\_language\_fallback(config\_key: str, top\_level\_config\_key: Optional[str] = None) {#AssemblyLine.sessions.config\_with\_language\_fallback}
```python
def config_with_language_fallback(
@@ -766,9 +718,7 @@ short title: My forms
- `str` - The value of the config key, or the alternative key, or None.
-
-
-#### get\_filenames\_having\_sessions(user\_id: Optional[Union[int, str]] = None, global\_search\_allowed\_roles: Optional[Union[Set[str], List[str]]] = None)
+#### get\_filenames\_having\_sessions(user\_id: Optional[Union[int, str]] = None, global\_search\_allowed\_roles: Optional[Union[Set[str], List[str]]] = None) {#AssemblyLine.sessions.get\_filenames\_having\_sessions}
```python
def get_filenames_having_sessions(
@@ -790,9 +740,7 @@ to help show the user a good list of interviews to filter search results.
- `List[str]` - List of filenames that have sessions saved for the user.
-
-
-#### get\_combined\_filename\_list(user\_id: Optional[Union[int, str]] = None, global\_search\_allowed\_roles: Optional[Union[Set[str], List[str]]] = None)
+#### get\_combined\_filename\_list(user\_id: Optional[Union[int, str]] = None, global\_search\_allowed\_roles: Optional[Union[Set[str], List[str]]] = None) {#AssemblyLine.sessions.get\_combined\_filename\_list}
```python
def get_combined_filename_list(
@@ -818,9 +766,7 @@ radio button and dropdown list expect.
List[Dict[str, str]]: List of filenames that have sessions saved for the user.
-
-
-#### update\_session\_metadata(filename: str, session\_id: str, data: Dict[str, Any], metadata\_key\_name: str = "metadata")
+#### update\_session\_metadata(filename: str, session\_id: str, data: Dict[str, Any], metadata\_key\_name: str = "metadata") {#AssemblyLine.sessions.update\_session\_metadata}
```python
def update_session_metadata(filename: str,
@@ -839,9 +785,7 @@ Upsert session metadata into jsonstorage using a PostgreSQL advisory lock
- `data` - A dict of metadata to add or update.
- `metadata_key_name` - The tag for the metadata in jsonstorage. Defaults to "metadata".
-
-
-#### update\_current\_session\_metadata(data: Dict[str, Any], metadata\_key\_name: str = "metadata")
+#### update\_current\_session\_metadata(data: Dict[str, Any], metadata\_key\_name: str = "metadata") {#AssemblyLine.sessions.update\_current\_session\_metadata}
```python
def update_current_session_metadata(data: Dict[str, Any],
diff --git a/docs/components/AssemblyLine/sign.md b/docs/components/AssemblyLine/sign.md
index 1d2e98e14..949776f37 100644
--- a/docs/components/AssemblyLine/sign.md
+++ b/docs/components/AssemblyLine/sign.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [AssemblyLine.sign](#AssemblyLine.sign)
+* AssemblyLine.sign
* [find\_font\_file\_by\_name](#AssemblyLine.sign.find_font_file_by_name)
* [get\_font](#AssemblyLine.sign.get_font)
* [create\_signature](#AssemblyLine.sign.create_signature)
@@ -10,9 +10,7 @@ sidebar_label: sign
title: AssemblyLine.sign
---
-
-
-#### find\_font\_file\_by\_name(font\_name: str, search\_dirs: List[str])
+#### find\_font\_file\_by\_name(font\_name: str, search\_dirs: List[str]) {#AssemblyLine.sign.find\_font\_file\_by\_name}
```python
def find_font_file_by_name(font_name: str,
@@ -35,9 +33,7 @@ matches the font name (case-insensitive).
- `Optional[str]` - The full path to the font file if found; otherwise, None.
-
-
-#### get\_font(font\_name: Optional[str] = None, font\_size: int = 48)
+#### get\_font(font\_name: Optional[str] = None, font\_size: int = 48) {#AssemblyLine.sign.get\_font}
```python
def get_font(
@@ -63,9 +59,7 @@ if necessary. If no font is found, the function falls back to the default Pillow
- `ImageFont.ImageFont` - The loaded font instance.
-
-
-#### create\_signature(name: str, output\_file: str, signature\_prefix: str = "/s/", font\_name: Optional[str] = None, font\_size: int = 48)
+#### create\_signature(name: str, output\_file: str, signature\_prefix: str = "/s/", font\_name: Optional[str] = None, font\_size: int = 48) {#AssemblyLine.sign.create\_signature}
```python
def create_signature(name: str,
diff --git a/docs/components/EFSPIntegration/conversions.md b/docs/components/EFSPIntegration/conversions.md
index 9e2bd902b..65ac30fb6 100644
--- a/docs/components/EFSPIntegration/conversions.md
+++ b/docs/components/EFSPIntegration/conversions.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [EFSPIntegration.conversions](#EFSPIntegration.conversions)
+* EFSPIntegration.conversions
* [error\_notification](#EFSPIntegration.conversions.error_notification)
* [log\_error\_and\_notify](#EFSPIntegration.conversions.log_error_and_notify)
* [convert\_court\_to\_id](#EFSPIntegration.conversions.convert_court_to_id)
@@ -25,9 +25,7 @@ title: EFSPIntegration.conversions
Functions that help convert the JSON-ized XML from the proxy server into usable information.
-
-
-#### error\_notification(err, message=None, trace=None, referer=None, the\_vars=None)
+#### error\_notification(err, message=None, trace=None, referer=None, the\_vars=None) {#EFSPIntegration.conversions.error\_notification}
```python
def error_notification(err,
@@ -43,9 +41,7 @@ Copied from docassemble.webapp.server.error_notification, since:
Some slight modifications to work without server backends
-
-
-#### log\_error\_and\_notify(context: str, resp: Optional[ApiResponse] = None)
+#### log\_error\_and\_notify(context: str, resp: Optional[ApiResponse] = None) {#EFSPIntegration.conversions.log\_error\_and\_notify}
```python
def log_error_and_notify(context: str, resp: Optional[ApiResponse] = None)
@@ -54,9 +50,7 @@ def log_error_and_notify(context: str, resp: Optional[ApiResponse] = None)
Similar to docassemble.webapp.server.error_notification, which will send an email to
the `error_notification_email` in the config.
-
-
-#### convert\_court\_to\_id(trial\_court)
+#### convert\_court\_to\_id(trial\_court) {#EFSPIntegration.conversions.convert\_court\_to\_id}
```python
def convert_court_to_id(trial_court) -> str
@@ -78,9 +72,7 @@ your court object use the "tyler_court_code" attribute though.
the string that should be the Tyler EFM court id, i.e. `adams` or `peoria:cr`
-
-
-#### choices\_and\_map(codes\_list: List[Dict[str, Any]], display: str = None, backing: str = None)
+#### choices\_and\_map(codes\_list: List[Dict[str, Any]], display: str = None, backing: str = None) {#EFSPIntegration.conversions.choices\_and\_map}
```python
def choices_and_map(codes_list: List[Dict[str, Any]],
@@ -105,9 +97,7 @@ to the full code object
second, a map of each code, from the backing key to the full code element. Useful for getting
all of the information about a code after a user has selected it.
-
-
-#### pretty\_display(data, tab\_depth=0, skip\_xml=True, item\_name=None)
+#### pretty\_display(data, tab\_depth=0, skip\_xml=True, item\_name=None) {#EFSPIntegration.conversions.pretty\_display}
```python
def pretty_display(data, tab_depth=0, skip_xml=True, item_name=None) -> str
@@ -129,20 +119,16 @@ Recursive, for subsequent calls `tab_depth` increases.
The string of markdown text that displays info about the given JSON structure
-
-
-#### debug\_display(resp: ApiResponse)
+#### debug\_display(resp: ApiResponse) {#EFSPIntegration.conversions.debug\_display}
```python
def debug_display(resp: ApiResponse) -> str
```
Returns a string with either the error of the response,
-or it's data run through [pretty_display](#pretty_display)
+or it's data run through [pretty_display](#EFSPIntegration.conversions.pretty_display)
-
-
-#### tyler\_daterep\_to\_datetime(tyler\_daterep: Mapping)
+#### tyler\_daterep\_to\_datetime(tyler\_daterep: Mapping) {#EFSPIntegration.conversions.tyler\_daterep\_to\_datetime}
```python
def tyler_daterep_to_datetime(tyler_daterep: Mapping) -> DADateTime
@@ -151,9 +137,7 @@ def tyler_daterep_to_datetime(tyler_daterep: Mapping) -> DADateTime
Takes an jsonized-XML object of "\{http://niem.gov/niem/niem-core/2.0\}ActivityDate,
returns the datetime it represents.
-
-
-#### tyler\_timestamp\_to\_datetime(timestamp\_ms: int)
+#### tyler\_timestamp\_to\_datetime(timestamp\_ms: int) {#EFSPIntegration.conversions.tyler\_timestamp\_to\_datetime}
```python
def tyler_timestamp_to_datetime(timestamp_ms: int) -> DADateTime
@@ -161,9 +145,7 @@ def tyler_timestamp_to_datetime(timestamp_ms: int) -> DADateTime
Given a timestamp in milliseconds from epoch (in UTC), make a datetime from it
-
-
-#### validate\_tyler\_regex(data\_field: Mapping)
+#### validate\_tyler\_regex(data\_field: Mapping) {#EFSPIntegration.conversions.validate\_tyler\_regex}
```python
def validate_tyler_regex(data_field: Mapping) -> Callable[[str], Any]
@@ -172,9 +154,7 @@ def validate_tyler_regex(data_field: Mapping) -> Callable[[str], Any]
Return a function that validates a given input with the provided regex,
suitable for use with docassemble's `validate:` question modifier
-
-
-#### parse\_service\_contacts(service\_list)
+#### parse\_service\_contacts(service\_list) {#EFSPIntegration.conversions.parse\_service\_contacts}
```python
def parse_service_contacts(service_list)
@@ -184,9 +164,7 @@ We'll take both Tyler service contact lists and Niem service contact lists.
Tyler's are just `\{"firstName": "Bob", "middleName": "P", ..., "serviceContactId": "abcrunh-13..."
Niem's are more complicated
-
-
-#### parse\_case\_info(proxy\_conn: ProxyConnection, new\_case: DAObject, entry: dict, court\_id: str, \*, fetch: bool = True, roles: dict = None)
+#### parse\_case\_info(proxy\_conn: ProxyConnection, new\_case: DAObject, entry: dict, court\_id: str, \*, fetch: bool = True, roles: dict = None) {#EFSPIntegration.conversions.parse\_case\_info}
```python
def parse_case_info(proxy_conn: ProxyConnection,
@@ -211,9 +189,7 @@ Given sparse information about a case, gets the full details about it
- `roles` - a dictionary of the party type codes to the party type name.
Used so we can filter and sort participants later
-
-
-#### fetch\_case\_info(proxy\_conn: ProxyConnection, new\_case: DAObject, roles: Optional[dict] = None)
+#### fetch\_case\_info(proxy\_conn: ProxyConnection, new\_case: DAObject, roles: Optional[dict] = None) {#EFSPIntegration.conversions.fetch\_case\_info}
```python
def fetch_case_info(proxy_conn: ProxyConnection,
@@ -231,9 +207,7 @@ Fills in these attributes with the full case details:
* date
* participants
-
-
-#### filter\_payment\_accounts(account\_list, allowable\_card\_types: List)
+#### filter\_payment\_accounts(account\_list, allowable\_card\_types: List) {#EFSPIntegration.conversions.filter\_payment\_accounts}
```python
def filter_payment_accounts(account_list, allowable_card_types: List) -> List
@@ -247,16 +221,14 @@ accepted at a particular court.
account_list:
- `allowable_card_types` - a list of the accepted card types at a court, usually
from the 'allowablecardtypes' dict entry in
- [get_full_court_info](interview_logic#get_full_court_info)'s response
+ [get_full_court_info](interview_logic#EFSPIntegration.interview_logic.get_full_court_info)'s response
**Returns**:
the list of payment account choices that are valid for a particular court
-
-
-#### payment\_account\_labels(resp: ApiResponse)
+#### payment\_account\_labels(resp: ApiResponse) {#EFSPIntegration.conversions.payment\_account\_labels}
```python
def payment_account_labels(resp: ApiResponse) -> Optional[List[Dict]]
@@ -264,22 +236,18 @@ def payment_account_labels(resp: ApiResponse) -> Optional[List[Dict]]
Returns all payment accounts as choices, without filters.
-
-
-#### filing\_id\_and\_label(case: Mapping, style: str = "FILING\_ID")
+#### filing\_id\_and\_label(case: Mapping, style: str = "FILING\_ID") {#EFSPIntegration.conversions.filing\_id\_and\_label}
```python
def filing_id_and_label(case: Mapping,
style: str = "FILING_ID") -> Dict[str, str]
```
-Converts a raw case information from [proxy_conn.get_filing_list()](py_efsp_client#get_filing_list)
+Converts a raw case information from [proxy_conn.get_filing_list()](py_efsp_client#EFSPIntegration.py_efsp_client.EfspConnection.get_filing_list)
into a key-value pair, where the key is the filing id and the value is the user-facing label
for that filing.
-
-
-#### get\_tyler\_roles(proxy\_conn: ProxyConnection, login\_data: Optional[Mapping], user\_details: Optional[ApiResponse] = None)
+#### get\_tyler\_roles(proxy\_conn: ProxyConnection, login\_data: Optional[Mapping], user\_details: Optional[ApiResponse] = None) {#EFSPIntegration.conversions.get\_tyler\_roles}
```python
def get_tyler_roles(
diff --git a/docs/components/EFSPIntegration/efm_client.md b/docs/components/EFSPIntegration/efm_client.md
index 8899e174f..e2a6a3ebb 100644
--- a/docs/components/EFSPIntegration/efm_client.md
+++ b/docs/components/EFSPIntegration/efm_client.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [EFSPIntegration.efm\_client](#EFSPIntegration.efm_client)
+* EFSPIntegration.efm\_client
* [ProxyConnection](#EFSPIntegration.efm_client.ProxyConnection)
* [\_\_init\_\_](#EFSPIntegration.efm_client.ProxyConnection.__init__)
* [authenticate\_user](#EFSPIntegration.efm_client.ProxyConnection.authenticate_user)
@@ -13,9 +13,7 @@ sidebar_label: efm_client
title: EFSPIntegration.efm_client
---
-
-
-## ProxyConnection Objects
+## ProxyConnection Objects {#EFSPIntegration.efm\_client.ProxyConnection}
```python
class ProxyConnection(EfspConnection)
@@ -23,12 +21,10 @@ class ProxyConnection(EfspConnection)
The main class you use to communicate with the E-file proxy server from docassemble.
-Many methods are unchanged from the parent class, [EfspConnection](py_efsp_client#EfspConnection),
+Many methods are unchanged from the parent class, [EfspConnection](py_efsp_client#EFSPIntegration.py_efsp_client.EfspConnection),
and are documented there.
-
-
-#### \_\_init\_\_(\*, url: str = None, api\_key: str = None, credentials\_code\_block: str = "tyler\_login", default\_jurisdiction: str = None)
+#### \_\_init\_\_(\*, url: str = None, api\_key: str = None, credentials\_code\_block: str = "tyler\_login", default\_jurisdiction: str = None) {#EFSPIntegration.efm\_client.ProxyConnection.\_\_init\_\_}
```python
def __init__(*,
@@ -41,9 +37,7 @@ def __init__(*,
Creates the connection. Tries to get params from docassemble's config, but can
be overriden with parameters to __init__.
-
-
-#### authenticate\_user(tyler\_email: str = None, tyler\_password: str = None, jeffnet\_key: str = None, \*, jurisdiction: str = None)
+#### authenticate\_user(tyler\_email: str = None, tyler\_password: str = None, jeffnet\_key: str = None, \*, jurisdiction: str = None) {#EFSPIntegration.efm\_client.ProxyConnection.authenticate\_user}
```python
def authenticate_user(tyler_email: str = None,
@@ -58,9 +52,7 @@ tyler_email (str)
tyler_password (str)
jeffnet_key (str)
-
-
-#### register\_user(person: Union[Individual, dict], registration\_type: str, \*, password: str = None, firm\_name\_or\_id: str = None)
+#### register\_user(person: Union[Individual, dict], registration\_type: str, \*, password: str = None, firm\_name\_or\_id: str = None) {#EFSPIntegration.efm\_client.ProxyConnection.register\_user}
```python
def register_user(person: Union[Individual, dict],
@@ -74,9 +66,7 @@ registration_type needs to be INDIVIDUAL, FIRM_ADMINISTRATOR, or FIRM_ADMIN_NEW_
If registration_type is INDIVIDUAL or FIRM_ADMINISTRATOR, you need a password.
If it's FIRM_ADMINISTRATOR or FIRM_ADMIN_NEW_MEMBER, you need a firm_name_or_id
-
-
-#### get\_service\_types(court\_id: str, court\_bundle: Union[ALDocumentBundle, dict] = None)
+#### get\_service\_types(court\_id: str, court\_bundle: Union[ALDocumentBundle, dict] = None) {#EFSPIntegration.efm\_client.ProxyConnection.get\_service\_types}
```python
def get_service_types(
@@ -86,9 +76,7 @@ def get_service_types(
Checks the court info: if it has conditional service types, call a special API with all filing info so far to get service types
-
-
-#### serialize\_person(person: Union[Person, Individual])
+#### serialize\_person(person: Union[Person, Individual]) {#EFSPIntegration.efm\_client.serialize\_person}
```python
def serialize_person(person: Union[Person, Individual]) -> Dict
diff --git a/docs/components/EFSPIntegration/interview_logic.md b/docs/components/EFSPIntegration/interview_logic.md
index 4c76b1e76..2dc9676c2 100644
--- a/docs/components/EFSPIntegration/interview_logic.md
+++ b/docs/components/EFSPIntegration/interview_logic.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [EFSPIntegration.interview\_logic](#EFSPIntegration.interview_logic)
+* EFSPIntegration.interview\_logic
* [EFCaseSearch](#EFSPIntegration.interview_logic.EFCaseSearch)
* [search\_went\_wrong](#EFSPIntegration.interview_logic.EFCaseSearch.search_went_wrong)
* [get\_lookup\_choices](#EFSPIntegration.interview_logic.EFCaseSearch.get_lookup_choices)
@@ -21,9 +21,7 @@ title: EFSPIntegration.interview_logic
A group of methods that were code blocks in various parts of the EFSP
package, but for better python tooling support, were moved here.
-
-
-## EFCaseSearch Objects
+## EFCaseSearch Objects {#EFSPIntegration.interview\_logic.EFCaseSearch}
```python
class EFCaseSearch(DAObject)
@@ -31,9 +29,7 @@ class EFCaseSearch(DAObject)
A data-class that has holds all of the information and state for a single case search
-
-
-#### search\_went\_wrong()
+#### search\_went\_wrong() {#EFSPIntegration.interview\_logic.EFCaseSearch.search\_went\_wrong}
```python
def search_went_wrong() -> bool
@@ -41,9 +37,7 @@ def search_went_wrong() -> bool
Returns true if something errored during the case search process
-
-
-#### get\_lookup\_choices(can\_file\_non\_indexed\_case: bool)
+#### get\_lookup\_choices(can\_file\_non\_indexed\_case: bool) {#EFSPIntegration.interview\_logic.EFCaseSearch.get\_lookup\_choices}
```python
def get_lookup_choices(
@@ -58,9 +52,7 @@ Not passed as direct arguments, but the object attributes `party_search_choice`,
`docket_lookup_choice`, and `non_indexed_choice` are the user-facing labels
for each choice.
-
-
-#### num\_case\_choices()
+#### num\_case\_choices() {#EFSPIntegration.interview\_logic.num\_case\_choices}
```python
def num_case_choices() -> int
@@ -69,9 +61,7 @@ def num_case_choices() -> int
The number of cases that someone should have to choose between if there are too many.
Mostly to limit the amount of up-front waiting someone will have to do.
-
-
-#### search\_case\_by\_name(\*, proxy\_conn, var\_name: str = None, court\_id: str, somebody, filter\_fn: Callable[[Any], bool], roles=None)
+#### search\_case\_by\_name(\*, proxy\_conn, var\_name: str = None, court\_id: str, somebody, filter\_fn: Callable[[Any], bool], roles=None) {#EFSPIntegration.interview\_logic.search\_case\_by\_name}
```python
def search_case_by_name(*,
@@ -86,9 +76,7 @@ def search_case_by_name(*,
Searches for cases by party name. If there are more than 10 cases found, we don't
add all of the detailed information about the case, just for the first few cases
-
-
-#### shift\_case\_select\_window(proxy\_conn, found\_cases: DAList, \*, direction: str, start\_idx: int, end\_idx: int, roles: dict = None)
+#### shift\_case\_select\_window(proxy\_conn, found\_cases: DAList, \*, direction: str, start\_idx: int, end\_idx: int, roles: dict = None) {#EFSPIntegration.interview\_logic.shift\_case\_select\_window}
```python
def shift_case_select_window(proxy_conn,
@@ -103,9 +91,7 @@ def shift_case_select_window(proxy_conn,
Specifically used in case_search.yml, with an action to only fetch a detailed information
for a few cases at a time
-
-
-#### get\_full\_court\_info(proxy\_conn, court\_id: str)
+#### get\_full\_court\_info(proxy\_conn, court\_id: str) {#EFSPIntegration.interview\_logic.get\_full\_court\_info}
```python
def get_full_court_info(proxy_conn, court_id: str) -> Dict
@@ -113,9 +99,7 @@ def get_full_court_info(proxy_conn, court_id: str) -> Dict
Gets all of the information about the court from the id
-
-
-#### get\_max\_allowed\_sizes(proxy\_conn, court\_id: str)
+#### get\_max\_allowed\_sizes(proxy\_conn, court\_id: str) {#EFSPIntegration.interview\_logic.get\_max\_allowed\_sizes}
```python
def get_max_allowed_sizes(proxy_conn,
@@ -124,9 +108,7 @@ def get_max_allowed_sizes(proxy_conn,
Returns attachment max size, then message max size
-
-
-#### make\_filter(search: Union[Callable[..., bool], SearchType, None])
+#### make\_filter(search: Union[Callable[..., bool], SearchType, None]) {#EFSPIntegration.interview\_logic.make\_filter}
```python
def make_filter(
@@ -140,9 +122,7 @@ Necessary because docassemble doesn't store lambdas and functions well in
interview dicts, so the filters need to be set as primitive types and kept
that way until the search actually happens (in filter_codes).
-
-
-#### filter\_codes(options: Iterable, filters: Iterable[Union[Callable[..., bool], SearchType]], default: str, exclude: Union[Callable[..., bool], SearchType, None] = None)
+#### filter\_codes(options: Iterable, filters: Iterable[Union[Callable[..., bool], SearchType]], default: str, exclude: Union[Callable[..., bool], SearchType, None] = None) {#EFSPIntegration.interview\_logic.filter\_codes}
```python
def filter_codes(
@@ -156,9 +136,7 @@ def filter_codes(
Given a list of filter functions from most specific to least specific,
(if true, use that code), filters a total list of codes. If any codes match the exclude filter, won't use them.
-
-
-#### get\_available\_efile\_courts(proxy\_conn)
+#### get\_available\_efile\_courts(proxy\_conn) {#EFSPIntegration.interview\_logic.get\_available\_efile\_courts}
```python
def get_available_efile_courts(proxy_conn) -> list
diff --git a/docs/components/EFSPIntegration/py_efsp_client.md b/docs/components/EFSPIntegration/py_efsp_client.md
index 5559030a2..392c3b2e9 100644
--- a/docs/components/EFSPIntegration/py_efsp_client.md
+++ b/docs/components/EFSPIntegration/py_efsp_client.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [EFSPIntegration.py\_efsp\_client](#EFSPIntegration.py_efsp_client)
+* EFSPIntegration.py\_efsp\_client
* [EfspConnection](#EFSPIntegration.py_efsp_client.EfspConnection)
* [\_\_init\_\_](#EFSPIntegration.py_efsp_client.EfspConnection.__init__)
* [authenticate\_user](#EFSPIntegration.py_efsp_client.EfspConnection.authenticate_user)
@@ -25,9 +25,7 @@ The base python client used to communicate with the E-file proxy server.
Doesn't include anything from docassemble, and can be used without having it installed.
-
-
-## EfspConnection Objects
+## EfspConnection Objects {#EFSPIntegration.py\_efsp\_client.EfspConnection}
```python
class EfspConnection()
@@ -35,9 +33,7 @@ class EfspConnection()
A python client that communicates with the E-file proxy server.
-
-
-#### \_\_init\_\_(\*, url: str, api\_key: str, default\_jurisdiction: str = None)
+#### \_\_init\_\_(\*, url: str, api\_key: str, default\_jurisdiction: str = None) {#EFSPIntegration.py\_efsp\_client.EfspConnection.\_\_init\_\_}
```python
def __init__(*, url: str, api_key: str, default_jurisdiction: str = None)
@@ -49,9 +45,7 @@ def __init__(*, url: str, api_key: str, default_jurisdiction: str = None)
api_key (str)
default_jurisdiction (str)
-
-
-#### authenticate\_user(\*, tyler\_email: Optional[str] = None, tyler\_password: Optional[str] = None, jeffnet\_key: Optional[str] = None, jurisdiction: str = None)
+#### authenticate\_user(\*, tyler\_email: Optional[str] = None, tyler\_password: Optional[str] = None, jeffnet\_key: Optional[str] = None, jurisdiction: str = None) {#EFSPIntegration.py\_efsp\_client.EfspConnection.authenticate\_user}
```python
def authenticate_user(*,
@@ -63,9 +57,7 @@ def authenticate_user(*,
Authenticates the user with the EFM server (not the E-file proxy).
-
-
-#### register\_user(person: dict, registration\_type: str, \*, password: str = None, firm\_name\_or\_id: str = None)
+#### register\_user(person: dict, registration\_type: str, \*, password: str = None, firm\_name\_or\_id: str = None) {#EFSPIntegration.py\_efsp\_client.EfspConnection.register\_user}
```python
def register_user(person: dict,
@@ -79,9 +71,7 @@ registration_type needs to be INDIVIDUAL, FIRM_ADMINISTRATOR, or FIRM_ADMIN_NEW_
If registration_type is INDIVIDUAL or FIRM_ADMINISTRATOR, you need a password.
If it's FIRM_ADMINISTRATOR or FIRM_ADMIN_NEW_MEMBER, you need a firm_name_or_id
-
-
-#### get\_password\_rules()
+#### get\_password\_rules() {#EFSPIntegration.py\_efsp\_client.EfspConnection.get\_password\_rules}
```python
def get_password_rules() -> ApiResponse
@@ -91,9 +81,7 @@ Password rules are stored in the global court, id 0.
TODO: They're in other courts too, including 1. Could they ever be different?
-
-
-#### get\_notification\_options()
+#### get\_notification\_options() {#EFSPIntegration.py\_efsp\_client.EfspConnection.get\_notification\_options}
```python
def get_notification_options() -> ApiResponse
@@ -101,9 +89,7 @@ def get_notification_options() -> ApiResponse
AKA NotificationPreferencesList
-
-
-#### get\_firm()
+#### get\_firm() {#EFSPIntegration.py\_efsp\_client.EfspConnection.get\_firm}
```python
def get_firm() -> ApiResponse
@@ -112,9 +98,7 @@ def get_firm() -> ApiResponse
Gets info about the "firm" for an associated user. If a user is a pro-se, this
contains their address information.
-
-
-#### update\_firm(firm: dict)
+#### update\_firm(firm: dict) {#EFSPIntegration.py\_efsp\_client.EfspConnection.update\_firm}
```python
def update_firm(firm: dict) -> ApiResponse
@@ -127,9 +111,7 @@ firm should have the below keys:
* phoneNumber
* email
-
-
-#### get\_courts(fileable\_only: bool = False, with\_names: bool = False)
+#### get\_courts(fileable\_only: bool = False, with\_names: bool = False) {#EFSPIntegration.py\_efsp\_client.EfspConnection.get\_courts}
```python
def get_courts(fileable_only: bool = False,
@@ -138,9 +120,7 @@ def get_courts(fileable_only: bool = False,
Gets the list of courts.
-
-
-#### get\_court(court\_id: str)
+#### get\_court(court\_id: str) {#EFSPIntegration.py\_efsp\_client.EfspConnection.get\_court}
```python
def get_court(court_id: str) -> ApiResponse
@@ -148,20 +128,16 @@ def get_court(court_id: str) -> ApiResponse
Gets codes for a specific court
-
-
-#### get\_court\_list()
+#### get\_court\_list() {#EFSPIntegration.py\_efsp\_client.EfspConnection.get\_court\_list}
```python
def get_court_list() -> ApiResponse
```
Gets a list of all of the courts that you can file into. Slightly more limited than
-[get_courts](#get_courts)
+[get_courts](#EFSPIntegration.py_efsp_client.EfspConnection.get_courts)
-
-
-#### get\_filing\_list(court\_id: str, user\_id: str = None, start\_date: datetime = None, before\_date: datetime = None)
+#### get\_filing\_list(court\_id: str, user\_id: str = None, start\_date: datetime = None, before\_date: datetime = None) {#EFSPIntegration.py\_efsp\_client.EfspConnection.get\_filing\_list}
```python
def get_filing_list(court_id: str,
@@ -172,9 +148,7 @@ def get_filing_list(court_id: str,
Returns a list of filings that a particular user has made with a court.
-
-
-#### get\_service\_types(court\_id: str, all\_vars: dict = None)
+#### get\_service\_types(court\_id: str, all\_vars: dict = None) {#EFSPIntegration.py\_efsp\_client.EfspConnection.get\_service\_types}
```python
def get_service_types(court_id: str, all_vars: dict = None) -> ApiResponse
@@ -182,9 +156,7 @@ def get_service_types(court_id: str, all_vars: dict = None) -> ApiResponse
Checks the court info: if it has conditional service types, call a special API with all filing info so far to get service types
-
-
-#### get\_cases\_raw(court\_id: str, \*, person\_name: dict = None, business\_name: str = None, docket\_number: str = None)
+#### get\_cases\_raw(court\_id: str, \*, person\_name: dict = None, business\_name: str = None, docket\_number: str = None) {#EFSPIntegration.py\_efsp\_client.EfspConnection.get\_cases\_raw}
```python
def get_cases_raw(court_id: str,
diff --git a/docs/components/FormFyxer/docx_wrangling.md b/docs/components/FormFyxer/docx_wrangling.md
index a444a2602..9123134d2 100644
--- a/docs/components/FormFyxer/docx_wrangling.md
+++ b/docs/components/FormFyxer/docx_wrangling.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [formfyxer.docx\_wrangling](#formfyxer.docx_wrangling)
+* formfyxer.docx\_wrangling
* [update\_docx](#formfyxer.docx_wrangling.update_docx)
* [get\_docx\_repr](#formfyxer.docx_wrangling.get_docx_repr)
* [get\_labeled\_docx\_runs](#formfyxer.docx_wrangling.get_labeled_docx_runs)
@@ -13,9 +13,7 @@ sidebar_label: docx_wrangling
title: formfyxer.docx_wrangling
---
-
-
-#### update\_docx(document: Union[docx.document.Document, str], modified\_runs: List[Tuple[int, int, str, int]])
+#### update\_docx(document: Union[docx.document.Document, str], modified\_runs: List[Tuple[int, int, str, int]]) {#formfyxer.docx\_wrangling.update\_docx}
```python
def update_docx(
@@ -43,9 +41,7 @@ Take a careful look at the output document to make sure it is still correct.
The modified document.
-
-
-#### get\_docx\_repr(docx\_path: str, paragraph\_start: int = 0, paragraph\_end: Optional[int] = None)
+#### get\_docx\_repr(docx\_path: str, paragraph\_start: int = 0, paragraph\_end: Optional[int] = None) {#formfyxer.docx\_wrangling.get\_docx\_repr}
```python
def get_docx_repr(docx_path: str,
@@ -64,9 +60,7 @@ Return a JSON representation of the paragraphs and runs in the DOCX file.
A JSON representation of the paragraphs and runs in the DOCX file.
-
-
-#### get\_labeled\_docx\_runs(docx\_path: Optional[str] = None, docx\_repr=Optional[str], custom\_people\_names: Optional[Tuple[str, str]] = None, openai\_client: Optional[OpenAI] = None, api\_key: Optional[str] = None)
+#### get\_labeled\_docx\_runs(docx\_path: Optional[str] = None, docx\_repr=Optional[str], custom\_people\_names: Optional[Tuple[str, str]] = None, openai\_client: Optional[OpenAI] = None, api\_key: Optional[str] = None) {#formfyxer.docx\_wrangling.get\_labeled\_docx\_runs}
```python
def get_labeled_docx_runs(
@@ -90,9 +84,7 @@ Scan the DOCX and return a list of modified text with Jinja2 variable names inse
A list of tuples, each containing a paragraph number, run number, and the modified text of the run.
-
-
-#### get\_modified\_docx\_runs(docx\_path: Optional[str] = None, docx\_repr: Optional[str] = None, custom\_example: str = "", instructions: str = "", openai\_client: Optional[OpenAI] = None, api\_key: Optional[str] = None, temperature=0.5)
+#### get\_modified\_docx\_runs(docx\_path: Optional[str] = None, docx\_repr: Optional[str] = None, custom\_example: str = "", instructions: str = "", openai\_client: Optional[OpenAI] = None, api\_key: Optional[str] = None, temperature=0.5) {#formfyxer.docx\_wrangling.get\_modified\_docx\_runs}
```python
def get_modified_docx_runs(docx_path: Optional[str] = None,
@@ -154,9 +146,7 @@ You may also want to customize the input example to better match your use case.
A list of tuples, each containing a paragraph number, run number, and the modified text of the run.
-
-
-#### make\_docx\_plain\_language(docx\_path: str)
+#### make\_docx\_plain\_language(docx\_path: str) {#formfyxer.docx\_wrangling.make\_docx\_plain\_language}
```python
def make_docx_plain_language(docx_path: str) -> docx.document.Document
@@ -164,9 +154,7 @@ def make_docx_plain_language(docx_path: str) -> docx.document.Document
Convert a DOCX file to plain language with the help of OpenAI.
-
-
-#### modify\_docx\_with\_openai\_guesses(docx\_path: str)
+#### modify\_docx\_with\_openai\_guesses(docx\_path: str) {#formfyxer.docx\_wrangling.modify\_docx\_with\_openai\_guesses}
```python
def modify_docx_with_openai_guesses(docx_path: str) -> docx.document.Document
diff --git a/docs/components/FormFyxer/lit_explorer.md b/docs/components/FormFyxer/lit_explorer.md
index 36f2dac37..4e8978c6b 100644
--- a/docs/components/FormFyxer/lit_explorer.md
+++ b/docs/components/FormFyxer/lit_explorer.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [formfyxer.lit\_explorer](#formfyxer.lit_explorer)
+* formfyxer.lit\_explorer
* [recursive\_get\_id](#formfyxer.lit_explorer.recursive_get_id)
* [spot](#formfyxer.lit_explorer.spot)
* [re\_case](#formfyxer.lit_explorer.re_case)
@@ -37,9 +37,7 @@ sidebar_label: lit_explorer
title: formfyxer.lit_explorer
---
-
-
-#### recursive\_get\_id(values\_to\_unpack: Union[dict, list], tmpl: Optional[set] = None)
+#### recursive\_get\_id(values\_to\_unpack: Union[dict, list], tmpl: Optional[set] = None) {#formfyxer.lit\_explorer.recursive\_get\_id}
```python
def recursive_get_id(values_to_unpack: Union[dict, list],
@@ -48,9 +46,7 @@ def recursive_get_id(values_to_unpack: Union[dict, list],
Pull ID values out of the LIST/NSMI results from Spot.
-
-
-#### spot(text: str, lower: float = 0.25, pred: float = 0.5, upper: float = 0.6, verbose: float = 0, token: str = "")
+#### spot(text: str, lower: float = 0.25, pred: float = 0.5, upper: float = 0.6, verbose: float = 0, token: str = "") {#formfyxer.lit\_explorer.spot}
```python
def spot(text: str,
@@ -64,9 +60,7 @@ def spot(text: str,
Call the Spot API (https://spot.suffolklitlab.org) to classify the text of a PDF using
the NSMIv2/LIST taxonomy (https://taxonomy.legal/), but returns only the IDs of issues found in the text.
-
-
-#### re\_case(text: str)
+#### re\_case(text: str) {#formfyxer.lit\_explorer.re\_case}
```python
def re_case(text: str) -> str
@@ -74,9 +68,7 @@ def re_case(text: str) -> str
Capture PascalCase, snake_case and kebab-case terms and add spaces to separate the joined words
-
-
-#### regex\_norm\_field(text: str)
+#### regex\_norm\_field(text: str) {#formfyxer.lit\_explorer.regex\_norm\_field}
```python
def regex_norm_field(text: str)
@@ -85,9 +77,7 @@ def regex_norm_field(text: str)
Apply some heuristics to a field name to see if we can get it to match AssemblyLine conventions.
See: https://assemblyline.suffolklitlab.org/docs/document_variables
-
-
-#### reformat\_field(text: str, max\_length: int = 30, tools\_token: Optional[str] = None)
+#### reformat\_field(text: str, max\_length: int = 30, tools\_token: Optional[str] = None) {#formfyxer.lit\_explorer.reformat\_field}
```python
def reformat_field(text: str,
@@ -99,9 +89,7 @@ Transforms a string of text into a snake_case variable close in length to `max_l
summarizing the string and stitching the summary together in snake_case.
h/t https://towardsdatascience.com/nlp-building-a-summariser-68e0c19e3a93
-
-
-#### norm(row)
+#### norm(row) {#formfyxer.lit\_explorer.norm}
```python
def norm(row)
@@ -109,9 +97,7 @@ def norm(row)
Normalize a word vector.
-
-
-#### vectorize(text: Union[List[str], str], tools\_token: Optional[str] = None)
+#### vectorize(text: Union[List[str], str], tools\_token: Optional[str] = None) {#formfyxer.lit\_explorer.vectorize}
```python
def vectorize(text: Union[List[str], str], tools_token: Optional[str] = None)
@@ -128,9 +114,7 @@ Vectorize a string of text.
last bit is nolonger correct, you have to use the micor-service
as we have had to remove SpaCY due to a breaking change
-
-
-#### normalize\_name(jur: str, group: str, n: int, per, last\_field: str, this\_field: str, tools\_token: Optional[str] = None)
+#### normalize\_name(jur: str, group: str, n: int, per, last\_field: str, this\_field: str, tools\_token: Optional[str] = None) {#formfyxer.lit\_explorer.normalize\_name}
```python
def normalize_name(jur: str,
@@ -148,9 +132,7 @@ not, to a snake_case variable name of appropriate length.
HACK: temporarily all we do is re-case it and normalize it using regex rules.
Will be replaced with call to LLM soon.
-
-
-#### cluster\_screens(fields: List[str] = [], damping: float = 0.7, tools\_token: Optional[str] = None)
+#### cluster\_screens(fields: List[str] = [], damping: float = 0.7, tools\_token: Optional[str] = None) {#formfyxer.lit\_explorer.cluster\_screens}
```python
def cluster_screens(fields: List[str] = [],
@@ -169,9 +151,7 @@ Groups the given fields into screens based on how much they are related.
- `Returns` - a suggested screen grouping, each screen name mapped to the list of fields on it
-
-
-## InputType Objects
+## InputType Objects {#formfyxer.lit\_explorer.InputType}
```python
class InputType(Enum)
@@ -180,9 +160,7 @@ class InputType(Enum)
Input type maps onto the type of input the PDF author chose for the field. We only
handle text, checkbox, and signature fields.
-
-
-#### field\_types\_and\_sizes(fields: Optional[Iterable[FormField]])
+#### field\_types\_and\_sizes(fields: Optional[Iterable[FormField]]) {#formfyxer.lit\_explorer.field\_types\_and\_sizes}
```python
def field_types_and_sizes(
@@ -199,9 +177,7 @@ Result will look like:
\}
]
-
-
-## AnswerType Objects
+## AnswerType Objects {#formfyxer.lit\_explorer.AnswerType}
```python
class AnswerType(Enum)
@@ -217,9 +193,7 @@ a choice, creating a narrative, or even applying legal reasoning. "Affidavi
form of created answers.
See Jarret and Gaffney, Forms That Work (2008)
-
-
-#### classify\_field(field: FieldInfo, new\_name: str)
+#### classify\_field(field: FieldInfo, new\_name: str) {#formfyxer.lit\_explorer.classify\_field}
```python
def classify_field(field: FieldInfo, new_name: str) -> AnswerType
@@ -228,9 +202,7 @@ def classify_field(field: FieldInfo, new_name: str) -> AnswerType
Apply heuristics to the field's original and "normalized" name to classify
it as either a "slot-in", "gathered", "third party" or "created" field type.
-
-
-#### get\_adjusted\_character\_count(field: FieldInfo)
+#### get\_adjusted\_character\_count(field: FieldInfo) {#formfyxer.lit\_explorer.get\_adjusted\_character\_count}
```python
def get_adjusted_character_count(field: FieldInfo) -> float
@@ -268,9 +240,7 @@ for the same data without considering the space the user actually needs.
>>> get_adjusted_character_count(\{"max_length": 1200\})
1150
-
-
-#### time\_to\_answer\_field(field: FieldInfo, new\_name: str, cpm: int = 40, cpm\_std\_dev: int = 17)
+#### time\_to\_answer\_field(field: FieldInfo, new\_name: str, cpm: int = 40, cpm\_std\_dev: int = 17) {#formfyxer.lit\_explorer.time\_to\_answer\_field}
```python
def time_to_answer_field(field: FieldInfo,
@@ -285,9 +255,7 @@ It will factor in the input type, the answer type (slot in, gathered, third part
amount of input text allowed in the field.
The return value is a function that can return N samples of how long it will take to answer the field (in minutes)
-
-
-#### time\_to\_answer\_form(processed\_fields, normalized\_fields)
+#### time\_to\_answer\_form(processed\_fields, normalized\_fields) {#formfyxer.lit\_explorer.time\_to\_answer\_form}
```python
def time_to_answer_form(processed_fields,
@@ -305,9 +273,7 @@ rough estimate, based on whether the field is:
a. short created (3 lines or so?)
b. long created (anything over 3 lines)
-
-
-#### cleanup\_text(text: str, fields\_to\_sentences: bool = False)
+#### cleanup\_text(text: str, fields\_to\_sentences: bool = False) {#formfyxer.lit\_explorer.cleanup\_text}
```python
def cleanup_text(text: str, fields_to_sentences: bool = False) -> str
@@ -315,9 +281,7 @@ def cleanup_text(text: str, fields_to_sentences: bool = False) -> str
Apply cleanup routines to text to provide more accurate readability statistics.
-
-
-#### text\_complete(prompt: str, max\_tokens: int = 500, creds: Optional[OpenAiCreds] = None, temperature: float = 0)
+#### text\_complete(prompt: str, max\_tokens: int = 500, creds: Optional[OpenAiCreds] = None, temperature: float = 0) {#formfyxer.lit\_explorer.text\_complete}
```python
def text_complete(prompt: str,
@@ -335,9 +299,7 @@ Run a prompt via openAI's API and return the result.
- `creds` _Optional[OpenAiCreds], optional_ - The credentials to use. Defaults to None.
- `temperature` _float, optional_ - The temperature to use. Defaults to 0.
-
-
-#### complete\_with\_command(text, command, tokens, creds: Optional[OpenAiCreds] = None)
+#### complete\_with\_command(text, command, tokens, creds: Optional[OpenAiCreds] = None) {#formfyxer.lit\_explorer.complete\_with\_command}
```python
def complete_with_command(text,
@@ -348,9 +310,7 @@ def complete_with_command(text,
Combines some text with a command to send to open ai.
-
-
-#### needs\_calculations(text: Union[str])
+#### needs\_calculations(text: Union[str]) {#formfyxer.lit\_explorer.needs\_calculations}
```python
def needs_calculations(text: Union[str]) -> bool
@@ -359,9 +319,7 @@ def needs_calculations(text: Union[str]) -> bool
A conservative guess at if a given form needs the filler to make math calculations,
something that should be avoided. If
-
-
-#### tools\_passive(input: Union[List[str], str], tools\_token: Optional[str] = None)
+#### tools\_passive(input: Union[List[str], str], tools\_token: Optional[str] = None) {#formfyxer.lit\_explorer.tools\_passive}
```python
def tools_passive(input: Union[List[str], str],
@@ -370,9 +328,7 @@ def tools_passive(input: Union[List[str], str],
Ping passive voice API for list of sentences using the passive voice
-
-
-#### get\_passive\_sentences(text: Union[List, str], tools\_token: Optional[str] = None)
+#### get\_passive\_sentences(text: Union[List, str], tools\_token: Optional[str] = None) {#formfyxer.lit\_explorer.get\_passive\_sentences}
```python
def get_passive_sentences(
@@ -391,9 +347,7 @@ Text can either be a string or a list of strings.
If provided a single string, it will be tokenized with NTLK and
sentences containing fewer than 2 words will be ignored.
-
-
-#### get\_citations(text: str, tokenized\_sentences: List[str])
+#### get\_citations(text: str, tokenized\_sentences: List[str]) {#formfyxer.lit\_explorer.get\_citations}
```python
def get_citations(text: str, tokenized_sentences: List[str]) -> List[str]
@@ -403,9 +357,7 @@ Get citations and some extra surrounding context (the full sentence), if the cit
fewer than 5 characters (often eyecite only captures a section symbol
for state-level short citation formats)
-
-
-#### get\_sensitive\_data\_types(fields: List[str], fields\_old: Optional[List[str]] = None)
+#### get\_sensitive\_data\_types(fields: List[str], fields\_old: Optional[List[str]] = None) {#formfyxer.lit\_explorer.get\_sensitive\_data\_types}
```python
def get_sensitive_data_types(
@@ -421,9 +373,7 @@ will not contain the old field name, only the corresponding field name from the
The sensitive data types are: Bank Account Number, Credit Card Number, Driver's License Number, and Social Security
Number.
-
-
-#### substitute\_phrases(input\_string: str, substitution\_phrases: Dict[str, str])
+#### substitute\_phrases(input\_string: str, substitution\_phrases: Dict[str, str]) {#formfyxer.lit\_explorer.substitute\_phrases}
```python
def substitute_phrases(
@@ -457,9 +407,7 @@ Substitute phrases in the input string and return the new string and positions o
>>> print(positions)
[(4, 17), (35, 48)]
-
-
-#### substitute\_neutral\_gender(input\_string: str)
+#### substitute\_neutral\_gender(input\_string: str) {#formfyxer.lit\_explorer.substitute\_neutral\_gender}
```python
def substitute_neutral_gender(
@@ -469,9 +417,7 @@ def substitute_neutral_gender(
Substitute gendered phrases with neutral phrases in the input string.
Primary source is https://github.com/joelparkerhenderson/inclusive-language
-
-
-#### substitute\_plain\_language(input\_string: str)
+#### substitute\_plain\_language(input\_string: str) {#formfyxer.lit\_explorer.substitute\_plain\_language}
```python
def substitute_plain_language(
@@ -481,9 +427,7 @@ def substitute_plain_language(
Substitute complex phrases with simpler alternatives.
Source of terms is drawn from https://www.plainlanguage.gov/guidelines/words/
-
-
-#### transformed\_sentences(sentence\_list: List[str], fun: Callable)
+#### transformed\_sentences(sentence\_list: List[str], fun: Callable) {#formfyxer.lit\_explorer.transformed\_sentences}
```python
def transformed_sentences(
@@ -495,9 +439,7 @@ Apply a function to a list of sentences and return only the sentences with chang
The result is a tuple of the original sentence, new sentence, and the starting and ending position
of each changed fragment in the sentence.
-
-
-#### parse\_form(in\_file: str, title: Optional[str] = None, jur: Optional[str] = None, cat: Optional[str] = None, normalize: bool = True, spot\_token: Optional[str] = None, tools\_token: Optional[str] = None, openai\_creds: Optional[OpenAiCreds] = None, rewrite: bool = False, debug: bool = False)
+#### parse\_form(in\_file: str, title: Optional[str] = None, jur: Optional[str] = None, cat: Optional[str] = None, normalize: bool = True, spot\_token: Optional[str] = None, tools\_token: Optional[str] = None, openai\_creds: Optional[OpenAiCreds] = None, rewrite: bool = False, debug: bool = False) {#formfyxer.lit\_explorer.parse\_form}
```python
def parse_form(in_file: str,
@@ -516,9 +458,7 @@ Read in a pdf, pull out basic stats, attempt to normalize its form fields, and r
in_file with the new fields (if `rewrite=1`). If you pass a spot token, we will guess the
NSMI code. If you pass openai creds, we will give suggestions for the title and description.
-
-
-#### form\_complexity(stats)
+#### form\_complexity(stats) {#formfyxer.lit\_explorer.form\_complexity}
```python
def form_complexity(stats)
diff --git a/docs/components/FormFyxer/pdf_wrangling.md b/docs/components/FormFyxer/pdf_wrangling.md
index 7268a80d7..eaa487b8b 100644
--- a/docs/components/FormFyxer/pdf_wrangling.md
+++ b/docs/components/FormFyxer/pdf_wrangling.md
@@ -1,6 +1,6 @@
# Table of Contents
-* [formfyxer.pdf\_wrangling](#formfyxer.pdf_wrangling)
+* formfyxer.pdf\_wrangling
* [FieldType](#formfyxer.pdf_wrangling.FieldType)
* [TEXT](#formfyxer.pdf_wrangling.FieldType.TEXT)
* [AREA](#formfyxer.pdf_wrangling.FieldType.AREA)
@@ -36,41 +36,29 @@ sidebar_label: pdf_wrangling
title: formfyxer.pdf_wrangling
---
-
-
-## FieldType Objects
+## FieldType Objects {#formfyxer.pdf\_wrangling.FieldType}
```python
class FieldType(Enum)
```
-
-
-#### TEXT
+#### TEXT {#formfyxer.pdf\_wrangling.FieldType.TEXT}
Text input Field
-
-
-#### AREA
+#### AREA {#formfyxer.pdf\_wrangling.FieldType.AREA}
Text input Field, but an area
-
-
-#### LIST\_BOX
+#### LIST\_BOX {#formfyxer.pdf\_wrangling.FieldType.LIST\_BOX}
allows multiple selection
-
-
-#### CHOICE
+#### CHOICE {#formfyxer.pdf\_wrangling.FieldType.CHOICE}
allows only one selection
-
-
-## FormField Objects
+## FormField Objects {#formfyxer.pdf\_wrangling.FormField}
```python
class FormField()
@@ -78,9 +66,7 @@ class FormField()
A data holding class, used to easily specify how a PDF form field should be created.
-
-
-#### \_\_init\_\_(field\_name: str, type\_name: Union[FieldType, str], x: int, y: int, font\_size: Optional[int] = None, tooltip: str = "", configs: Optional[Dict[str, Any]] = None)
+#### \_\_init\_\_(field\_name: str, type\_name: Union[FieldType, str], x: int, y: int, font\_size: Optional[int] = None, tooltip: str = "", configs: Optional[Dict[str, Any]] = None) {#formfyxer.pdf\_wrangling.FormField.\_\_init\_\_}
```python
def __init__(field_name: str,
@@ -107,9 +93,7 @@ Constructor
[reportlab User Guide](https://www.reportlab.com/docs/reportlab-userguide.pdf)
- `field_name` - the name of the field, exposed to via most APIs. Not the tooltip, but `users1_name__0`
-
-
-#### set\_fields(in\_file: Union[str, Path, BinaryIO], out\_file: Union[str, Path, BinaryIO], fields\_per\_page: Iterable[Iterable[FormField]], \*, overwrite=False)
+#### set\_fields(in\_file: Union[str, Path, BinaryIO], out\_file: Union[str, Path, BinaryIO], fields\_per\_page: Iterable[Iterable[FormField]], \*, overwrite=False) {#formfyxer.pdf\_wrangling.set\_fields}
```python
def set_fields(in_file: Union[str, Path, BinaryIO],
@@ -157,9 +141,7 @@ set_fields('no_fields.pdf', 'four_fields_on_second_page.pdf',
Nothing.
-
-
-#### rename\_pdf\_fields(in\_file: Union[str, Path, BinaryIO], out\_file: Union[str, Path, BinaryIO], mapping: Mapping[str, str])
+#### rename\_pdf\_fields(in\_file: Union[str, Path, BinaryIO], out\_file: Union[str, Path, BinaryIO], mapping: Mapping[str, str]) {#formfyxer.pdf\_wrangling.rename\_pdf\_fields}
```python
def rename_pdf_fields(in_file: Union[str, Path, BinaryIO],
@@ -185,9 +167,9 @@ Args:
Returns:
Nothing
-
+```
-#### unlock\_pdf\_in\_place(in\_file: Union[str, Path, BinaryIO])
+#### unlock\_pdf\_in\_place(in\_file: Union[str, Path, BinaryIO]) {#formfyxer.pdf\_wrangling.unlock\_pdf\_in\_place}
```python
def unlock_pdf_in_place(in_file: Union[str, Path, BinaryIO]) -> None
@@ -195,9 +177,7 @@ def unlock_pdf_in_place(in_file: Union[str, Path, BinaryIO]) -> None
Try using pikePDF to unlock the PDF it it is locked. This won't work if it has a non-zero length password.
-
-
-#### has\_fields(pdf\_file: str)
+#### has\_fields(pdf\_file: str) {#formfyxer.pdf\_wrangling.has\_fields}
```python
def has_fields(pdf_file: str) -> bool
@@ -214,9 +194,7 @@ Check if a PDF has at least one form field using PikePDF.
- `bool` - True if the PDF has at least one form field, False otherwise.
-
-
-#### get\_existing\_pdf\_fields(in\_file: Union[str, Path, BinaryIO, Pdf])
+#### get\_existing\_pdf\_fields(in\_file: Union[str, Path, BinaryIO, Pdf]) {#formfyxer.pdf\_wrangling.get\_existing\_pdf\_fields}
```python
def get_existing_pdf_fields(
@@ -225,9 +203,7 @@ def get_existing_pdf_fields(
Use PikePDF to get fields from the PDF
-
-
-#### swap\_pdf\_page(\*, source\_pdf: Union[str, Path, Pdf], destination\_pdf: Union[str, Path, Pdf], source\_offset: int = 0, destination\_offset: int = 0, append\_fields: bool = False)
+#### swap\_pdf\_page(\*, source\_pdf: Union[str, Path, Pdf], destination\_pdf: Union[str, Path, Pdf], source\_offset: int = 0, destination\_offset: int = 0, append\_fields: bool = False) {#formfyxer.pdf\_wrangling.swap\_pdf\_page}
```python
def swap_pdf_page(*,
@@ -242,9 +218,7 @@ def swap_pdf_page(*,
the source and destination PDFs. By default, it will remove any existing annotations (which include form fields)
in the destination PDF. If you wish to append annotations instead, specify `append_fields = True`
-
-
-#### copy\_pdf\_fields(\*, source\_pdf: Union[str, Path, Pdf], destination\_pdf: Union[str, Path, Pdf], source\_offset: int = 0, destination\_offset: int = 0, append\_fields: bool = False)
+#### copy\_pdf\_fields(\*, source\_pdf: Union[str, Path, Pdf], destination\_pdf: Union[str, Path, Pdf], source\_offset: int = 0, destination\_offset: int = 0, append\_fields: bool = False) {#formfyxer.pdf\_wrangling.copy\_pdf\_fields}
```python
def copy_pdf_fields(*,
@@ -288,9 +262,7 @@ new_pdf_with_fields.save("new_pdf_with_fields.pdf")
A pikepdf.Pdf object with new fields. If `blank_pdf` was a pikepdf.Pdf object, the
same object is returned.
-
-
-#### get\_textboxes\_in\_pdf(in\_file: Union[str, Path, BinaryIO], line\_margin=0.02, char\_margin=2.0)
+#### get\_textboxes\_in\_pdf(in\_file: Union[str, Path, BinaryIO], line\_margin=0.02, char\_margin=2.0) {#formfyxer.pdf\_wrangling.get\_textboxes\_in\_pdf}
```python
def get_textboxes_in_pdf(in_file: Union[str, Path, BinaryIO],
@@ -300,9 +272,7 @@ def get_textboxes_in_pdf(in_file: Union[str, Path, BinaryIO],
Gets all of the text boxes found by pdfminer in a PDF, as well as their bounding boxes
-
-
-#### get\_bracket\_chars\_in\_pdf(in\_file: Union[str, Path, BinaryIO], line\_margin=0.02, char\_margin=0.0)
+#### get\_bracket\_chars\_in\_pdf(in\_file: Union[str, Path, BinaryIO], line\_margin=0.02, char\_margin=0.0) {#formfyxer.pdf\_wrangling.get\_bracket\_chars\_in\_pdf}
```python
def get_bracket_chars_in_pdf(in_file: Union[str, Path, BinaryIO],
@@ -315,9 +285,7 @@ TODO: Will eventually be used to find [ ] as checkboxes, but right now we can
This simply gets all of the brackets, and the characters of [hi] in a PDF and [ ] are the exact same distance apart.
Currently going with just "[hi]" doesn't happen, let's hope that assumption holds.
-
-
-#### intersect\_bbox(bbox\_a, bbox\_b, vert\_dilation=2, horiz\_dilation=2)
+#### intersect\_bbox(bbox\_a, bbox\_b, vert\_dilation=2, horiz\_dilation=2) {#formfyxer.pdf\_wrangling.intersect\_bbox}
```python
def intersect_bbox(bbox_a, bbox_b, vert_dilation=2, horiz_dilation=2) -> bool
@@ -325,9 +293,7 @@ def intersect_bbox(bbox_a, bbox_b, vert_dilation=2, horiz_dilation=2) -> bool
bboxes are [left edge, bottom edge, horizontal length, vertical length]
-
-
-#### intersect\_bboxs(bbox\_a, bboxes, vert\_dilation=2, horiz\_dilation=2)
+#### intersect\_bboxs(bbox\_a, bboxes, vert\_dilation=2, horiz\_dilation=2) {#formfyxer.pdf\_wrangling.intersect\_bboxs}
```python
def intersect_bboxs(bbox_a,
@@ -338,9 +304,7 @@ def intersect_bboxs(bbox_a,
Returns an iterable of booleans, one of each of the input bboxes, true if it collides with bbox_a
-
-
-#### contain\_boxes(bbox\_a: BoundingBoxF, bbox\_b: BoundingBoxF)
+#### contain\_boxes(bbox\_a: BoundingBoxF, bbox\_b: BoundingBoxF) {#formfyxer.pdf\_wrangling.contain\_boxes}
```python
def contain_boxes(bbox_a: BoundingBoxF, bbox_b: BoundingBoxF) -> BoundingBoxF
@@ -348,9 +312,7 @@ def contain_boxes(bbox_a: BoundingBoxF, bbox_b: BoundingBoxF) -> BoundingBoxF
Given two bounding boxes, return a single bounding box that contains both of them.
-
-
-#### get\_dist\_sq(point\_a: XYPair, point\_b: XYPair)
+#### get\_dist\_sq(point\_a: XYPair, point\_b: XYPair) {#formfyxer.pdf\_wrangling.get\_dist\_sq}
```python
def get_dist_sq(point_a: XYPair, point_b: XYPair) -> float
@@ -358,9 +320,7 @@ def get_dist_sq(point_a: XYPair, point_b: XYPair) -> float
returns the distance squared between two points. Faster than the true euclidean dist
-
-
-#### get\_dist(point\_a: XYPair, point\_b: XYPair)
+#### get\_dist(point\_a: XYPair, point\_b: XYPair) {#formfyxer.pdf\_wrangling.get\_dist}
```python
def get_dist(point_a: XYPair, point_b: XYPair) -> float
@@ -368,9 +328,7 @@ def get_dist(point_a: XYPair, point_b: XYPair) -> float
euclidean (L^2 norm) distance between two points
-
-
-#### get\_connected\_edges(point: XYPair, point\_list: Sequence)
+#### get\_connected\_edges(point: XYPair, point\_list: Sequence) {#formfyxer.pdf\_wrangling.get\_connected\_edges}
```python
def get_connected_edges(point: XYPair, point_list: Sequence)
@@ -379,9 +337,7 @@ def get_connected_edges(point: XYPair, point_list: Sequence)
point list is always ordered clockwise from the bottom left,
i.e. bottom left, top left, top right, bottom right
-
-
-#### bbox\_distance(bbox\_a: BoundingBoxF, bbox\_b: BoundingBoxF)
+#### bbox\_distance(bbox\_a: BoundingBoxF, bbox\_b: BoundingBoxF) {#formfyxer.pdf\_wrangling.bbox\_distance}
```python
def bbox_distance(
@@ -396,9 +352,7 @@ around a field, is the most likely to be the actual text label for the PDF field
bboxes are 4 floats, x, y, width and height
-
-
-#### get\_possible\_fields(in\_pdf\_file: Union[str, Path], textboxes: Optional[List[List[Textbox]]] = None)
+#### get\_possible\_fields(in\_pdf\_file: Union[str, Path], textboxes: Optional[List[List[Textbox]]] = None) {#formfyxer.pdf\_wrangling.get\_possible\_fields}
```python
def get_possible_fields(
@@ -432,9 +386,7 @@ print(fields[0][0])
For each page in the input PDF, a list of predicted form fields
-
-
-#### get\_possible\_checkboxes(img: Union[str, cv2.Mat], find\_small=False)
+#### get\_possible\_checkboxes(img: Union[str, cv2.Mat], find\_small=False) {#formfyxer.pdf\_wrangling.get\_possible\_checkboxes}
```python
def get_possible_checkboxes(img: Union[str, cv2.Mat],
@@ -447,9 +399,7 @@ Assumes the checkbox is square.
find_small: if true, finds smaller checkboxes. Sometimes will "find" a checkbox in letters,
like O and D, if the font is too small
-
-
-#### get\_possible\_radios(img: Union[str, BinaryIO, cv2.Mat])
+#### get\_possible\_radios(img: Union[str, BinaryIO, cv2.Mat]) {#formfyxer.pdf\_wrangling.get\_possible\_radios}
```python
def get_possible_radios(img: Union[str, BinaryIO, cv2.Mat])
@@ -458,9 +408,7 @@ def get_possible_radios(img: Union[str, BinaryIO, cv2.Mat])
Even though it's called "radios", it just gets things shaped like circles, not
doing any semantic analysis yet.
-
-
-#### get\_possible\_text\_fields(img: Union[str, BinaryIO, cv2.Mat], text\_lines: List[Textbox], default\_line\_height: int = 44)
+#### get\_possible\_text\_fields(img: Union[str, BinaryIO, cv2.Mat], text\_lines: List[Textbox], default\_line\_height: int = 44) {#formfyxer.pdf\_wrangling.get\_possible\_text\_fields}
```python
def get_possible_text_fields(
@@ -476,9 +424,7 @@ Won't find field inputs as boxes
default_line_height: the default height (16 pt), in pixels (at 200 dpi), which is 45
-
-
-#### auto\_add\_fields(in\_pdf\_file: Union[str, Path], out\_pdf\_file: Union[str, Path])
+#### auto\_add\_fields(in\_pdf\_file: Union[str, Path], out\_pdf\_file: Union[str, Path]) {#formfyxer.pdf\_wrangling.auto\_add\_fields}
```python
def auto_add_fields(in_pdf_file: Union[str, Path], out_pdf_file: Union[str,
@@ -508,9 +454,7 @@ auto_add_fields('no_fields.pdf', 'newly_added_fields.pdf')
Nothing
-
-
-#### is\_tagged(in\_pdf\_file: Union[str, Path, pikepdf.Pdf])
+#### is\_tagged(in\_pdf\_file: Union[str, Path, pikepdf.Pdf]) {#formfyxer.pdf\_wrangling.is\_tagged}
```python
def is_tagged(in_pdf_file: Union[str, Path, pikepdf.Pdf]) -> bool
diff --git a/docs/components/GithubFeedbackForm/github_feedback.md b/docs/components/GithubFeedbackForm/github_feedback.md
index e41dd91eb..deef50458 100644
--- a/docs/components/GithubFeedbackForm/github_feedback.md
+++ b/docs/components/GithubFeedbackForm/github_feedback.md
@@ -157,7 +157,7 @@ The key lines in the above are:
The `only_once_review_widget` will ask two questions, one is a simple "Did we help you?" with thumbs up and thumbs down options, and the second is an open text box for users to write more. If they answer the first question and refresh the screen or continue through the interview, the feedback widget won't be shown again, given that the user
doesn't go back past the widget's screen in the interview.
-You can change several aspects of the review widget. For more information, see [the API reference of `review_widget` in ALToolbox](../ALToolbox/misc.md#review_widget). That is the function `only_once_review_widget` is using.
+You can change several aspects of the review widget. For more information, see [the API reference of `review_widget` in ALToolbox](../ALToolbox/misc.md#ALToolbox.misc.review_widget). That is the function `only_once_review_widget` is using.
The `only_once_review_widget` review information is only stored on the docassemble server, and can be viewed [using the feedback browsing interview](#how-to-browse-feedback-on-the-server).
diff --git a/docs/get_started/beginners_guide.md b/docs/get_started/beginners_guide.md
index 5c265125b..d90585b35 100644
--- a/docs/get_started/beginners_guide.md
+++ b/docs/get_started/beginners_guide.md
@@ -13,11 +13,11 @@ You will need access to a [docassemble playground](https://docassemble.org/docs/
## Quick introduction
-[The Hello, World exercise](#do-the-hello-world-exercise) is a quick, friendly introduction to docassemble.
+[The Hello, World exercise](../docassemble_intro/hello-world.md) is a quick, friendly introduction to docassemble.
After doing the exercise, [watch a demonstration of the Weaver](https://www.youtube.com/live/1zF_omoCm1c?si=u9MqDGm_1G3iAH7t&t=1595), a Document Assembly Line tool for quickly turning prepared forms into draft docassemble interviews. The code generated by the Weaver is not a finished interview; it is a starting point intended for further editing.
-Finally, [review the interview project management page](#review-the-interview-project-management-guide) to get an idea of what an interview-building project is like.
+Finally, [review the interview project management page](project_management.md) to get an idea of what an interview-building project is like.
## Interview builder training
diff --git a/docs/volunteer/volunteer.mdx b/docs/volunteer/volunteer.mdx
index c416452ab..adab48eff 100644
--- a/docs/volunteer/volunteer.mdx
+++ b/docs/volunteer/volunteer.mdx
@@ -110,6 +110,6 @@ And more! Whatever your skills and interests, we can probably put them to good u
We expect volunteers who are actively training or working on a project to check in regularly. We generally check in weekly by responding to a post in Teams with a status update. (This is also a regular reminder to let us know if you need something else to work on!)
-## Ready? Sign up to volunteer
+## Ready? Sign up to volunteer {#sign-up-to-volunteer}
diff --git a/fix-doc-anchors.py b/fix-doc-anchors.py
new file mode 100755
index 000000000..6ecd6a1ec
--- /dev/null
+++ b/fix-doc-anchors.py
@@ -0,0 +1,204 @@
+#!/usr/bin/env python3
+"""Post-process the auto-generated API reference pages so their in-page anchors
+work with Docusaurus' broken-anchor checker.
+
+``pydoc-markdown`` emits raw ```` tags before every
+heading and a "Table of Contents" whose links point at those ids. Docusaurus
+only registers anchors that come from Markdown headings (or a handful of theme
+components), so every one of those links is reported as a broken anchor at
+build time.
+
+This script rewrites each generated page under ``docs/components`` so that:
+
+* ```` immediately followed by a heading becomes an explicit
+ Docusaurus heading id: ``#### heading {#X}``.
+* the "Table of Contents" entry that links a module to itself (an ``
``,
+ which Docusaurus never gives an id) loses its now-danglink link.
+* short cross-references copied out of Python docstrings
+ (``[foo](#foo)``, ``[bar](other_module#bar)``) are expanded to the fully
+ qualified id that the heading now carries.
+
+It is idempotent: once a page has been processed the ```` tags are gone
+and the headings already carry ``{#...}``, so re-running it is a no-op. It runs
+locally against the committed pages and again in CI after ``fix-doc-titles.sh``.
+"""
+
+from __future__ import annotations
+
+import re
+from pathlib import Path
+
+COMPONENTS_DIR = Path("docs/components")
+
+A_ID_RE = re.compile(r'^\s*$')
+HEADING_RE = re.compile(r"^(#{1,6})\s+\S")
+HEADING_HAS_ID_RE = re.compile(r"\{#[^}]+\}\s*$")
+FENCE_RE = re.compile(r"^(`{3,}|~{3,})(.*)$")
+TOP_TOC_LINK_RE = re.compile(r"^\* \[(?P[^\]]+)\]\(#(?P[^)]+)\)\s*$")
+TOC_TITLE_RE = re.compile(r"^# (Table of Contents|[\w.]+\.[\w.]+)\s*$")
+# [label](target) where target is `#name` or `path/to/module#name` or
+# `module.md#name` and `name` is a plain (dot-free) identifier.
+SHORT_XREF_RE = re.compile(
+ r"\]\((?P[^)#\s]*?)#(?P[A-Za-z_][A-Za-z0-9_]*)\)"
+)
+
+
+def iter_pages() -> list[Path]:
+ return sorted(COMPONENTS_DIR.rglob("*.md"))
+
+
+def build_id_index(pages: list[Path]) -> dict[str, dict[str, str]]:
+ """stem -> {last dotted segment -> fully qualified id}.
+
+ Ambiguous short names (two members that share a final segment) are dropped
+ so we never rewrite a link to the wrong target.
+ """
+ index: dict[str, dict[str, str]] = {}
+ for page in pages:
+ mapping: dict[str, str] = {}
+ ambiguous: set[str] = set()
+ for line in page.read_text(encoding="utf-8").splitlines():
+ match = A_ID_RE.match(line)
+ if not match:
+ continue
+ full = match.group(1)
+ short = full.rsplit(".", 1)[-1]
+ if short in mapping and mapping[short] != full:
+ ambiguous.add(short)
+ mapping.setdefault(short, full)
+ for name in ambiguous:
+ mapping.pop(name, None)
+ index[page.stem] = mapping
+ return index
+
+
+def _fence_delimiter(line: str) -> tuple[str, str] | None:
+ match = FENCE_RE.match(line.lstrip())
+ if not match:
+ return None
+ return match.group(1), match.group(2).strip()
+
+
+def _heading_id_suffix(anchor: str) -> str:
+ # Underscores in the raw id would be parsed as Markdown emphasis
+ # ("__init__" -> "init"), corrupting the anchor. pydoc
+ # already escapes them in the visible heading text; do the same here.
+ return f" {{#{anchor.replace('_', r'\_')}}}"
+
+
+def attach_heading_ids(lines: list[str]) -> tuple[list[str], bool]:
+ out: list[str] = []
+ changed = False
+ fence: tuple[str, int] | None = None
+ i = 0
+ while i < len(lines):
+ line = lines[i]
+ delimiter = _fence_delimiter(line)
+ if delimiter is not None:
+ marker, info = delimiter
+ if fence is None:
+ if marker[0] not in info: # an opening ``` can't have ` in its info string
+ fence = (marker[0], len(marker))
+ elif marker[0] == fence[0] and len(marker) >= fence[1] and info == "":
+ fence = None
+
+ anchor_match = A_ID_RE.match(line)
+ if not anchor_match:
+ out.append(line)
+ i += 1
+ continue
+
+ # Look past blank lines for the heading this anchor belongs to.
+ j = i + 1
+ while j < len(lines) and lines[j].strip() == "":
+ j += 1
+ if j < len(lines) and HEADING_RE.match(lines[j]):
+ if fence is not None:
+ # A malformed docstring code fence upstream never closed; the
+ # heading below would be swallowed by it. Close it first.
+ out.append(fence[0] * fence[1])
+ out.append("")
+ fence = None
+ heading = lines[j].rstrip()
+ if not HEADING_HAS_ID_RE.search(heading):
+ heading = f"{heading}{_heading_id_suffix(anchor_match.group(1))}"
+ out.append(heading)
+ changed = True
+ i = j + 1
+ else:
+ # No heading follows - drop the tag, it is invisible to Docusaurus.
+ changed = True
+ i += 1
+ return out, changed
+
+
+def drop_module_self_link(lines: list[str]) -> tuple[list[str], bool]:
+ # Only the pydoc-generated pages carry a "Table of Contents" heading.
+ if not lines or not TOC_TITLE_RE.match(lines[0]):
+ return lines, False
+ for idx, line in enumerate(lines[:6]):
+ match = TOP_TOC_LINK_RE.match(line)
+ if not match or "." not in match.group("anchor"):
+ continue
+ # The first top-level ("* [x](...)") bullet is the module heading, which
+ # Docusaurus renders as an and never assigns an id.
+ lines[idx] = f"* {match.group('text')}"
+ return lines, True
+ return lines, False
+
+
+def expand_short_xrefs(
+ text: str, stem: str, index: dict[str, dict[str, str]]
+) -> tuple[str, bool]:
+ changed = False
+
+ def replace(match: re.Match[str]) -> str:
+ nonlocal changed
+ path = match.group("path")
+ frag = match.group("frag")
+ target_stem = Path(path).name[:-3] if path.endswith(".md") else Path(path).name
+ target_stem = target_stem or stem
+ full = index.get(target_stem, {}).get(frag)
+ if not full or "." not in full:
+ return match.group(0)
+ changed = True
+ return f"]({path}#{full})"
+
+ return SHORT_XREF_RE.sub(replace, text), changed
+
+
+def process(page: Path, index: dict[str, dict[str, str]]) -> bool:
+ with page.open("r", encoding="utf-8", newline="") as handle:
+ original = handle.read()
+ newline = "\r\n" if "\r\n" in original else "\n"
+ trailing_newline = original.endswith(newline)
+ lines = original.split(newline)
+ if trailing_newline:
+ lines = lines[:-1]
+
+ lines, a = attach_heading_ids(lines)
+ lines, b = drop_module_self_link(lines)
+
+ text = newline.join(lines)
+ if trailing_newline:
+ text += newline
+ text, c = expand_short_xrefs(text, page.stem, index)
+
+ if a or b or c:
+ with page.open("w", encoding="utf-8", newline="") as handle:
+ handle.write(text)
+ return True
+ return False
+
+
+def main() -> None:
+ if not COMPONENTS_DIR.is_dir():
+ raise SystemExit(f"expected to run from the docs root; {COMPONENTS_DIR} not found")
+ pages = iter_pages()
+ index = build_id_index(pages)
+ touched = [page for page in pages if process(page, index)]
+ print(f"fix-doc-anchors: updated {len(touched)} of {len(pages)} reference pages")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index a5953c89d..ff48e9000 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -10,6 +10,7 @@ import Link from '@docusaurus/Link';
import Translate, {translate} from '@docusaurus/Translate';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useBaseUrl from '@docusaurus/useBaseUrl';
+import useBrokenLinks from '@docusaurus/useBrokenLinks';
import Layout from '@theme/Layout';
import clsx from 'clsx';
import styles from './styles.module.css';
@@ -22,6 +23,10 @@ function Home() {
},
} = useDocusaurusContext();
+ // The "#partners" section below is a plain
, which Docusaurus' broken
+ // anchor checker doesn't see on its own; register it explicitly.
+ useBrokenLinks().collectAnchor('partners');
+
return (