docassemble.AssemblyLine 4.4.0__tar.gz → 4.5.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 (100) hide show
  1. {docassemble_assemblyline-4.4.0/docassemble.AssemblyLine.egg-info → docassemble_assemblyline-4.5.0}/PKG-INFO +1 -1
  2. docassemble_assemblyline-4.5.0/docassemble/AssemblyLine/__init__.py +1 -0
  3. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/al_document.py +115 -8
  4. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/al_general.py +2 -2
  5. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/al_visual.yml +12 -5
  6. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/assembly_line.yml +2 -2
  7. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/interview_list.yml +2 -2
  8. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/test_aldocument.yml +4 -4
  9. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/sessions.py +1 -1
  10. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/test_al_general.py +13 -0
  11. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0/docassemble.AssemblyLine.egg-info}/PKG-INFO +1 -1
  12. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/pyproject.toml +1 -1
  13. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/setup.py +1 -1
  14. docassemble_assemblyline-4.4.0/docassemble/AssemblyLine/__init__.py +0 -1
  15. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/LICENSE +0 -0
  16. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/MANIFEST.in +0 -0
  17. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/README.md +0 -0
  18. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/al_courts.py +0 -0
  19. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/custom_jinja_filters.py +0 -0
  20. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/al_code.yml +0 -0
  21. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/al_document.yml +0 -0
  22. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/al_language.yml +0 -0
  23. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/al_package.yml +0 -0
  24. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/al_package_unstyled.yml +0 -0
  25. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/al_question_test.yml +0 -0
  26. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/al_reminders.yml +0 -0
  27. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/al_saved_sessions.yml +0 -0
  28. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/al_saved_sessions_store.yml +0 -0
  29. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/al_settings.yml +0 -0
  30. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/al_terms_of_use.yml +0 -0
  31. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/assembly_line_unstyled.yml +0 -0
  32. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/demo_search_sessions.yml +0 -0
  33. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/feedback.yml +0 -0
  34. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/ql_baseline.yml +0 -0
  35. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/ql_catchall.yml +0 -0
  36. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/ql_namechange.yml +0 -0
  37. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/reserved_words.yml +0 -0
  38. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/test_al_table_document.yml +0 -0
  39. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/test_aladdendum.yml +0 -0
  40. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/test_alcourts.yml +0 -0
  41. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/test_aldocument_background_assembly.yml +0 -0
  42. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/test_alexhibit.yml +0 -0
  43. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/test_alexhibit_maxsize.yml +0 -0
  44. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/test_bundle_parity.yml +0 -0
  45. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/test_catchall.yml +0 -0
  46. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/test_familiar_disambiguation.yml +0 -0
  47. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/test_if_final.yml +0 -0
  48. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/test_preferred_formats.yml +0 -0
  49. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/test_preferred_name.yml +0 -0
  50. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/test_question_library.yml +0 -0
  51. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/questions/test_signature.yml +0 -0
  52. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/sources/README.md +0 -0
  53. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/sources/ar-words.yml +0 -0
  54. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/sources/es-words.yml +0 -0
  55. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/sources/fr-words.yml +0 -0
  56. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/sources/languages.yml +0 -0
  57. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/sources/ne-words.yml +0 -0
  58. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/sources/test_aldocument.feature +0 -0
  59. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_docx_1.docx +0 -0
  60. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_jpg_1.jpg +0 -0
  61. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_pdf_1.pdf +0 -0
  62. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_png_1.png +0 -0
  63. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/sources/test_question_library.feature +0 -0
  64. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/sources/translation_es.xlsx +0 -0
  65. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/sources/translation_ht.xlsx +0 -0
  66. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/sources/translation_pt.xlsx +0 -0
  67. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/static/README.md +0 -0
  68. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/static/al_audio.css +0 -0
  69. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/static/al_audio.js +0 -0
  70. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/static/aldocument.css +0 -0
  71. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/static/aldocument.js +0 -0
  72. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/static/interview_list.css +0 -0
  73. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/static/limit_upload_size.js +0 -0
  74. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/static/lt1-pullout-10-getting-organized.pdf +0 -0
  75. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/static/ma_logo.png +0 -0
  76. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/static/placeholder.png +0 -0
  77. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/static/seal.jpg +0 -0
  78. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/static/styles.css +0 -0
  79. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/templates/README.md +0 -0
  80. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/templates/al_basic_addendum.docx +0 -0
  81. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/templates/exhibit_cover_sheet.docx +0 -0
  82. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/templates/exhibit_table_of_contents.docx +0 -0
  83. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/templates/general_cover_sheet.docx +0 -0
  84. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/templates/sample_word_template.docx +0 -0
  85. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/templates/test_aldocument_docx_1.docx +0 -0
  86. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/templates/test_aldocument_pdf_1.pdf +0 -0
  87. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/templates/test_catchall.docx +0 -0
  88. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/data/templates/test_if_final.docx +0 -0
  89. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/language.py +0 -0
  90. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/py.typed +0 -0
  91. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/requirements.txt +0 -0
  92. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/sign.py +0 -0
  93. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/test_al_document.py +0 -0
  94. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble/AssemblyLine/test_language.py +0 -0
  95. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble.AssemblyLine.egg-info/SOURCES.txt +0 -0
  96. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble.AssemblyLine.egg-info/dependency_links.txt +0 -0
  97. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble.AssemblyLine.egg-info/not-zip-safe +0 -0
  98. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble.AssemblyLine.egg-info/requires.txt +0 -0
  99. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/docassemble.AssemblyLine.egg-info/top_level.txt +0 -0
  100. {docassemble_assemblyline-4.4.0 → docassemble_assemblyline-4.5.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: docassemble.AssemblyLine
3
- Version: 4.4.0
3
+ Version: 4.5.0
4
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.
5
5
  Home-page: https://courtformsonline.org
6
6
  Author: Suffolk Legal Innovation and Technology Lab
@@ -0,0 +1 @@
1
+ __version__ = '4.5.0'
@@ -1581,6 +1581,7 @@ class ALDocumentBundle(DAList):
1581
1581
  self.auto_gather = False
1582
1582
  if "gathered" not in kwargs:
1583
1583
  self.gathered = True
1584
+ self._set_default_attributes()
1584
1585
  self.initializeAttribute("cache", DALazyAttribute)
1585
1586
  self.always_enabled = hasattr(self, "enabled") and self.enabled
1586
1587
  # Pre-cache some DALazyTemplates we set up to aid translation that won't
@@ -1589,6 +1590,24 @@ class ALDocumentBundle(DAList):
1589
1590
  # When the key is "preview", append it to the file name
1590
1591
  self.suffix_to_append = "preview"
1591
1592
 
1593
+ def _set_default_attributes(self) -> None:
1594
+ if not hasattr(self, "add_page_numbers"):
1595
+ self.add_page_numbers = False
1596
+ if not hasattr(self, "page_number_prefix"):
1597
+ self.page_number_prefix = ""
1598
+ if not hasattr(self, "page_number_start"):
1599
+ self.page_number_start = 1
1600
+ if not hasattr(self, "page_number_digits"):
1601
+ self.page_number_digits = 5
1602
+ if not hasattr(self, "page_number_area"):
1603
+ self.page_number_area = None
1604
+ if not hasattr(self, "page_number_font_size"):
1605
+ self.page_number_font_size = 10
1606
+ if not hasattr(self, "page_number_offset_horizontal"):
1607
+ self.page_number_offset_horizontal = 15
1608
+ if not hasattr(self, "page_number_offset_vertical"):
1609
+ self.page_number_offset_vertical = 15
1610
+
1592
1611
  def as_pdf(
1593
1612
  self,
1594
1613
  key: str = "final",
@@ -1648,6 +1667,17 @@ class ALDocumentBundle(DAList):
1648
1667
  filename=f"{base_name(self.filename)}{append_suffix}.pdf",
1649
1668
  pdfa=pdfa,
1650
1669
  )
1670
+ if hasattr(self, "add_page_numbers") and self.add_page_numbers:
1671
+ self._set_default_attributes()
1672
+ pdf.bates_number(
1673
+ prefix=self.page_number_prefix,
1674
+ start=self.page_number_start,
1675
+ digits=self.page_number_digits,
1676
+ area=self.page_number_area,
1677
+ font_size=self.page_number_font_size,
1678
+ offset_horizontal=self.page_number_offset_horizontal,
1679
+ offset_vertical=self.page_number_offset_vertical,
1680
+ )
1651
1681
  pdf.title = self.title
1652
1682
  setattr(self.cache, safe_key, pdf)
1653
1683
 
@@ -2385,6 +2415,7 @@ class ALDocumentBundle(DAList):
2385
2415
  label: str = "Send",
2386
2416
  icon: str = "envelope",
2387
2417
  preferred_formats: Optional[Union[str, List[str]]] = None,
2418
+ email_legend_class: str = "h4",
2388
2419
  ) -> str:
