docassemble.AssemblyLine 2.27.2__tar.gz → 2.28.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {docassemble.AssemblyLine-2.27.2/docassemble.AssemblyLine.egg-info → docassemble_assemblyline-2.28.1}/PKG-INFO +1 -1
- docassemble_assemblyline-2.28.1/docassemble/AssemblyLine/__init__.py +1 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/al_courts.py +18 -4
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/al_document.py +69 -3
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/al_general.py +113 -33
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/al_code.yml +5 -2
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/al_visual.yml +4 -4
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/ql_baseline.yml +7 -9
- docassemble_assemblyline-2.28.1/docassemble/AssemblyLine/data/questions/test_bundle_parity.yml +79 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/test_al_general.py +9 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1/docassemble.AssemblyLine.egg-info}/PKG-INFO +1 -1
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble.AssemblyLine.egg-info/SOURCES.txt +1 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/setup.py +1 -1
- docassemble.AssemblyLine-2.27.2/docassemble/AssemblyLine/__init__.py +0 -1
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/LICENSE +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/MANIFEST.in +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/README.md +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/al_document.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/al_language.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/al_package.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/al_package_unstyled.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/al_question_test.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/al_reminders.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/al_saved_sessions.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/al_saved_sessions_store.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/al_settings.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/al_terms_of_use.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/assembly_line.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/assembly_line_unstyled.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/feedback.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/interview_list.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/ql_catchall.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/reserved_words.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/test_al_table_document.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/test_aladdendum.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/test_alcourts.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/test_aldocument.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/test_alexhibit.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/test_alexhibit_maxsize.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/questions/test_question_library.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/sources/README.md +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/sources/es-words.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/sources/languages.yml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/sources/test_aldocument.feature +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/sources/test_alexhibit_docx_1.docx +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/sources/test_alexhibit_jpg_1.jpg +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/sources/test_alexhibit_pdf_1.pdf +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/sources/test_alexhibit_png_1.png +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/sources/test_question_library.feature +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/sources/translation_es.xlsx +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/sources/translation_ht.xlsx +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/sources/translation_pt.xlsx +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/static/README.md +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/static/al_audio.css +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/static/al_audio.js +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/static/aldocument.css +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/static/aldocument.js +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/static/interview_list.css +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/static/limit_upload_size.js +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/static/lt1-pullout-10-getting-organized.pdf +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/static/ma_logo.png +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/static/placeholder.png +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/static/seal.jpg +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/static/styles.css +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/templates/README.md +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/templates/al_basic_addendum.docx +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/templates/exhibit_cover_sheet.docx +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/templates/exhibit_table_of_contents.docx +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/templates/general_cover_sheet.docx +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/templates/sample_word_template.docx +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/templates/test_aldocument_docx_1.docx +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/data/templates/test_aldocument_pdf_1.pdf +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/language.py +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/project_maintenance.py +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/py.typed +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/requirements.txt +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/sessions.py +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/test_al_document.py +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/AssemblyLine/test_language.py +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble/__init__.py +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble.AssemblyLine.egg-info/dependency_links.txt +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble.AssemblyLine.egg-info/namespace_packages.txt +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble.AssemblyLine.egg-info/not-zip-safe +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble.AssemblyLine.egg-info/requires.txt +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/docassemble.AssemblyLine.egg-info/top_level.txt +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/pyproject.toml +0 -0
- {docassemble.AssemblyLine-2.27.2 → docassemble_assemblyline-2.28.1}/setup.cfg +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '2.28.1'
|
|
@@ -3,7 +3,7 @@ Package for a very simple / MVP list of courts that is mostly signature compatib
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
|
-
from typing import Any, Dict, List, Optional, Union, Set
|
|
6
|
+
from typing import Any, Callable, Dict, List, Mapping, Optional, Union, Set
|
|
7
7
|
import pandas as pd
|
|
8
8
|
import docassemble.base.functions
|
|
9
9
|
from docassemble.base.util import (
|
|
@@ -110,7 +110,9 @@ class ALCourt(Court):
|
|
|
110
110
|
all_info = f"{ all_info }[BR]{ self.address.on_one_line() }"
|
|
111
111
|
return f"{ all_info }[BR]{ self.description }"
|
|
112
112
|
|
|
113
|
-
def from_row(
|
|
113
|
+
def from_row(
|
|
114
|
+
self, df_row: Union[pd.Series, pd.DataFrame], ensure_lat_long: bool = True
|
|
115
|
+
) -> None:
|
|
114
116
|
"""
|
|
115
117
|
Loads data from a single Pandas Dataframe into the current court object.
|
|
116
118
|
Note: It will try to convert column names that don't make valid
|
|
@@ -203,6 +205,7 @@ class ALCourtLoader(DAObject):
|
|
|
203
205
|
|
|
204
206
|
Attributes:
|
|
205
207
|
filename (str): Path to the file containing court information.
|
|
208
|
+
converters (Dict[str, Callable]): A dictionary of functions to apply to columns in the dataframe.
|
|
206
209
|
"""
|
|
207
210
|
|
|
208
211
|
def init(self, *pargs, **kwargs):
|
|
@@ -411,6 +414,8 @@ class ALCourtLoader(DAObject):
|
|
|
411
414
|
|
|
412
415
|
The method determines the file type (.csv, .xlsx, or .json) based on its extension and reads it accordingly.
|
|
413
416
|
|
|
417
|
+
If the "callable" attribute is defined on the instance, it will be used to convert the data in the dataframe.
|
|
418
|
+
|
|
414
419
|
Returns:
|
|
415
420
|
pd.DataFrame: A dataframe containing the list of courts.
|
|
416
421
|
|
|
@@ -427,11 +432,20 @@ class ALCourtLoader(DAObject):
|
|
|
427
432
|
else:
|
|
428
433
|
load_path = str(self.filename)
|
|
429
434
|
|
|
435
|
+
def convert_zip(z: Any) -> str:
|
|
436
|
+
return str(z).zfill(5)
|
|
437
|
+
|
|
438
|
+
merged_converters: Dict[str, Callable[[object], object]] = {
|
|
439
|
+
"address_zip": convert_zip
|
|
440
|
+
}
|
|
441
|
+
if hasattr(self, "converters") and self.converters:
|
|
442
|
+
assert isinstance(self.converters, dict)
|
|
443
|
+
merged_converters.update(self.converters)
|
|
430
444
|
to_load = path_and_mimetype(load_path)[0]
|
|
431
445
|
if self.filename.lower().endswith(".xlsx"):
|
|
432
|
-
df = pd.read_excel(to_load)
|
|
446
|
+
df = pd.read_excel(to_load, converters=merged_converters) # type: ignore
|
|
433
447
|
elif self.filename.lower().endswith(".csv"):
|
|
434
|
-
df = pd.read_csv(to_load)
|
|
448
|
+
df = pd.read_csv(to_load, converters=merged_converters) # type: ignore
|
|
435
449
|
elif self.filename.lower().endswith(".json"):
|
|
436
450
|
# TODO: we may need to normalize a JSON file
|
|
437
451
|
df = pd.read_json(to_load)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import re
|
|
2
2
|
import os
|
|
3
3
|
import mimetypes
|
|
4
|
-
from typing import Any, Dict, List, Union, Callable, Optional
|
|
4
|
+
from typing import Any, Dict, List, Literal, Union, Callable, Optional
|
|
5
5
|
from docassemble.base.util import (
|
|
6
6
|
Address,
|
|
7
7
|
LatitudeLongitude,
|
|
@@ -34,6 +34,7 @@ from textwrap import wrap
|
|
|
34
34
|
from math import floor
|
|
35
35
|
import subprocess
|
|
36
36
|
from collections import ChainMap
|
|
37
|
+
import pikepdf
|
|
37
38
|
|
|
38
39
|
__all__ = [
|
|
39
40
|
"ALAddendumField",
|
|
@@ -180,6 +181,50 @@ def table_row(title: str, button_htmls: List[str] = []) -> str:
|
|
|
180
181
|
return html
|
|
181
182
|
|
|
182
183
|
|
|
184
|
+
def pdf_page_parity(pdf_path: str) -> Literal["even", "odd"]:
|
|
185
|
+
"""
|
|
186
|
+
Count the number of pages in the PDF and
|
|
187
|
+
return "even" if it is divisible by 2 and "odd"
|
|
188
|
+
if it is not divisible by 2.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
pdf_path (str): Path to the PDF in the filesystem
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
Literal["even", "odd"]: The parity of the number of pages in the PDF
|
|
195
|
+
"""
|
|
196
|
+
with pikepdf.open(pdf_path) as pdf:
|
|
197
|
+
num_pages = len(pdf.pages)
|
|
198
|
+
if num_pages % 2 == 0:
|
|
199
|
+
return "even"
|
|
200
|
+
return "odd"
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def add_blank_page(pdf_path: str) -> None:
|
|
204
|
+
"""
|
|
205
|
+
Add a blank page to the end of a PDF.
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
pdf_path (str): Path to the PDF in the filesystem
|
|
209
|
+
"""
|
|
210
|
+
# Load the PDF
|
|
211
|
+
with pikepdf.open(pdf_path, allow_overwriting_input=True) as pdf:
|
|
212
|
+
# Retrieve the last page
|
|
213
|
+
last_page = pdf.pages[-1]
|
|
214
|
+
|
|
215
|
+
# Extract the size of the last page
|
|
216
|
+
media_box = last_page.MediaBox
|
|
217
|
+
|
|
218
|
+
# Create a new blank page with the same dimensions as the last page
|
|
219
|
+
blank_page = pikepdf.Page(pikepdf.Dictionary(MediaBox=media_box))
|
|
220
|
+
|
|
221
|
+
# Add the blank page to the end of the PDF
|
|
222
|
+
pdf.pages.append(blank_page)
|
|
223
|
+
|
|
224
|
+
# Overwrite the original PDF with the modified version
|
|
225
|
+
pdf.save(pdf_path)
|
|
226
|
+
|
|
227
|
+
|
|
183
228
|
class ALAddendumField(DAObject):
|
|
184
229
|
"""
|
|
185
230
|
Represents a field with attributes determining its display in an addendum, typically for PDF templates.
|
|
@@ -1441,6 +1486,7 @@ class ALDocumentBundle(DAList):
|
|
|
1441
1486
|
enabled (bool, optional): Determines if the bundle is active. Defaults to True.
|
|
1442
1487
|
auto_gather (bool, optional): Automatically gathers attributes. Defaults to False.
|
|
1443
1488
|
gathered (bool, optional): Specifies if attributes have been gathered. Defaults to True.
|
|
1489
|
+
default_parity (Optional[Literal["even", "odd"]]): Default parity to enforce on the PDF. Defaults to None.
|
|
1444
1490
|
|
|
1445
1491
|
Examples:
|
|
1446
1492
|
Given three documents: `Cover page`, `Main motion form`, and `Notice of Interpreter Request`,
|
|
@@ -1481,6 +1527,7 @@ class ALDocumentBundle(DAList):
|
|
|
1481
1527
|
refresh: bool = True,
|
|
1482
1528
|
pdfa: bool = False,
|
|
1483
1529
|
append_matching_suffix: bool = True,
|
|
1530
|
+
ensure_parity: Optional[Literal["even", "odd"]] = None,
|
|
1484
1531
|
) -> Optional[DAFile]:
|
|
1485
1532
|
"""
|
|
1486
1533
|
Returns a consolidated PDF of all enabled documents in the bundle.
|
|
@@ -1491,6 +1538,8 @@ class ALDocumentBundle(DAList):
|
|
|
1491
1538
|
pdfa (bool): If True, generates a PDF/A compliant document, defaults to False.
|
|
1492
1539
|
append_matching_suffix (bool): Flag to determine if matching suffix should be appended to file name, default is True.
|
|
1493
1540
|
Used primarily to enhance automated tests.
|
|
1541
|
+
ensure_parity (Optional[Literal["even", "odd"]]): Ensures the number of pages in the PDF is even or odd. If omitted,
|
|
1542
|
+
no parity is enforced. Defaults to None.
|
|
1494
1543
|
|
|
1495
1544
|
Returns:
|
|
1496
1545
|
Optional[DAFile]: Combined PDF file or None if no documents are enabled.
|
|
@@ -1533,6 +1582,19 @@ class ALDocumentBundle(DAList):
|
|
|
1533
1582
|
)
|
|
1534
1583
|
pdf.title = self.title
|
|
1535
1584
|
setattr(self.cache, safe_key, pdf)
|
|
1585
|
+
|
|
1586
|
+
if hasattr(self, "default_parity") and not ensure_parity:
|
|
1587
|
+
ensure_parity = self.default_parity
|
|
1588
|
+
|
|
1589
|
+
if ensure_parity not in [None, "even", "odd"]:
|
|
1590
|
+
raise ValueError("ensure_parity must be either 'even', 'odd' or None")
|
|
1591
|
+
|
|
1592
|
+
if ensure_parity: # Check for odd/even requirement
|
|
1593
|
+
if pdf_page_parity(pdf.path()) == ensure_parity:
|
|
1594
|
+
return pdf
|
|
1595
|
+
else:
|
|
1596
|
+
add_blank_page(pdf.path())
|
|
1597
|
+
|
|
1536
1598
|
return pdf
|
|
1537
1599
|
|
|
1538
1600
|
def __str__(self) -> str:
|
|
@@ -2182,8 +2244,12 @@ class ALDocumentBundle(DAList):
|
|
|
2182
2244
|
return send_email(
|
|
2183
2245
|
to=to,
|
|
2184
2246
|
template=template,
|
|
2185
|
-
|
|
2186
|
-
|
|
2247
|
+
# Add both DOCX and PDF versions, but if it's not possible to be a DOCX don't add the PDF
|
|
2248
|
+
# twice
|
|
2249
|
+
attachments=list(
|
|
2250
|
+
dict.fromkeys(
|
|
2251
|
+
self.as_editable_list(key=key) + self.as_pdf_list(key=key)
|
|
2252
|
+
)
|
|
2187
2253
|
),
|
|
2188
2254
|
**kwargs,
|
|
2189
2255
|
)
|
|
@@ -425,7 +425,13 @@ class ALAddress(Address):
|
|
|
425
425
|
else:
|
|
426
426
|
output += ", " + str(self.state)
|
|
427
427
|
if hasattr(self, "zip") and self.zip:
|
|
428
|
-
|
|
428
|
+
current_country = (
|
|
429
|
+
self.country if hasattr(self, "country") else get_country()
|
|
430
|
+
)
|
|
431
|
+
if current_country == "US":
|
|
432
|
+
output += " " + str(self.zip).zfill(5)
|
|
433
|
+
else:
|
|
434
|
+
output += " " + str(self.zip)
|
|
429
435
|
elif hasattr(self, "postal_code") and self.postal_code:
|
|
430
436
|
output += " " + str(self.postal_code)
|
|
431
437
|
if (
|
|
@@ -508,7 +514,13 @@ class ALAddress(Address):
|
|
|
508
514
|
else:
|
|
509
515
|
output += ", " + str(self.state)
|
|
510
516
|
if hasattr(self, "zip") and self.zip:
|
|
511
|
-
|
|
517
|
+
current_country = (
|
|
518
|
+
self.country if hasattr(self, "country") else get_country()
|
|
519
|
+
)
|
|
520
|
+
if current_country == "US":
|
|
521
|
+
output += " " + str(self.zip).zfill(5)
|
|
522
|
+
else:
|
|
523
|
+
output += " " + str(self.zip)
|
|
512
524
|
elif hasattr(self, "postal_code") and self.postal_code:
|
|
513
525
|
output += " " + str(self.postal_code)
|
|
514
526
|
return output
|
|
@@ -576,7 +588,13 @@ class ALAddress(Address):
|
|
|
576
588
|
else:
|
|
577
589
|
output += ", " + str(self.state)
|
|
578
590
|
if hasattr(self, "zip") and self.zip:
|
|
579
|
-
|
|
591
|
+
current_country = (
|
|
592
|
+
self.country if hasattr(self, "country") else get_country()
|
|
593
|
+
)
|
|
594
|
+
if current_country == "US":
|
|
595
|
+
output += " " + str(self.zip).zfill(5)
|
|
596
|
+
else:
|
|
597
|
+
output += " " + str(self.zip)
|
|
580
598
|
elif hasattr(self, "postal_code") and self.postal_code:
|
|
581
599
|
output += " " + str(self.postal_code)
|
|
582
600
|
if (
|
|
@@ -1267,9 +1285,13 @@ class ALIndividual(Individual):
|
|
|
1267
1285
|
|
|
1268
1286
|
If the individual has selected the "self-described" option, it will use their custom input.
|
|
1269
1287
|
|
|
1288
|
+
Can be formatted however the author likes.
|
|
1289
|
+
|
|
1270
1290
|
Returns:
|
|
1271
1291
|
set: A set of strings representing the individual's pronouns.
|
|
1272
1292
|
"""
|
|
1293
|
+
if hasattr(self, "pronouns") and isinstance(self.pronouns, str):
|
|
1294
|
+
return {self.pronouns}
|
|
1273
1295
|
if self.pronouns.all_false():
|
|
1274
1296
|
return {str(self.pronoun_prefer_not_to_say_label)}
|
|
1275
1297
|
pronouns = set(self.pronouns.true_values()) - {"self-described"}
|
|
@@ -1277,6 +1299,16 @@ class ALIndividual(Individual):
|
|
|
1277
1299
|
pronouns = pronouns.union(self.pronouns_self_described.splitlines())
|
|
1278
1300
|
return pronouns
|
|
1279
1301
|
|
|
1302
|
+
def list_pronouns(self) -> str:
|
|
1303
|
+
"""
|
|
1304
|
+
Retrieve a formatted string of the individual's pronouns, arranged with
|
|
1305
|
+
the comma_list() function.
|
|
1306
|
+
|
|
1307
|
+
Returns:
|
|
1308
|
+
str: A formatted string of the individual's pronouns.
|
|
1309
|
+
"""
|
|
1310
|
+
return comma_list(sorted(self.get_pronouns()))
|
|
1311
|
+
|
|
1280
1312
|
def language_fields(
|
|
1281
1313
|
self,
|
|
1282
1314
|
choices: Optional[List[Dict[str, str]]] = None,
|
|
@@ -1500,32 +1532,38 @@ class ALIndividual(Individual):
|
|
|
1500
1532
|
Returns:
|
|
1501
1533
|
str: The appropriate pronoun.
|
|
1502
1534
|
"""
|
|
1535
|
+
# Developers can do funky things; be a little flexible
|
|
1536
|
+
if hasattr(self, "pronouns") and isinstance(self.pronouns, str):
|
|
1537
|
+
pronouns = DADict(elements={self.pronouns.lower(): True})
|
|
1538
|
+
else:
|
|
1539
|
+
pronouns = self.pronouns
|
|
1540
|
+
|
|
1503
1541
|
if self == this_thread.global_vars.user:
|
|
1504
1542
|
output = word("you", **kwargs)
|
|
1505
1543
|
elif (
|
|
1506
1544
|
hasattr(self, "pronouns")
|
|
1507
|
-
and isinstance(
|
|
1508
|
-
and len(
|
|
1545
|
+
and isinstance(pronouns, DADict)
|
|
1546
|
+
and len(pronouns.true_values()) == 1
|
|
1509
1547
|
and (
|
|
1510
1548
|
(
|
|
1511
|
-
|
|
1549
|
+
pronouns.true_values()[0]
|
|
1512
1550
|
in ["she/her/hers", "he/him/his", "they/them/theirs", "ze/zir/zirs"]
|
|
1513
1551
|
)
|
|
1514
1552
|
or (
|
|
1515
|
-
|
|
1553
|
+
pronouns.get("self-described")
|
|
1516
1554
|
and has_parsable_pronouns(self.pronouns_self_described)
|
|
1517
1555
|
)
|
|
1518
1556
|
)
|
|
1519
1557
|
):
|
|
1520
|
-
if
|
|
1558
|
+
if pronouns.get("she/her/hers"):
|
|
1521
1559
|
output = word("her", **kwargs)
|
|
1522
|
-
elif
|
|
1560
|
+
elif pronouns.get("he/him/his"):
|
|
1523
1561
|
output = word("him", **kwargs)
|
|
1524
|
-
elif
|
|
1562
|
+
elif pronouns.get("they/them/theirs"):
|
|
1525
1563
|
output = word("them", **kwargs)
|
|
1526
|
-
elif
|
|
1564
|
+
elif pronouns.get("ze/zir/zirs"):
|
|
1527
1565
|
output = word("zir", **kwargs)
|
|
1528
|
-
elif
|
|
1566
|
+
elif pronouns.get("self-described"):
|
|
1529
1567
|
output = parse_custom_pronouns(self.pronouns_self_described)["o"]
|
|
1530
1568
|
elif hasattr(self, "person_type") and self.person_type in [
|
|
1531
1569
|
"business",
|
|
@@ -1567,34 +1605,39 @@ class ALIndividual(Individual):
|
|
|
1567
1605
|
Returns:
|
|
1568
1606
|
str: The appropriate possessive phrase.
|
|
1569
1607
|
"""
|
|
1608
|
+
if hasattr(self, "pronouns") and isinstance(self.pronouns, str):
|
|
1609
|
+
pronouns = DADict(elements={self.pronouns.lower(): True})
|
|
1610
|
+
else:
|
|
1611
|
+
pronouns = self.pronouns
|
|
1612
|
+
|
|
1570
1613
|
if self == this_thread.global_vars.user and (
|
|
1571
1614
|
"thirdperson" not in kwargs or not kwargs["thirdperson"]
|
|
1572
1615
|
):
|
|
1573
1616
|
output = your(target, **kwargs)
|
|
1574
1617
|
elif (
|
|
1575
1618
|
hasattr(self, "pronouns")
|
|
1576
|
-
and isinstance(
|
|
1577
|
-
and len(
|
|
1619
|
+
and isinstance(pronouns, DADict)
|
|
1620
|
+
and len(pronouns.true_values()) == 1
|
|
1578
1621
|
and (
|
|
1579
1622
|
(
|
|
1580
|
-
|
|
1623
|
+
pronouns.true_values()[0]
|
|
1581
1624
|
in ["she/her/hers", "he/him/his", "they/them/theirs", "ze/zir/zirs"]
|
|
1582
1625
|
)
|
|
1583
1626
|
or (
|
|
1584
|
-
|
|
1627
|
+
pronouns.get("self-described")
|
|
1585
1628
|
and has_parsable_pronouns(self.pronouns_self_described)
|
|
1586
1629
|
)
|
|
1587
1630
|
)
|
|
1588
1631
|
):
|
|
1589
|
-
if
|
|
1632
|
+
if pronouns.get("she/her/hers"):
|
|
1590
1633
|
output = her(target, **kwargs)
|
|
1591
|
-
elif
|
|
1634
|
+
elif pronouns.get("he/him/his"):
|
|
1592
1635
|
output = his(target, **kwargs)
|
|
1593
|
-
elif
|
|
1636
|
+
elif pronouns.get("they/them/theirs"):
|
|
1594
1637
|
output = their(target, **kwargs)
|
|
1595
|
-
elif
|
|
1638
|
+
elif pronouns.get("ze/zir/zirs"):
|
|
1596
1639
|
output = word("zir", **kwargs) + " " + target
|
|
1597
|
-
elif
|
|
1640
|
+
elif pronouns.get("self-described"):
|
|
1598
1641
|
output = (
|
|
1599
1642
|
parse_custom_pronouns(self.pronouns_self_described)["p"]
|
|
1600
1643
|
+ " "
|
|
@@ -1628,34 +1671,39 @@ class ALIndividual(Individual):
|
|
|
1628
1671
|
Returns:
|
|
1629
1672
|
str: The appropriate subjective pronoun.
|
|
1630
1673
|
"""
|
|
1674
|
+
if hasattr(self, "pronouns") and isinstance(self.pronouns, str):
|
|
1675
|
+
pronouns = DADict(elements={self.pronouns.lower(): True})
|
|
1676
|
+
else:
|
|
1677
|
+
pronouns = self.pronouns
|
|
1678
|
+
|
|
1631
1679
|
if self == this_thread.global_vars.user and (
|
|
1632
1680
|
"thirdperson" not in kwargs or not kwargs["thirdperson"]
|
|
1633
1681
|
):
|
|
1634
1682
|
output = word("you", **kwargs)
|
|
1635
1683
|
elif (
|
|
1636
1684
|
hasattr(self, "pronouns")
|
|
1637
|
-
and isinstance(
|
|
1638
|
-
and len(
|
|
1685
|
+
and isinstance(pronouns, DADict)
|
|
1686
|
+
and len(pronouns.true_values()) == 1
|
|
1639
1687
|
and (
|
|
1640
1688
|
(
|
|
1641
|
-
|
|
1689
|
+
pronouns.true_values()[0]
|
|
1642
1690
|
in ["she/her/hers", "he/him/his", "they/them/theirs", "ze/zir/zirs"]
|
|
1643
1691
|
)
|
|
1644
1692
|
or (
|
|
1645
|
-
|
|
1693
|
+
pronouns.get("self-described")
|
|
1646
1694
|
and has_parsable_pronouns(self.pronouns_self_described)
|
|
1647
1695
|
)
|
|
1648
1696
|
)
|
|
1649
1697
|
):
|
|
1650
|
-
if
|
|
1698
|
+
if pronouns.get("she/her/hers"):
|
|
1651
1699
|
output = word("she", **kwargs)
|
|
1652
|
-
elif
|
|
1700
|
+
elif pronouns.get("he/him/his"):
|
|
1653
1701
|
output = word("he", **kwargs)
|
|
1654
|
-
elif
|
|
1702
|
+
elif pronouns.get("they/them/theirs"):
|
|
1655
1703
|
output = word("they", **kwargs)
|
|
1656
|
-
elif
|
|
1704
|
+
elif pronouns.get("ze/zir/zirs"):
|
|
1657
1705
|
output = word("ze", **kwargs)
|
|
1658
|
-
elif
|
|
1706
|
+
elif pronouns.get("self-described"):
|
|
1659
1707
|
output = parse_custom_pronouns(self.pronouns_self_described)["s"]
|
|
1660
1708
|
elif hasattr(self, "person_type") and self.person_type in [
|
|
1661
1709
|
"business",
|
|
@@ -1672,6 +1720,36 @@ class ALIndividual(Individual):
|
|
|
1672
1720
|
return capitalize(output)
|
|
1673
1721
|
return output
|
|
1674
1722
|
|
|
1723
|
+
def name_full(self) -> str:
|
|
1724
|
+
"""Returns the individual's full name.
|
|
1725
|
+
|
|
1726
|
+
Returns:
|
|
1727
|
+
str: The individual's full name.
|
|
1728
|
+
"""
|
|
1729
|
+
return self.name.full(middle="full")
|
|
1730
|
+
|
|
1731
|
+
def name_initials(self) -> str:
|
|
1732
|
+
"""
|
|
1733
|
+
Returns the individual's name with the middle name as an initial.
|
|
1734
|
+
Equivalent to `name.full(middle="initial")`, which is also the default.
|
|
1735
|
+
Defined only to make it possible to be explicit about the name form.
|
|
1736
|
+
|
|
1737
|
+
Returns:
|
|
1738
|
+
str: The individual's name with the middle name as an initial.
|
|
1739
|
+
"""
|
|
1740
|
+
return self.name.full(middle="initial")
|
|
1741
|
+
|
|
1742
|
+
def name_short(self) -> str:
|
|
1743
|
+
"""
|
|
1744
|
+
Returns the individual's name without any middle name.
|
|
1745
|
+
|
|
1746
|
+
Equivalent to self.name.firstlast()
|
|
1747
|
+
|
|
1748
|
+
Returns:
|
|
1749
|
+
str: The individual'
|
|
1750
|
+
"""
|
|
1751
|
+
return self.name.firstlast()
|
|
1752
|
+
|
|
1675
1753
|
|
|
1676
1754
|
# (DANav isn't in public DA API, but currently in functions.py)
|
|
1677
1755
|
def section_links(nav) -> List[str]: # type: ignore
|
|
@@ -2048,7 +2126,7 @@ def get_visible_al_nav_items(
|
|
|
2048
2126
|
|
|
2049
2127
|
# For dictionaries at top level
|
|
2050
2128
|
item_copy = deepcopy(item)
|
|
2051
|
-
if not item_copy.pop("hidden", False): # if not hidden
|
|
2129
|
+
if not str(item_copy.pop("hidden", "False")).lower() == "true": # if not hidden
|
|
2052
2130
|
for key, val in item_copy.items():
|
|
2053
2131
|
if isinstance(val, list): # if value of a key is a list
|
|
2054
2132
|
new_sublist: List[Union[str, dict]] = []
|
|
@@ -2057,8 +2135,10 @@ def get_visible_al_nav_items(
|
|
|
2057
2135
|
if isinstance(subitem, str):
|
|
2058
2136
|
new_sublist.append(subitem)
|
|
2059
2137
|
# Add dictionaries if not hidden
|
|
2060
|
-
elif
|
|
2061
|
-
|
|
2138
|
+
elif (
|
|
2139
|
+
isinstance(subitem, dict)
|
|
2140
|
+
and not str(subitem.pop("hidden", "False")).lower()
|
|
2141
|
+
== "true"
|
|
2062
2142
|
):
|
|
2063
2143
|
new_sublist.append(subitem)
|
|
2064
2144
|
item_copy[key] = new_sublist
|
|
@@ -186,13 +186,16 @@ code: |
|
|
|
186
186
|
# If the user role was set to "unknown" at the time wizard run
|
|
187
187
|
user_role = user_ask_role
|
|
188
188
|
---
|
|
189
|
-
#
|
|
189
|
+
# HTML for interviews using ALKiln tests at ALKiln
|
|
190
|
+
# Necessary for servers that set their `restrict input variables` config value to `True`
|
|
191
|
+
# If you are using al_package_unstyled.yml, copy it into your `default screen parts: post`
|
|
190
192
|
template: alkiln_trigger_html
|
|
191
193
|
content: |
|
|
192
194
|
<div data-variable="${ encode_name(str( user_info().variable )) }" id="trigger" aria-hidden="true" style="display: none;"></div>
|
|
193
195
|
---
|
|
194
196
|
# HTML for interviews using ALKiln tests at ALKiln versions 5.9.0 and above.
|
|
195
|
-
#
|
|
197
|
+
# Necessary for interviews that use docassemble generic objects or index variables
|
|
198
|
+
# If you are using al_package_unstyled.yml, copy it into your `default screen parts: post`
|
|
196
199
|
template: alkiln_proxy_html
|
|
197
200
|
content: |
|
|
198
201
|
<div id="alkiln_proxy_var_values"
|
|
@@ -41,10 +41,10 @@ default screen parts:
|
|
|
41
41
|
corner back button label: |
|
|
42
42
|
Undo
|
|
43
43
|
pre: |
|
|
44
|
-
% if get_config('debug'):
|
|
45
|
-
`id: ${ user_info().question_id }`
|
|
46
|
-
`Variable
|
|
47
|
-
`
|
|
44
|
+
% if get_config('debug') and not url_args.get("hide_hud", "").lower() in ["1", "on", "true", "yes"]:
|
|
45
|
+
`id: ${ user_info().question_id }`[BR]
|
|
46
|
+
`Variable: ${ user_info().variable }`[BR]
|
|
47
|
+
`Version: ${ user_info().package.replace("docassemble.", "") + " " if not user_info().package.startswith("docassemble.playground") else "" }${ package_version_number }; ${ al_version }`
|
|
48
48
|
<div data-variable="${ encode_name(str( user_info().variable )) }" id="sought_variable" aria-hidden="true" style="display: none;"></div>
|
|
49
49
|
% endif
|
|
50
50
|
# We need both pre and post until old interviews are updated to v2 of the testing framework or v1 of the testing framework is updated. In future, we will need this in `post` so that it will work on signature pages.
|
|
@@ -71,19 +71,17 @@ subquestion: |
|
|
|
71
71
|
fields:
|
|
72
72
|
- note: |
|
|
73
73
|
${ display_template(al_terms_of_use, scrollable=True) }
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
choices:
|
|
79
|
-
- I accept the terms of use.
|
|
80
|
-
validation messages:
|
|
81
|
-
minlength: |
|
|
82
|
-
You cannot continue unless you agree to the terms of use.
|
|
74
|
+
To continue, you must accept our terms of use
|
|
75
|
+
- I accept the terms of use: acknowledged_information_use
|
|
76
|
+
datatype: yesnowide
|
|
77
|
+
grid: 8
|
|
83
78
|
continue button field: al_intro_screen
|
|
84
79
|
terms:
|
|
85
80
|
green words: |
|
|
86
81
|
Green words are legal terms or a short way of referring to something that needs more explanation. The definition or explanation pops up when you tap the green words.
|
|
82
|
+
validation code: |
|
|
83
|
+
if not acknowledged_information_use:
|
|
84
|
+
validation_error("You must accept the terms of use to continue.", field="acknowledged_information_use")
|
|
87
85
|
---
|
|
88
86
|
##### Backwards compatibility #####
|
|
89
87
|
code: |
|
docassemble_assemblyline-2.28.1/docassemble/AssemblyLine/data/questions/test_bundle_parity.yml
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
include:
|
|
3
|
+
- assembly_line.yml
|
|
4
|
+
---
|
|
5
|
+
objects:
|
|
6
|
+
- the_doc: ALDocument.using(
|
|
7
|
+
title="The document",
|
|
8
|
+
filename="the_document",
|
|
9
|
+
enabled=True,
|
|
10
|
+
has_addendum=False
|
|
11
|
+
)
|
|
12
|
+
---
|
|
13
|
+
objects:
|
|
14
|
+
- even_bundle: ALDocumentBundle.using(
|
|
15
|
+
title="Even bundle",
|
|
16
|
+
filename="the_bundle",
|
|
17
|
+
elements=[
|
|
18
|
+
the_doc
|
|
19
|
+
],
|
|
20
|
+
default_parity="even",
|
|
21
|
+
enabled=True
|
|
22
|
+
)
|
|
23
|
+
- odd_bundle: ALDocumentBundle.using(
|
|
24
|
+
title="Even bundle",
|
|
25
|
+
filename="the_bundle",
|
|
26
|
+
elements=[
|
|
27
|
+
the_doc,
|
|
28
|
+
the_doc
|
|
29
|
+
],
|
|
30
|
+
enabled=True
|
|
31
|
+
)
|
|
32
|
+
- bundle_with_default: ALDocumentBundle.using(
|
|
33
|
+
title="Even bundle",
|
|
34
|
+
filename="the_bundle",
|
|
35
|
+
elements=[
|
|
36
|
+
the_doc
|
|
37
|
+
],
|
|
38
|
+
default_parity="even",
|
|
39
|
+
enabled=True
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
objects:
|
|
44
|
+
- bundle_of_bundles: ALDocumentBundle.using(
|
|
45
|
+
title="Bundle of bundles",
|
|
46
|
+
filename="the_bundle",
|
|
47
|
+
elements=[
|
|
48
|
+
even_bundle,
|
|
49
|
+
bundle_with_default
|
|
50
|
+
],
|
|
51
|
+
enabled=True
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
attachment:
|
|
56
|
+
variable name: the_doc[i]
|
|
57
|
+
content: |
|
|
58
|
+
Test content
|
|
59
|
+
---
|
|
60
|
+
mandatory: True
|
|
61
|
+
question: |
|
|
62
|
+
About to make a PDF
|
|
63
|
+
continue button field: the_field
|
|
64
|
+
---
|
|
65
|
+
mandatory: True
|
|
66
|
+
question: |
|
|
67
|
+
Download
|
|
68
|
+
subquestion: |
|
|
69
|
+
# Should be even
|
|
70
|
+
${ even_bundle.as_pdf(ensure_parity="even") }
|
|
71
|
+
|
|
72
|
+
# should be odd
|
|
73
|
+
${ odd_bundle.as_pdf(ensure_parity="odd") }
|
|
74
|
+
|
|
75
|
+
# should be even
|
|
76
|
+
${ bundle_with_default.as_pdf() }
|
|
77
|
+
|
|
78
|
+
# Should be even
|
|
79
|
+
${ bundle_of_bundles.as_pdf() }
|
|
@@ -427,6 +427,15 @@ class TestALIndividual(unittest.TestCase):
|
|
|
427
427
|
with self.assertRaises(DAAttributeError):
|
|
428
428
|
self.individual.pronoun_objective()
|
|
429
429
|
|
|
430
|
+
def test_name_methods(self):
|
|
431
|
+
self.individual.name.first = "John"
|
|
432
|
+
self.individual.name.middle = "Jacob"
|
|
433
|
+
self.individual.name.last = "Jingleheimer"
|
|
434
|
+
|
|
435
|
+
self.assertEqual(self.individual.name_full(), "John Jacob Jingleheimer")
|
|
436
|
+
self.assertEqual(self.individual.name_initials(), "John J. Jingleheimer")
|
|
437
|
+
self.assertEqual(self.individual.name_short(), "John Jingleheimer")
|
|
438
|
+
|
|
430
439
|
|
|
431
440
|
class test_get_visible_al_nav_items(unittest.TestCase):
|
|
432
441
|
def test_case_1(self):
|
|
@@ -49,6 +49,7 @@ docassemble/AssemblyLine/data/questions/test_alcourts.yml
|
|
|
49
49
|
docassemble/AssemblyLine/data/questions/test_aldocument.yml
|
|
50
50
|
docassemble/AssemblyLine/data/questions/test_alexhibit.yml
|
|
51
51
|
docassemble/AssemblyLine/data/questions/test_alexhibit_maxsize.yml
|
|
52
|
+
docassemble/AssemblyLine/data/questions/test_bundle_parity.yml
|
|
52
53
|
docassemble/AssemblyLine/data/questions/test_question_library.yml
|
|
53
54
|
docassemble/AssemblyLine/data/sources/README.md
|
|
54
55
|
docassemble/AssemblyLine/data/sources/es-words.yml
|
|
@@ -44,7 +44,7 @@ def find_package_data(where='.', package='', exclude=standard_exclude, exclude_d
|
|
|
44
44
|
return out
|
|
45
45
|
|
|
46
46
|
setup(name='docassemble.AssemblyLine',
|
|
47
|
-
version='2.
|
|
47
|
+
version='2.28.1',
|
|
48
48
|
description=(''),
|
|
49
49
|
long_description='# Suffolk LIT Lab Document Assembly Line\r\n\r\n[](https://badge.fury.io/py/docassemble-AssemblyLine)\r\n\r\n<img src="https://user-images.githubusercontent.com/7645641/142245862-c2eb02ab-3090-4e97-9653-bb700bf4c54d.png" alt="drawing" width="300" alt="work together" style="align: center;"/>\r\n\r\nThe Assembly Line Project is a collection of volunteers, students, and institutions who joined together\r\nduring the COVID-19 pandemic to help increase access to the court system. Our vision is mobile-friendly,\r\neasy to use **guided** online forms that help empower litigants to access the court remotely.\r\n\r\nOur signature project is [CourtFormsOnline.org](https://courtformsonline.org).\r\n\r\nWe designed a step-by-step, assembly line style process for automating court forms on top of Docassemble\r\nand built several tools along the way that **you** can use in your home jurisdiction.\r\n\r\nThis package contains **runtime code** and **pre-written questions** to support authoring robust, \r\nconsistent, and attractive Docassemble interviews that help complete court forms.\r\n\r\nRead more on our [documentation page](https://suffolklitlab.org/docassemble-AssemblyLine-documentation/).\r\n\r\n\r\n# Related repositories\r\n\r\n* https://github.com/SuffolkLitLab/docassemble-ALWeaver\r\n* https://github.com/SuffolkLitLab/docassemble-ALMassachusetts\r\n* https://github.com/SuffolkLitLab/docassemble-MassAccess\r\n* https://github.com/SuffolkLitLab/docassemble-ALThemeTemplate\r\n* https://github.com/SuffolkLitLab/EfileProxyServer\r\n\r\n# Documentation\r\n\r\nhttps://suffolklitlab.org/docassemble-AssemblyLine-documentation/\r\n\r\n# Installation\r\n\r\n## Menu-driven installation\r\n\r\nThe recommended installation method is with the [guided installation script](https://suffolklitlab.org/docassemble-AssemblyLine-documentation/docs/installation).\r\n\r\n## Manual installation\r\n\r\nNormally you do not need to manually install the Assembly Line. Use the [installation script](https://suffolklitlab.org/docassemble-AssemblyLine-documentation/docs/installation)\r\nif you can. The instructions below are for your optional reference.\r\n\r\nThis package depends on the following configuration changes on your Docassemble server:\r\n\r\n* Ensure that [font-awesome](https://docassemble.org/docs/config.html#default%20icons) is enabled (this may be on by default:\r\n```yaml\r\ndefault icons: font awesome\r\n```\r\n* Add a [Google API key](https://docassemble.org/docs/config.html#google) that has access to:\r\n * Google Places API\r\n * Google Geocoding API\r\n* Add a [VoiceRSS API key](https://docassemble.org/docs/config.html#voicerss)\r\n* Add a [Twilio API key](https://docassemble.org/docs/config.html#twilio) for SMS support\r\n* Add an email account: [Mailgun](https://docassemble.org/docs/config.html#mailgun%20api) or [SendGrid](https://docassemble.org/docs/config.html#sendgrid%20api) recommended for email support\r\n* To show package update time and to enable the feedback form, add a GitHub Private Access token to your config.yml file, like this:\r\n```yaml\r\n# Needs access to create new issues on repositories\r\ngithub issues:\r\n username: "suffolklitlab-issues"\r\n token: "12345"\r\n# Does not need any special access to public repositories \r\ngithub readonly:\r\n username: "suffolklitlab-issues"\r\n password: "45678"\r\n type: "basic"\r\n```\r\n* If you are also using the [Assembly Line Weaver](https://github.com/SuffolkLITLab/docassemble-assemblylinewizard), you may want to set up a [Docassemble API key](https://docassemble.org/docs/api.html#manage_api) in your config.yml file to allow you to install packages automatically, like this:\r\n```yaml\r\ninstall packages api key: 12345\r\n```\r\n\r\n# Migration\r\n\r\nSee [discussion here](https://github.com/SuffolkLITLab/docassemble-AssemblyLine/issues/69)\r\n\r\n\r\n# ALDocument class\r\n\r\n## Purpose\r\n\r\nThe ALDocument class is a small utility library that makes it simpler to use the following features in an interview:\r\n\r\n* Conditional assembly of multiple, optional documents that are triggered in different ways in your interview\r\n* An addendum for PDF files that makes it simple to deal with overflow text\r\n* A customizable download screen that lists the documents in a neat table\r\n* A customizable "send" button that allows the user to email the final forms to a location of their choice\r\n\r\nHere is a small snippet that you can copy and modify that shows how to use the most important features of the ALDocument class.\r\n\r\n```\r\n---\r\nobjects:\r\n - CRA_Motion_to_Dismiss_attachment: ALDocument.using(filename="CRA_Motion_to_Dismiss", title="Motion to Dismiss CRA", enabled=True, has_addendum=True, default_overflow_message="[See addendum]") \r\n---\r\nobjects:\r\n - al_user_bundle: ALDocumentBundle.using(elements=[CRA_Motion_to_Dismiss_attachment], title="Forms to download and deliver to court", filename="motion_to_dismiss_CRA.pdf")\r\n - al_court_bundle: ALDocumentBundle.using(elements=[CRA_Motion_to_Dismiss_attachment], title="Forms to download and deliver to court", filename="motion_to_dismiss_CRA.pdf")\r\n---\r\ngeneric object: ALDocument\r\nattachment:\r\n variable name: x.addendum\r\n docx template file: docx_addendum.docx\r\n---\r\ncode: |\r\n CRA_Motion_to_Dismiss_attachment.overflow_fields[\'reasons_for_request\'].overflow_trigger = 640\r\n CRA_Motion_to_Dismiss_attachment.overflow_fields[\'reasons_for_request\'].label = "Reasons for request"\r\n CRA_Motion_to_Dismiss_attachment.overflow_fields.gathered = True\r\n \r\n---\r\nattachment:\r\n variable name: CRA_Motion_to_Dismiss_attachment[i]\r\n name: CRA Motion to Dismiss\r\n filename: CRA_Motion_to_Dismiss\r\n skip undefined: True\r\n pdf template file: CRA_Motion_to_Dismiss.pdf\r\n fields: \r\n - "court_county": ${ trial_court.address.county }\r\n - "docket_number": ${ docket_number }\r\n - "user_signature": ${ users[0].signature_if_final(i) }\r\n - "signature_date": ${ signature_date }\r\n```\r\n\r\nIt is very common to have a *contingent* document in ALDocument. If your document is contingent, remove the `enabled=True` from the object declaration, and use\r\nsome other method to "turn on" the attachment.\r\n\r\nE.g.,\r\n\r\n```\r\ncode: |\r\n CRA_Motion_to_Dismiss_attachment.enabled = condition1 and condition2\r\n```\r\n\r\n# Changelog\r\n\r\nSee [CHANGELOG.MD](https://github.com/SuffolkLITLab/docassemble-AssemblyLine/blob/main/CHANGELOG.md)\r\n',
|
|
50
50
|
long_description_content_type='text/markdown',
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '2.27.2'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|