diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 94edfbe0d..4b6ab5073 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -42,6 +42,7 @@ jobs: run: | cd docs pydoc-markdown + ./fix-doc-titles.sh - uses: actions/setup-node@v3 with: node-version: 20 diff --git a/.github/workflows/test-deploy.yml b/.github/workflows/test-deploy.yml index bfbe7a881..c6cfbd79b 100644 --- a/.github/workflows/test-deploy.yml +++ b/.github/workflows/test-deploy.yml @@ -42,6 +42,7 @@ jobs: run: | cd docs pydoc-markdown + ./fix-doc-titles.sh - uses: actions/setup-node@v3 with: node-version: 20 diff --git a/docs/components/ALToolbox/al_income.md b/docs/components/ALToolbox/al_income.md index 83dfa0dc1..bddad4afe 100644 --- a/docs/components/ALToolbox/al_income.md +++ b/docs/components/ALToolbox/al_income.md @@ -1,9 +1,77 @@ ---- -sidebar_label: al_income -title: ALToolbox.al_income ---- +# 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) + * [\_\_str\_\_](#ALToolbox.al_income.ALPeriodicAmount.__str__) + * [total](#ALToolbox.al_income.ALPeriodicAmount.total) + * [ALIncome](#ALToolbox.al_income.ALIncome) + * [total](#ALToolbox.al_income.ALIncome.total) + * [ALExpense](#ALToolbox.al_income.ALExpense) + * [ALIncomeList](#ALToolbox.al_income.ALIncomeList) + * [sources](#ALToolbox.al_income.ALIncomeList.sources) + * [matches](#ALToolbox.al_income.ALIncomeList.matches) + * [total](#ALToolbox.al_income.ALIncomeList.total) + * [move\_checks\_to\_list](#ALToolbox.al_income.ALIncomeList.move_checks_to_list) + * [ALJob](#ALToolbox.al_income.ALJob) + * [gross\_total](#ALToolbox.al_income.ALJob.gross_total) + * [deductions](#ALToolbox.al_income.ALJob.deductions) + * [net\_total](#ALToolbox.al_income.ALJob.net_total) + * [employer\_name\_address\_phone](#ALToolbox.al_income.ALJob.employer_name_address_phone) + * [normalized\_hours](#ALToolbox.al_income.ALJob.normalized_hours) + * [ALJobList](#ALToolbox.al_income.ALJobList) + * [total](#ALToolbox.al_income.ALJobList.total) + * [gross\_total](#ALToolbox.al_income.ALJobList.gross_total) + * [net\_total](#ALToolbox.al_income.ALJobList.net_total) + * [deductions](#ALToolbox.al_income.ALJobList.deductions) + * [ALExpenseList](#ALToolbox.al_income.ALExpenseList) + * [ALAsset](#ALToolbox.al_income.ALAsset) + * [total](#ALToolbox.al_income.ALAsset.total) + * [equity](#ALToolbox.al_income.ALAsset.equity) + * [ALAssetList](#ALToolbox.al_income.ALAssetList) + * [market\_value](#ALToolbox.al_income.ALAssetList.market_value) + * [balance](#ALToolbox.al_income.ALAssetList.balance) + * [equity](#ALToolbox.al_income.ALAssetList.equity) + * [owners](#ALToolbox.al_income.ALAssetList.owners) + * [ALVehicle](#ALToolbox.al_income.ALVehicle) + * [year\_make\_model](#ALToolbox.al_income.ALVehicle.year_make_model) + * [ALVehicleList](#ALToolbox.al_income.ALVehicleList) + * [ALSimpleValue](#ALToolbox.al_income.ALSimpleValue) + * [total](#ALToolbox.al_income.ALSimpleValue.total) + * [\_\_str\_\_](#ALToolbox.al_income.ALSimpleValue.__str__) + * [ALSimpleValueList](#ALToolbox.al_income.ALSimpleValueList) + * [sources](#ALToolbox.al_income.ALSimpleValueList.sources) + * [total](#ALToolbox.al_income.ALSimpleValueList.total) + * [ALItemizedValue](#ALToolbox.al_income.ALItemizedValue) + * [income\_fields](#ALToolbox.al_income.ALItemizedValue.income_fields) + * [\_\_str\_\_](#ALToolbox.al_income.ALItemizedValue.__str__) + * [ALItemizedValueDict](#ALToolbox.al_income.ALItemizedValueDict) + * [hook\_after\_gather](#ALToolbox.al_income.ALItemizedValueDict.hook_after_gather) + * [\_\_str\_\_](#ALToolbox.al_income.ALItemizedValueDict.__str__) + * [ALItemizedJob](#ALToolbox.al_income.ALItemizedJob) + * [total](#ALToolbox.al_income.ALItemizedJob.total) + * [gross\_total](#ALToolbox.al_income.ALItemizedJob.gross_total) + * [deduction\_total](#ALToolbox.al_income.ALItemizedJob.deduction_total) + * [net\_total](#ALToolbox.al_income.ALItemizedJob.net_total) + * [employer\_name\_address\_phone](#ALToolbox.al_income.ALItemizedJob.employer_name_address_phone) + * [normalized\_hours](#ALToolbox.al_income.ALItemizedJob.normalized_hours) + * [ALItemizedJobList](#ALToolbox.al_income.ALItemizedJobList) + * [sources](#ALToolbox.al_income.ALItemizedJobList.sources) + * [total](#ALToolbox.al_income.ALItemizedJobList.total) + * [gross\_total](#ALToolbox.al_income.ALItemizedJobList.gross_total) + * [deduction\_total](#ALToolbox.al_income.ALItemizedJobList.deduction_total) + * [net\_total](#ALToolbox.al_income.ALItemizedJobList.net_total) + + + + +### times\_per\_year -#### times\_per\_year +```python +def times_per_year(times_per_year_list: List[Tuple[int, str]], + times_per_year: float) -> str +``` Get the lower-case textual description that matches a time period contained in a "times per year" list. @@ -27,7 +95,15 @@ represent "every two years". Items not contained in the list (to provi specific lookup name) will have a string representation that is rounded to the nearest whole integer. -#### recent\_years + + +### recent\_years + +```python +def recent_years(past: int = 25, + order: str = "descending", + future: int = 1) -> List[int] +``` Returns a list of the most recent past years, continuing into the future. Defaults to most recent 15 years+1. Useful to populate a combobox of years @@ -40,6 +116,8 @@ The default is 15 * order \{string\} 'descending' or 'ascending'. Default is `descending`. * future (defaults to 1). + + ## ALPeriodicAmount Objects ```python @@ -50,7 +128,7 @@ Represents an amount (could be an income or an expense depending on the context) that reoccurs some times per year. E.g, to express a weekly period, use 52. The default is 1 (a year). -**Attributes**: +#### Attributes .value \{str | float | Decimal\} A number representing an amount of money accumulated during the `times_per_year` of this income. @@ -60,16 +138,30 @@ 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\_\_ + +```python +def __str__() -> str +``` Returns the income's `.total()` as string, not its object name. -#### total + + +### total + +```python +def total(times_per_year: float = 1) -> Decimal +``` Returns the income over the specified times_per_year, To calculate `.total()`, an ALPeriodicAmount must have a `.times_per_year` and `.value`. + + ## ALIncome Objects ```python @@ -81,7 +173,7 @@ incomes must include hours per period (times per year). Period is some denominator of a year. E.g, to express a weekly period, use 52. The default is 1 (a year). -**Attributes**: +#### Attributes .value \{str | float | Decimal\} A number representing an amount of money accumulated during the `times_per_year` of this income. @@ -95,7 +187,13 @@ 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 + + +### total + +```python +def total(times_per_year: float = 1) -> Decimal +``` Returns the income over the specified times_per_year, taking into account hours per period for hourly items. For example, for an hourly income of 10 @@ -105,6 +203,8 @@ and `income.total(52)` would be 400, the weekly income. To calculate `.total()`, an ALIncome must have a `.times_per_year` and `.value`. It can also have `.is_hourly` and `.hours_per_period`. + + ## ALExpense Objects ```python @@ -113,6 +213,8 @@ class ALExpense(ALPeriodicAmount) Not much changes from ALPeriodic Amount, just the generic object questions + + ## ALIncomeList Objects ```python @@ -128,17 +230,39 @@ use of these attributes and methods in its items: .value .total() -#### sources + + +### sources + +```python +def sources() -> Set[str] +``` Returns a set of the unique sources in the ALIncomeList. -#### matches + + +### matches + +```python +def matches(source: SourceType, + exclude_source: Optional[SourceType] = None) -> "ALIncomeList" +``` Returns an ALIncomeList consisting only of elements matching the specified income source, assisting in filling PDFs with predefined spaces. `source` may be a list. -#### total + + +### total + +```python +def total(times_per_year: float = 1, + source: Optional[SourceType] = None, + exclude_source: Optional[SourceType] = None, + owner: Optional[str] = None) -> Decimal +``` Returns the total periodic value in the list, gathering the list items if necessary. You can optionally filter by `source`. `source` can be a @@ -148,7 +272,14 @@ To calculate `.total()` correctly, all items must have a `.total()` and it should be a positive value. Job-type incomes should automatically exclude deductions. -#### move\_checks\_to\_list + + +### move\_checks\_to\_list + +```python +def move_checks_to_list(selected_types: Optional[DADict] = None, + selected_terms: Optional[Mapping] = None) +``` Gives a 'gather by checklist' option. If no selected_types param is passed, requires that a .selected_types @@ -159,6 +290,8 @@ Sets the attribute "moved" to true, doesn't set gathered, because idempotent, so trying to also gather all info about the checks in the list doesn't work well. + + ## ALJob Objects ```python @@ -173,7 +306,7 @@ user must enter the total amount for "net" and "gross" incom Can be stored in an ALJobList. -**Attributes**: +#### Attributes .value \{float | Decimal\} A number representing an amount of money accumulated during the `times_per_year` of this income. @@ -190,7 +323,13 @@ Can be stored in an ALJobList. .employer \{Individual\} (Optional) A docassemble Individual object, employer.address is the address and employer.phone is the phone -#### gross\_total + + +### gross\_total + +```python +def gross_total(times_per_year: float = 1) -> Decimal +``` Same as ALIncome total. Returns the income over the specified times_per_year, representing the `.value` attribute of the item. @@ -198,7 +337,13 @@ representing the `.value` attribute of the item. `times_per_year` is some denominator of a year. E.g. to express a weekly period, use 52. The default is 1 (a year). -#### deductions + + +### deductions + +```python +def deductions(times_per_year: float = 1) -> Decimal +``` Returns the total deductions from someone's pay over the specificed times_per_year (not per hour if hourly). @@ -206,7 +351,13 @@ Returns the total deductions from someone's pay over the specificed times_p `times_per_year` is some denominator of a year. E.g. to express a weekly period, use 52. The default is 1 (a year). -#### net\_total + + +### net\_total + +```python +def net_total(times_per_year: float = 1) -> Decimal +``` Returns the net income over a time period, found using `self.value` and `self.deduction`. @@ -219,13 +370,25 @@ 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 + +```python +def employer_name_address_phone() -> str +``` Returns name, address and phone number of employer as a string. Forces gathering the `.employer`, `.employer_address`, and `.employer_phone` attributes. -#### normalized\_hours + + +### normalized\_hours + +```python +def normalized_hours(times_per_year: float = 1) -> float +``` Returns the normalized number of hours worked in a given times_per_year, based on the self.hours_per_period and self.times_per_year attributes. @@ -239,6 +402,8 @@ period, use 52. The default is 1 (a year). This will force the gathering of the attributes `.hours_per_period` and `.times_per_year` + + ## ALJobList Objects ```python @@ -249,7 +414,16 @@ 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. -#### total + + +### total + +```python +def total(times_per_year: float = 1, + source: Optional[SourceType] = None, + exclude_source: Optional[SourceType] = None, + owner: Optional[str] = None) -> Decimal +``` Returns the sum of the gross incomes of its ALJobs divided by the time times_per_year. You can filter the jobs by `source`. `source` can be a @@ -258,7 +432,15 @@ 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 + + +### gross\_total + +```python +def gross_total(times_per_year: float = 1, + source: Optional[SourceType] = None, + exclude_source: Optional[SourceType] = None) -> Decimal +``` Returns the sum of the gross incomes of its ALJobs divided by the time times_per_year. You can filter the jobs by `source`. `source` can be a @@ -267,7 +449,15 @@ 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). -#### net\_total + + +### net\_total + +```python +def net_total(times_per_year: float = 1, + source: Optional[SourceType] = None, + exclude_source: Optional[SourceType] = None) -> Decimal +``` Returns the sum of the net incomes of its ALJobs divided by the time times_per_year. You can filter the jobs by `source`. `source` can be a @@ -279,12 +469,22 @@ If the job is hourly, the `net_total()` may not be comparable to the `times_per_year` is some denominator of a year. E.g, to express a weekly period, use 52. The default is 1 (a year). -#### deductions + + +### deductions + +```python +def deductions(times_per_year: float = 1, + source: Optional[SourceType] = None, + exclude_source: Optional[SourceType] = None) -> Decimal +``` Returns the sum of the deductions of its ALJobs divided by the time times_per_year. You can filter the jobs by `source`. Leaving out `source` will use all sources. + + ## ALExpenseList Objects ```python @@ -298,6 +498,8 @@ A list of expenses * source * display name + + ## ALAsset Objects ```python @@ -310,7 +512,7 @@ asset represents a financial account rather than a physical asset. Can be stored in an ALAssetList. -**Attributes**: +#### Attributes .market_value \{float | Decimal\} Market value of the asset. .balance \{float | Decimal \} Current balance of the account, e.g., like @@ -325,34 +527,48 @@ 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 + + +### total + +```python +def total(times_per_year: float = 1) -> Decimal +``` Returns the .value attribute divided by the times per year you want to calculate. The value defaults to 0. `times_per_year` is some denominator of a year. E.g, to express a weekly period, use 52. The default is 1 (a year). -**Arguments**: +#### Arguments - `times_per_year` _float, optional_ - The number of times per year to calculate. Defaults to 1. -**Returns**: +#### Returns - `Decimal` - The .value attribute divided by the times per year. -#### equity + + +### equity + +```python +def equity(loan_attribute="balance") -> Decimal +``` Returns the total equity in the asset (e.g., market value minus balance). -**Arguments**: +#### Arguments - `loan_attribute` _str, optional_ - The attribute of the asset to use as the loan value. Defaults to "balance". -**Returns**: +#### Returns - `Decimal` - The total equity in the asset. + + ## ALAssetList Objects ```python @@ -363,7 +579,7 @@ A list of ALAssets. The `total()` of the list will be the total income earned, which may not be what you want for a list of assets. To get the total value of all assets, use the `market_value()` method. -**Attributes**: +#### Attributes - `market_value` _float | Decimal_ - Market value of the asset. - `balance` _float | Decimal_ - Current balance of the account, e.g., like @@ -378,13 +594,20 @@ 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 + + +### market\_value + +```python +def market_value(source: Optional[SourceType] = None, + exclude_source: Optional[SourceType] = None) -> Decimal +``` Returns the total `.market_value` of assets in the list. You can filter the assets by `source`. `source` can be a string or a list. -**Arguments**: +#### Arguments - `source` _Optional[SourceType]_ - The source of the assets to include in the calculation. If None, all sources are included. Can be a string or a list. @@ -392,17 +615,24 @@ You can filter the assets by `source`. `source` can be a string or a list. If None, no sources are excluded. -**Returns**: +#### Returns - `Decimal` - The total market value of the assets. -#### balance + + +### balance + +```python +def balance(source: Optional[SourceType] = None, + exclude_source: Optional[SourceType] = None) -> Decimal +``` Returns the total `.balance` of assets in the list, which typically corresponds to the available funds in a financial account. You can filter the assets by `source`. `source` can be a string or a list. -**Arguments**: +#### Arguments - `source` _Optional[SourceType]_ - The source of the assets to include in the calculation. If None, all sources are included. Can be a string or a list. @@ -410,35 +640,50 @@ You can filter the assets by `source`. `source` can be a string or a list. If None, no sources are excluded. -**Returns**: +#### Returns - `Decimal` - The total balance of the assets. -#### equity + + +### equity + +```python +def equity(source: Optional[SourceType] = None, + exclude_source: Optional[SourceType] = None, + loan_attribute: str = "balance") -> Decimal +``` Calculates and returns the total equity in the assets. This method triggers the gathering of assets, then iterates over each asset. If a source or exclude_source is not specified, or if the asset's source satisfies the source criteria, the equity of the asset is added to the total. -**Arguments**: +#### Arguments - `source` _Optional[SourceType]_ - The source of the assets to include in the calculation. If None, all sources are included. - `exclude_source` _Optional[SourceType]_ - The source of the assets to exclude from the calculation. If None, no sources are excluded. - `loan_attribute` _str, optional_ - The attribute of the asset to use as the loan value. Defaults to "balance". -**Returns**: +#### Returns - `Decimal` - The total equity in the assets. -#### owners + + +### owners + +```python +def owners(source: Optional[SourceType] = None, + exclude_source: Optional[SourceType] = None) -> Set[str] +``` Returns a set of the unique owners of the assets. You can filter the assets by `source`. `source` can be a string or a list. -**Arguments**: +#### Arguments - `source` _Optional[SourceType]_ - The source of the assets to include in the calculation. If None, all sources are included. Can be a string or a list. @@ -446,10 +691,12 @@ You can filter the assets by `source`. `source` can be a string or a list. If None, no sources are excluded. -**Returns**: +#### Returns - `Set[str]` - A set of the unique owners of the assets. + + ## ALVehicle Objects ```python @@ -463,7 +710,7 @@ such as year, make, and model, and includes methods for representing these attributes in a standardized format, as often required on financial statement forms. -**Attributes**: +#### Attributes - `year` _str_ - The model year of the vehicle, e.g., '2022'. - `make` _str_ - The make of the vehicle, e.g., 'Honda'. @@ -475,20 +722,28 @@ statement forms. - `owner` _str_ - Full name of the vehicle owner. - `source` _str, optional_ - The source of the asset, defaults to 'vehicle'. -#### year\_make\_model + + +### year\_make\_model + +```python +def year_make_model(separator: str = " / ") -> str +``` Returns a string of the format year/make/model of the vehicle. Triggers gathering those attributes. -**Arguments**: +#### Arguments separator \{str\} (Optional) The separator between the year, make and model. -**Returns**: +#### Returns A string of the format year/make/model of the vehicle. + + ## ALVehicleList Objects ```python @@ -497,6 +752,8 @@ class ALVehicleList(ALAssetList) List of ALVehicles. Extends ALAssetList. + + ## ALSimpleValue Objects ```python @@ -506,14 +763,20 @@ class ALSimpleValue(DAObject) Represents a currency value. It's meant to be stored in a list. Can be an item in an ALSimpleValueList. -**Attributes**: +#### Attributes .value \{str | float \} The monetary value of the item. .transaction_type \{str\} (Optional) Can be "expense", which will give a negative value to the total of the item. .source \{str\} (Optional) The "source" of the item, like "vase". -#### total + + +### total + +```python +def total() -> Decimal +``` If desired, to use as a ledger, values can be signed (mixed positive and negative). Setting transaction_type = 'expense' makes the value negative. @@ -522,10 +785,18 @@ Use min=0 in that case. If you use signed values, be careful when placing in an ALIncomeList object. The `total()` method may return unexpected results in that case. -#### \_\_str\_\_ + + +### \_\_str\_\_ + +```python +def __str__() -> str +``` Returns the total as a formatted string + + ## ALSimpleValueList Objects ```python @@ -534,16 +805,31 @@ class ALSimpleValueList(DAList) Represents a filterable DAList of ALSimpleValues. -#### sources + + +### sources + +```python +def sources() -> Set +``` Returns a set of the unique sources of values stored in the list. -#### total + + +### total + +```python +def total(source: Optional[SourceType] = None, + exclude_source: Optional[SourceType] = None) -> Decimal +``` Returns the total value in the list, gathering the list items if necessary. You can filter the values by `source`. `source` can be a string or a list. + + ## ALItemizedValue Objects ```python @@ -558,7 +844,7 @@ WARNING: This item's period-based value can't be calculated correctly outside of an ALItemizedJob. Its value should only be accessed through the filtering methods of the ALItemizedJob that contains it. -**Attributes**: +#### Attributes .value \{float | Decimal\} A number representing an amount of money accumulated during the `times_per_year` of this item or this item's job. @@ -572,15 +858,29 @@ filtering methods of the ALItemizedJob that contains it. If the ".exists" attribute is False or undefined, the item will not be used when calculating totals. -#### income\_fields + + +### income\_fields + +```python +def income_fields(use_exists=True) -> List[Dict[str, Any]] +``` Returns a YAML structure representing the list of fields for an itemized value, to be passed to a `code` attribute of a question's fields -#### \_\_str\_\_ + + +### \_\_str\_\_ + +```python +def __str__() -> str +``` Returns a string of the value of the item with two decimal places. + + ## ALItemizedValueDict Objects ```python @@ -596,7 +896,13 @@ and one for deductions. WARNING: Should only be accessed through an ALItemizedJob. Otherwise you may get unexpected results. -#### hook\_after\_gather + + +### hook\_after\_gather + +```python +def hook_after_gather() -> None +``` Update item lists after they've been gathered or edited to remove non-existent items. Will still allow the developer to set `auto_gather=False` if they @@ -606,11 +912,19 @@ 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:` -#### \_\_str\_\_ + + +### \_\_str\_\_ + +```python +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 ```python @@ -636,7 +950,7 @@ If the financial statement only requires "gross" and "net" i ALJobList has a simpler API and may be the preferred way to represent the income in code. -**Attributes**: +#### Attributes .to_add \{ALItemizedValueDict\} Dict of ALItemizedValues that would be added to a job's net total, like wages and tips. @@ -670,55 +984,99 @@ 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 + + +### total + +```python +def total(times_per_year: float = 1, + source: Optional[SourceType] = None, + exclude_source: Optional[SourceType] = None) -> Decimal +``` Alias for ALItemizedJob.gross_total to integrate with ALIncomeList math. -#### gross\_total + + +### gross\_total + +```python +def gross_total(times_per_year: float = 1, + source: Optional[SourceType] = None, + exclude_source: Optional[SourceType] = None) -> Decimal +``` Returns the sum of positive values (payments) for a given times_per_year. You can filter the items by `source`. `source` can be a string or a list. If you use sources from deductions, they will be ignored. -**Arguments**: +#### Arguments - `kwarg` - times_per_year \{float\} (Optional) Number of times per year you want to calculate. E.g, to express a weekly period, use 52. Default is 1. - `kwarg` - source \{str | [str]\} (Optional) Source or list of sources of desired item(s). -#### deduction\_total + + +### deduction\_total + +```python +def deduction_total(times_per_year: float = 1, + source: Optional[SourceType] = None, + exclude_source: Optional[SourceType] = None) -> Decimal +``` Returns the sum of money going out (normally, deductions like union dues) divided by a pay times_per_year as a positive value. You can filter the items by `source`. `source` can be a string or a list. -**Arguments**: +#### Arguments - `kwarg` - times_per_year \{float\} (Optional) Number of times per year you want to calculate. E.g, to express a weekly period, use 52. Default is 1. - `kwarg` - source \{str | List[str]\} (Optional) Source or list of sources of desired item(s). -#### net\_total + + +### net\_total + +```python +def net_total(times_per_year: float = 1, + source: Optional[SourceType] = None, + exclude_source: Optional[SourceType] = None) -> Decimal +``` Returns the net (gross minus deductions) value of the job divided by `times_per_year`. You can filter the items by `source`. `source` can be a string or a list. E.g. "full time" or ["full time", "union dues"] -**Arguments**: +#### Arguments - `kwarg` - times_per_year \{float\} (Optional) Number of times per year you want to calculate. E.g, to express a weekly period, use 52. Default is 1. - `kwarg` - source \{str | List[str]\} (Optional) Source or list of sources of desired item(s). -#### employer\_name\_address\_phone + + +### employer\_name\_address\_phone + +```python +def employer_name_address_phone() -> str +``` Returns concatenation of employer name and, if they exist, employer address and phone number. -#### normalized\_hours + + +### normalized\_hours + +```python +def normalized_hours(times_per_year: float = 1) -> float +``` Returns the normalized number of hours worked in a given times_per_year, based on the self.hours_per_period and self.times_per_year attributes. @@ -726,6 +1084,8 @@ based on the self.hours_per_period and self.times_per_year attributes. For example, if the person works 10 hours a week, it will return 520 when the times_per_year parameter is 1. + + ## ALItemizedJobList Objects ```python @@ -735,23 +1095,45 @@ 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 + + +### sources + +```python +def sources(which_side: Optional[str] = None) -> Set[str] +``` Returns a set of the unique sources in all of the jobs. By default gets from both sides, if which_side is "deductions", only gets from deductions. -#### total + + +### total + +```python +def total(times_per_year: float = 1, + source: Optional[SourceType] = None, + exclude_source: Optional[SourceType] = None) -> Decimal +``` Alias for ALItemizedJobList.gross_total to integrate with ALIncomeList math. -#### gross\_total + + +### gross\_total + +```python +def gross_total(times_per_year: float = 1, + source: Optional[SourceType] = None, + exclude_source: Optional[SourceType] = None) -> Decimal +``` Returns the sum of the gross incomes of the list's jobs divided by the times_per_year. You can filter the items by `source`. `source` can be a string or a list. -**Arguments**: +#### Arguments - `kwarg` - source \{str | [str]\} - (Optional) Source or list of sources of desired job items to sum from every itemized job. @@ -759,13 +1141,21 @@ string or a list. - `kwarg` - times_per_year \{float\} (Optional) Number of times per year you want to calculate. E.g, to express a weekly period, use 52. Default is 1. -#### deduction\_total + + +### deduction\_total + +```python +def deduction_total(times_per_year: float = 1, + source: Optional[SourceType] = None, + exclude_source: Optional[SourceType] = None) -> Decimal +``` Returns the sum of the deductions of the list's jobs divided by the times_per_year. You can filter the items by `source`. `source` can be a string or a list. -**Arguments**: +#### Arguments - `kwarg` - source \{str | [str]\} - (Optional) Source or list of sources of desired job items to sum from every itemized job. @@ -773,13 +1163,21 @@ string or a list. - `kwarg` - times_per_year \{float\} (Optional) Number of times per year you want to calculate. E.g, to express a weekly period, use 52. Default is 1. -#### net\_total + + +### net\_total + +```python +def net_total(times_per_year: float = 1, + source: Optional[SourceType] = None, + exclude_source: Optional[SourceType] = None) -> Decimal +``` Returns the net of the list's jobs (money in minus money out) divided by the times_per_year. You can filter the items by `source`. `source` can be a string or a list. -**Arguments**: +#### Arguments - `kwarg` - source \{str | List[str]\} - (Optional) Source or list of sources of desired job items to sum from every itemized job. diff --git a/docs/components/ALToolbox/business_days.md b/docs/components/ALToolbox/business_days.md index 04e46c571..0ee57f76c 100644 --- a/docs/components/ALToolbox/business_days.md +++ b/docs/components/ALToolbox/business_days.md @@ -1,9 +1,25 @@ ---- -sidebar_label: business_days -title: ALToolbox.business_days ---- +# ALToolbox.business_days -#### standard\_holidays +* [ALToolbox.business\_days](#ALToolbox.business_days) + * [standard\_holidays](#ALToolbox.business_days.standard_holidays) + * [is\_business\_day](#ALToolbox.business_days.is_business_day) + * [get\_next\_business\_day](#ALToolbox.business_days.get_next_business_day) + * [get\_date\_after\_n\_business\_days](#ALToolbox.business_days.get_date_after_n_business_days) + + + + +### standard\_holidays + +```python +def standard_holidays( + year, + country="US", + subdiv="MA", + add_holidays: Optional[Mapping] = None, + remove_holidays: Optional[Iterable[str]] = None +) -> holidays.HolidayBase +``` Get all holidays in the specified year, country, and state (or other subdivision). Note that this draws on the "holidays" package which may deviate slightly from @@ -24,7 +40,17 @@ the keys are datetime.date objects. \} ``` -#### is\_business\_day + + +### is\_business\_day + +```python +def is_business_day(date: Union[str, DADateTime], + country="US", + subdiv="MA", + add_holidays: Optional[Mapping] = None, + remove_holidays: Optional[Iterable[str]] = None) -> bool +``` Returns true if and only if the specified date is a business day (i.e., not a holiday) in the specified jurisdiction. Business days are considered to be: @@ -37,7 +63,19 @@ in the specified jurisdiction. Business days are considered to be: assert(is_business_day("2023-03-26") == False) ``` -#### get\_next\_business\_day + + +### get\_next\_business\_day + +```python +def 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) -> DADateTime +``` Returns the first day AFTER the specified start date that is not a federal or state holiday, Saturday or Sunday. Optionally, @@ -49,7 +87,7 @@ holidays around the world and in various states and provinces, but local court rules may differ. You can see what holidays are used at https://github.com/dr-prodigy/python-holidays/tree/master/holidays/countries -**Arguments**: +#### Arguments - `start_date` - the date to start with. Can be a date-formatted string (i.e. "2023-03-37", or "3-27-2023") or a DADateTime object @@ -61,11 +99,23 @@ https://github.com/dr-prodigy/python-holidays/tree/master/holidays/countries will add those holidays to be considered - `remove_holidays` - the list of date strings ("12/25") of dates that are no longer holidays -#### get\_date\_after\_n\_business\_days + + +### get\_date\_after\_n\_business\_days + +```python +def 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) -> DADateTime +``` Returns a time period which contains a minimum of `n` business days. -**Arguments**: +#### Arguments - `start_date` - the date to start with. Can be a date-formatted string (i.e. "2023-03-37", or "3-27-2023") or a DADateTime object diff --git a/docs/components/ALToolbox/copy_button.md b/docs/components/ALToolbox/copy_button.md index 9e55cc063..c37110d7f 100644 --- a/docs/components/ALToolbox/copy_button.md +++ b/docs/components/ALToolbox/copy_button.md @@ -1,15 +1,30 @@ ---- -sidebar_label: copy_button -title: ALToolbox.copy_button ---- +# ALToolbox.copy_button -#### copy\_button\_html +* [ALToolbox.copy\_button](#ALToolbox.copy_button) + * [copy\_button\_html](#ALToolbox.copy_button.copy_button_html) + + + + +### copy\_button\_html + +```python +def 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 = "") -> str +``` Return the html for a button that will let a user copy the given text To use, include `docassemble.ALToolbox:copy_button.yml` in your DA interview. -**Arguments**: +#### Arguments - `text_to_copy` - text you want the user to be able to copy. - `text_before` - the prompt that will appear to the left of the HTML input diff --git a/docs/components/ALToolbox/llms.md b/docs/components/ALToolbox/llms.md index 62ba91373..66e481fdb 100644 --- a/docs/components/ALToolbox/llms.md +++ b/docs/components/ALToolbox/llms.md @@ -1,15 +1,57 @@ ---- -sidebar_label: llms -title: ALToolbox.llms ---- +# 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) + * [classify\_text](#ALToolbox.llms.classify_text) + * [synthesize\_user\_responses](#ALToolbox.llms.synthesize_user_responses) + * [define\_fields\_from\_dict](#ALToolbox.llms.define_fields_from_dict) + * [Goal](#ALToolbox.llms.Goal) + * [response\_satisfies\_me\_or\_follow\_up](#ALToolbox.llms.Goal.response_satisfies_me_or_follow_up) + * [get\_next\_question](#ALToolbox.llms.Goal.get_next_question) + * [GoalDict](#ALToolbox.llms.GoalDict) + * [satisfied](#ALToolbox.llms.GoalDict.satisfied) + * [GoalQuestion](#ALToolbox.llms.GoalQuestion) + * [GoalSatisfactionList](#ALToolbox.llms.GoalSatisfactionList) + * [mark\_satisfied\_goals](#ALToolbox.llms.GoalSatisfactionList.mark_satisfied_goals) + * [keep\_going](#ALToolbox.llms.GoalSatisfactionList.keep_going) + * [need\_more\_questions](#ALToolbox.llms.GoalSatisfactionList.need_more_questions) + * [satisfied](#ALToolbox.llms.GoalSatisfactionList.satisfied) + * [get\_next\_goal\_and\_question](#ALToolbox.llms.GoalSatisfactionList.get_next_goal_and_question) + * [synthesize\_draft\_response](#ALToolbox.llms.GoalSatisfactionList.synthesize_draft_response) + * [provide\_feedback](#ALToolbox.llms.GoalSatisfactionList.provide_feedback) + * [IntakeQuestion](#ALToolbox.llms.IntakeQuestion) + * [IntakeQuestionList](#ALToolbox.llms.IntakeQuestionList) + * [need\_more\_questions](#ALToolbox.llms.IntakeQuestionList.need_more_questions) + + + + +### chat\_completion -#### chat\_completion +```python +def 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 +) -> Union[List[Any], Dict[str, Any], str] +``` A light wrapper on the OpenAI chat endpoint. Includes support for token limits, minimal error handling, and moderation. -**Arguments**: +#### Arguments - `system_message` _str_ - The role the chat engine should play - `user_message` _str_ - The message (data) from the user @@ -25,43 +67,78 @@ Includes support for token limits, minimal error handling, and moderation. - `max_input_tokens` _Optional[int]_ - The maximum number of tokens to send to the API. Defaults to 128000. -**Returns**: +#### Returns A string with the response from the API endpoint or JSON data if json_mode is True -#### extract\_fields\_from\_text + + +### extract\_fields\_from\_text + +```python +def 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") -> Dict[str, Any] +``` Extracts fields from text. -**Arguments**: +#### Arguments - `text` _str_ - The text to extract fields from - `field_list` _Dict[str,str]_ - A list of fields to extract, with the key being the field name and the value being a description of the field -**Returns**: +#### Returns A dictionary of fields extracted from the text -#### match\_goals\_from\_text + + +### match\_goals\_from\_text + +```python +def 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") -> Dict[str, Any] +``` Reads a user's message and determines whether it meets a set of goals, with the help of an LLM. -**Arguments**: +#### Arguments - `text` _str_ - The text to extract goals from - `field_list` _Dict[str,str]_ - A list of goals to extract, with the key being the goal name and the value being a description of the goal -**Returns**: +#### Returns A dictionary of fields extracted from the text -#### classify\_text + + +### classify\_text + +```python +def 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") -> str +``` Given a text, classify it into one of the provided choices with the assistance of a large language model. -**Arguments**: +#### Arguments - `text` _str_ - The text to classify - `choices` _Dict[str,str]_ - A list of choices to classify the text into, with the key being the choice name and the value being a description of the choice @@ -70,12 +147,23 @@ Given a text, classify it into one of the provided choices with the assistance o - `temperature` _float_ - The temperature to use for GPT. Defaults to 0. - `model` _str_ - The model to use for the GPT API -#### synthesize\_user\_responses + + +### synthesize\_user\_responses + +```python +def 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") -> str +``` Given a first draft and a series of follow-up questions and answers, use an LLM to synthesize the user's responses into a single, coherent reply. -**Arguments**: +#### Arguments - `custom_instructions` _str_ - Custom instructions for the LLM to follow in constructing the synthesized response - `initial_draft` _str_ - The initial draft of the response from the user @@ -85,13 +173,20 @@ into a single, coherent reply. - `temperature` _float_ - The temperature to use for GPT. Defaults to 0. - `model` _str_ - The model to use for the GPT API -#### define\_fields\_from\_dict + + +### define\_fields\_from\_dict + +```python +def define_fields_from_dict(field_dict: Dict[str, Any], + fields_to_ignore: Optional[List] = None) -> None +``` Assigns the values in a dictionary of fields to the corresponding fields in a Docassemble interview. Docassemble and built-in keywords are never defined by this function. If fields_to_ignore is provided, those fields will also be ignored. -**Arguments**: +#### Arguments - `field_dict` _Dict[str, Any]_ - A dictionary of fields to define, with the key being the field name and the value presumably taken from the output of extract_fields_from_text. @@ -99,10 +194,12 @@ Docassemble and built-in keywords are never defined by this function. If fields_ safety when defining fields from untrusted sources. E.g., ["user_is_logged_in"] -**Returns**: +#### Returns None + + ## Goal Objects ```python @@ -111,30 +208,52 @@ class Goal(DAObject) A class to represent a goal. -**Attributes**: +#### Attributes - `name` _str_ - The name of the goal - `description` _str_ - A description of the goal - `satisfied` _bool_ - Whether the goal is satisfied -#### response\_satisfies\_me\_or\_follow\_up + + +### response\_satisfies\_me\_or\_follow\_up + +```python +def 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") -> str +``` Returns the text of the next question to ask the user or the string "satisfied" if the user's response satisfies the goal. -**Arguments**: +#### Arguments - `response` _str_ - The response to check -**Returns**: +#### Returns True if the response satisfies the goal, False otherwise -#### get\_next\_question + + +### get\_next\_question + +```python +def get_next_question(thread_so_far: List[Dict[str, str]], + openai_client: Optional[OpenAI] = None, + model="gpt-4o-mini") -> str +``` Returns the text of the next question to ask the user. + + ## GoalDict Objects ```python @@ -143,10 +262,18 @@ class GoalDict(DADict) A class to represent a DADict of Goals. -#### satisfied + + +### satisfied + +```python +def satisfied() +``` Returns True if all goals are satisfied, False otherwise. + + ## GoalQuestion Objects ```python @@ -155,12 +282,14 @@ class GoalQuestion(DAObject) A class to represent a question about a goal. -**Attributes**: +#### Attributes - `goal` _Goal_ - The goal the question is about - `question` _str_ - The question to ask the user - `response` _str_ - The user's response to the question + + ## GoalSatisfactionList Objects ```python @@ -187,7 +316,7 @@ open ai: key: sk-... ``` -**Attributes**: +#### Attributes - `goals` _List[Goal]_ - The goals in the list, provided as a dictionary - `goal_list` _GoalList_ - The list of Goals @@ -196,47 +325,91 @@ 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 + +```python +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. -**Returns**: +#### Returns None -#### keep\_going + + +### keep\_going + +```python +def keep_going() +``` Returns 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 + +```python +def need_more_questions() +``` Returns True if there is at least one unsatisfied goal, False otherwise. Also has the side effect of checking the user's most recent response to see if it satisfies the goal and updating the next question to be asked. -#### satisfied + + +### satisfied + +```python +def satisfied() +``` Returns True if all goals are satisfied, False otherwise. -#### get\_next\_goal\_and\_question + + +### get\_next\_goal\_and\_question + +```python +def get_next_goal_and_question() +``` Returns the next unsatisfied goal, along with a follow-up question to ask the user, if relevant. -**Returns**: +#### Returns 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 + +```python +def synthesize_draft_response() +``` Returns a draft response that synthesizes the user's responses to the questions. -#### provide\_feedback + + +### provide\_feedback + +```python +def provide_feedback(feedback_prompt: str = "") +``` Returns feedback to the user based on the goals they satisfied. + + ## IntakeQuestion Objects ```python @@ -245,11 +418,13 @@ class IntakeQuestion(DAObject) A class to represent a question in an LLM-assisted intake questionnaire. -**Attributes**: +#### Attributes - `question` _str_ - The question to ask the user - `response` _str_ - The user's response to the question + + ## IntakeQuestionList Objects ```python @@ -266,7 +441,7 @@ enough information to determine if the user meets the criteria. In/out criteria are often pretty short, so we do not make or support embeddings at the moment. -**Attributes**: +#### Attributes - `criteria` _Dict[str, str]_ - A dictionary of criteria to match, indexed by problem type - `problem_type_descriptions` _Dict[str, str]_ - A dictionary of descriptions of the problem types @@ -282,7 +457,13 @@ 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 + +```python +def need_more_questions() +``` Returns True if the user needs to answer more questions, False otherwise. diff --git a/docs/components/ALToolbox/misc.md b/docs/components/ALToolbox/misc.md index 08a8db4c3..6e270b74f 100644 --- a/docs/components/ALToolbox/misc.md +++ b/docs/components/ALToolbox/misc.md @@ -1,9 +1,36 @@ ---- -sidebar_label: misc -title: ALToolbox.misc ---- - -#### thousands +# ALToolbox.misc + +* [ALToolbox.misc](#ALToolbox.misc) + * [thousands](#ALToolbox.misc.thousands) + * [tel](#ALToolbox.misc.tel) + * [fa\_icon](#ALToolbox.misc.fa_icon) + * [space](#ALToolbox.misc.space) + * [yes\_no\_unknown](#ALToolbox.misc.yes_no_unknown) + * [number\_to\_letter](#ALToolbox.misc.number_to_letter) + * [collapse\_template](#ALToolbox.misc.collapse_template) + * [tabbed\_templates\_html](#ALToolbox.misc.tabbed_templates_html) + * [review\_widget](#ALToolbox.misc.review_widget) + * [sum\_if\_defined](#ALToolbox.misc.sum_if_defined) + * [add\_records](#ALToolbox.misc.add_records) + * [output\_checkbox](#ALToolbox.misc.output_checkbox) + * [nice\_county\_name](#ALToolbox.misc.nice_county_name) + * [button\_array](#ALToolbox.misc.button_array) + * [none\_to\_empty](#ALToolbox.misc.none_to_empty) + * [option\_or\_other](#ALToolbox.misc.option_or_other) + * [true\_values\_with\_other](#ALToolbox.misc.true_values_with_other) + * [include\_a\_year](#ALToolbox.misc.include_a_year) + * [is\_leap\_year](#ALToolbox.misc.is_leap_year) + * [age\_in\_years](#ALToolbox.misc.age_in_years) + * [format\_date\_if\_defined](#ALToolbox.misc.format_date_if_defined) + + + + +### thousands + +```python +def thousands(num: Union[float, str, Decimal], show_decimals=False) -> str +``` Return a whole number formatted with thousands separator. Optionally, format with 2 decimal points (for a PDF form with the @@ -12,11 +39,28 @@ currency symbol already present in the form) If `show_decimals`, will call `int(num)`, truncating the decimals instead of rounding to the closest int. -#### tel + + +### tel + +```python +def tel(phone_number) -> str +``` Format a phone number so you can click on it to open in your phone dialer -#### fa\_icon + + +### fa\_icon + +```python +def 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) -> str +``` Display a fontawesome icon inline. @@ -24,7 +68,7 @@ Docassemble allows you to display an icon from [fontawesome](https://fontawesome but it does not provide control over the size or color of the icon. This function gives you more control over the icon that is inserted. -**Arguments**: +#### Arguments - `icon` - a string representing a fontawesome icon. The icon needs to be in the [free library](https://fontawesome.com/search?o=r&m=free). @@ -39,27 +83,58 @@ you more control over the icon that is inserted. - `aria_hidden` - if True, adds `aria-hidden="true"` to the icon, which is the default -**Returns**: +#### Returns HTML for a font-awesome icon of the specified size and color. -#### space + + +### space + +```python +def space(var_name: str, prefix=" ", suffix="") -> str +``` If the value as a string is defined, return it prefixed/suffixed. Defaults to prefix of a space. Helps build a sentence with less cruft. Equivalent to SPACE function in HotDocs. -#### yes\_no\_unknown + + +### yes\_no\_unknown + +```python +def yes_no_unknown(var_name: str, + condition: Optional[bool], + unknown="Unknown", + placeholder=0) +``` Return 'unknown' if the value is None rather than False. Helper for PDF filling with yesnomaybe fields -#### number\_to\_letter + + +### number\_to\_letter + +```python +def number_to_letter(n: Optional[int]) -> str +``` Returns a capital letter representing ordinal position. E.g., 1=A, 2=B, etc. Appends letters once you reach 26 in a way compatible with Excel/Google Sheets column naming conventions. 27=AA, 28=AB... -#### collapse\_template + + +### collapse\_template + +```python +def collapse_template(template: DALazyTemplate, + classname: str | None = None, + closed_icon: str = "caret-right", + open_icon: str = "caret-down", + collapsed: bool = True) -> str +``` Insert HTML for a Bootstrap "collapse" div. @@ -68,11 +143,32 @@ Optionally, you can specify a custom icon to override the defaults: The default icons are "right caret" which displays when the text is collapsed (`closed_icon`) and "down caret" which displays when the text is open (`open_icon`). -#### tabbed\_templates\_html + + +### tabbed\_templates\_html + +```python +def tabbed_templates_html(tab_group_name: str, *pargs) -> str +``` Provided a list of templates, create Bootstrap v 4.5 tabs with the `subject` as the tab label. -#### review\_widget + + +### review\_widget + +```python +def 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!") -> str +``` A widget that allows people to give a quick review (thumbs up and down, with an optional text component) in the middle of an interview without triggering a page reload. @@ -81,7 +177,7 @@ If `review_action` is provided, once you press either of the thumbs, a text inpu a submit button appears, and once the text review is submitted (or after the thumbs, if no `review_action` was provided), a final "thank you" message is displayed. -**Arguments**: +#### Arguments - `up_action` - the variable name of an event to be executed on the server if the thumbs up is pressed @@ -94,34 +190,68 @@ a submit button appears, and once the text review is submitted (or after the thu - `submit_review_button` - text on the button to submit their text review - `post_review_display` - text displayed to user after review is submitted -**Returns**: +#### Returns the HTML string of the widget -#### sum\_if\_defined + + +### sum\_if\_defined + +```python +def sum_if_defined(*pargs) +``` Lets you add up the value of variables that are not in a list -#### add\_records + + +### add\_records + +```python +def add_records(obj, labels) +``` List demo interviews in the current package to be run from the landing page -#### output\_checkbox + + +### output\_checkbox + +```python +def output_checkbox(value_to_check: bool, + checked_value: str = "[X]", + unchecked_value: str = "[ ]") +``` Generate a conditional checkbox for docx templates -**Arguments**: +#### Arguments - `checked_value` - defaults to `[X]` but can be set to any string or even a `DAFile` or `DAStaticFile` with the image of a checkbox - `unchecked_value` - opposite meaning of `checked_value` and defaults to `[ ]` -#### nice\_county\_name + + +### nice\_county\_name + +```python +def nice_county_name(address: Address) -> str +``` If the county name contains the word "County", which Google Address Autocomplete does by default, remove it. -#### button\_array + + +### button\_array + +```python +def button_array(buttons: List[ButtonDict], + custom_container_class="", + custom_link_class="") -> str +``` Create a grid of da-buttons from a dictionary of links and icons @@ -132,7 +262,7 @@ on any page of an interview in the `subquestion` area. Optionally, you can limit access to paricular buttons by specifying a privilege or a list of privileges. -**Arguments**: +#### Arguments - `button_list` - a dictionary of ButtonDicts (or plain dictionaries) with the following keys: - `name`: the text to display on the button @@ -144,11 +274,17 @@ of privileges. - `custom_link_class` - optional, a string of additional CSS classes to add to each link -**Returns**: +#### Returns HTML for a grid of buttons -#### none\_to\_empty + + +### none\_to\_empty + +```python +def none_to_empty(val: Any) +``` If the value is None or "None", return a DAEmpty value. Otherwise return the value. @@ -158,45 +294,66 @@ when handling a radio button that is not required and left unanswered. A DAEmpty value appears as an empty string in the output. You can also safely transform it or use any method on it without raising an error. -**Arguments**: +#### Arguments - `val` - the value to check -**Returns**: +#### Returns a DAEmpty if the value is None, otherwise the value -#### option\_or\_other + + +### option\_or\_other + +```python +def option_or_other(variable_name: str, + other_variable_name: Optional[str] = None) -> str +``` If the variable is set to 'Other', return the value of the 'other' variable. Otherwise return the value of the variable. This is useful for filling in a template and to prevent the word 'Other' from appearing in the output. -**Arguments**: +#### Arguments - `variable_name` - the name of the variable to check - `other_variable_name` - the name of the variable to return if the value of the first variable is 'Other' -**Returns**: +#### Returns the value of the variable if it is not 'Other', otherwise the value of the other variable -#### true\_values\_with\_other + + +### true\_values\_with\_other + +```python +def true_values_with_other( + variable_name: str, + other_variable_name: Optional[str] = None) -> List[str] +``` Return a list of values that are True, with the value of the 'other' variable appended to the end of the list. This is useful for filling in a template and to prevent the word 'Other' from appearing in the output. -**Arguments**: +#### Arguments - `variable` - the dictionary of variables to check - `other_variable_name` - the name of the variable (as a string) to return if the value of the first variable is 'Other' -**Returns**: +#### Returns a list of values that are True, with the value of the 'other' variable appended to the end of the list. -#### include\_a\_year + + +### include\_a\_year + +```python +def include_a_year(text: str, field: Optional[str] = None) -> bool +``` Validates whether the input text contains at least one 4-digit sequence that occurs within a range of ~ 200 years, indicating a valid "year" @@ -205,37 +362,58 @@ or a moving date. Returns True if found, otherwise raises a DAValidationError. -#### is\_leap\_year + + +### is\_leap\_year + +```python +def is_leap_year(year: int) -> bool +``` Helper function for `age_in_years` to determine if a year is a leap year. -**Arguments**: +#### Arguments - `year` - The year to check. -**Returns**: +#### Returns True if the year is a leap year, False otherwise. -#### age\_in\_years + + +### age\_in\_years + +```python +def age_in_years(the_date: Union[str, DADateTime]) -> int +``` Calculate the age in years from a date (treated like a date of birth). -**Arguments**: +#### Arguments - `the_date` - A string or DADateTime object representing the date of birth. -**Returns**: +#### Returns The age in years as an integer. -#### format\_date\_if\_defined + + +### format\_date\_if\_defined + +```python +def format_date_if_defined(date_object_name: str, + *pargs, + default: str = "", + **kwargs) -> str +``` Format a date string if it is defined, otherwise return an empty string. Passes all additional arguments to the `format_date` function. -**Arguments**: +#### Arguments - `date_object_name` - The date string to format. - `*pargs` - Additional positional arguments to pass to `format_date`. @@ -243,7 +421,7 @@ Passes all additional arguments to the `format_date` function. - `**kwargs` - Additional keyword arguments to pass to `format_date`. E.g., format="yyyy-MM-dd" -**Returns**: +#### Returns A formatted date string if `date_object_name` is defined, otherwise an empty string. diff --git a/docs/components/ALToolbox/save_input_data.md b/docs/components/ALToolbox/save_input_data.md index 14affdefc..9d3e5bca0 100644 --- a/docs/components/ALToolbox/save_input_data.md +++ b/docs/components/ALToolbox/save_input_data.md @@ -1,9 +1,18 @@ ---- -sidebar_label: save_input_data -title: ALToolbox.save_input_data ---- +# ALToolbox.save_input_data -#### save\_input\_data +* [ALToolbox.save\_input\_data](#ALToolbox.save_input_data) + * [save\_input\_data](#ALToolbox.save_input_data.save_input_data) + + + + +### save\_input\_data + +```python +def save_input_data(title: str = "", + input_dict: Optional[Dict[str, Any]] = None, + tags: Optional[List[str]] = None) -> None +``` This function is used by survey type interviews to save input data for data reporting purposes. diff --git a/docs/components/AssemblyLine/al_courts.md b/docs/components/AssemblyLine/al_courts.md index 5a32190b5..d5a5b098e 100644 --- a/docs/components/AssemblyLine/al_courts.md +++ b/docs/components/AssemblyLine/al_courts.md @@ -1,10 +1,30 @@ ---- -sidebar_label: al_courts -title: AssemblyLine.al_courts ---- +# 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) + * [short\_label\_and\_address](#AssemblyLine.al_courts.ALCourt.short_label_and_address) + * [short\_description](#AssemblyLine.al_courts.ALCourt.short_description) + * [from\_row](#AssemblyLine.al_courts.ALCourt.from_row) + * [geolocate](#AssemblyLine.al_courts.ALCourt.geolocate) + * [geocode](#AssemblyLine.al_courts.ALCourt.geocode) + * [ALCourtLoader](#AssemblyLine.al_courts.ALCourtLoader) + * [init](#AssemblyLine.al_courts.ALCourtLoader.init) + * [all\_courts](#AssemblyLine.al_courts.ALCourtLoader.all_courts) + * [unique\_column\_values](#AssemblyLine.al_courts.ALCourtLoader.unique_column_values) + * [county\_list](#AssemblyLine.al_courts.ALCourtLoader.county_list) + * [county\_has\_one\_court](#AssemblyLine.al_courts.ALCourtLoader.county_has_one_court) + * [county\_court](#AssemblyLine.al_courts.ALCourtLoader.county_court) + * [matching\_courts\_in\_county](#AssemblyLine.al_courts.ALCourtLoader.matching_courts_in_county) + * [filter\_courts](#AssemblyLine.al_courts.ALCourtLoader.filter_courts) + * [as\_court](#AssemblyLine.al_courts.ALCourtLoader.as_court) + Package for a very simple / MVP list of courts that is mostly signature compatible w/ MACourts for now + + ## ALCourt Objects ```python @@ -18,67 +38,112 @@ 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 + + +### init + +```python +def init(*pargs, **kwargs) -> None +``` Create a new court object. -**Arguments**: +#### Arguments - `*pargs` - Standard DAObject positional arguments - `**kwargs` - Standard DAObject keyword arguments -#### short\_label + + +### short\_label + +```python +def short_label() -> str +``` Returns a string that represents a nice, disambiguated label for the court. This may not match the court's name. If the name omits city, we append city name to the court name. This is good for a drop-down selection list. -**Returns**: +#### Returns - `str` - string representing the court's name, with city if needed to disambiguate -#### short\_label\_and\_address + + +### short\_label\_and\_address + +```python +def short_label_and_address() -> str +``` Returns a markdown formatted string with the name and address of the court. More concise version without description; suitable for a responsive case. -**Returns**: +#### Returns - `str` - string representing the court's name and address -#### short\_description + + +### short\_description + +```python +def short_description() -> str +``` Returns a Markdown formatted string that includes the disambiguated name and the description of the court, for inclusion in the results page with radio buttons. -**Returns**: +#### Returns - `str` - string representing the court's name and description -#### from\_row + + +### from\_row + +```python +def from_row(df_row: Union[pd.Series, pd.DataFrame], + ensure_lat_long: bool = True) -> None +``` Loads data from a single Pandas Dataframe into the current court object. Note: It will try to convert column names that don't make valid attributes. Best practice is to use good attribute names (no spaces) that don't interfere with existing attributes or methods of DAObject -**Arguments**: +#### Arguments - `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 + +```python +def geolocate() -> None +``` Use Google Maps to geocode the court's address and store the result in the location attribute. Deprecated: use geocode() instead. -#### geocode + + +### geocode + +```python +def geocode() -> None +``` Use Google Maps to geocode the court's address and store the result in the location attribute. + + ## ALCourtLoader Objects ```python @@ -89,79 +154,118 @@ Object to hold some methods surrounding loading/filtering courts. Built around Pandas dataframe. -**Attributes**: +#### Attributes - `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 + + +### init + +```python +def init(*pargs, **kwargs) -> None +``` Create a new courtloader object. -**Arguments**: +#### Arguments - `*pargs` - Standard DAObject positional arguments - `**kwargs` - Standard DAObject keyword arguments -#### all\_courts + + +### all\_courts + +```python +def all_courts() -> List[Dict[int, str]] +``` Return a list of all courts in the spreadsheet. -**Returns**: +#### Returns List[Dict[int, str]]: List of all ALCourt instances without filtering. -#### unique\_column\_values + + +### unique\_column\_values + +```python +def unique_column_values(column_name: str) -> Set[str] +``` Retrieve a set of unique values present in a specified dataframe column. -**Arguments**: +#### Arguments - `column_name` _str_ - The name of the column in the dataframe. -**Returns**: +#### Returns Set[str]: - 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 + + +### county\_list + +```python +def county_list(column_name: str = "address_county") -> Set[str] +``` Get a set of all unique names for the specified column in the given spreadsheet. Typically used to get a list of all possible counties that have a court. -**Arguments**: +#### Arguments - `column_name` _str_ - The name of the column in the dataframe. -**Returns**: +#### Returns - `Set[str]` - A list of all unique values in the specified row in the given spreadsheet -#### county\_has\_one\_court + + +### county\_has\_one\_court + +```python +def county_has_one_court(county_name: str, + county_column: str = "address_county") -> bool +``` Returns True if there is only one court associated with the specified county in the spreadsheet. Returns False otherwise. -**Arguments**: +#### Arguments - `county_name` _str_ - The name of the county to check. - `county_column` _str_ - The name of the column in the dataframe that contains the county names. Defaults to "address_county". -**Returns**: +#### Returns - `bool` - True if there is only one court associated with the specified county in the spreadsheet. -#### county\_court + + +### county\_court + +```python +def county_court(intrinsicName: str, + county_name: str, + county_column: str = "address_county") -> ALCourt +``` Return the first court matching the county name. Should only be used when you know there is exactly one match -**Arguments**: +#### Arguments - `intrinsicName` _str_ - The intrinsic name you want the newly returned object to have (used for DA namespace searching). - `county_name` _str_ - The name of the county to check. @@ -169,11 +273,23 @@ when you know there is exactly one match Defaults to "address_county". -**Returns**: +#### Returns - `ALCourt` - The first court matching the county name. -#### matching\_courts\_in\_county + + +### matching\_courts\_in\_county + +```python +def 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 +) -> List[Dict[int, str]] +``` Retrieve a list of all courts in the specified county. @@ -181,7 +297,7 @@ This function fetches courts suitable for displaying as a drop-down or radio but in Docassemble. The results are dictionaries where the key is the index in the dataframe, useful for retrieving the court's full details later using the as_court() method. -**Arguments**: +#### Arguments - `county_name` _str_ - Name of the county. - `county_column` _str, optional_ - Column heading which contains county name. Defaults to "address_county". @@ -191,18 +307,30 @@ useful for retrieving the court's full details later using the as_court() m the search_string in a case-insensitive manner. Defaults to None. -**Returns**: +#### Returns List[Dict[int, str]]: List of dictionaries representing matching courts. -#### filter\_courts + + +### filter\_courts + +```python +def 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 +) -> List[Dict[int, str]] +``` Return a filtered subset of courts represented as a list of dictionaries. Each dictionary has the format \{index: name\}, where "index" refers to the dataframe index and "name" is determined by the `display_column`. -**Arguments**: +#### Arguments - `court_types` _Optional[Union[List[str], str]]_ - Exact string match or matches used to filter results (inclusive). Examples include "District" or ["Municipal","Superior"]. @@ -213,22 +341,30 @@ is determined by the `display_column`. the search_string in a case-insensitive manner. Defaults to None. -**Returns**: +#### Returns List[Dict[int, str]]: List of dictionaries representing filtered courts. -#### as\_court + + +### as\_court + +```python +def as_court(intrinsicName: str, + index: Union[int, str], + ensure_lat_long: bool = True) -> ALCourt +``` Retrieve the court at the specified index as an ALCourt object. -**Arguments**: +#### Arguments - `intrinsicName` _str_ - The intrinsic name you want to assign to the returned object (used for DA namespace searching). - `index` _Union[int, str]_ - The index position of the court in the dataframe. - `ensure_lat_long` _bool, optional_ - Whether to ensure the presence of latitude and longitude data. Defaults to True. -**Returns**: +#### Returns - `ALCourt` - An ALCourt object initialized with data from the specified index. diff --git a/docs/components/AssemblyLine/al_document.md b/docs/components/AssemblyLine/al_document.md index 3719edc70..ac6b4e3af 100644 --- a/docs/components/AssemblyLine/al_document.md +++ b/docs/components/AssemblyLine/al_document.md @@ -1,9 +1,130 @@ ---- -sidebar_label: al_document -title: AssemblyLine.al_document ---- +# 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) + * [key](#AssemblyLine.al_document.key) + * [safeattr](#AssemblyLine.al_document.safeattr) + * [html\_safe\_str](#AssemblyLine.al_document.html_safe_str) + * [table\_row](#AssemblyLine.al_document.table_row) + * [pdf\_page\_parity](#AssemblyLine.al_document.pdf_page_parity) + * [add\_blank\_page](#AssemblyLine.al_document.add_blank_page) + * [ALAddendumField](#AssemblyLine.al_document.ALAddendumField) + * [init](#AssemblyLine.al_document.ALAddendumField.init) + * [overflow\_value](#AssemblyLine.al_document.ALAddendumField.overflow_value) + * [max\_lines](#AssemblyLine.al_document.ALAddendumField.max_lines) + * [value](#AssemblyLine.al_document.ALAddendumField.value) + * [has\_overflow](#AssemblyLine.al_document.ALAddendumField.has_overflow) + * [original\_or\_overflow\_message](#AssemblyLine.al_document.ALAddendumField.original_or_overflow_message) + * [safe\_value](#AssemblyLine.al_document.ALAddendumField.safe_value) + * [value\_if\_defined](#AssemblyLine.al_document.ALAddendumField.value_if_defined) + * [\_\_str\_\_](#AssemblyLine.al_document.ALAddendumField.__str__) + * [columns](#AssemblyLine.al_document.ALAddendumField.columns) + * [type](#AssemblyLine.al_document.ALAddendumField.type) + * [is\_list](#AssemblyLine.al_document.ALAddendumField.is_list) + * [is\_object\_list](#AssemblyLine.al_document.ALAddendumField.is_object_list) + * [overflow\_markdown](#AssemblyLine.al_document.ALAddendumField.overflow_markdown) + * [overflow\_docx](#AssemblyLine.al_document.ALAddendumField.overflow_docx) + * [ALAddendumFieldDict](#AssemblyLine.al_document.ALAddendumFieldDict) + * [init](#AssemblyLine.al_document.ALAddendumFieldDict.init) + * [initializeObject](#AssemblyLine.al_document.ALAddendumFieldDict.initializeObject) + * [from\_list](#AssemblyLine.al_document.ALAddendumFieldDict.from_list) + * [defined\_fields](#AssemblyLine.al_document.ALAddendumFieldDict.defined_fields) + * [overflow](#AssemblyLine.al_document.ALAddendumFieldDict.overflow) + * [has\_overflow](#AssemblyLine.al_document.ALAddendumFieldDict.has_overflow) + * [DALazyAttribute](#AssemblyLine.al_document.DALazyAttribute) + * [\_\_getstate\_\_](#AssemblyLine.al_document.DALazyAttribute.__getstate__) + * [ALDocument](#AssemblyLine.al_document.ALDocument) + * [init](#AssemblyLine.al_document.ALDocument.init) + * [as\_pdf](#AssemblyLine.al_document.ALDocument.as_pdf) + * [as\_docx](#AssemblyLine.al_document.ALDocument.as_docx) + * [as\_list](#AssemblyLine.al_document.ALDocument.as_list) + * [need\_addendum](#AssemblyLine.al_document.ALDocument.need_addendum) + * [has\_overflow](#AssemblyLine.al_document.ALDocument.has_overflow) + * [overflow](#AssemblyLine.al_document.ALDocument.overflow) + * [original\_or\_overflow\_message](#AssemblyLine.al_document.ALDocument.original_or_overflow_message) + * [safe\_value](#AssemblyLine.al_document.ALDocument.safe_value) + * [overflow\_value](#AssemblyLine.al_document.ALDocument.overflow_value) + * [is\_enabled](#AssemblyLine.al_document.ALDocument.is_enabled) + * [ALStaticDocument](#AssemblyLine.al_document.ALStaticDocument) + * [init](#AssemblyLine.al_document.ALStaticDocument.init) + * [\_\_getitem\_\_](#AssemblyLine.al_document.ALStaticDocument.__getitem__) + * [as\_list](#AssemblyLine.al_document.ALStaticDocument.as_list) + * [as\_pdf](#AssemblyLine.al_document.ALStaticDocument.as_pdf) + * [as\_docx](#AssemblyLine.al_document.ALStaticDocument.as_docx) + * [show](#AssemblyLine.al_document.ALStaticDocument.show) + * [is\_enabled](#AssemblyLine.al_document.ALStaticDocument.is_enabled) + * [ALDocumentBundle](#AssemblyLine.al_document.ALDocumentBundle) + * [init](#AssemblyLine.al_document.ALDocumentBundle.init) + * [as\_pdf](#AssemblyLine.al_document.ALDocumentBundle.as_pdf) + * [\_\_str\_\_](#AssemblyLine.al_document.ALDocumentBundle.__str__) + * [as\_zip](#AssemblyLine.al_document.ALDocumentBundle.as_zip) + * [preview](#AssemblyLine.al_document.ALDocumentBundle.preview) + * [has\_enabled\_documents](#AssemblyLine.al_document.ALDocumentBundle.has_enabled_documents) + * [enabled\_documents](#AssemblyLine.al_document.ALDocumentBundle.enabled_documents) + * [as\_flat\_list](#AssemblyLine.al_document.ALDocumentBundle.as_flat_list) + * [get\_titles](#AssemblyLine.al_document.ALDocumentBundle.get_titles) + * [as\_pdf\_list](#AssemblyLine.al_document.ALDocumentBundle.as_pdf_list) + * [as\_docx\_list](#AssemblyLine.al_document.ALDocumentBundle.as_docx_list) + * [as\_editable\_list](#AssemblyLine.al_document.ALDocumentBundle.as_editable_list) + * [get\_cacheable\_documents](#AssemblyLine.al_document.ALDocumentBundle.get_cacheable_documents) + * [download\_list\_html](#AssemblyLine.al_document.ALDocumentBundle.download_list_html) + * [download\_html](#AssemblyLine.al_document.ALDocumentBundle.download_html) + * [send\_email\_table\_row](#AssemblyLine.al_document.ALDocumentBundle.send_email_table_row) + * [send\_button\_to\_html](#AssemblyLine.al_document.ALDocumentBundle.send_button_to_html) + * [send\_button\_html](#AssemblyLine.al_document.ALDocumentBundle.send_button_html) + * [send\_email](#AssemblyLine.al_document.ALDocumentBundle.send_email) + * [is\_enabled](#AssemblyLine.al_document.ALDocumentBundle.is_enabled) + * [as\_docx](#AssemblyLine.al_document.ALDocumentBundle.as_docx) + * [as\_list](#AssemblyLine.al_document.ALDocumentBundle.as_list) + * [ALExhibit](#AssemblyLine.al_document.ALExhibit) + * [init](#AssemblyLine.al_document.ALExhibit.init) + * [ocr\_ready](#AssemblyLine.al_document.ALExhibit.ocr_ready) + * [ocr\_pages](#AssemblyLine.al_document.ALExhibit.ocr_pages) + * [as\_pdf](#AssemblyLine.al_document.ALExhibit.as_pdf) + * [num\_pages](#AssemblyLine.al_document.ALExhibit.num_pages) + * [complete](#AssemblyLine.al_document.ALExhibit.complete) + * [\_\_str\_\_](#AssemblyLine.al_document.ALExhibit.__str__) + * [ocrmypdf\_task](#AssemblyLine.al_document.ocrmypdf_task) + * [ALExhibitList](#AssemblyLine.al_document.ALExhibitList) + * [init](#AssemblyLine.al_document.ALExhibitList.init) + * [as\_pdf](#AssemblyLine.al_document.ALExhibitList.as_pdf) + * [size\_in\_bytes](#AssemblyLine.al_document.ALExhibitList.size_in_bytes) + * [ocr\_ready](#AssemblyLine.al_document.ALExhibitList.ocr_ready) + * [hook\_after\_gather](#AssemblyLine.al_document.ALExhibitList.hook_after_gather) + * [ALExhibitDocument](#AssemblyLine.al_document.ALExhibitDocument) + * [init](#AssemblyLine.al_document.ALExhibitDocument.init) + * [has\_overflow](#AssemblyLine.al_document.ALExhibitDocument.has_overflow) + * [ocr\_ready](#AssemblyLine.al_document.ALExhibitDocument.ocr_ready) + * [\_\_getitem\_\_](#AssemblyLine.al_document.ALExhibitDocument.__getitem__) + * [as\_list](#AssemblyLine.al_document.ALExhibitDocument.as_list) + * [as\_pdf](#AssemblyLine.al_document.ALExhibitDocument.as_pdf) + * [as\_docx](#AssemblyLine.al_document.ALExhibitDocument.as_docx) + * [ALTableDocument](#AssemblyLine.al_document.ALTableDocument) + * [init](#AssemblyLine.al_document.ALTableDocument.init) + * [has\_overflow](#AssemblyLine.al_document.ALTableDocument.has_overflow) + * [\_\_getitem\_\_](#AssemblyLine.al_document.ALTableDocument.__getitem__) + * [as\_list](#AssemblyLine.al_document.ALTableDocument.as_list) + * [as\_pdf](#AssemblyLine.al_document.ALTableDocument.as_pdf) + * [as\_docx](#AssemblyLine.al_document.ALTableDocument.as_docx) + * [ALUntransformedDocument](#AssemblyLine.al_document.ALUntransformedDocument) + * [init](#AssemblyLine.al_document.ALUntransformedDocument.init) + * [has\_overflow](#AssemblyLine.al_document.ALUntransformedDocument.has_overflow) + * [as\_list](#AssemblyLine.al_document.ALUntransformedDocument.as_list) + * [as\_pdf](#AssemblyLine.al_document.ALUntransformedDocument.as_pdf) + * [as\_docx](#AssemblyLine.al_document.ALUntransformedDocument.as_docx) + * [ALDocumentUpload](#AssemblyLine.al_document.ALDocumentUpload) + * [unpack\_dafilelist](#AssemblyLine.al_document.unpack_dafilelist) + + + + +### random\_suffix -#### random\_suffix +```python +def random_suffix(length: int = 8) -> str +``` Return a random string for use in unique IDs. @@ -11,128 +132,178 @@ Note: this is powerful enough for the expected usecase of distinguishing a few HTML elements from each other, but not cryptographically secure or as strong as a true GUID. -**Arguments**: +#### Arguments - `length` _int_ - The length of the random string to generate. Defaults to 8. -**Returns**: +#### Returns - `str` - A random string of lowercase letters and digits. -#### base\_name + + +### base\_name + +```python +def base_name(filename: str) -> str +``` Extracts the base name of a file without its extension. -**Arguments**: +#### Arguments - `filename` _str_ - The full name of the file. -**Returns**: +#### Returns - `str` - The base name of the file without its extension. -#### label + + +### label + +```python +def label(dictionary: dict) -> str +``` Return the value of the first dictionary item. Given a dictionary like: \{"some_attribute":"Some label"\}, this function returns the value of the first dictionary item. Useful for working with the `columns` method of an ALAddendumField. -**Arguments**: +#### Arguments - `dictionary` _dict_ - The dictionary to extract the value from. -**Returns**: +#### Returns - `str` - The value of the first dictionary item or an empty string if not found. -#### key + + +### key + +```python +def key(dictionary: dict) -> str +``` Return the key of the first dictionary item. Given a dictionary like: \{"some_attribute":"Some label"\}, this function returns the key of the first dictionary item. Useful for working with the `columns` method of an ALAddendumField. -**Arguments**: +#### Arguments - `dictionary` _dict_ - The dictionary to extract the key from. -**Returns**: +#### Returns - `str` - The key of the first dictionary item or an empty string if not found. -#### safeattr + + +### safeattr + +```python +def safeattr(object: Any, key: str) -> str +``` Safely retrieve an attribute or key value from an object. -**Arguments**: +#### Arguments - `object` _Any_ - The object (which could be a dict, DADict, or DAObject) from which to retrieve the value. - `key` _str_ - The key or attribute name. -**Returns**: +#### Returns - `str` - The retrieved value or an empty string if not found or if an error occurred. -**Notes**: +#### Notes The `location` attribute of an Address object or any LatitudeLongitude attribute of a DAObject is always skipped. -#### html\_safe\_str + + +### html\_safe\_str + +```python +def html_safe_str(the_string: str) -> str +``` Convert a string into a format that's safe for use as an HTML class or ID. -**Arguments**: +#### Arguments - `the_string` _str_ - The string to be converted. -**Returns**: +#### Returns - `str` - A string that's safe for use as an HTML class or ID. -#### table\_row + + +### table\_row + +```python +def table_row(title: str, button_htmls: List[str] = []) -> str +``` Generate an HTML row string for an AL document-styled table. -**Arguments**: +#### Arguments - `title` _str_ - The title to display in the row. - `button_htmls` _List[str], optional_ - A list of HTML strings representing buttons. Defaults to an empty list. -**Returns**: +#### Returns - `str` - An HTML string representing a row in an AL document-styled table. -#### pdf\_page\_parity + + +### pdf\_page\_parity + +```python +def pdf_page_parity(pdf_path: str) -> Literal["even", "odd"] +``` Count the number of pages in the PDF and return "even" if it is divisible by 2 and "odd" if it is not divisible by 2. -**Arguments**: +#### Arguments - `pdf_path` _str_ - Path to the PDF in the filesystem -**Returns**: +#### Returns Literal["even", "odd"]: The parity of the number of pages in the PDF -#### add\_blank\_page + + +### add\_blank\_page + +```python +def add_blank_page(pdf_path: str) -> None +``` Add a blank page to the end of a PDF. -**Arguments**: +#### Arguments - `pdf_path` _str_ - Path to the PDF in the filesystem + + ## ALAddendumField Objects ```python @@ -144,7 +315,7 @@ Represents a field with attributes determining its display in an addendum, typic The field can manage items that are either strings or list-like structures. Handling of dictionary overflow is not currently supported. -**Attributes**: +#### Attributes - `field_name` _str_ - The name of a docassemble variable that this object represents. - `overflow_trigger` _Union[int, bool]_ - Specifies the limit after which the text is truncated and moved @@ -157,27 +328,42 @@ is not currently supported. Defaults to "string". Planned for future implementation. -**Notes**: +#### Notes The attributes `headers` and `field_style` are planned for future releases and are not currently implemented. -#### init + + +### init + +```python +def init(*pargs, **kwargs) -> None +``` Standard DAObject init method. -**Arguments**: +#### Arguments - `*pargs` - Positional arguments - `**kwargs` - Keyword arguments -#### overflow\_value + + +### overflow\_value + +```python +def overflow_value(preserve_newlines: bool = False, + input_width: int = 80, + overflow_message: str = "", + preserve_words: bool = True) -> Any +``` Retrieve the overflow portion of a variable that exceeds the content of `safe_value()`. This function addresses both list-like objects and strings, ensuring that the returned overflow content adheres to whitespace preferences specified by the parameters. -**Arguments**: +#### Arguments - `preserve_newlines` _bool, optional_ - Determines the treatment of newline characters. If True, the returned string can contain single newline characters. Sequences of newline @@ -194,39 +380,61 @@ content adheres to whitespace preferences specified by the parameters. and the overflow. Defaults to True. -**Returns**: +#### Returns - `Any` - The portion of the variable exceeding the content safe for display, considered as overflow. -#### max\_lines + + +### max\_lines + +```python +def max_lines(input_width: int = 80) -> int +``` Compute the maximum number of lines that can fit in the input given the specified input width. -**Arguments**: +#### Arguments - `input_width` _int, optional_ - The width of the input or display area. Defaults to 80. -**Returns**: +#### Returns - `int` - The maximum number of lines accommodated by the input width. -#### value + + +### value + +```python +def value() -> Any +``` Retrieve the complete value without considering overflow constraints. This can be especially helpful in appendices where there's a desire to showcase the entire value without the necessity of toggling between various sections or pages. -**Returns**: +#### Returns - `Any` - The whole value of the field, irrespective of overflow. -#### has\_overflow + + +### has\_overflow + +```python +def has_overflow(overflow_message: str = "", + input_width: int = 80, + preserve_newlines: bool = False, + _original_value: Optional[str] = None, + preserve_words: bool = True) -> bool +``` Return True only if the value's length exceeds the overflow trigger. -**Arguments**: +#### Arguments - `overflow_message` _str_ - A short message to go on the page where text is cutoff. - `input_width` _int_ - The width, in characters, of the input box. Defaults to 80. @@ -241,17 +449,28 @@ Return True only if the value's length exceeds the overflow trigger. trigger, regardless of whether it is in the middle of a word. -**Returns**: +#### Returns - `bool` - True if the value's length exceeds the overflow trigger, False otherwise. -#### original\_or\_overflow\_message + + +### original\_or\_overflow\_message + +```python +def original_or_overflow_message( + overflow_message: str = "", + input_width: int = 80, + preserve_newlines: bool = False, + _original_value: Optional[str] = None, + preserve_words: bool = True) -> Union[str, List[Any]] +``` Return the original value if it is less than the overflow trigger (once processed), otherwise return the overflow message. Unlike safe_value(), this will never output a partial value. -**Arguments**: +#### Arguments - `overflow_message` _str_ - A short message to go on the page where text is cutoff. - `input_width` _int_ - The width, in characters, of the input box. Defaults to 80. @@ -266,11 +485,21 @@ Unlike safe_value(), this will never output a partial value. trigger, regardless of whether it is in the middle of a word. -**Returns**: +#### Returns Union[str, List[Any]]: Either a string representing the overflow message or the original value -#### safe\_value + + +### safe\_value + +```python +def safe_value(overflow_message: str = "", + input_width: int = 80, + preserve_newlines: bool = False, + _original_value: Optional[str] = None, + preserve_words: bool = True) -> Union[str, List[Any]] +``` Return just the portion of the variable that heuristics suggest will fit in the specified overflow_trigger limit. If the value is not defined, return an empty string. @@ -286,7 +515,7 @@ with a single space. If `preserve_newlines` is false, all whitespace, including newlines and tabs, will be replaced with a single space. -**Arguments**: +#### Arguments - `overflow_message` _str_ - A short message to go on the page where text is cutoff. - `input_width` _int_ - The width, in characters, of the input box. Defaults to 80. @@ -299,29 +528,48 @@ with a single space. - `preserve_words` _bool_ - Indicates whether words should be preserved in their entirety without being split. -**Returns**: +#### Returns Union[str, List[Any]]: The portion of the variable that fits within the overflow trigger. -#### value\_if\_defined + + +### value\_if\_defined + +```python +def value_if_defined() -> Any +``` Fetch the value of the designated field if it exists; otherwise, return an empty string. This method ensures that the addendum does not inadvertently trigger docassemble's variable gathering. -**Returns**: +#### Returns - `Any` - The value of the field if it exists, otherwise an empty string. -#### \_\_str\_\_ + + +### \_\_str\_\_ + +```python +def __str__() +``` Represent the ALAddendumField instance as a string. -**Returns**: +#### Returns - `str` - The string representation of the value contained within the field. -#### columns + + +### columns + +```python +def columns(skip_empty_attributes: bool = True, + skip_attributes: Optional[set] = None) -> Optional[list] +``` Return a list of the attributes present within the object that would make sense to go in the table of an addendum. @@ -329,23 +577,29 @@ in the table of an addendum. If the `headers` attribute exists, this will be prioritized. Otherwise, the method will infer columns from the first value in the list. Empty attributes and the `complete` attribute are typically ignored. -**Arguments**: +#### Arguments - `skip_empty_attributes` _bool, optional_ - Determines whether empty attributes are included in the list. Defaults to True. - `skip_attributes` _Optional[set], optional_ - A set of attributes to ignore. Defaults to \{"complete"\}. -**Returns**: +#### Returns - `Optional[list]` - A list of columns or None if no meaningful columns can be determined. -**Notes**: +#### Notes The "location" attribute of an Address object is always skipped in the column list. -#### type + + +### type + +```python +def type() -> str +``` Determine the data type of the contained value. @@ -354,27 +608,45 @@ Categories: - 'object_list': A list containing dictionaries or objects. - 'other': Any other type. -**Returns**: +#### Returns - `str` - The type category of the value. -#### is\_list + + +### is\_list + +```python +def is_list() -> bool +``` Check if the field contains a list value, whether it consists of objects, dictionaries, or standard values. -**Returns**: +#### Returns - `bool` - True if the field contains a list, otherwise False. -#### is\_object\_list + + +### is\_object\_list + +```python +def is_object_list() -> bool +``` Determine if the field contains a list of dictionaries or objects. -**Returns**: +#### Returns - `bool` - True if the field contains a list of dictionaries or objects, otherwise False. -#### overflow\_markdown + + +### overflow\_markdown + +```python +def overflow_markdown() -> str +``` Generate a markdown representation of the overflow values. @@ -382,11 +654,19 @@ The method returns either a markdown table or a bulleted list based on the struc This utility offers a standardized way to represent overflow content, though users might prefer to manually control the output's format. -**Returns**: +#### Returns - `str` - A markdown representation of the overflow values. -#### overflow\_docx + + +### overflow\_docx + +```python +def overflow_docx( + path: str = "docassemble.ALDocumentDict:data/templates/addendum_table.docx" +) -> Any +``` Insert a formatted table into a docx file, representing the overflow values. @@ -394,16 +674,18 @@ This method provides a convenient way to add overflow content into a docx file, doesn't offer formatting control. If more formatting flexibility is required, consider directly fetching the overflow values using the `overflow_value()` method. -**Arguments**: +#### Arguments - `path` _str, optional_ - Path to the template docx file to be used. Defaults to a predetermined path. -**Returns**: +#### Returns A docx template with the inserted table. + + ## ALAddendumFieldDict Objects ```python @@ -419,77 +701,115 @@ contexts, ensuring only the necessary text is shown. Adding a new entry will implicitly set the `field_name` attribute of the field -**Attributes**: +#### Attributes - `style` _str_ - Determines the display behavior. If set to "overflow_only", only the overflow text will be displayed. -#### init + + +### init + +```python +def init(*pargs, **kwargs) -> None +``` Standard DAObject init method. -**Arguments**: +#### Arguments - `*pargs` - Positional arguments - `**kwargs` - Keyword arguments -#### initializeObject + + +### initializeObject + +```python +def initializeObject(*pargs, **kwargs) -> Any +``` Initializes a new dictionary entry and sets its `field_name` attribute. When an entry is implicitly created, this method ensures the item knows its own field name by setting the `field_name` attribute. -**Arguments**: +#### Arguments - `*pargs` - List of arguments to use to create the dict entry. The 0th arg is also used to set the `field_name` attribute. - `**kwargs` - List of keyword arguments used to create the dict entry -**Returns**: +#### Returns The new dictionary entry created -#### from\_list + + +### from\_list + +```python +def from_list(data: List[Dict]) -> None +``` Populate the dictionary using a list of field data. -**Arguments**: +#### Arguments - `data` _list_ - List of dictionaries containing ield data with keys "field_name" and "overflow_trigger". -#### defined\_fields + + +### defined\_fields + +```python +def defined_fields(style: str = "overflow_only") -> list +``` Fetch a list of fields that are defined. -**Arguments**: +#### Arguments - `style` _str, optional_ - If set to "overflow_only", only the fields with overflow values will be returned. Defaults to "overflow_only". -**Returns**: +#### Returns - `list` - List of defined fields based on the specified style. -#### overflow + + +### overflow + +```python +def overflow() -> list +``` Retrieve fields that have overflowed their character limits. -**Returns**: +#### Returns - `list` - A list of fields with overflow values. -#### has\_overflow + + +### has\_overflow + +```python +def has_overflow() -> bool +``` Determine if any field within the dictionary exceeds its overflow limit. -**Returns**: +#### Returns - `bool` - True if at least one field overflows, False otherwise. + + ## DALazyAttribute Objects ```python @@ -502,11 +822,17 @@ This is particularly helpful when there's a need to cache information on a The implementation leverages Docassemble's object pickling process by customizing the `__getstate__` method that Pickle uses for serialization. -**Attributes**: +#### Attributes - `instanceName` _str_ - A unique identifier for the object instance, if available. -#### \_\_getstate\_\_ + + +### \_\_getstate\_\_ + +```python +def __getstate__() -> dict +``` Overrides the default method used by Pickle for object serialization. @@ -514,10 +840,12 @@ If the object has an `instanceName` attribute, it is retained during serializati Otherwise, an empty dictionary is returned, ensuring that other attributes are not persisted across page loads. -**Returns**: +#### Returns - `dict` - A dictionary containing only the `instanceName` if it exists, or empty otherwise. + + ## ALDocument Objects ```python @@ -553,7 +881,7 @@ single object representing all of the possible documents an interview can generate, and use encapsulated logic to trigger individual documents inclusion on the final download screen. -**Attributes**: +#### Attributes - `filename` _str_ - name used for output PDF - `title` _str_ - display name for the output PDF @@ -565,7 +893,7 @@ on the final download screen. document could have overflow, like for a PDF template. -**Notes**: +#### Notes The `enabled` attribute should always be defined by a code block or the objects block, because by default it is considered fresh on each page @@ -651,20 +979,35 @@ on the final download screen. my_doc.overflow_fields.gathered = True ``` -#### init + + +### init + +```python +def init(*pargs, **kwargs) -> None +``` Standard DAObject init method. -**Arguments**: +#### Arguments - `*pargs` - Positional arguments - `**kwargs` - Keyword arguments -#### as\_pdf + + +### as\_pdf + +```python +def as_pdf(key: str = "final", + refresh: bool = True, + pdfa: bool = False, + append_matching_suffix: bool = True) -> DAFile +``` Generates a PDF version of the assembled document. -**Arguments**: +#### Arguments - `key` _str_ - Document version key. Defaults to "final". - `refresh` _bool_ - If True, generates the attachment anew each time. Defaults to True. @@ -672,65 +1015,109 @@ Generates a PDF version of the assembled document. - `append_matching_suffix` _bool_ - If True, appends the key as a suffix to the filename when it matches the suffix to append. Defaults to True. -**Returns**: +#### Returns - `DAFile` - Assembled document in PDF format, possibly combined with addendum. -#### as\_docx + + +### as\_docx + +```python +def as_docx(key: str = "final", + refresh: bool = True, + append_matching_suffix: bool = True) -> DAFile +``` Generates a DOCX version of the assembled document, if possible. Falls back to PDF if not. -**Arguments**: +#### Arguments - `key` _str_ - Document version key. Defaults to "final". - `refresh` _bool_ - If True, generates the attachment anew each time. Defaults to True. - `append_matching_suffix` _bool_ - If True, appends the key as a suffix to the filename when it matches the suffix to append. Defaults to True. -**Returns**: +#### Returns - `DAFile` - Assembled document in DOCX or PDF format. -#### as\_list + + +### as\_list + +```python +def as_list(key: str = "final", refresh: bool = True) -> List[DAFile] +``` Generates a list containing the main document and its addendum, if applicable. -**Arguments**: +#### Arguments - `key` _str_ - Document version key. Defaults to "final". - `refresh` _bool_ - If True, generates the attachments anew each time. Defaults to True. -**Returns**: +#### Returns - `List[DAFile]` - List containing the main document and possibly its addendum. -#### need\_addendum + + +### need\_addendum + +```python +def need_addendum() -> bool +``` Determines if there's a need for an addendum in the document. First checks if the addendum is enabled, and then checks if there's overflow. -**Returns**: +#### Returns - `bool` - True if an addendum is needed, False otherwise. -#### has\_overflow + + +### has\_overflow + +```python +def has_overflow() -> bool +``` Checks if the document has fields that exceed their character limits. -**Returns**: +#### Returns - `bool` - True if there are overflow fields, False otherwise. -#### overflow + + +### overflow + +```python +def overflow() -> list +``` Retrieves a list of fields that have overflowed their character limits. -**Returns**: +#### Returns - `list` - List of overflow fields. -#### original\_or\_overflow\_message + + +### original\_or\_overflow\_message + +```python +def 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) -> Union[str, List[Any]] +``` Helper syntax to access a member field. @@ -738,7 +1125,7 @@ Return the original value if it is less than the overflow trigger (once processe Unlike safe_value(), this will never output a partial value. -**Arguments**: +#### Arguments - `field_name` _str_ - The name of the field to check. - `overflow_message` _str_ - A short message to go on the page where text is cutoff. @@ -754,15 +1141,25 @@ Unlike safe_value(), this will never output a partial value. trigger, regardless of whether it is in the middle of a word. -**Returns**: +#### Returns Union[str, List[Any]]: Either the original value or the overflow message, never a truncated value. -#### safe\_value + + +### safe\_value + +```python +def safe_value(field_name: str, + overflow_message: Optional[str] = None, + preserve_newlines: bool = False, + input_width: int = 80, + preserve_words: bool = True) -> str +``` Retrieve the "safe" value of a specified field, which is shorter than the overflow trigger. -**Arguments**: +#### Arguments - `field_name` _str_ - The name of the field to retrieve the safe value from. - `overflow_message` _Optional[str]_ - Message to display when the field value overflows. Defaults to the class's default overflow message. @@ -771,15 +1168,25 @@ Retrieve the "safe" value of a specified field, which is shorter than - `preserve_words` _bool_ - Whether to avoid splitting words during formatting. Defaults to True. -**Returns**: +#### Returns - `str` - The "safe" value of the specified field. -#### overflow\_value + + +### overflow\_value + +```python +def overflow_value(field_name: str, + overflow_message: Optional[str] = None, + preserve_newlines: bool = False, + input_width: int = 80, + preserve_words: bool = True) -> str +``` Retrieve the "overflow" value of a specified field, which is the amount exceeding the overflow trigger. -**Arguments**: +#### Arguments - `field_name` _str_ - The name of the field to retrieve the overflow value from. - `overflow_message` _Optional[str]_ - Message to display when the field value overflows. Defaults to the object's default overflow message. @@ -788,11 +1195,17 @@ Retrieve the "overflow" value of a specified field, which is the amoun - `preserve_words` _bool_ - Whether to avoid splitting words during formatting. Defaults to True. -**Returns**: +#### Returns - `str` - The "overflow" value of the specified field. -#### is\_enabled + + +### is\_enabled + +```python +def is_enabled(refresh: bool = True) -> bool +``` Determine if a document is considered "enabled" based on various conditions. @@ -801,15 +1214,17 @@ A document is "enabled" if: 2. The .enabled attribute is set to true (calculated fresh once per page load). 3. The cache.enabled attribute is set to true. -**Arguments**: +#### Arguments - `refresh` _bool_ - If True, refreshes the enabled status of the document. Defaults to True. -**Returns**: +#### Returns - `bool` - True if the document is enabled, otherwise False. + + ## ALStaticDocument Objects ```python @@ -818,13 +1233,13 @@ class ALStaticDocument(DAStaticFile) A class for initializing static documents for inclusion in an ALDocumentBundle with a one-liner. -**Notes**: +#### Notes Static files should always be placed in the `/data/static` folder of a package. The `/data/templates` folder is private and the ALDocumentBundle requires publicly accessible files. -**Attributes**: +#### Attributes - `filename` _str_ - Path to the file within `/data/static/`. - `title` _str_ - Title displayed as a row when invoking `download_list_html()` method from ALDocumentBundle. @@ -846,42 +1261,70 @@ 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 + + +### init + +```python +def init(*pargs, **kwargs) -> None +``` Standard DAObject init method. -**Arguments**: +#### Arguments - `*pargs` - Positional arguments - `**kwargs` - Keyword arguments -#### \_\_getitem\_\_ + + +### \_\_getitem\_\_ + +```python +def __getitem__(key) +``` Override to ensure 'final' and 'private' keys always exist and reference the same file. -**Returns**: +#### Returns - `ALStaticDocument` - Returns self. -#### as\_list + + +### as\_list + +```python +def as_list(key: str = "final", refresh: bool = True) -> List[DAStaticFile] +``` Get the document as a list. -**Arguments**: +#### Arguments - `key` _str_ - Key to access the document. Defaults to "final". - `refresh` _bool_ - Whether to refresh the document. Defaults to True. -**Returns**: +#### Returns - `List[DAStaticFile]` - A list containing this document. -#### as\_pdf + + +### as\_pdf + +```python +def as_pdf(key: str = "final", + pdfa: bool = False, + filename: str = "", + append_matching_suffix: bool = True, + refresh: bool = False) -> Union[DAStaticFile, DAFile] +``` Convert the document into PDF format. -**Arguments**: +#### Arguments - `key` _str_ - Key to access the document. Defaults to "final". - `pdfa` _bool_ - Whether to return the document in PDF/A format. Defaults to False. @@ -890,53 +1333,76 @@ Convert the document into PDF format. - `refresh` _bool_ - Whether to refresh the document. Defaults to False. -**Returns**: +#### Returns Union[DAStaticFile, DAFile]: The document in PDF format. -#### as\_docx + + +### as\_docx + +```python +def as_docx( + key: str = "final", + refresh: bool = True, + append_matching_suffix: bool = False) -> Union[DAStaticFile, DAFile] +``` Convert the document into DOCX format, if possible. If not, return as PDF. -**Arguments**: +#### Arguments - `key` _str_ - Key to access the document. Defaults to "final". - `refresh` _bool_ - Whether to refresh the document. Defaults to True. - `append_matching_suffix` _bool_ - Not used for static documents. They remain unchanged. -**Returns**: +#### Returns Union[DAStaticFile, DAFile]: The document in DOCX or PDF format. -#### show + + +### show + +```python +def show(**kwargs) -> DAFile +``` Display the document. This method provides a workaround for problems generating thumbnails. -**Arguments**: +#### Arguments - `**kwargs` - Args to pass to DAFile's show function -**Returns**: +#### Returns - `DAFile` - Displayable version of the document. -#### is\_enabled + + +### is\_enabled + +```python +def is_enabled(**kwargs) -> bool +``` Check if the document is enabled. -**Arguments**: +#### Arguments - `**kwargs` - Unused (for signature compatibility only) -**Returns**: +#### Returns - `bool` - True if the document is enabled, otherwise False. + + ## ALDocumentBundle Objects ```python @@ -953,7 +1419,7 @@ or "disabled", which will determine its inclusion in the generated bun A bundle can be output as a single merged PDF or as a list of individual documents. For nested bundles, each can be rendered as a merged PDF or a list of documents. -**Attributes**: +#### Attributes - `filename` _str_ - The name of the output file (without extension). - `title` _str_ - The title of the bundle. @@ -982,20 +1448,38 @@ bundles, each can be rendered as a merged PDF or a list of documents. zipped_files = bundle.as_zip() ``` -#### init + + +### init + +```python +def init(*pargs, **kwargs) -> None +``` Standard DAObject init method. -**Arguments**: +#### Arguments - `*pargs` - Positional arguments - `**kwargs` - Keyword arguments -#### as\_pdf + + +### as\_pdf + +```python +def as_pdf( + key: str = "final", + refresh: bool = True, + pdfa: bool = False, + append_matching_suffix: bool = True, + ensure_parity: Optional[Literal["even", + "odd"]] = None) -> Optional[DAFile] +``` Returns a consolidated PDF of all enabled documents in the bundle. -**Arguments**: +#### Arguments - `key` _str_ - Identifier for the document version, default is "final". - `refresh` _bool_ - Flag to return a newly assembled version, default is True. @@ -1006,25 +1490,42 @@ Returns a consolidated PDF of all enabled documents in the bundle. no parity is enforced. Defaults to None. -**Returns**: +#### Returns - `Optional[DAFile]` - Combined PDF file or None if no documents are enabled. -#### \_\_str\_\_ + + +### \_\_str\_\_ + +```python +def __str__() -> str +``` Produces a string representation of the PDF in a compatible method with the DAFile class. In an interview, this will show a thumbnail of the PDF by default. -**Returns**: +#### Returns - `str` - String representation of the PDF. -#### as\_zip + + +### as\_zip + +```python +def as_zip(key: str = "final", + refresh: bool = True, + pdfa: bool = False, + title: str = "", + format: Optional[str] = "pdf", + include_pdf: Optional[bool] = True) -> DAFile +``` Returns a zip file containing all enabled documents in the bundle in the specified format. -**Arguments**: +#### Arguments - `key` _str_ - Identifier for the document version, default is "final". - `refresh` _bool_ - Flag to reconsider the 'enabled' attribute, default is True. @@ -1034,125 +1535,193 @@ Returns a zip file containing all enabled documents in the bundle in the specifi - `include_pdf` _bool_ - Flag to include a PDF version of the document if it's originally in docx format, default is True. -**Returns**: +#### Returns - `DAFile` - A zip file containing the enabled documents. -#### preview + + +### preview + +```python +def preview(refresh: bool = True) -> Optional[DAFile] +``` Returns a preview version of the bundle as a PDF. -**Arguments**: +#### Arguments - `refresh` _bool_ - Flag to reconsider the 'enabled' attribute, default is True. -**Returns**: +#### Returns - `Optional[DAFile]` - Preview PDF file or None if no documents are enabled. -#### has\_enabled\_documents + + +### has\_enabled\_documents + +```python +def has_enabled_documents(refresh=False) -> bool +``` Checks if there is at least one enabled document in the bundle. -**Arguments**: +#### Arguments - `refresh` _bool_ - Flag to reconsider the 'enabled' attribute, default is False. -**Returns**: +#### Returns - `bool` - True if there's at least one enabled document, otherwise False. -#### enabled\_documents + + +### enabled\_documents + +```python +def enabled_documents(refresh: bool = True) -> List[Any] +``` Retrieves all enabled documents within the bundle. -**Arguments**: +#### Arguments - `refresh` _bool_ - Flag to reconsider the 'enabled' attribute, default is True. -**Returns**: +#### Returns - `List[Any]` - List of enabled documents. -#### as\_flat\_list + + +### as\_flat\_list + +```python +def as_flat_list(key: str = "final", refresh: bool = True) -> List[DAFile] +``` Flattens and returns all enabled documents in the bundle, even from nested bundles. -**Arguments**: +#### Arguments - `key` _str_ - Identifier for the document version, default is "final". - `refresh` _bool_ - Flag to reconsider the 'enabled' attribute, default is True. -**Returns**: +#### Returns - `List[DAFile]` - Flattened list of enabled documents. -#### get\_titles + + +### get\_titles + +```python +def get_titles(key: str = "final", refresh: bool = True) -> List[str] +``` Retrieves the titles of all enabled documents in the bundle. -**Arguments**: +#### Arguments - `key` _str_ - Identifier for the document version, default is "final". - `refresh` _bool_ - Flag to reconsider the 'enabled' attribute, default is True. -**Returns**: +#### Returns - `List[str]` - Titles of the enabled documents. -#### as\_pdf\_list + + +### as\_pdf\_list + +```python +def as_pdf_list(key: str = "final", + refresh: bool = True, + pdfa: bool = False) -> List[DAFile] +``` Returns all enabled documents in the bundle as individual PDFs, even from nested bundles. -**Arguments**: +#### Arguments - `key` _str_ - Identifier for the document version, default is "final". - `refresh` _bool_ - Flag to reconsider the 'enabled' attribute and regenerate the enabled documents, default is True. - `pdfa` _bool_ - Flag to return the documents in PDF/A format, default is False. -**Returns**: +#### Returns - `List[DAFile]` - List of enabled documents as individual PDFs. -#### as\_docx\_list + + +### as\_docx\_list + +```python +def as_docx_list(key: str = "final", refresh: bool = True) -> List[DAFile] +``` Generates a list of enabled documents from the bundle represented as DOCX files. If a particular document can't be represented as a DOCX, its original format or a PDF is returned. -**Arguments**: +#### Arguments - `key` _str_ - Identifier for the document version, default is "final". - `refresh` _bool_ - Flag to reconsider the 'enabled' attribute, default is True. -**Returns**: +#### Returns - `List[DAFile]` - List of documents represented as DOCX files or in their original format. -#### as\_editable\_list + + +### as\_editable\_list + +```python +def as_editable_list(key: str = "final", refresh: bool = True) -> List[DAFile] +``` Generates a list of editable (DOCX or RTF) versions of the documents in the bundle. For documents that are not in DOCX or RTF formats, the original file format is returned. -**Arguments**: +#### Arguments - `key` _str_ - Identifier for the document version, default is "final". - `refresh` _bool_ - Flag to reconsider the 'enabled' attribute, default is True. -**Returns**: +#### Returns - `List[DAFile]` - Flat list of documents in DOCX or RTF formats or their original format. -#### get\_cacheable\_documents + + +### get\_cacheable\_documents + +```python +def 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 +) -> Tuple[List[Dict[str, DAFile]], Optional[DAFile], Optional[DAFile]] +``` Generates a cache of all enabled documents in the bundle, and returns it in a structure that can be cached and returned for use in a background process. @@ -1165,7 +1734,7 @@ The result looks like this: DAFile, # Zip of whole bundle DAFile # PDF of whole bundle -**Arguments**: +#### Arguments - `key` _str_ - Identifier for the document version, default is "final". - `pdf` _bool_ - Flag to include a PDF version of each file, default is True. @@ -1180,15 +1749,42 @@ DAFile # PDF of whole bundle - `zip_format` _Optional[str]_ - Format of the primary version of each document. -**Returns**: +#### Returns 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 + + +### download\_list\_html + +```python +def 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) -> str +``` Constructs an HTML table displaying a list of documents with 'view' and 'download' buttons. -**Arguments**: +#### Arguments - `key` _str_ - Identifier for the document version, default is "final". - `format` _str_ - Specifies the format of the files in the list. Can be "pdf", "docx", or "original". Default is "pdf". @@ -1215,18 +1811,32 @@ Constructs an HTML table displaying a list of documents with 'view' an - `zip_format` _Optional[str]_ - Format of the files in the zip archive. If None, defaults to value of "format" parameter. -**Returns**: +#### Returns - `str` - HTML representation of a table with documents and their associated actions. -#### download\_html + + +### download\_html + +```python +def 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") -> str +``` Returns an HTML string of a table to display all the docs combined into one pdf with 'view' and 'download' buttons. Deprecated; use download_list_html instead -**Arguments**: +#### Arguments - `key` _str_ - Identifier for the document version, default is "final". - `format` _str_ - Specifies the format of the files in the list. Can be "pdf", "docx", or "original". Default is "pdf". @@ -1239,33 +1849,55 @@ Deprecated; use download_list_html instead - `download_icon` _str_ - Icon for the 'download' button, default is "download". -**Returns**: +#### Returns - `str` - HTML representation of a table with documents and their associated actions. -#### send\_email\_table\_row + + +### send\_email\_table\_row + +```python +def send_email_table_row(key: str = "final", + send_label: str = "Send", + send_icon: str = "envelope") -> str +``` Generate HTML doc table row for an input box and button that allows someone to send the bundle to the specified email address. -**Arguments**: +#### Arguments - `key` _str_ - A key used to identify which version of the ALDocument to send. Defaults to "final". - `send_label` _str_ - Label for the 'send' button. Default is "Send". - `send_icon` _str_ - Icon for the 'send' button. Default is "envelope". -**Returns**: +#### Returns - `str` - The generated HTML string for the table row. -#### send\_button\_to\_html + + +### send\_button\_to\_html + +```python +def 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) -> str +``` Generate HTML for a button that allows someone to send the bundle to a specific email address. The email address is not editable by the end user in contrast to send_button_html. -**Arguments**: +#### Arguments - `email` _str_ - The recipient's email address. - `editable` _bool, optional_ - Flag indicating if the bundle is editable. Defaults to False. (deprecated; use preferred_formats instead) @@ -1277,11 +1909,23 @@ in contrast to send_button_html. - `preferred_formats` _Optional[Union[str,List[str]]], optional_ - A list of allowed formats for the document. Defaults to "pdf" if not specified. -**Returns**: +#### Returns - `str` - The generated HTML string for the button. -#### send\_button\_html + + +### send\_button\_html + +```python +def 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) -> str +``` Generate HTML for an input box and button that allows someone to send the bundle to the specified email address. @@ -1289,7 +1933,7 @@ to the specified email address. Optionally, display a checkbox that allows someone to decide whether or not to include an editable (Word) copy of the file, if and only if it is available. -**Arguments**: +#### Arguments - `key` _str, optional_ - A key used to identify which version of the ALDocument to send. Defaults to "final". - `show_editable_checkbox` _bool, optional_ - Flag indicating if the checkbox @@ -1303,17 +1947,28 @@ include an editable (Word) copy of the file, if and only if it is available. - `preferred_formats` _Optional[Union[str,List[str]]], optional_ - A list of allowed formats for the document. Defaults to "pdf" if not specified. -**Returns**: +#### Returns - `str` - The generated HTML string for the input box and button. -#### send\_email + + +### send\_email + +```python +def 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) -> bool +``` Send an email with the current bundle as a series of flat pdfs (one per bundle entry) or as editable documents. This function is similar to https://docassemble.org/docs/functions.html#send_email with additional parameters. -**Arguments**: +#### Arguments - `to` _Any_ - The email address, list of email addresses, or list of Individuals with a .email attribute to send to. - `key` _str, optional_ - Specifies which version of the document to send. Defaults to "final". @@ -1323,52 +1978,74 @@ https://docassemble.org/docs/functions.html#send_email with additional parameter - `**kwargs` - Additional parameters to pass to the da `send_email` function. -**Returns**: +#### Returns - `bool` - Indicates if the email was sent successfully. -#### is\_enabled + + +### is\_enabled + +```python +def is_enabled(refresh=True) -> bool +``` Check if the bundle itself is enabled, and if it has at least one enabled child document. -**Arguments**: +#### Arguments - `refresh` _bool_ - Whether to refresh the enabled status. Defaults to True. -**Returns**: +#### Returns - `bool` - Indicates if the bundle and its child documents are enabled. -#### as\_docx + + +### as\_docx + +```python +def as_docx(key: str = "final", + refresh: bool = True, + append_matching_suffix: bool = True) -> DAFile +``` Convert the enabled documents to a single DOCX file or PDF file if conversion fails. -**Arguments**: +#### Arguments - `key` _str, optional_ - The key to identify enabled documents. Defaults to "final". - `refresh` _bool, optional_ - Refresh the enabled documents before conversion. Defaults to True. - `append_matching_suffix` _bool, optional_ - Append a matching suffix to the output filename. Defaults to True. -**Returns**: +#### Returns - `DAFile` - A DAFile object containing the concatenated DOCX or PDF file. -#### as\_list + + +### as\_list + +```python +def as_list(key: str = "final", refresh: bool = True) -> List[DAFile] +``` Return a list of enabled documents. -**Arguments**: +#### Arguments - `key` _str, optional_ - The key to identify enabled documents. Defaults to "final". - `refresh` _bool, optional_ - Refresh the enabled documents before returning the list. Defaults to True. -**Returns**: +#### Returns - `List[DAFile]` - A list of enabled DAFile objects. + + ## ALExhibit Objects ```python @@ -1377,7 +2054,7 @@ class ALExhibit(DAObject) Class to represent a single exhibit, with cover page, which may contain multiple documents representing pages. -**Attributes**: +#### Attributes - `pages` _list_ - List of individual DAFiles representing uploaded images or documents. - `cover_page` _DAFile | DAFileCollection_ - (optional) A DAFile or DAFileCollection object created by an `attachment:` block @@ -1385,16 +2062,28 @@ 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 + + +### init + +```python +def init(*pargs, **kwargs) -> None +``` Standard DAObject init method. -**Arguments**: +#### Arguments - `*pargs` - Positional arguments - `**kwargs` - Keyword arguments -#### ocr\_ready + + +### ocr\_ready + +```python +def ocr_ready() -> bool +``` Returns True if the OCR process is complete. OCR is non-blocking, and assembly will work even if OCR is not complete. Check this status if you want to wait to deliver a document until @@ -1403,25 +2092,44 @@ OCR is complete. Will return true (but log a warning) if OCR was never started on the documents. That situation is likely a developer error, as you shouldn't wait for OCR if it never started -**Returns**: +#### Returns - `bool` - True iff OCR process has finished on all pages. -#### ocr\_pages + + +### ocr\_pages + +```python +def ocr_pages() -> List[DAFile] +``` Retrieve the OCR-processed version of pages if available, else return the original pages. -**Returns**: +#### Returns - `List[DAFile]` - List of pages, either OCR-processed or original. -#### as\_pdf + + +### as\_pdf + +```python +def 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) -> DAFile +``` Generates a PDF version of the exhibit, with optional features like Bates numbering or a cover page. Note that these are keyword only parameters, not positional. -**Arguments**: +#### Arguments - `refresh` _bool_ - If True, forces the exhibit to refresh before generating the PDF. (unused, provided for signature compatibility) - `prefix` _str_ - Prefix for Bates numbering if 'add_page_numbers' is True. @@ -1432,19 +2140,32 @@ Note that these are keyword only parameters, not positional. - `append_matching_suffix` _bool_ - If True, appends a suffix to the filename based on certain matching criteria. -**Returns**: +#### Returns - `DAFile` - PDF representation of the exhibit. -#### num\_pages + + +### num\_pages + +```python +def num_pages() -> int +``` Calculate the total number of pages in the exhibit. -**Returns**: +#### Returns - `int` - Total page count. -#### complete + + +### complete + +```python +@property +def complete() -> bool +``` For purposes of list gathering, trigger the attributes in the order necessary to gather a complete exhibit object. @@ -1453,15 +2174,28 @@ Indicates if the exhibit is complete. NOTE: This property always returns True after triggering the required attributes. -#### \_\_str\_\_ + + +### \_\_str\_\_ + +```python +def __str__() -> str +``` Return the title of the exhibit. -**Returns**: +#### Returns - `str` - Title of the exhibit. -#### ocrmypdf\_task + + +### ocrmypdf\_task + +```python +def ocrmypdf_task(from_file: Union[DAFile, DAFileList], + to_pdf: DAFile) -> Optional[str] +``` Processes the provided files using the 'ocrmypdf' utility to apply Optical Character Recognition (OCR). @@ -1470,21 +2204,23 @@ For non-image files, the text in the file is skipped during OCR. This function is designed to be executed as a background task (id: al_exhibit_ocr_pages_bg). -**Arguments**: +#### Arguments - `from_file` _Union[DAFile, DAFileList]_ - The source file or list of files to be OCR-processed. - `to_pdf` _DAFile_ - The destination file where the OCR-processed output will be saved. -**Returns**: +#### Returns - `Optional[str]` - The path of the OCR-processed file if successful; None otherwise. -**Raises**: +#### Raises - `subprocess.TimeoutExpired` - If the ocrmypdf process takes longer than an hour. + + ## ALExhibitList Objects ```python @@ -1494,7 +2230,7 @@ class ALExhibitList(DAList) A list representation of ALExhibit objects. Provides utility functions for managing exhibits and rendering them into a single PDF file. -**Attributes**: +#### Attributes - `maximum_size` _int_ - The maximum allowed size in bytes of the entire document. - `auto_label` _bool_ - If True, automatically numbers exhibits for cover page and table of contents. Defaults to True. @@ -1502,20 +2238,36 @@ 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 + + +### init + +```python +def init(*pargs, **kwargs) -> None +``` Standard DAObject init method. -**Arguments**: +#### Arguments - `*pargs` - Positional arguments - `**kwargs` - Keyword arguments -#### as\_pdf + + +### as\_pdf + +```python +def as_pdf(filename="file.pdf", + pdfa: bool = False, + add_page_numbers: bool = False, + toc_pages: int = 0, + append_matching_suffix: bool = True) -> DAFile +``` Compiles all exhibits in the list into a single PDF. -**Arguments**: +#### Arguments - `filename` _str_ - Desired filename for the generated PDF. - `pdfa` _bool_ - If True, generates the PDF in PDF/A format. @@ -1524,31 +2276,51 @@ Compiles all exhibits in the list into a single PDF. - `append_matching_suffix` _bool_ - If True, appends matching suffix to the filename. -**Returns**: +#### Returns - `DAFile` - A single PDF containing all exhibits. -#### size\_in\_bytes + + +### size\_in\_bytes + +```python +def size_in_bytes() -> int +``` Calculates the total size in bytes of all exhibits in the list. -**Returns**: +#### Returns - `int` - Total size of all exhibits in bytes. -#### ocr\_ready + + +### ocr\_ready + +```python +def ocr_ready() -> bool +``` Checks if all exhibits in the list have completed the OCR process. -**Returns**: +#### Returns - `bool` - True if all exhibits are OCRed or if OCR hasn't started. False otherwise. -#### hook\_after\_gather + + +### hook\_after\_gather + +```python +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 ```python @@ -1558,7 +2330,7 @@ class ALExhibitDocument(ALDocument) Represents a collection of uploaded documents, formatted like a record appendix or an exhibit list, complete with an optional table of contents and page numbering. -**Attributes**: +#### Attributes - `exhibits` _ALExhibitList_ - A list of ALExhibit documents. Each item represents a distinct exhibit, which can span multiple pages. @@ -1580,85 +2352,112 @@ or an exhibit list, complete with an optional table of contents and page numberi **Examples**: ``` ---- -objects: - - exhibit_attachment: ALExhibitDocument.using(title="Exhibits", filename="exhibits" ) ---- code: | # This block is not needed, but you can provide and customize for your needs. # This mirrors the fallback block in ql_baseline.yml exhibit_attachment.enabled = exhibit_attachment.exhibits.has_exhibits ---- -objects: - - al_user_bundle: ALDocumentBundle.using(elements=[my_instructions, my_main_attachment, exhibit_attachment], filename="user_bundle.pdf", title="All forms to download for your records") -``` - - Example of using a custom label function, https://docassemble.org/docs/functions.html#item_label: -``` ---- objects: - exhibit_attachment: ALExhibitDocument.using(title="Exhibits", filename="exhibits" , auto_labeler=item_label) ``` -#### init + + +### init + +```python +def init(*pargs, **kwargs) -> None +``` Standard DAObject init method. -**Arguments**: +#### Arguments - `*pargs` - Positional arguments - `**kwargs` - Keyword arguments -#### has\_overflow + + +### has\_overflow + +```python +def has_overflow() -> bool +``` Check if there is any overflow in the document. This is for compatibility with ALDocument; Exhibits inherently don't have overflow. -**Returns**: +#### Returns - `bool` - Always False for this implementation. -#### ocr\_ready + + +### ocr\_ready + +```python +def ocr_ready() -> bool +``` Determine if all exhibits within the document have undergone OCR processing. -**Returns**: +#### Returns - `bool` - True if all exhibits have been OCRed or if the OCR process hasn't been initiated. -#### \_\_getitem\_\_ + + +### \_\_getitem\_\_ + +```python +def __getitem__(key) +``` Overridden method to ensure 'final' and 'private' keys always reference the same file. -**Arguments**: +#### Arguments - `key` - The key to fetch the item. -**Returns**: +#### Returns - `ALExhibitDocument` - Returns the current instance of the class. -#### as\_list + + +### as\_list + +```python +def as_list(key: str = "final", refresh: bool = True) -> List[DAFile] +``` Retrieve the document as a list. -**Arguments**: +#### Arguments - `key` _str_ - Identifier key for the document. Default is "final". - `refresh` _bool_ - If True, the document list will be refreshed. Default is True. -**Returns**: +#### Returns - `List[DAFile]` - A list containing the document. -#### as\_pdf + + +### as\_pdf + +```python +def as_pdf(key: str = "final", + refresh: bool = True, + pdfa: bool = False, + append_matching_suffix: bool = True) -> DAFile +``` Render the document as a PDF. -**Arguments**: +#### Arguments - `key` _str_ - Identifier key for the document. Default is "final". For compatibility with ALDocument. @@ -1668,25 +2467,35 @@ Render the document as a PDF. - `append_matching_suffix` _bool_ - If True, appends a matching suffix to the filename. -**Returns**: +#### Returns - `DAFile` - The document rendered as a PDF. -#### as\_docx + + +### as\_docx + +```python +def as_docx(key: str = "final", + refresh: bool = True, + append_matching_suffix: bool = True) -> DAFile +``` Despite the name, renders the document as a PDF. Provided for signature compatibility. -**Arguments**: +#### Arguments - `key` _str, optional_ - Identifier key for the document. Default is "final". - `refresh` _bool, optional_ - If True, refreshes the DOCX document. Default is True. - `append_matching_suffix` _bool, optional_ - If True, appends a matching suffix to the filename (for automated tests). -**Returns**: +#### Returns - `DAFile` - The document rendered as a PDF. + + ## ALTableDocument Objects ```python @@ -1696,67 +2505,103 @@ class ALTableDocument(ALDocument) Represents a document tailored for table-like data presentation. This class provides functionality to export data as a table in various formats such as PDF and DOCX. -**Attributes**: +#### Attributes - `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". - `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 + + +### init + +```python +def init(*pargs, **kwargs) -> None +``` Standard DAObject init method. -**Arguments**: +#### Arguments - `*pargs` - Positional arguments - `**kwargs` - Keyword arguments -#### has\_overflow + + +### has\_overflow + +```python +def has_overflow() -> bool +``` Check for overflow in the document. For compatibility with ALDocument; Tables inherently don't have overflow. -**Returns**: +#### Returns - `bool` - Always False for this implementation. -#### \_\_getitem\_\_ + + +### \_\_getitem\_\_ + +```python +def __getitem__(key) +``` Allows for index-based retrieval of a document. Overridden to ensure 'final' and 'private' keys always return the same document. -**Arguments**: +#### Arguments - `key` - The key to fetch the item. -**Returns**: +#### Returns - `DAFile` - The document in its PDF format. -#### as\_list + + +### as\_list + +```python +def as_list(key: str = "final", + refresh: bool = True, + **kwargs) -> List[DAFile] +``` Retrieve the document as a list. -**Arguments**: +#### Arguments - `key` _str_ - Identifier key for the document. Default is "final". - `refresh` _bool_ - If True, the document list will be refreshed. Default is True. -**Returns**: +#### Returns - `List[DAFile]` - A list containing the document. -#### as\_pdf + + +### as\_pdf + +```python +def as_pdf(key: str = "final", + refresh: bool = True, + pdfa: bool = False, + append_matching_suffix: bool = True, + **kwargs) -> DAFile +``` Despite the name, returns the document as an Excel Spreadsheet (XLSX file). Name retained for signature compatibility. -**Arguments**: +#### Arguments - `key` _str_ - Identifier key for the document, mainly for compatibility with ALDocument. - `refresh` _bool_ - For signature compatibility @@ -1764,16 +2609,24 @@ Name retained for signature compatibility. - `append_matching_suffix` _bool_ - For signature compatibility -**Returns**: +#### Returns - `DAFile` - The table rendered as an XLSX spreadsheet -#### as\_docx + + +### as\_docx + +```python +def as_docx(key: str = "bool", + refresh: bool = True, + append_matching_suffix: bool = True) -> DAFile +``` Despite the name, returns the document as an Excel Spreadsheet (XLSX file). Name retained for signature compatibility. -**Arguments**: +#### Arguments - `key` _str_ - Identifier key for the document, mainly for compatibility with ALDocument. - `refresh` _bool_ - For signature compatibility @@ -1781,10 +2634,12 @@ Name retained for signature compatibility. - `append_matching_suffix` _bool_ - For signature compatibility -**Returns**: +#### Returns - `DAFile` - The table rendered as an XLSX spreadsheet + + ## ALUntransformedDocument Objects ```python @@ -1795,51 +2650,81 @@ Represents an untransformed document. The class provides methods to access the d without making any modifications to it. The provided methods are mainly for duck-typing compatibility with ALDocument. -**Attributes**: +#### Attributes - `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 + + +### init + +```python +def init(*pargs, **kwargs) -> None +``` Standard DAObject init method. -**Arguments**: +#### Arguments - `*pargs` - Positional arguments - `**kwargs` - Keyword arguments -#### has\_overflow + + +### has\_overflow + +```python +def has_overflow() -> bool +``` Check for overflow in the document. For compatibility with ALDocument. Untransformed documents inherently don't have overflow. -**Returns**: +#### Returns - `bool` - Always False for this implementation. -#### as\_list + + +### as\_list + +```python +def as_list(key: str = "final", + refresh: bool = True, + **kwargs) -> List[DAFile] +``` Retrieve the document as a list. -**Arguments**: +#### Arguments - `key` _str_ - Identifier key for the document. Default is "final". - `refresh` _bool_ - If True, the document list will be refreshed. Default is True. -**Returns**: +#### Returns - `List[DAFile]` - A list containing the document. -#### as\_pdf + + +### as\_pdf + +```python +def as_pdf(key: str = "final", + refresh: bool = True, + pdfa: bool = False, + append_matching_suffix: bool = True, + **kwargs) -> DAFile +``` Fetch the document in its original form, without any transformations. This method is primarily for duck-typing compatibility with ALDocument. -**Arguments**: +#### Arguments - `key` _str_ - Identifier key for the document. Unused, but included for compatibility. - `refresh` _bool_ - If True, fetches the latest version of the document. Default is True. @@ -1847,27 +2732,37 @@ This method is primarily for duck-typing compatibility with ALDocument. - `append_matching_suffix` _bool_ - Unused argument for compatibility. -**Returns**: +#### Returns - `DAFile` - The original, untransformed document. -#### as\_docx + + +### as\_docx + +```python +def as_docx(key: str = "final", + refresh: bool = True, + append_matching_suffix: bool = True) -> DAFile +``` Fetch the document in its original form, without any transformations. This method is primarily for duck-typing compatibility with ALDocument. -**Arguments**: +#### Arguments - `key` _str_ - Identifier key for the document. Default is "final". - `refresh` _bool_ - If True, fetches the latest version of the document. Default is True. - `append_matching_suffix` _bool_ - Unused argument for compatibility. -**Returns**: +#### Returns - `DAFile` - The original, untransformed document. + + ## ALDocumentUpload Objects ```python @@ -1877,16 +2772,22 @@ class ALDocumentUpload(ALUntransformedDocument) Simplified class to handle uploaded documents, without any of the complexity of the ALExhibitDocument class. -#### unpack\_dafilelist + + +### unpack\_dafilelist + +```python +def unpack_dafilelist(the_file: DAFileList) -> DAFile +``` Creates a plain DAFile out of the first item in a DAFileList -**Arguments**: +#### Arguments - `the_file` _DAFileList_ - an item representing an uploaded document in a Docassemble interview -**Returns**: +#### Returns A DAFile representing the first item in the DAFileList, with a fixed instanceName attribute. diff --git a/docs/components/AssemblyLine/al_general.md b/docs/components/AssemblyLine/al_general.md index 89d5f09c0..8156cf637 100644 --- a/docs/components/AssemblyLine/al_general.md +++ b/docs/components/AssemblyLine/al_general.md @@ -1,22 +1,102 @@ ---- -sidebar_label: al_general -title: AssemblyLine.al_general ---- +# 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) + * [formatted\_unit](#AssemblyLine.al_general.ALAddress.formatted_unit) + * [block](#AssemblyLine.al_general.ALAddress.block) + * [line\_one](#AssemblyLine.al_general.ALAddress.line_one) + * [line\_two](#AssemblyLine.al_general.ALAddress.line_two) + * [on\_one\_line](#AssemblyLine.al_general.ALAddress.on_one_line) + * [normalized\_address](#AssemblyLine.al_general.ALAddress.normalized_address) + * [state\_name](#AssemblyLine.al_general.ALAddress.state_name) + * [ALAddressList](#AssemblyLine.al_general.ALAddressList) + * [init](#AssemblyLine.al_general.ALAddressList.init) + * [\_\_str\_\_](#AssemblyLine.al_general.ALAddressList.__str__) + * [ALNameList](#AssemblyLine.al_general.ALNameList) + * [init](#AssemblyLine.al_general.ALNameList.init) + * [\_\_str\_\_](#AssemblyLine.al_general.ALNameList.__str__) + * [ALPeopleList](#AssemblyLine.al_general.ALPeopleList) + * [init](#AssemblyLine.al_general.ALPeopleList.init) + * [names\_and\_addresses\_on\_one\_line](#AssemblyLine.al_general.ALPeopleList.names_and_addresses_on_one_line) + * [familiar](#AssemblyLine.al_general.ALPeopleList.familiar) + * [familiar\_or](#AssemblyLine.al_general.ALPeopleList.familiar_or) + * [short\_list](#AssemblyLine.al_general.ALPeopleList.short_list) + * [full\_names](#AssemblyLine.al_general.ALPeopleList.full_names) + * [pronoun\_reflexive](#AssemblyLine.al_general.ALPeopleList.pronoun_reflexive) + * [ALIndividual](#AssemblyLine.al_general.ALIndividual) + * [init](#AssemblyLine.al_general.ALIndividual.init) + * [signature\_if\_final](#AssemblyLine.al_general.ALIndividual.signature_if_final) + * [phone\_numbers](#AssemblyLine.al_general.ALIndividual.phone_numbers) + * [contact\_methods](#AssemblyLine.al_general.ALIndividual.contact_methods) + * [merge\_letters](#AssemblyLine.al_general.ALIndividual.merge_letters) + * [formatted\_age](#AssemblyLine.al_general.ALIndividual.formatted_age) + * [normalized\_address](#AssemblyLine.al_general.ALIndividual.normalized_address) + * [name\_fields](#AssemblyLine.al_general.ALIndividual.name_fields) + * [address\_fields](#AssemblyLine.al_general.ALIndividual.address_fields) + * [gender\_fields](#AssemblyLine.al_general.ALIndividual.gender_fields) + * [pronoun\_fields](#AssemblyLine.al_general.ALIndividual.pronoun_fields) + * [get\_pronouns](#AssemblyLine.al_general.ALIndividual.get_pronouns) + * [list\_pronouns](#AssemblyLine.al_general.ALIndividual.list_pronouns) + * [language\_fields](#AssemblyLine.al_general.ALIndividual.language_fields) + * [language\_name](#AssemblyLine.al_general.ALIndividual.language_name) + * [gender\_male](#AssemblyLine.al_general.ALIndividual.gender_male) + * [gender\_female](#AssemblyLine.al_general.ALIndividual.gender_female) + * [gender\_other](#AssemblyLine.al_general.ALIndividual.gender_other) + * [gender\_nonbinary](#AssemblyLine.al_general.ALIndividual.gender_nonbinary) + * [gender\_unknown](#AssemblyLine.al_general.ALIndividual.gender_unknown) + * [gender\_undisclosed](#AssemblyLine.al_general.ALIndividual.gender_undisclosed) + * [gender\_self\_described](#AssemblyLine.al_general.ALIndividual.gender_self_described) + * [contact\_fields](#AssemblyLine.al_general.ALIndividual.contact_fields) + * [initials](#AssemblyLine.al_general.ALIndividual.initials) + * [address\_block](#AssemblyLine.al_general.ALIndividual.address_block) + * [pronoun](#AssemblyLine.al_general.ALIndividual.pronoun) + * [pronoun\_objective](#AssemblyLine.al_general.ALIndividual.pronoun_objective) + * [pronoun\_possessive](#AssemblyLine.al_general.ALIndividual.pronoun_possessive) + * [pronoun\_subjective](#AssemblyLine.al_general.ALIndividual.pronoun_subjective) + * [pronoun\_reflexive](#AssemblyLine.al_general.ALIndividual.pronoun_reflexive) + * [name\_full](#AssemblyLine.al_general.ALIndividual.name_full) + * [name\_initials](#AssemblyLine.al_general.ALIndividual.name_initials) + * [name\_short](#AssemblyLine.al_general.ALIndividual.name_short) + * [familiar](#AssemblyLine.al_general.ALIndividual.familiar) + * [\_\_str\_\_](#AssemblyLine.al_general.ALIndividual.__str__) + * [section\_links](#AssemblyLine.al_general.section_links) + * [will\_send\_to\_real\_court](#AssemblyLine.al_general.will_send_to_real_court) + * [filter\_letters](#AssemblyLine.al_general.filter_letters) + * [fa\_icon](#AssemblyLine.al_general.fa_icon) + * [is\_sms\_enabled](#AssemblyLine.al_general.is_sms_enabled) + * [is\_phone\_or\_email](#AssemblyLine.al_general.is_phone_or_email) + * [github\_modified\_date](#AssemblyLine.al_general.github_modified_date) + * [language\_name](#AssemblyLine.al_general.language_name) + * [safe\_states\_list](#AssemblyLine.al_general.safe_states_list) + * [has\_parsable\_pronouns](#AssemblyLine.al_general.has_parsable_pronouns) + * [parse\_custom\_pronouns](#AssemblyLine.al_general.parse_custom_pronouns) + * [get\_visible\_al\_nav\_items](#AssemblyLine.al_general.get_visible_al_nav_items) + + + + +### safe\_subdivision\_type -#### safe\_subdivision\_type +```python +def safe_subdivision_type(country_code: str) -> Optional[str] +``` Returns the subdivision type for the country with the given country code. If no subdivision type is found, returns None. -**Arguments**: +#### Arguments - `country_code` _str_ - The ISO-3166-1 alpha-2 code for the country. -**Returns**: +#### Returns - `Optional[str]` - The subdivision type for the country with the given country code. + + ## ALAddress Objects ```python @@ -27,7 +107,7 @@ This class is used to store addresses. The ALAddress class extends the Address class with the `address_fields()` method and "smarter" handling of the unit attribute when printing a formatted address. -**Attributes**: +#### Attributes - `address` _str_ - The street where the person lives. - `unit` _str_ - The unit number where the person lives. @@ -37,7 +117,22 @@ 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 + + +### address\_fields + +```python +def 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) -> List[Dict[str, Any]] +``` Return a YAML structure representing the list of fields for the object's address. @@ -48,7 +143,7 @@ rather than `users[0].address.address`. If `show_if` is used, it will not be app NOTE: This function is stateful under specific conditions. Refer to the conditions mentioned below. -**Arguments**: +#### Arguments - `country_code` _Optional[str]_ - ISO-3166-1 alpha-2 code of the country. Defaults to None. - `default_state` _Optional[str]_ - Default state to set. Defaults to None. @@ -61,12 +156,12 @@ NOTE: This function is stateful under specific conditions. Refer to the conditio - `required` _Dict[str, bool], optional_ - A dictionary of field names and if they should be required. Default is None (everything but unit and zip is required) -**Returns**: +#### Returns List[Dict[str, Any]]: A list of dictionaries representing address fields. -**Notes**: +#### Notes - The function will set the `country` attribute of the Address to `country_code` under these circumstances: @@ -77,11 +172,19 @@ 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 + + +### formatted\_unit + +```python +def formatted_unit(language: Optional[str] = None, + require: bool = False, + bare: bool = False) -> str +``` Returns the unit, formatted appropriately. -**Arguments**: +#### Arguments - `language` _str, optional_ - The language in which to format the unit. Defaults to None (which uses system language). - `require` _bool, optional_ - A flag indicating whether the unit is required. If set to True, the function will @@ -90,7 +193,7 @@ Returns the unit, formatted appropriately. True, the function will not add 'Unit' regardless of other conditions. Defaults to False. -**Returns**: +#### Returns str: The formatted unit. If the unit attribute does not exist and require is set to False, this will be an @@ -98,11 +201,22 @@ 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 + + +### block + +```python +def block(language: Optional[str] = None, + international: bool = False, + show_country: Optional[bool] = None, + bare: bool = False, + long_state: bool = False, + show_impounded: bool = False) -> str +``` Returns a one-line formatted address, primarily for geocoding. -**Arguments**: +#### Arguments - `language` _str, optional_ - Language for the address format. - `international` _bool_ - If True, formats the address as an international address. Defaults to False. @@ -113,45 +227,73 @@ Returns a one-line formatted address, primarily for geocoding. - `show_impounded` _bool_ - If True, shows the address even if impounded. Defaults to False. -**Returns**: +#### Returns - `str` - The one-line formatted address. -#### line\_one + + +### line\_one + +```python +def line_one(language: Optional[str] = None, + bare: bool = False, + show_impounded: bool = False) -> str +``` Returns the first line of the address, including the unit number if it exists. -**Arguments**: +#### Arguments - `language` _str, optional_ - Language for the address format. - `bare` _bool_ - If True, excludes certain formatting elements. Defaults to False. - `show_impounded` _bool_ - If True, shows the address even if impounded. Defaults to False. -**Returns**: +#### Returns - `str` - The first line of the address. -#### line\_two + + +### line\_two + +```python +def line_two(language: Optional[str] = None, + long_state: bool = False, + show_impounded: bool = False) -> str +``` Returns the second line of the address, including city, state, and postal code. -**Arguments**: +#### Arguments - `language` _str, optional_ - Language for the address format. - `long_state` _bool_ - If True, uses the full state name. Defaults to False. - `show_impounded` _bool_ - If True, shows the address even if impounded. Defaults to False. -**Returns**: +#### Returns - `str` - The second line of the address. -#### on\_one\_line + + +### on\_one\_line + +```python +def 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) -> str +``` Returns a one-line formatted address. -**Arguments**: +#### Arguments - `include_unit` _bool_ - If True, includes the unit in the formatted address. Defaults to True. - `omit_default_country` _bool_ - If True, doesn't show the Docassemble default country in the formatted address. Defaults to True. @@ -163,11 +305,17 @@ Returns a one-line formatted address. - `show_impounded` _bool_ - If True, shows the address even if impounded. Defaults to False. -**Returns**: +#### Returns - `str` - The one-line formatted address. -#### normalized\_address + + +### normalized\_address + +```python +def normalized_address() -> Union[Address, "ALAddress"] +``` Try geocoding the address, returning the normalized version if successful. @@ -179,13 +327,19 @@ the version of the address as entered by the user. Warning: currently the normalized address will not be redacted if the address is impounded. -**Returns**: +#### Returns Union[Address, "ALAddress"]: Normalized address if geocoding is successful, otherwise the original address. -#### state\_name + + +### state\_name + +```python +def state_name(country_code: Optional[str] = None) -> str +``` Returns the full state name based on the state abbreviation. @@ -195,18 +349,20 @@ object. Otherwise, the method uses, in order: 1. The country code associated with the Address object, and then 2. The country set in the global config for the server. -**Arguments**: +#### Arguments - `country_code` _str, optional_ - ISO-3166-1 alpha-2 code to override the country attribute of the Address object. For valid codes, refer to: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements -**Returns**: +#### Returns - `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 ```python @@ -219,26 +375,40 @@ 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 + + +### init + +```python +def init(*pargs, **kwargs) -> None +``` Standard DAObject init method. -**Arguments**: +#### Arguments - `*pargs` - Positional arguments - `**kwargs` - Keyword arguments -#### \_\_str\_\_ + + +### \_\_str\_\_ + +```python +def __str__() -> str +``` Provide a string representation of the ALAddressList. This method returns the addresses in the list formatted in a comma-separated manner using the on_one_line method of ALAddress. -**Returns**: +#### Returns - `str` - Formatted string of all addresses in the list. + + ## ALNameList Objects ```python @@ -249,23 +419,37 @@ A class to store a list of IndividualName objects. Extends the DAList class and is tailored for IndividualName objects. -#### init + + +### init + +```python +def init(*pargs, **kwargs) -> None +``` Standard DAObject init method. -**Arguments**: +#### Arguments - `*pargs` - Positional arguments - `**kwargs` - Keyword arguments -#### \_\_str\_\_ + + +### \_\_str\_\_ + +```python +def __str__() -> str +``` Provide a string representation of the ALNameList. -**Returns**: +#### Returns - `str` - Formatted string of all names in the list. + + ## ALPeopleList Objects ```python @@ -276,83 +460,126 @@ Class to store a list of ALIndividual objects, representing people. For example, defendants, plaintiffs, or children. -#### init + + +### init + +```python +def init(*pargs, **kwargs) -> None +``` Standard DAObject init method. -**Arguments**: +#### Arguments - `*pargs` - Positional arguments - `**kwargs` - Keyword arguments -#### names\_and\_addresses\_on\_one\_line + + +### names\_and\_addresses\_on\_one\_line + +```python +def names_and_addresses_on_one_line(comma_string: str = "; ", + bare=False) -> str +``` Provide names and addresses of individuals on one line. -**Arguments**: +#### Arguments - `comma_string` _str, optional_ - The string to use between name-address pairs. Defaults to '; '. - `bare` _bool, optional_ - If True, prevents appending the word "Unit" to the unit attribute. Defaults to False. -**Returns**: +#### Returns - `str` - Formatted string of names followed by addresses. -#### familiar + + +### familiar + +```python +def familiar(**kwargs) -> str +``` Provide a list of familiar forms of names of individuals. -**Arguments**: +#### Arguments - `**kwargs` - Keyword arguments to pass to the familiar method. -**Returns**: +#### Returns - `str` - Formatted string of familiar names. -#### familiar\_or + + +### familiar\_or + +```python +def familiar_or(**kwargs) -> str +``` Provide a list of familiar forms of names of individuals separated by 'or'. -**Arguments**: +#### Arguments - `**kwargs` - Keyword arguments to pass to the familiar method. -**Returns**: +#### Returns - `str` - Formatted string of familiar names separated by 'or'. -#### short\_list + + +### short\_list + +```python +def short_list(limit: int, truncate_string: str = ", et. al.") -> str +``` Return a subset of the list, truncated with 'et. al.' if it exceeds a given limit. -**Arguments**: +#### Arguments - `limit` _int_ - The maximum number of items to display before truncating. - `truncate_string` _str, optional_ - The string to append when truncating. Defaults to ', et. al.'. -**Returns**: +#### Returns - `str` - Formatted string of names, truncated if needed. -#### full\_names + + +### full\_names + +```python +def full_names(comma_string=", ", and_string=word("and")) -> str +``` Return a formatted list of full names of individuals. -**Arguments**: +#### Arguments - `comma_string` _str, optional_ - The string to use between names. Defaults to ','. - `and_string` _str, optional_ - The string to use before the last name in the list. Defaults to 'and'. -**Returns**: +#### Returns - `str` - Formatted string of full names. -#### pronoun\_reflexive + + +### pronoun\_reflexive + +```python +def pronoun_reflexive(**kwargs) -> str +``` Returns the appropriate reflexive pronoun for the list of people, depending on the `person` keyword argument and the number of items in the list. @@ -360,17 +587,19 @@ on the `person` keyword argument and the number of items in the list. If the list is singular, return the reflexive pronoun for the first item in the list. If it is plural, return the appropriate plural reflexive pronoun (e.g., "themselves") -**Arguments**: +#### Arguments - `**kwargs` - Additional keyword arguments that are defined [upstream](https://docassemble.org/docs/objects.html#language%20methods). - person (Optional[[Union[str,int]]): Whether to use a first, second, or third person pronoun. Can be one of 1/"1p", 2/"2p", or 3/"3p" (default is 3). See [upstream](https://docassemble.org/docs/objects.html#language%20methods) documentation for more information. - default (Optional[str]): The default word to use if the pronoun is not defined, e.g. "the agent". If not defined, the default term is the user's name. -**Returns**: +#### Returns - `str` - The reflexive pronoun for the list. + + ## ALIndividual Objects ```python @@ -383,7 +612,7 @@ This class extends the Individual class and adds more tailored attributes and me relevant for the assembly line project. Specifically, it has attributes for previous addresses, other addresses, mailing addresses, previous names, aliases, and a preferred name. -**Attributes**: +#### Attributes - `previous_addresses` _ALAddressList_ - List of previous addresses. - `other_addresses` _ALAddressList_ - List of other addresses. @@ -394,34 +623,53 @@ other addresses, mailing addresses, previous names, aliases, and a preferred nam - `preferred_name` _IndividualName_ - The preferred name. -**Notes**: +#### Notes Objects as attributes should not be passed directly to the constructor due to initialization requirements in the Docassemble framework. See the `init` method. -#### init + + +### init + +```python +def init(*pargs, **kwargs) -> None +``` Standard DAObject init method. -**Arguments**: +#### Arguments - `*pargs` - Positional arguments - `**kwargs` - Keyword arguments -#### signature\_if\_final + + +### signature\_if\_final + +```python +def signature_if_final(i: str) -> Union[DAFile, str] +``` Returns the individual's signature if `i` is "final", which usually means we are assembling the final version of the document (as opposed to a preview). -**Arguments**: +#### Arguments - `i` _str_ - The condition which, if set to "final", returns the signature. -**Returns**: +#### Returns Union[DAFile, str]: The signature if the condition is met, otherwise an empty string. -#### phone\_numbers + + +### phone\_numbers + +```python +def phone_numbers(country: Optional[str] = None, + show_impounded: bool = False) -> str +``` Fetches and formats the phone numbers of the individual. @@ -433,56 +681,95 @@ Supports the following attributes: - `other_number`: Any other phone number - `home_number`: Home phone number (if applicable) -**Arguments**: +#### Arguments - `country` _str, optional_ - The country for phone number formatting. Defaults to the country of the docassemble server. - `show_impounded` _bool_ - If True, shows the phone numbers even if impounded. Defaults to False. -**Returns**: +#### Returns - `str` - Formatted string of phone numbers. -#### contact\_methods + + +### contact\_methods + +```python +def contact_methods() -> str +``` Generates a formatted string of all provided contact methods. -**Returns**: +#### Returns - `str` - A formatted string indicating the available methods to contact the individual. -#### merge\_letters + + +### merge\_letters + +```python +def merge_letters(new_letters: str) -> None +``` If the Individual has a child_letters attribute, add the new letters to the existing list Avoid using. Only used in 209A. -**Arguments**: +#### Arguments - `new_letters` _str_ - The new letters to add to the existing list of letters -#### formatted\_age + + +### formatted\_age + +```python +def formatted_age() -> str +``` Calculates and formats the age of the individual based on their birthdate. -**Returns**: +#### Returns - `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 + +```python +def normalized_address() -> Union[Address, ALAddress] +``` Fetches the normalized version of the address. -**Returns**: +#### Returns Union[Address, ALAddress]: The normalized address object. -#### name\_fields + + +### name\_fields + +```python +def 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 +) -> List[Dict[str, str]] +``` Generates suitable field prompts for a name based on the type of entity (person or business) and other provided parameters. -**Arguments**: +#### Arguments - `person_or_business` _str, optional_ - Specifies the entity type. It can either be "person" or "business". Default is "person". @@ -499,21 +786,36 @@ and other provided parameters. - `title_options` - (Union[List[str], Callable], optional): Deprecated parameter, use `title_choices` instead. If provided, it will be used to set the title choices. -**Returns**: +#### Returns List[Dict[str, str]]: A list of dictionaries where each dictionary contains field prompt details. -**Notes**: +#### Notes 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 + + +### address\_fields + +```python +def 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) -> List[Dict[str, str]] +``` Generate field prompts for capturing an address. -**Arguments**: +#### Arguments - `country_code` _str_ - The default country for the address. Defaults to "US". - `default_state` _Optional[str]_ - Default state if applicable. Defaults to None. @@ -526,16 +828,27 @@ Generate field prompts for capturing an address. - `required` _Dict[str, bool], optional_ - A dictionary of field names and if they should be required. Default is None (everything but unit and zip is required) -**Returns**: +#### Returns List[Dict[str, str]]: A list of dictionaries with field prompts for addresses. -#### gender\_fields + + +### gender\_fields + +```python +def 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 +) -> List[Dict[str, str]] +``` Generate fields for capturing gender information, including a self-described option. -**Arguments**: +#### Arguments - `show_help` _bool_ - Whether to show additional help text. Defaults to False. - `show_if` _Union[str, Dict[str, str], None]_ - Condition to determine if the field should be shown. Defaults to None. @@ -543,20 +856,34 @@ self-described option. - `choices` _Optional[Union[List[Dict[str, str]], Callable]]_ - A list of choices of genders to use in the prompts, or a callable that returns such a list. Default set of choices includes male, female, nonbinary, prefer-not-to-say, self-described, and unknown. -**Returns**: +#### Returns List[Dict[str, str]]: A list of dictionaries with field prompts for gender. -**Notes**: +#### Notes self-described will provide an input that overrides the value of `gender` and is not persisted. -#### pronoun\_fields + + +### pronoun\_fields + +```python +def 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) -> List[Dict[str, str]] +``` Generate fields for capturing pronoun information. -**Arguments**: +#### Arguments - `show_help` _bool_ - Whether to show additional help text. Defaults to False. - `show_if` _Union[str, Dict[str, str], None]_ - Condition to determine if the field should be shown. Defaults to None. @@ -567,11 +894,17 @@ Generate fields for capturing pronoun information. - `choices` _Optional[List[Dict[str, str]]]_ - A list of custom pronoun choices. Defaults to None. If not provided, global magic variable `al_pronoun_choices` will be used. -**Returns**: +#### Returns List[Dict[str, str]]: A list of dictionaries with field prompts for pronouns. -#### get\_pronouns + + +### get\_pronouns + +```python +def get_pronouns() -> set +``` Retrieve a set of the individual's pronouns. @@ -579,24 +912,40 @@ If the individual has selected the "self-described" option, it will us Can be formatted however the author likes. -**Returns**: +#### Returns - `set` - A set of strings representing the individual's pronouns. -#### list\_pronouns + + +### list\_pronouns + +```python +def list_pronouns() -> str +``` Retrieve a formatted string of the individual's pronouns, arranged with the comma_list() function. -**Returns**: +#### Returns - `str` - A formatted string of the individual's pronouns. -#### language\_fields + + +### language\_fields + +```python +def 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) -> List[Dict[str, str]] +``` Generate fields for capturing language preferences. -**Arguments**: +#### Arguments - `choices` _Optional[Union[List[Dict[str, str]], Callable]]_ - A list or callable of language choices. Defaults to None. - `style` _str_ - The display style of choices. Defaults to "radio". @@ -604,84 +953,162 @@ Generate fields for capturing language preferences. - `maxlengths` _Dict[str, int], optional_ - A dictionary of field names and their maximum lengths. Default is None. -**Returns**: +#### Returns List[Dict[str, str]]: A list of dictionaries with field prompts for language preferences. -#### language\_name + + +## language\_name + +```python +def language_name() -> str +``` Get the human-readable version of the individual's selected language. -**Returns**: +#### Returns - `str` - The human-readable version of the language. If 'other' is selected, it returns the value in `language_other`. Otherwise, it uses the `language_name` function. -#### gender\_male + + +### gender\_male + +```python +@property +def gender_male() -> bool +``` 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 + +```python +@property +def gender_female() -> bool +``` 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 + +```python +@property +def gender_other() -> bool +``` 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 + +```python +@property +def gender_nonbinary() -> bool +``` 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 + +```python +@property +def gender_unknown() -> bool +``` 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 + +```python +@property +def gender_undisclosed() -> bool +``` 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 + +```python +@property +def gender_self_described() -> bool +``` 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 + +```python +def contact_fields() -> None +``` Return field prompts for other contact info -#### initials + + +### initials + +```python +@property +def initials() -> str +``` Returns the initials of the individual as a string. For example, "Quinten K Steenhuis" would return "QKS". -#### address\_block + + +### address\_block + +```python +def address_block(language=None, + international=False, + show_country=False, + bare=False, + show_impounded=False) -> str +``` Generate a formatted address block for mailings. -**Arguments**: +#### Arguments - `language` _Optional_ - The language in which the address is written. - `international` _bool_ - If True, format for international mailing. Defaults to False. @@ -690,11 +1117,17 @@ Generate a formatted address block for mailings. - `show_impounded` _bool_ - If True, show the address even if it is impounded. Defaults to False. -**Returns**: +#### Returns - `str` - The formatted address block. -#### pronoun + + +### pronoun + +```python +def pronoun(**kwargs) -> str +``` Returns an objective pronoun as appropriate, based on the user's `pronouns` attribute or `gender` attribute. @@ -704,30 +1137,42 @@ If the user has selected multiple pronouns, each will appear, separated by a &qu This method will not trigger the definition of `gender` or `pronouns`, but it will use them if they are defined, with `pronouns` taking precedence. As a default, it will either use the value of `default` or the individual's full name. -**Arguments**: +#### Arguments - `**kwargs` - Additional keyword arguments that are defined [upstream](https://docassemble.org/docs/objects.html#language%20methods). - person (Optional[[Union[str,int]]): Whether to use a first, second, or third person pronoun. Can be one of 1/"1p", 2/"2p", or 3/"3p" (default is 3). See [upstream](https://docassemble.org/docs/objects.html#language%20methods) documentation for more information. - default (Optional[str]): The default word to use if the pronoun is not defined, e.g. "the agent". If not defined, the default term is the user's name. -**Returns**: +#### Returns - `str` - The appropriate pronoun. -#### pronoun\_objective + + +### pronoun\_objective + +```python +def pronoun_objective(**kwargs) -> str +``` Returns the same pronoun as the `pronoun()` method. -**Arguments**: +#### Arguments - `**kwargs` - Additional keyword arguments. -**Returns**: +#### Returns - `str` - The appropriate objective pronoun. -#### pronoun\_possessive + + +### pronoun\_possessive + +```python +def pronoun_possessive(target, **kwargs) -> str +``` Returns a possessive pronoun and a target word, based on attributes. @@ -738,7 +1183,7 @@ Given a target word, the function returns "\{pronoun\} \{target\}". Th "my", "her," "his," "its," or "their". It depends on the `gender` and `person_type` attributes and whether the individual is the current user. -**Arguments**: +#### Arguments - `target` _str_ - The target word to follow the pronoun. - `**kwargs` - Additional keyword arguments that can be passed to modify the behavior. These might include: @@ -746,11 +1191,17 @@ and whether the individual is the current user. - `person` (Optional[Union[str, int]]): Whether to use a first, second, or third person pronoun. Can be one of 1/"1p", 2/"2p", or 3/"3p" (default is 3). See [upstream documentation](https://docassemble.org/docs/objects.html#language%20methods) for more information. -**Returns**: +#### Returns - `str` - The appropriate possessive phrase, e.g., "her book", "their document". -#### pronoun\_subjective + + +### pronoun\_subjective + +```python +def pronoun_subjective(**kwargs) -> str +``` Returns a subjective pronoun, based on attributes. @@ -758,17 +1209,23 @@ The pronoun could be "you," "we", "she," "he, on the `gender` and `person_type` attributes and whether the individual is the current user. -**Arguments**: +#### Arguments - `**kwargs` - Additional keyword arguments that are defined [upstream](https://docassemble.org/docs/objects.html#language%20methods). - person (Optional[[Union[str,int]]): Whether to use a first, second, or third person pronoun. Can be one of 1/"1p", 2/"2p", or 3/"3p" (default is 3). See [upstream](https://docassemble.org/docs/objects.html#language%20methods) documentation for more information. - default (Optional[str]): The default word to use if the pronoun is not defined, e.g. "the agent". If not defined, the default term is the user's name. -**Returns**: +#### Returns - `str` - The appropriate subjective pronoun. -#### pronoun\_reflexive + + +### pronoun\_reflexive + +```python +def pronoun_reflexive(**kwargs) -> str +``` Returns the appropriate reflexive pronoun ("herself", "themself", "myself"), based on the user's pronouns or gender and whether we are asked to return a 1st, 2nd, or 3rd person pronoun. @@ -777,18 +1234,24 @@ Note that if the person has pronouns of they/them/theirs or a nonbinary gender, reflexive pronoun and not "themselves". This has growing acceptance although some consider it nonstandard. See: https://www.merriam-webster.com/wordplay/themself -**Arguments**: +#### Arguments - `**kwargs` - Additional keyword arguments that are defined [upstream](https://docassemble.org/docs/objects.html#language%20methods). - person (Optional[[Union[str,int]]): Whether to use a first, second, or third person pronoun. Can be one of 1/"1p", 2/"2p", or 3/"3p" (default is 3). See [upstream](https://docassemble.org/docs/objects.html#language%20methods) documentation for more information. - default (Optional[str]): The default word to use if the pronoun is not defined, e.g. "the agent". If not defined, the default term is the user's name. -**Returns**: +#### Returns - `str` - The appropriate reflexive pronoun. -#### name\_full + + +### name\_full + +```python +def name_full() -> str +``` Returns the individual's full name. @@ -796,11 +1259,17 @@ If the person has the attribute person_type and it is defined as either `business` or `organization`, it will only return the first name, even if middle, last, or suffix are defined. -**Returns**: +#### Returns - `str` - The individual or business's full name. -#### name\_initials + + +### name\_initials + +```python +def name_initials() -> str +``` Returns the individual's name with the middle name as an initial. Equivalent to `name.full(middle="initial")`, which is also the default. @@ -810,11 +1279,17 @@ If the person has the attribute person_type and it is defined as either `business` or `organization`, it will only return the "initials" of the first name, even if middle, last, or suffix are defined. -**Returns**: +#### Returns - `str` - The individual's name with the middle name as an initial. -#### name\_short + + +### name\_short + +```python +def name_short() -> str +``` Returns the individual's name without any middle name. @@ -824,11 +1299,18 @@ If the person has the attribute person_type and it is defined as either `business` or `organization`, it will only return the first name, even if middle, last, or suffix are defined. -**Returns**: +#### Returns - `str` - The individual' -#### familiar + + +### familiar + +```python +def familiar(unique_names: Optional[List[Any]] = None, + default: Optional[str] = None) -> str +``` Returns the individual's name in the most familiar form possible. @@ -851,13 +1333,13 @@ If the person has the attribute `person_type` and it is defined as either `business` or `organization`, it will only return the first name, even if middle, last, or suffix are defined. -**Arguments**: +#### Arguments - `unique_names` _Optional[List[Any]]_ - A list of unique names to compare against. Defaults to None. - `default` _Optional[str]_ - The default name to return if no unique name is found. Defaults to None. -**Returns**: +#### Returns - `str` - The individual's name in the most familiar form possible. @@ -868,7 +1350,13 @@ 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\_\_ + +```python +def __str__() -> str +``` Returns a string representation of the individual, which is their full name with the middle name shortened to one letter. @@ -877,56 +1365,83 @@ If the individual has the attribute `person_type` and it is defined as either `business` or `organization`, it will only return the first name, even if middle, last, or suffix are defined. -**Returns**: +#### Returns - `str` - The individual's name. -#### section\_links + + +## section\_links + +```python +def section_links(nav) -> List[str] +``` Returns a list of clickable navigation links without animation. -**Arguments**: +#### Arguments - `nav` - The navigation object. -**Returns**: +#### Returns - `List[str]` - A list of clickable navigation links without animation. -#### will\_send\_to\_real\_court + + +## will\_send\_to\_real\_court + +```python +def will_send_to_real_court() -> bool +``` For legacy email to court forms, this checks to see if the form is being run on the dev, test, or production server. The text "dev" or "test" needs to be in the URL root in the DA config: can change in `/config`. -**Returns**: +#### Returns - `bool` - True if the form is being run on the dev, test, or production server. -#### filter\_letters + + +## filter\_letters + +```python +def filter_letters(letter_strings: Union[List[str], str]) -> str +``` Used to take a list of letters like ["A","ABC","AB"] and filter out any duplicate letters. Avoid using, this is created for 209A. -**Arguments**: +#### Arguments - `letter_strings` _Union[List[str], str]_ - A list of letters. -**Returns**: +#### Returns - `str` - A string of unique letters. -#### fa\_icon + + +## fa\_icon + +```python +def fa_icon(icon: str, + color: str = "primary", + color_css: Optional[str] = None, + size: str = "sm") -> str +``` Return HTML for a font-awesome icon of the specified size and color. You can reference a CSS variable (such as Bootstrap theme color) or a true CSS color reference, such as 'blue' or '`DDDDDD`'. Defaults to Bootstrap theme color "primary". -**Arguments**: +#### Arguments - `icon` _str_ - The name of the icon to use. See https://fontawesome.com/icons for a list of icons. - `color` _str_ - The color of the icon. Defaults to "primary". @@ -934,42 +1449,62 @@ a CSS variable (such as Bootstrap theme color) or a true CSS color reference, su - `size` _str_ - The size of the icon. Defaults to "sm". -**Returns**: +#### Returns - `str` - HTML for the icon. -#### is\_sms\_enabled + + +## is\_sms\_enabled + +```python +def is_sms_enabled() -> bool +``` Checks if SMS (Twilio) is enabled on the server. Does not verify that it works. See https://docassemble.org/docs/config.html#twilio for more info. -**Returns**: +#### Returns - `bool` - True if there is a non-empty Twilio config on the server, False otherwise -#### is\_phone\_or\_email + + +## is\_phone\_or\_email + +```python +def is_phone_or_email(text: str) -> bool +``` Returns True if the string is either a valid phone number or a valid email address. If SMS is not enabled on the server (through the Twilio config), only accepts emails. Email validation is extremely minimal--just checks for an @ sign between two non-zero length strings. -**Arguments**: +#### Arguments - `text` _str_ - The string to check. -**Returns**: +#### Returns - `bool` - True if the string is either a valid phone number or a valid email address. -**Raises**: +#### Raises DAValidationError if the string is neither a valid phone number nor a valid email address. -#### github\_modified\_date + + +## github\_modified\_date + +```python +def github_modified_date(github_user: str, + github_repo_name: str, + auth=None) -> Union[DADateTime, None] +``` Returns the date that the given GitHub repository was modified or None if API call fails. @@ -990,73 +1525,104 @@ type: basic If no valid auth information is in the configuration, it will fall back to anonymous authentication. The GitHub API is rate-limited to 60 anonymous API queries/hour. -**Arguments**: +#### Arguments - `github_user` _str_ - The GitHub username of the repository owner. - `github_repo_name` _str_ - The name of the repository. - `auth` _Optional[dict]_ - A dictionary containing authentication information. Defaults to None. -**Returns**: +#### Returns Union[DADateTime, None]: The date that the given GitHub repository was modified or None if API call fails. -#### language\_name + + +## language\_name + +```python +def language_name(language_code: str) -> str +``` Given a 2 digit language code abbreviation, returns the full name of the language. The language name will be passed through the `word()` function. -**Arguments**: +#### Arguments - `language_code` _str_ - A 2 digit language code abbreviation. -**Returns**: +#### Returns - `str` - The full name of the language. -#### safe\_states\_list + + +## safe\_states\_list + +```python +def safe_states_list(country_code: str) -> List[Dict[str, str]] +``` Wrapper around states_list that doesn't error if passed an invalid country_code (e.g., a country name spelled out) -**Arguments**: +#### Arguments - `country_code` _str_ - A 2 digit country code abbreviation. -**Returns**: +#### Returns List[Dict[str, str]]: A list of dictionaries with field prompts for states. -#### has\_parsable\_pronouns + + +## has\_parsable\_pronouns + +```python +def has_parsable_pronouns(pronouns: str) -> bool +``` Returns True if the pronouns string can be parsed into a dictionary of pronouns. -**Arguments**: +#### Arguments - `pronouns` - a string of pronouns in the format "objective/subjective/possessive" -**Returns**: +#### Returns True if the pronouns string can be parsed into a dictionary of pronouns, False otherwise -#### parse\_custom\_pronouns + + +## parse\_custom\_pronouns + +```python +def parse_custom_pronouns(pronouns: str) -> Dict[str, str] +``` Parses a custom pronoun string into a dictionary of pronouns. -**Arguments**: +#### Arguments - `pronouns` - a string of pronouns in the format "objective/subjective/possessive" -**Returns**: +#### Returns a dictionary of pronouns in the format \{"o": objective, "s": subjective, "p": possessive\} -#### get\_visible\_al\_nav\_items + + +## get\_visible\_al\_nav\_items + +```python +def get_visible_al_nav_items( + nav_items: List[Union[str, dict]]) -> List[Union[str, dict]] +``` Processes a list of nav items and returns only the ones that are not hidden. Can be used to control the visible nav items in a more declarative way while keeping @@ -1070,12 +1636,12 @@ data = [ \{"key2": [\{"subkey": "subvalue", "hidden": False\}, \{"subkey": "subvalue2", "hidden": True\}]\}, ] -**Arguments**: +#### Arguments - `nav_items` - a list of nav items -**Returns**: +#### Returns a list of nav items with hidden items removed diff --git a/docs/components/AssemblyLine/custom_jinja_filters.md b/docs/components/AssemblyLine/custom_jinja_filters.md index e8a5d0874..6c2aa9ff3 100644 --- a/docs/components/AssemblyLine/custom_jinja_filters.md +++ b/docs/components/AssemblyLine/custom_jinja_filters.md @@ -1,9 +1,22 @@ ---- -sidebar_label: custom_jinja_filters -title: AssemblyLine.custom_jinja_filters ---- +# AssemblyLine.custom_jinja_filters -#### catchall\_options +* [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) + * [catchall\_question](#AssemblyLine.custom_jinja_filters.catchall_question) + * [catchall\_subquestion](#AssemblyLine.custom_jinja_filters.catchall_subquestion) + * [if\_final](#AssemblyLine.custom_jinja_filters.if_final) + * [catchall\_fields\_code](#AssemblyLine.custom_jinja_filters.catchall_fields_code) + + + + +### catchall\_options + +```python +def catchall_options(value: Any, *raw_items: Any) -> DACatchAll +``` Jinja2 filter to support defining options for DACatchAll fields inside a DOCX template. @@ -32,41 +45,6 @@ Example in an interview with `features: use catchall: True` turned on: \{\{ my_catchall_field_2 | catchall_options(\{"code1": "label1"\}, \{"code2": "label2"\}) \}\} ``` ``` ---- -if: | - hasattr(x, "_catchall_options") -generic object: DACatchAll -question: | - $\{ x.object_name() \}? -fields: - - $\{ x.object_name() \}: x.value - code: x._catchall_options -``` - -**Arguments**: - -- `value` _DACatchAll_ - The DACatchAll object to which the options will be assigned. -- `*raw_items` - A variable number of arguments representing the options to be added. - -**Returns**: - -- `DACatchAll` - The modified DACatchAll object with the assigned options. - -#### catchall\_label - -Jinja2 filter to allow you to define a label for a DACatchAll field inside a DOCX template. - -This filter takes a label string and assigns it to the `label` attribute of the -DACatchAll object. This label can be used to provide a more descriptive name for the -catchall field in the user interface. - -Example usage in a DOCX template: -Example in an interview with `features: use catchall: True` turned on: -``` -\{\{ my_catchall_field | catchall_label("My Custom Label") \}\} -``` -``` ---- generic object: DACatchAll question: | $\{ x.label if hasattr(x, "label") else x.object_name() \}? @@ -74,17 +52,23 @@ fields: - $\{ x.label if hasattr(x, "label") else x.object_name() \}: x.value ``` -**Arguments**: +#### Arguments - `value` _DACatchAll_ - The DACatchAll object to which the label will be assigned. - `label` _str_ - The label string to assign to the DACatchAll object. -**Returns**: +#### Returns - `DACatchAll` - The modified DACatchAll object with the assigned label. -#### catchall\_datatype + + +### catchall\_datatype + +```python +def catchall_datatype(value: Any, datatype: str) -> DACatchAll +``` Jinja2 filter to allow you to define a datatype for a DACatchAll field inside a DOCX template. @@ -98,17 +82,23 @@ Example usage in a DOCX template: \{\{ my_catchall_field | catchall_datatype("radio") \}\} ``` -**Arguments**: +#### Arguments - `value` _DACatchAll_ - The DACatchAll object to which the datatype will be assigned. - `datatype` _str_ - The datatype string to assign to the DACatchAll object. -**Returns**: +#### Returns - `DACatchAll` - The modified DACatchAll object with the assigned datatype. -#### catchall\_question + + +### catchall\_question + +```python +def catchall_question(value: Any, question: str) -> DACatchAll +``` Jinja2 filter to allow you to define a question for a DACatchAll field inside a DOCX template. @@ -122,17 +112,23 @@ Example usage in a DOCX template: \{\{ my_catchall_field | catchall_question("What additional information do you need?") \}\} ``` -**Arguments**: +#### Arguments - `value` _DACatchAll_ - The DACatchAll object to which the question will be assigned. - `question` _str_ - The question string to assign to the DACatchAll object. -**Returns**: +#### Returns - `DACatchAll` - The modified DACatchAll object with the assigned question. -#### catchall\_subquestion + + +### catchall\_subquestion + +```python +def catchall_subquestion(value: Any, subquestion: str) -> DACatchAll +``` Jinja2 filter to allow you to define a subquestion for a DACatchAll field inside a DOCX template. @@ -146,17 +142,28 @@ Example usage in a DOCX template: \{\{ my_catchall_field | catchall_subquestion("Please provide additional details.") \}\} ``` -**Arguments**: +#### Arguments - `value` _DACatchAll_ - The DACatchAll object to which the subquestion will be assigned. - `subquestion` _str_ - The subquestion string to assign to the DACatchAll object. -**Returns**: +#### Returns - `DACatchAll` - The modified DACatchAll object with the assigned subquestion. -#### if\_final + + +### if\_final + +```python +@pass_context +def if_final(context: Jinja2Context, + value: Any, + i: Optional[str] = None, + expected_values: Union[str, List[str]] = "final", + placeholder: Optional[str] = None) -> Any +``` Jinja2 filter to only seek the definition of a variable if the current value of `i` is equal to the expected value (normally "final"); otherwise, @@ -216,30 +223,36 @@ as in an ALDocument's "preview" or "final" values. ``` -**Arguments**: +#### Arguments - `context` _Jinja2Context_ - The Jinja2 context, automatically passed by the `pass_context` decorator. - `value` _Any_ - The original value as passed to the filter. - `i` _str, optional_ - The current value of `i`. If not provided, it will be fetched from the context. -- `expected_i` _Union[str, List[str]], optional_ - The expected value(s) of `i` to trigger passthrough of `value`. +- `expected_values` _Union[str, List[str]], optional_ - The expected value(s) of `i` to trigger returning `value`. Defaults to "final". - `placeholder` _str, optional_ - The placeholder string to return if the condition is not met. If not provided, a default placeholder will be generated based on the variable name. -**Returns**: +#### Returns + +- `Any` - The original `value` if `i` matches `expected_values`, otherwise the `placeholder`. -- `Any` - The original `value` if `i` matches `expected_i`, otherwise the `placeholder`. + -#### catchall\_fields\_code +### catchall\_fields\_code + +```python +def catchall_fields_code(value: Any) -> List[Dict[str, Any]] +``` Create Docassemble code for a catchall field with the appropriate datatypes. -**Arguments**: +#### Arguments - `value` _DACatchAll_ - The DACatchAll object containing the question and options. -**Returns**: +#### Returns List[Dict[str, Any]]: A dictionary containing the Docassemble code for the catchall question. diff --git a/docs/components/AssemblyLine/language.md b/docs/components/AssemblyLine/language.md index bf19f6e3a..a0ade6bbc 100644 --- a/docs/components/AssemblyLine/language.md +++ b/docs/components/AssemblyLine/language.md @@ -1,38 +1,68 @@ ---- -sidebar_label: language -title: AssemblyLine.language ---- +# AssemblyLine.language -#### get\_local\_languages\_yaml +* [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) + * [get\_language\_list\_dropdown\_item](#AssemblyLine.language.get_language_list_dropdown_item) + * [get\_language\_list](#AssemblyLine.language.get_language_list) + * [get\_language\_list\_item](#AssemblyLine.language.get_language_list_item) + + + + +### get\_local\_languages\_yaml + +```python +def get_local_languages_yaml() -> str +``` Get the path to the local languages.yml file. If it does not exist, it will return the path to the languages.yml -**Returns**: +#### Returns - `str` - the path to the local languages.yml file if it exists, otherwise the path to the languages.yml file -#### get\_tuples + + +### get\_tuples + +```python +def get_tuples(lang_codes: List[str], + languages_path: Optional[str] = None) -> List[Tuple[str, str]] +``` Returns a list of tuples representing the language name, followed by language ISO 639-1 code. It will use the native_name value from the languages.yml file if available, otherwise it will use the English name from pycountry. If neither is present, it will use the language code itself. -**Arguments**: +#### Arguments - `lang_codes` - a list of ISO 639-1 language codes (e.g. ['en', 'es']) - `languages_path` - the path to the languages.yml file (defaults to data/sources/languages.yml) -**Returns**: +#### Returns A list of tuples representing the language name, followed by language ISO 639-1 code. -#### get\_language\_list\_dropdown + + +### get\_language\_list\_dropdown + +```python +def 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") -> str +``` Get a Bootstrap 5 dropdown menu for language selection that can be added to navigation bar. -**Arguments**: +#### Arguments - `lang_codes` - a list of ISO 639-1 language codes (e.g. ['en', 'es']) - `current` - the current language code @@ -41,27 +71,45 @@ Get a Bootstrap 5 dropdown menu for language selection that can be added to navi - `icon` - the name of the icon to use for the dropdown menu (defaults to fa-solid fa-language fa-xl) - `extra_class` - additional classes to add to the link -**Returns**: +#### Returns A string containing the HTML for a dropdown menu for language selection. -#### get\_language\_list\_dropdown\_item + + +### get\_language\_list\_dropdown\_item + +```python +def get_language_list_dropdown_item(language: Tuple[str, str], + link: bool = True, + event_name="al_change_language") -> str +``` Given an ordered tuple, returns a link to the current interview with lang=language code and the link title given in the first part of the tuple. -**Arguments**: +#### Arguments - `language` - a tuple containing the language name and language code - `link` - whether to return a link or just the text - `event_name` - the name of the event to trigger when the language is changed -**Returns**: +#### Returns - `str` - A string containing the HTML for a dropdown menu item for language selection. -#### get\_language\_list + + +### get\_language\_list + +```python +def 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_change_language") -> str +``` Given a list of language codes, returns a Bootstrap-formatted unordered inline list. The current language will not be a link. @@ -69,7 +117,7 @@ a Bootstrap-formatted unordered inline list. The current language will not be a Deprecated behavior: instead of a list of language codes, you can provide list of tuples containing the language name and language code. This is deprecated and may be removed in a future version. -**Arguments**: +#### Arguments - `languages` - a list of tuples containing the language name and language code (deprecated) - `current` - the current language code @@ -78,23 +126,31 @@ tuples containing the language name and language code. This is deprecated and ma - `event_name` - the name of the event to trigger when the language is changed -**Returns**: +#### Returns A string containing the HTML for an unordered inline list of language selection. -#### get\_language\_list\_item + + +### get\_language\_list\_item + +```python +def get_language_list_item(language, + link=True, + event_name="al_change_language") -> str +``` Given an ordered tuple, returns a link to the current interview with lang=language code and the link title given in the first part of the tuple. -**Arguments**: +#### Arguments - `language` - a tuple containing the language name and language code - `link` - whether to return a link or just the text - `event_name` - the name of the event to trigger when the language is changed -**Returns**: +#### Returns - `str` - A string containing the HTML for an unordered inline list item for language selection. diff --git a/docs/components/AssemblyLine/sessions.md b/docs/components/AssemblyLine/sessions.md index 1051cb677..3d19e2f3d 100644 --- a/docs/components/AssemblyLine/sessions.md +++ b/docs/components/AssemblyLine/sessions.md @@ -1,22 +1,65 @@ ---- -sidebar_label: sessions -title: AssemblyLine.sessions ---- - -#### is\_file\_like +# 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) + * [get\_saved\_interview\_list](#AssemblyLine.sessions.get_saved_interview_list) + * [find\_matching\_sessions](#AssemblyLine.sessions.find_matching_sessions) + * [delete\_interview\_sessions](#AssemblyLine.sessions.delete_interview_sessions) + * [interview\_list\_html](#AssemblyLine.sessions.interview_list_html) + * [nice\_interview\_title](#AssemblyLine.sessions.nice_interview_title) + * [pascal\_to\_zwspace](#AssemblyLine.sessions.pascal_to_zwspace) + * [nice\_interview\_subtitle](#AssemblyLine.sessions.nice_interview_subtitle) + * [radial\_progress](#AssemblyLine.sessions.radial_progress) + * [local\_date](#AssemblyLine.sessions.local_date) + * [session\_list\_html](#AssemblyLine.sessions.session_list_html) + * [rename\_interview\_answers](#AssemblyLine.sessions.rename_interview_answers) + * [set\_current\_session\_metadata](#AssemblyLine.sessions.set_current_session_metadata) + * [rename\_current\_session](#AssemblyLine.sessions.rename_current_session) + * [save\_interview\_answers](#AssemblyLine.sessions.save_interview_answers) + * [get\_filtered\_session\_variables](#AssemblyLine.sessions.get_filtered_session_variables) + * [get\_filtered\_session\_variables\_string](#AssemblyLine.sessions.get_filtered_session_variables_string) + * [load\_interview\_answers](#AssemblyLine.sessions.load_interview_answers) + * [load\_interview\_json](#AssemblyLine.sessions.load_interview_json) + * [export\_interview\_variables](#AssemblyLine.sessions.export_interview_variables) + * [is\_valid\_json](#AssemblyLine.sessions.is_valid_json) + * [config\_with\_language\_fallback](#AssemblyLine.sessions.config_with_language_fallback) + * [get\_filenames\_having\_sessions](#AssemblyLine.sessions.get_filenames_having_sessions) + * [get\_combined\_filename\_list](#AssemblyLine.sessions.get_combined_filename_list) + * [update\_session\_metadata](#AssemblyLine.sessions.update_session_metadata) + * [update\_current\_session\_metadata](#AssemblyLine.sessions.update_current_session_metadata) + + + + +### is\_file\_like + +```python +def is_file_like(obj: Any) -> bool +``` Return True if the object is a file-like object. -**Arguments**: +#### Arguments - `obj` _Any_ - The object to test -**Returns**: +#### Returns - `bool` - True if the object is a file-like object. -#### set\_interview\_metadata + + +### set\_interview\_metadata + +```python +def set_interview_metadata(filename: str, + session_id: str, + data: Dict, + metadata_key_name="metadata") -> None +``` Add searchable interview metadata for the specified filename and session ID. Intended to be used to add an interview title, etc. @@ -26,30 +69,54 @@ Standardized metadata dictionary: - original_interview_filename - variable_count -**Arguments**: +#### Arguments - `filename` _str_ - The filename of the interview to add metadata for - `session_id` _str_ - The session ID of the interview to add metadata for - `data` _Dict_ - The metadata to add - `metadata_key_name` _str, optional_ - The name of the metadata key. Defaults to "metadata". -#### get\_interview\_metadata + + +### get\_interview\_metadata + +```python +def get_interview_metadata( + filename: str, + session_id: str, + metadata_key_name: str = "metadata") -> Dict[str, Any] +``` Retrieve the unencrypted metadata associated with an interview. We implement this with the docassemble jsonstorage table and a dedicated `tag` which defaults to `metadata`. -**Arguments**: +#### Arguments - `filename` _str_ - The filename of the interview to retrieve metadata for - `session_id` _str_ - The session ID of the interview to retrieve metadata for - `metadata_key_name` _str, optional_ - The name of the metadata key. Defaults to "metadata". -**Returns**: +#### Returns Dict[str, Any]: The metadata associated with the interview -#### get\_saved\_interview\_list + + +### get\_saved\_interview\_list + +```python +def 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) -> List[Dict[str, Any]] +``` Get a list of saved sessions for the specified filename. If the save_interview_answers function was used to add metadata, the result list will include columns containing the metadata. @@ -62,7 +129,7 @@ and likely do not need to be resumed, it will also have the side effect of exclu results. Answer sets generally have exactly one "step", which is the step where information was copied from an existing interview to the answer set. -**Arguments**: +#### Arguments - `filename` _str, optional_ - The filename of the interview to retrieve sessions for. Defaults to al_session_store_default_filename. - `user_id` _Union[int, str, None], optional_ - The user ID to retrieve sessions for. Defaults to None. @@ -75,17 +142,38 @@ an existing interview to the answer set. - `exclude_newly_started_sessions` _bool, optional_ - Whether to exclude sessions that are still on "step 1". Defaults to False. -**Returns**: +#### Returns List[Dict[str, Any]]: A list of saved sessions for the specified filename. -#### find\_matching\_sessions + + +### find\_matching\_sessions + +```python +def 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 +) -> List[Dict[str, Any]] +``` Get a list of sessions where the metadata for the session matches the provided keyword search terms and metadata filters. This function is designed to be used in a search interface where the user can search for sessions by keyword and specific metadata values. The keyword search is case-insensitive and will match any part of the metadata column values. -**Arguments**: +#### Arguments - `keyword` _str_ - The keyword to search for in the metadata - `metadata_column_names` _List[str], optional_ - The names of the metadata columns to search. If not provided, defaults to ["title", "auto_title", "description"]. @@ -106,7 +194,7 @@ The keyword search is case-insensitive and will match any part of the metadata c - cast_type: Optional. One of 'int', 'float', or None for string (default) -**Returns**: +#### Returns List[Dict[str, Any]]: A list of saved sessions for the specified filename that match the search keyword and metadata filters @@ -129,19 +217,50 @@ 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 + + +### delete\_interview\_sessions + +```python +def delete_interview_sessions( + user_id: Optional[int] = None, + filename_to_exclude: str = al_session_store_default_filename, + exclude_current_filename: bool = True) -> None +``` Delete all sessions for the specified user, excluding the current filename and by default, the intentionally saved "answer sets". Created because interview_list(action="delete_all") is both quite slow and because it deletes answer sets. -**Arguments**: +#### Arguments - `user_id` _Optional[int], optional_ - The user ID to delete sessions for. Defaults to None. - `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 + + +### interview\_list\_html + +```python +def 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) -> str +``` Return a string containing an HTML-formatted table with the list of saved answers associated with the specified filename. @@ -154,7 +273,7 @@ designed when inside an AssemblyLine line interview. are on "page 1" (exactly 1 step was taken to copy the answers and the user isn't able to interact with the answer set itself in a way that adds additional steps) -**Arguments**: +#### Arguments - `filename` _str, optional_ - Name of the file. Defaults to `al_session_store_default_filename`. - `user_id` _Union[int, str, None], optional_ - User's ID. Defaults to None. @@ -175,11 +294,17 @@ itself in a way that adds additional steps) - `answers` _Optional[List[Dict[str, Any]]], optional_ - A list of answers to format and display. Defaults to showing all sessions for the current user. -**Returns**: +#### Returns - `str` - HTML-formatted table containing the list of saved answers. -#### nice\_interview\_title + + +### nice\_interview\_title + +```python +def nice_interview_title(answer: Dict[str, str]) -> str +``` Return a human readable version of the interview name. Will try several strategies in descending priority order. @@ -187,78 +312,131 @@ in descending priority order. 1. Try removing the package and path from the filename and replace _ with spaces. 4. Finally, return "Untitled interview" or translated phrase from system-wide words.yml -**Arguments**: +#### Arguments - `answer` _Dict[str, str]_ - The answer dictionary to get the interview title from -**Returns**: +#### Returns - `str` - The human readable interview title -#### pascal\_to\_zwspace + + +### pascal\_to\_zwspace + +```python +def pascal_to_zwspace(text: str) -> str +``` Insert a zero-width space into words that are PascalCased to help with word breaks on small viewports. -**Arguments**: +#### Arguments - `text` _str_ - The text to insert zero-width spaces into -**Returns**: +#### Returns - `str` - The text with zero-width spaces inserted -#### nice\_interview\_subtitle + + +### nice\_interview\_subtitle + +```python +def nice_interview_subtitle(answer: Dict[str, str], + exclude_identical=True) -> str +``` Return first defined of the "title" metadata, the "auto_title" metadata, or empty string. If exclude_identical, return empty string when title is the same as the subtitle. -**Arguments**: +#### Arguments - `answer` _Dict[str, str]_ - The answer dictionary to get the interview subtitle from - `exclude_identical` _bool, optional_ - If True, excludes the subtitle if it is identical to the title. Defaults to True. -**Returns**: +#### Returns - `str` - The human readable interview subtitle -#### radial\_progress + + +### radial\_progress + +```python +def radial_progress(answer: Dict[str, Union[str, int]]) -> str +``` Return HTML for a radial progress bar, or the number of steps if progress isn't available in the metadata. -**Arguments**: +#### Arguments - `answer` _Dict[str, Union[str, int]]_ - The answer dictionary to get the interview progress from -**Returns**: +#### Returns - `str` - the HTML as a string -#### local\_date + + +### local\_date + +```python +def local_date(utcstring: Optional[str]) -> DADateTime +``` Return a localized date from a UTC string. -**Arguments**: +#### Arguments - `utcstring` _Optional[str]_ - The UTC string to convert to a localized date -**Returns**: +#### Returns - `DADateTime` - The localized date -#### session\_list\_html + + +### session\_list\_html + +```python +def 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) -> str +``` Return a string containing an HTML-formatted table with the list of user sessions. While interview_list_html() is for answer sets, this feature is for standard user sessions. The results exclude the answer set filename by default. -**Arguments**: +#### Arguments - `filename` _Optional[str], optional_ - Name of the file. Defaults to None. - `user_id` _Union[int, str, None], optional_ - User's ID. Defaults to None. @@ -285,16 +463,25 @@ user sessions. The results exclude the answer set filename by default. -**Returns**: +#### Returns - `str` - HTML-formatted table containing the list of user sessions. -#### rename\_interview\_answers + + +### rename\_interview\_answers + +```python +def rename_interview_answers(filename: str, + session_id: str, + new_name: str, + metadata_key_name: str = "metadata") -> None +``` Update the 'title' metadata of an interview, as stored in the dedicated `metadata` column, without touching other metadata that may be present. -**Arguments**: +#### Arguments - `filename` _str_ - The filename of the interview to rename - `session_id` _str_ - The session ID of the interview to rename @@ -303,30 +490,58 @@ 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 + + +### set\_current\_session\_metadata + +```python +def set_current_session_metadata(data: Dict[str, Any], + metadata_key_name: str = "metadata") -> None +``` Set metadata for the current session, such as the title, in an unencrypted database entry. -**Arguments**: +#### Arguments - `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 + + +### rename\_current\_session + +```python +def rename_current_session(new_name: str, + metadata_key_name: str = "metadata") -> None +``` Update the "title" metadata entry for the current session without changing any other metadata that might be present. -**Arguments**: +#### Arguments - `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 + + +### save\_interview\_answers + +```python +def 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) -> str +``` Copies the answers from a given session into a new session with a specified interview filename. -**Arguments**: +#### Arguments - `filename` _str, optional_ - The desired filename for the new session. Defaults to `al_session_store_default_filename`. - `variables_to_filter` _Union[Set[str], List[str], None], optional_ - The "base" list or set of variables to filter out. Defaults to `al_sessions_variables_to_remove`. There's usually no reason to change this and changing it might break sessions. @@ -338,17 +553,28 @@ Copies the answers from a given session into a new session with a specified inte - `additional_variables_to_filter` _Union[Set[str], List[str], None], optional_ - List or set of variables to filter out. Defaults to None. -**Returns**: +#### Returns - `str` - ID of the new session. -#### get\_filtered\_session\_variables + + +### get\_filtered\_session\_variables + +```python +def 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 +) -> Dict[str, Any] +``` Retrieves a filtered subset of variables from a specified interview and session. If no filename and session ID are given, it will return a filtered list of variables from the current interview. -**Arguments**: +#### Arguments - `filename` _Optional[str], optional_ - Filename of the session. Defaults to None. - `session_id` _Optional[int], optional_ - Session ID to retrieve variables from. Defaults to None. @@ -356,16 +582,28 @@ from the current interview. - `additional_variables_to_filter` _Union[Set[str], List[str], None], optional_ - List or set of additional variables to exclude. Defaults to None. -**Returns**: +#### Returns Dict[str, Any]: A dictionary of filtered session variables. -#### get\_filtered\_session\_variables\_string + + +### get\_filtered\_session\_variables\_string + +```python +def 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) -> str +``` Returns a JSON string that represents the filtered contents of a specified filename and session ID. If no filename and session ID are provided, the current session's variables will be used. -**Arguments**: +#### Arguments - `filename` _Optional[str], optional_ - Filename of the session. Defaults to None. - `session_id` _Optional[int], optional_ - Session ID to retrieve variables from. Defaults to None. @@ -374,17 +612,30 @@ If no filename and session ID are provided, the current session's variables - `indent` _int, optional_ - Number of spaces to indent the JSON string. Defaults to 4. -**Returns**: +#### Returns - `str` - A JSON-formatted string of filtered session variables. -#### load\_interview\_answers + + +### load\_interview\_answers + +```python +def 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 +) -> Optional[Union[int, bool]] +``` Loads answers from a specified session. If the parameter `new_session` is set to True, it will create a new session with the provided or current interview filename. Otherwise, it will load the answers into the active session. This function is primarily used for migrating answers between sessions. -**Arguments**: +#### Arguments - `old_interview_filename` _str_ - Filename of the old interview. - `old_session_id` _str_ - Session ID of the old interview. @@ -394,17 +645,27 @@ the active session. This function is primarily used for migrating answers betwee - `additional_variables_to_filter` _Optional[List[str]], optional_ - List of additional variables to exclude. Defaults to None. -**Returns**: +#### Returns 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 + + +### load\_interview\_json + +```python +def load_interview_json( + json_string: str, + new_session: bool = False, + new_interview_filename: Optional[str] = None, + variables_to_filter: Optional[List[str]] = None) -> Optional[int] +``` Given a JSON string, this function loads the specified variables into a Docassemble session. JSON strings containing annotated class names will be transformed into Docassemble objects. If the `new_session` argument is not set, the JSON answers will be loaded into the current interview. -**Arguments**: +#### Arguments - `json_string` _str_ - A JSON-formatted string containing session variables. - `new_session` _bool, optional_ - Specifies whether to create a new session or load into the current one. Defaults to False. @@ -412,17 +673,29 @@ If the `new_session` argument is not set, the JSON answers will be loaded into t - `variables_to_filter` _Optional[List[str]], optional_ - List of variables to exclude. Defaults to None. -**Returns**: +#### Returns 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 + + +### export\_interview\_variables + +```python +def 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) -> DAFile +``` Generates a DAFile containing a JSON representation of a specified session's interview answers. The resultant output is compatible with `set_session_variables(process_objects=True)` and `set_variables(process_objects=True)` methods. -**Arguments**: +#### Arguments - `filename` _Optional[str], optional_ - Filename of the session. Defaults to None. - `session_id` _Optional[int], optional_ - Session ID to retrieve variables from. Defaults to None. @@ -431,24 +704,38 @@ The resultant output is compatible with `set_session_variables(process_objects=T - `additional_variables_to_filter` _Union[Set, List[str], None], optional_ - List or set of additional variables to exclude. Defaults to None. -**Returns**: +#### Returns - `DAFile` - DAFile with a JSON representation of the answers -#### is\_valid\_json + + +### is\_valid\_json + +```python +def is_valid_json(json_string: str) -> bool +``` Checks if the provided string is a valid JSON-formatted string. -**Arguments**: +#### Arguments - `json_string` _str_ - The string to be checked for JSON validity. -**Returns**: +#### Returns - `bool` - True if the string is a valid JSON, otherwise it raises a validation error and returns False. -#### config\_with\_language\_fallback + + +### config\_with\_language\_fallback + +```python +def config_with_language_fallback( + config_key: str, + top_level_config_key: Optional[str] = None) -> Optional[str] +``` Returns the value of a config key under `assembly line` `interview list` with options to fallback to an alternative key at the top level of the global configuration. @@ -465,32 +752,50 @@ en: In progress forms es: Formularios en progreso short title: My forms -**Arguments**: +#### Arguments - `config_key` _str_ - The config key to look up. The config can be a single string or a dictionary with language keys. - `top_level_config_key` _str, optional_ - Optional, alternative top-level config key to look up. Defaults to None. -**Returns**: +#### Returns - `str` - The value of the config key, or the alternative key, or None. -#### get\_filenames\_having\_sessions + + +### get\_filenames\_having\_sessions + +```python +def get_filenames_having_sessions( + user_id: Optional[Union[int, str]] = None, + global_search_allowed_roles: Optional[Union[Set[str], List[str]]] = None +) -> List[str] +``` Get a list of all filenames that have sessions saved for a given user, in order to help show the user a good list of interviews to filter search results. -**Arguments**: +#### Arguments - `user_id` _Optional[Union[int, str]], optional_ - User ID to get the list of filenames for. Defaults to current logged-in user. Use "all" to get all filenames. - `global_search_allowed_roles` _Optional[Union[Set[str], List[str]]], optional_ - Roles that are allowed to search for all sessions. Defaults to admin, developer, and advocate. -**Returns**: +#### Returns - `List[str]` - List of filenames that have sessions saved for the user. -#### get\_combined\_filename\_list + + +### get\_combined\_filename\_list + +```python +def get_combined_filename_list( + user_id: Optional[Union[int, str]] = None, + global_search_allowed_roles: Optional[Union[Set[str], List[str]]] = None +) -> List[Dict[str, str]] +``` Get a list of all filenames that have sessions saved for a given user. If it is possible to show a descriptive name for the filename (from the main dispatch area of the configuration), @@ -499,36 +804,53 @@ it will show that instead of the filename. The results will be in the form of [\{filename: Descriptive name\}], which is what the Docassemble radio button and dropdown list expect. -**Arguments**: +#### Arguments - `user_id` _Optional[Union[int, str]], optional_ - User ID to get the list of filenames for. Defaults to current logged in user. Use "all" to get all filenames. - `global_search_allowed_roles` _Optional[Union[Set[str], List[str]]], optional_ - Roles that are allowed to search for all sessions. Defaults to admin, developer, and advocate. -**Returns**: +#### Returns List[Dict[str, str]]: List of filenames that have sessions saved for the user. -#### update\_session\_metadata + + +### update\_session\_metadata + +```python +def update_session_metadata(filename: str, + session_id: str, + data: Dict[str, Any], + metadata_key_name: str = "metadata") -> None +``` Upsert session metadata into jsonstorage using a PostgreSQL advisory lock (two-int form) to serialize concurrent upserts on the same (session_id,filename,tags) key. -**Arguments**: +#### Arguments - `filename` - The filename of the interview session to update. - `session_id` - The ID of the session to update. - `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 + + +### update\_current\_session\_metadata + +```python +def update_current_session_metadata(data: Dict[str, Any], + metadata_key_name: str = "metadata" + ) -> None +``` Updates metadata for the current session without retrieving the data first. This is a wrapper for update_session_metadata() that uses the current interview's filename and session ID from current_context(). -**Arguments**: +#### Arguments - `data` _Dict[str, Any]_ - A dictionary of metadata to add or update. - `metadata_key_name` _str, optional_ - The tag for the metadata in the diff --git a/docs/components/AssemblyLine/sign.md b/docs/components/AssemblyLine/sign.md index b2f606285..bb0ba06a1 100644 --- a/docs/components/AssemblyLine/sign.md +++ b/docs/components/AssemblyLine/sign.md @@ -1,9 +1,19 @@ ---- -sidebar_label: sign -title: AssemblyLine.sign ---- +# AssemblyLine.sign -#### find\_font\_file\_by\_name +* [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) + + + + +### find\_font\_file\_by\_name + +```python +def find_font_file_by_name(font_name: str, + search_dirs: List[str]) -> Optional[str] +``` Recursively search for a font file by name in the specified directories. @@ -11,17 +21,26 @@ This function appends '.ttf' to the font name if it is not already pre searches through each directory in `search_dirs` recursively for a file that matches the font name (case-insensitive). -**Arguments**: +#### Arguments - `font_name` _str_ - The name of the font to search for (without path). - `search_dirs` _List[str]_ - A list of directories to search. -**Returns**: +#### Returns - `Optional[str]` - The full path to the font file if found; otherwise, None. -#### get\_font + + +### get\_font + +```python +def get_font( + font_name: Optional[str] = None, + font_size: int = 48 +) -> Union[ImageFont.ImageFont, ImageFont.FreeTypeFont] +``` Loads a font by name from candidate directories and returns an ImageFont instance. @@ -30,17 +49,27 @@ name (without a path). In the latter case, the function will search for the font `/var/www/.fonts` and `/usr/share/fonts/truetype/`, automatically appending '.ttf' if necessary. If no font is found, the function falls back to the default Pillow font. -**Arguments**: +#### Arguments - `font_name` _Optional[str]_ - The desired font's full path or name. Defaults to None. - `font_size` _int_ - The size of the font to be used. Defaults to 48. -**Returns**: +#### Returns - `ImageFont.ImageFont` - The loaded font instance. -#### create\_signature + + +### create\_signature + +```python +def create_signature(name: str, + output_file: str, + signature_prefix: str = "/s/", + font_name: Optional[str] = None, + font_size: int = 48) -> None +``` Creates an image file that simulates a signature. @@ -49,7 +78,7 @@ The signature image is generated by combining the provided `signature_prefix` create an image with appropriate dimensions, and then the text is drawn onto a white background. The final image is saved to the specified output file path. -**Arguments**: +#### Arguments - `name` _str_ - The person's name to be signed. - `output_file` _str_ - The full file path where the image will be written. diff --git a/docs/components/EFSPIntegration/conversions.md b/docs/components/EFSPIntegration/conversions.md index f5fe66102..928b8462e 100644 --- a/docs/components/EFSPIntegration/conversions.md +++ b/docs/components/EFSPIntegration/conversions.md @@ -1,11 +1,37 @@ ---- -sidebar_label: conversions -title: EFSPIntegration.conversions ---- +# 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) + * [choices\_and\_map](#EFSPIntegration.conversions.choices_and_map) + * [pretty\_display](#EFSPIntegration.conversions.pretty_display) + * [debug\_display](#EFSPIntegration.conversions.debug_display) + * [tyler\_daterep\_to\_datetime](#EFSPIntegration.conversions.tyler_daterep_to_datetime) + * [tyler\_timestamp\_to\_datetime](#EFSPIntegration.conversions.tyler_timestamp_to_datetime) + * [validate\_tyler\_regex](#EFSPIntegration.conversions.validate_tyler_regex) + * [parse\_service\_contacts](#EFSPIntegration.conversions.parse_service_contacts) + * [parse\_case\_info](#EFSPIntegration.conversions.parse_case_info) + * [fetch\_case\_info](#EFSPIntegration.conversions.fetch_case_info) + * [filter\_payment\_accounts](#EFSPIntegration.conversions.filter_payment_accounts) + * [payment\_account\_labels](#EFSPIntegration.conversions.payment_account_labels) + * [filing\_id\_and\_label](#EFSPIntegration.conversions.filing_id_and_label) + * [get\_tyler\_roles](#EFSPIntegration.conversions.get_tyler_roles) + Functions that help convert the JSON-ized XML from the proxy server into usable information. -#### error\_notification + + +### error\_notification + +```python +def error_notification(err, + message=None, + trace=None, + referer=None, + the_vars=None) +``` Copied from docassemble.webapp.server.error_notification, since: 1) things from webapp.* are unstable @@ -13,12 +39,24 @@ Copied from docassemble.webapp.server.error_notification, since: Some slight modifications to work without server backends -#### log\_error\_and\_notify + + +### log\_error\_and\_notify + +```python +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 + + +### convert\_court\_to\_id + +```python +def convert_court_to_id(trial_court) -> str +``` Converts a court type to the specific id string expected by Tyler. @@ -27,21 +65,29 @@ A fairly ad-hoc function; it will check if the object has several attributes tries to just make a lower case on the string. We strongly recommend that your court object use the "tyler_court_code" attribute though. -**Arguments**: +#### Arguments - `trial_court` - the court object -**Returns**: +#### Returns the string that should be the Tyler EFM court id, i.e. `adams` or `peoria:cr` -#### choices\_and\_map + + +### choices\_and\_map + +```python +def choices_and_map(codes_list: List[Dict[str, Any]], + display: str = None, + backing: str = None) -> Tuple[List[Any], Dict] +``` Takes the responses from the 'codes' service and make a DA ready list of choices and a map back to the full code object -**Arguments**: +#### Arguments - `codes_list` - should be the direct response from a 'codes' service, i.e. `proxy_conn.get_case_categories(court_id).data` - `display` - a python format string, where the input variables are the keys of the individual code elements. By @@ -49,18 +95,24 @@ to the full code object - `backing` - the key to each dict element in the codes_list that you want to use as the "canonical" representation of the code, i.e. each is unique, and there aren't conflicts -**Returns**: +#### Returns a tuple; first, a list of the codes that can be used at the `choices` in a docassemble field, 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 + + +### pretty\_display + +```python +def pretty_display(data, tab_depth=0, skip_xml=True, item_name=None) -> str +``` Given an arbitrarily nested JSON structure, print it nicely as markdown. Recursive, for subsequent calls `tab_depth` increases. -**Arguments**: +#### Arguments - `data` - the JSON structure (python dicts, lists, strings and ints) to print - `tab_depth` - how many spaces to add before each new line, to make the markdown correct @@ -69,40 +121,82 @@ Recursive, for subsequent calls `tab_depth` increases. - `item_name` - when recursing, will show the parent's name when showing elements in a list -**Returns**: +#### Returns The string of markdown text that displays info about the given JSON structure -#### debug\_display + + +### 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) -#### tyler\_daterep\_to\_datetime + + +### tyler\_daterep\_to\_datetime + +```python +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 + + +### tyler\_timestamp\_to\_datetime + +```python +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 + + +### validate\_tyler\_regex + +```python +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 + + +### parse\_service\_contacts + +```python +def parse_service_contacts(service_list) +``` 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 + + +### parse\_case\_info + +```python +def parse_case_info(proxy_conn: ProxyConnection, + new_case: DAObject, + entry: dict, + court_id: str, + *, + fetch: bool = True, + roles: dict = None) +``` Given sparse information about a case, gets the full details about it -**Arguments**: +#### Arguments - `proxy_conn` - the connection to the EFileProxyServer - `new_case` - the object to hold all of the information about the case @@ -113,7 +207,15 @@ 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 + + +### fetch\_case\_info + +```python +def fetch_case_info(proxy_conn: ProxyConnection, + new_case: DAObject, + roles: Optional[dict] = None) -> None +``` Fills in these attributes with the full case details: * attorneys @@ -125,12 +227,18 @@ Fills in these attributes with the full case details: * date * participants -#### filter\_payment\_accounts + + +### filter\_payment\_accounts + +```python +def filter_payment_accounts(account_list, allowable_card_types: List) -> List +``` Gets a list of all payment accounts and filters them by if the card is accepted at a particular court. -**Arguments**: +#### Arguments account_list: - `allowable_card_types` - a list of the accepted card types at a court, usually @@ -138,21 +246,43 @@ accepted at a particular court. [get_full_court_info](interview_logic#get_full_court_info)'s response -**Returns**: +#### Returns the list of payment account choices that are valid for a particular court -#### payment\_account\_labels + + +### payment\_account\_labels + +```python +def payment_account_labels(resp: ApiResponse) -> Optional[List[Dict]] +``` Returns all payment accounts as choices, without filters. -#### filing\_id\_and\_label + + +### 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) 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 + + +### get\_tyler\_roles + +```python +def get_tyler_roles( + proxy_conn: ProxyConnection, + login_data: Optional[Mapping], + user_details: Optional[ApiResponse] = None) -> Tuple[bool, bool] +``` Gets whether or not the user of this interview is a Tyler Admin, and a 'global' admin. The global admin means that they are allowed to change specific Global payment methods, diff --git a/docs/components/EFSPIntegration/efm_client.md b/docs/components/EFSPIntegration/efm_client.md index b2dfa02d8..badd8537f 100644 --- a/docs/components/EFSPIntegration/efm_client.md +++ b/docs/components/EFSPIntegration/efm_client.md @@ -1,18 +1,15 @@ ---- -sidebar_label: efm_client -title: EFSPIntegration.efm_client ---- +# EFSPIntegration.efm_client -## DALogger Objects +* [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) + * [register\_user](#EFSPIntegration.efm_client.ProxyConnection.register_user) + * [get\_service\_types](#EFSPIntegration.efm_client.ProxyConnection.get_service_types) + * [serialize\_person](#EFSPIntegration.efm_client.serialize_person) -```python -class DALogger(LoggerAdapter) -``` - -#### log -Delegate a log call to Docassemble's `log` function, after adding -contextual information from this adapter instance. + ## ProxyConnection Objects @@ -25,29 +22,73 @@ The main class you use to communicate with the E-file proxy server from docassem Many methods are unchanged from the parent class, [EfspConnection](py_efsp_client#EfspConnection), and are documented there. -#### \_\_init\_\_ + + +### \_\_init\_\_ + +```python +def __init__(*, + url: str = None, + api_key: str = None, + credentials_code_block: str = "tyler_login", + default_jurisdiction: str = None) +``` Creates the connection. Tries to get params from docassemble's config, but can be overriden with parameters to __init__. -#### authenticate\_user + + +### authenticate\_user + +```python +def authenticate_user(tyler_email: str = None, + tyler_password: str = None, + jeffnet_key: str = None, + *, + jurisdiction: str = None) -> ApiResponse +``` Params: tyler_email (str) tyler_password (str) jeffnet_key (str) -#### register\_user + + +### register\_user + +```python +def register_user(person: Union[Individual, dict], + registration_type: str, + *, + password: str = None, + firm_name_or_id: str = None) -> ApiResponse +``` registration_type needs to be INDIVIDUAL, FIRM_ADMINISTRATOR, or FIRM_ADMIN_NEW_MEMBER. 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 + + +### get\_service\_types + +```python +def get_service_types( + court_id: str, + court_bundle: Union[ALDocumentBundle, 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 -#### serialize\_person + + +### serialize\_person + +```python +def serialize_person(person: Union[Person, Individual]) -> Dict +``` Converts a Docassemble Person or Individual into a dictionary suitable for json.dumps and in format expected by Tyler-specific endpoints on the EFSPProxy diff --git a/docs/components/EFSPIntegration/interview_logic.md b/docs/components/EFSPIntegration/interview_logic.md index d462d0b8f..4c38a4b1c 100644 --- a/docs/components/EFSPIntegration/interview_logic.md +++ b/docs/components/EFSPIntegration/interview_logic.md @@ -1,11 +1,24 @@ ---- -sidebar_label: interview_logic -title: EFSPIntegration.interview_logic ---- +# 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) + * [num\_case\_choices](#EFSPIntegration.interview_logic.num_case_choices) + * [search\_case\_by\_name](#EFSPIntegration.interview_logic.search_case_by_name) + * [shift\_case\_select\_window](#EFSPIntegration.interview_logic.shift_case_select_window) + * [get\_full\_court\_info](#EFSPIntegration.interview_logic.get_full_court_info) + * [get\_max\_allowed\_sizes](#EFSPIntegration.interview_logic.get_max_allowed_sizes) + * [make\_filter](#EFSPIntegration.interview_logic.make_filter) + * [filter\_codes](#EFSPIntegration.interview_logic.filter_codes) + * [get\_available\_efile\_courts](#EFSPIntegration.interview_logic.get_available_efile_courts) + 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 ```python @@ -14,11 +27,24 @@ 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 + +```python +def search_went_wrong() -> bool +``` Returns true if something errored during the case search process -#### get\_lookup\_choices + + +### get\_lookup\_choices + +```python +def get_lookup_choices( + can_file_non_indexed_case: bool) -> List[Dict[str, str]] +``` Returns the DA choice list of what ways you are allowed to search for a case; By default, this is "party_search", and "docket_lookup", and depending on the @@ -28,30 +54,81 @@ 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 + +```python +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 + + +### search\_case\_by\_name + +```python +def search_case_by_name(*, + proxy_conn, + var_name: str = None, + court_id: str, + somebody, + filter_fn: Callable[[Any], bool], + roles=None) -> Tuple[bool, DAList] +``` 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 + + +### shift\_case\_select\_window + +```python +def shift_case_select_window(proxy_conn, + found_cases: DAList, + *, + direction: str, + start_idx: int, + end_idx: int, + roles: dict = None) -> Tuple[int, int] +``` 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 + + +### get\_full\_court\_info + +```python +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 + + +### get\_max\_allowed\_sizes + +```python +def get_max_allowed_sizes(proxy_conn, + court_id: str) -> Optional[Tuple[int, int]] +``` Returns attachment max size, then message max size -#### make\_filter + + +### make\_filter + +```python +def make_filter( + search: Union[Callable[..., bool], SearchType, + None]) -> Callable[..., bool] +``` Makes a 'filter' function from some simple type. @@ -59,12 +136,29 @@ 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 + + +### filter\_codes + +```python +def filter_codes( + options: Iterable, + filters: Iterable[Union[Callable[..., bool], SearchType]], + default: str, + exclude: Union[Callable[..., bool], SearchType, None] = None +) -> Tuple[List[Any], Optional[str]] +``` 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 + + +### get\_available\_efile\_courts + +```python +def get_available_efile_courts(proxy_conn) -> list +``` Gets the list of efilable courts, if it can diff --git a/docs/components/EFSPIntegration/py_efsp_client.md b/docs/components/EFSPIntegration/py_efsp_client.md index 3dcf79519..76069fe09 100644 --- a/docs/components/EFSPIntegration/py_efsp_client.md +++ b/docs/components/EFSPIntegration/py_efsp_client.md @@ -1,68 +1,120 @@ ---- -sidebar_label: py_efsp_client -title: EFSPIntegration.py_efsp_client ---- +# 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) + * [register\_user](#EFSPIntegration.py_efsp_client.EfspConnection.register_user) + * [get\_password\_rules](#EFSPIntegration.py_efsp_client.EfspConnection.get_password_rules) + * [get\_notification\_options](#EFSPIntegration.py_efsp_client.EfspConnection.get_notification_options) + * [get\_firm](#EFSPIntegration.py_efsp_client.EfspConnection.get_firm) + * [update\_firm](#EFSPIntegration.py_efsp_client.EfspConnection.update_firm) + * [get\_courts](#EFSPIntegration.py_efsp_client.EfspConnection.get_courts) + * [get\_court](#EFSPIntegration.py_efsp_client.EfspConnection.get_court) + * [get\_court\_list](#EFSPIntegration.py_efsp_client.EfspConnection.get_court_list) + * [get\_filing\_list](#EFSPIntegration.py_efsp_client.EfspConnection.get_filing_list) + * [get\_service\_types](#EFSPIntegration.py_efsp_client.EfspConnection.get_service_types) + * [get\_cases\_raw](#EFSPIntegration.py_efsp_client.EfspConnection.get_cases_raw) + 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. -#### CORR\_ID\_HEADER - -TODO(brycew): Figure out how to add + -## LoggerWithContext Objects +## EfspConnection Objects ```python -class LoggerWithContext(LoggerAdapter) +class EfspConnection() ``` -Acts like the `merge_extra` feature from LoggerAdapter (python 3.13) is always on. +A python client that communicates with the E-file proxy server. -See https://github.com/python/cpython/pull/107292/files. + -## EfspConnection Objects +### \_\_init\_\_ ```python -class EfspConnection() +def __init__(*, url: str, api_key: str, default_jurisdiction: str = None) ``` -A python client that communicates with the E-file proxy server. - -#### \_\_init\_\_ - -**Arguments**: +#### Arguments url (str) api_key (str) default_jurisdiction (str) -#### authenticate\_user + + +### authenticate\_user + +```python +def authenticate_user(*, + tyler_email: Optional[str] = None, + tyler_password: Optional[str] = None, + jeffnet_key: Optional[str] = None, + jurisdiction: str = None) -> ApiResponse +``` Authenticates the user with the EFM server (not the E-file proxy). -#### register\_user + + +### register\_user + +```python +def register_user(person: dict, + registration_type: str, + *, + password: str = None, + firm_name_or_id: str = None) -> ApiResponse +``` registration_type needs to be INDIVIDUAL, FIRM_ADMINISTRATOR, or FIRM_ADMIN_NEW_MEMBER. 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 + +```python +def get_password_rules() -> ApiResponse +``` 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 + +```python +def get_notification_options() -> ApiResponse +``` AKA NotificationPreferencesList -#### get\_firm + + +### get\_firm + +```python +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 + + +### update\_firm + +```python +def update_firm(firm: dict) -> ApiResponse +``` firm should have the below keys: * firstName, middleName, lastName if it's a person @@ -71,28 +123,72 @@ firm should have the below keys: * phoneNumber * email -#### get\_courts + + +### get\_courts + +```python +def get_courts(fileable_only: bool = False, + with_names: bool = False) -> ApiResponse +``` Gets the list of courts. -#### get\_court + + +### get\_court + +```python +def get_court(court_id: str) -> ApiResponse +``` Gets codes for a specific court -#### get\_court\_list + + +### 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\_filing\_list + + +### get\_filing\_list + +```python +def get_filing_list(court_id: str, + user_id: str = None, + start_date: datetime = None, + before_date: datetime = None) -> ApiResponse +``` Returns a list of filings that a particular user has made with a court. -#### get\_service\_types + + +### get\_service\_types + +```python +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 + + +### get\_cases\_raw + +```python +def get_cases_raw(court_id: str, + *, + person_name: dict = None, + business_name: str = None, + docket_number: str = None) -> ApiResponse +``` Finds existing cases at a particular court. Only one of person_name, business_name, or docket_number should be provided at a time. diff --git a/docs/components/EFSPIntegration/test/test_proxy_conn.md b/docs/components/EFSPIntegration/test/test_proxy_conn.md index e68283cfc..b62e1c5a3 100644 --- a/docs/components/EFSPIntegration/test/test_proxy_conn.md +++ b/docs/components/EFSPIntegration/test/test_proxy_conn.md @@ -1,3 +1,8 @@ +# EFSPIntegration.test.test_proxy_conn + +* [EFSPIntegration.test.test\_proxy\_conn](#EFSPIntegration.test.test_proxy_conn) + * [jurisdiction](#EFSPIntegration.test.test_proxy_conn.jurisdiction) + --- sidebar_label: test_proxy_conn title: EFSPIntegration.test.test_proxy_conn @@ -10,6 +15,8 @@ Env vars needed to run: * TYLER_USER_EMAIL: the email of a user account in the specific jurisdiction of Tyler's EFM (should be a firm account) * TYLER_USER_PASSWORD: the password for that user account + + #### jurisdiction 'massachusetts' diff --git a/docs/components/formfyxer/docx_wrangling.md b/docs/components/formfyxer/docx_wrangling.md new file mode 100644 index 000000000..c888ea14f --- /dev/null +++ b/docs/components/formfyxer/docx_wrangling.md @@ -0,0 +1,181 @@ +# 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) + * [get\_modified\_docx\_runs](#formfyxer.docx_wrangling.get_modified_docx_runs) + * [make\_docx\_plain\_language](#formfyxer.docx_wrangling.make_docx_plain_language) + * [modify\_docx\_with\_openai\_guesses](#formfyxer.docx_wrangling.modify_docx_with_openai_guesses) + + + + +### update\_docx + +```python +def update_docx( + document: Union[docx.document.Document, str], + modified_runs: List[Tuple[int, int, str, + int]]) -> docx.document.Document +``` + +Update the document with the modified runs. + +Note: OpenAI is probabilistic, so the modified run indices may not be correct. +When the index of a run or paragraph is out of range, a new paragraph +will be inserted at the end of the document or a new run at the end of the +paragraph's runs. + +Take a careful look at the output document to make sure it is still correct. + +#### Arguments + +- `document` - the docx.Document object, or the path to the DOCX file +- `modified_runs` - a tuple of paragraph number, run number, the modified text, a question (not used), and whether a new paragraph should be inserted (for conditional text) + + +#### Returns + + The modified document. + + + +### get\_docx\_repr + +```python +def get_docx_repr(docx_path: str, + paragraph_start: int = 0, + paragraph_end: Optional[int] = None) +``` + +Return a JSON representation of the paragraphs and runs in the DOCX file. + +#### Arguments + +- `docx_path` - path to the DOCX file + + +#### Returns + + A JSON representation of the paragraphs and runs in the DOCX file. + + + +### get\_labeled\_docx\_runs + +```python +def 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) -> List[Tuple[int, int, str, int]] +``` + +Scan the DOCX and return a list of modified text with Jinja2 variable names inserted. + +#### Arguments + +- `docx_path` - path to the DOCX file +- `docx_repr` - a string representation of the paragraphs and runs in the DOCX file, if docx_path is not provided. This might be useful if you want +- `custom_people_names` - a tuple of custom names and descriptions to use in addition to the default ones. Like: ("clients", "the person benefiting from the form") + + +#### Returns + + A list of tuples, each containing a paragraph number, run number, and the modified text of the run. + + + +### get\_modified\_docx\_runs + +```python +def 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) -> List[Tuple[int, int, str, int]] +``` + +Use GPT to rewrite the contents of a DOCX file paragraph by paragraph. Does not handle tables, footers, or +other structures yet. + +This is a light wrapper that provides the structure of DOCX paragraphs and runs to your prompt +to OpenAI to facilitate the rewriting of the document without disrupting formatting. + +For example, this could be used to: +* Remove any passive voice +* Replace placeholder text with variable names +* Rewrite to a 6th grade reading level +* Do an advanced search and replace, without requiring you to use a regex + +By default, the example prompt includes a sample like this: + +[ +[0, 0, "Dear "], +[0, 1, "John Smith:"], +[1, 0, "I hope this letter finds you well."], +] + +Your custom instructions should include an example of how the sample will be modified, like the one below: + +Example reply, indicating paragraph, run, the new text, and a number indicating if this changes the +current paragraph, adds one before, or adds one after (-1, 0, 1): + +\{"results": +[ +[0, 1, "Dear \{\{ other_parties[0] \}\}:", 0], +[2, 0, "\{%p if is_tenant %\}", -1], +[3, 0, "\{%p endif %\}", 1], +] +\} + +You may also want to customize the input example to better match your use case. + +#### Arguments + +- `docx_path` _str_ - path to the DOCX file +- `docx_repr` _str_ - a string representation of the paragraphs and runs in the DOCX file, if docx_path is not provided. +- `custom_example` _Optional[str]_ - a string containing the purpose and overview of the task + instructions (str) a string containing specific instructions for the task +- `openai_client` _Optional[OpenAI]_ - an OpenAI client object. If not provided a new one will be created. +- `api_key` _Optional[str]_ - an OpenAI API key. If not provided, it will be obtained from the environment +- `temperature` _float_ - the temperature to use when generating text. Lower temperatures are more conservative. + + +#### Returns + + A list of tuples, each containing a paragraph number, run number, and the modified text of the run. + + + +### make\_docx\_plain\_language + +```python +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 + +```python +def modify_docx_with_openai_guesses(docx_path: str) -> docx.document.Document +``` + +Uses OpenAI to guess the variable names for a document and then modifies the document with the guesses. + +#### Arguments + +- `docx_path` _str_ - Path to the DOCX file to modify. + + +#### Returns + +- `docx.Document` - The modified document, ready to be saved to the same or a new path + diff --git a/docs/components/formfyxer/lit_explorer.md b/docs/components/formfyxer/lit_explorer.md new file mode 100644 index 000000000..44995afe3 --- /dev/null +++ b/docs/components/formfyxer/lit_explorer.md @@ -0,0 +1,524 @@ +# 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) + * [regex\_norm\_field](#formfyxer.lit_explorer.regex_norm_field) + * [reformat\_field](#formfyxer.lit_explorer.reformat_field) + * [norm](#formfyxer.lit_explorer.norm) + * [vectorize](#formfyxer.lit_explorer.vectorize) + * [normalize\_name](#formfyxer.lit_explorer.normalize_name) + * [cluster\_screens](#formfyxer.lit_explorer.cluster_screens) + * [InputType](#formfyxer.lit_explorer.InputType) + * [field\_types\_and\_sizes](#formfyxer.lit_explorer.field_types_and_sizes) + * [AnswerType](#formfyxer.lit_explorer.AnswerType) + * [classify\_field](#formfyxer.lit_explorer.classify_field) + * [get\_adjusted\_character\_count](#formfyxer.lit_explorer.get_adjusted_character_count) + * [time\_to\_answer\_field](#formfyxer.lit_explorer.time_to_answer_field) + * [time\_to\_answer\_form](#formfyxer.lit_explorer.time_to_answer_form) + * [cleanup\_text](#formfyxer.lit_explorer.cleanup_text) + * [text\_complete](#formfyxer.lit_explorer.text_complete) + * [complete\_with\_command](#formfyxer.lit_explorer.complete_with_command) + * [needs\_calculations](#formfyxer.lit_explorer.needs_calculations) + * [tools\_passive](#formfyxer.lit_explorer.tools_passive) + * [get\_passive\_sentences](#formfyxer.lit_explorer.get_passive_sentences) + * [get\_citations](#formfyxer.lit_explorer.get_citations) + * [get\_sensitive\_data\_types](#formfyxer.lit_explorer.get_sensitive_data_types) + * [substitute\_phrases](#formfyxer.lit_explorer.substitute_phrases) + * [substitute\_neutral\_gender](#formfyxer.lit_explorer.substitute_neutral_gender) + * [substitute\_plain\_language](#formfyxer.lit_explorer.substitute_plain_language) + * [transformed\_sentences](#formfyxer.lit_explorer.transformed_sentences) + * [parse\_form](#formfyxer.lit_explorer.parse_form) + * [form\_complexity](#formfyxer.lit_explorer.form_complexity) + + + + +### recursive\_get\_id + +```python +def recursive_get_id(values_to_unpack: Union[dict, list], + tmpl: Optional[set] = None) +``` + +Pull ID values out of the LIST/NSMI results from Spot. + + + +### spot + +```python +def spot(text: str, + lower: float = 0.25, + pred: float = 0.5, + upper: float = 0.6, + verbose: float = 0, + token: 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 + +```python +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 + +```python +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://suffolklitlab.org/docassemble-AssemblyLine-documentation/docs/document_variables + + + +### reformat\_field + +```python +def reformat_field(text: str, + max_length: int = 30, + tools_token: Optional[str] = None) +``` + +Transforms a string of text into a snake_case variable close in length to `max_length` name by +summarizing the string and stitching the summary together in snake_case. +h/t https://towardsdatascience.com/nlp-building-a-summariser-68e0c19e3a93 + + + +### norm + +```python +def norm(row) +``` + +Normalize a word vector. + + + +### vectorize + +```python +def vectorize(text: Union[List[str], str], tools_token: Optional[str] = None) +``` + +Vectorize a string of text. + +#### Arguments + +- `text` - a string of multiple words to vectorize +- `tools_token` - the token to tools.suffolklitlab.org, used for micro-service + to reduce the amount of memory you need on your machine. If + not passed, you need to have `en_core_web_lg` installed. NOTE: this + 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 + +```python +def normalize_name(jur: str, + group: str, + n: int, + per, + last_field: str, + this_field: str, + tools_token: Optional[str] = None) -> Tuple[str, float] +``` + +Normalize a field name, if possible to the Assembly Line conventions, and if +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 + +```python +def cluster_screens(fields: List[str] = [], + damping: float = 0.7, + tools_token: Optional[str] = None) -> Dict[str, List[str]] +``` + +Groups the given fields into screens based on how much they are related. + +#### Arguments + +- `fields` - a list of field names +- `damping` - a value >= 0.5 and < 1. Tunes how related screens should be +- `tools_token` - the token to tools.suffolklitlab.org, needed of doing + micro-service vectorization + +- `Returns` - a suggested screen grouping, each screen name mapped to the list of fields on it + + + +## InputType Objects + +```python +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 + +```python +def field_types_and_sizes( + fields: Optional[Iterable[FormField]]) -> List[FieldInfo] +``` + +Transform the fields provided by get_existing_pdf_fields into a summary format. +Result will look like: +[ +\{ +"var_name": var_name, +"type": "text | checkbox | signature", +"max_length": n +\} +] + + + +## AnswerType Objects + +```python +class AnswerType(Enum) +``` + +Answer type describes the effort the user answering the form will require. +"Slot-in" answers are a matter of almost instantaneous recall, e.g., name, address, etc. +"Gathered" answers require looking around one's desk, for e.g., a health insurance number. +"Third party" answers require picking up the phone to call someone else who is the keeper +of the information. +"Created" answers don't exist before the user is presented with the question. They may include +a choice, creating a narrative, or even applying legal reasoning. "Affidavits" are a special +form of created answers. +See Jarret and Gaffney, Forms That Work (2008) + + + +### classify\_field + +```python +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 + +```python +def get_adjusted_character_count(field: FieldInfo) -> float +``` + +Determines the bracketed length of an input field based on its max_length attribute, +returning a float representing the approximate length of the field content. + +The function chunks the answers into 5 different lengths (checkboxes, 2 words, short, medium, and long) +instead of directly using the character count, as forms can allocate different spaces +for the same data without considering the space the user actually needs. + +#### Arguments + +- `field` _FieldInfo_ - An object containing information about the input field, + including the "max_length" attribute. + + +#### Returns + +- `float` - The approximate length of the field content, categorized into checkboxes, 2 words, short, + medium, or long based on the max_length attribute. + + +**Examples**: + + >>> get_adjusted_character_count(\{"type"\}: InputType.CHECKBOX) + 4.7 + >>> get_adjusted_character_count(\{"max_length": 100\}) + 9.4 + >>> get_adjusted_character_count(\{"max_length": 300\}) + 230 + >>> get_adjusted_character_count(\{"max_length": 600\}) + 115 + >>> get_adjusted_character_count(\{"max_length": 1200\}) + 1150 + + + +### time\_to\_answer\_field + +```python +def time_to_answer_field(field: FieldInfo, + new_name: str, + cpm: int = 40, + cpm_std_dev: int = 17) -> Callable[[int], np.ndarray] +``` + +Apply a heuristic for the time it takes to answer the given field, in minutes. +It is hand-written for now. +It will factor in the input type, the answer type (slot in, gathered, third party or created), and the +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 + +```python +def time_to_answer_form(processed_fields, + normalized_fields) -> Tuple[float, float] +``` + +Provide an estimate of how long it would take an average user to respond to the questions +on the provided form. +We use signals such as the field type, name, and space provided for the response to come up with a +rough estimate, based on whether the field is: +1. fill in the blank +2. gathered - e.g., an id number, case number, etc. +3. third party: need to actually ask someone the information - e.g., income of not the user, anything else? +4. created: +a. short created (3 lines or so?) +b. long created (anything over 3 lines) + + + +### cleanup\_text + +```python +def cleanup_text(text: str, fields_to_sentences: bool = False) -> str +``` + +Apply cleanup routines to text to provide more accurate readability statistics. + + + +### text\_complete + +```python +def text_complete(prompt: str, + max_tokens: int = 500, + creds: Optional[OpenAiCreds] = None, + temperature: float = 0) -> str +``` + +Run a prompt via openAI's API and return the result. + +#### Arguments + +- `prompt` _str_ - The prompt to send to the API. +- `max_tokens` _int, optional_ - The number of tokens to generate. Defaults to 500. +- `creds` _Optional[OpenAiCreds], optional_ - The credentials to use. Defaults to None. +- `temperature` _float, optional_ - The temperature to use. Defaults to 0. + + + +### complete\_with\_command + +```python +def complete_with_command(text, + command, + tokens, + creds: Optional[OpenAiCreds] = None) -> str +``` + +Combines some text with a command to send to open ai. + + + +### needs\_calculations + +```python +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 + +```python +def tools_passive(input: Union[List[str], str], + tools_token: Optional[str] = None) +``` + +Ping passive voice API for list of sentences using the passive voice + + + +### get\_passive\_sentences + +```python +def get_passive_sentences( + text: Union[List, str], + tools_token: Optional[str] = None +) -> List[Tuple[str, List[Tuple[int, int]]]] +``` + +Return a list of tuples, where each tuple represents a +sentence in which passive voice was detected along with a list of the +starting and ending position of each fragment that is phrased in the passive voice. +The combination of the two can be used in the PDFStats frontend to highlight the +passive text in an individual sentence. + +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 + +```python +def get_citations(text: str, tokenized_sentences: List[str]) -> List[str] +``` + +Get citations and some extra surrounding context (the full sentence), if the citation is +fewer than 5 characters (often eyecite only captures a section symbol +for state-level short citation formats) + + + +### get\_sensitive\_data\_types + +```python +def get_sensitive_data_types( + fields: List[str], + fields_old: Optional[List[str]] = None) -> Dict[str, List[str]] +``` + +Given a list of fields, identify those related to sensitive information and return a dictionary with the sensitive +fields grouped by type. A list of the old field names can also be provided. These fields should be in the same +order. Passing the old field names allows the sensitive field algorithm to match more accurately. The return value +will not contain the old field name, only the corresponding field name from the first parameter. + +The sensitive data types are: Bank Account Number, Credit Card Number, Driver's License Number, and Social Security +Number. + + + +### substitute\_phrases + +```python +def substitute_phrases( + input_string: str, + substitution_phrases: Dict[str, + str]) -> Tuple[str, List[Tuple[int, int]]] +``` + +Substitute phrases in the input string and return the new string and positions of substituted phrases. + +#### Arguments + +- `input_string` _str_ - The input string containing phrases to be replaced. +- `substitution_phrases` _Dict[str, str]_ - A dictionary mapping original phrases to their replacement phrases. + + +#### Returns + + Tuple[str, List[Tuple[int, int]]]: A tuple containing the new string with substituted phrases and a list of + tuples, each containing the start and end positions of the substituted + phrases in the new string. + + +**Example**: + + >>> input_string = "The quick brown fox jumped over the lazy dog." + >>> substitution_phrases = \{"quick brown": "swift reddish", "lazy dog": "sleepy canine"\} + >>> new_string, positions = substitute_phrases(input_string, substitution_phrases) + >>> print(new_string) + "The swift reddish fox jumped over the sleepy canine." + >>> print(positions) + [(4, 17), (35, 48)] + + + +### substitute\_neutral\_gender + +```python +def substitute_neutral_gender( + input_string: str) -> Tuple[str, List[Tuple[int, int]]] +``` + +Substitute gendered phrases with neutral phrases in the input string. +Primary source is https://github.com/joelparkerhenderson/inclusive-language + + + +### substitute\_plain\_language + +```python +def substitute_plain_language( + input_string: str) -> Tuple[str, List[Tuple[int, int]]] +``` + +Substitute complex phrases with simpler alternatives. +Source of terms is drawn from https://www.plainlanguage.gov/guidelines/words/ + + + +### transformed\_sentences + +```python +def transformed_sentences( + sentence_list: List[str], + fun: Callable) -> List[Tuple[str, str, List[Tuple[int, int]]]] +``` + +Apply a function to a list of sentences and return only the sentences with changed terms. +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 + +```python +def 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) +``` + +Read in a pdf, pull out basic stats, attempt to normalize its form fields, and re-write the +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 + +```python +def form_complexity(stats) +``` + +Gets a single number of how hard the form is to complete. Higher is harder. + diff --git a/docs/components/formfyxer/pdf_wrangling.md b/docs/components/formfyxer/pdf_wrangling.md new file mode 100644 index 000000000..58f4648f2 --- /dev/null +++ b/docs/components/formfyxer/pdf_wrangling.md @@ -0,0 +1,525 @@ +# 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) + * [LIST\_BOX](#formfyxer.pdf_wrangling.FieldType.LIST_BOX) + * [CHOICE](#formfyxer.pdf_wrangling.FieldType.CHOICE) + * [FormField](#formfyxer.pdf_wrangling.FormField) + * [\_\_init\_\_](#formfyxer.pdf_wrangling.FormField.__init__) + * [set\_fields](#formfyxer.pdf_wrangling.set_fields) + * [rename\_pdf\_fields](#formfyxer.pdf_wrangling.rename_pdf_fields) + * [unlock\_pdf\_in\_place](#formfyxer.pdf_wrangling.unlock_pdf_in_place) + * [has\_fields](#formfyxer.pdf_wrangling.has_fields) + * [get\_existing\_pdf\_fields](#formfyxer.pdf_wrangling.get_existing_pdf_fields) + * [swap\_pdf\_page](#formfyxer.pdf_wrangling.swap_pdf_page) + * [copy\_pdf\_fields](#formfyxer.pdf_wrangling.copy_pdf_fields) + * [get\_textboxes\_in\_pdf](#formfyxer.pdf_wrangling.get_textboxes_in_pdf) + * [get\_bracket\_chars\_in\_pdf](#formfyxer.pdf_wrangling.get_bracket_chars_in_pdf) + * [intersect\_bbox](#formfyxer.pdf_wrangling.intersect_bbox) + * [intersect\_bboxs](#formfyxer.pdf_wrangling.intersect_bboxs) + * [contain\_boxes](#formfyxer.pdf_wrangling.contain_boxes) + * [get\_dist\_sq](#formfyxer.pdf_wrangling.get_dist_sq) + * [get\_dist](#formfyxer.pdf_wrangling.get_dist) + * [get\_connected\_edges](#formfyxer.pdf_wrangling.get_connected_edges) + * [bbox\_distance](#formfyxer.pdf_wrangling.bbox_distance) + * [get\_possible\_fields](#formfyxer.pdf_wrangling.get_possible_fields) + * [get\_possible\_checkboxes](#formfyxer.pdf_wrangling.get_possible_checkboxes) + * [get\_possible\_radios](#formfyxer.pdf_wrangling.get_possible_radios) + * [get\_possible\_text\_fields](#formfyxer.pdf_wrangling.get_possible_text_fields) + * [auto\_add\_fields](#formfyxer.pdf_wrangling.auto_add_fields) + * [is\_tagged](#formfyxer.pdf_wrangling.is_tagged) + + + + +## FieldType Objects + +```python +class FieldType(Enum) +``` + + + +### TEXT + +Text input Field + + + +### AREA + +Text input Field, but an area + + + +### LIST\_BOX + +allows multiple selection + + + +### CHOICE + +allows only one selection + + + +## FormField Objects + +```python +class FormField() +``` + +A data holding class, used to easily specify how a PDF form field should be created. + + + +### \_\_init\_\_ + +```python +def __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) +``` + +Constructor + +#### Arguments + +- `x` - the x position of the lower left corner of the field. Should be in X,Y coordinates, + where (0, 0) is the lower left of the page, x goes to the right, and units are in + points (1/72th of an inch) +- `y` - the y position of the lower left corner of the field. Should be in X,Y coordinates, + where (0, 0) is the lower left of the page, y goes up, and units are in points + (1/72th of an inch) +- `config` - a dictionary containing any keyword argument to the reportlab field functions, + which will vary depending on what type of field this is. See section 4.7 of the + [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 + +```python +def set_fields(in_file: Union[str, Path, BinaryIO], + out_file: Union[str, Path, BinaryIO], + fields_per_page: Iterable[Iterable[FormField]], + *, + overwrite=False) +``` + +Adds fields per page to the in_file PDF, writing the new PDF to a new file. + +Example usage: + +```python +set_fields('no_fields.pdf', 'four_fields_on_second_page.pdf', + [ + [], # nothing on the first page + [ # Second page + FormField('new_field', 'text', 110, 105, configs=\{'width': 200, 'height': 30\}), + # Choice needs value to be one of the possible options, and options to be a list of strings or tuples + FormField('new_choices', 'choice', 110, 400, configs=\{'value': 'Option 1', 'options': ['Option 1', 'Option 2']\}), + # Radios need to have the same name, with different values + FormField('new_radio1', 'radio', 110, 600, configs=\{'value': 'option a'\}), + FormField('new_radio1', 'radio', 110, 500, configs=\{'value': 'option b'\}) + ] + ] +) +``` + +#### Arguments + +- `in_file` - the input file name or path of a PDF that we're adding the fields to +- `out_file` - the output file name or path where the new version of in_file will + be written. Doesn't need to exist. +- `fields_per_page` - for each page, a series of fields that should be added to that + page. +- `owerwrite` - if the input file already some fields (AcroForm fields specifically) + and this value is true, it will erase those existing fields and just add + `fields_per_page`. If not true and the input file has fields, this won't generate + a PDF, since there isn't currently a way to merge AcroForm fields from + different PDFs. + + +#### Returns + + Nothing. + + + +### rename\_pdf\_fields + +```python +def rename_pdf_fields(in_file: Union[str, Path, BinaryIO], + out_file: Union[str, Path, BinaryIO], + mapping: Mapping[str, str]) -> None +``` + +Given a dictionary that maps old to new field names, rename the AcroForm +field with a matching key to the specified value. + +**Example**: + +```python +rename_pdf_fields('current.pdf', 'new_field_names.pdf', + \{'abc123': 'user1_name', 'abc124', 'user1_address_city'\}) + +Args: + in_file: the filename of an input file + out_file: the filename of the output file. Doesn't need to exist, + will be overwritten if it does exist. + mapping: the python dict that maps from a current field name to the desired name + +Returns: + Nothing + + + +### unlock\_pdf\_in\_place + +```python +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 + +```python +def has_fields(pdf_file: str) -> bool +``` + +Check if a PDF has at least one form field using PikePDF. + +#### Arguments + +- `pdf_file` _str_ - The path to the PDF file. + + +#### Returns + +- `bool` - True if the PDF has at least one form field, False otherwise. + + + +### get\_existing\_pdf\_fields + +```python +def get_existing_pdf_fields( + in_file: Union[str, Path, BinaryIO, Pdf]) -> List[List[FormField]] +``` + +Use PikePDF to get fields from the PDF + + + +### swap\_pdf\_page + +```python +def 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) -> Pdf +``` + +(DEPRECATED: use copy_pdf_fields) Copies the AcroForm fields from one PDF to another blank PDF form. Optionally, choose a starting page for both +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 + +```python +def 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) -> Pdf +``` + +Copies the AcroForm fields from one PDF to another blank PDF form (without AcroForm fields). +Useful for getting started with an updated PDF form, where the old fields are pretty close to where +they should go on the new document. + +Optionally, you can choose a starting page for both +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` + +**Example**: + +```python +new_pdf_with_fields = copy_pdf_fields( + source_pdf="old_pdf.pdf", + destination_pdf="new_pdf_with_no_fields.pdf") +new_pdf_with_fields.save("new_pdf_with_fields.pdf") +``` + + +#### Arguments + +- `source_pdf` - a file name or path to a PDF that has AcroForm fields +- `destination_pdf` - a file name or path to a PDF without AcroForm fields. Existing fields will be removed. +- `source_offset` - the starting page that fields will be copied from. Defaults to 0. +- `destination_offset` - the starting page that fields will be copied to. Defaults to 0. +- `append_annotations` - controls whether formfyxer will try to append form fields instead of + overwriting. Defaults to false; when enabled may lead to undefined behavior. + + +#### Returns + + A pikepdf.Pdf object with new fields. If `blank_pdf` was a pikepdf.Pdf object, the + same object is returned. + + + +### get\_textboxes\_in\_pdf + +```python +def get_textboxes_in_pdf(in_file: Union[str, Path, BinaryIO], + line_margin=0.02, + char_margin=2.0) -> List[List[Textbox]] +``` + +Gets all of the text boxes found by pdfminer in a PDF, as well as their bounding boxes + + + +### get\_bracket\_chars\_in\_pdf + +```python +def get_bracket_chars_in_pdf(in_file: Union[str, Path, BinaryIO], + line_margin=0.02, + char_margin=0.0) -> List +``` + +Gets all of the bracket characters ('[' and ']') found by pdfminer in a PDF, as well as their bounding boxes +TODO: Will eventually be used to find [ ] as checkboxes, but right now we can't tell the difference between [ ] and [i]. +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 + +```python +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 + +```python +def intersect_bboxs(bbox_a, + bboxes, + vert_dilation=2, + horiz_dilation=2) -> Iterable[bool] +``` + +Returns an iterable of booleans, one of each of the input bboxes, true if it collides with bbox_a + + + +### contain\_boxes + +```python +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 + +```python +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 + +```python +def get_dist(point_a: XYPair, point_b: XYPair) -> float +``` + +euclidean (L^2 norm) distance between two points + + + +### get\_connected\_edges + +```python +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 + +```python +def bbox_distance( + bbox_a: BoundingBoxF, bbox_b: BoundingBoxF +) -> Tuple[float, Tuple[XYPair, XYPair], Tuple[XYPair, XYPair]] +``` + +Gets our specific "distance measure" between two different bounding boxes. +This distance is roughly the sum of the horizontal and vertical difference in alignment of +the closest shared field-bounding box edge. We are trying to find which, given a list of text boxes +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 + +```python +def get_possible_fields( + in_pdf_file: Union[str, Path], + textboxes: Optional[List[List[Textbox]]] = None +) -> List[List[FormField]] +``` + +Given an input PDF, runs a series of heuristics to predict where there +might be places for user enterable information (i.e. PDF fields), and returns +those predictions. + +**Example**: + +```python +fields = get_possible_fields('no_field.pdf') +print(fields[0][0]) +# Type: FieldType.TEXT, Name: name, User name: , X: 67.68, Y: 666.0, Configs: \{'fieldFlags': 'doNotScroll', 'width': 239.4, 'height': 16\} +``` + + +#### Arguments + +- `in_pdf_file` - the input PDF +- `textboxes` _optional_ - the location of various lines of text in the PDF. + If not given, will be calculated automatically. This allows us to + pass through expensive info to calculate through several functions. + + +#### Returns + + For each page in the input PDF, a list of predicted form fields + + + +### get\_possible\_checkboxes + +```python +def get_possible_checkboxes(img: Union[str, cv2.Mat], + find_small=False) -> Union[np.ndarray, List] +``` + +Uses boxdetect library to determine if there are checkboxes on an image of a PDF page. +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 + +```python +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 + +```python +def get_possible_text_fields( + img: Union[str, BinaryIO, cv2.Mat], + text_lines: List[Textbox], + default_line_height: int = 44) -> List[Tuple[BoundingBox, int]] +``` + +Uses openCV to attempt to find places where a PDF could expect an input text field. + +Caveats so far: only considers straight, normal horizonal lines that don't touch any vertical lines as fields +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 + +```python +def auto_add_fields(in_pdf_file: Union[str, Path], out_pdf_file: Union[str, + Path]) +``` + +Uses [get_possible_fields](#formfyxer.pdf_wrangling.get_possible_fields) and +[set_fields](#formfyxer.pdf_wrangling.set_fields) to automatically add new detected fields +to an input PDF. + +**Example**: + +```python +auto_add_fields('no_fields.pdf', 'newly_added_fields.pdf') +``` + + +#### Arguments + +- `in_pdf_file` - the input file name or path of the PDF where we'll try to find possible fields +- `out_pdf_file` - the output file name or path of the PDF where a new version of `in_pdf_file` will + be stored, with the new fields. Doesn't need to existing, but if a file does exist at that + filename, it will be overwritten. + + +#### Returns + + Nothing + + + +### is\_tagged + +```python +def is_tagged(in_pdf_file: Union[str, Path, pikepdf.Pdf]) -> bool +``` + +Determines if the input PDF file is tagged for accessibility. + +#### Arguments + +- `in_pdf_file` _Union[str, Path]_ - The path to the PDF file, as a string or a Path object. + + +#### Returns + +- `bool` - True if the PDF is tagged, False otherwise. + diff --git a/docs/components/sidebar.json b/docs/components/sidebar.json index 1dd9f9fc0..3ad375fb4 100644 --- a/docs/components/sidebar.json +++ b/docs/components/sidebar.json @@ -1,5 +1,12 @@ { - "items": [], - "label": null, + "items": [ + "components/ALToolbox/al_income", + "components/ALToolbox/business_days", + "components/ALToolbox/copy_button", + "components/ALToolbox/llms", + "components/ALToolbox/misc", + "components/ALToolbox/save_input_data" + ], + "label": "ALToolbox", "type": "category" } \ No newline at end of file diff --git a/fix-doc-titles.sh b/fix-doc-titles.sh new file mode 100755 index 000000000..8384a69f8 --- /dev/null +++ b/fix-doc-titles.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +# Fix auto-generated documentation titles and navigation +# Replace "Table of Contents" with the actual module name +# Improve header hierarchy for better navigation + +echo "Fixing documentation titles and navigation..." + +for file in $(find docs/components -name "*.md" -exec grep -l "# Table of Contents" {} \;); do + # Extract the module name from the first TOC entry + module_name=$(grep -m 1 "^\* \[.*\]" "$file" | sed 's/^\* \[\(.*\)\](#.*)/\1/' | sed 's/\\_/_/g') + if [ ! -z "$module_name" ]; then + echo "Processing $file -> $module_name" + + # Replace "Table of Contents" with module name + sed -i "1s/# Table of Contents/# $module_name/" "$file" + + # Promote method headers from H4 (####) to H3 (###) for better navigation + # This makes methods appear in the right-hand navigation menu + # Handle both regular and escaped method names + sed -i 's/^#### \([a-zA-Z_\\][a-zA-Z0-9_\\]*\)(/### \1(/g' "$file" + + # Also promote method headers that don't have parameters (like properties) + sed -i 's/^#### \([a-zA-Z_\\][a-zA-Z0-9_\\]*\)$/### \1/g' "$file" + + # Clean up method headers to show only method name (without parameters) in navigation + # This keeps the full signature in the content but shows clean names in the TOC + sed -i 's/^### \([a-zA-Z_\\][a-zA-Z0-9_\\]*\)(.*/### \1/g' "$file" + + # Also clean up the table of contents to show clean method names + sed -i 's/\* \[\([a-zA-Z_\\][a-zA-Z0-9_\\]*\)([^)]*)/ * [\1/g' "$file" + + # Promote standalone functions (those at module level, not class methods) to H2 + # Identify standalone functions from TOC: they appear as " * [function_name]" (module level) + # vs class methods which appear as " * [method_name]" (indented further) + # Promote standalone functions (those at module level, not class methods) to H2 + # This creates a clearer navigation hierarchy where standalone functions + # are separate from class methods + + # For al_general.md, promote common standalone functions + if [[ "$file" == *"al_general.md" ]]; then + sed -i 's/^### section\\_links$/## section\\_links/g' "$file" + sed -i 's/^### will\\_send\\_to\\_real\\_court$/## will\\_send\\_to\\_real\\_court/g' "$file" + sed -i 's/^### filter\\_letters$/## filter\\_letters/g' "$file" + sed -i 's/^### fa\\_icon$/## fa\\_icon/g' "$file" + sed -i 's/^### is\\_sms\\_enabled$/## is\\_sms\\_enabled/g' "$file" + sed -i 's/^### is\\_phone\\_or\\_email$/## is\\_phone\\_or\\_email/g' "$file" + sed -i 's/^### github\\_modified\\_date$/## github\\_modified\\_date/g' "$file" + sed -i 's/^### language\\_name$/## language\\_name/g' "$file" + sed -i 's/^### safe\\_states\\_list$/## safe\\_states\\_list/g' "$file" + sed -i 's/^### has\\_parsable\\_pronouns$/## has\\_parsable\\_pronouns/g' "$file" + sed -i 's/^### parse\\_custom\\_pronouns$/## parse\\_custom\\_pronouns/g' "$file" + sed -i 's/^### get\\_visible\\_al\\_nav\\_items$/## get\\_visible\\_al\\_nav\\_items/g' "$file" + fi + + # Convert **Arguments**: and **Returns**: to proper H4 headings for better navigation + sed -i 's/^\*\*Arguments\*\*:/#### Arguments/g' "$file" + sed -i 's/^\*\*Returns\*\*:/#### Returns/g' "$file" + sed -i 's/^\*\*Attributes\*\*:/#### Attributes/g' "$file" + sed -i 's/^\*\*Notes\*\*:/#### Notes/g' "$file" + sed -i 's/^\*\*Raises\*\*:/#### Raises/g' "$file" + + # Remove stray YAML frontmatter blocks that appear in the middle of files + # These are artifacts from the old template processing + sed -i '/^---$/,/^---$/d' "$file" + fi +done + +echo "Done fixing documentation titles and navigation." diff --git a/pydoc-markdown.yml b/pydoc-markdown.yml index 7b60d8ff6..c1b0794a9 100644 --- a/pydoc-markdown.yml +++ b/pydoc-markdown.yml @@ -18,8 +18,29 @@ renderer: relative_sidebar_path: sidebar.json sidebar_top_level_label: null markdown: + # Better escaping and HTML handling escape_html_in_docstring: true escape_curly_braces_in_docstring: true - signature_code_block: false + + # Enhanced code and signature formatting + signature_code_block: true + signature_in_header: true + code_headers: false + html_headers: false + + # Better type hints and data rendering render_typehint_in_data_header: true - toc_maxdepth: 6 + + # Enhanced table of contents with proper depth + render_toc: true + toc_maxdepth: 3 + + # Better titles and descriptions + descriptive_class_title: true + descriptive_module_title: false + + # Fixed header levels for better hierarchy + use_fixed_header_levels: true + + # Better anchor insertion + insert_header_anchors: true diff --git a/pydoc-module-header.hbs b/pydoc-module-header.hbs new file mode 100644 index 000000000..fb547c7ce --- /dev/null +++ b/pydoc-module-header.hbs @@ -0,0 +1,13 @@ +--- +sidebar_label: "{{ module.name }}" +title: "{{#if module.docstring.summary}}{{ module.docstring.summary }}{{else}}{{ module.name }}{{/if}}" +--- + +# Table of Contents + +{{#each module.members}} +* [{{ name }}](#{{ name }}) +{{#each members}} + * [{{ name }}](#{{ ../name }}.{{ name }}) +{{/each}} +{{/each}} diff --git a/sidebars.js b/sidebars.js index 04c99b26a..ab007f8b5 100644 --- a/sidebars.js +++ b/sidebars.js @@ -130,6 +130,8 @@ module.exports = { "components/AssemblyLine/al_document", "components/AssemblyLine/language", "components/AssemblyLine/sessions", + "components/AssemblyLine/custom_jinja_filters", + "components/AssemblyLine/sign", ] }, 'components/ALRecipes/alrecipes_overview', @@ -183,7 +185,6 @@ module.exports = { 'components/EFSPIntegration/conversions', 'components/EFSPIntegration/interview_logic', 'components/EFSPIntegration/py_efsp_client', - 'components/EFSPIntegration/test/test_conversions', ] }, { diff --git a/src/css/custom.css b/src/css/custom.css index 20df0c9ab..73c958b0e 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -294,4 +294,142 @@ html[data-theme="dark"] { .positive { color: var(--ifm-color-success-dark); +} + +/* API Documentation improvements */ + +/* Apply to all auto-generated API documentation pages */ +html[class*="docs-doc-id-components/"] { + /* Better spacing for method sections */ + h4[id*="init"], + h4[id*="__init__"], + h4[id*="all_"], + h4[id*="short_"], + h4[id*="from_"], + h4[id*="geo"], + h4[id*="county"], + h4[id*="matching"], + h4[id*="filter"], + h4[id*="as_"], + h4[id*="unique"] { + margin-top: 2rem; + padding-top: 1rem; + border-top: 1px solid var(--ifm-table-border-color); + } + + /* Better styling for class headings */ + h2[id*="Objects"] code { + background-color: var(--ifm-color-primary-light); + color: white; + padding: 0.2rem 0.5rem; + border-radius: var(--ifm-code-border-radius); + font-weight: bold; + } + + /* Improve code block appearance in method signatures */ + h4 code { + background-color: var(--ifm-code-background); + border: 1px solid var(--ifm-table-border-color); + padding: 0.3rem 0.6rem; + border-radius: var(--ifm-code-border-radius); + font-family: var(--ifm-font-family-monospace); + font-size: 0.9rem; + } + + /* Better styling for argument and return value sections */ + p strong:first-child { + color: var(--ifm-color-primary); + font-size: 1.1rem; + } + + /* Improve parameter lists */ + ul li code:first-child { + background-color: var(--ifm-color-info-contrast-background); + color: var(--ifm-color-info-dark); + padding: 0.1rem 0.3rem; + border-radius: 3px; + font-weight: 600; + } + + /* Better spacing for method descriptions */ + p + p strong { + margin-top: 1rem; + } + + /* Enhance table of contents in right sidebar */ + .table-of-contents { + h4 code, + a code { + background-color: var(--ifm-code-background); + padding: 0.1rem 0.3rem; + border-radius: 3px; + font-size: 0.85rem; + } + + /* Better nesting for class methods */ + li li a { + padding-left: 1rem; + font-size: 0.9rem; + } + } + + /* Improve the main table of contents */ + h1 + ul { + background-color: var(--ifm-color-secondary-contrast-background); + border: 1px solid var(--ifm-table-border-color); + border-radius: var(--ifm-card-border-radius); + padding: 1.5rem; + margin-bottom: 2rem; + + li { + margin-bottom: 0.5rem; + } + + /* Style class names in TOC */ + > li > a { + font-weight: 600; + color: var(--ifm-color-primary); + } + + /* Style method names in TOC */ + li li a { + color: var(--ifm-color-emphasis-700); + font-family: var(--ifm-font-family-monospace); + font-size: 0.9rem; + } + } + + /* Better code block styling */ + pre code { + border-radius: var(--ifm-code-border-radius); + } + + /* Improve signature code blocks */ + .language-python { + margin: 1rem 0; + + .token.keyword { + color: var(--ifm-color-primary); + } + + .token.function { + color: var(--ifm-color-info-dark); + } + + .token.string { + color: var(--ifm-color-success-dark); + } + } +} + +/* Dark mode adjustments for API docs */ +html[data-theme="dark"][class*="docs-doc-id-components/"] { + h2[id*="Objects"] code { + background-color: var(--ifm-color-primary-dark); + } + + ul li code:first-child { + background-color: var(--ifm-color-info-dark); + color: var(--ifm-color-info-contrast-foreground); + } } \ No newline at end of file