2389
2420
  """
2390
2421
  Generate HTML for an input box and button that allows someone to send the bundle
@@ -2404,6 +2435,8 @@ class ALDocumentBundle(DAList):
2404
2435
  icon (str, optional): The Fontawesome icon for the button. Defaults
2405
2436
  to "envelope".
2406
2437
  preferred_formats (Optional[Union[str,List[str]]], optional): A list of allowed formats for the document. Defaults to "pdf" if not specified.
2438
+ email_legend_class (str, optional): CSS class applied to the email
2439
+ section legend. Defaults to "h4".
2407
2440
 
2408
2441
  Returns:
2409
2442
  str: The generated HTML string for the input box and button.
@@ -2443,7 +2476,7 @@ class ALDocumentBundle(DAList):
2443
2476
  # Container of whole email section with header
2444
2477
  return_str = f"""
2445
2478
  <fieldset class="al_send_bundle al_send_section_alone {html_safe_str(self.instanceName)}" id="al_send_bundle_{name}" name="al_send_bundle_{name}">
2446
- <legend class="h4 al_doc_email_header">{str(self.get_email_copy)}</legend>
2479
+ <legend class="{email_legend_class} al_doc_email_header">{str(self.get_email_copy)}</legend>
2447
2480
  """
2448
2481
  # "Editable" checkbox
2449
2482
  if (
@@ -2735,9 +2768,14 @@ class ALExhibit(DAObject):
2735
2768
  self,
2736
2769
  *,
2737
2770
  refresh: bool = False,
2738
- prefix: str = "",
2739
2771
  pdfa: bool = False,
2740
2772
  add_page_numbers: bool = True,
2773
+ page_number_prefix: str = "",
2774
+ page_number_digits: int = 5,
2775
+ page_number_area=None,
2776
+ page_number_font_size: float = 10,
2777
+ page_number_offset_horizontal: float = 15,
2778
+ page_number_offset_vertical: float = 15,
2741
2779
  add_cover_page: bool = True,
2742
2780
  filename: Optional[str] = None,
2743
2781
  append_matching_suffix: bool = True,
@@ -2749,9 +2787,14 @@ class ALExhibit(DAObject):
2749
2787
 
2750
2788
  Args:
2751
2789
  refresh (bool): If True, forces the exhibit to refresh before generating the PDF. (unused, provided for signature compatibility)
2752
- prefix (str): Prefix for Bates numbering if 'add_page_numbers' is True.
2753
2790
  pdfa (bool): If True, the generated PDF will be in PDF/A format.
2754
2791
  add_page_numbers (bool): If True, apply Bates numbering starting from 'self.start_page'.
2792
+ page_number_prefix (str): If add_page_numbers is True, this gets added to the beginning on the bates number each page (e.g. `EX-`).
2793
+ page_number_digits (int): How many digits (i.e. leading 0s) that the bates number will have
2794
+ page_number_area (str): Where on the page the bates number will go ("TOP_LEFT", "TOP_RIGHT", "BOTTOM_LEFT", "BOTTOM_RIGHT" (default))
2795
+ page_number_font_size (float): How big the bates page number will be in points (default is 10).
2796
+ page_number_offset_horizontal (float): The number of pixels that the bates page number is offset from the left / right of the page.
2797
+ page_number_offset_vertical (float): The number of pixels that the bates page number is offset from the top / bottom of the page.
2755
2798
  add_cover_page (bool): If True, prepend the exhibit with a cover page.
2756
2799
  filename (Optional[str]): Custom filename for the generated PDF. Default is "exhibits.pdf".
2757
2800
  append_matching_suffix (bool): If True, appends a suffix to the filename based on certain matching criteria.
@@ -2779,7 +2822,15 @@ class ALExhibit(DAObject):
2779
2822
  )
2780
2823
 
2781
2824
  if add_page_numbers:
2782
- concatenated_pages.bates_number(prefix=prefix, start=self.start_page)
2825
+ concatenated_pages.bates_number(
2826
+ start=self.start_page,
2827
+ prefix=page_number_prefix,
2828
+ digits=page_number_digits,
2829
+ area=page_number_area,
2830
+ font_size=page_number_font_size,
2831
+ offset_horizontal=page_number_offset_horizontal,
2832
+ offset_vertical=page_number_offset_vertical,
2833
+ )
2783
2834
 
2784
2835
  setattr(self._cache, safe_key, concatenated_pages)
2785
2836
  return getattr(self._cache, safe_key)
@@ -2913,6 +2964,12 @@ class ALExhibitList(DAList):
2913
2964
  filename="file.pdf",
2914
2965
  pdfa: bool = False,
2915
2966
  add_page_numbers: bool = False,
2967
+ page_number_prefix: str = "",
2968
+ page_number_digits: int = 5,
2969
+ page_number_area=None,
2970
+ page_number_font_size: float = 10,
2971
+ page_number_offset_horizontal: float = 15,
2972
+ page_number_offset_vertical: float = 15,
2916
2973
  toc_pages: int = 0,
2917
2974
  append_matching_suffix: bool = True,
2918
2975
  ) -> DAFile:
@@ -2923,6 +2980,12 @@ class ALExhibitList(DAList):
2923
2980
  filename (str): Desired filename for the generated PDF.
2924
2981
  pdfa (bool): If True, generates the PDF in PDF/A format.
2925
2982
  add_page_numbers (bool): If True, adds page numbers to the generated PDF.
2983
+ page_number_prefix (str): What the bates number added to each page should start with (e.g. `EX-`).
2984
+ page_number_digits (int): How many digits (i.e. leading 0s) that the bates number will have
2985
+ page_number_area (str): Where on the page the bates number will go ("TOP_LEFT", "TOP_RIGHT", "BOTTOM_LEFT", "BOTTOM_RIGHT" (default))
2986
+ page_number_font_size (float): How big the bates page number will be in points (default is 10).
2987
+ page_number_offset_horizontal (float): The number of pixels that the bates page number is offset from the left / right of the page.
2988
+ page_number_offset_vertical (float): The number of pixels that the bates page number is offset from the top / bottom of the page.
2926
2989
  toc_pages (int): Expected number of pages in the table of contents.
2927
2990
  append_matching_suffix (bool): If True, appends matching suffix to the filename.
2928
2991
 
@@ -2934,12 +2997,19 @@ class ALExhibitList(DAList):
2934
2997
  exhibit.cover_page
2935
2998
  if self.include_table_of_contents and toc_pages != 1:
2936
2999
  self._update_page_numbers(toc_guess_pages=toc_pages)
3000
+ if not page_number_prefix and self.bates_prefix:
3001
+ page_number_prefix = self.bates_prefix
2937
3002
  return pdf_concatenate(
2938
3003
  [
2939
3004
  exhibit.as_pdf(
2940
3005
  add_cover_page=self.include_exhibit_cover_pages,
2941
3006
  add_page_numbers=add_page_numbers,
2942
- prefix=self.bates_prefix,
3007
+ page_number_prefix=page_number_prefix,
3008
+ page_number_digits=page_number_digits,
3009
+ page_number_area=page_number_area,
3010
+ page_number_font_size=page_number_font_size,
3011
+ page_number_offset_horizontal=page_number_offset_horizontal,
3012
+ page_number_offset_vertical=page_number_offset_vertical,
2943
3013
  )
2944
3014
  for exhibit in self
2945
3015
  ],
@@ -3072,12 +3142,19 @@ class ALExhibitDocument(ALDocument):
3072
3142
  has_addendum: bool
3073
3143
  auto_labeler: Callable
3074
3144
  auto_ocr: bool
3145
+ # Deprecated
3075
3146
  bates_prefix: str
3076
3147
  maximum_size: int
3077
3148
  maximum_size_per_doc: int
3078
3149
  suffix_to_append: str
3079
3150
  exhibits: ALExhibitList
3080
3151
  table_of_contents: DAFile
3152
+ page_number_prefix: str
3153
+ page_number_digits: int
3154
+ page_number_area: str | None
3155
+ page_number_font_size: float
3156
+ page_number_offset_horizontal: float
3157
+ page_number_offset_vertical: float
3081
3158
 
3082
3159
  def init(self, *pargs, **kwargs) -> None:
3083
3160
  """Standard DAObject init method.
