docassemble.AssemblyLine 4.2.0__tar.gz → 4.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 (105) hide show
  1. {docassemble_assemblyline-4.2.0/docassemble.AssemblyLine.egg-info → docassemble_assemblyline-4.4.0}/PKG-INFO +9 -11
  2. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/README.md +2 -1
  3. docassemble_assemblyline-4.4.0/docassemble/AssemblyLine/__init__.py +1 -0
  4. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/al_courts.py +1 -3
  5. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/al_document.py +52 -33
  6. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/al_general.py +37 -27
  7. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/custom_jinja_filters.py +50 -5
  8. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/al_code.yml +67 -30
  9. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/al_document.yml +62 -39
  10. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/al_language.yml +5 -4
  11. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/al_question_test.yml +7 -7
  12. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/al_reminders.yml +51 -19
  13. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/al_saved_sessions.yml +22 -15
  14. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/al_saved_sessions_store.yml +5 -1
  15. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/al_settings.yml +20 -14
  16. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/al_visual.yml +47 -22
  17. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/demo_search_sessions.yml +11 -5
  18. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/feedback.yml +1 -2
  19. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/interview_list.yml +57 -43
  20. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/ql_baseline.yml +120 -43
  21. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/ql_catchall.yml +1 -1
  22. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/ql_namechange.yml +1 -1
  23. docassemble_assemblyline-4.4.0/docassemble/AssemblyLine/data/questions/reserved_words.yml +94 -0
  24. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/test_alcourts.yml +5 -5
  25. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/test_aldocument.yml +7 -4
  26. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/test_aldocument_background_assembly.yml +1 -1
  27. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/test_alexhibit_maxsize.yml +1 -1
  28. docassemble_assemblyline-4.4.0/docassemble/AssemblyLine/data/questions/test_preferred_name.yml +132 -0
  29. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/test_question_library.yml +15 -9
  30. docassemble_assemblyline-4.4.0/docassemble/AssemblyLine/data/sources/ar-words.yml +753 -0
  31. docassemble_assemblyline-4.4.0/docassemble/AssemblyLine/data/sources/es-words.yml +863 -0
  32. docassemble_assemblyline-4.4.0/docassemble/AssemblyLine/data/sources/fr-words.yml +878 -0
  33. docassemble_assemblyline-4.4.0/docassemble/AssemblyLine/data/sources/ne-words.yml +841 -0
  34. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/sessions.py +73 -81
  35. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/test_al_document.py +2 -0
  36. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/test_al_general.py +132 -2
  37. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/test_language.py +2 -0
  38. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0/docassemble.AssemblyLine.egg-info}/PKG-INFO +9 -11
  39. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble.AssemblyLine.egg-info/SOURCES.txt +4 -1
  40. docassemble_assemblyline-4.4.0/docassemble.AssemblyLine.egg-info/requires.txt +2 -0
  41. docassemble_assemblyline-4.4.0/pyproject.toml +64 -0
  42. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/setup.py +2 -2
  43. docassemble_assemblyline-4.2.0/docassemble/AssemblyLine/__init__.py +0 -1
  44. docassemble_assemblyline-4.2.0/docassemble/AssemblyLine/data/questions/reserved_words.yml +0 -92
  45. docassemble_assemblyline-4.2.0/docassemble/AssemblyLine/data/sources/es-words.yml +0 -687
  46. docassemble_assemblyline-4.2.0/docassemble/__init__.py +0 -1
  47. docassemble_assemblyline-4.2.0/docassemble.AssemblyLine.egg-info/requires.txt +0 -2
  48. docassemble_assemblyline-4.2.0/pyproject.toml +0 -30
  49. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/LICENSE +0 -0
  50. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/MANIFEST.in +0 -0
  51. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/al_package.yml +0 -0
  52. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/al_package_unstyled.yml +0 -0
  53. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/al_terms_of_use.yml +0 -0
  54. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/assembly_line.yml +0 -0
  55. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/assembly_line_unstyled.yml +0 -0
  56. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/test_al_table_document.yml +0 -0
  57. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/test_aladdendum.yml +0 -0
  58. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/test_alexhibit.yml +0 -0
  59. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/test_bundle_parity.yml +0 -0
  60. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/test_catchall.yml +0 -0
  61. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/test_familiar_disambiguation.yml +0 -0
  62. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/test_if_final.yml +0 -0
  63. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/test_preferred_formats.yml +0 -0
  64. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/questions/test_signature.yml +0 -0
  65. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/sources/README.md +0 -0
  66. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/sources/languages.yml +0 -0
  67. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/sources/test_aldocument.feature +0 -0
  68. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_docx_1.docx +0 -0
  69. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_jpg_1.jpg +0 -0
  70. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_pdf_1.pdf +0 -0
  71. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_png_1.png +0 -0
  72. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/sources/test_question_library.feature +0 -0
  73. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/sources/translation_es.xlsx +0 -0
  74. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/sources/translation_ht.xlsx +0 -0
  75. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/sources/translation_pt.xlsx +0 -0
  76. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/static/README.md +0 -0
  77. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/static/al_audio.css +0 -0
  78. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/static/al_audio.js +0 -0
  79. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/static/aldocument.css +0 -0
  80. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/static/aldocument.js +0 -0
  81. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/static/interview_list.css +0 -0
  82. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/static/limit_upload_size.js +0 -0
  83. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/static/lt1-pullout-10-getting-organized.pdf +0 -0
  84. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/static/ma_logo.png +0 -0
  85. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/static/placeholder.png +0 -0
  86. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/static/seal.jpg +0 -0
  87. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/static/styles.css +0 -0
  88. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/templates/README.md +0 -0
  89. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/templates/al_basic_addendum.docx +0 -0
  90. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/templates/exhibit_cover_sheet.docx +0 -0
  91. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/templates/exhibit_table_of_contents.docx +0 -0
  92. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/templates/general_cover_sheet.docx +0 -0
  93. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/templates/sample_word_template.docx +0 -0
  94. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/templates/test_aldocument_docx_1.docx +0 -0
  95. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/templates/test_aldocument_pdf_1.pdf +0 -0
  96. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/templates/test_catchall.docx +0 -0
  97. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/data/templates/test_if_final.docx +0 -0
  98. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/language.py +0 -0
  99. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/py.typed +0 -0
  100. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/requirements.txt +0 -0
  101. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble/AssemblyLine/sign.py +0 -0
  102. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble.AssemblyLine.egg-info/dependency_links.txt +0 -0
  103. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble.AssemblyLine.egg-info/not-zip-safe +0 -0
  104. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/docassemble.AssemblyLine.egg-info/top_level.txt +0 -0
  105. {docassemble_assemblyline-4.2.0 → docassemble_assemblyline-4.4.0}/setup.cfg +0 -0
