docassemble.AssemblyLine 3.2.0__tar.gz → 3.4.0__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.
Files changed (98) hide show
  1. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/LICENSE +1 -1
  2. {docassemble_assemblyline-3.2.0/docassemble.AssemblyLine.egg-info → docassemble_assemblyline-3.4.0}/PKG-INFO +12 -4
  3. docassemble_assemblyline-3.4.0/docassemble/AssemblyLine/__init__.py +1 -0
  4. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/al_courts.py +24 -8
  5. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/al_document.py +109 -16
  6. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/al_general.py +41 -8
  7. docassemble_assemblyline-3.4.0/docassemble/AssemblyLine/custom_jinja_filters.py +123 -0
  8. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/al_code.yml +39 -39
  9. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/al_saved_sessions.yml +1 -1
  10. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/al_saved_sessions_store.yml +4 -4
  11. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/al_settings.yml +9 -2
  12. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/al_visual.yml +16 -12
  13. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/interview_list.yml +1 -1
  14. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/ql_baseline.yml +53 -24
  15. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/ql_catchall.yml +37 -17
  16. docassemble_assemblyline-3.4.0/docassemble/AssemblyLine/data/questions/ql_namechange.yml +40 -0
  17. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/test_aldocument.yml +42 -15
  18. docassemble_assemblyline-3.4.0/docassemble/AssemblyLine/data/questions/test_signature.yml +28 -0
  19. docassemble_assemblyline-3.4.0/docassemble/AssemblyLine/data/sources/translation_es.xlsx +0 -0
  20. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/language.py +16 -3
  21. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/project_maintenance.py +4 -1
  22. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/sessions.py +17 -16
  23. docassemble_assemblyline-3.4.0/docassemble/AssemblyLine/sign.py +144 -0
  24. docassemble_assemblyline-3.4.0/docassemble/__init__.py +1 -0
  25. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0/docassemble.AssemblyLine.egg-info}/PKG-INFO +12 -4
  26. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble.AssemblyLine.egg-info/SOURCES.txt +4 -2
  27. docassemble_assemblyline-3.4.0/docassemble.AssemblyLine.egg-info/requires.txt +2 -0
  28. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble.AssemblyLine.egg-info/top_level.txt +1 -0
  29. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/pyproject.toml +0 -3
  30. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/setup.py +4 -5
  31. docassemble_assemblyline-3.2.0/docassemble/AssemblyLine/__init__.py +0 -1
  32. docassemble_assemblyline-3.2.0/docassemble/AssemblyLine/data/sources/translation_es.xlsx +0 -0
  33. docassemble_assemblyline-3.2.0/docassemble/AssemblyLine/data/sources/translation_es_broken.xlsx +0 -0
  34. docassemble_assemblyline-3.2.0/docassemble/__init__.py +0 -2
  35. docassemble_assemblyline-3.2.0/docassemble.AssemblyLine.egg-info/namespace_packages.txt +0 -1
  36. docassemble_assemblyline-3.2.0/docassemble.AssemblyLine.egg-info/requires.txt +0 -2
  37. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/MANIFEST.in +0 -0
  38. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/README.md +0 -0
  39. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/al_document.yml +0 -0
  40. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/al_language.yml +0 -0
  41. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/al_package.yml +0 -0
  42. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/al_package_unstyled.yml +0 -0
  43. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/al_question_test.yml +0 -0
  44. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/al_reminders.yml +0 -0
  45. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/al_terms_of_use.yml +0 -0
  46. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/assembly_line.yml +0 -0
  47. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/assembly_line_unstyled.yml +0 -0
  48. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/demo_search_sessions.yml +0 -0
  49. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/feedback.yml +0 -0
  50. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/reserved_words.yml +0 -0
  51. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/test_al_table_document.yml +0 -0
  52. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/test_aladdendum.yml +0 -0
  53. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/test_alcourts.yml +0 -0
  54. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/test_aldocument_background_assembly.yml +0 -0
  55. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/test_alexhibit.yml +0 -0
  56. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/test_alexhibit_maxsize.yml +0 -0
  57. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/test_bundle_parity.yml +0 -0
  58. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/test_familiar_disambiguation.yml +0 -0
  59. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/questions/test_question_library.yml +0 -0
  60. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/sources/README.md +0 -0
  61. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/sources/es-words.yml +0 -0
  62. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/sources/languages.yml +0 -0
  63. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/sources/test_aldocument.feature +0 -0
  64. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_docx_1.docx +0 -0
  65. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_jpg_1.jpg +0 -0
  66. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_pdf_1.pdf +0 -0
  67. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_png_1.png +0 -0
  68. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/sources/test_question_library.feature +0 -0
  69. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/sources/translation_ht.xlsx +0 -0
  70. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/sources/translation_pt.xlsx +0 -0
  71. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/static/README.md +0 -0
  72. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/static/al_audio.css +0 -0
  73. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/static/al_audio.js +0 -0
  74. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/static/aldocument.css +0 -0
  75. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/static/aldocument.js +0 -0
  76. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/static/interview_list.css +0 -0
  77. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/static/limit_upload_size.js +0 -0
  78. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/static/lt1-pullout-10-getting-organized.pdf +0 -0
  79. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/static/ma_logo.png +0 -0
  80. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/static/placeholder.png +0 -0
  81. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/static/seal.jpg +0 -0
  82. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/static/styles.css +0 -0
  83. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/templates/README.md +0 -0
  84. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/templates/al_basic_addendum.docx +0 -0
  85. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/templates/exhibit_cover_sheet.docx +0 -0
  86. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/templates/exhibit_table_of_contents.docx +0 -0
  87. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/templates/general_cover_sheet.docx +0 -0
  88. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/templates/sample_word_template.docx +0 -0
  89. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/templates/test_aldocument_docx_1.docx +0 -0
  90. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/data/templates/test_aldocument_pdf_1.pdf +0 -0
  91. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/py.typed +0 -0
  92. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/requirements.txt +0 -0
  93. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/test_al_document.py +0 -0
  94. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/test_al_general.py +0 -0
  95. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble/AssemblyLine/test_language.py +0 -0
  96. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble.AssemblyLine.egg-info/dependency_links.txt +0 -0
  97. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/docassemble.AssemblyLine.egg-info/not-zip-safe +0 -0
  98. {docassemble_assemblyline-3.2.0 → docassemble_assemblyline-3.4.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2023 Suffolk Legal Innovation and Technology Lab
3
+ Copyright (c) 2025 Suffolk Legal Innovation and Technology Lab
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,14 +1,22 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: docassemble.AssemblyLine
3
- Version: 3.2.0
3
+ Version: 3.4.0
4
4
  Home-page: https://courtformsonline.org
5
5
  Author: Suffolk Legal Innovation and Technology Lab
6
6
  Author-email: qsteenhuis@suffolk.edu
7
7
  License: The MIT License (MIT)
8
8
  Description-Content-Type: text/markdown
9
9
  License-File: LICENSE
10
- Requires-Dist: docassemble.ALToolbox>=0.8.3
11
- Requires-Dist: docassemble.GithubFeedbackForm>=0.2.1
10
+ Requires-Dist: docassemble.ALToolbox>=0.11.1
11
+ Requires-Dist: docassemble.GithubFeedbackForm>=0.4.1.1
12
+ Dynamic: author
13
+ Dynamic: author-email
14
+ Dynamic: description
15
+ Dynamic: description-content-type
16
+ Dynamic: home-page
17
+ Dynamic: license
18
+ Dynamic: license-file
19
+ Dynamic: requires-dist
12
20
 
13
21
  # Suffolk LIT Lab Document Assembly Line
14
22
 
@@ -0,0 +1 @@
1
+ __version__ = '3.4.0'
@@ -24,19 +24,28 @@ __all__ = [
24
24
 
25
25
 
26
26
  class ALCourt(Court):
27
- """Object representing a court in Massachusetts.
28
- TODO: it could be interesting to store a jurisdiction on a court. But this is non-trivial. Should it be geo boundaries?
27
+ """Object representing a court in Massachusetts. We use a function on the CourtList object that filters courts by
28
+ address and can use any of those three features of the court to do the filtering.
29
+
30
+ <!-- TODO: it could be interesting to store a jurisdiction on a court. But this is non-trivial. Should it be geo boundaries?
29
31
  A list of cities? A list of counties? Instead, we use a function on the CourtList object that filters courts by
30
- address and can use any of those three features of the court to do the filtering."""
32
+ address and can use any of those three features of the court to do the filtering.-->
33
+ """
31
34
 
32
- def init(self, *pargs, **kwargs):
35
+ def init(self, *pargs, **kwargs) -> None:
36
+ """Create a new court object.
37
+
38
+ Args:
39
+ *pargs: Standard DAObject positional arguments
40
+ **kwargs: Standard DAObject keyword arguments
41
+ """
33
42
  super().init(*pargs, **kwargs)
34
43
  if "address" not in kwargs:
35
44
  self.initializeAttribute("address", ALAddress)
36
45
  if (
37
46
  "jurisdiction" not in kwargs
38
47
  ): # This attribute isn't used. Could be a better way to handle court locating
39
- self.jurisdiction = []
48
+ self.jurisdiction: list = []
40
49
  if "location" not in kwargs:
41
50
  self.initializeAttribute("location", LatitudeLongitude)
42
51
 
@@ -208,7 +217,13 @@ class ALCourtLoader(DAObject):
208
217
  converters (Dict[str, Callable]): A dictionary of functions to apply to columns in the dataframe.
209
218
  """
210
219
 
211
- def init(self, *pargs, **kwargs):
220
+ def init(self, *pargs, **kwargs) -> None:
221
+ """Create a new courtloader object.
222
+
223
+ Args:
224
+ *pargs: Standard DAObject positional arguments
225
+ **kwargs: Standard DAObject keyword arguments
226
+ """
212
227
  super().init(*pargs, **kwargs)
213
228
  self.package = docassemble.base.functions.this_thread.current_question.package
214
229
  if not hasattr(self, "filename"):
@@ -240,8 +255,9 @@ class ALCourtLoader(DAObject):
240
255
  column_name (str): The name of the column in the dataframe.
241
256
 
242
257
  Returns:
243
- Set[str]: A set containing unique values from the specified column.
244
- Returns an empty set if an error occurs.
258
+ Set[str]:
259
+ - A set containing unique values from the specified column.
260
+ - Returns an empty set if the column does not exist or an error occurs.
245
261
  """
246
262
  df = self._load_courts()
247
263
  try:
@@ -248,7 +248,13 @@ class ALAddendumField(DAObject):
248
248
  The attributes `headers` and `field_style` are planned for future releases and are not currently implemented.
249
249
  """
250
250
 
251
- def init(self, *pargs, **kwargs):
251
+ def init(self, *pargs, **kwargs) -> None:
252
+ """Standard DAObject init method.
253
+
254
+ Args:
255
+ *pargs: Positional arguments
256
+ **kwargs: Keyword arguments
257
+ """
252
258
  super().init(*pargs, **kwargs)
253
259
 
254
260
  def overflow_value(
@@ -752,7 +758,13 @@ class ALAddendumFieldDict(DAOrderedDict):
752
758
  only the overflow text will be displayed.
753
759
  """
754
760
 
755
- def init(self, *pargs, **kwargs):
761
+ def init(self, *pargs, **kwargs) -> None:
762
+ """Standard DAObject init method.
763
+
764
+ Args:
765
+ *pargs: Positional arguments
766
+ **kwargs: Keyword arguments
767
+ """
756
768
  super(ALAddendumFieldDict, self).init(*pargs, **kwargs)
757
769
  self.object_type = ALAddendumField
758
770
  self.auto_gather = False
@@ -990,7 +1002,13 @@ class ALDocument(DADict):
990
1002
  ```
991
1003
  """
992
1004
 
993
- def init(self, *pargs, **kwargs):
1005
+ def init(self, *pargs, **kwargs) -> None:
1006
+ """Standard DAObject init method.
1007
+
1008
+ Args:
1009
+ *pargs: Positional arguments
1010
+ **kwargs: Keyword arguments
1011
+ """
994
1012
  super(ALDocument, self).init(*pargs, **kwargs)
995
1013
  self.initializeAttribute("overflow_fields", ALAddendumFieldDict)
996
1014
  if not hasattr(self, "default_overflow_message"):
@@ -1345,7 +1363,13 @@ class ALStaticDocument(DAStaticFile):
1345
1363
  Consider handling files in `/data/templates` if deemed useful, potentially by copying into a DAFile using `pdf_concatenate()`.
1346
1364
  """
1347
1365
 
1348
- def init(self, *pargs, **kwargs):
1366
+ def init(self, *pargs, **kwargs) -> None:
1367
+ """Standard DAObject init method.
1368
+
1369
+ Args:
1370
+ *pargs: Positional arguments
1371
+ **kwargs: Keyword arguments
1372
+ """
1349
1373
  super().init(*pargs, **kwargs)
1350
1374
  self.has_addendum = False
1351
1375
  self.auto_gather = False
@@ -1515,7 +1539,13 @@ class ALDocumentBundle(DAList):
1515
1539
  ```
1516
1540
  """
1517
1541
 
1518
- def init(self, *pargs, **kwargs):
1542
+ def init(self, *pargs, **kwargs) -> None:
1543
+ """Standard DAObject init method.
1544
+
1545
+ Args:
1546
+ *pargs: Positional arguments
1547
+ **kwargs: Keyword arguments
1548
+ """
1519
1549
  super().init(*pargs, **kwargs)
1520
1550
  if "auto_gather" not in kwargs:
1521
1551
  self.auto_gather = False
@@ -1936,8 +1966,11 @@ class ALDocumentBundle(DAList):
1936
1966
  view_icon: str = "eye",
1937
1967
  download_label: str = "Download",
1938
1968
  download_icon: str = "download",
1969
+ send_label: str = "Send",
1970
+ send_icon: str = "envelope",
1939
1971
  zip_label: Optional[str] = None,
1940
1972
  zip_icon: str = "file-archive",
1973
+ zip_row_label: Optional[str] = "",
1941
1974
  append_matching_suffix: bool = True,
1942
1975
  include_email: bool = False,
1943
1976
  use_previously_cached_files: bool = False,
@@ -1958,10 +1991,14 @@ class ALDocumentBundle(DAList):
1958
1991
  view_icon (str): Icon for the 'view' button, default is "eye".
1959
1992
  download_label (str): Label for the 'download' button, default is "Download".
1960
1993
  download_icon (str): Icon for the 'download' button, default is "download".
1994
+ send_label (str): Label for the 'send' button. Default is "Send".
1995
+ send_icon (str): Fontawesome icon for the 'send' button. Default is "envelope".
1961
1996
  zip_label (Optional[str]): Label for the zip option. If not provided, uses the generic template for `self.zip_label` ("Download all").
1962
1997
  zip_icon (str): Icon for the zip option, default is "file-archive".
1998
+ zip_row_label (str, optional): Text to go in the left-most column
1999
+ of the table's zip row. Will default to the value of `self.title`.
1963
2000
  append_matching_suffix (bool): Flag to determine if matching suffix should be appended to file name, default is True.
1964
- include_email (bool): Flag to include an email option, default is False.
2001
+ include_email (bool): Flag to include an option, default is False.
1965
2002
  use_previously_cached_files (bool): Flag to use previously cached files (e.g., made in background) if defined. default is False.
1966
2003
  include_full_pdf (bool): Flag to include a full PDF option, default is False.
1967
2004
  full_pdf_label (Optional[str]): Label for the full PDF option. If not provided, uses the generic template for `self.full_pdf_label` ("Download all").
@@ -2052,7 +2089,10 @@ class ALDocumentBundle(DAList):
2052
2089
  size="md",
2053
2090
  classname="al_zip al_button",
2054
2091
  )
2055
- html += table_row(zip_label, zip_button)
2092
+ safe_zip_row_label: str = (
2093
+ zip_row_label or (hasattr(self, "title") and self.title) or zip_label
2094
+ )
2095
+ html += table_row(safe_zip_row_label, zip_button)
2056
2096
 
2057
2097
  if include_full_pdf and bundled_pdf:
2058
2098
  if not full_pdf_label:
@@ -2071,7 +2111,9 @@ class ALDocumentBundle(DAList):
2071
2111
  html += table_row(full_pdf_label, full_pdf_button)
2072
2112
 
2073
2113
  if include_email:
2074
- html += self.send_email_table_row(key=key)
2114
+ html += self.send_email_table_row(
2115
+ key=key, send_label=send_label, send_icon=send_icon
2116
+ )
2075
2117
 
2076
2118
  html += "\n</div>"
2077
2119
 
@@ -2150,13 +2192,17 @@ class ALDocumentBundle(DAList):
2150
2192
 
2151
2193
  return html
2152
2194
 
2153
- def send_email_table_row(self, key: str = "final") -> str:
2195
+ def send_email_table_row(
2196
+ self, key: str = "final", send_label: str = "Send", send_icon: str = "envelope"
2197
+ ) -> str:
2154
2198
  """
2155
2199
  Generate HTML doc table row for an input box and button that allows
2156
2200
  someone to send the bundle to the specified email address.
2157
2201
 
2158
2202
  Args:
2159
2203
  key (str): A key used to identify which version of the ALDocument to send. Defaults to "final".
2204
+ send_label (str): Label for the 'send' button. Default is "Send".
2205
+ send_icon (str): Icon for the 'send' button. Default is "envelope".
2160
2206
 
2161
2207
  Returns:
2162
2208
  str: The generated HTML string for the table row.
@@ -2189,7 +2235,7 @@ class ALDocumentBundle(DAList):
2189
2235
  """
2190
2236
 
2191
2237
  # "Send" button for the 2nd column of the table row
2192
- send_button = f'{action_button_html(javascript_string, label="Send", icon="envelope", color="primary", size="md", classname="al_send_email_button al_button", id_tag=al_send_button_id)}'
2238
+ send_button = f'{action_button_html(javascript_string, label=send_label, icon=send_icon, color="primary", size="md", classname="al_send_email_button al_button", id_tag=al_send_button_id)}'
2193
2239
 
2194
2240
  # Whole row put together
2195
2241
  html = f"""
@@ -2261,6 +2307,8 @@ class ALDocumentBundle(DAList):
2261
2307
  key: str = "final",
2262
2308
  show_editable_checkbox: bool = True,
2263
2309
  template_name: str = "",
2310
+ label: str = "Send",
2311
+ icon: str = "envelope",
2264
2312
  ) -> str:
2265
2313
  """
2266
2314
  Generate HTML for an input box and button that allows someone to send the bundle
@@ -2276,6 +2324,9 @@ class ALDocumentBundle(DAList):
2276
2324
  Defaults to True.
2277
2325
  template_name (str, optional): Name of the template variable that is used to fill
2278
2326
  the email contents. By default, the `x.send_email_template` template will be used.
2327
+ label (str, optional): The label for the button. Defaults to "Send".
2328
+ icon (str, optional): The Fontawesome icon for the button. Defaults
2329
+ to "envelope".
2279
2330
 
2280
2331
  Returns:
2281
2332
  str: The generated HTML string for the input box and button.
@@ -2327,7 +2378,7 @@ class ALDocumentBundle(DAList):
2327
2378
  <input value="{user_info().email if user_logged_in() else ''}" alt="Email address for document" class="form-control" type="email" size="35" name="{al_email_input_id}" id="{al_email_input_id}">
2328
2379
  </span>
2329
2380
 
2330
- {action_button_html(javascript_string, label="Send", icon="envelope", color="primary", size="md", classname="al_send_email_button", id_tag=al_send_button_id)}
2381
+ {action_button_html(javascript_string, label=label, icon=icon, color="primary", size="md", classname="al_send_email_button", id_tag=al_send_button_id)}
2331
2382
 
2332
2383
  </div>
2333
2384
  """
@@ -2496,7 +2547,13 @@ class ALExhibit(DAObject):
2496
2547
  starting_page (int): first page number to use in table of contents
2497
2548
  """
2498
2549
 
2499
- def init(self, *pargs, **kwargs):
2550
+ def init(self, *pargs, **kwargs) -> None:
2551
+ """Standard DAObject init method.
2552
+
2553
+ Args:
2554
+ *pargs: Positional arguments
2555
+ **kwargs: Keyword arguments
2556
+ """
2500
2557
  super().init(*pargs, **kwargs)
2501
2558
  self.initializeAttribute("_cache", DALazyAttribute)
2502
2559
  self.object_type = DAFileList
@@ -2716,7 +2773,13 @@ class ALExhibitList(DAList):
2716
2773
  auto_ocr (bool): If True, automatically starts OCR processing for uploaded exhibits. Defaults to True.
2717
2774
  """
2718
2775
 
2719
- def init(self, *pargs, **kwargs):
2776
+ def init(self, *pargs, **kwargs) -> None:
2777
+ """Standard DAObject init method.
2778
+
2779
+ Args:
2780
+ *pargs: Positional arguments
2781
+ **kwargs: Keyword arguments
2782
+ """
2720
2783
  super().init(*pargs, **kwargs)
2721
2784
  if not hasattr(self, "auto_label"):
2722
2785
  self.auto_label = True
@@ -2894,7 +2957,25 @@ class ALExhibitDocument(ALDocument):
2894
2957
  ```
2895
2958
  """
2896
2959
 
2897
- def init(self, *pargs, **kwargs):
2960
+ include_exhibit_cover_pages: bool
2961
+ include_table_of_contents: bool
2962
+ add_page_numbers: bool
2963
+ has_addendum: bool
2964
+ auto_labeler: Callable
2965
+ auto_ocr: bool
2966
+ bates_prefix: str
2967
+ maximum_size: int
2968
+ suffix_to_append: str
2969
+ exhibits: ALExhibitList
2970
+ table_of_contents: DAFile
2971
+
2972
+ def init(self, *pargs, **kwargs) -> None:
2973
+ """Standard DAObject init method.
2974
+
2975
+ Args:
2976
+ *pargs: Positional arguments
2977
+ **kwargs: Keyword arguments
2978
+ """
2898
2979
  super().init(*pargs, **kwargs)
2899
2980
  self.initializeAttribute("exhibits", ALExhibitList)
2900
2981
  if hasattr(self, "auto_labeler"):
@@ -3045,7 +3126,13 @@ class ALTableDocument(ALDocument):
3045
3126
  table (???): Represents the actual table data. Type and attributes need more context to document.
3046
3127
  """
3047
3128
 
3048
- def init(self, *pargs, **kwargs):
3129
+ def init(self, *pargs, **kwargs) -> None:
3130
+ """Standard DAObject init method.
3131
+
3132
+ Args:
3133
+ *pargs: Positional arguments
3134
+ **kwargs: Keyword arguments
3135
+ """
3049
3136
  super().init(*pargs, **kwargs)
3050
3137
  self.has_addendum = False
3051
3138
  if not hasattr(self, "suffix_to_append"):
@@ -3156,7 +3243,13 @@ class ALUntransformedDocument(ALDocument):
3156
3243
  suffix_to_append (str): Suffix that can be appended to file names, defaulting to "preview".
3157
3244
  """
3158
3245
 
3159
- def init(self, *pargs, **kwargs):
3246
+ def init(self, *pargs, **kwargs) -> None:
3247
+ """Standard DAObject init method.
3248
+
3249
+ Args:
3250
+ *pargs: Positional arguments
3251
+ **kwargs: Keyword arguments
3252
+ """
3160
3253
  super().init(*pargs, **kwargs)
3161
3254
  self.has_addendum = False
3162
3255
  if not hasattr(self, "suffix_to_append"):
@@ -293,7 +293,8 @@ class ALAddress(Address):
293
293
  True, the function will not add 'Unit' regardless of other conditions. Defaults to False.
294
294
 
295
295
  Returns:
296
- str: The formatted unit. If the unit attribute does not exist and require is set to False, this will be an
296
+ str:
297
+ The formatted unit. If the unit attribute does not exist and require is set to False, this will be an
297
298
  empty string. If the unit attribute exists and is not None or an empty string, the function will return
298
299
  the unit number, possibly prefixed with 'Unit'. If the unit attribute exists and is None or an empty
299
300
  string, the function will return an empty string.
@@ -627,7 +628,8 @@ class ALAddress(Address):
627
628
  Warning: currently the normalized address will not be redacted if the address is impounded.
628
629
 
629
630
  Returns:
630
- Union[Address, "ALAddress"]: Normalized address if geocoding is successful, otherwise
631
+ Union[Address, "ALAddress"]:
632
+ Normalized address if geocoding is successful, otherwise
631
633
  the original address.
632
634
  """
633
635
  try:
@@ -680,7 +682,13 @@ class ALAddressList(DAList):
680
682
  of the list in a formatted manner.
681
683
  """
682
684
 
683
- def init(self, *pargs, **kwargs):
685
+ def init(self, *pargs, **kwargs) -> None:
686
+ """Standard DAObject init method.
687
+
688
+ Args:
689
+ *pargs: Positional arguments
690
+ **kwargs: Keyword arguments
691
+ """
684
692
  super(ALAddressList, self).init(*pargs, **kwargs)
685
693
  self.object_type = ALAddress
686
694
 
@@ -702,7 +710,13 @@ class ALNameList(DAList):
702
710
  Extends the DAList class and is tailored for IndividualName objects.
703
711
  """
704
712
 
705
- def init(self, *pargs, **kwargs):
713
+ def init(self, *pargs, **kwargs) -> None:
714
+ """Standard DAObject init method.
715
+
716
+ Args:
717
+ *pargs: Positional arguments
718
+ **kwargs: Keyword arguments
719
+ """
706
720
  super().init(*pargs, **kwargs)
707
721
  self.object_type = IndividualName
708
722
 
@@ -720,7 +734,13 @@ class ALPeopleList(DAList):
720
734
 
721
735
  For example, defendants, plaintiffs, or children."""
722
736
 
723
- def init(self, *pargs, **kwargs):
737
+ def init(self, *pargs, **kwargs) -> None:
738
+ """Standard DAObject init method.
739
+
740
+ Args:
741
+ *pargs: Positional arguments
742
+ **kwargs: Keyword arguments
743
+ """
724
744
  super(ALPeopleList, self).init(*pargs, **kwargs)
725
745
  self.object_type = ALIndividual
726
746
 
@@ -874,7 +894,13 @@ class ALIndividual(Individual):
874
894
  aliases: ALNameList
875
895
  preferred_name: IndividualName
876
896
 
877
- def init(self, *pargs, **kwargs):
897
+ def init(self, *pargs, **kwargs) -> None:
898
+ """Standard DAObject init method.
899
+
900
+ Args:
901
+ *pargs: Positional arguments
902
+ **kwargs: Keyword arguments
903
+ """
878
904
  super(ALIndividual, self).init(*pargs, **kwargs)
879
905
  # Initialize the attributes that are themselves objects. Requirement to work with Docassemble
880
906
  # See: https://docassemble.org/docs/objects.html#ownclassattributes
@@ -2068,7 +2094,14 @@ class ALIndividual(Individual):
2068
2094
  return f"{self.name.first} {self.name.middle}"
2069
2095
  return self.name.first
2070
2096
 
2071
- first_and_last_candidates = [person.name.firstlast() for person in unique_names]
2097
+ first_and_last_candidates = [
2098
+ (
2099
+ person.name.firstlast()
2100
+ if hasattr(person.name, "last")
2101
+ else person.name.first
2102
+ )
2103
+ for person in unique_names
2104
+ ]
2072
2105
  if self.name_short() not in first_and_last_candidates:
2073
2106
  return self.name_short()
2074
2107
 
@@ -2425,7 +2458,7 @@ def parse_custom_pronouns(pronouns: str) -> Dict[str, str]:
2425
2458
 
2426
2459
 
2427
2460
  def get_visible_al_nav_items(
2428
- nav_items: List[Union[str, dict]]
2461
+ nav_items: List[Union[str, dict]],
2429
2462
  ) -> List[Union[str, dict]]:
2430
2463
  """
2431
2464
  Processes a list of nav items and returns only the ones that are not hidden.
@@ -0,0 +1,123 @@
1
+ # pre-load
2
+
3
+ # Because this has the pre-load preamble, this code runs automatically each time the
4
+ # server reloads. you do not need to import this module in your code.
5
+
6
+ # See: https://docassemble.org/docs/documents.html#register_jinja_filter
7
+
8
+ from typing import Any
9
+ from docassemble.base.util import register_jinja_filter, DACatchAll
10
+
11
+
12
+ def catchall_options(value: Any, *raw_items: Any) -> DACatchAll:
13
+ """Jinja2 filter to support defining options for DACatchAll fields inside a DOCX template.
14
+
15
+ This filter takes a list of items, which can be strings, dictionaries, or tuples,
16
+ and converts them into a list of tuples containing the code and label for each option.
17
+
18
+ The items can be in various formats:
19
+
20
+ - String: `"code: label"`
21
+ - Dictionary: `{"code": "label"}`
22
+ - Tuple: `("code", "label")`
23
+ - List of any of the above types
24
+
25
+ The resulting list of tuples is assigned to the `_catchall_options` attribute of the
26
+ DACatchAll object, which can then be used to populate the options in the catchall field.
27
+
28
+ Example usage in a DOCX template:
29
+
30
+ ```
31
+ {{ my_catchall_field | catchall_options("code1: label1", "code2: label2") }}
32
+
33
+ {{ my_catchall_field_2 | catchall_options({"code1": "label1"}, {"code2": "label2"}) }}
34
+ ```
35
+
36
+ Example in an interview with `features: use catchall: True` turned on:
37
+
38
+ ```
39
+ ---
40
+ if: |
41
+ hasattr(x, "_catchall_options")
42
+ generic object: DACatchAll
43
+ question: |
44
+ ${ x.object_name() }?
45
+ fields:
46
+ - ${ x.object_name() }: x.value
47
+ code: x._catchall_options
48
+ ```
49
+
50
+ Args:
51
+ value (DACatchAll): The DACatchAll object to which the options will be assigned.
52
+ *raw_items: A variable number of arguments representing the options to be added.
53
+ Returns:
54
+ DACatchAll: The modified DACatchAll object with the assigned options.
55
+ """
56
+ if isinstance(value, DACatchAll):
57
+ pairs = []
58
+ for item in raw_items:
59
+ if isinstance(item, str):
60
+ if ":" in item:
61
+ code, label = item.split(":", 1)
62
+ else:
63
+ code = label = item
64
+ pairs.append((code.strip(), label.strip()))
65
+ elif isinstance(item, dict):
66
+ for code, label in item.items():
67
+ pairs.append((code.strip(), label.strip()))
68
+ elif isinstance(item, tuple) and len(item) == 2:
69
+ code, label = item
70
+ pairs.append((code.strip(), label.strip()))
71
+ elif isinstance(item, list):
72
+ for subitem in item:
73
+ if isinstance(subitem, str):
74
+ if ":" in subitem:
75
+ code, label = subitem.split(":", 1)
76
+ else:
77
+ code = label = subitem
78
+ pairs.append((code.strip(), label.strip()))
79
+ elif isinstance(subitem, dict):
80
+ for code, label in subitem.items():
81
+ pairs.append((code.strip(), label.strip()))
82
+ elif isinstance(subitem, tuple) and len(subitem) == 2:
83
+ code, label = subitem
84
+ pairs.append((code.strip(), label.strip()))
85
+ value._catchall_options = pairs
86
+ return value
87
+
88
+
89
+ def catchall_label(value: Any, label: str) -> DACatchAll:
90
+ """Jinja2 filter to allow you to define a label for a DACatchAll field inside a DOCX template.
91
+
92
+ This filter takes a label string and assigns it to the `label` attribute of the
93
+ DACatchAll object. This label can be used to provide a more descriptive name for the
94
+ catchall field in the user interface.
95
+
96
+ Example usage in a DOCX template:
97
+ ```
98
+ {{ my_catchall_field | catchall_label("My Custom Label") }}
99
+ ```
100
+ Example in an interview with `features: use catchall: True` turned on:
101
+ ```
102
+ ---
103
+ generic object: DACatchAll
104
+ question: |
105
+ ${ x.label if hasattr(x, "label") else x.object_name() }?
106
+ fields:
107
+ - ${ x.label if hasattr(x, "label") else x.object_name() }: x.value
108
+ ```
109
+ Args:
110
+ value (DACatchAll): The DACatchAll object to which the label will be assigned.
111
+ label (str): The label string to assign to the DACatchAll object.
112
+
113
+ Returns:
114
+ DACatchAll: The modified DACatchAll object with the assigned label.
115
+
116
+ """
117
+ if isinstance(value, DACatchAll):
118
+ value.label = label
119
+ return value
120
+
121
+
122
+ register_jinja_filter("catchall_options", catchall_options)
123
+ register_jinja_filter("catchall_label", catchall_label)