@@ -3092,8 +3169,6 @@ class ALExhibitDocument(ALDocument):
3092
3169
  self.exhibits.auto_labeler = self.auto_labeler
3093
3170
  if hasattr(self, "auto_ocr"):
3094
3171
  self.exhibits.auto_ocr = self.auto_ocr
3095
- if hasattr(self, "bates_prefix"):
3096
- self.exhibits.bates_prefix = self.bates_prefix
3097
3172
  if hasattr(self, "include_exhibit_cover_pages"):
3098
3173
  self.exhibits.include_exhibit_cover_pages = self.include_exhibit_cover_pages
3099
3174
  else:
@@ -3111,13 +3186,30 @@ class ALExhibitDocument(ALDocument):
3111
3186
  else:
3112
3187
  self.include_table_of_contents = True
3113
3188
  self.exhibits.include_table_of_contents = True
3189
+ if hasattr(self, "bates_prefix"):
3190
+ self.exhibits.bates_prefix = self.bates_prefix
3114
3191
  if not hasattr(self, "add_page_numbers"):
3115
3192
  self.add_page_numbers = False
3193
+ self._set_default_attributes()
3116
3194
  self.has_addendum = False
3117
3195
  if not hasattr(self, "suffix_to_append"):
3118
3196
  # When the key is "preview", append it to the file name