@@ -1,22 +1,19 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: docassemble.AssemblyLine
3
- Version: 4.2.0
3
+ Version: 4.4.0
4
+ Summary: Quickly go from a paper court form to a runnable, guided, step-by-step web application powered by Docassemble. Swap out branding and pre-built questions to meet your needs.
4
5
  Home-page: https://courtformsonline.org
5
6
  Author: Suffolk Legal Innovation and Technology Lab
6
- Author-email: qsteenhuis@suffolk.edu
7
- License: The MIT License (MIT)
7
+ Author-email: Suffolk Legal Innovation and Technology Lab <litlab@suffolk.edu>
8
+ License-Expression: MIT
9
+ Project-URL: Homepage, https://courtformsonline.org
8
10
  Description-Content-Type: text/markdown
9
11
  License-File: LICENSE
10
- Requires-Dist: docassemble.ALToolbox>=0.12.0
11
- Requires-Dist: docassemble.GithubFeedbackForm>=0.4.1.1
12
+ Requires-Dist: docassemble.ALToolbox>=0.16.0
13
+ Requires-Dist: docassemble.GitHubFeedbackForm>=0.4.1.1
12
14
  Dynamic: author
13
- Dynamic: author-email
14
- Dynamic: description
15
- Dynamic: description-content-type
16
15
  Dynamic: home-page
17
- Dynamic: license
18
16
  Dynamic: license-file
19
- Dynamic: requires-dist
20
17
 
21
18
  # Suffolk LIT Lab Document Assembly Line
22
19
 
@@ -55,7 +52,7 @@ https://suffolklitlab.org/docassemble-AssemblyLine-documentation/
55
52
 
56
53
  ## Menu-driven installation
57
54
 