3119
3197
  self.suffix_to_append = "preview"
3120
3198
 
3199
+ def _set_default_attributes(self) -> None:
3200
+ if not hasattr(self, "page_number_prefix"):
3201
+ self.page_number_prefix = ""
3202
+ if not hasattr(self, "page_number_digits"):
3203
+ self.page_number_digits = 5
3204
+ if not hasattr(self, "page_number_area"):
3205
+ self.page_number_area = None
3206
+ if not hasattr(self, "page_number_font_size"):
3207
+ self.page_number_font_size = 10
3208
+ if not hasattr(self, "page_number_offset_horizontal"):
3209
+ self.page_number_offset_horizontal = 15
3210
+ if not hasattr(self, "page_number_offset_vertical"):
3211
+ self.page_number_offset_vertical = 15
3212
+
3121
3213
  def has_overflow(self) -> bool:
3122
3214
  """
3123
3215
  Check if there is any overflow in the document.
@@ -3192,12 +3284,21 @@ class ALExhibitDocument(ALDocument):
3192
3284
  filename = base_name(self.filename) + ".pdf"
3193
3285
 
3194
3286
  if len(self.exhibits):
3287
+ self._set_default_attributes()
3195
3288
  if self.include_table_of_contents:
3196
3289
  toc_pages = self.table_of_contents.num_pages()
3197
3290
  return pdf_concatenate(
3198
3291
  self.table_of_contents,
3199
3292
  self.exhibits.as_pdf(
3200
- add_page_numbers=self.add_page_numbers, toc_pages=toc_pages
3293
+ add_page_numbers=self.add_page_numbers,
3294
+ page_number_prefix=self.page_number_prefix,
3295
+ page_number_digits=self.page_number_digits,
3296
+ page_number_area=self.page_number_area,
3297
+ page_number_font_size=self.page_number_font_size,
3298
+ page_number_offset_horizontal=self.page_number_offset_horizontal,
3299
+ page_number_offset_vertical=self.page_number_offset_vertical,
3300
+ toc_pages=toc_pages,
3301
+ pdfa=pdfa,
3201
3302
  ),
3202
3303
  filename=filename,
3203
3304
  pdfa=pdfa,
@@ -3205,6 +3306,12 @@ class ALExhibitDocument(ALDocument):
3205
3306
  else:
3206
3307
  return self.exhibits.as_pdf(
3207
3308
  add_page_numbers=self.add_page_numbers,
3309
+ page_number_prefix=self.page_number_prefix,
3310
+ page_number_digits=self.page_number_digits,
3311
+ page_number_area=self.page_number_area,
3312
+ page_number_font_size=self.page_number_font_size,
3313
+ page_number_offset_horizontal=self.page_number_offset_horizontal,
3314
+ page_number_offset_vertical=self.page_number_offset_vertical,
3208
3315
  filename=filename,
3209
3316
  pdfa=pdfa,
3210
3317
  )
@@ -1914,7 +1914,7 @@ class ALIndividual(Individual):
1914
1914
  if len(pronouns_to_use) > 0:
1915
1915
  output = "/".join(pronouns_to_use)
1916
1916
  else:
1917
- output = default
1917
+ output = f"{default}'s {target}"
1918
1918
  elif hasattr(self, "person_type") and self.person_type in [
1919
1919
  "business",
1920
1920
  "organization",
@@ -1928,7 +1928,7 @@ class ALIndividual(Individual):
1928
1928
  else:
1929
1929
  output = their(target, **kwargs)
1930
1930
  else:
1931
- output = default
1931
+ output = f"{default}'s {target}"
1932
1932
 
1933
1933
  if "capitalize" in kwargs and kwargs["capitalize"]:
1934
1934
  return capitalize(output)
@@ -110,9 +110,16 @@ data from code:
110
110
  label: str(al_load_answer_set_string)
111
111
  hidden: not get_config('assembly line',{}).get('enable answer sets')
112
112
  - url: |
113
- url_action('al_error_action_download_screen')
114
- label: str(al_download_answer_set_string)
115
- hidden: (not get_config('assembly line',{}).get('enable answer set imports')) or (_internal.get('steps') < 2)
113
+ url_ask(["al_sessions_json_file", {"recompute": ["al_sessions_import_json"]}, "al_sessions_load_status"])
114
+ label: str(al_import_answer_set_string)
115
+ hidden: |
116
+ not (
117
+ (
118
+ get_config('assembly line',{}).get('enable answer sets')
119
+ and get_config('assembly line',{}).get('enable answer set imports')
120
+ )
121
+ or (user_logged_in() and user_has_privilege('admin'))
122
+ )
116
123
  ---
117
124
  template: al_start_over_string
118
125
  content: >-
@@ -134,9 +141,9 @@ template: al_load_answer_set_string
134
141
  content: >-
135
142
  Load answer set
136
143
  ---
137
- template: al_download_answer_set_string
144
+ template: al_import_answer_set_string
138
145
  content: >-
139
- Download answer set
146
+ Import answer set
140
147
  ---
141
148
  event: al_exit_logout
142
149
  code: |
@@ -1,4 +1,4 @@
1
- # For usage, see https://suffolklitlab.org/docassemble-AssemblyLine-documentation/docs/framework/magic_variables
1
+ # For usage, see https://assemblyline.suffolklitlab.org/docs/components/AssemblyLine/magic_variables
2
2
  ---
3
3
  include:
4
4
  - al_language.yml
@@ -19,4 +19,4 @@ modules:
19
19
  - .al_document
20
20
  - .al_courts
21
21
  - docassemble.GithubFeedbackForm.github_issue
22
-
22
+
@@ -18,7 +18,7 @@ comment: |
18
18
  new form label: Start a new form
19
19
  new form url: https://courtformsonline.org
20
20
  logo url: null # Defaults to `app homepage`
21
- logo image url: https://app.yourserver.org/packagestatic/docassemble.AssemblyLine/ma_logo.png
21
+ logo image url: https://app.example.org/packagestatic/docassemble.AssemblyLine/ma_logo.png
22
22
  logo image alt: Logo
23
23
  answer sets title: Answer sets
24
24
  logo title row 1: null # Defaults to `interview page title`
@@ -490,4 +490,4 @@ code: |
490
490
  event: delete_results_action
491
491
  code: |
492
492
  undefine("limit_filename")
493
- undefine("search_keyword")
493
+ undefine("search_keyword")
@@ -31,7 +31,7 @@ code: |
31
31
  ---
32
32
  objects:
33
33
  # No addenda, all start enabled
34
- - multi_bundle_1: ALDocumentBundle.using(elements=[pdf_1, docx_1, notice_to_quit], title="Multiple docs 1", filename="multi_bundle_1" )
34
+ - multi_bundle_1: ALDocumentBundle.using(elements=[pdf_1, docx_1, notice_to_quit], title="Multiple docs 1", filename="multi_bundle_1", add_page_numbers=True, page_numbers_font_size=20 )
35
35
  - single_pdf_bundle_1: ALDocumentBundle.using(elements=[pdf_1], title="One pdf", filename="single_pdf_1" )
36
36
  - single_docx_bundle_1: ALDocumentBundle.using(elements=[docx_1], title="One docx", filename="single_docx_1" )
37
37
  ---
@@ -341,9 +341,9 @@ subquestion: |
341
341
 
342
342
  Send button which allows the user to edit the email address.
343
343
 
344
- multi_bundle_1.send_button_html( key="test_key", show_editable_checkbox=False, label="Custom send label", icon="search" )
344
+ multi_bundle_1.send_button_html( key="test_key", show_editable_checkbox=False, label="Custom send label", icon="search", email_legend_class="h5" )
345
345
 
346
- ${ multi_bundle_1.send_button_html( key="test_key", show_editable_checkbox=False, label="Custom send label", icon="search" ) }
346
+ ${ multi_bundle_1.send_button_html( key="test_key", show_editable_checkbox=False, label="Custom send label", icon="search", email_legend_class="h5" ) }
347
347
 
348
348
  ---
349
349
  single_pdf_bundle_1.send_button_html( key="test_key", show_editable_checkbox=False, label="Custom send label", icon="search" )
@@ -380,4 +380,4 @@ subquestion: |
380
380
  id: end aldocument tests
381
381
  event: end_aldocument_tests
382
382
  question: The end of ALDocument tests
383
- ---
383
+ ---
@@ -1714,7 +1714,7 @@ def update_session_metadata(
1714
1714
 
1715
1715
  # 2) Derive two signed 32‑bit ints from MD5(session_id|filename|tags)
1716
1716
  key_string = f"{session_id}|{filename}|{metadata_key_name}"
1717
- digest = hashlib.md5(key_string.encode("utf-8")).digest()
1717
+ digest = hashlib.md5(key_string.encode("utf-8"), usedforsecurity=False).digest()
1718
1718
  high_u32, low_u32 = struct.unpack(">II", digest[:8])
1719
1719
 
1720
1720
  def to_signed_32(x: int) -> int:
@@ -418,6 +418,19 @@ class TestALIndividual(unittest.TestCase):
418
418
  self.individual.pronoun_possessive(item, capitalize=True), "Its fish"
419
419
  )
420
420
 
421
+ # Test for when user provides a pronoun string that cannot be parsed
422
+ # (doesn't follow the required 2-3 slash format), should fall back to using name's target
423
+ self.individual.pronouns = "custom"
424
+ self.individual.person_type = "individual"
425
+ self.individual.name.first = "John"
426
+ self.individual.name.last = "Smith"
427
+ # When pronouns can't be parsed, should use "{name}'s {target}"
428
+ self.assertEqual(self.individual.pronoun_possessive(item), "John Smith's fish")
429
+ self.assertEqual(
430
+ self.individual.pronoun_possessive(item, capitalize=True),
431
+ "John Smith's fish",
432
+ )
433
+
421
434
  def test_pronoun_subjective(self):
422
435
  self.individual.pronouns = None
423
436
  self.individual.person_type = "individual"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: docassemble.AssemblyLine
3
- Version: 4.4.0
3
+ Version: 4.5.0
4
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.
5
5
  Home-page: https://courtformsonline.org
6
6
  Author: Suffolk Legal Innovation and Technology Lab
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
 
7
7
  [project]
8
8
  name = "docassemble.AssemblyLine"
9
- version = "4.4.0"
9
+ version = "4.5.0"
10
10
  description = "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."
11
11
  readme = "README.md"
12
12
  authors = [
@@ -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='4.4.0',
47
+ version='4.5.0',
48
48
  description=(''),
49
49
  long_description='# Suffolk LIT Lab Document Assembly Line\r\n\r\n[![PyPI version](https://badge.fury.io/py/docassemble-AssemblyLine.svg)](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__ = '4.4.0'