58
- The recommended installation method is with the [guided installation script](https://suffolklitlab.org/docassemble-AssemblyLine-documentation/docs/installation).
55
+ The recommended installation method is with the [guided installation script](https://assemblyline.suffolklitlab.org/docs/get_started/installation).
59
56
 
60
57
  ## Manual installation
61
58
 
@@ -155,3 +152,4 @@ code: |
155
152
  # Changelog
156
153
 
157
154
  See [CHANGELOG.MD](https://github.com/SuffolkLITLab/docassemble-AssemblyLine/blob/main/CHANGELOG.md)
155
+
@@ -35,7 +35,7 @@ https://suffolklitlab.org/docassemble-AssemblyLine-documentation/
35
35
 
36
36
  ## Menu-driven installation
37
37
 
38
- The recommended installation method is with the [guided installation script](https://suffolklitlab.org/docassemble-AssemblyLine-documentation/docs/installation).
38
+ The recommended installation method is with the [guided installation script](https://assemblyline.suffolklitlab.org/docs/get_started/installation).
39
39
 
40
40
  ## Manual installation
41
41
 
@@ -135,3 +135,4 @@ code: |
135
135
  # Changelog
136
136
 
137
137
  See [CHANGELOG.MD](https://github.com/SuffolkLITLab/docassemble-AssemblyLine/blob/main/CHANGELOG.md)
138
+
@@ -0,0 +1 @@
1
+ __version__ = '4.4.0'
@@ -2,13 +2,11 @@
2
2
  Package for a very simple / MVP list of courts that is mostly signature compatible w/ MACourts for now
3
3
  """
4
4
 
5
- import os
6
- from typing import Any, Callable, Dict, List, Mapping, Optional, Union, Set, Tuple
5
+ from typing import Any, Callable, Dict, List, Optional, Union, Set, Tuple
7
6
  import pandas as pd
8
7
  import docassemble.base.functions
9
8
  from docassemble.base.util import (
10
9
  path_and_mimetype,
11
- Address,
12
10
  LatitudeLongitude,
13
11
  DAObject,
14
12
  log,
@@ -12,6 +12,7 @@ from docassemble.base.util import (
12
12
  DAFile,
13
13
  DAFileCollection,
14
14
  DAFileList,
15
+ DALazyTemplate,
15
16
  defined,
16
17
  pdf_concatenate,
17
18
  zip_file,
@@ -28,18 +29,17 @@ from docassemble.base.util import (
28
29
  DAStaticFile,
29
30
  alpha,
30
31
  showifdef,
32
+ word,
31
33
  )
32
34
  from docassemble.base.pdfa import pdf_to_pdfa
33
35
  from textwrap import wrap
34
36
  from math import floor
35
37
  import subprocess
36
- from collections import ChainMap
37
38
  import pikepdf
38
39
  from typing import Tuple
39
40
  import secrets
40
41
  import string
41
42
 
42
-
43
43
  __all__ = [
44
44
  "ALAddendumField",
45
45
  "ALAddendumFieldDict",
@@ -315,6 +315,9 @@ class ALAddendumField(DAObject):
315
315
 
316
316
  # If trigger is not a boolean value, overflow value is the value that starts at the end of the safe value.
317
317
  original_value = self.value_if_defined()
318
+ # Ensure a DALazyTemplate is rendered to a string for downstream string ops
319
+ if isinstance(original_value, DALazyTemplate):
320
+ original_value = str(original_value)
318
321
  safe_text = self.safe_value(
319
322
  overflow_message=overflow_message,
320
323
  input_width=input_width,
@@ -409,6 +412,9 @@ class ALAddendumField(DAObject):
409
412
  val = _original_value
410
413
  else:
411
414
  val = self.value_if_defined()
415
+ # If this is a template block, render it now so comparisons work correctly
416
+ if isinstance(val, DALazyTemplate):
417
+ val = str(val)
412
418
 
413
419
  return (
414
420
  self.safe_value(
@@ -508,6 +514,11 @@ class ALAddendumField(DAObject):
508
514
  value = _original_value
509
515
  else:
510
516
  value = self.value_if_defined()
517
+
518
+ # Convert template blocks to strings for purposes of evaluating overflow
519
+ if isinstance(value, DALazyTemplate):
520
+ value = str(value)
521
+
511
522
  if (
512
523
  isinstance(value, str)
513
524
  and len(value) <= self.overflow_trigger
@@ -1996,11 +2007,11 @@ class ALDocumentBundle(DAList):
1996
2007
  refresh: bool = True,
1997
2008
  pdfa: bool = False,
1998
2009
  include_zip: bool = True,
1999
- view_label="View",
2010
+ view_label: Optional[str] = None,
2000
2011
  view_icon: str = "eye",
2001
- download_label: str = "Download",
2012
+ download_label: Optional[str] = None,
2002
2013
  download_icon: str = "download",
2003
- send_label: str = "Send",
2014
+ send_label: Optional[str] = None,
2004
2015
  send_icon: str = "envelope",
2005
2016
  zip_label: Optional[str] = None,
2006
2017
  zip_icon: str = "file-archive",
@@ -2023,11 +2034,11 @@ class ALDocumentBundle(DAList):
2023
2034
  refresh (bool): Flag to reconsider the 'enabled' attribute, default is True.
2024
2035
  pdfa (bool): Flag to return documents in PDF/A format, default is False.
2025
2036
  include_zip (bool): Flag to include a zip option, default is True.
2026
- view_label (str): Label for the 'view' button, default is "View".
2037
+ view_label (str): Label for the 'view' button, default is self.view_label or "View".
2027
2038
  view_icon (str): Icon for the 'view' button, default is "eye".
2028
- download_label (str): Label for the 'download' button, default is "Download".
2039
+ download_label (str): Label for the 'download' button, default is self.download_label or "Download".
2029
2040
  download_icon (str): Icon for the 'download' button, default is "download".
2030
- send_label (str): Label for the 'send' button. Default is "Send".
2041
+ send_label (str): Label for the 'send' button. Default is self.send_label or "Send".
2031
2042
  send_icon (str): Fontawesome icon for the 'send' button. Default is "envelope".
2032
2043
  zip_label (Optional[str]): Label for the zip option. If not provided, uses the generic template for `self.zip_label` ("Download all").
2033
2044
  zip_icon (str): Icon for the zip option, default is "file-archive".
@@ -2044,11 +2055,14 @@ class ALDocumentBundle(DAList):
2044
2055
  Returns:
2045
2056
  str: HTML representation of a table with documents and their associated actions.
2046
2057
  """
2047
- if not hasattr(self, "_cached_zip_label"):
2048
- self._cached_zip_label = str(self.zip_label)
2058
+ if not view_label:
2059
+ view_label = str(self.view_label) or word("View")
2049
2060
 
2050
- if not hasattr(self, "_cached_full_pdf_label"):
2051
- self._cached_full_pdf_label = str(self.full_pdf_label)
2061
+ if not download_label:
2062
+ download_label = str(self.download_label) or word("Download")
2063
+
2064
+ if not send_label:
2065
+ send_label = str(self.send_label) or word("Send")
2052
2066
 
2053
2067
  if zip_format is None:
2054
2068
  zip_format = format
@@ -2123,7 +2137,7 @@ class ALDocumentBundle(DAList):
2123
2137
  # Add a zip file row if included
2124
2138
  if include_zip and bundled_zip:
2125
2139
  if not zip_label:
2126
- zip_label = self._cached_zip_label
2140
+ zip_label = str(self.zip_label)
2127
2141
  filename_root = os.path.splitext(str(self.filename))[0]
2128
2142
  zip_button = action_button_html(
2129
2143
  bundled_zip.url_for(
@@ -2142,7 +2156,7 @@ class ALDocumentBundle(DAList):
2142
2156
 
2143
2157
  if include_full_pdf and bundled_pdf:
2144
2158
  if not full_pdf_label:
2145
- full_pdf_label = self._cached_full_pdf_label
2159
+ full_pdf_label = str(self.full_pdf_label)
2146
2160
  filename_root = os.path.splitext(str(self.filename))[0]
2147
2161
  full_pdf_button = action_button_html(
2148
2162
  bundled_pdf.url_for(
@@ -2239,12 +2253,17 @@ class ALDocumentBundle(DAList):
2239
2253
  return html
2240
2254
 
2241
2255
  def send_email_table_row(
2242
- self, key: str = "final", send_label: str = "Send", send_icon: str = "envelope"
2256
+ self,
2257
+ key: str = "final",
2258
+ send_label: Optional[str] = None,
2259
+ send_icon: str = "envelope",
2243
2260
  ) -> str:
2244
2261
  """
2245
2262
  Generate HTML doc table row for an input box and button that allows
2246
2263
  someone to send the bundle to the specified email address.
2247
2264
 
2265
+ This should normally only be called by download_list_html.
2266
+
2248
2267
  Args:
2249
2268
  key (str): A key used to identify which version of the ALDocument to send. Defaults to "final".
2250
2269
  send_label (str): Label for the 'send' button. Default is "Send".
@@ -2253,14 +2272,12 @@ class ALDocumentBundle(DAList):
2253
2272
  Returns:
2254
2273
  str: The generated HTML string for the table row.
2255
2274
  """
2275
+ if not send_label:
2276
+ send_label = str(self.send_label) or word("Send")
2277
+
2256
2278
  if not self.has_enabled_documents():
2257
2279
  return "" # Don't let people email an empty set of documents
2258
- if not hasattr(self, "_cached_get_email_copy"):
2259
- self._cached_get_email_copy = str(self.get_email_copy)
2260
- if not hasattr(self, "_cached_include_editable_documents"):
2261
- self._cached_include_editable_documents = str(
2262
- self.include_editable_documents
2263
- )
2280
+
2264
2281
  name = html_safe_str(self.instanceName) + random_suffix()
2265
2282
  al_wants_editable_input_id = "_ignore_al_wants_editable_" + name
2266
2283
  al_email_input_id = "_ignore_al_doc_email_" + name
@@ -2298,7 +2315,7 @@ class ALDocumentBundle(DAList):
2298
2315
  email: str,
2299
2316
  editable: Optional[bool] = None,
2300
2317
  template_name: str = "",
2301
- label: str = "Send",
2318
+ label: Optional[str] = None,
2302
2319
  icon: str = "envelope",
2303
2320
  color: str = "primary",
2304
2321
  key: str = "final",
@@ -2322,10 +2339,11 @@ class ALDocumentBundle(DAList):
2322
2339
  Returns:
2323
2340
  str: The generated HTML string for the button.
2324
2341
  """
2342
+ if label is None:
2343
+ label = str(self.send_label) or word("Send")
2344
+
2325
2345
  if not self.has_enabled_documents():
2326
2346
  return "" # Don't let people email an empty set of documents
2327
- if not hasattr(self, "_cached_get_email_copy"):
2328
- self._cached_get_email_copy = str(self.get_email_copy)
2329
2347
  name = html_safe_str(self.instanceName) + random_suffix()
2330
2348
  al_send_button_id = "al_send_email_to_button_" + name
2331
2349
 
@@ -2392,12 +2410,6 @@ class ALDocumentBundle(DAList):
2392
2410
  """
2393
2411
  if not self.has_enabled_documents():
2394
2412
  return "" # Don't let people email an empty set of documents
2395
- if not hasattr(self, "_cached_get_email_copy"):
2396
- self._cached_get_email_copy = str(self.get_email_copy)
2397
- if not hasattr(self, "_cached_include_editable_documents"):
2398
- self._cached_include_editable_documents = str(
2399
- self.include_editable_documents
2400
- )
2401
2413
 
2402
2414
  if isinstance(preferred_formats, str):
2403
2415
  preferred_formats = [preferred_formats]
@@ -2431,7 +2443,7 @@ class ALDocumentBundle(DAList):
2431
2443
  # Container of whole email section with header
2432
2444
  return_str = f"""
2433
2445
  <fieldset class="al_send_bundle al_send_section_alone {html_safe_str(self.instanceName)}" id="al_send_bundle_{name}" name="al_send_bundle_{name}">
2434
- <legend class="h4 al_doc_email_header">{self._cached_get_email_copy}</legend>
2446
+ <legend class="h4 al_doc_email_header">{str(self.get_email_copy)}</legend>
2435
2447
  """
2436
2448
  # "Editable" checkbox
2437
2449
  if (
@@ -2444,7 +2456,7 @@ class ALDocumentBundle(DAList):
2444
2456
  <div class="form-check-container">
2445
2457
  <div class="form-check">
2446
2458
  <input class="form-check-input al_wants_editable" type="checkbox" id="{al_wants_editable_input_id}">
2447
- <label class="al_wants_editable form-check-label" for="{al_wants_editable_input_id}">{self._cached_include_editable_documents}
2459
+ <label class="al_wants_editable form-check-label" for="{al_wants_editable_input_id}">{str(self.include_editable_documents)}
2448
2460
  </label>
2449
2461
  </div>
2450
2462
  </div>
@@ -2863,10 +2875,11 @@ class ALExhibitList(DAList):
2863
2875
 
2864
2876
  Attributes:
2865
2877
  maximum_size (int): The maximum allowed size in bytes of the entire document.
2878
+ maximum_size_per_doc (int): The maximum allowed size in bytes per document in the list
2866
2879
  auto_label (bool): If True, automatically numbers exhibits for cover page and table of contents. Defaults to True.
2867
2880
  auto_labeler (Callable): An optional function or lambda to transform the exhibit's index to a label.
2868
2881
  Uses A..Z labels by default.
2869
- auto_ocr (bool): If True, automatically starts OCR processing for uploaded exhibits. Defaults to True.
2882
+ auto_ocr (bool): If True, automatically starts OCR processing for uploaded exhibits. Defaults to False.
2870
2883
  """
2871
2884
 
2872
2885
  def init(self, *pargs, **kwargs) -> None:
@@ -3061,6 +3074,7 @@ class ALExhibitDocument(ALDocument):
3061
3074
  auto_ocr: bool
3062
3075
  bates_prefix: str
3063
3076
  maximum_size: int
3077
+ maximum_size_per_doc: int
3064
3078
  suffix_to_append: str
3065
3079
  exhibits: ALExhibitList
3066
3080
  table_of_contents: DAFile
@@ -3085,8 +3099,13 @@ class ALExhibitDocument(ALDocument):
3085
3099
  else:
3086
3100
  self.include_exhibit_cover_pages = True
3087
3101
  self.exhibits.include_exhibit_cover_pages = True
3102
+ if hasattr(self, "maximum_size_per_doc"):
3103
+ self.exhibits.maximum_size_per_doc = self.maximum_size_per_doc
3088
3104
  if hasattr(self, "maximum_size"):
3089
3105
  self.exhibits.maximum_size = self.maximum_size
3106
+ if not hasattr(self, "maximum_size_per_doc"):
3107
+ self.maximum_size_per_doc = self.maximum_size
3108
+ self.exhibits.maximum_size_per_doc = self.maximum_size
3090
3109
  if hasattr(self, "include_table_of_contents"):
3091
3110
  self.exhibits.include_table_of_contents = self.include_table_of_contents
3092
3111
  else:
@@ -28,16 +28,14 @@ from docassemble.base.util import (
28
28
  states_list,
29
29
  subdivision_type,
30
30
  their,
31
- this_thread,
32
31
  url_action,
33
32
  validation_error,
34
- value,
35
33
  word,
36
34
  your,
37
35
  log,
38
36
  value,
39
37
  )
40
- from docassemble.ALToolbox.misc import fa_icon
38
+ import docassemble.base.functions
41
39
  import random
42
40
  import re
43
41
  import pycountry
@@ -325,7 +323,7 @@ class ALAddress(Address):
325
323
  if not bare and (
326
324
  unit_lower.isnumeric()
327
325
  or (
328
- not " " in self.unit
326
+ " " not in self.unit
329
327
  and not any(
330
328
  x in unit_lower
331
329
  for x in [
@@ -374,7 +372,7 @@ class ALAddress(Address):
374
372
  Returns:
375
373
  str: The one-line formatted address.
376
374
  """
377
- if this_thread.evaluation_context == "docx":
375
+ if docassemble.base.functions.this_thread.evaluation_context == "docx":
378
376
  line_breaker = '</w:t><w:br/><w:t xml:space="preserve">'
379
377
  else:
380
378
  line_breaker = " [NEWLINE] "
@@ -1660,10 +1658,13 @@ class ALIndividual(Individual):
1660
1658
  Used to assist with checkbox filling in PDFs with "skip undefined"
1661
1659
  turned on.
1662
1660
  """
1663
- return not (
1664
- self.gender
1665
- in ["prefer-not-to-say", "male", "female", "unknown", "nonbinary"]
1666
- )
1661
+ return self.gender not in [
1662
+ "prefer-not-to-say",
1663
+ "male",
1664
+ "female",
1665
+ "unknown",
1666
+ "nonbinary",
1667
+ ]
1667
1668
 
1668
1669
  def contact_fields(self) -> None:
1669
1670
  """
@@ -1701,7 +1702,7 @@ class ALIndividual(Individual):
1701
1702
  Returns:
1702
1703
  str: The formatted address block.
1703
1704
  """
1704
- if this_thread.evaluation_context == "docx":
1705
+ if docassemble.base.functions.this_thread.evaluation_context == "docx":
1705
1706
  if isinstance(self.address, ALAddress):
1706
1707
  return self.address.block(
1707
1708
  language=language,
@@ -1778,7 +1779,7 @@ class ALIndividual(Individual):
1778
1779
  else:
1779
1780
  pronouns = self.pronouns
1780
1781
 
1781
- if self == this_thread.global_vars.user:
1782
+ if self == docassemble.base.functions.this_thread.global_vars.user:
1782
1783
  output = word("you", **kwargs)
1783
1784
  elif hasattr(self, "pronouns") and self.pronouns:
1784
1785
  pronouns_to_use = []
@@ -1876,7 +1877,7 @@ class ALIndividual(Individual):
1876
1877
  else:
1877
1878
  default = self.name_full()
1878
1879
 
1879
- if self == this_thread.global_vars.user and (
1880
+ if self == docassemble.base.functions.this_thread.global_vars.user and (
1880
1881
  "thirdperson" not in kwargs or not kwargs["thirdperson"]
1881
1882
  ):
1882
1883
  output = your(target, **kwargs)
@@ -1963,7 +1964,7 @@ class ALIndividual(Individual):
1963
1964
  else:
1964
1965
  pronouns = self.pronouns
1965
1966
 
1966
- if self == this_thread.global_vars.user:
1967
+ if self == docassemble.base.functions.this_thread.global_vars.user:
1967
1968
  output = word("you", **kwargs)
1968
1969
  elif hasattr(self, "pronouns") and self.pronouns:
1969
1970
  pronouns_to_use = []
@@ -2042,7 +2043,7 @@ class ALIndividual(Individual):
2042
2043
  if person == "2p":
2043
2044
  return word("yourselves")
2044
2045
 
2045
- if self == this_thread.global_vars.user:
2046
+ if self == docassemble.base.functions.this_thread.global_vars.user:
2046
2047
  output = word("yourself", **kwargs)
2047
2048
 
2048
2049
  if "default" in kwargs:
@@ -2058,7 +2059,7 @@ class ALIndividual(Individual):
2058
2059
  else:
2059
2060
  pronouns = None
2060
2061
 
2061
- if self == this_thread.global_vars.user:
2062
+ if self == docassemble.base.functions.this_thread.global_vars.user:
2062
2063
  output = word("yourself", **kwargs)
2063
2064
  elif hasattr(self, "pronouns") and self.pronouns:
2064
2065
  pronouns_to_use = []
@@ -2188,10 +2189,10 @@ class ALIndividual(Individual):
2188
2189
 
2189
2190
  In order, it will try to use:
2190
2191
 
2191
- * just the first name
2192
- * the first name and suffix
2193
- * the first and middle name
2194
- * the first and last name
2192
+ * just the preferred name (if set) or first name
2193
+ * the preferred/first name and suffix
2194
+ * the preferred/first and middle name
2195
+ * the preferred/first and last name
2195
2196
  * the full name
2196
2197
  * the default value, e.g., "the minor", if provided
2197
2198
  * the full name
@@ -2221,33 +2222,42 @@ class ALIndividual(Individual):
2221
2222
  if unique_names is None:
2222
2223
  unique_names = []
2223
2224
 
2225
+ # Use preferred_name.first if it exists and is non-empty, otherwise use name.first
2226
+ first_name_to_use = self.name.first
2227
+ if (
2228
+ hasattr(self, "preferred_name")
2229
+ and hasattr(self.preferred_name, "first")
2230
+ and self.preferred_name.first
2231
+ ):
2232
+ first_name_to_use = self.preferred_name.first
2233
+
2224
2234
  first_name_candidates = [person.familiar() for person in unique_names]
2225
- if self.name.first not in first_name_candidates:
2226
- return self.name.first
2235
+ if first_name_to_use not in first_name_candidates:
2236
+ return first_name_to_use
2227
2237
 
2228
2238
  first_name_and_suffix_candidates = [
2229
2239
  f"{person.familiar()} {person.name.suffix if hasattr(person.name, 'suffix') else ''}"
2230
2240
  for person in unique_names
2231
2241
  ]
2232
2242
  if (
2233
- f"{self.name.first} {self.name.suffix if hasattr(self.name, 'suffix') else ''}"
2243
+ f"{first_name_to_use} {self.name.suffix if hasattr(self.name, 'suffix') else ''}"
2234
2244
  not in first_name_and_suffix_candidates
2235
2245
  ):
2236
2246
  if hasattr(self.name, "suffix") and self.name.suffix:
2237
- return f"{self.name.first} {self.name.suffix if hasattr(self.name, 'suffix') else ''}"
2238
- return self.name.first
2247
+ return f"{first_name_to_use} {self.name.suffix if hasattr(self.name, 'suffix') else ''}"
2248
+ return first_name_to_use
2239
2249
 
2240
2250
  first_and_middle_candidates = [
2241
2251
  f"{person.name.first} {person.name.middle if hasattr(person.name, 'middle') and person.name.middle else ''}"
2242
2252
  for person in unique_names
2243
2253
  ]
2244
2254
  if (
2245
- f"{self.name.first} {self.name.middle if hasattr(self.name, 'middle') and self.name.middle else ''}"
2255
+ f"{first_name_to_use} {self.name.middle if hasattr(self.name, 'middle') and self.name.middle else ''}"
2246
2256
  not in first_and_middle_candidates
2247
2257
  ):
2248
2258
  if hasattr(self.name, "middle") and self.name.middle:
2249
- return f"{self.name.first} {self.name.middle}"
2250
- return self.name.first
2259
+ return f"{first_name_to_use} {self.name.middle}"
2260
+ return first_name_to_use
2251
2261
 
2252
2262
  first_and_last_candidates = [
2253
2263
  (
@@ -5,9 +5,8 @@
5
5
 
6
6
  # See: https://docassemble.org/docs/documents.html#register_jinja_filter
7
7
 
8
- import re
9
8
  from typing import Any, Dict, List, Optional, Union
10
- from docassemble.base.util import register_jinja_filter, DACatchAll, word
9
+ from docassemble.base.util import register_jinja_filter, DACatchAll
11
10
  from jinja2 import Undefined, pass_context
12
11
  from jinja2.runtime import Context as Jinja2Context
13
12
 
@@ -18,6 +17,7 @@ __all__ = [
18
17
  "catchall_question",
19
18
  "catchall_subquestion",
20
19
  "catchall_fields_code",
20
+ "catchall_complete",
21
21
  ]
22
22
 
23
23
 
@@ -29,6 +29,7 @@ def catchall_options(value: Any, *raw_items: Any) -> DACatchAll:
29
29
 
30
30
  The items can be in various formats:
31
31
 
32
+ - String: `"code_is_the_label"`
32
33
  - String: `"code: label"`
33
34
  - Dictionary: `{"code": "label"}`
34
35
  - Tuple: `("code", "label")`
@@ -66,14 +67,14 @@ def catchall_options(value: Any, *raw_items: Any) -> DACatchAll:
66
67
  DACatchAll: The modified DACatchAll object with the assigned options.
67
68
  """
68
69
  if isinstance(value, DACatchAll):
69
- pairs = []
70
+ pairs: list[str | tuple[str, str]] = []
70
71
  for item in raw_items:
71
72
  if isinstance(item, str):
72
73
  if ":" in item:
73
74
  code, label = item.split(":", 1)
75
+ pairs.append((code.strip(), label.strip()))
74
76
  else:
75
- code = label = item
76
- pairs.append((code.strip(), label.strip()))
77
+ pairs.append(item.strip())
77
78
  elif isinstance(item, dict):
78
79
  for code, label in item.items():
79
80
  pairs.append((code.strip(), label.strip()))
@@ -203,6 +204,49 @@ def catchall_subquestion(value: Any, subquestion: str) -> DACatchAll:
203
204
  return value
204
205
 
205
206
 
207
+ def catchall_complete(
208
+ value: DACatchAll,
209
+ question: str = "",
210
+ subquestion: str = "",
211
+ label: str = "",
212
+ datatype: str = "",
213
+ options: Any = "",
214
+ ) -> DACatchAll:
215
+ """
216
+ Jinja2 filter to allow you to define multiple attributes of a DACatchAll field inside a DOCX template.
217
+
218
+ Each argument after `value` corresponds to the similarly named `catchall_` function.
219
+
220
+ Example usage in a DOCX template:
221
+ ```
222
+ {{ my_catchall_field | catchall_complete(question="What additional information do you need?", subquestion="Be specific", label="no label") }}
223
+ ```
224
+
225
+ Args:
226
+ value (DACatchAll): The DACatchAll object to which the attributes will be assigned.
227
+ question (str, optional): The question text to set on the DACatchAll object.
228
+ subquestion (str, optional): The subquestion text to set on the DACatchAll object.
229
+ label (str, optional): The label to set on the DACatchAll object.
230
+ datatype (str, optional): The datatype to set on the DACatchAll object.
231
+ options (Any, optional): The options to set on the DACatchAll object.
232
+
233
+ Returns:
234
+ DACatchAll: The modified DACatchAll object with the assigned attributes.
235
+ """
236
+ if isinstance(value, DACatchAll):
237
+ if question:
238
+ catchall_question(value, question)
239
+ if subquestion:
240
+ catchall_subquestion(value, subquestion)
241
+ if label:
242
+ catchall_label(value, label)
243
+ if datatype:
244
+ catchall_datatype(value, datatype)
245
+ if options:
246
+ catchall_options(value, options)
247
+ return value
248
+
249
+
206
250
  def _undefined_label(ud: Undefined) -> Union[str, None]:
207
251
  """
208
252
  Extract the variable name from a Jinja2 Undefined object for use as a placeholder label.
@@ -314,6 +358,7 @@ register_jinja_filter("catchall_label", catchall_label)
314
358
  register_jinja_filter("catchall_datatype", catchall_datatype)
315
359
  register_jinja_filter("catchall_question", catchall_question)
316
360
  register_jinja_filter("catchall_subquestion", catchall_subquestion)
361
+ register_jinja_filter("catchall_complete", catchall_complete)
317
362
  register_jinja_filter("if_final", if_final)
318
363
 
319
364